返回介绍

7.1 X86

发布于 2025-02-22 14:00:43 字数 2845 浏览 0 评论 0 收藏 0

7.1.1 MSVC

如下为相应的反汇编代码(MSVC 2010 Express)

Listing 7.2 MSVC 2010 Express

#!bash
_TEXT   SEGMENT
_a$ = 8                                  ; size = 4
_b$ = 12                                 ; size = 4
_c$ = 16                                 ; size = 4
_f      PROC
        push ebp
        mov ebp, esp
        mov eax, DWORD PTR _a$[ebp]
        imul eax, DWORD PTR _b$[ebp]
        add eax, DWORD PTR _c$[ebp]
        pop ebp
        ret 0
_f      ENDP

_main   PROC
        push ebp
        mov ebp, esp
        push 3 ; 3rd argument
        push 2 ; 2nd argument
        push 1 ; 1st argument
        call _f
        add esp, 12
        push eax
        push OFFSET $SG2463 ; ’%d’, 0aH, 00H
        call _printf
        add esp, 8
        ; return 0
        xor eax, eax
        pop ebp
        ret 0
_main ENDP

我们可以看到函数 main() 中 3 个数字被圧栈,然后函数 f(int, int, int) 被调用。函数 f() 内部访问参数时使用了像_ a$=8 的宏,同样,在函数内部访问局部变量也使用了类似的形式,不同的是访问参数时偏移值(为正值)。因此 EBP 寄存器的值加上宏_a$的值指向压栈参数。

_a$[ebp] 的值被存储在寄存器 eax 中,IMUL 指令执行后,eax 的值为 eax 与 _b$[ebp] 的乘积,然后 eax 与 _c$[ebp] 的值相加并将和放入 eax 寄存器中,之后返回 eax 的值。返回值作为 printf() 的参数。

7.1.2 MSVC+OllyDbg

我们在 OllyDbg 中观察,跟踪到函数 f() 使用第一个参数的位置,可以看到寄存器 EBP 指向栈底,图中使用红色箭头标识。栈帧中第一个被保存的是 EBP 的值,第二个是返回地址(RA),第三个是参数 1,接下来是参数 2,以此类推。因此,当我们访问第一个参数时 EBP 应该加 8(2 个 32-bit 字节宽度)。

enter image description here

Figure 7.1: OllyDbg: 函数 f() 内部

7.1.3 GCC

使用 GCC4.4.1 编译后在 IDA 中查看

Listing 7.3: GCC 4.4.1

#!bash
            public f
f           proc near

arg_0       = dword ptr 8
arg_4       = dword ptr 0Ch
arg_8       = dword ptr 10h

            push    ebp
            mov     ebp, esp
            mov     eax, [ebp+arg_0]  ; 1st argument
            imul    eax, [ebp+arg_4]  ; 2nd argument
            add     eax, [ebp+arg_8]  ; 3rd argument
            pop     ebp
            retn
f           endp

            public main
main        proc near

var_10      = dword ptr -10h
var_C       = dword ptr -0Ch
var_8       = dword ptr -8

            push    ebp
            mov     ebp, esp
            and     esp, 0FFFFFFF0h
            sub     esp, 10h
            mov     [esp+10h+var_8], 3  ; 3rd argument
            mov     [esp+10h+var_C], 2  ; 2nd argument
            mov     [esp+10h+var_10], 1  ; 1st argument
            call    f
            mov     edx, offset aD ; "%d
"
            mov     [esp+10h+var_C], eax
            mov     [esp+10h+var_10], edx
            call    _printf
            mov     eax, 0
            leave
            retn
main    endp

几乎相同的结果。

执行两个函数后栈指针 ESP 并没有显示恢复,因为倒数第二个指令 LEAVE(B.6.2)会自动恢复栈指针。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文