6

我有一些汇编代码,我想找出调用函数原型,以便我可以从 c++ 代码中获取所有函数。

我真正想做的是将dll注入正在运行的进程中,并从我的dll中调用正在运行的进程的函数。现在我已经成功注入了我的 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]

那么如何004BAFAC从Visual C++调用函数呢?

4

2 回答 2

2

在汇编函数中,参数从堆栈中弹出,从最后一个开始。因此,要将参数传递给函数,首先将它们推入堆栈,然后调用该函数。在 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 中对函数进行原型设计时,将所有参数作为 DWORD 原型将起作用(在 C++ 中除外)。

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

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

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

于 2013-03-10T15:16:06.240 回答
2

没有更多细节,真的很难说出发生了什么。由于代码异常,我怀疑该应用程序已被混淆。IDA 可能会让你的运气更好。

简短的回答是,所有函数似乎都采用指向某物的指针eax0057A3F8可能采用 4 字节整数)。很难说这些是指向什么的。您可能需要一个汇编助手来从 C++ 调用这些。


首先,您需要制定调用约定: Both6013BE24004BAFAC似乎采用单个参数 in eax,根据Wikipedia 上的此列表,仅 Borland(fastcall)、Watcom(默认情况下)或 Embarcadero Delphi 使用该参数。您还没有说您正在逆向工程的应用程序是否是用 C++ 编写的,但即使是,我认为如果没有一点汇编,您将很难调用。

6013BE24出现在函数表中查找函数,例如ebx=**(void***)0x60184610(我忘记了指针到函数指针的样子);我会看看这是否指向某处的重定位表。它还需要一个指向结构的指针eax(类似于struct Foo { void * dummy; Bar * bar; ... }),然后大致执行return ebx(eax->bar). 我不知道它是否真的返回任何东西,但它会返回寄存器中返回的任何东西。我不知道为什么它使用ebx而不是不需要保留的寄存器。

004BAFAC设置一个堆栈帧,保留ebx,然后0057A3F8使用 in bar(即 eax) 中的内容进行一些调用。如果bar是 a void**,它看起来像f(bar[2]); f(bar[3]); f(bar[5]); f(bar[6]); f(bar[7]); f(bar[4]); f(bar[8]); f(bar[17]);然后它bar[17]再次加载(并且反汇编结束)。我怀疑bar实际上是某种结构。

0057A3F8似乎在eax.

于 2013-03-10T17:14:49.160 回答