昆山张浦做网站,深圳网站制作公司价位,开封河南网站建设,软件app开发培训文章目录 背景介绍问题举例技巧解决步骤思考参考资料 背景介绍
GDB不仅可以用来调试程序#xff0c;还可以直接修改被调试程序的二进制文件。这种方式相比于改源码重新编译、gdb attach有什么优势呢#xff1f;考虑以下企业生产环境中的几个调试场景#xff1a;
需要… 文章目录 背景介绍问题举例技巧解决步骤思考参考资料 背景介绍
GDB不仅可以用来调试程序还可以直接修改被调试程序的二进制文件。这种方式相比于改源码重新编译、gdb attach有什么优势呢考虑以下企业生产环境中的几个调试场景
需要修改的二进制文件是其他领域的你没有源码和编译工程让相关领域出调试对接件比较费时但你只想临时改一行别人的代码几分钟内完成验证。调试环境上使用gdb attach进程方式有困难 被调试的服务进程没有启动断点(可定位性很差)或者gdb手动拉起的方法非常复杂等服务正常启动后再attach已经赶不上打断点的时机。长时间gdb挂住业务进程导致触发丢心跳复位。你不确定修改的二进制文件同时被几个进程加载但你诉求很明确就是直接改文件对所有进程生效。
以下举一个简单的例子介绍GDB修改程序二进制文件的技巧
问题举例
有一个需修改的二进制文件C码如下
int main() {int grade 65;if (grade 60) { // 这里写错了需要修改成 60及格printf(pass\n);} else {printf(fail\n);}return 0;
}程序执行结果如下
# gcc main.c -o main ./main
fail【问题】这里需要将grade 60 要改成 grade 60。只通过GDB修改二进制文件的方式怎么实现
技巧解决步骤
1、缺省情况下gdb是以只读方式加载程序的。需要先通过命令行指定加载方式为可写再通过file命令加载二进制文件
(gdb) set write on
(gdb) show write
Writing into executable and core files is on.
(gdb) file main
Reading symbols from main...(no debugging symbols found)...done.2、结合C码和汇编代码定位出需修改的汇编指令
(gdb) disassemble /mr main
Dump of assembler code for function main:0x0000000000001135 0: 55 push %rbp0x0000000000001136 1: 48 89 e5 mov %rsp,%rbp0x0000000000001139 4: 48 83 ec 10 sub $0x10,%rsp0x000000000000113d 8: c7 45 fc 41 00 00 00 movl $0x41,-0x4(%rbp)0x0000000000001144 15: 83 7d fc 3c cmpl $0x3c,-0x4(%rbp) # 0x3c 60, 对应C码grade 600x0000000000001148 19: 7f 0e jg 0x1158 main350x000000000000114a 21: 48 8d 3d b3 0e 00 00 lea 0xeb3(%rip),%rdi # 0x20040x0000000000001151 28: e8 da fe ff ff callq 0x1030 putsplt0x0000000000001156 33: eb 0c jmp 0x1164 main470x0000000000001158 35: 48 8d 3d aa 0e 00 00 lea 0xeaa(%rip),%rdi # 0x20090x000000000000115f 42: e8 cc fe ff ff callq 0x1030 putsplt0x0000000000001164 47: b8 00 00 00 00 mov $0x0,%eax0x0000000000001169 52: c9 leaveq0x000000000000116a 53: c3 retq
不难发现 if (grade 60) 对应的指令为0x1148 19: 7f 0e jg 0x1158 main35 这里只需要将jg指令改jle指令即可。
3、jg, jle指令格式参考指令集手册如下 所以只需要将 7f 0e 改成7e 0e即可。
4、修改二进制代码注意大小端和指令长度用gdb的set命令修改地址处的内容方法如下
(gdb) disassemble /mr main
Dump of assembler code for function main:...0x0000000000001148 19: 7f 0e jg 0x1158 main35...
(gdb) set *(short *)0x1148 0xe7e (指令长度为2个字节这里是小端序)
(gdb) disassemble /mr main
Dump of assembler code for function main:...0x0000000000001148 19: 7e 0e jle 0x1158 main35...
End of assembler dump.退出gdb, 执行main程序输出pass说明修改生效
# ./main
pass思考
如果改成70分以上及格如何修改如果是aarch64格式的二进制呢
注意涉及到立即数的修改x86_64和aarch64差异很大。aarch64中不同的汇编指令对立即数的存储方式和表示范围都不同具体操作时需查询对应的指令集手册。
参考资料
【1】《100个gdb小技巧》
【2】《ARM Architecture Reference Manual, for ARMv8-A architecture profile》
【3】《64-ia-32-architectures-software-developer-vol-2a-manual》