使用 gdb 对指定可执行文件之外的单步汇编代码导致错误“找不到当前函数的边界”

Posted

技术标签:

【中文标题】使用 gdb 对指定可执行文件之外的单步汇编代码导致错误“找不到当前函数的边界”【英文标题】:Using gdb to single-step assembly code outside specified executable causes error "cannot find bounds of current function" 【发布时间】:2011-01-26 02:55:54 【问题描述】:

我在 gdb 的目标可执行文件之外,我什至没有对应于该目标的堆栈。无论如何我都想单步执行,这样我就可以验证我的汇编代码中发生了什么,因为我不是 x86 汇编方面的专家。不幸的是,gdb 拒绝进行这种简单的汇编级调试。它允许我在适当的断点处设置和停止,但是一旦我尝试单步前进,gdb 就会报告错误“找不到当前函数的边界”并且 EIP 不会改变。

其他细节:

机器代码是由 gcc asm 语句生成的,我将它从 objdump -d 的输出复制到它正在执行的内核内存位置。我不介意使用加载器将目标代码加载到重定位地址的简单方法,但请记住加载必须在内核模块中完成。

我想另一种选择是生成一个虚假的内核模块或调试信息文件以提供给 gdb,使其相信该区域在程序代码中。 gdb 在内核可执行文件本身上运行良好。

(对于那些真正想知道的人,我在运行时将代码插入到 VMware VM 内的 Linux 内核数据空间中,并通过 VMware Workstation 的内置 gdb 存根从 gdb 远程调试内核进行调试。注意我是不编写内核漏洞利用;我是一名正在编写原型的安全研究生。)

(我可以在我的程序集中的每条指令上设置一个断点。这可行,但一段时间后会变得相当费力,因为 x86 汇编指令的大小会有所不同,并且每次我重新启动时程序集的位置都会改变。)

【问题讨论】:

聪明的ksplice.com 人通过组装“假”内核模块并加载它们将数据和代码注入内核。如果他们能做到,你为什么不能呢? ;-) 【参考方案1】:

运行gdbtui,而不是gdb。或者使用-tui 开关运行gdb。或者输入gdb后按C-x C-a。现在您处于 GDB 的 TUI 模式。

输入layout asm 以制作上部窗口显示组件——这将自动跟随您的指令指针,尽管您也可以在调试时更改框架或滚动。按C-x s进入SingleKey模式,其中run continue up down finish等缩写为一个键,让你快速浏览你的程序。

+-------------------------------------------------- --------------------------+ B+>|0x402670
推 %r15 | |0x402672
mov %edi,%r15d | |0x402675
推 %r14 | |0x402677
推 %r13 | |0x402679
mov %rsi,%r13 | |0x40267c
推 %r12 | |0x40267e
push %rbp | |0x40267f
push %rbx | |0x402680
sub $0x438,%rsp | |0x402687
mov (%rsi),%rdi | |0x40268a
movq $0x402a10,0x400(%rsp) | |0x402696
movq $0x0,0x408(%rsp) | |0x4026a2
movq $0x402510,0x410(%rsp) | +-------------------------------------------------- --------------------------+ 子进程 21518 在:主线:??电脑:0x402670 (gdb) 文件 /opt/j64-602/bin/jconsole 从 /opt/j64-602/bin/jconsole 读取符号...完成。 (未找到调试符号)...完成。 (gdb) 布局汇编 (gdb) 开始 (gdb)

【讨论】:

【参考方案2】:

您可以使用stepinexti(可缩写为sini)单步执行您的机器代码。

【讨论】:

哇。回想起来,我并没有忘记 stepi。我想我只是假设因为 gdb 没有源代码,该步骤将恢复为汇编指令。 注意:您通常不能为汇编程序键入“break main”、“run”。键入“layout asm”、“start”。我是通过阅读下面的消息得到的,但阅读这篇文章的其他人可能没有那么耐心。 @Dmitry start 相当于tbreak main 后跟run(注意:tbreak 而不是break【参考方案3】:

您可以在这里做的最有用的事情是display/i $pc,然后使用stepi,正如R Samuel Klatchko 的回答中已经建议的那样。这告诉 gdb 在每次打印提示之前反汇编当前指令;然后你可以继续按 Enter 重复 stepi 命令。

(有关更多详细信息,请参阅my answer to another question - 该问题的上下文不同,但原理相同。)

【讨论】:

以上是关于使用 gdb 对指定可执行文件之外的单步汇编代码导致错误“找不到当前函数的边界”的主要内容,如果未能解决你的问题,请参考以下文章

GDB调试指南-单步调试

gdb中一些常用的调试命令

防止 GDB 单步执行函数(或文件)

如何在QEMU上的GDB中单步ARM组装?

GDB 调试多线程程序的总结

g++编译选项