你們有沒有想過,一些系統監控軟件是如何得知咱們所進行的操做的?殺軟啓發式分析是如何對病毒行爲進行攔截和監控的?外掛又是如何讀取到遊戲的內部數據的?這些功能的實現,基本都有API HOOK存在。API HOOK分爲ring0和ring3層,這裏咱們以ring3層API HOOK 進行講解分析。 app
API HOOK 在ring 3的實現,分爲inline 和修改導入表2種方法,所謂inline,是指直接寫入並覆蓋函數開頭字節彙編碼的方法,這種方法有一個問題,即是他被殺軟重點監控,成功率極低,而修改導入表的方法,則是指直接經過修改導入表,攔截特定函數調用序列的方法,優缺點不一,因爲本文只關注過導入表修改法的API HOOK,所以本文重點講解修改導入表方法。
ide
首先讓咱們講講導入表的結構吧,這種表的目的是記錄外部DLL導入函數地址的,經過修改導入表的表項指針, 可以使用戶的實際調用序列轉入你的函數中,此時對用戶來講,你的函數即是他要調用的「API」,映像數據目錄的結構以下:
函數
typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; DWORD Size; } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
根據這個結構,咱們知道,導入表每個項,有2個數據構成,一個是相對虛擬地址的地址,一個表項的大小,導入表的結構是: 編碼
typedef struct _IMAGE_THUNK_DATA32 { union { PBYTE ForwarderString; PDWORD Function; DWORD Ordinal; PIMAGE_IMPORT_BY_NAME AddressOfData; } u1; } IMAGE_THUNK_DATA32;
導入表分別記錄着: spa
ForwarderString 指向一個轉向者字符串的RVA
Function 被輸入的函數的內存地
Ordinal 被輸入的API的序數
AddressOfData 指向IMAGE_IMPORT_BY_NAME
首先,第一個問題來了,如何獲取IMAGE_DATA_DIRECTORY的指針呢,能夠經過ImageDirectoryEntryToData獲取,該函數定義爲 操作系統
PVOID WINAPI ImageDirectoryEntryToData( _In_ PVOID Base, _In_ BOOLEAN MappedAsImage, _In_ USHORT DirectoryEntry, _Out_ PULONG Size );
函數一共4個參數分別爲一下含義:
線程
Base:映像基地址 指針
MappedAsImage:它爲true時,系統將該模塊以映像文件的形式映射,不然以數據文件的形式映射。 blog
DirectoryEntry:要得到的段的索引,能夠爲如下值 索引
Size:這是一個輸出參數,表示輸出的信息的 大小
根據函數形式,咱們將執行
Import=(PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(Module,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,&Size);
如今,咱們獲得了導入表,若是返回值有效,咱們將執行一個循環以進行遍歷導入表,首先先看看這個循環:
while(Import->Name) { PSTR ModuleName=(PSTR)((PBYTE)Module+Import->Name); if(lstrcmpA(ModuleName,APIModuleName)==0) { PIMAGE_THUNK_DATA Thunk=(PIMAGE_THUNK_DATA)((PBYTE)Module+Import->FirstThunk); while(Thunk->u1.Function) { PROC *Proc=(PROC *)&Thunk->u1.Function; BOOL bFound=(*Proc==APIFunName); if(bFound) { if(!WriteProcessMemory(GetCurrentProcess(),Proc,&Function,sizeof(Function),NULL)&&(ERROR_NOACCESS==GetLastError())) { DWORD OldProtect=0; if(VirtualProtect(Proc,sizeof(Function),PAGE_WRITECOPY,&OldProtect)) { WriteProcessMemory(GetCurrentProcess(),Proc,&Function,sizeof(Function),NULL); VirtualProtect(Proc,sizeof(Function),OldProtect,&OldProtect); } } break; } Thunk++; } } Import++; }
這段代碼轉換成UML活動圖是:
至此,一個API HOOK基本邏輯已經被實現,但是這段代碼僅對本程序有效,那麼,如何讓其餘程序有效呢?這就須要DLL注入技術,實現DLL注入的方法不少,能夠利用操做系統消息鉤子、遠程線程注入等多種方法完成注入,舒適提示,要注入到遠程進程進行攔截,由於須要DLL注入技術,所以須要將API HOOK 代碼寫入DLL後,經過遠程加載DLL完成攔截操做,是非DLL以前記得恢復API HOOK設置,不然將致使異常。
看到這裏,相信你們大體已經知道API HOOK技術實現的具體細節了,如今動動你的手指,相信你也能夠本身實現一個API HOOK