c++ - 如何从汇编代码中找出函数原型(prototype)?

标签 c++ visual-studio visual-c++ assembly reverse-engineering

我有一些汇编代码,我想找出调用函数的原型(prototype),以便我可以从 C++ 代码中调用所有函数。

我真正想做的是将一个 dll 注入(inject)到正在运行的进程中,并从我的 dll 中调用正在运行的进程的函数。现在我已经成功注入(inject)了我的 dll 但不知道如何进行“调用”。

我是新手,对汇编代码了解不多。我的 dll 是用 visual c++ 2012 编写的。

这是运行过程的代码:

CPU Disasm
Address   Hex dump          Command                                  Comments
6013BE24  /$  53            PUSH EBX
6013BE25  |.  8B1D 10461860 MOV EBX,DWORD PTR DS:[60184610]
6013BE2B  |.  8B1B          MOV EBX,DWORD PTR DS:[EBX]
6013BE2D  |.  8B40 04       MOV EAX,DWORD PTR DS:[EAX+4]
6013BE30  |.  FFD3          CALL EBX
6013BE32  |.  5B            POP EBX
6013BE33  \.  C3            RETN

你可以看到 6013BE30 正在调用函数,而函数(EBX)在 004BAFAC

CPU Disasm
Address   Hex dump          Command                                  Comments
004BAFAC  /$  55            PUSH EBP                                 ; Test.004BAFAC(guessed void)
004BAFAD  |.  8BEC          MOV EBP,ESP
004BAFAF  |.  53            PUSH EBX
004BAFB0  |.  8BD8          MOV EBX,EAX
004BAFB2  |.  8B43 08       MOV EAX,DWORD PTR DS:[EBX+8]
004BAFB5  |.  E8 3EF40B00   CALL 0057A3F8                            ; [Test.0057A3F8
004BAFBA  |.  8B43 0C       MOV EAX,DWORD PTR DS:[EBX+0C]
004BAFBD  |.  E8 36F40B00   CALL 0057A3F8                            ; [Test.0057A3F8
004BAFC2  |.  8B43 14       MOV EAX,DWORD PTR DS:[EBX+14]
004BAFC5  |.  E8 2EF40B00   CALL 0057A3F8                            ; [Test.0057A3F8
004BAFCA  |.  8B43 18       MOV EAX,DWORD PTR DS:[EBX+18]
004BAFCD  |.  E8 26F40B00   CALL 0057A3F8                            ; [Test.0057A3F8
004BAFD2  |.  8B43 1C       MOV EAX,DWORD PTR DS:[EBX+1C]
004BAFD5  |.  E8 1EF40B00   CALL 0057A3F8                            ; [Test.0057A3F8
004BAFDA  |.  8B43 10       MOV EAX,DWORD PTR DS:[EBX+10]
004BAFDD  |.  E8 16F40B00   CALL 0057A3F8                            ; [Test.0057A3F8
004BAFE2  |.  8B43 20       MOV EAX,DWORD PTR DS:[EBX+20]
004BAFE5  |.  E8 0EF40B00   CALL 0057A3F8                            ; [Test.0057A3F8
004BAFEA  |.  8B43 44       MOV EAX,DWORD PTR DS:[EBX+44]
004BAFED  |.  E8 06F40B00   CALL 0057A3F8                            ; [Test.0057A3F8
004BAFF2  |.  8B43 44       MOV EAX,DWORD PTR DS:[EBX+44]

那么如何在 Visual C++ 中调用 004BAFAC 处的函数呢?

最佳答案

在汇编函数中,参数从栈中弹出,从最后一个开始。因此,要将参数传递给函数,首先将它们压入堆栈,然后调用函数。在 MASM 中,这看起来类似于显示消息框:

.data 
MsgBoxCaption  db "Attention",0 
MsgBoxText     db "Hello Message Box!",0 

.code
start:
push 0
mov eax, offset MsgBoxCaption
push eax
push offset MsgBoxText
push 0
call MessageBoxA
call ExitProcess
end start

虽然在 C++ 中它看起来像这样:

int retval = MessageBox(NULL, "Hello Message Box!", "Attention", 0);

用 OllyDbg 反汇编你会得到:

CPU Disasm
Address   Hex dump          Command                                  Comments
011D13C0  |.  6A 00         PUSH 0                                   ; /Type = MB_OK|MB_DEFBUTTON1|MB_APPLMODAL
011D13C2  |.  68 54571D01   PUSH OFFSET 011D5754                     ; |Caption = "Attention"
011D13C7  |.  68 3C571D01   PUSH OFFSET 011D573C                     ; |Text = "Hello Message Box!"
011D13CC  |.  6A 00         PUSH 0                                   ; |hOwner = NULL
011D13CE  |.  FF15 40831D01 CALL DWORD PTR DS:[<&USER32.MessageBoxA> ; \USER32.MessageBoxA

返回值存储在 eax 中。您会看到,如果数据类型大于 DWORD(4 字节),您实际上不是在传递值,而是在传递引用。每个参数实际上只是一个 DWORD。这是因为堆栈在 32 位系统中是 32 位对齐的,因此只能保存 32 位值。寄存器的情况也是如此。在 32 位系统中,寄存器是 32 位宽。如果传递字符串,则传递的是对该字符串的引用,而不是字符串,也不是可变宽度的字符/字节数组。在 Integer 的情况下,它很可能作为值而不是引用传递。当在 MASM 中对函数进行原型(prototype)设计时,将所有参数作为 DWORD 进行原型(prototype)设计(但在 C++ 中则不行)。

因此在您上面的示例中,似乎有一个参数被传递到堆栈上(push ebx)。我说看起来像,因为它很可能只是将 ebx 推送到存储它以供以后检索(即,在再次弹出调用 ebx 之后 - 也许存储在 ebx 中的值需要保留)。您只能在实际运行实时调试 session 并观察堆栈/寄存器时才能确定。跳过调用并检查前后的堆栈指针 (esp) 以查看有多少参数传递给函数(同样:1 个参数 = 1 个 DWORD = 4 个字节)。

要在 C++ 中对您的函数进行原型(prototype)设计,您需要弄清楚参数的数据类型,可能是通过单步执行汇编代码并在围绕相关函数遍历代码时检查寄存器和/或堆栈。 eax 中的返回值也是如此。所以 eax 永远不会保存字符串,而可能是对字符串的引用,但它可能保存 32 位或更小的整数。您还必须通过逆向周围的代码来找出 eax 指向的数据类型。

编辑:实际上我写的东西有一半是错误的,最值得注意的是参数总是引用,所以请重读我写的东西。对于给您带来的不便,我们深表歉意 - 累了就不应该回答问题:)

关于c++ - 如何从汇编代码中找出函数原型(prototype)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15323056/

相关文章:

c++ - eclipse "crossGCC"

c++ - 列出/设置使 & C++ 搜索头文件的目录

c++ - 强制包含可以与 Visual C++ 中的预编译 header 一起使用吗?

c++ - 如何通过队列指针访问存储在节点中的类中的数据?

visual-studio - 智能感知如何在 Visual Studio 中工作?

C# 如何检查解决方案配置

c# - 在 C# .NET 项目中使用 C++ 包装器

visual-c++ - C++ 项目中文件版本中的自定义字段

c++ - 将日期/时间值写入注册表

c++ - 迭代器是否支持+运算符?