源代码见后文。
在debug版本中总是出现堆栈平衡检查通不过的情况~~单步跟了一下发现是在detour函数里检查堆栈平衡前没有保存前一栈帧的ESI,导致当前堆栈平衡检查完之后的ESI保存的是当前函数被调用前的ESP,和上一层调用者的ESP不一样,所以__RTC_CheckEsp的时候报错。
解决办法很简单,detour函数里调函数前保存一下ESI,完了之后再恢复,这样就不会在debug版本中报堆栈平衡被破坏的bug了:)
(MyMessageBoxA函数里那两个条件编译~~)
代码
#include <windows.h> #include <iostream> //using namespace std; DWORD head;//保存API返回地址 int nRet; BYTE orig_code[5] = {0x90, 0x90, 0x90, 0x90, 0x90};//存放原始的指令 BYTE hook_code[5] = {0xe9, 0, 0, 0, 0};//存放跳转到MyMessageBoxA的指令 BYTE jmp_org_code[5] = {0xe9, 0, 0, 0, 0};//存放跳转到原起始地址后5字节的指令 int MyMessageBoxA( HWND hWnd, // handle to owner window LPCTSTR lpText, // text in message box LPCTSTR lpCaption, // message box title UINT uType // message box style ); int MyMessageBoxAA( HWND hWnd, // handle to owner window LPCTSTR lpText, // text in message box LPCTSTR lpCaption, // message box title UINT uType // message box style ); int MyFunc(); void Hook(); int jmp_back(); ULONG OldFuncAddr; ULONG MyFuncAddr; ULONG jmp_backAddr; //在修改前几个字节时,注意:取出的指令为完整的 int main() { Hook(); int rt = MessageBoxA(NULL, "Hello World", "Title", MB_OK); // cout << rt << endl;//查看返回值是否已修改成功 getchar(); system("pause"); return 0; } void Hook() { DWORD dwOldProtect; OldFuncAddr = (ULONG)MessageBoxA; // MyFuncAddr = MyMessageBoxA的实际地址 MyFuncAddr = *(ULONG *)((BYTE *)MyMessageBoxA+1) + (ULONG)MyMessageBoxA + 5; // jmp_backAddr = jmp_back的实际地址 jmp_backAddr = *(ULONG *)((BYTE *)jmp_back+1) + (ULONG)jmp_back + 5; //修改内存为PAGE_EXECUTE_READWRITE VirtualProtect((LPVOID)jmp_backAddr, 10, PAGE_EXECUTE_READWRITE, &dwOldProtect); VirtualProtect((LPVOID)OldFuncAddr, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect); //计算跳转地址 *((ULONG*)(hook_code+1)) = (ULONG)MyFuncAddr - (ULONG)OldFuncAddr - 5; memcpy(orig_code,(BYTE *)OldFuncAddr, 5); memcpy((BYTE*)OldFuncAddr, hook_code, 5); //计算返回地址 *((ULONG*)(jmp_org_code+1)) = (ULONG)OldFuncAddr - (ULONG)jmp_backAddr - 5; memcpy((BYTE *)jmp_backAddr, orig_code, 5); memcpy((BYTE *)jmp_backAddr + 5, jmp_org_code, 5); } __declspec(naked) int jmp_back() { __asm { _emit 0x90 _emit 0x90 _emit 0x90 _emit 0x90 _emit 0x90 _emit 0x90 _emit 0x90 _emit 0x90 _emit 0x90 _emit 0x90 } } //MyMessageBoxA:在函数执行前进行自己的处理 __declspec(naked) int MyMessageBoxA( HWND hWnd, // handle to owner window LPCTSTR lpText, // text in message box LPCTSTR lpCaption, // message box title UINT uType // message box style ) { #ifdef DEBUG __asm push esi #endif printf("MyMessageBoxA is called\r\n"); #ifdef DEBUG __asm pop esi #endif __asm { pop head pop hWnd pop lpText pop lpCaption pop uType } MyFunc();////可以加入函数过程 __asm { //压栈过程 push uType push lpCaption push lpText push hWnd push head //跳回MessageBoxA入口点 jmp jmp_back; ret; } } int MyFunc() { printf("Hello World\r\n"); return 1; }