对 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 RELRO
,GOT
部分的non-PLT部分(.got[= readelf 输出中的 25=] 是只读的,但 .got.plt 仍然是可写的。而在完整的 RELRO 中,整个 GOT (.got 和 .got.plt 两者)被标记为只读。
If you want to have full readonly use -z, now
as well.
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
.
的运气
是否期望对程序地址所做的更改 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 RELRO
,GOT
部分的non-PLT部分(.got[= readelf 输出中的 25=] 是只读的,但 .got.plt 仍然是可写的。而在完整的 RELRO 中,整个 GOT (.got 和 .got.plt 两者)被标记为只读。
If you want to have full readonly use
-z, now
as well.
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
.