【问题标题】:What does EBP+8 in this case in OllyDbg and Assembler mean?在这种情况下,OllyDbg 和 Assembler 中的 EBP+8 是什么意思?
【发布时间】:2012-06-07 08:32:26
【问题描述】:

我只是在 OllyDbg 中学习汇编和调试技能,以便学习如何使用未记录的函数。现在我遇到了以下问题:

我有以下代码部分(来自 OllyDbg):

MOV EDI,EDI
PUSH EBP
MOV EBP,ESP
MOV EAX, DWORD PTR SS:[EBP+8]
XOR EDX,EDX
LEA ECX, DWORD PTR DS:[EAX+4]
MOV DWORD PTR DS:[EAX], EDX
MOV DWORD PTR DS:[ECX+4],ECX
MOV DWORD PTR DS:[ECX],ECX
MOV DWORD PTR DS:[EAX+C],ECX
MOV ECX, DWORD PTR SS:[EBP+C]

这是函数的开始,目标是找到数据结构。所以我发现它首先将 EBP 推入堆栈,然后将 ESP(当前堆栈指针)移动到 EBP,我认为它现在为函数定义了一个堆栈帧。现在教程说,在流行的布局中,第一个参数放在 [EBP+8],第二个放在 [EBP+C]

这是我不明白的。我怎么知道第一个参数放在 EBP+8 处?

希望有人可以帮助我! 谢谢!

【问题讨论】:

    标签: assembly ollydbg stack-frame


    【解决方案1】:

    您指的是哪种“未记录的函数”?汇编大部分时间只是编译的高级代码。几乎没有任何关于它的“无证”。

    EBP 最常用作函数中的堆栈帧指针,尤其是在 C 调用约定中(也称为 cdecl)。使用这种约定,参数以相反的顺序在堆栈上传递(例如,最后一个参数首先被压入),并且被调用的函数使用EBP 来访问它们。根据您发布的代码,我认为第一个参数可能指向数据结构。看看:

    MOV EAX, DWORD PTR SS:[EBP+8]
    LEA ECX, DWORD PTR DS:[EAX+4]
    MOV DWORD PTR DS:[EAX], EDX
    MOV DWORD PTR DS:[ECX+4],ECX
    MOV DWORD PTR DS:[ECX],ECX
    MOV DWORD PTR DS:[EAX+C],ECX
    MOV ECX, DWORD PTR SS:[EBP+C]
    

    第一条指令将第一个参数移动到EAX。然后将偏移量 4 添加到该参数并移动到 ECX。请注意,这是由LEA 指令完成的,它是“加载有效地址”的简写。它用于无符号算术,编译器喜欢在进行指针算术和添加偏移量时使用它 - 所以每当你看到这条指令时,你应该警惕它对 可能 的任何操作都是指向结构的指针.当然,没有办法确定。稍后我们有一些MOVs 往返于该地址,其中ECX 用于访问内存。这些结构(如果存在)在 C 语言中看起来像这样:

    struct a { /* pointed to by EAX / [EBP+8] */
        int memb1; /* MOV DWORD PTR DS:[EAX], EDX */
        struct b* memb2; /* LEA ECX, DWORD PTR DS:[EAX+4] */
        int memb3; /* unused? */
        int memb4; /* MOV DWORD PTR DS:[EAX+C],ECX */
    };
    
    struct b {
        int memb1; /* MOV DWORD PTR DS:[ECX],ECX */
        int memb2; /* MOV DWORD PTR DS:[ECX+4],ECX */
    };
    

    希望这能以某种方式解决问题。逆向工程汇编代码是一项非常艰巨且耗时的任务,尤其是在您没有任何 API 调用来告诉您应用程序使用的参数类型的情况下。

    【讨论】:

    • 该函数从 NTDLL.DLL 调用 RtlInitializeGenericTable。该函数末尾有一个 RET 14,我认为这意味着它使用 stdcall 调用约定。对我来说,仍然不清楚您如何确定传递给函数的第一个参数位于 EBP+8 处?
    • 假设函数使用C调用约定并建立一个基于ebp的栈帧,函数的第n个参数放在EBP+4+4n,从n开始= 1.RET 14并不一定意味着完全抛弃cdecl:它只是意味着调用者在调用函数后不必清理堆栈空间。
    • 对不起,愚蠢的问题。好的,现在我知道第一个参数放在 EBP+4+4n 处,如果 n = 1,那么它是 EBp+8。这很有帮助。你怎么知道参数放在 EBP+4+4n ?为了获得这种知识,您是否有任何链接或提示我应该学习或经历什么。我想我在这里缺少一些基本知识......
    • 是的,这是关于堆栈帧的外观以及使用 C 调用约定时如何处理参数的基本知识。看看:msdn.microsoft.com/en-us/library/zkwh89ks(VS.80).aspxcodeproject.com/Articles/1388/Calling-Conventions-Demystifiedsco.com/developers/devspecs/abi386-4.pdf(从第 35 页开始)。
    • 啊,我想我明白了。你能确认我是否理解正确:参数被压入堆栈,然后调用函数。然后前 4 个字节被压​​入,这是返回地址,以便在函数之后跳转回来。然后我们将当前的 EBP 地址压入堆栈,然后保存它。又是 4 个字节!现在,当我们查看时,我们需要将 4 个字节返回到返回地址,然后将 4 个字节返回到第一个参数,即 EBP+8。这对吗?
    猜你喜欢
    • 2020-04-04
    • 2017-03-28
    • 2016-08-26
    • 2014-10-27
    • 2019-10-15
    • 2020-11-03
    • 1970-01-01
    • 1970-01-01
    • 2012-04-21
    相关资源
    最近更新 更多