在反向调试期间,对程序地址空间所做的更改是否不会还原?
我一直在调试一个程序,当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 二进制文件