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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

WIN32练习项目(函数调用监视器)

發布時間:2025/3/21 编程问答 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 WIN32练习项目(函数调用监视器) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、簡介

這是滴水三期WIN32最后一個項目,進程通信用的是共享內存的方式。


通過內存注入方式向目標進程victim注入DLL,監視程序可以通過IAT HOOK監視目標進程調用MessageBoxA,CreateFileA,通過inline HOOK監視victim自己實現的Add函數。另外,監視程序還可以遠程調用這三個函數。

二、運行結果

注入

監控MessageBoxA

項目和可執行文件可以到我的github下載
https://github.com/Kwansy98/WIN32hanshudiaoyongjianshiqi

三、目標程序Victim.exe

victim是要注入的程序,界面如下圖:

這個程序可以創建對話框,調用CreateFileA獲取文件句柄并打印文件大小,可以做加法運算。沒什么特別的,你可以自己寫一個。

四、控制程序HackVictim.exe

這個程序的界面如下圖:

為了方便調試,我創建該項目時用的是控制臺項目的模板,在main函數里畫界面。這樣可以方便的printf。

該程序的功能是將DLL用內存注入的方式注入到指定進程,注入成功后可以監視目標程序的函數調用,前兩個函數是IAT表里有的,第三個函數是目標程序自己實現的加法函數。

點擊“開始監控”后,在目標程序victim調用函數后,會有控制臺輸出。也可以點擊“遠程調用”來遠程調用指定函數。

IAT HOOK和Inline HOOK經測試可以正常卸載。

講一下控制程序的注意點(坑點和難點)
內存注入這塊,我是從文件系統中讀取dll,然后拉伸,然后修復IAT,然后修復重定位,然后用VirtualAllocEx 和WriteProcessMemory完成注入的。需要注意一點就是IAT表里面只有kernel32.dll和user32.dll的函數是正確的(比如LoadLibrary,MessageBox),因為這兩個dll不管在哪個進程里位置都固定,其他dll里的函數的地址全是錯的。

注入之后要計算入口點地址,創建遠程線程時傳的地址是遠程進程中的入口函數,這個值得計算方法是: 入口點到DLL基址的偏移 + 遠程DLL基址。

五、DLL

這部分是核心,是本項目最難的環節。DLL被控制程序注入到目標程序后,很多函數都要自己手動獲取函數地址(通過LoadLibrary+GetProcAddress)。

typedef int (*PFNSPRINTF)( char *, const char *,...); typedef void* (*PFNMALLOC)(size_t); typedef void (*PFNFREE)(void*); typedef void* (*PFNMEMSET)(void*,int,size_t); typedef void* (*PFNMEMCPY)(void*,void*,size_t); typedef size_t (*PFNSTRLEN)(const char *); ...... PFNSPRINTF _sprintf; PFNMALLOC _malloc; PFNFREE _free; PFNMEMSET _memset; PFNMEMCPY _memcpy; PFNSTRLEN _strlen; ...... // 手動加載要用到的函數 HMODULE hModule = LoadLibraryA("MSVCRT.dll"); _sprintf = (PFNSPRINTF)GetProcAddress(hModule, "sprintf"); _malloc = (PFNMALLOC)GetProcAddress(hModule, "malloc"); _free = (PFNFREE)GetProcAddress(hModule, "free"); _memset = (PFNMEMSET)GetProcAddress(hModule, "memset"); _memcpy = (PFNMEMCPY)GetProcAddress(hModule, "memcpy"); _strlen = (PFNSTRLEN)GetProcAddress(hModule, "strlen");

為了方便調試,我給DLL申請了個控制臺,自己封裝了一個輸出函數,當然,肯定沒有printf好用了。

// 申請控制臺 AllocConsole(); g_hStdout = CreateFileA("CONOUT$",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_WRITE,0,OPEN_EXISTING,0,0); //SetStdHandle(STD_OUTPUT_HANDLE,hStdout); Log("申請控制臺成功\n"); ...... void Log(LPCSTR text) {WriteFile(g_hStdout,text,_strlen(text),0,0); }

有一個坑點需要注意,我們寫自己修改的MessageBoxA,CreateFileA函數時,記得要寫上調用約定WINAPI,不寫的話程序會崩潰。

// 被監控的MessageBox int WINAPI MyMessageBoxA(HWND hWnd,LPCTSTR lpText,LPCTSTR lpCaption,UINT uType) {typedef int (WINAPI *PFNMESSAGEBOX)(HWND,LPCTSTR,LPCTSTR,UINT); PFNMESSAGEBOX pFnMessageBox = (PFNMESSAGEBOX)GetProcAddress(LoadLibraryA("user32.dll"), "MessageBoxA");char szOutput[1000] = {0};_sprintf(szOutput,"MessageBoxA(%X, %s, %s, %X)\n", hWnd, lpText, lpCaption, uType);Log(szOutput);return pFnMessageBox(hWnd,lpText,lpCaption,uType); }

inline hook部分,我們寫自定義Add函數時,要注意堆棧平衡,切記不要在裸函數里定義局部變量,除非你自己提升了堆棧,否則會把上層函數的數據覆蓋掉的。我這里用最簡單的做法,就是使用全局變量。

// 被監控的Add void __declspec(naked)MyAdd() { // 獲取關心的寄存器狀態__asm{mov g_context.Esp,espmov g_context.Eax,eaxmov g_context.Ecx,ecxmov g_context.Edx,edxmov g_context.Ebx,ebx} // 保存8個常用寄存器和標志寄存器__asm{pushadpushfd}// 我的代碼,注意堆棧平衡 __asm{ mov eax,g_context.Espmov ecx,[eax+0x4]mov g_num1,ecxmov eax,g_context.Espmov ecx,[eax+0x8]mov g_num2,ecx}_sprintf(g_szLogBuffer, "Add(%d, %d)\n", g_num1,g_num2);Log(g_szLogBuffer);// 恢復寄存器,執行被替換的代碼,然后返回// 004011D0 55 push ebp// 004011D1 8B EC mov ebp,esp// 004011D3 83 EC 40 sub esp,40h__asm{popfdpopadpush ebpmov ebp,espsub esp,40hjmp g_ret} }

六、總結

這個項目我寫了4、5天,基本上都是用的前面的知識,確實有點難度,但總體上還是順利做出來了,卡得最久的還是進程通信那塊。

總結

以上是生活随笔為你收集整理的WIN32练习项目(函数调用监视器)的全部內容,希望文章能夠幫你解決所遇到的問題。

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