我是逆向工程的初学者,作为一个初学者,我开始读“面向初学者的逆向工程”。 >

现在,让我们尝试在Linux的GCC 4.4.1编译器中编译相同的C / C ++代码:
gcc 1.c -o 1接下来,在IDA反汇编程序的帮助下,让我们看看main()函数是如何创建的。 IDA和MSVC一样,都使用Intel-syntax5。


main proc near

var_10 = dword ptr -10h

     push ebp
     mov ebp, esp
     and esp, 0FFFFFFF0h
     sub esp, 10h
     mov eax, offset aHelloWorld ; "hello, world\n"
     mov [esp+10h+var_10], eax
     call _printf
     mov eax, 0
     leave
     retn
main endp


有两行我根本听不懂:


and esp, 0FFFFFFF0h
sub esp, 10h

据我了解,我们将0FFFFFFF0h(等于-16)值添加到ESP中,以便将堆栈对齐到16字节边界以进行优化。

我的问题是:为什么我们要加-16然后减去16到堆栈中?对我来说似乎毫无意义,难道我们不能直接减去32吗?
其次,如果我很好理解:


该程序以EBP = ESP开头,因为没有在堆栈上。
然后将EBP推入堆栈。假设程序为64位,则ESP现在为EBP-8(因为64位)。现在我们有了ESP!= EBP。
然后我们将ESP的内容复制到EBP中。因此,我们有EBP = ESP和EBP = fristEBP(程序启动时为EBP)-8.

为什么我们需要修改EBP的值? PUSH指令应该更改ESP的值,而不是EBP的值,所以为什么在函数prolog上不修改EBP值会有什么问题?


所以现在有了EBP = ESP,两者都是fristEBP(程序启动时为EBP)-8。所以现在我们将-16添加到堆栈中,因此ESP变为ESP-16(如果我们考虑一直在堆栈中添加-8,则为ESP-24)。 。
-16字节边界与-24有什么关系?
为什么还要用sub esp, 10h从堆栈中再次减去16?


注意:对不起英语,对不起,如果我问的是愚蠢的问题,这本书还不够清晰,我在网上找不到解释。

评论

并且不添加将堆栈对齐到16个字节边界,即123456a1和fffffff0将导致123456a0

不会有丢失数据的风险吗?

#1 楼

在第一个操作码中不是add。是and。因此,它将清除地址中最后一个字节的低位半字节。这是完成对齐的方式,而不需要添加任何内容。只有稍后您sub 16才有空间容纳局部变量。


为什么我们需要修改EBP的值? EBP存储初始ESP值。 EBP指向当前的堆栈框架。这是随函数创建的局部变量的地方。在修改EBP之前,它已存储在堆栈中,以便我们可以在离开函数之前对其进行恢复。

评论


好的,我明白了,但是如果我们想清除较低的半字节,为什么还要添加0FFFFFFF0h而不是0FFFFFFF0F?

–黑暗
18年5月31日在9:48

低位半字节是3-0位,那么为什么我们要在7-4位上放0来做到这一点?

–PawełŁukasik
18年5月31日在9:53

我看错了,对不起

–马克
18年5月31日在10:01

好的别担心!

–PawełŁukasik
18年5月31日在10:22