国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
HOOK API——Windows核心編程 第22章 插入DLL和掛接API學(xué)習(xí)筆記

HOOK API——Windows核心編程 第22章 插入DLL和掛接API學(xué)習(xí)筆記


介紹:HOOK API是指截獲特定進(jìn)程或系統(tǒng)對某個(gè)API函數(shù)的調(diào)用,使得API的執(zhí)行流程轉(zhuǎn)向指定的代碼。Windows下的應(yīng)用程序都建立在API函數(shù)至上,所以截獲API是一項(xiàng)相當(dāng)有用的技術(shù),它使得用戶有機(jī)會(huì)干預(yù)其它應(yīng)用程序的程序流程。

最常用的一種掛鉤API的方法是改變目標(biāo)進(jìn)程中調(diào)用API函數(shù)的代碼,使得它們對API的調(diào)用變?yōu)閷τ脩糇远x函數(shù)的調(diào)用。

HOOK API和HOOK技術(shù)完全不同。盡管它們都是鉤子。HOOK鉤的是消息,它在系統(tǒng)將消息傳遞給應(yīng)用程序之前截獲它,然后進(jìn)行操作、或修改消息、或停止消息的傳遞;而HOOK API截獲的是應(yīng)用程序?qū)ο到y(tǒng)API的調(diào)用,它在應(yīng)用程序?qū)ο到y(tǒng)API的調(diào)用之前截獲此調(diào)用動(dòng)作,讓其轉(zhuǎn)而調(diào)用我們所定義的函數(shù)(內(nèi)容可能是進(jìn)行一些操作后再調(diào)用原系統(tǒng)API)。

關(guān)于HOOK技術(shù),微軟為我們提供了現(xiàn)成的API,有固定的使用步驟。

而對于HOOK API技術(shù),微軟并沒有向我們提供類似的API,沒有那么簡潔的步驟可供我們參考,也許是因?yàn)槲④洸⒉幌M覀冇眠@樣的手段編程,所以相對要麻煩一些。

以下為《windows核心編程》學(xué)習(xí)筆記:

windows編程中,有些時(shí)候必須要打破進(jìn)程的界限。訪問另一個(gè)進(jìn)程的地址空間。這些情況包括:

1.當(dāng)你想要為另一個(gè)進(jìn)程創(chuàng)建的窗口建立子類時(shí),即為此窗口指定新的窗口過程函數(shù)。

2.當(dāng)你需要調(diào)試幫助時(shí)。

3.當(dāng)你想要掛接其它進(jìn)程時(shí)(HOOK API?)。

一旦你的DLL插入到另一個(gè)進(jìn)程的地址空間,就可以對另一個(gè)進(jìn)程為所欲為。

一、為另一個(gè)進(jìn)程創(chuàng)建的窗口建立一個(gè)子類。

建立子類就能改變窗口的行為特性。若要建立子類,只需要調(diào)用SetWindowLongPtr函數(shù),改變窗口的內(nèi)存塊中的窗口過程地址,指向一個(gè)新的(你自己的)WndProc。

當(dāng)調(diào)用下面所示的SetWindowLongPtr函數(shù),建立一個(gè)窗口的子類時(shí),你告訴系統(tǒng),發(fā)送到或者顯示在hwnd設(shè)定的窗口中的所有消息都應(yīng)該送往MySubclassProc,而不是送往窗口正常的窗口過程:

SetWindowLongPtr(hwnd,GWLP_WNDPROC,MySubclassProc);

換句話說,當(dāng)系統(tǒng)需要將消息發(fā)送到指定窗口的WndProc時(shí),要查看它的地址,然后直接調(diào)用WndProc。在這里,系統(tǒng)發(fā)現(xiàn)MySubclassProc函數(shù)的地址與窗口相關(guān)聯(lián),因此就直接調(diào)用MySubclassProc函數(shù)。

窗口函數(shù)被調(diào)用的過程是這樣的:如,進(jìn)程A正在運(yùn)行,并且已經(jīng)創(chuàng)建了一個(gè)窗口。文件User32.dll被映射到進(jìn)程A的地址空間中。對User32.dll文件的映射是為了接收和發(fā)送在進(jìn)程A中運(yùn)行的任何線程創(chuàng)建的任何窗口中發(fā)送和顯示的消息(USER32.DLL里含有DispatchMessage函數(shù),函數(shù)為:

LONG DispatchMessage (CONST MSG *msg){

LONG lResult;

WNDPROC lpfnWndProc =

(WNDPROC)GetWindowLongPtr(msg.hwnd, GWLP_WNDPROC);

lResult = lpfnWndProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);

return (lResult);

}

)。

當(dāng)User32.dll的映像發(fā)現(xiàn)一個(gè)消息時(shí),它首先要確定窗口的WndProc的地址,然后調(diào)用該地址,傳遞窗口的句柄、消息和wParam和lParam值。當(dāng)WndProc處理該消息后,User32.dll便循環(huán)運(yùn)行,并等待另一個(gè)窗口消息被處理。

 

若想在進(jìn)程B中為進(jìn)程A的線程所創(chuàng)建的窗口建立子類(即指定窗口過程函數(shù)),在進(jìn)程B中就需要得到目標(biāo)窗口的句柄,方法很多,如FindWindow。

 

但是,由于進(jìn)程的邊界問題,Microsoft決定不讓SetWindowLongPtr改變另一個(gè)進(jìn)程創(chuàng)建的窗口過程。不是SetWindowLongPtr不能為窗口指定窗口過程函數(shù),而是由于進(jìn)程的邊界問題,使得這樣不具有可操作性。如果能將子類過程(MySubclassProc)的代碼放入進(jìn)程A的地址空間,就可以方便地調(diào)用SetWindowLongPtr函數(shù),將進(jìn)程A的地址傳遞給MySubclassProc函數(shù)。將這個(gè)方法成為將DLL(含有MySubclassProc的代碼)“插入”進(jìn)程的地址空間。有若干種方法可以用來進(jìn)行這項(xiàng)操作。

1.使用注冊表來插入DLL

2.使用Windows掛鉤來插入DLL

3.使用遠(yuǎn)程線程來插入DLL

分別來學(xué)習(xí)一下:

1.使用注冊表來插入DLL

這種方式是在注冊表中的 HKEY_LOCAL_MACHINE/Software/Microsoft/Windows NT/CurrentVersion/Windows/AppInit_DLLs關(guān)鍵字里保存要加載的dll文件名(或包含路徑)。這樣再重新啟動(dòng)系統(tǒng)(系統(tǒng)初始化)后,dll就得到了加載。而要使其失效,同樣需要重新啟動(dòng)電腦。這種方法dll只能被加載到使用User32.dll的進(jìn)程中。

2.使用Windows掛鉤來插入DLL

使用HOOK的方式(而非HOOK API)來插入DLL到另一個(gè)進(jìn)程的地址空間。

HOW?

我們都知道,可以用進(jìn)程A為進(jìn)程B掛鉤(HOOK),比如A按調(diào)用SetWindowsHookEx:

HHOOK hHook = SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,hinstDll,0);

安裝了一個(gè)WH_GETMESSAGE類型的鉤子,安裝到系統(tǒng)內(nèi)的所有線程(0),鉤子函數(shù)(鉤子過程)為hinstDll所指定的DLL里的GetMsgProc函數(shù)。當(dāng)一個(gè)進(jìn)程,如進(jìn)程B中的一個(gè)線程準(zhǔn)備將一條消息發(fā)送到一個(gè)窗口時(shí),系統(tǒng)查看發(fā)現(xiàn)該線程已經(jīng)被安裝了WH_GETMESSAGE類型的鉤子,于是系統(tǒng)知道應(yīng)該將這個(gè)消息先送給鉤子函數(shù)GetMsgProc。既然如此,系統(tǒng)就會(huì)去查看包含GetMsgProc的DLL是否被映射到進(jìn)程B中,如果沒有則強(qiáng)制映射。然后調(diào)用GetMsgProc對消息進(jìn)行處理。

這就是HOOK的大概過程。

如果我們在GetMsgProc函數(shù)體里用SetWindowLongPtr函數(shù)為消息即將發(fā)送給的窗口設(shè)置窗口過程函數(shù),就可以完成為窗口設(shè)置子類(即指定新的窗口過程函數(shù))的工作。當(dāng)然新的窗口過程函數(shù)的代碼必須與GetMsgProc位于同一個(gè)DLL里。

即:

目標(biāo)窗口被掛接WH_GETMESSAGE類型鉤子,當(dāng)有消息發(fā)送到此窗口時(shí),系統(tǒng)調(diào)用鉤子過程GetMsgProc,在此函數(shù)中,調(diào)用SetWindowLongPtr設(shè)置窗口的新窗口過程函數(shù)。

王艷萍版《windows程序設(shè)計(jì)》中提到的利用HOOK注入DLL的方法與此類似,只不過那里沒有強(qiáng)調(diào)設(shè)置子類這一點(diǎn),而只是為了注入DLL:

使用Windows鉤子注入特定DLL到其它進(jìn)程時(shí)一般都在目標(biāo)進(jìn)程上安裝WH_GETMESSAGE鉤子,因?yàn)閃indows下的應(yīng)用程序大部分都需要調(diào)用GetMessage或PeekMessage來從消息隊(duì)列中獲取消息,所以WH_GETMESSAGE型鉤子函數(shù)一定會(huì)被調(diào)用,而各個(gè)進(jìn)程要執(zhí)行鉤子函數(shù),必須要將鉤子函數(shù)所在的DLL加載到目標(biāo)進(jìn)程匯總,這個(gè)工作是系統(tǒng)為我們完成的,系統(tǒng)會(huì)自動(dòng)強(qiáng)迫所有能產(chǎn)生激活SH_GETMESSAGE鉤子的消息的進(jìn)程調(diào)用LoadLibrary來加載鉤子函數(shù)所在的dll,然后執(zhí)行其中的鉤子函數(shù)。由于此時(shí)的鉤子的目的只是為了加載鉤子函數(shù)所在的DLL(DLL中其它部分才是加載它的原因),所以此時(shí)鉤子函數(shù)可以什么都不做,而只是return ::CallNextHookEx(g_hHook,code,wParam,lParam);。

 

3.使用遠(yuǎn)程線程來插入DLL

Windows的大多數(shù)函數(shù)都只允許調(diào)用函數(shù)的進(jìn)程對自己進(jìn)行操作。但是,有些函數(shù)卻允許一個(gè)進(jìn)程對另一個(gè)進(jìn)程進(jìn)行操作。

這個(gè)方法的思路是,讓目標(biāo)進(jìn)程中的線程調(diào)用LoadLibrary來加載必要的DLL(DLL里可以包括我們希望目標(biāo)進(jìn)程用來調(diào)用以覆蓋其本應(yīng)調(diào)用的API的我們自己定義的API實(shí)現(xiàn))。但是如何才能控制另一個(gè)進(jìn)程中的線程去調(diào)用LoadLibrary呢?方法是我們在目標(biāo)進(jìn)程中創(chuàng)建一個(gè)新線程,由于這個(gè)線程是我們自己創(chuàng)建的,當(dāng)然我們讓它干什么都可以(通過代碼實(shí)現(xiàn))。Windows提供了一個(gè)函數(shù),使我們能夠非常容易地在另一個(gè)進(jìn)程中創(chuàng)建線程,這就是CreateRemoteThread函數(shù):

HANDLE CreateRemoteThread(

    HANDLE hProcess,

    PSECURITY_ATTRIBUTES psa,

    DWORD dwStackSize,

    PTHREAD_START_ROUTINE pfnStartAddr,

    PVOID pvParam,

    DWORD fdwCreate,

    PDWORD pdwThreadId);

對比一下CreateThread函數(shù):

HANDLE CreateRemoteThread(

    PSECURITY_ATTRIBUTES psa,

    DWORD dwStackSize,

    PTHREAD_START_ROUTINE pfnStartAddr,

    PVOID pvParam,

    DWORD fdwCreate,

    PDWORD pdwThreadId);

兩者非常相似,只是前者多了一個(gè)參數(shù)hProcess,這個(gè)線程就指明了此函數(shù)是為哪個(gè)遠(yuǎn)程進(jìn)程創(chuàng)建新線程。pfnStartAddr指明了線程函數(shù)的內(nèi)存地址。當(dāng)然,該內(nèi)存地址與遠(yuǎn)程進(jìn)程是相關(guān)的。線程函數(shù)的代碼不能位于你自己的進(jìn)程的地址空間中。

值得一提的是,在Windows2000里,CreateThread是用對CreateRemoteThread進(jìn)行封裝來實(shí)現(xiàn)的:

HANDLE CreateThread(PSECURITY_ATTRIBUTES psa,DWORD dwStackSize,PTHREAD_START_ROUTINE pfnStartAddr,PVOID pvParam,DWORD fdwCreate,PDWORD pdwThreadID)

{

return (CreateRemoteThread(GetCurrentProcess(),

psa,dwStackSize,pfnStartAddr,pvParam,fdwCreate,pdwThreadID));

}

遠(yuǎn)程注入DLL(以及利用此方法進(jìn)行API掛接)的思想和步驟概括如下:

思想:在我們自己的進(jìn)程中為目標(biāo)進(jìn)程創(chuàng)建一個(gè)新線程,讓此線程執(zhí)行LoadLibraryA(or W)加載我們希望注入的DLL(里面包含我們希望掛接的API的我們實(shí)現(xiàn)的版本)。在DLL被注入時(shí),DLL的主函數(shù)DllMain得到機(jī)會(huì)執(zhí)行,在DllMain里完成API的替換工作。

步驟:

1.使用VirtualAllocEx函數(shù),在遠(yuǎn)程進(jìn)程(目標(biāo)進(jìn)程)的空間里分配內(nèi)存。

2.使用WriteProcessMemory函數(shù),將要注入的DLL路徑名拷貝到第一步驟中分配的內(nèi)存中。

3.使用GetProcAddress函數(shù),獲取LoadLibraryA或LoadLibraryW函數(shù)的實(shí)地址(在Kernel32.dll中),作為之后創(chuàng)建遠(yuǎn)程線程時(shí)傳遞給線程函數(shù)(LoadLibraryA或LoadLibraryW)的參數(shù)。

4.使用CreateRemoteThread函數(shù),在遠(yuǎn)程進(jìn)程中創(chuàng)建線程,用于加載DLL。它的線程函數(shù)為LoadLibraryA/LoadLibraryW,參數(shù)為步驟3的返回值。

這時(shí),DLL已經(jīng)被插入遠(yuǎn)程進(jìn)程的地址空間中,同時(shí)DLL的DllMain函數(shù)接收到一個(gè)DLL_PROCESS_ATTACH通知,并且能夠執(zhí)行需要的代碼(你注入此DLL的目的所在)。當(dāng)DllMain返回時(shí),遠(yuǎn)程線程從它對LoadLibrary的調(diào)用返回到BaseThreadStart。然后BaseThreadStart調(diào)用ExitThread,使遠(yuǎn)程線程終止運(yùn)行,它已經(jīng)完成了注入DLL的任務(wù),并且DLL也得到機(jī)會(huì)完成我們希望它的任務(wù)(在DllMain中)。

如果在DllMain中完成對API的掛接,那么通過遠(yuǎn)程注入實(shí)現(xiàn)的API掛接就完成了。當(dāng)然,不要忘了執(zhí)行下面的步驟從目標(biāo)進(jìn)程的地址空間中刪除DLL。

5.使用VirtualFreeEx函數(shù),釋放第一個(gè)步驟中分配的內(nèi)存。

6.使用GetProcAddress函數(shù),獲得FreeLibrary函數(shù)的實(shí)地址(在Kernel32.dll里)。

7.使用CreateRemoteThread函數(shù),在遠(yuǎn)程進(jìn)程中創(chuàng)建一個(gè)線程,它調(diào)用FreeLibrary函數(shù),傳遞遠(yuǎn)程DLL的HINSTANCE。

下面研究一下在DllMain中如何完成API的掛接。

首先了解一下導(dǎo)入表。

對于一個(gè)模塊來說,如果它調(diào)用的函數(shù)的實(shí)現(xiàn)代碼在其它模塊中,那么這個(gè)函數(shù)就叫做導(dǎo)入函數(shù)。對于一個(gè)模塊來說,他的所有導(dǎo)入函數(shù)的函數(shù)名和函數(shù)所駐留的DLL名等信息都保留在該模塊的導(dǎo)入表(Import Table)中。導(dǎo)入表是一個(gè)IMAGE_IMPORT_DESCRIPTOR結(jié)構(gòu)的數(shù)組,每一個(gè)IMAGE_IMPORT_DESCRIPTOR結(jié)構(gòu)表述了一個(gè)導(dǎo)入模塊。

結(jié)構(gòu)體的定義詳見王艷萍版《Windows程序設(shè)計(jì)》320頁。

此結(jié)構(gòu)體中的兩個(gè)關(guān)鍵信息是1.函數(shù)序號(hào)/名稱表的偏移量,2.IAT(導(dǎo)入地址表Import Address Table)的偏移量,根據(jù)這兩個(gè)信息可以分別找到這兩個(gè)表。

應(yīng)用程序啟動(dòng)時(shí),載入器根據(jù)PE文件(如DLL)的導(dǎo)入表記錄的DLL名加載相應(yīng)DLL模塊,再根據(jù)導(dǎo)入表的hint/name表(OriginalFirstThunk指向的數(shù)組)記錄的函數(shù)名取得函數(shù)的地址,將這些地址保存到導(dǎo)入表的IAT中。

應(yīng)用程序在調(diào)用導(dǎo)入函數(shù)時(shí),要先到導(dǎo)入表的IAT中找到這個(gè)函數(shù)的地址,然后再調(diào)用。例如,調(diào)用User32.dll模塊中的MessageBoxA函數(shù)的代碼最終會(huì)被匯編成如下代碼:

call      dword ptr [__imp__MessageBoxA@16(0042428c)]

函數(shù)的IAT僅僅是一個(gè)DWORD數(shù)組,數(shù)組的每個(gè)成員記錄著一個(gè)導(dǎo)入函數(shù)的地址。地址0042428c是導(dǎo)入地址表中MessageBoxA函數(shù)對應(yīng)成員的地址,這個(gè)地址處的內(nèi)容是MessageBoxA在User32模塊的真實(shí)地址。可見,調(diào)用API函數(shù)時(shí),程序先要轉(zhuǎn)向PE文件的導(dǎo)入地址表取得API函數(shù)的真實(shí)地址,然后再轉(zhuǎn)向API函數(shù)的執(zhí)行代碼。

于是我們可以用修改IAT表的方法來完成HOOK API的實(shí)現(xiàn)。比如,如果將0042428c地指出的內(nèi)容用一個(gè)自定義函數(shù)的地址覆蓋掉,那么以后這個(gè)模塊對MessageBoxA的調(diào)用實(shí)際上就成了對改自定義函數(shù)的調(diào)用,應(yīng)用程序以為自己調(diào)用的是系統(tǒng)API,但是我們將IAT表修改后,使得在它試圖尋找系統(tǒng)API的時(shí)候,卻找到了我們定義的用來代替該API的自定義函數(shù)。但是,為了保持堆棧的平衡,自定義函數(shù)使用的調(diào)用規(guī)則和參數(shù)的個(gè)數(shù)必須與它所替代的API函數(shù)完全相同。

這種用修改IAT表進(jìn)行HOOK API的方法是最穩(wěn)定的一種。

下面將詳細(xì)介紹。

首先要在PE文件(如DLL)中定位導(dǎo)入表。這主要是對PE文件結(jié)構(gòu)的分析。

PE文件格式是任何可執(zhí)行文件或DLL的文件格式,PE文件以64字節(jié)的DOS頭開始(IMAGE_DOS_HEADER結(jié)構(gòu)),接著是一小段DOS程序,然后是248字節(jié)的NT文件頭(IMAGE_NT_HEADERS結(jié)構(gòu))。NT文件頭相對文件開始位置的偏移量(因?yàn)橹虚g的DOS程序長短不定)可以有IMAGE_DOS_HEADER結(jié)構(gòu)的e_lfanew給出。

下面的代碼取得了一個(gè)指向IMAGE_OPTIONAL_HEADER結(jié)構(gòu)的指針。

HMODULE hMod = ::GetModuleHandle(NULL);

IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER*)hMod;

IMAGE_OPTIONAL_HEADER* pOptHeader =

          (IMAGE_OPTIONAL_HEADER*)((BYTE*)hMod+pDosHeader->e_lfanes+24);

IMAGE_OPTIONAL_HEADER結(jié)構(gòu)體里保存著許多重要的信息,包括我們最感興趣的數(shù)據(jù)目錄表指針(即我們想要操作的表的地址)。PE文件保存了16個(gè)數(shù)據(jù)目錄,最常見的有導(dǎo)入表、導(dǎo)出表、資源和重定位表。我們感興趣的是導(dǎo)入表。它是一個(gè)IMAGE_IMPORT_DESCRIPTOR結(jié)構(gòu)的數(shù)組,每個(gè)結(jié)構(gòu)對應(yīng)著一個(gè)導(dǎo)入模塊。下面的代碼取得導(dǎo)入表中第一個(gè)IMAGE_IMPORT_DESCRIPTOR結(jié)構(gòu)的指針(導(dǎo)入表首地址)。

IMAGE_IMPORT_DESCRIPTOR* pImportDesc = (IMAGE_IMPORT_DESCRIPTOR*)((BYTE*)hMod+pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

除了通過分析PE文件的結(jié)構(gòu)來定位模塊的導(dǎo)入表外,還可以使用ImageDirectoryEntryToData函數(shù)。這個(gè)函數(shù)知道模塊基地址后,直接返回指定數(shù)據(jù)目錄表的首地址,用法如下:

PVOID ImageDirectoryEntryToData(

PVOID Base,                          //模塊及地址

BOOLEAN MappedAsImage,     //如果此參數(shù)是TRUE,文件被系統(tǒng)當(dāng)做鏡像映射,否則,

                                            //將當(dāng)做數(shù)據(jù)文件映射

USHORT DirectoryEntry,          //指定要取得哪個(gè)表的表首地址 傳入

                                            //IMAGE_DIRECTORY_ENTRY_IMPORT,取得導(dǎo)入表

                                            //首地址

PULONG Size                          //返回表象的大小

);//為了調(diào)用此API,請?zhí)砑哟a“#include<ImageHlp.h>”和“#progma comment(lib."ImageHil")”

IMAGE_IMPORT_DESCRIPTOR結(jié)構(gòu)包含了hint/name(函數(shù)序號(hào)/名稱)表和IAT表的偏移量。這兩個(gè)表的大小相同,一個(gè)成員對應(yīng)一個(gè)導(dǎo)入函數(shù),分別記錄了導(dǎo)入函數(shù)的名稱和地址。下面的代碼打印出了此模塊從其它模塊導(dǎo)入的所有函數(shù)的名稱和地址。

此模塊從很多其它模塊(DLL)中導(dǎo)入函數(shù),這里分別打印出它們。每一個(gè)IMAGE_IMPORT_DESCRIPTOR結(jié)構(gòu)描述了一個(gè)模塊(DLL)向此模塊導(dǎo)入函數(shù)的情況,該結(jié)構(gòu)提供了很多表的地址,如hint/name表和IAT表,這兩個(gè)表分別記錄了了從此IMAGE_IMPORT_DESCEIPTOR結(jié)構(gòu)所描述的模塊導(dǎo)入的函數(shù)的名稱和地址。

while(pImportDesc->FirstThunk)

{

char* pszDllName=(char*)((BYTE*)hMod+pImportDesc->Name);

printf("/n 模塊名稱:%s/n",pszDllName);

//一個(gè)IMAGE_THUNK_DATA就是一個(gè)雙字,它指定了一個(gè)導(dǎo)入函數(shù)

IMAGE_THUNK_DATA *pThunk =

(IMAGE_THUNK_DATA*)((BYTE*)hMod+pImportDesc->OriginalFirstThunk);

int n = 0;

while(pThunk->u1.Function)

{//取得函數(shù)名稱。hint/name表項(xiàng)前兩個(gè)字節(jié)是函數(shù)序號(hào),后面才是函數(shù)名稱字符串

 char* pszFunName=(char*)((BYTE*)hMod+(DWORD)pThunk->

u1.AddressOfData+2);

//取得函數(shù)地址。IAT表就是一個(gè)DWORD類型的數(shù)組,每個(gè)成員記錄一個(gè)函數(shù)的地址

PDWORD lpAddr = (DWORD*)((BYTE*)hMod+pImportDesc->FirstThunk)+n;

//打印出函數(shù)名稱和地址

printf("從此模塊導(dǎo)入的函數(shù):%-25s, ",pszFunName);

printf("函數(shù)地址:%X/n",lpAddr);

n++;pThunk++;

}

pImportDesc++;

}

由上述可知,定位導(dǎo)入表之后即可定位導(dǎo)入地址表。為了截獲API調(diào)用,只要用自定義函數(shù)的地址覆蓋掉導(dǎo)入地址表中真實(shí)的API函數(shù)地址即可。這就是用DLL遠(yuǎn)程注入和修改IAT表的方式實(shí)現(xiàn)HOOK API的過程。

具體掛鉤過程為:在我們注入的DLL里,因?yàn)镈LL第一次被注入時(shí)系統(tǒng)會(huì)自動(dòng)調(diào)用DLL的DllMain函數(shù),在DllMain里調(diào)用我們同在此DLL里定義的SetHookApi函數(shù),在SetHookApi函數(shù)里完成對目標(biāo)進(jìn)程(亦即當(dāng)前進(jìn)程,因?yàn)楝F(xiàn)在調(diào)用DLL內(nèi)函數(shù)的就是我們的目標(biāo)進(jìn)程)IAT表的修改,具體修改方法為:

1.保存原有真實(shí)API地址,因?yàn)榇藭r(shí)該API已經(jīng)被映射到該進(jìn)程的空間中,所以該API的函數(shù)名就代表了其在進(jìn)程空間里的地址;這個(gè)應(yīng)在SetHookApi外完成,why?

2.定位當(dāng)前進(jìn)程的導(dǎo)入表-IMAGE_IMPORT_DESCRIPTOR數(shù)組;

3.在導(dǎo)入表中查找要替換的API所在的DLL模塊對應(yīng)的IMAGE_IMPORT_DESCRIPTOR結(jié)構(gòu);

4.找到后,再定位導(dǎo)入地址表IAT;

5.找到該DLL的IAT后,通過之前保存的真實(shí)API地址與IAT表中的u1.Function成員進(jìn)行匹配,找到存放此真實(shí)API地址的內(nèi)存;

6.取得我們定義的用以替代此API的函數(shù)的地址;

7.WriteProcessMemory進(jìn)行對IAT表的改寫。

搞定。

 

============================================

============================================

最后總結(jié)一下利用遠(yuǎn)程注入DLL、修改IAT表的方式進(jìn)行HOOK API的思路:

1.要想讓目標(biāo)進(jìn)程的API被HOOK掉,需要讓目標(biāo)進(jìn)程執(zhí)行我們?yōu)槠涠x的SetHookApi函數(shù),如何能讓目標(biāo)進(jìn)程執(zhí)行我們定義的函數(shù)呢?方法是讓目標(biāo)函數(shù)加載我們定義的DLL,SetHookApi的定義也在此DLL里,利用DLL第一次加載時(shí)會(huì)執(zhí)行DllMain的機(jī)會(huì),執(zhí)行SetHookApi。

2.新問題,如何讓目標(biāo)進(jìn)程調(diào)用LoadLibrary加載我們定義的DLL呢?方法是為目標(biāo)進(jìn)程創(chuàng)建一個(gè)遠(yuǎn)程線程,為其指定線程函數(shù)為LoadLibrary,參數(shù)為"Mydll.dll"。這樣目標(biāo)進(jìn)程的新線程創(chuàng)建后就會(huì)加載我們定義的DLL到目標(biāo)進(jìn)程的空間。創(chuàng)建遠(yuǎn)程線程的方法是CreateRemoteThread函數(shù)。

3.至此,完成了DLL的加載,DLL加載后目標(biāo)進(jìn)程會(huì)自動(dòng)執(zhí)行DllMain,DllMain中執(zhí)行SetHookApi函數(shù),完成對API的掛接。如何完成API的掛接?只需要修改目標(biāo)進(jìn)程的IAT表。目標(biāo)進(jìn)程又一個(gè)導(dǎo)入表,記錄了各個(gè)模塊導(dǎo)入到此進(jìn)程中的導(dǎo)入函數(shù)的信息,其中又有一個(gè)IAT表記錄導(dǎo)入函數(shù)地址的信息,只需要修改IAT表中欲覆蓋的API的函數(shù)地址為我們定義的函數(shù)的地址即可完成API的掛接

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
揭示win32 api攔截細(xì)節(jié)
基于API HOOK的剪切板監(jiān)控
首款反射式PE殼<琥珀>
如何實(shí)現(xiàn)api鉤子
Ring3下Hook API實(shí)現(xiàn)分析
window HOOK技術(shù)NowCode
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服