对 GOT 所做的更改是否预期在反向调试期间被撤销?

Are changes made to the GOT expected to be reversed during reverse debugging?

是否期望对程序地址所做的更改 space 不会在反向调试期间恢复?

我一直在调试一个程序,当 GOT 中指向 strlen 的指针在执行过程中损坏时会出现段错误。多亏了对此 question 的评论提出的建议,我通过与 -z relro 选项链接将此程序的 GOT 设置为只读;但是,这并不能阻止相关指针被覆盖。即,我可以 start gdb 中的程序,步进到第一次出现的 strlen,验证指针是否有效(例如:x/g 0x5555555d10a8 ==> 0x5555555d10a8 <strlen@got.plt>: 0x00007ffff7e8d1e0),continue 运行,等待指针变为无效(指向程序地址space之外的无意义地址;例如:x/g 0x5555555d10a8 ==> 0x5555555d10a8 <strlen@got.plt>: 0x0000000000002156),提示一个segv.

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

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

-z relro选项只做部分只读(In partial RELROGOT部分的non-PLT部分(.got[= readelf 输出中的 25=] 是只读的,但 .got.plt 仍然是可写的。而在完整的 RELRO 中,整个 GOT (.got.got.plt 两者)被标记为只读。

If you want to have full readonly use -z, now as well.

Hardening ELF binaries using Relocation

First, why is the GOT mutable despite the -z relro linker option?

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

Second, is it expected for a location in memory (the pointer to strlen) that is altered during program execution to not be restored to its original value during reverse execution?

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

的运气