我有一些汇编代码,我想找出调用函数的原型(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/