Android内核环境下获取结构体成员偏移量的方法及GDB工作流
Android内核结构体成员偏移量获取方法(Genymotion环境)
先理清几个核心概念
- boot.img:Android的启动镜像,包含压缩后的内核(zImage/bzImage)和初始化ramdisk,官方/Genymotion默认提供的boot.img里的内核不带调试符号(为了减小体积)。
- bzImage/zImage:都是压缩后的Linux内核镜像格式,Android内核通常用bzImage,同样发布版无调试符号。
- vmlinux:未压缩、带完整DWARF调试符号的内核镜像,这才是GDB/工具解析结构体布局的核心文件。
方法一:编译带调试符号的内核 + GDB调试(最可靠)
这是获取准确偏移量的标准流程:
- 拿到对应内核源码:
Genymotion的内核基于对应Android版本的AOSP内核定制,去Genymotion官网或对应的开源仓库拉取,也可以直接下载匹配你虚拟机Android版本的AOSP内核源码。 - 开启调试编译选项:
修改内核配置文件.config,确保:
也可以用CONFIG_DEBUG_INFO=y # 开启完整调试符号 CONFIG_DEBUG_INFO_REDUCED=n # 禁用精简调试信息(如果存在) CONFIG_GDB_SCRIPTS=y # 开启GDB辅助脚本(可选,方便调试)make menuconfig图形化配置,在Kernel hacking->Compile-time checks and compiler options里找到对应选项。 - 编译内核:
根据虚拟机架构执行编译命令(比如arm64架构):
编译完成后会得到带符号的make ARCH=arm64 vmlinuxvmlinux,同时可以用mkbootimg工具打包成可替换的boot.img。 - 替换Genymotion的boot.img:
找到Genymotion虚拟机的存储目录(比如~/.Genymobile/Genymotion/Virtual Machines/[虚拟机名称]),替换里面的boot.img为你编译的版本。 - 启动调试:
- 启动虚拟机,用adb连接,关闭内核调试限制:
adb shell su -c "echo 1 > /proc/sys/kernel/kptr_restrict" adb shell su -c "echo 0 > /proc/sys/kernel/yama/ptrace_scope" - 转发调试端口:
adb forward tcp:1234 tcp:1234 - 用GDB加载vmlinux并连接:
gdb vmlinux (gdb) target remote :1234 (gdb) ptype /o struct binder_ref # 查看结构体成员偏移量
- 启动虚拟机,用adb连接,关闭内核调试限制:
方法二:直接用现成带符号的vmlinux(省编译时间)
如果不想自己编译,可寻找对应Android版本的预编译带符号vmlinux(部分安全研究社区、AOSP预编译包中会有)。
即使不连接运行的内核,直接用GDB加载vmlinux也能查看结构体布局:
gdb vmlinux (gdb) ptype /o struct binder_ref
只要vmlinux的编译环境(架构、Android版本、编译器)和目标内核一致,偏移量就是准确的。
方法三:轻量工具替代(无需GDB)
- pahole:属于dwarves工具包,专门解析DWARF调试信息,输出结构体布局更简洁:
pahole -C struct binder_ref vmlinux - ctfparse:如果只有boot.img,先提取里面的内核镜像,再用ctfparse提取CTF格式符号(但符号可能不全,优先级低于vmlinux)。
注意事项
- 确保内核源码/符号文件的版本、架构和你的Genymotion虚拟机完全匹配,不同版本的binder结构体可能有成员增减。
- 部分Genymotion虚拟机可能需要开启内核调试模式,可在虚拟机设置中调整。
内容的提问来源于stack exchange,提问作者Cyb3rCr0wCC




