




已閱讀5頁,還剩4頁未讀, 繼續(xù)免費(fèi)閱讀
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
翻譯:一、序言對(duì)大多數(shù)的Windows開發(fā)者來說,如何在Win32系統(tǒng)中對(duì)API函數(shù)的調(diào)用進(jìn)行攔截一直是項(xiàng)極富挑戰(zhàn)性的課題,因?yàn)檫@將是對(duì)你所掌握的計(jì)算機(jī)知識(shí)較為全面的考驗(yàn),尤其是一些在如今使用RAD進(jìn)行軟件開發(fā)時(shí)并不常用的知識(shí),這包括了操作系統(tǒng)原理、匯編語言甚至是關(guān)于機(jī)器指令代碼的(聽上去真是有點(diǎn)恐怖,不過這是事實(shí))。當(dāng)前廣泛使用的Windows操作系統(tǒng)中,像Win 9x和Win NT/2K,都提供了一種比較穩(wěn)健的機(jī)制來使得各個(gè)進(jìn)程的內(nèi)存地址空間之間是相互獨(dú)立,也就是說一個(gè)進(jìn)程中的某個(gè)有效的內(nèi)存地址對(duì)另一個(gè)進(jìn)程來說是無意義的,這種內(nèi)存保護(hù)措施大大增加了系統(tǒng)的穩(wěn)定性。不過,這也使得進(jìn)行系統(tǒng)級(jí)的API攔截的工作的難度也大大加大了。當(dāng)然,我這里所指的是比較文雅的攔截方式,通過修改可執(zhí)行文件在內(nèi)存中的映像中有關(guān)代碼,實(shí)現(xiàn)對(duì)API調(diào)用的動(dòng)態(tài)攔截;而不是采用比較暴力的方式,直接對(duì)可執(zhí)行文件的磁盤存儲(chǔ)中機(jī)器代碼進(jìn)行改寫。 二、API鉤子系統(tǒng)一般框架通常,我們把攔截API的調(diào)用的這個(gè)過程稱為是安裝一個(gè)API鉤子(API Hook)。一個(gè)API鉤子至少有兩個(gè)模塊組成:一個(gè)是鉤子服務(wù)器(Hook Server)模塊,一般為EXE的形式;一個(gè)是鉤子驅(qū)動(dòng)器(Hook Driver)模塊,一般為DLL的形式。服務(wù)器主要負(fù)責(zé)向目標(biāo)進(jìn)程注入驅(qū)動(dòng)器,使得驅(qū)動(dòng)器工作在目標(biāo)進(jìn)程的地址空間中,這是關(guān)鍵的第一步。驅(qū)動(dòng)器則負(fù)責(zé)實(shí)際的API攔截工作,以便在我們所關(guān)心的API函數(shù)調(diào)用的前后能做一些我們需要的工作。一個(gè)大家比較常見的API鉤子的例子就是一些實(shí)時(shí)翻譯軟件(像金山詞霸)中必備的的功能:屏幕抓詞,它主要是對(duì)一些GDI 函數(shù)進(jìn)行了攔截,獲取它們的輸入?yún)?shù)中的字符串,然后在自己的窗口中顯示出來。針對(duì)上述的兩個(gè)部分,有以下兩點(diǎn)需要我們重點(diǎn)考慮的:選用何種DLL注入技術(shù) 采用何種API攔截機(jī)制三、注入技術(shù)的選用由于在Win32系統(tǒng)中各個(gè)進(jìn)程的地址是互相獨(dú)立的,因此我們無法在一個(gè)進(jìn)程中對(duì)另一個(gè)進(jìn)程的代碼進(jìn)行有效的修改。而你要完成 API鉤子的工作就必須進(jìn)行這種操作。因此,我們必須采取某種獨(dú)特的手段,使得API鉤子(準(zhǔn)確的說是鉤子驅(qū)動(dòng)器)能夠成為目標(biāo)進(jìn)程中的一部分,才有較大的可能來對(duì)目標(biāo)進(jìn)程數(shù)據(jù)和代碼進(jìn)行有控制的修改。通常有以下幾種注入方式: 1利用注冊(cè)表如果我們準(zhǔn)備攔截的進(jìn)程連接了User32.dll,也就是使用了User32中的API(一般圖形界面的應(yīng)用程序都符合這個(gè)條件),那么就可以簡單把你的鉤子驅(qū)動(dòng)器DLL的名字作為值添加在下面注冊(cè)表的鍵下: HKEY_LOCAL_MACHINESoftwareMicrosoftWindowsNTCurrentVersionWindowsAppInit_DLLs 值的形式可以為單個(gè)DLL的文件名,或者是一組DLL的文件名,相鄰的名稱之間用逗號(hào)或空格間隔。所有由該值標(biāo)識(shí)的DLL將在符合條件的應(yīng)用程序啟動(dòng)的時(shí)候裝載。這是一個(gè)操作系統(tǒng)內(nèi)建的機(jī)制,相對(duì)其他方式來說危險(xiǎn)性較小,但它有一些比較明顯的缺點(diǎn):該方法僅適用于NT/2K操作系統(tǒng)??纯存I的名稱你就應(yīng)該明白 為了激活或停止鉤子的注入,必須重新啟動(dòng)Windows。這個(gè)就似乎太不方便了不能用此方法向沒有使用User32的應(yīng)用程序注入DLL,例如控制臺(tái)應(yīng)用程序不管需要與否,鉤子DLL將注入每一個(gè)GUI應(yīng)用程序,這將導(dǎo)致整個(gè)系統(tǒng)性能的下降2 建立系統(tǒng)范圍的Windows鉤子要向某個(gè)進(jìn)程注入DLL,一個(gè)十分普遍也是比較簡單的方法就是建立在標(biāo)準(zhǔn)的Windows鉤子的基礎(chǔ)上。 Windows鉤子一般是在DLL中實(shí)現(xiàn)的,這是一個(gè)全局性的Windows鉤子的基本要求,這也符合我們的需要。當(dāng)我們成功地調(diào)用 SetWindowsHookEx函數(shù)之后,便在系統(tǒng)中安裝了某種類型的消息鉤子,這個(gè)鉤子可以是針對(duì)某個(gè)進(jìn)程,也可以是針對(duì)系統(tǒng)中的所有進(jìn)程。一旦某個(gè)進(jìn)程中產(chǎn)生了該類型的消息,操作系統(tǒng)會(huì)自動(dòng)把該鉤子所在的DLL映像到該進(jìn)程的地址空間中,從而使得消息回調(diào)函數(shù)(在SetWindowsHookEx的參數(shù)中指定)能夠?qū)Υ讼⑦M(jìn)行適當(dāng)?shù)奶幚?,在這里,我們所感興趣的當(dāng)然不是對(duì)消息進(jìn)行什么處理,因此在消息回調(diào)函數(shù)中只需把消息鉤子向后傳遞就可以了,但是我們所需的DLL已經(jīng)成功地注入了目標(biāo)進(jìn)程的地址空間,從而可以完成后續(xù)工作。我們知道,不同進(jìn)程中使用的DLL之間是不能直接共享數(shù)據(jù)的,因?yàn)樗鼈兓顒?dòng)在不同的地址空間中。但在Windows鉤子DLL中,有一些數(shù)據(jù),例如Windows鉤子句柄HHook,這是由SetWindowsHookEx函數(shù)返回值得到的,并且作為參數(shù)將在CallNextHookEx函數(shù)和 UnhookWindoesHookEx函數(shù)中使用,顯然使用SetWindowsHookEx函數(shù)的進(jìn)程和使用CallNextHookEx函數(shù)的進(jìn)程一般不會(huì)是同一個(gè)進(jìn)程,因此我們必須能夠使句柄在所有的地址空間中都是有效的有意義的,也就是說,它的值必須必須在這些鉤子DLL所掛鉤的進(jìn)程之間是共享的。為了達(dá)到這個(gè)目的,我們就應(yīng)該把它存儲(chǔ)在一個(gè)共享的數(shù)據(jù)區(qū)域中。在VC+中我們可以采用預(yù)編譯指令#pragma data_seg在DLL文件中創(chuàng)建一個(gè)新的段,并且在DEF文件中把該段的屬性設(shè)置為“shared”,這樣就建立了一個(gè)共享數(shù)據(jù)段。對(duì)于使用 Delphi的人來說就沒有這么幸運(yùn)了:沒有類似的比較簡單的方法(或許是有的,但我沒有找到)。不過我們還是可以利用內(nèi)存映像技術(shù)來申請(qǐng)使用一塊各進(jìn)程可以共享的內(nèi)存區(qū)域,主要是利用了CreateFileMapping和MapViewOfFile這兩個(gè)函數(shù)。這倒是一個(gè)通用的方法,適合所有的開發(fā)語言,只要它能使用Windows的API。在Borland的BCB中有一個(gè)指令#pragma codeseg與VC+中的#pragma data_seg指令有點(diǎn)類似,應(yīng)該也能起到一樣的作用,但我試了一下,沒有沒有效果,而BCB的聯(lián)機(jī)幫助中對(duì)此也提到的不多,不知怎樣才能正確的使用。一旦鉤子DLL加載進(jìn)入目標(biāo)進(jìn)程的地址空間后,在我們調(diào)用UnHookWindowsHookEx函數(shù)之前是無法使它停止工作的,除非目標(biāo)進(jìn)程關(guān)閉。這種DLL注入方式有兩個(gè)優(yōu)點(diǎn): 這種機(jī)制在Win 9x/Me和Win NT/2K中都是得到支持的,預(yù)計(jì)在以后的版本中也將得到支持鉤子DLL可以在不需要的時(shí)候,可由我們主動(dòng)的調(diào)用UnHookWindowsHookEx來卸載,比起使用注冊(cè)表的機(jī)制來說方便了許多盡管這是一種相當(dāng)簡潔明了的方法,但它也有一些顯而易見的缺點(diǎn):首先值得我們注意的是,Windows鉤子將會(huì)降低整個(gè)系統(tǒng)的性能,因?yàn)樗~外增加了系統(tǒng)在消息處理方面的時(shí)間其次,只有當(dāng)目標(biāo)進(jìn)程準(zhǔn)備接受某種消息時(shí),鉤子所在的DLL才會(huì)被系統(tǒng)映射到該進(jìn)程的地址空間中,鉤子才能真正開始發(fā)揮作用。因此如果我們要對(duì)某些進(jìn)程的整個(gè)生命周期內(nèi)的API調(diào)用情況進(jìn)行監(jiān)控,用這種方法顯然會(huì)遺漏某些API的調(diào)用 3使用 CreateRemoteThread函數(shù)在我看來這是一個(gè)相當(dāng)棒的方法,然而不幸的是,CreateRemoteThread這個(gè)函數(shù)只能在Win NT/2K系統(tǒng)中才得到支持,雖然在Win 9x中這個(gè)API也能被安全的調(diào)用而不出錯(cuò),但它除了返回一個(gè)空值之外什么也不做。整個(gè)DLL注入過程十分簡單。我們知道,任何一個(gè)進(jìn)程都可以使用 LoadLibrary來動(dòng)態(tài)地加載一個(gè)DLL。但問題是,我們?nèi)绾巫屇繕?biāo)進(jìn)程在我們的控制下來加載我們的鉤子DLL(也就是鉤子驅(qū)動(dòng)器)呢?這里有一個(gè) API函數(shù)CreateRemoteThread,通過它可在一個(gè)進(jìn)程中可建立并運(yùn)行一個(gè)遠(yuǎn)程的線程。調(diào)用該API需要指定一個(gè)線程函數(shù)指針作為參數(shù),該線程函數(shù)的原型如下: Function ThreadProc(lpParam: Pointer): DWORD;我們?cè)賮砜匆幌翷oadLibrary的函數(shù)原型: Function LoadLibrary(lpFileName: PChar): HModule;可以看出,這兩個(gè)函數(shù)原型實(shí)質(zhì)上是完全相同的(其實(shí)返回值是否相同關(guān)系不大,因?yàn)槲覀兪菬o法得到遠(yuǎn)程線程函數(shù)的返回值的),只是叫法不同而已,這種相同使得我們可以把直接把LoadLibrary當(dāng)做線程函數(shù)來使用,從而在目標(biāo)進(jìn)程中加載鉤子DLL。類似的,當(dāng)我們需要卸載鉤子DLL時(shí),也可以FreeLibrary作為線程函數(shù)來使用,在目標(biāo)進(jìn)程中移去鉤子DLL。一切看來是十分的簡潔方便。通過調(diào)用GetProcAddress函數(shù),我們可以得到LoadLibrary函數(shù)的地址。由于LoadLibrary是Kernel32中的函數(shù),而這個(gè)系統(tǒng)DLL的映射地址對(duì)每一個(gè)進(jìn)程來說都是相同的,因此LoadLibrary函數(shù)的地址也是如此。這點(diǎn)將確保我們能把該函數(shù)的地址作為一個(gè)有效的參數(shù)傳遞給CreateRemoteThread使用。 AddrOfLoadLibrary := GetProcAddress(GetModuleHandle(Kernel32.dll), LoadLibrary); HremoteThread := CreateRemoteThread(HTargetProcess, nil, 0, AddrOfLoadLibrary, HookDllName, 0, nil); 要使用CreateRemoteThread,我們需要目標(biāo)進(jìn)程的句柄作為參數(shù)。當(dāng)我們用OpenProcess函數(shù)來得到進(jìn)程的句柄時(shí),通常是希望對(duì)此進(jìn)程有全權(quán)的存取操作,也就是以PROCESS_ALL_ACCESS為標(biāo)志打開進(jìn)程。但對(duì)于一些系統(tǒng)級(jí)的進(jìn)程,直接這樣顯然是不行的,只能返回一個(gè)的空句柄(值為零)。為此,我們必須把自己設(shè)置為擁有調(diào)試級(jí)的特權(quán),這樣將具有最大的存取權(quán)限,從而使得我們能對(duì)這些系統(tǒng)級(jí)的進(jìn)程也可以進(jìn)行一些必要的操作。 4 通過BHO來注入DLL 有時(shí),我們想要注入DLL的對(duì)象僅僅是Internet Explorer。幸運(yùn)的是,Windows操作系統(tǒng)為我們提供了一個(gè)簡單的歸檔的方法(這保證了它的可靠性) 利用Browser Helper Objects(BHO)。一個(gè)BHO是一個(gè)在 DLL中實(shí)現(xiàn)的COM對(duì)象,它主要實(shí)現(xiàn)了一個(gè)IObjectWithSite接口,而每當(dāng)IE運(yùn)行時(shí),它會(huì)自動(dòng)加載所有實(shí)現(xiàn)了該接口的COM對(duì)象。 四、攔截機(jī)制在鉤子應(yīng)用的系統(tǒng)級(jí)別方面,有兩類API攔截的機(jī)制內(nèi)核級(jí)的攔截和用戶級(jí)的攔截。內(nèi)核級(jí)的鉤子主要是通過一個(gè)內(nèi)核模式的驅(qū)動(dòng)程序來實(shí)現(xiàn),顯然它的功能應(yīng)該最為強(qiáng)大,能捕捉到系統(tǒng)活動(dòng)的任何細(xì)節(jié),但難度也較大,不在我們探討的范圍之內(nèi)(尤其對(duì)我這個(gè)使用Delphi的人來說,還沒涉足這塊領(lǐng)域,因此也無法探討);而用戶級(jí)的鉤子則通常是在普通的DLL中實(shí)現(xiàn)整個(gè)API的攔截工作,這才是我們現(xiàn)在所重點(diǎn)關(guān)注的。攔截API函數(shù)的調(diào)用,一般可有以下幾種方法: 1代理DLL(特洛伊木馬)一個(gè)容易想到的可行的方法是用一個(gè)同名的DLL去替換原先那個(gè)輸出我們準(zhǔn)備攔截的API所在的DLL。當(dāng)然代理DLL也要和原來的一樣,輸出所有函數(shù)。如果想到DLL中可能輸出了上百個(gè)函數(shù),我們就應(yīng)該明白這種方法的效率是不高的。另外,我們還得考慮DLL的版本問題。 2改寫執(zhí)行代碼有許多攔截的方法是基于可執(zhí)行代碼的改寫。其中一個(gè)就是改變?cè)贑ALL指令中使用的函數(shù)地址,這種方法有些難度,也比較容易出錯(cuò)。它的基本思路是檢索出在內(nèi)存中所有你所要攔截的API的CALL指令,然后把原先的地址改成為你自己提供的函數(shù)的地址。另外一種代碼改寫的方法的實(shí)現(xiàn)方法更為復(fù)雜,它的主要的實(shí)現(xiàn)步驟是先找到原先的API函數(shù)的地址,然后把該函數(shù)開始的幾個(gè)字節(jié)用一個(gè)JMP指令代替(有時(shí)還不得不改用一個(gè)INT指令),使得對(duì)該API函數(shù)的調(diào)用能夠轉(zhuǎn)向我們自己的函數(shù)調(diào)用。實(shí)現(xiàn)這種方法要牽涉到一系列壓棧和出棧這樣的較底層的操作,顯然對(duì)我們的匯編語言和操作系統(tǒng)底層方面的知識(shí)是一種考驗(yàn)。這個(gè)方法倒和很多病毒的感染機(jī)制相類似。 3以調(diào)試器的身份進(jìn)行攔截另一個(gè)可選的方法是在目標(biāo)函數(shù)中安置一個(gè)調(diào)試斷點(diǎn),使得進(jìn)程運(yùn)行到此處就進(jìn)入調(diào)試狀態(tài)。然而這樣一些問題也隨之而來,其中較主要的是調(diào)試異常的產(chǎn)生將把進(jìn)程中所有的線程都掛起。它也需要一個(gè)額外的調(diào)試模塊來處理所有的異常,整個(gè)進(jìn)程將一直在調(diào)試狀態(tài)下運(yùn)行,直至它運(yùn)行結(jié)束。4改寫輸入地址表這種方法主要得益于現(xiàn)如今Windows系統(tǒng)中所使用的可執(zhí)行文件(包括EXE文件和DLL文件)的良好結(jié)構(gòu)PE文件格式(Portable Executable File Format),因此它相當(dāng)穩(wěn)健,又簡單易行。要理解這種方法是如何運(yùn)作的,首先你得對(duì)PE文件格式有所理解。一個(gè)PE文件的結(jié)構(gòu)大致如下圖所示:一般PE文件一開始是一段DOS程序,當(dāng)你的程序在不支持Windows的環(huán)境中運(yùn)行時(shí),它就會(huì)顯示“This Program cannot be run in DOS mode”這樣的警告語句,接著這個(gè)DOS文件頭,就開始真正的PE文件內(nèi)容了。首先是一段稱為“IMAGE_NT_HEADER”的數(shù)據(jù),其中是許多關(guān)于整個(gè)PE文件的消息,在這段數(shù)據(jù)的尾端是一個(gè)稱為Data Directory的數(shù)據(jù)表,通過它能快速定位一些PE文件中段(section)的地址。在這段數(shù)據(jù)之后,則是一個(gè) “IMAGE_SECTION_HEADER”的列表,其中的每一項(xiàng)都詳細(xì)描述了后面一個(gè)段的相關(guān)信息。接著它就是PE文件中最主要的段數(shù)據(jù)了,執(zhí)行代碼、數(shù)據(jù)和資源等等信息就分別存放在這些段中。在所有的這些段里,有一個(gè)被稱為“.idata”的段(輸入數(shù)據(jù)段)值得我們?nèi)プ⒁?,該段中包含著一些被稱為輸入地址表(IAT,Import Address Table)的數(shù)據(jù)列表。每個(gè)用隱式方式加載的API所在的DLL都有一個(gè)IAT與之對(duì)應(yīng),同時(shí)一個(gè)API的地址也與IAT中一項(xiàng)相對(duì)應(yīng)。當(dāng)一個(gè)應(yīng)用程序加載到內(nèi)存中后,針對(duì)每一個(gè)API函數(shù)調(diào)用,相應(yīng)的產(chǎn)生如下的匯編指令: JMP DWORD PTR XXXXXXXX 如果在VC+中使用了_delcspec(import),那么相應(yīng)的指令就成為CALL DWORD PTR XXXXXXXX。不管怎樣,上述方括號(hào)中的總是一個(gè)地址,指向了輸入地址表中一個(gè)項(xiàng),是一個(gè)DWORD,而正是這個(gè)DWORD才是API函數(shù)在內(nèi)存中的真正地址。因此我們要想攔截一個(gè)API的調(diào)用,只要簡單的把那個(gè)DWORD改為我們自己的函數(shù)的地址,那么所有關(guān)于這個(gè)API的調(diào)用將轉(zhuǎn)到我們自己的函數(shù)中去,攔截工作也就宣告順利的成功了。這里要注意的是,自定義的函數(shù)的調(diào)用形式應(yīng)該是API的調(diào)用方式,也就是stdcall方式,而Delphi中默認(rèn)的是 pascal的調(diào)用方式,也就是register方式,它們?cè)趨?shù)的傳遞方式等方面存在著較大的區(qū)別。另外,自定義的函數(shù)的參數(shù)形式可以和原先的API函數(shù)相同的,不過這也不是必須的,而且這樣的話在有些時(shí)候也會(huì)出現(xiàn)一些問題,我在后面將會(huì)提到。因此要攔截API的調(diào)用,首先我們就要得到相應(yīng)的IAT的地址。系統(tǒng)把一個(gè)進(jìn)程模塊加載到內(nèi)存中,其實(shí)就是把PE文件幾乎是原封不動(dòng)的映射到進(jìn)程的地址空間中去,而模塊句柄HModule實(shí)際上就是模塊映像在內(nèi)存中的地址,PE文件中一些數(shù)據(jù)項(xiàng)的地址,都是相對(duì)于這個(gè)地址的偏移量,因此被稱為相對(duì)虛擬地址(RVA,Relative Virtual Address)。于是我們就可以從HModule開始,經(jīng)過一系列的地址偏移而得到IAT的地址。不過我這里有一個(gè)簡單的方法,它使用了一個(gè)現(xiàn)有的API函數(shù) ImageDirectoryEntryToData,它幫助我們?cè)诙ㄎ籌AT時(shí)能少走幾步,省得把偏移地址弄錯(cuò)了,走上彎路。不過純粹使用RVA從 HModule開始來定位IAT的地址其實(shí)并不麻煩,而且這樣還更有助于我們對(duì)PE文件的結(jié)構(gòu)的了解。上面提到的API函數(shù)是在DbgHelp.dll中輸出的(這是從Win 2K才開始有的,在這之前是由ImageHlp.dll提供的),有關(guān)這個(gè)函數(shù)的詳細(xì)介紹可參見MSDN。 在找到IAT之后,我們只需在其中遍歷,找到我們需要的API地址,然后用我們自己的函數(shù)地址去覆蓋它。下面給出一段對(duì)應(yīng)的源碼: procedure RedirectApiCall; var ImportDesc:PIMAGE_IMPORT_DESCRIPTOR; FirstThunk:PIMAGE_THUNK_DATA32; sz:DWORD; begin /得到一個(gè)輸入描述結(jié)構(gòu)列表的首地址,每個(gè)DLL都對(duì)應(yīng)一個(gè)這樣的結(jié)構(gòu) ImportDesc:=ImageDirectoryEntryToData(Pointer(HTargetModule), true, IMAGE_DIRECTORY_ENTRY_IMPORT, sz); while Pointer(ImportDesc.Name)nil do begin /判斷是否是所需的DLL輸入描述 if StrIComp(PChar(DllName),PChar(HTargetModule+ImportDesc.Name)=0 then begin /得到IAT的首地址 FirstThunk:=PIMAGE_THUNK_DATA32(HTargetModule+ImportDesc.FirstThunk); while FirstThunk.Funcnil do begin if FirstThunk.Func=OldAddressOfAPI then begin /找到了匹配的API地址 /改寫API的地址 break; end; Inc(FirstThunk); end; end; Inc(ImportDesc); end; end; 最后有一點(diǎn)要指出,如果我們手工執(zhí)行鉤子DLL的退出目標(biāo)進(jìn)程,那么在退出前應(yīng)該把函數(shù)調(diào)用地址改回原先的地址,也就是API的真正地址,因?yàn)橐坏┠愕腄LL退出了,改寫的新的地址將指向一個(gè)毫無意義的內(nèi)存區(qū)域,再使用它顯然會(huì)出現(xiàn)一個(gè)非法操作。 五、替換函數(shù)的編寫 前面關(guān)鍵的兩步做完了,一個(gè)API鉤子基本上也就完成了。不過還有一些相關(guān)的東西需要我們研究一番的,包括怎樣做一個(gè)替換函數(shù)。 下面是一個(gè)做替換函數(shù)的步驟: 首先,不失一般性,我們先假設(shè)有這樣的一個(gè)API函數(shù),它的原型如下: function someAPI(param1: Pchar;param2: Integer): DWORD; 接著再建立一個(gè)與之有相同參數(shù)和返回值的函數(shù)類型: type FuncType= function (param1: Pchar;param2: Integer): DWORD; 然后我們把someAPI函數(shù)的地址存放在OldAddress指針中。接著我們就可以著手寫替換函數(shù)的代碼了: function DummyFunc(param1: Pchar;param2: Integer): DWORD; begin /做一些調(diào)用前的操作 result := FuncType(OldAddress) (param1 , param2); /調(diào)用原先的API函數(shù) /做一些調(diào)用后的操作 end; 我們?cè)侔堰@個(gè)函數(shù)的地址保存到NewAddress中,接著用這地址覆蓋掉原先API的地址。這樣當(dāng)目標(biāo)進(jìn)程調(diào)用該API的時(shí)候,實(shí)際上是調(diào)用了我們自己的函數(shù),在其中我們可以做一些操作,然后在調(diào)用原先的API函數(shù),結(jié)果就像什么也沒發(fā)生過一樣。當(dāng)然,我們也可以改變輸入?yún)?shù),甚至是屏蔽調(diào)這個(gè)API函數(shù)的調(diào)用。盡管上述方法是可行的,但有一個(gè)明顯的不足:這種替換函數(shù)的制作方法不具有通用性,只能針對(duì)少量的函數(shù)。如果只有幾個(gè)API要攔截,那么只需照上述說的重復(fù)幾次就行了。但如果有各種各樣的API要處理,它們的參數(shù)個(gè)數(shù)和類型以及返回值的類型是各不相同的,還是采用這種方法就太沒效率了。的確是的,上面給出的只是一個(gè)最簡單最容易想到的方法,只是一個(gè)替換函數(shù)的基本構(gòu)架。正如我前面所提到的,替換函數(shù)的與原先的API函數(shù)的參數(shù)類型不必相同,一般的我們可以設(shè)計(jì)一個(gè)沒有調(diào)用參數(shù)也沒有返回值的函數(shù),通過一定的技巧,使它能適應(yīng)各種各樣的API函數(shù)調(diào)用,不過這得要求你對(duì)匯編語言有一定的了解。
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 《守護(hù)健康:心腦血管疾病防治課件》
- 《腹瀉嘔吐病案探討》課件
- 招聘助理崗位培訓(xùn)大綱
- 挑戰(zhàn)2024年高級(jí)會(huì)計(jì)考試試題及答案難點(diǎn)
- 消防職業(yè)技能提升途徑試題及答案
- 《社區(qū)護(hù)理》課件
- 模擬醫(yī)學(xué)教育科研
- 冷凍品代理商管理體系
- 《市場營銷策略》課件
- 人教版九年級(jí)物理下冊(cè)第十三章內(nèi)能第二節(jié)內(nèi)能的教學(xué)設(shè)計(jì)
- 發(fā)現(xiàn)人生的閃光點(diǎn)主題班會(huì)課件
- 司法鑒定專題培訓(xùn)課件
- 智能制造裝備應(yīng)用專業(yè)群市場需求調(diào)研報(bào)告
- 風(fēng)濕免疫疾病的藥物不良反應(yīng)與監(jiān)測(cè)策略
- 【上市公司內(nèi)部控制問題及對(duì)策的案例探析:以小米集團(tuán)為例11000字(論文)】
- 福建省福州市倉山區(qū)2023-2024學(xué)年六年級(jí)上學(xué)期期末數(shù)學(xué)試卷
- 廣西陸上風(fēng)電項(xiàng)目規(guī)劃清單
- 考試工作先進(jìn)個(gè)人事跡
- 反假貨幣培訓(xùn)
- 《延年益壽養(yǎng)生方法》課件
- 《全的針灸方法》課件
評(píng)論
0/150
提交評(píng)論