Dra*_*mer 7 c assembly x86-64 memory-address
我已经用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
Run Code Online (Sandbox Code Playgroud)
这是从行传递给它scanf的字符串的地址。我假设是exectable文件中的位置,因为如果我以调试模式()重新启动Radare2,则将其替换为。"%d"lea rdi, [0x000368ff]0x000368ff"%d"r2 -d ./execlea rdi, [0x000368ff]lea rdi, [someMemoryAddress]
如果文件中lea rdi, [0x000368ff]有什么硬编码,那么在运行时指令如何更改为实际的存储器地址?
Radare欺骗了您,您所看到的并不是真正的指示,它已为您简化了。
真正的指示是:
0x00001205 488d3df3560300 lea rdi, qword [rip + 0x356f3]
0x0000120c b800000000 mov eax, 0
Run Code Online (Sandbox Code Playgroud)
这是典型的位置无关负载。要使用的字符串在offset处存储在二进制文件中0x000368ff,但是由于可执行文件与位置无关,因此需要在运行时计算实际地址。由于下一条指令位于offset处0x0000120c,因此您知道,无论二进制文件在内存中的何处加载,您想要的地址都将是rip + (0x000368ff - 0x0000120c)= rip + 0x356f3,这就是您在上面看到的。
在进行静态分析时,由于Radare不知道内存中二进制文件的基地址,因此它仅计算0x0000120c + 0x356f3= 0x000368ff。这使逆向工程更加容易,但是由于实际的指令是不同的,因此可能造成混乱。
例如,以下程序:
int main(void) {
puts("Hello world!");
}
Run Code Online (Sandbox Code Playgroud)
编译后产生:
int main(void) {
puts("Hello world!");
}
Run Code Online (Sandbox Code Playgroud)
所以rip + 0x99= 0x6bb + 0x99= 0x754,如果我们看一下0x754二进制文件中的offset hd:
6b4: 48 8d 3d 99 00 00 00 lea rdi,[rip+0x99]
6bb: e8 a0 fe ff ff call 560 <puts@plt>
Run Code Online (Sandbox Code Playgroud)
完整说明是
48 8d 3d f3 56 03 00
Run Code Online (Sandbox Code Playgroud)
这条指令是字面上的
lea rdi, [rip + 0x000356f3]
Run Code Online (Sandbox Code Playgroud)
用rip相对寻址模式。指令指针rip在0x0000120c执行指令时具有该值,从而rdi接收所需的值0x000368ff。
如果这不是真实地址,则您的程序可能是与位置无关的可执行文件(PIE),可能会被重定位。由于地址是使用相对相对寻址模式编码的,因此无论二进制文件加载在何处,都无需重定位且地址正确。