我试图从我注入的c++ dll中获取一个asm函数的原型来调用它。
这里是函数。
PUSH EBP
MOV EBP,ESP
PUSH -1
PUSH Program.0151A5BB
MOV EAX,DWORD PTR FS:[0]
PUSH EAX
SUB ESP,0F8
MOV EAX,DWORD PTR DS:[167D380]
XOR EAX,EBP
MOV DWORD PTR SS:[EBP-14],EAX
PUSH EBX
PUSH ESI
PUSH EDI
PUSH EAX
LEA EAX,DWORD PTR SS:[EBP-C]
MOV DWORD PTR FS:[0],EAX
MOV DWORD PTR SS:[EBP-10],ESP
MOV EDI,EDX
MOV ESI,ECX
MOV DWORD PTR SS:[EBP-4],0
CMP ESI,0FFFF
JE SHORT Program.0117DFC9
CALL Program.01205130
MOV ECX,82
CALL Program.012F2AE0
MOV ECX,ESI
CALL Program.012F3050
MOV ECX,EDI
CALL Program.012F3050
MOV ECX,DWORD PTR SS:[EBP+8]
CALL Program.012F2EA0
MOV ECX,DWORD PTR SS:[EBP+C]
CALL Program.012F3050
MOV ECX,DWORD PTR SS:[EBP+10]
CALL Program.012F2EA0
MOV ECX,DWORD PTR SS:[EBP+14]
CALL Program.012F2EA0
MOV CL,1
CALL Program.012F39B0
MOV DWORD PTR SS:[EBP-4],-1
MOV ECX,DWORD PTR SS:[EBP-C]
MOV DWORD PTR FS:[0],ECX
POP ECX
POP EDI
POP ESI
POP EBX
MOV ECX,DWORD PTR SS:[EBP-14]
XOR ECX,EBP
CALL Program.014BB1AC
MOV ESP,EBP
POP EBP
RETN
下面是一个调用这个函数的例子:
JMP Program.001CDD83
CALL Program.000930A0
MOV ECX,EAX
CALL Program.0024EC10
PUSH EAX ; /Arg4
PUSH DWORD PTR SS:[EBP-168] ; |Arg3
PUSH DWORD PTR DS:[EDI+8] ; |Arg2
PUSH DWORD PTR SS:[EBP-160] ; |Arg1
MOV EDX,DWORD PTR SS:[EBP-16C] ; |
MOV ECX,DWORD PTR SS:[EBP-164] ; |
CALL Program.0006DF80 ; \<---- TARGET FUNCTION
ADD ESP,10
JMP Program.001CDD83
TEST EAX,800
JE SHORT Program.001CDF6D
TEST ESI,ESI
JE Program.001CDD83
CMP ESI,DWORD PTR DS:[72202C]
JE Program.001CDD83
CMP ESI,DWORD PTR DS:[584684]
通过函数调用,我能够推断出这是一个 __fastcall 函数,因为它使用了 EDX 和 ECX 寄存器,并通过堆栈获取4个附加参数。
在调用的瞬间检查栈和寄存器,我可以确定6个参数都是数字。
这是一张刚刚在函数调用时的状态图。
考虑到这些,我做了这样的定义
typedef void(__fastcall *_programFunction)(DWORD ECX, DWORD EDX, DWORD param1, DWORD param2, DWORD param3, DWORD param4);
它调用函数和函数 作品 但我的DLL 崩溃 显示这个错误。
"Debug Error!Run-Time Check Failure #0--ESP的值在一次函数调用中没有正确保存。这通常是由于调用一个用一种调用约定声明的函数,而用另一种调用约定声明的函数指针。"
我很确定这是一个 __fastcall 函数,因为它是唯一一个优先处理 EDX 和 ECX 在栈上。另外,调用函数并没有清理栈,这也是另一个提示,对于 __fastcall
有什么技巧可以从asm代码中推导出函数protptype?
我的思路有什么问题吗?
EDIT:
我查了一下 主要实际 说过
ADD ESP,在你的函数调用后的10在我看来更像是__cdecl:调用者清理栈。如果是一个__fastcall,你应该在最后找到RET 10。–
当我手动将前两个参数添加到 ECX
和 EDX
册。
像这样
typedef void(__cdecl *_targetFunction)(DWORD param1, DWORD param2, DWORD param3, DWORD param4);
_targetFunction fcall= (_targetFunction)(ADD_TARGET_FUNCTION);
__asm
{
mov ECX, ECX_PARAM
mov EDX, EDX_PARAM
}
fcall(param1, pram2, param3, param4);
谢谢!但我为什么要这样做呢?有什么办法可以自动设置寄存器吗?
谢谢你!我想让一个asm函数的原型从我注入的c++ dll中调用它。
由于优化的原因,你偶尔会发现一些函数不完全符合正常的调用习惯。
在这种情况下,解决方案是使用内联汇编,你在问题中已经完成了。
typedef void(__cdecl *_targetFunction)(DWORD param1, DWORD param2, DWORD param3, DWORD param4);
_targetFunction fcall= (_targetFunction)(ADD_TARGET_FUNCTION);
__asm
{
mov ECX, ECX_PARAM
mov EDX, EDX_PARAM
}
fcall(param1, pram2, param3, param4);
有时候就是这样.