我已经反汇编了一个使用 Cscanf
函数的x86 elf 二进制文件。
以下是与scanf
相关的反汇编代码块:
0x0804857a 89442404 mov dword [esp + 0x4], eax
0x0804857e c70424b28604. mov dword [esp], 0x80486b2
0x08048585 e8eafdffff call sym.imp.scanf
通过gdb
检查,地址0x80486b2
处的内存包含数据0x7325
(ASCII代码中的">%s"字符串)。
因此,这段代码显然是在堆栈上以相反的顺序推送scanf
参数,以便使用这两个参数调用scanf
。
这通常用 C 语言编码为scanf ("%s", &somevar);
鉴于汇编代码,我在这里所期望的是常量0x80486b2
的32 位表示形式被加载到堆栈指针指向的地址中......
相反,mov
指令已将地址0x80486b2
处的任何内容的 32 位表示形式加载到堆栈指针指向的地址中......是吗?
所以我们基本上得到的是,mov
刚刚将数据从一个内存位置移动到另一个内存位置,根据这个 x86 程序集介绍(在众多其他来源中)这是非法的(重点是我的):
在需要内存传输的情况下,源内存 内容必须首先加载到寄存器中,然后才能存储到 目标内存地址。
这里没有使用登记册作为中介。
这怎么可能?
如果我理解得很好,这里的
mov
指令将地址0x80486b2处的任何内容的 32 位表示形式加载到堆栈指针指向的地址中......是吗?
不。指令
mov dword [esp], 0x80486b2
将0x80486B2
的即时值复制到寄存器ESP
指向的地址。这个地方是传递给scanf
函数的第一个参数。
所以我们基本上得到的是
mov
刚刚将数据从一个内存位置移动到另一个内存位置, [...]
不。该指令将立即的 32 位值移动到内存位置。在这种情况下,MOV 的指令签名为:
MOV r/m32, imm32 Move imm32 to r/m32.
值0x80486b2
写入寄存器 ESP 指向的 DWORD 内存地址。
指令mov dword [esp + 0x4], eax
确实将第二个参数从EAX
传递到scanf
。
指令mov dword [esp], 0x80486b2
将 32 位即时值0x80486b2移动到 ESP 指向的 32 位内存位置。 如果它将存储地址0x80486b2的 32 位值移动到目标中,则它将被写入为mov dword [esp], dword [0x80486b2]
。但是,这不是 MOV 指令允许的操作数组合。
请注意,您的反汇编使用的是 NASM 语法。