欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
如何實(shí)現api鉤子
 

一、

序言對大多數的Windows開(kāi)發(fā)者來(lái)說(shuō),如何在Win32系統中對API函數的調用進(jìn)行攔截一直是項極富挑戰性的課題,因為這將是對你所掌握的計算機知識較為全面的考驗,尤其是一些在如今使用RAD進(jìn)行軟件開(kāi)發(fā)時(shí)并不常用的知識,這包括了操作系統原理、匯編語(yǔ)言甚至是關(guān)于機器指令代碼的(聽(tīng)上去真是有點(diǎn)恐怖,不過(guò)這是事實(shí))。

 

當前廣泛使用的Windows操作系統中,像Win 9xWin NT/2K,都提供了一種比較穩健的機制來(lái)使得各個(gè)進(jìn)程的內存地址空間之間是相互獨立,也就是說(shuō)一個(gè)進(jìn)程中的某個(gè)有效的內存地址對另一個(gè)進(jìn)程來(lái)說(shuō)是無(wú)意義的,這種內存保護措施大大增加了系統的穩定性。不過(guò),這也使得進(jìn)行系統級的API攔截的工作的難度也大大加大了。

 

當然,我這里所指的是比較文雅的攔截方式,通過(guò)修改可執行文件在內存中的映像中有關(guān)代碼,實(shí)現對API調用的動(dòng)態(tài)攔截;而不是采用比較暴力的方式,直接對可執行文件的磁盤(pán)存儲中機器代碼進(jìn)行改寫(xiě)。

 

 

二、

API鉤子系統一般框架通常,我們把攔截API的調用的這個(gè)過(guò)程稱(chēng)為是安裝一個(gè)API鉤子(API Hook)。一個(gè)API鉤子至少有兩個(gè)模塊組成:一個(gè)是鉤子服務(wù)器(Hook Server)模塊,一般為EXE的形式;一個(gè)是鉤子驅動(dòng)器(Hook Driver)模塊,一般為DLL的形式。

 

服務(wù)器主要負責向目標進(jìn)程注入驅動(dòng)器,使得驅動(dòng)器工作在目標進(jìn)程的地址空間中,這是關(guān)鍵的第一步。驅動(dòng)器則負責實(shí)際的API攔截工作,以便在我們所關(guān)心的API函數調用的前后能做一些我們需要的工作。

 

一個(gè)大家比較常見(jiàn)的API鉤子的例子就是一些實(shí)時(shí)翻譯軟件(像金山詞霸)中必備的的功能:屏幕抓詞,它主要是對一些GDI 函數進(jìn)行了攔截,獲取它們的輸入參數中的字符串,然后在自己的窗口中顯示出來(lái)。針對上述的兩個(gè)部分,有以下兩點(diǎn)需要我們重點(diǎn)考慮的: 選用何種DLL注入技術(shù) 采用何種API攔截機制

 

 三、

注入技術(shù)的選用由于在Win32系統中各個(gè)進(jìn)程的地址是互相獨立的,因此我們無(wú)法在一個(gè)進(jìn)程中對另一個(gè)進(jìn)程的代碼進(jìn)行有效的修改。而你要完成API鉤子的工作就必須進(jìn)行這種操作。因此,我們必須采取某種獨特的手段,使得API鉤子(準確的說(shuō)是鉤子驅動(dòng)器)能夠成為目標進(jìn)程中的一部分,才有較大的可能來(lái)對目標進(jìn)程數據和代碼進(jìn)行有控制的修改。

 

通常有以下幾種注入方式:

 

1.利用注冊表如果我們準備攔截的進(jìn)程連接了User32.dll,也就是使用了User32中的API(一般圖形界面的應用程序都符合這個(gè)條件),那么就可以簡(jiǎn)單把你的鉤子驅動(dòng)器DLL的名字作為值添加在下面注冊表的鍵下: HKEY_LOCAL_MACHINE\Software\Microsoft\WindowsNT\CurrentVersion\Windows\AppInit_DLLs 值的形式可以為單個(gè)DLL的文件名,或者是一組DLL的文件名,相鄰的名稱(chēng)之間用逗號或空格間隔。所有由該值標識的DLL將在符合條件的應用程序啟動(dòng)的時(shí)候裝載。這是一個(gè)操作系統內建的機制,相對其他方式來(lái)說(shuō)危險性較小,但它有一些比較明顯的缺點(diǎn): 該方法僅適用于NT/2K操作系統??纯存I的名稱(chēng)你就應該明白 為了激活或停止鉤子的注入,必須重新啟動(dòng)Windows。這個(gè)就似乎太不方便了 不能用此方法向沒(méi)有使用User32的應用程序注入DLL,例如控制臺應用程序 不管需要與否,鉤子DLL將注入每一個(gè)GUI應用程序,這將導致整個(gè)系統性能的下降

 

2

 

建立系統范圍的Windows鉤子要向某個(gè)進(jìn)程注入DLL,一個(gè)十分普遍也是比較簡(jiǎn)單的方法就是建立在標準的Windows鉤子的基礎上。Windows鉤子一般是在DLL中實(shí)現的,這是一個(gè)全局性的Windows鉤子的基本要求,這也符合我們的需要。當我們成功地調用SetWindowsHookEx函數之后,便在系統中安裝了某種類(lèi)型的消息鉤子,這個(gè)鉤子可以是針對某個(gè)進(jìn)程,也可以是針對系統中的所有進(jìn)程。一旦某個(gè)進(jìn)程中產(chǎn)生了該類(lèi)型的消息,操作系統會(huì )自動(dòng)把該鉤子所在的DLL映像到該進(jìn)程的地址空間中,從而使得消息回調函數(在SetWindowsHookEx的參數中指定)能夠對此消息進(jìn)行適當的處理,在這里,我們所感興趣的當然不是對消息進(jìn)行什么處理,因此在消息回調函數中只需把消息鉤子向后傳遞就可以了,但是我們所需的DLL已經(jīng)成功地注入了目標進(jìn)程的地址空間,從而可以完成后續工作。

 

我們知道,不同進(jìn)程中使用的DLL之間是不能直接共享數據的,因為它們活動(dòng)在不同的地址空間中。但在Windows鉤子DLL中,有一些數據,例如Windows鉤子句柄HHook,這是由SetWindowsHookEx函數返回值得到的,并且作為參數將在CallNextHookEx函數和UnhookWindoesHookEx函數中使用,顯然使用SetWindowsHookEx函數的進(jìn)程和使用CallNextHookEx函數的進(jìn)程一般不會(huì )是同一個(gè)進(jìn)程,因此我們必須能夠使句柄在所有的地址空間中都是有效的有意義的,也就是說(shuō),它的值必須必須在這些鉤子DLL所掛鉤的進(jìn)程之間是共享的。為了達到這個(gè)目的,我們就應該把它存儲在一個(gè)共享的數據區域中。

 

VC++中我們可以采用預編譯指令#pragma data_segDLL文件中創(chuàng )建一個(gè)新的段,并且在DEF文件中把該段的屬性設置為“shared”,這樣就建立了一個(gè)共享數據段。對于使用Delphi的人來(lái)說(shuō)就沒(méi)有這么幸運了:沒(méi)有類(lèi)似的比較簡(jiǎn)單的方法(或許是有的,但我沒(méi)有找到)。不過(guò)我們還是可以利用內存映像技術(shù)來(lái)申請使用一塊各進(jìn)程可以共享的內存區域,主要是利用了CreateFileMappingMapViewOfFile這兩個(gè)函數。這倒是一個(gè)通用的方法,適合所有的開(kāi)發(fā)語(yǔ)言,只要它能使用WindowsAPI。

 

BorlandBCB中有一個(gè)指令#pragma codesegVC++中的#pragma data_seg指令有點(diǎn)類(lèi)似,應該也能起到一樣的作用,但我試了一下,沒(méi)有沒(méi)有效果,而BCB的聯(lián)機幫助中對此也提到的不多,不知怎樣才能正確的使用。一旦鉤子DLL加載進(jìn)入目標進(jìn)程的地址空間后,在我們調用UnHookWindowsHookEx函數之前是無(wú)法使它停止工作的,除非目標進(jìn)程關(guān)閉。

 

這種DLL注入方式有兩個(gè)優(yōu)點(diǎn): 這種機制在Win 9x/MeWin NT/2K中都是得到支持的,預計在以后的版本中也將得到支持 鉤子DLL可以在不需要的時(shí)候,可由我們主動(dòng)的調用UnHookWindowsHookEx來(lái)卸載,比起使用注冊表的機制來(lái)說(shuō)方便了許多盡管這是一種相當簡(jiǎn)潔明了的方法,但它也有一些顯而易見(jiàn)的缺點(diǎn): 首先值得我們注意的是,Windows鉤子將會(huì )降低整個(gè)系統的性能,因為它額外增加了系統在消息處理方面的時(shí)間 其次,只有當目標進(jìn)程準備接受某種消息時(shí),鉤子所在的DLL才會(huì )被系統映射到該進(jìn)程的地址空間中,鉤子才能真正開(kāi)始發(fā)揮作用。因此如果我們要對某些進(jìn)程的整個(gè)生命周期內的API調用情況進(jìn)行監控,用這種方法顯然會(huì )遺漏某些API的調用

 

3

 使用 CreateRemoteThread函數在我看來(lái)這是一個(gè)相當棒的方法,然而不幸的是,CreateRemoteThread這個(gè)函數只能在Win NT/2K系統中才得到支持,雖然在Win 9x中這個(gè)API也能被安全的調用而不出錯,但它除了返回一個(gè)空值之外什么也不做。整個(gè)DLL注入過(guò)程十分簡(jiǎn)單。我們知道,任何一個(gè)進(jìn)程都可以使用LoadLibrary來(lái)動(dòng)態(tài)地加載一個(gè)DLL。但問(wèn)題是,我們如何讓目標進(jìn)程在我們的控制下來(lái)加載我們的鉤子DLL(也就是鉤子驅動(dòng)器)呢?這里有一個(gè)API函數CreateRemoteThread,通過(guò)它可在一個(gè)進(jìn)程中可建立并運行一個(gè)遠程的線(xiàn)程。

 

調用該API需要指定一個(gè)線(xiàn)程函數指針作為參數,該線(xiàn)程函數的原型如下: Function ThreadProc(lpParam: Pointer): DWORD;我們再來(lái)看一下LoadLibrary的函數原型: Function LoadLibrary(lpFileName: PChar): HModule;可以看出,這兩個(gè)函數原型實(shí)質(zhì)上是完全相同的(其實(shí)返回值是否相同關(guān)系不大,因為我們是無(wú)法得到遠程線(xiàn)程函數的返回值的),只是叫法不同而已,這種相同使得我們可以把直接把LoadLibrary當做線(xiàn)程函數來(lái)使用,從而在目標進(jìn)程中加載鉤子DLL。

 

類(lèi)似的,當我們需要卸載鉤子DLL時(shí),也可以FreeLibrary作為線(xiàn)程函數來(lái)使用,在目標進(jìn)程中移去鉤子DLL。一切看來(lái)是十分的簡(jiǎn)潔方便。通過(guò)調用GetProcAddress函數,我們可以得到LoadLibrary函數的地址。由于LoadLibraryKernel32中的函數,而這個(gè)系統DLL的映射地址對每一個(gè)進(jìn)程來(lái)說(shuō)都是相同的,因此LoadLibrary函數的地址也是如此。這點(diǎn)將確保我們能把該函數的地址作為一個(gè)有效的參數傳遞給CreateRemoteThread使用。

AddrOfLoadLibrary := GetProcAddress(GetModuleHandle(Kernel32.dll), LoadLibrary);

HremoteThread := CreateRemoteThread(HTargetProcess, nil, 0, AddrOfLoadLibrary, HookDllName, 0, nil);

 

要使用CreateRemoteThread,我們需要目標進(jìn)程的句柄作為參數。當我們用OpenProcess函數來(lái)得到進(jìn)程的句柄時(shí),通常是希望對此進(jìn)程有全權的存取操作,也就是以PROCESS_ALL_ACCESS為標志打開(kāi)進(jìn)程。但對于一些系統級的進(jìn)程,直接這樣顯然是不行的,只能返回一個(gè)的空句柄(值為零)。為此,我們必須把自己設置為擁有調試級的特權,這樣將具有最大的存取權限,從而使得我們能對這些系統級的進(jìn)程也可以進(jìn)行一些必要的操作。

 

4

 

通過(guò)BHO來(lái)注入DLL 有時(shí),我們想要注入DLL的對象僅僅是Internet Explorer。幸運的是,Windows操作系統為我們提供了一個(gè)簡(jiǎn)單的歸檔的方法(這保證了它的可靠性)―― 利用Browser Helper ObjectsBHO)。一個(gè)BHO是一個(gè)在 DLL中實(shí)現的COM對象,它主要實(shí)現了一個(gè)IObjectWithSite接口,而每當IE運行時(shí),它會(huì )自動(dòng)加載所有實(shí)現了該接口的COM對象。

 

四、

 

攔截機制在鉤子應用的系統級別方面,有兩類(lèi)API攔截的機制――內核級的攔截和用戶(hù)級的攔截。內核級的鉤子主要是通過(guò)一個(gè)內核模式的驅動(dòng)程序來(lái)實(shí)現,顯然它的功能應該最為強大,能捕捉到系統活動(dòng)的任何細節,但難度也較大,不在我們探討的范圍之內(尤其對我這個(gè)使用Delphi的人來(lái)說(shuō),還沒(méi)涉足這塊領(lǐng)域,因此也無(wú)法探討);

 

而用戶(hù)級的鉤子則通常是在普通的DLL中實(shí)現整個(gè)API的攔截工作,這才是我們現在所重點(diǎn)關(guān)注的。攔截API函數的調用,一般可有以下幾種方法:

1 代理DLL(特洛伊木馬)一個(gè)容易想到的可行的方法是用一個(gè)同名的DLL去替換原先那個(gè)輸出我們準備攔截的API所在的DLL。當然代理DLL也要和原來(lái)的一樣,輸出所有函數。如果想到DLL中可能輸出了上百個(gè)函數,我們就應該明白這種方法的效率是不高的。另外,我們還得考慮DLL的版本問(wèn)題。

 

2.改寫(xiě)執行代碼有許多攔截的方法是基于可執行代碼的改寫(xiě)。其中一個(gè)就是改變在CALL指令中使用的函數地址,這種方法有些難度,也比較容易出錯。它的基本思路是檢索出在內存中所有你所要攔截的APICALL指令,然后把原先的地址改成為你自己提供的函數的地址。

 

另外一種代碼改寫(xiě)的方法的實(shí)現方法更為復雜,它的主要的實(shí)現步驟是先找到原先的API函數的地址,然后把該函數開(kāi)始的幾個(gè)字節用一個(gè)JMP指令代替(有時(shí)還不得不改用一個(gè)INT指令),使得對該API函數的調用能夠轉向我們自己的函數調用。實(shí)現這種方法要牽涉到一系列壓棧和出棧這樣的較底層的操作,顯然對我們的匯編語(yǔ)言和操作系統底層方面的知識是一種考驗。這個(gè)方法倒和很多病毒的感染機制相類(lèi)似。

 

3.以調試器的身份進(jìn)行攔截另一個(gè)可選的方法是在目標函數中安置一個(gè)調試斷點(diǎn),使得進(jìn)程運行到此處就進(jìn)入調試狀態(tài)。然而這樣一些問(wèn)題也隨之而來(lái),其中較主要的是調試異常的產(chǎn)生將把進(jìn)程中所有的線(xiàn)程都掛起。它也需要一個(gè)額外的調試模塊來(lái)處理所有的異常,整個(gè)進(jìn)程將一直在調試狀態(tài)下運行,直至它運行結束。

4.改寫(xiě)輸入地址表這種方法主要得益于現如今Windows系統中所使用的可執行文件(包括EXE文件和DLL文件)的良好結構――PE文件格式(Portable Executable File Format),因此它相當穩健,又簡(jiǎn)單易行。要理解這種方法是如何運作的,首先你得對PE文件格式有所理解。

 

一個(gè)PE文件的結構大致如下圖所示: 一般PE文件一開(kāi)始是一段DOS程序,當你的程序在不支持Windows的環(huán)境中運行時(shí),它就會(huì )顯示“This Program cannot be run in DOS mode”這樣的警告語(yǔ)句,接著(zhù)這個(gè)DOS文件頭,就開(kāi)始真正的PE文件內容了。首先是一段稱(chēng)為“IMAGE_NT_HEADER”的數據,其中是許多關(guān)于整個(gè)PE文件的消息,在這段數據的尾端是一個(gè)稱(chēng)為Data Directory的數據表,通過(guò)它能快速定位一些PE文件中段(section)的地址。在這段數據之后,則是一個(gè)“IMAGE_SECTION_HEADER”的列表,其中的每一項都詳細描述了后面一個(gè)段的相關(guān)信息。接著(zhù)它就是PE文件中最主要的段數據了,執行代碼、數據和資源等等信息就分別存放在這些段中。

 

在所有的這些段里,有一個(gè)被稱(chēng)為“.idata”的段(輸入數據段)值得我們去注意,該段中包含著(zhù)一些被稱(chēng)為輸入地址表(IAT,Import Address Table)的數據列表。每個(gè)用隱式方式加載的API所在的DLL都有一個(gè)IAT與之對應,同時(shí)一個(gè)API的地址也與IAT中一項相對應。當一個(gè)應用程序加載到內存中后,針對每一個(gè)API函數調用,相應的產(chǎn)生如下的匯編指令:

JMP DWORD PTR [XXXXXXXX]

 

如果在VC++中使用了_delcspec(import),那么相應的指令就成為

CALL DWORD PTR [XXXXXXXX]。

 

不管怎樣,上述方括號中的總是一個(gè)地址,指向了輸入地址表中一個(gè)項,是一個(gè)DWORD,而正是這個(gè)DWORD才是API函數在內存中的真正地址。因此我們要想攔截一個(gè)API的調用,只要簡(jiǎn)單的把那個(gè)DWORD改為我們自己的函數的地址,那么所有關(guān)于這個(gè)API的調用將轉到我們自己的函數中去,攔截工作也就宣告順利的成功了。這里要注意的是,自定義的函數的調用形式應該是API的調用方式,也就是stdcall方式,而Delphi中默認的是pascal的調用方式,也就是register方式,它們在參數的傳遞方式等方面存在著(zhù)較大的區別。

 

另外,自定義的函數的參數形式可以和原先的API函數相同的,不過(guò)這也不是必須的,而且這樣的話(huà)在有些時(shí)候也會(huì )出現一些問(wèn)題,我在后面將會(huì )提到。因此要攔截API的調用,首先我們就要得到相應的IAT的地址。系統把一個(gè)進(jìn)程模塊加載到內存中,其實(shí)就是把PE文件幾乎是原封不動(dòng)的映射到進(jìn)程的地址空間中去,而模塊句柄HModule實(shí)際上就是模塊映像在內存中的地址,PE文件中一些數據項的地址,都是相對于這個(gè)地址的偏移量,因此被稱(chēng)為相對虛擬地址(RVA,Relative Virtual Address)。

 

于是我們就可以從HModule開(kāi)始,經(jīng)過(guò)一系列的地址偏移而得到IAT的地址。不過(guò)我這里有一個(gè)簡(jiǎn)單的方法,它使用了一個(gè)現有的API函數 ImageDirectoryEntryToData,它幫助我們在定位IAT時(shí)能少走幾步,省得把偏移地址弄錯了,走上彎路。不過(guò)純粹使用RVAHModule開(kāi)始來(lái)定位IAT的地址其實(shí)并不麻煩,而且這樣還更有助于我們對PE文件的結構的了解。上面提到的API函數是在DbgHelp.dll中輸出的(這是從Win 2K才開(kāi)始有的,在這之前是由ImageHlp.dll提供的),有關(guān)這個(gè)函數的詳細介紹可參見(jiàn)MSDN。

 

在找到IAT之后,我們只需在其中遍歷,找到我們需要的API地址,然后用我們自己的函數地址去覆蓋它。下面給出一段對應的源碼:

procedure RedirectApiCall; var ImportDesc:PIMAGE_IMPORT_DESCRIPTOR; FirstThunk:PIMAGE_THUNK_DATA32; sz:DWORD;

begin

//得到一個(gè)輸入描述結構列表的首地址,每個(gè)DLL都對應一個(gè)這樣的結構 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.Func<>nil do

begin

if FirstThunk.Func=OldAddressOfAPI then

begin

//找到了匹配的API地址 ……

//改寫(xiě)API的地址

break;

end;

Inc(FirstThunk);

end;

end;

Inc(ImportDesc);

end;

end;

 

最后有一點(diǎn)要指出,如果我們手工執行鉤子DLL的退出目標進(jìn)程,那么在退出前應該把函數調用地址改回原先的地址,也就是API的真正地址,因為一旦你的DLL退出了,改寫(xiě)的新的地址將指向一個(gè)毫無(wú)意義的內存區域,再使用它顯然會(huì )出現一個(gè)非法操作。

 

五、

 

替換函數的編寫(xiě) 前面關(guān)鍵的兩步做完了,一個(gè)API鉤子基本上也就完成了。不過(guò)還有一些相關(guān)的東西需要我們研究一番的,包括怎樣做一個(gè)替換函數。 下面是一個(gè)做替換函數的步驟: 首先,不失一般性,我們先假設有這樣的一個(gè)API函數,它的原型如下:

function someAPI(param1: Pchar;param2: Integer): DWORD;

 

接著(zhù)再建立一個(gè)與之有相同參數和返回值的函數類(lèi)型:

type FuncType= function (param1: Pchar;param2: Integer): DWORD;

然后我們把someAPI函數的地址存放在OldAddress指針中。接著(zhù)我們就可以著(zhù)手寫(xiě)替換函數的代碼了:

function DummyFunc(param1: Pchar;param2: Integer): DWORD; begin ……

//做一些調用前的操作

result := FuncType(OldAddress) (param1 , param2);

//調用原先的API函數 ……

//做一些調用后的操作

end;

 

我們再把這個(gè)函數的地址保存到NewAddress中,接著(zhù)用這地址覆蓋掉原先API的地址。這樣當目標進(jìn)程調用該API的時(shí)候,實(shí)際上是調用了我們自己的函數,在其中我們可以做一些操作,然后在調用原先的API函數,結果就像什么也沒(méi)發(fā)生過(guò)一樣。當然,我們也可以改變輸入參數,甚至是屏蔽調這個(gè)API函數的調用。

 

盡管上述方法是可行的,但有一個(gè)明顯的不足:這種替換函數的制作方法不具有通用性,只能針對少量的函數。如果只有幾個(gè)API要攔截,那么只需照上述說(shuō)的重復幾次就行了。但如果有各種各樣的API要處理,它們的參數個(gè)數和類(lèi)型以及返回值的類(lèi)型是各不相同的,還是采用這種方法就太沒(méi)效率了。

 

的確是的,上面給出的只是一個(gè)最簡(jiǎn)單最容易想到的方法,只是一個(gè)替換函數的基本構架。正如我前面所提到的,替換函數的與原先的API函數的參數類(lèi)型不必相同,一般的我們可以設計一個(gè)沒(méi)有調用參數也沒(méi)有返回值的函數,通過(guò)一定的技巧,使它能適應各種各樣的API函數調用,不過(guò)這得要求你對匯編語(yǔ)言有一定的了解。

 

下面我就對此詳細的說(shuō)一下。 首先,我們來(lái)看一下執行到一個(gè)函數內部前的堆棧情況(這里函數的調用方式為stdcall)。 由上面的例圖可知,函數的調用參數是按照從右到左的順序壓入堆棧的(堆棧是由高端向低端發(fā)展的),同時(shí)還壓入了一個(gè)函數返回地址。在進(jìn)入函數之前,ESP正指向返回地址。因此,我們只要從ESP+4開(kāi)始就可以取得這個(gè)函數的調用參數了,每取一個(gè)參數遞增4。另外,當從函數中返回時(shí),一般在EAX中存放函數的返回值。

 

了解了上述知識,我們就可以設計如下的一個(gè)比較通用的替換函數,它利用了Delphi的內嵌式匯編語(yǔ)言的特性。

Procedure DummyFunc;  

asm add esp,4 mov eax,esp//得到第一個(gè)參數

mov eax,esp+4//得到第二個(gè)參數 ……

//做一些處理,這里要保證esp在這之后恢復原樣

call OldAddress //調用原先的API函數 ……

//做一些其它的事情

end;

 

當然,這個(gè)替換函數還是比較簡(jiǎn)單的,你可以在其中調用一些純粹用OP語(yǔ)言寫(xiě)的函數或過(guò)程,去完成一些更復雜的操作(要是都用匯編來(lái)完成,那可得把你忙死了),不過(guò)應該這些函數的調用方式統一設置為stdcall方式,這使它們只利用堆棧來(lái)傳遞參數,因此你也只需時(shí)刻掌握好堆棧的變化情況就行了。如果你直接把上述匯編代碼所對應的機器指令存放在一個(gè)字節數組中,然后把數組的地址當作函數地址來(lái)使用,效果是一樣的。

 

以上代碼在 Win 2K/xp & Delphi 6.0 中實(shí)現。

 

 

六、后記

做一個(gè)API鉤子的確是件不容易的事情,尤其對我這個(gè)使用Delphi的人來(lái)說(shuō),為了解決某個(gè)問(wèn)題,經(jīng)常在OP、C++和匯編語(yǔ)言的資料中東查西找,在程序調試中還不時(shí)的發(fā)生一些意想不到的事情,弄的自己是手忙腳亂。不過(guò),好歹總算做出了一個(gè)API鉤子的雛形,還是令自己十分的高興,對計算機系統方面的知識也掌握了不少,受益非淺。當初在寫(xiě)這篇文章之前,我只是想翻譯一篇從網(wǎng)上Down下來(lái)的英文資料(網(wǎng)址為www.codeproject.com ,文章名叫“API Hook Revealed”,示例源代碼是用VC++寫(xiě)的,這里不得不佩服老外的水平,文章寫(xiě)得很有深度,而且每個(gè)細節都講的十分詳細)。

 

不過(guò)翻著(zhù)翻著(zhù),就覺(jué)得自己真是水平有限,很多地方雖然自己明白了,就是不知怎樣用中文來(lái)表達意思才明確,于是只得把已經(jīng)翻譯出來(lái)的覺(jué)得還可以一用的那部分加上一些自己在實(shí)際操作中的體會(huì )與心得,雜湊出了上面的這篇文章,盡管可能有些不倫不類(lèi),但也是化了我的很多時(shí)間,嘔心瀝血?。☉M愧,慚愧?。?,希望高手不要見(jiàn)笑,請多多指教。

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
HOOK API——Windows核心編程 第22章 插入DLL和掛接API學(xué)習筆記
Windows下HookAPI技術(shù)
Windows核心編程:DLL注入和API攔截
揭示win32 api攔截細節
Win2K下的Api函數的攔截
WINDOWS的鉤子函數知識與匯編實(shí)例 一
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久