更换汇编指令会更改其他指令

时间:2015-02-06 23:44:03

标签: c++

我试图在一个函数上放置一个调用指令来模拟一个钩子,所以我应该在函数的开头替换6个字节来放置我的调用,对于操作码是2个字节,对于地址是dword。但是在我挂钩之前这是函数的反汇编

void realFunction()
{
00B533C0  push        ebp  
00B533C1  mov         ebp,esp  
00B533C3  sub         esp,0C0h  
00B533C9  push        ebx  
00B533CA  push        esi  
00B533CB  push        edi  
00B533CC  lea         edi,[ebp-0C0h]  
00B533D2  mov         ecx,30h  
00B533D7  mov         eax,0CCCCCCCCh  
00B533DC  rep stos    dword ptr es:[edi]  
    MessageBox(NULL, "realFunction()", "Trace", MB_OK);
00B533DE  mov         esi,esp  
00B533E0  push        0  
00B533E2  push        0B56488h  
00B533E7  push        0B56490h  
00B533EC  push        0  
00B533EE  call        dword ptr ds:[0B5613Ch]  
00B533F4  cmp         esi,esp  
00B533F6  call        _RTC_CheckEsp (0B53A10h)  
}

奇怪的是,我只需要替换6个字节

void realFunction()
{
00B533C0  call        fakeFunction (0B52EF0h)  
00B533C5  rol         byte ptr [eax],0 <-- 
00B533C8  add         byte ptr [ebx+56h],dl <--
00B533CB  push        edi <--
00B533CC  lea         edi,[ebp-0C0h] <--
00B533D2  mov         ecx,30h  
00B533D7  mov         eax,0CCCCCCCCh  
00B533DC  rep stos    dword ptr es:[edi]  
    MessageBox(NULL, "realFunction()", "Trace", MB_OK);
00B533DE  mov         esi,esp  
00B533E0  push        0  
00B533E2  push        0B56488h  
00B533E7  push        0B56490h  
00B533EC  push        0  
00B533EE  call        dword ptr ds:[0B5613Ch]  
00B533F4  cmp         esi,esp  
00B533F6  call        _RTC_CheckEsp (0B53A10h)  
}

钩子的代码

#include <iostream>
#include <windows.h>

using namespace std;

void realFunction()
{
    MessageBox(NULL, "realFunction()", "Trace", MB_OK);
}

__declspec(naked) void fakeFunction()
{
    __asm {
        pushad;
        pushfd;
    }

    MessageBox(NULL, "fakeFunction()", "Trace", MB_OK);

    __asm{
        popfd;
        popad;
        ret; //This should return back and resumes the execution of the original function;
    }
}

void main()
{
    DWORD size = sizeof(double);
    DWORD oldProtection;
    DWORD realFunctionAddr = (DWORD)realFunction;
    DWORD fakeFunctionAddr = (DWORD)fakeFunction;

    VirtualProtect((LPVOID)realFunctionAddr, size, PAGE_EXECUTE_READWRITE, &oldProtection);
    *((PBYTE)(realFunctionAddr)) = 0xE8;
    *((PDWORD)(realFunctionAddr + 1)) = fakeFunctionAddr - realFunctionAddr - 5;
    VirtualProtect((LPVOID)fakeFunctionAddr, size, oldProtection, &oldProtection);

    realFunction();

    while (true){
        cin.get();
    }
}

我想了解为什么会发生这种情况,为什么不更改我更换的6个字节?

1 个答案:

答案 0 :(得分:2)

如您所见,sub esp,0C0h指令从地址00B533C3开始,但下一条指令push ebx从地址00B533C9开始。您已经覆盖了地址00B533C0到00B533C5,因此在您的6个字节之后立即处于sub esp,0C0h指令的中间位置。

反汇编程序无法知道某个字节是垃圾而不是指令,因此它会尝试尽可能地将字节解释为指令,当然,您看到的是无意义的指令。过了一段时间(巧合)恰好发生了一个荒谬的指令的结束与过去的实际指令的结束一致,所以从反汇编程序的那一点开始成功地解释了指令,这就是为什么你的函数的其余部分看起来还不错。

如果你查看实际的字节,而不是汇编语言对这些字节的助记符解释,你会看到没有任何时髦的事情发生。

(或许,除非您似乎已经替换了5而不是6个字节。)