C/C++:Windows编程—IAT Hook实例(程序启动拦截)
C/C++:Windows編程—IAT Hook實(shí)例(程序啟動(dòng)攔截)
前言+思路
本文默認(rèn)讀者有IAT Hook的相關(guān)的基礎(chǔ)知識(shí)了哈,記錄筆者在IAT Hook實(shí)戰(zhàn)中遇到到問(wèn)題以及解決思路。
筆者想實(shí)現(xiàn)一個(gè)功能能夠攔截到程序的啟動(dòng)。經(jīng)過(guò)調(diào)研,大多程序如果是通過(guò)雙擊或者鼠標(biāo)啟動(dòng)的 一般都是有 Windows資源管理器explorer.exe進(jìn)程進(jìn)行創(chuàng)建的。最近剛好學(xué)習(xí)了IAT Hook就用IAT Hook 實(shí)戰(zhàn)一下。創(chuàng)建進(jìn)程Windows API CreateProcessW,所以我們用OD調(diào)試證明一下。使用OD 附加 explorer.exe進(jìn)程,ctrl + g 輸入CreateProcessW 然后在這個(gè)函數(shù)那里用F2打下斷點(diǎn), 然后d打開(kāi)IE瀏覽器或者其他程序。
從這里我們可以看到,在桌面通過(guò)鼠標(biāo)打開(kāi)的程序確實(shí)是使用的explorer.exe進(jìn)程的CreateProcessW方法。我們可以用vs帶的命令工具dumpbin 或 DEPENDS.EXE 查看exe或者dll程序的模塊依賴情況。從下圖,雖然我們看到kernel32.dll在explorer.exe的PE中也有,但是我們上圖OD調(diào)試中看到 kernel32.CreateProcessW調(diào)完了是會(huì)回到shell32.dll中的某個(gè)地方,所以這里可以看出是使用的shell32.dll中的kernel32.dll的CreateProcessW。
到這里我們可能就會(huì)這樣去做了,以shell32.dll作為起始地址,在shell32.dll的導(dǎo)入表中找kernel32.dll然后在 kernel32.dll的IAT中找CreateProcessW 函數(shù)然后進(jìn)行IAT Hook。筆者當(dāng)然開(kāi)始的時(shí)候也是這樣想的,不過(guò)情況沒(méi)那么簡(jiǎn)單。下面是筆者在做IAT Hook時(shí)的一段分析思路以及遇到的坑。請(qǐng)結(jié)合下面的幾張圖 容易理解些。
// OD上看,在win7下的explorer.exe中 使用的是SHELL32.dll中的kernel.dll!!!所以這里起始地址應(yīng)該是SHELL32.dll//HMODULE hModuleExe = GetModuleHandle(_T("SHELL32.dll"));// 起始地址用SHELL32.dll模塊,在它的導(dǎo)入表能找到對(duì)應(yīng)的kernel32.dll動(dòng)態(tài)庫(kù),但是從在kernel32.dll的IAT找不到CreateProcessW :)// 媽蛋,筆者當(dāng)然沒(méi)有放棄,筆者繼續(xù)分析,網(wǎng)上找了個(gè) DEPENDS.EXE 來(lái)分析 kernel32.dll。確實(shí)找到了CreateProcessW是kernel32.dll中API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL模塊的導(dǎo)出函數(shù),通過(guò)dumpin查看該動(dòng)態(tài)庫(kù)它函數(shù)全部給到kernel32.dll了// 所以這里的起始地址應(yīng)該為kernel32.dll,然后找它導(dǎo)入表中的API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL模塊,// 然后從API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL找它的IAT中的CreateProcessW,然后進(jìn)行hook。//HMODULE hModuleExe = GetModuleHandle(_T("kernel32.dll"));// 但是,從kernel32.dll的導(dǎo)入表中找到的API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL的中IAT中找到的函數(shù)和內(nèi)存中的CreateProcessW函數(shù)地址仍然對(duì)不上號(hào)!// 所以筆者又去分析shell32.dll,通過(guò)DEPENDS.exe工具發(fā)現(xiàn)shell32.dll的PE結(jié)構(gòu)也是有API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL,// 然后再看kernel32.dll中鏈接的API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL好像是個(gè)快捷方式 應(yīng)該是鏈接的shell32.dll中API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL// 所以這里的起始地址還是SHELL32.dll模塊,同樣是去找API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL然后找其中的IAT中的CreateProcessW進(jìn)行hookHMODULE hModuleExe = GetModuleHandle(_T("shell32.dll"));分析kernel32.dll
分析shell32.dll
dumpbin查看API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL導(dǎo)出函數(shù)情況
實(shí)現(xiàn)效果
看不清可以看嗶哩嗶哩視頻演示地址 https://www.bilibili.com/video/av82627683/
Windows編程—IAT Hook實(shí)例(實(shí)現(xiàn)Windows程序啟動(dòng)攔截效果)
程序代碼
筆者開(kāi)發(fā)環(huán)境win10-64 + vs2010 32位程序,筆者測(cè)試程序運(yùn)行環(huán)境 win7 x86,這里使用DebugView查看dll中打印的日志,使用Process Explorer查看dll注入情況。
這里主要使用IAT Hook的hook CreateProcessW,IAT Hook難點(diǎn)是找到需要hook的函數(shù)的動(dòng)態(tài)庫(kù) 以及這個(gè)動(dòng)態(tài)庫(kù)的"母體"!
PE結(jié)構(gòu)中的一個(gè)DLL對(duì)應(yīng)一個(gè)導(dǎo)入表項(xiàng),一個(gè)函數(shù)對(duì)應(yīng)IAT導(dǎo)入地址表中的一個(gè)IAT項(xiàng)。
找到母體才能進(jìn)行遍歷該母體的導(dǎo)入表進(jìn)而找到動(dòng)態(tài)庫(kù)對(duì)應(yīng)的導(dǎo)入表項(xiàng),通過(guò)找到的導(dǎo)入表項(xiàng)可以找到該動(dòng)態(tài)庫(kù)的IAT表,再遍歷IAT表 找到hook函數(shù)對(duì)應(yīng)的IAT表項(xiàng),有hook函數(shù)的導(dǎo)入地址表 就可以更改導(dǎo)入地址表的函數(shù)地址了,就可以進(jìn)行hook了!
下面是IATHookTest.dll的代碼
#include "stdafx.h" #include <Windows.h>DWORD g_funcAddrOrigninal = NULL; // CreateProcessW函數(shù)的地址 DWORD g_funcIATfuncAddr = NULL; // 導(dǎo)入地址表的地址,就是存放函數(shù)地址的地址,用于卸載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("是否打開(kāi)程序:%s "),appName);if(IDYES == MessageBox(NULL,strMsg,_T("請(qǐng)選擇"),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函數(shù)地址,該函數(shù)是Kernel32.dll導(dǎo)出的函數(shù)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!!!所以這里起始地址應(yīng)該是SHELL32.dll// 起始地址用SHELL32.dll模塊在它的導(dǎo)入表能找到對(duì)應(yīng)的kernel32.dll動(dòng)態(tài)庫(kù),但是從在kernel32.dll的IAT找不到CreateProcessW :)// 媽蛋,筆者當(dāng)然沒(méi)有放棄,筆者繼續(xù)分析,網(wǎng)上找了個(gè) DEPENDS.EXE 來(lái)分析 kernel32.dll。確實(shí)找到了CreateProcessW是kernel32.dll中API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL模塊的導(dǎo)出函數(shù)!// 所以這里的起始地址應(yīng)該為kernel32.dll,然后找它導(dǎo)入表中的API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL模塊,// 然后從API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL找它的IAT中的CreateProcessW,然后進(jìn)行hook//HMODULE hModuleExe = GetModuleHandle(_T("kernel32.dll"));// 但是,從kernel32.dll的導(dǎo)入表中找到的API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL中IAT中找到的函數(shù)和內(nèi)存中的函數(shù)地址仍然對(duì)不上號(hào)!// 所以筆者又去分析shell32.dll,通過(guò)DEPENDS.exe工具發(fā)現(xiàn)shell32.dll的PE結(jié)構(gòu)也是有API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL,// 然后再看shell32.dll中鏈接的API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL好些是個(gè)快捷方式 應(yīng)該是鏈接的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結(jié)構(gòu)PIMAGE_DOS_HEADER pDosHead = (PIMAGE_DOS_HEADER)hModuleExe;PIMAGE_NT_HEADERS pNtHead = (PIMAGE_NT_HEADERS)((DWORD)hModuleExe + pDosHead->e_lfanew);// 保存映像基址和導(dǎo)入表的RVAULONGLONG dwImageBase = pNtHead->OptionalHeader.ImageBase;ULONGLONG dwImpDicRva = pNtHead->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;// 導(dǎo)入表的VA,導(dǎo)入表的一項(xiàng)對(duì)應(yīng)一個(gè)DLL模塊PIMAGE_IMPORT_DESCRIPTOR pImageDes= (PIMAGE_IMPORT_DESCRIPTOR)(dwImageBase + dwImpDicRva);PIMAGE_IMPORT_DESCRIPTOR pImageTemp = pImageDes;// 在導(dǎo)入表中查找要hook的模塊是否存在bool bFind = false;while(pImageTemp->Name) // 最后一項(xiàng)結(jié)構(gòu)體為全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;// 已經(jīng)找到要HOOK的DLL模塊if(bFind){// 導(dǎo)入地址表,一項(xiàng)對(duì)應(yīng)一個(gè)函數(shù),進(jìn)行遍歷 查找到要hook的函數(shù)PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)(dwImageBase + pImageTemp->FirstThunk);while(pThunk->u1.Function) // 最后一項(xiàng)結(jié)構(gòu)體為全0{DWORD* pFuncAddr = (DWORD*)&(pThunk->u1.Function); // 這個(gè)地址上內(nèi)存存放的是【函數(shù)的地址】// 取出函數(shù)的地址 和 之前在程序中找到的函數(shù)地址做比較,如果一樣就找到了該函數(shù)的導(dǎo)入地址表了!//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; // 將存放函數(shù)地址的內(nèi)存地址保存,以便后面卸載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; }完整項(xiàng)目
項(xiàng)目包含一個(gè)InjectDllTool工程代碼,使用MFC寫(xiě)的dll注入小程序,然后注入IATHookTest.dll 實(shí)現(xiàn)普通程序的啟動(dòng)攔截效果。完整代碼可以在這里下載,沒(méi)分可以在這里github下載最新代碼,如果可以的話給點(diǎn)個(gè)小星星喲。
總結(jié)
以上是生活随笔為你收集整理的C/C++:Windows编程—IAT Hook实例(程序启动拦截)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: ssh远程连接(ubuntu、windo
- 下一篇: C++读取一行数据