我已经用Radare2反汇编了一个C程序。在此程序中,有许多对scanf
的调用,如下所示:
0x000011fe 488d4594 lea rax, [var_6ch]
0x00001202 4889c6 mov rsi, rax
0x00001205 488d3df35603. lea rdi, [0x000368ff] ; "%d" ; const char *format
0x0000120c b800000000 mov eax, 0
0x00001211 e86afeffff call sym.imp.__isoc99_scanf ; int scanf(const char *format)
0x00001216 8b4594 mov eax, dword [var_6ch]
0x00001219 83f801 cmp eax, 1 ; rsi ; "ELF\x02\x01\x01"
0x0000121c 740a je 0x1228
这里
scanf
具有从"%d"
行传递给它的字符串lea rdi, [0x000368ff]
的地址。我假设0x000368ff
是可执行表文件中"%d"
的位置,因为如果以 Debug模式(r2 -d ./exec
)重新启动Radare2,则lea rdi, [0x000368ff]
将被lea rdi, [someMemoryAddress]
替换。如果
lea rdi, [0x000368ff]
是文件中的硬编码内容,那么该指令在运行时如何更改为实际的内存地址? 最佳答案
Radare欺骗了您,您所看到的并不是真正的说明,它已为您简化了。
真正的指示是:
0x00001205 488d3df3560300 lea rdi, qword [rip + 0x356f3]
0x0000120c b800000000 mov eax, 0
这是典型的与位置无关的
lea
。要使用的字符串存储在二进制文件中,偏移量为0x000368ff
,但是由于可执行文件与位置无关,因此需要在运行时计算实际地址。由于下一条指令的偏移量为0x0000120c
,因此您知道,无论二进制文件在内存中的何处加载,您想要的地址都是rip + (0x000368ff - 0x0000120c)
= rip + 0x356f3
,即您在上面看到的。在进行静态分析时,由于Radare不知道内存中二进制文件的基址,因此它仅计算
0x0000120c + 0x356f3
= 0x000368ff
。这使逆向工程更加容易,但是由于实际的指令是不同的,因此可能会造成混淆。例如,以下程序:
int main(void) {
puts("Hello world!");
}
编译后产生:
6b4: 48 8d 3d 99 00 00 00 lea rdi,[rip+0x99]
6bb: e8 a0 fe ff ff call 560 <puts@plt>
因此,
rip + 0x99
= 0x6bb + 0x99
= 0x754
,如果我们用0x754
查看二进制文件中的偏移量hd
:$ hd -s 0x754 -n 16 a.out
00000754 48 65 6c 6c 6f 20 77 6f 72 6c 64 21 00 00 00 00 |Hello world!....|
00000764
关于c - 该程序如何知道此字符串的确切存储位置?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57748994/