WIN32 Inline HOOK
生活随笔
收集整理的這篇文章主要介紹了
WIN32 Inline HOOK
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Inline hook 和CE里面的代碼注入很像(應該是一個東西),這個技術的原理是,修改匯編指令,讓某個指令跳轉到我們定義的函數,然后在函數內完成被替換的指令,然后再跳轉回去。在我們定義的函數內,我們可以實時獲取寄存器的值,從而可以完成對函數行為的監視和修改。
在我們定義的函數內,需要注意,寄存器的值和堆棧狀態,執行前后必須完全一致,否則程序會出錯。為了實現這個目的,我們需要用到裸函數。
下面是代碼,要注意代碼中使用的地址僅在我的機器上有效,如果你要編譯這個程序,第一次運行會失敗,請根據生成的匯編代碼,找到Plus的地址,然后對SetInlineHook的參數1作相應修改。
另外補充一點,如果被替換的代碼不含修改堆棧的指令(如push),則可以用call和ret的方式來實現跳轉,這樣寫起來更方便些。
// InlineHook.cpp : Defines the entry point for the console application. //#include "stdafx.h" #include <windows.h> #include <STDIO.H>int Plus(int x, int y); void HookAddress(); void SetInlineHook(DWORD originalCodeAddr, DWORD originalSize, DWORD newCodeAddr); void UnsetInlineHook(DWORD originalCodeAddr);BYTE g_bOriginCode[64]; // 原始代碼,卸載HOOK時用到 DWORD g_dwOriginCodeSize; // 原始代碼的大小 DWORD g_ret; // HOOK函數內跳轉到原函數的地址int main(int argc, char* argv[]) {// 00401080 55 push ebp// 00401081 8B EC mov ebp,esp// 00401083 83 EC 40 sub esp,40h// 00401080 是Plus的第一行匯編地址,CALL/JMP最少需要5字節,所以要替換這3條指令SetInlineHook(0x00401080,6,(DWORD)HookAddress);printf("%d\n",Plus(1,2));UnsetInlineHook(0x00401080);printf("%d\n",Plus(3,4));return 0; }// 一個普通的函數,將對它設置HOOK int Plus(int x, int y) {return x+y; }// HOOK跳轉的地址 void __declspec(naked)HookAddress() {// 執行被替換的代碼__asm{push ebpmov ebp,espsub esp,40h }// 保存8個常用寄存器和標志寄存器__asm{pushadpushfd}// 我的代碼,功能是查看寄存器狀態// 這段代碼有BUG,不能在裸函數里直接定義變量,而應該使用全局變量// 因為這些變量使用的是上層函數的堆棧// 我懶得改了DWORD _eax,_ecx,_edx,_ebx;__asm{mov _eax,eaxmov _ecx,ecxmov _edx,edxmov _ebx,ebx}printf("eax: %x\n", _eax);printf("ecx: %x\n", _ecx);printf("edx: %x\n", _edx);printf("ebx: %x\n", _ebx);// 恢復寄存器,然后返回__asm{popfdpopadjmp g_ret} }// 設置HOOK的函數 void SetInlineHook(DWORD originalCodeAddr, DWORD originalSize, DWORD newCodeAddr) {if (originalCodeAddr==0||originalSize<5||newCodeAddr==0){printf("參數錯誤\n");return;}// 設置內存寫權限DWORD dwOldProtectFlag;BOOL bRet = VirtualProtectEx(GetCurrentProcess(),(LPVOID)originalCodeAddr,originalSize,PAGE_EXECUTE_READWRITE,&dwOldProtectFlag);if (!bRet){printf("修改內存屬性失敗\n");return;}// 存儲原始硬編碼,卸載的時候要把原始代碼貼回去 memcpy(g_bOriginCode,(LPVOID)originalCodeAddr,originalSize);g_dwOriginCodeSize = originalSize;// 計算E8 CALL后面的4字節 = 要跳轉的地址 - CALL的下一條指令的地址DWORD dwJmpCode = newCodeAddr - (originalCodeAddr + 5);// 將要替換的代碼區域全部初始化為NOPmemset((LPVOID)originalCodeAddr,0x90,originalSize);// HOOK*(PBYTE)originalCodeAddr = 0xE9; // JMP*PDWORD(originalCodeAddr+1) = dwJmpCode;// 設置返回地址g_ret = originalCodeAddr + originalSize;// 恢復內存屬性VirtualProtectEx(GetCurrentProcess(),(LPVOID)originalCodeAddr,originalSize,dwOldProtectFlag,NULL); }// 卸載HOOK的函數 void UnsetInlineHook(DWORD originalCodeAddr) {VirtualProtectEx(GetCurrentProcess(),(LPVOID)originalCodeAddr,g_dwOriginCodeSize,PAGE_EXECUTE_READWRITE,NULL);memcpy((LPVOID)originalCodeAddr,g_bOriginCode,g_dwOriginCodeSize); }執行結果:
該程序對我們定義的Plus函數設置HOOK,然后跳轉到我們定義的裸函數內部,在裸函數里獲取并打印了寄存器的內容,然后執行被替代的匯編指令,最后返回原處執行。
然后我們卸載HOOK之后又調用了一次Plus函數,驗證卸載成功。
總結
以上是生活随笔為你收集整理的WIN32 Inline HOOK的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: IAT HOOK
- 下一篇: vs中使用def导出函数