我正试图在函数中放置一条调用指令来模拟钩子,所以我应该替换函数开头的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个字节被更改?
如您所见,sub esp,0C0h
指令从地址00B533C3开始,但下一条指令push ebx
从地址00B533C9开始。您已经覆盖了地址00B533C0到00B533C5,因此在您的6个字节之后,您立即处于sub esp,0C0h
指令的中间。
反汇编程序无法知道某个字节是垃圾,而不是指令,所以它试图尽可能地将字节解释为指令,当然,你看到的是荒谬的指令。过了一段时间,(巧合的是)一条荒谬指令的结尾与过去的实际指令的结尾重合,所以从那时起,反汇编程序成功地解释了指令,这就是为什么你的函数的其余部分看起来还可以。
如果你观察实际的字节,而不是这些字节的汇编语言助记符解释,你会发现没有什么奇怪的事情发生
(也许,除了您似乎替换了5个字节,而不是6个字节。)