C语言 在反向调试期间,对 GOT 所做的更改是否应被撤消?



在反向调试期间,对程序地址空间所做的更改是否不会还原?

我一直在调试一个程序,当GOT中指向strlen的指针在执行过程中损坏时,该程序会出现段错误。感谢对这个问题的评论提出的建议,我通过与-z relro选项链接使该程序的 GOT 成为只读;但是,这并不能阻止有问题的指针被覆盖。 也就是说,我可以在gdb中start程序,单步到strlen的第一个出现,验证指针是否有效(例如:x/g 0x5555555d10a8 ==> 0x5555555d10a8 <strlen@got.plt>: 0x00007ffff7e8d1e0(,continue运行,等待指针无效(指向程序地址空间之外的无意义地址;例如:x/g 0x5555555d10a8 ==> 0x5555555d10a8 <strlen@got.plt>: 0x0000000000002156(,提示segv

但是,如果我record full整个执行(从第一行到程序段错误(,然后在reverse-continue期间使用指向strlen的指针awatch地址,则观察点永远不会触发。 当程序最终返回到指令 #0 时,指针仍然指向它段错误时的无效地址。

这就引出了两个问题。 首先,为什么尽管有-z relro链接器选项,GOT仍然是可变的? 其次,在程序执行期间更改的内存中的位置(指向strlen的指针(是否应该在反向执行期间不会恢复到其原始值?

首先,为什么尽管有 -z relro 链接器选项,GOT还是可变的?

-Wl,-z,relro申请的只是部分RELRO 保护。此选项的主要目的是将 GOT 移动到 BSS 之前,以避免由于 BSS 中的缓冲区溢出而导致条目损坏,并且还使 GOT 的一小部分为只读。你想要的是完整的RELRO,它是通过-Wl,-z,relro,-z,now获得的。-z now链接器标志使加载程序在启动时解析所有符号,然后在启动程序之前将包含 GOT 的段重新映射为只读。

其次,在程序执行期间更改的内存中的位置(指向strlen的指针(是否应该在反向执行期间不会恢复到其原始值?

在开始调试之前,您可能忘记设置target record-full,但我不确定这是否有任何影响,因为您已经使用了record full。反向执行并不容易,调试器可能会出于性能原因决定反向 GOT(或其他部分(的内存修改(因为通常无论如何都不应触及这些修改(。GDB 的记录功能还有一些其他限制,例如不支持 AVX 指令。我不知道更多可以给出更好的答案。你可以试试运气rr.

-z relro选项只做部分只读(在部分RELRO中,GOT部分的非PLT部分(.gotfrom readelf output(是只读的,但.got.plt仍然是可写的。而在完整的 RELRO 中,整个 GOT (.got 和 .got.plt两者都被标记为只读。

如果您想拥有完全只读,也可以使用-z, now

使用重定位强化 ELF 二进制文件

最新更新