C/C++:Windows编程—IAT Hook实例(程序启动拦截)
C/C++:Windows編程—IAT Hook實例(程序啟動攔截)
前言+思路
本文默認讀者有IAT Hook的相關的基礎知識了哈,記錄筆者在IAT Hook實戰中遇到到問題以及解決思路。
筆者想實現一個功能能夠攔截到程序的啟動。經過調研,大多程序如果是通過雙擊或者鼠標啟動的 一般都是有 Windows資源管理器explorer.exe進程進行創建的。最近剛好學習了IAT Hook就用IAT Hook 實戰一下。創建進程Windows API CreateProcessW,所以我們用OD調試證明一下。使用OD 附加 explorer.exe進程,ctrl + g 輸入CreateProcessW 然后在這個函數那里用F2打下斷點, 然后d打開IE瀏覽器或者其他程序。
從這里我們可以看到,在桌面通過鼠標打開的程序確實是使用的explorer.exe進程的CreateProcessW方法。我們可以用vs帶的命令工具dumpbin 或 DEPENDS.EXE 查看exe或者dll程序的模塊依賴情況。從下圖,雖然我們看到kernel32.dll在explorer.exe的PE中也有,但是我們上圖OD調試中看到 kernel32.CreateProcessW調完了是會回到shell32.dll中的某個地方,所以這里可以看出是使用的shell32.dll中的kernel32.dll的CreateProcessW。
到這里我們可能就會這樣去做了,以shell32.dll作為起始地址,在shell32.dll的導入表中找kernel32.dll然后在 kernel32.dll的IAT中找CreateProcessW 函數然后進行IAT Hook。筆者當然開始的時候也是這樣想的,不過情況沒那么簡單。下面是筆者在做IAT Hook時的一段分析思路以及遇到的坑。請結合下面的幾張圖 容易理解些。
// OD上看,在win7下的explorer.exe中 使用的是SHELL32.dll中的kernel.dll!!!所以這里起始地址應該是SHELL32.dll//HMODULE hModuleExe = GetModuleHandle(_T("SHELL32.dll"));// 起始地址用SHELL32.dll模塊,在它的導入表能找到對應的kernel32.dll動態庫,但是從在kernel32.dll的IAT找不到CreateProcessW :)// 媽蛋,筆者當然沒有放棄,筆者繼續分析,網上找了個 DEPENDS.EXE 來分析 kernel32.dll。確實找到了CreateProcessW是kernel32.dll中API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL模塊的導出函數,通過dumpin查看該動態庫它函數全部給到kernel32.dll了// 所以這里的起始地址應該為kernel32.dll,然后找它導入表中的API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL模塊,// 然后從API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL找它的IAT中的CreateProcessW,然后進行hook。//HMODULE hModuleExe = GetModuleHandle(_T("kernel32.dll"));// 但是,從kernel32.dll的導入表中找到的API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL的中IAT中找到的函數和內存中的CreateProcessW函數地址仍然對不上號!// 所以筆者又去分析shell32.dll,通過DEPENDS.exe工具發現shell32.dll的PE結構也是有API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL,// 然后再看kernel32.dll中鏈接的API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL好像是個快捷方式 應該是鏈接的shell32.dll中API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL// 所以這里的起始地址還是SHELL32.dll模塊,同樣是去找API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL然后找其中的IAT中的CreateProcessW進行hookHMODULE hModuleExe = GetModuleHandle(_T("shell32.dll"));分析kernel32.dll
分析shell32.dll
dumpbin查看API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL導出函數情況
實現效果
看不清可以看嗶哩嗶哩視頻演示地址 https://www.bilibili.com/video/av82627683/
Windows編程—IAT Hook實例(實現Windows程序啟動攔截效果)
程序代碼
筆者開發環境win10-64 + vs2010 32位程序,筆者測試程序運行環境 win7 x86,這里使用DebugView查看dll中打印的日志,使用Process Explorer查看dll注入情況。
這里主要使用IAT Hook的hook CreateProcessW,IAT Hook難點是找到需要hook的函數的動態庫 以及這個動態庫的"母體"!
PE結構中的一個DLL對應一個導入表項,一個函數對應IAT導入地址表中的一個IAT項。
找到母體才能進行遍歷該母體的導入表進而找到動態庫對應的導入表項,通過找到的導入表項可以找到該動態庫的IAT表,再遍歷IAT表 找到hook函數對應的IAT表項,有hook函數的導入地址表 就可以更改導入地址表的函數地址了,就可以進行hook了!
下面是IATHookTest.dll的代碼
#include "stdafx.h" #include <Windows.h>DWORD g_funcAddrOrigninal = NULL; // CreateProcessW函數的地址 DWORD g_funcIATfuncAddr = NULL; // 導入地址表的地址,就是存放函數地址的地址,用于卸載IAT Hooktypedef BOOL (WINAPI *CreateProcessWFunc)(LPCWSTR lpApplicationName,LPWSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,BOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation);BOOL WINAPI MyCreateProcessW(LPCWSTR lpApplicationName,LPWSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,BOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation) {OutputDebugString(_T("MyCreateProcessW enter-----"));OutputDebugString(lpApplicationName);OutputDebugString(lpCommandLine);CreateProcessWFunc func = (CreateProcessWFunc)g_funcAddrOrigninal;BOOL ret = FALSE;CString appName = lpApplicationName;CString strMsg;strMsg.Format(_T("是否打開程序:%s "),appName);if(IDYES == MessageBox(NULL,strMsg,_T("請選擇"),MB_YESNO)){ret = func(lpApplicationName,lpCommandLine,lpProcessAttributes,lpThreadAttributes,bInheritHandles,dwCreationFlags,lpEnvironment,lpCurrentDirectory,lpStartupInfo,lpProcessInformation);}else{ret = TRUE;}OutputDebugString(_T("MyCreateProcessW exit-----"));return ret; }void IATHOOKCreateProcessW() {OutputDebugString(_T("IATHOOKCreateProcessW, enter "));// 獲取CreateProcessW函數地址,該函數是Kernel32.dll導出的函數HMODULE hModuleKernel = GetModuleHandle(_T("kernel32.dll")); if(hModuleKernel == NULL){OutputDebugString(_T("IATHOOKCreateProcessW,LoadLibrary kernel32.dll failed !!!"));return;}CreateProcessWFunc CreateProcessWAddress = (CreateProcessWFunc)GetProcAddress(hModuleKernel,"CreateProcessW");if(CreateProcessWAddress == NULL){OutputDebugString(_T("IATHOOKCreateProcessW,GetProcAddress CreateProcessW failed !!!"));return;}g_funcAddrOrigninal = (DWORD)CreateProcessWAddress;//CString addr;//addr.Format(_T("kernel->CreateProcessWAddress = %x"),g_funcAddrOrigninal);//OutputDebugString(addr);//HMODULE hModuleExe = GetModuleHandle(_T("SHELL32.dll"));// OD上看,在win7下的explorer.exe中 使用的是SHELL32.dll中的kernel.dll!!!所以這里起始地址應該是SHELL32.dll// 起始地址用SHELL32.dll模塊在它的導入表能找到對應的kernel32.dll動態庫,但是從在kernel32.dll的IAT找不到CreateProcessW :)// 媽蛋,筆者當然沒有放棄,筆者繼續分析,網上找了個 DEPENDS.EXE 來分析 kernel32.dll。確實找到了CreateProcessW是kernel32.dll中API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL模塊的導出函數!// 所以這里的起始地址應該為kernel32.dll,然后找它導入表中的API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL模塊,// 然后從API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL找它的IAT中的CreateProcessW,然后進行hook//HMODULE hModuleExe = GetModuleHandle(_T("kernel32.dll"));// 但是,從kernel32.dll的導入表中找到的API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL中IAT中找到的函數和內存中的函數地址仍然對不上號!// 所以筆者又去分析shell32.dll,通過DEPENDS.exe工具發現shell32.dll的PE結構也是有API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL,// 然后再看shell32.dll中鏈接的API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL好些是個快捷方式 應該是鏈接的shell32.dll中API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL// 所以這里的起始地址還是SHELL32.dll模塊,同樣是去找API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL然后找其中的IATHMODULE hModuleExe = GetModuleHandle(_T("shell32.dll"));// 獲取PE結構PIMAGE_DOS_HEADER pDosHead = (PIMAGE_DOS_HEADER)hModuleExe;PIMAGE_NT_HEADERS pNtHead = (PIMAGE_NT_HEADERS)((DWORD)hModuleExe + pDosHead->e_lfanew);// 保存映像基址和導入表的RVAULONGLONG dwImageBase = pNtHead->OptionalHeader.ImageBase;ULONGLONG dwImpDicRva = pNtHead->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;// 導入表的VA,導入表的一項對應一個DLL模塊PIMAGE_IMPORT_DESCRIPTOR pImageDes= (PIMAGE_IMPORT_DESCRIPTOR)(dwImageBase + dwImpDicRva);PIMAGE_IMPORT_DESCRIPTOR pImageTemp = pImageDes;// 在導入表中查找要hook的模塊是否存在bool bFind = false;while(pImageTemp->Name) // 最后一項結構體為全0{char* pName = (char*)(dwImageBase + pImageTemp->Name); // name地址CString cstrName = pName;if(cstrName.CompareNoCase(_T("API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL")) == 0){OutputDebugString(_T("IATHOOKCreateProcessW,find API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL"));bFind = true;break;}pImageTemp++;}bool bFindFnc = false;// 已經找到要HOOK的DLL模塊if(bFind){// 導入地址表,一項對應一個函數,進行遍歷 查找到要hook的函數PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)(dwImageBase + pImageTemp->FirstThunk);while(pThunk->u1.Function) // 最后一項結構體為全0{DWORD* pFuncAddr = (DWORD*)&(pThunk->u1.Function); // 這個地址上內存存放的是【函數的地址】// 取出函數的地址 和 之前在程序中找到的函數地址做比較,如果一樣就找到了該函數的導入地址表了!//CString addr;//addr.Format(_T("IAT->funcAddr = %x"),*pFuncAddr);//OutputDebugString(addr);if(*pFuncAddr == g_funcAddrOrigninal){bFindFnc = true;DWORD dwMyHookAddr = (DWORD)MyCreateProcessW;g_funcIATfuncAddr = (DWORD)pFuncAddr; // 將存放函數地址的內存地址保存,以便后面卸載hookOutputDebugString(_T("IATHOOKCreateProcessW, CreateProcessW was found"));BOOL bRet = WriteProcessMemory(GetCurrentProcess(),pFuncAddr,&dwMyHookAddr,sizeof(DWORD),NULL);if(bRet){OutputDebugString(_T("IATHOOKCreateProcessW,WriteProcessMemory suc"));}else{OutputDebugString(_T("IATHOOKCreateProcessW,WriteProcessMemory fail !!!"));}break;}pThunk++;}}if(bFindFnc == false){OutputDebugString(_T("IATHOOKCreateProcessW, not find CreateProcessW!!!"));}}void UNIATHOOKCreateProcessW() {OutputDebugString(_T("UNIATHOOKCreateProcessW, enter "));if(g_funcIATfuncAddr){if(g_funcAddrOrigninal){OutputDebugString(_T("UNIATHOOKCreateProcessW,CreateProcessW was found"));BOOL bRet = WriteProcessMemory(GetCurrentProcess(),(LPVOID)g_funcIATfuncAddr,&g_funcAddrOrigninal,sizeof(DWORD),NULL);if(bRet){OutputDebugString(_T("UNIATHOOKCreateProcessW,WriteProcessMemory suc"));}else{OutputDebugString(_T("UNIATHOOKCreateProcessW,WriteProcessMemory fail !!!"));}}} }BOOL WINAPI DllMain (HANDLE hInst,ULONG ul_reason_for_call,LPVOID lpReserved) {switch (ul_reason_for_call) {case DLL_PROCESS_ATTACH: {IATHOOKCreateProcessW();}break;case DLL_PROCESS_DETACH: {UNIATHOOKCreateProcessW();}break;case DLL_THREAD_ATTACH: {}break;case DLL_THREAD_DETACH: {}break;}return TRUE; }完整項目
項目包含一個InjectDllTool工程代碼,使用MFC寫的dll注入小程序,然后注入IATHookTest.dll 實現普通程序的啟動攔截效果。完整代碼可以在這里下載,沒分可以在這里github下載最新代碼,如果可以的話給點個小星星喲。
總結
以上是生活随笔為你收集整理的C/C++:Windows编程—IAT Hook实例(程序启动拦截)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ssh远程连接(ubuntu、windo
- 下一篇: C++读取一行数据