【发布时间】:2019-06-14 22:05:10
【问题描述】:
我拿起了《实用逆向工程》这本书,在第 14 页(x86 汇编)上有以下示例:
mov eax, 0AAAAAAAh
mov ebx, 0BBBBBBBh
push eax
push ebx
pop esi
pop edi
现在,我将 eax 和 ebx 推入堆栈,但我弹出堆栈的 esi 和 edi。这是为什么?我以为我会推送和弹出相同的寄存器。
【问题讨论】:
-
你可以弹出到任何你想要的寄存器(或内存)。堆栈不会跟踪值是如何到达那里的。这个技巧通常出现在针对大小优化的利用代码中,而不是使用更多字节的
mov。 -
啊啊! pop esi 告诉 pop 的目的地。我认为您必须指定要弹出的内容。但现在我发现这毫无意义,因为您只能弹出堆栈顶部的内容。谢谢!
-
是的,
push/pop/call/ret与普通的内存存储/加载非常相似,除了那些指令隐式使用esp值作为“栈顶指针”,因此很自然地将它们用于“LIFO” "(后进先出)类型的队列。但是您应该能够识别它背后的简单内存操作(尽管比尝试通过sub esp,4mov [esp],eax而不是push eax来复制它更原子) -
@Jester:它仅在 x86-64 长模式下保存字节以复制 64 位寄存器,例如
push rbx / pop rdi(1 + 1 字节)与mov rdi, rbx(3 字节:REX +操作码 + modrm)。在 32 位代码中,复制带有mov esi,ebx的寄存器仍然只有 2 个字节。也许您正在考虑将寄存器设置为一个小的立即数,例如push 1/pop eax(2 + 1 个字节)与mov eax, 1(5 个字节,因为没有可用的 mov r/m32,sign_extended_imm8 编码)。 -
你推送的是值,而不是寄存器。这些值通常来自来自寄存器,但即使这样也不是必需的。您在此处弹出 寄存器。