Android平台Go语言二进制文件Hook框架及实现方案咨询
Android平台Go二进制文件的动态Hook方案
针对Android上的Go语言静态二进制,确实无法直接复用Frida对C++/ELF的常规Hook逻辑(比如Module.findExportByName),但有几种可行的动态Hook方案,满足你无需依赖IDA等逆向工具的需求:
1. 利用Frida结合Go符号表/内存特征扫描
如果目标Go二进制未剥离符号(编译时未加-s -w参数),可以直接通过Frida遍历进程符号表定位目标函数:
// Frida脚本:Hook time.Now() const targetProc = Process.getModuleByName("your_go_binary_name"); // 遍历符号表查找time.Now const timeNowSymbol = Process.enumerateSymbols(targetProc.name).find(sym => sym.name === "time.Now"); if (timeNowSymbol) { Interceptor.attach(timeNowSymbol.address, { onEnter: function(args) { console.log("[+] time.Now() 被调用"); }, onLeave: function(retVal) { // Go的time.Time是结构体,需按内存结构解析 const timePtr = retVal.readPointer(); console.log("[+] time.Now() 返回值地址:", timePtr); } }); } else { console.log("[-] 未找到time.Now符号,请检查二进制是否保留符号"); }
如果二进制已剥离符号,可以通过Go函数的特征指令扫描内存定位:Go函数开头通常会有访问TLS的指令(如MOVQ (TLS), CX),结合go tool nm提前获取的函数偏移(无需IDA),直接计算地址:
# 先用go tool nm获取time.Now的偏移 go tool nm your_go_binary_name | grep "time.Now" # 输出类似:12345678 T time.Now
然后在Frida脚本中直接计算地址:
const moduleBase = Process.getModuleByName("your_go_binary_name").base; const timeNowAddr = moduleBase.add(0x12345678); // 替换为实际偏移 Interceptor.attach(timeNowAddr, { onEnter: function(args) { console.log("[+] time.Now() 被Hook"); } });
2. 使用专门的Go动态Hook库(gohook)
gohook是一款针对Go语言的Hook库,支持动态替换Go函数实现,需交叉编译为Android共享库后注入目标进程:
步骤1:编写Hook逻辑(Go代码)
package main import ( "time" "github.com/rainycape/gohook" ) // 自定义的time.Now替代函数 func fakeNow() time.Time { println("[Hooked] time.Now() 被调用,返回伪造时间") return time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC) } func main() { // Hook time.Now函数 origNow := time.Now if err := gohook.Hook(origNow, fakeNow, nil); err != nil { panic(err) } defer gohook.Unhook(origNow) // 保持进程运行,维持Hook状态 select{} }
步骤2:交叉编译为Android共享库
# 针对arm64架构 GOOS=android GOARCH=arm64 go build -buildmode=c-shared -o libgohook.so main.go # 针对arm32架构 GOOS=android GOARCH=arm go build -buildmode=c-shared -o libgohook.so main.go
步骤3:用Frida注入共享库
编写Frida注入脚本inject.js:
const libPath = "/data/local/tmp/libgohook.so"; // 上传到设备的路径 const module = Process.load(libPath); console.log("[+] 注入Hook库成功");
执行注入:
frida -U -f com.your.go.app -l inject.js --no-pause
注意事项
- Go的函数调用约定与C不同,处理参数/返回值时需注意内存结构(比如结构体返回会通过指针传递)。
- 静态编译的Go二进制没有动态依赖,所有函数都在主模块中,需针对主进程二进制操作。
- 若目标二进制开启了代码混淆,需结合内存特征或调试信息进一步定位函数。
内容的提问来源于stack exchange,提问作者Aimar
相关产品推荐
相关产品推荐

