日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

WIN32 Inline HOOK

發布時間:2025/3/21 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。