使用汇编和C++调用一个函数两次

4
我是一个有用的助手,可以翻译文本。
我有一段代码,它会将要调用的函数更改为我的新函数,但我不仅想调用我的新函数,还想调用旧函数。这是一个例子,让您了解我的意思:
如果我反汇编我的.exe文件,我将看到以下部分:
L00123456:
      mov   eax, [L00654321] //doesn't matter
      mov   ecx, [eax+1Ch]   //doesn't matter
      push  esi              //the only parameter
0x123 call  SUB_L00999999    //this is the function I wanna overwrite
      //...

英译中:

(0x123 是那行的地址) 所以,我用了这段代码:

DWORD old;
DWORD from = 0x123;
DWORD to   = MyNewFunction;
VirtualProtect(from, 5, PAGE_EXECUTE_READWRITE, &old);

DWORD disp = to - (from + 5);
*(BYTE *)(from) = 0xE8;
*(DWORD *)(from + 1) = (DWORD)disp;

现在,它不再调用SUB_L00999999函数,而是调用MyNewFunction函数...那么,你有什么想法如何仍然调用旧函数吗?我尝试过很多方式,但都会导致我的应用程序崩溃。
int MyNewFunction(int parameter)
{
    DWORD oldfunction = 0x00999999;
    _asm push parameter
    _asm call oldfunction
}

注:我使用的是Visual Studio C++ 2010,这些代码在一个.exe中加载的.dll文件中。
谢谢。
2个回答

2

ret指令期望栈顶的参数是返回地址。你可以通过在新函数的ret指令之前立即将旧函数地址推入栈中来利用这一点。当调用返回(或者更确切地说,分支到旧函数)时,栈指针会移动以使原始返回地址(这里是0x128)位于栈顶,因此栈看起来没有受到破坏。(与没有绕路时一样)。


1
尝试使用 _asm { push oldfunction; ret 4 } 并通过调试器检查输出。我不确定C编译器是否会添加/删除其他可能会破坏堆栈的内容。当进入oldfunction时,堆栈应该与进入newfunction时完全相同。 (哦,还有一些寄存器可能需要相同,您可能需要在retn之前设置它们)。 - Mark H
你的答案也可以工作,但是由于我们不仅需要使用我的参数调用函数,还需要返回到旧的堆栈然后调用函数,所以这更加复杂。我在某个项目文件中看到过这种方式,并尝试以这种方式进行操作,但比@myeviltacos的方式更难。谢谢你的帮助。 - Toribio

2
我之前遇到过类似的问题。无论如何,_asm call dword ptr [oldfunction] 对我有效。

谢谢,伙计。这个很好用,我不记得我有些时候以前用过它了... - Toribio

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接