API Hook 原理

一、什麼是API Hook

    見下圖所示,API Hook就是對API的正常調用起一個攔截或中間層的作用,這樣可以
在調用正常的API之前得到控制權,執行自己的代碼。其中Module指映射到內存中的可執
行文件或DLL。

      module0    module1
 |       |
CALL module1!API001 --------------------------------->| API001
 |<-------------------------------------------|
 |       |
  API215 |<----------------------------------CALL module0!API215
 |------------------------------------------->|
 |       |
 *       *
       vs.

      module0    Hooooks.dll    module1
 |        |       |
CALL module1!API001 -------->API001>----------------->| API001
 |<-----------------<HOOOOK<------------------|
 |        |       |
  API215 |<-----------------<API215<---------CALL module0!API215
 |------------------>HOOOOK>----------------->|
 |        |       |
 *        *       *


二、API Hook的原理
   
    這裏的API既包括傳統的Win32 APIs,也包括任何Module輸出的函數調用。熟悉PE文件格
式的朋友都知道,PE文件將對外部Module輸出函數的調用信息保存在輸入表中,即.idata段。
下面首先介紹本段的結構。
    輸入表首先以一個IMAGE_IMPORT_DESCRIPTOR(簡稱IID)數組開始。每個被PE文件隱式鏈接
進來的DLL都有一個IID.在這個數組中的最後一個單元是NULL,可以由此計算出該數組的項數。
例如,某個PE文件從兩個DLL中引入函數,就存在兩個IID結構來描述這些DLL文件,並在兩個
IID結構的最後由一個內容全爲0的IID結構作爲結束。幾個結構定義如下:

IMAGE_IMPORT_DESCRIPTOR struct
union{
DWORD Characteristics; ;00h
DWORD OriginalFirstThunk;
};
TimeDateStamp DWORD ;04h
ForwarderChain DWORD ;08h
Name DWORD ;0Ch
FirstThunk DWORD ;10h
IMAGE_IMPROT_DESCRIPTOR ends

typedef struct _IMAGE_THUNK_DATA{
union{
PBYTE ForwarderString;
PDWORD Functions;
DWORD Ordinal;
PIMAGE_IMPORT_BY_NAME AddressOfData;
}u1;
}

IMAGE_IMPORT_BY_NAME結構保存一個輸入函數的相關信息:
IMAGE_IMPORT_BY_NAME struct
Hint WORD ? ;本函數在其所駐留DLL的輸出表中的序號
Name BYTE ? ;輸入函數的函數名,以NULL結尾的ASCII字符串
IMAGE_IMPORT_BY_NAME ends

OriginalFirstThunk(Characteristics):這是一個IMAGE_THUNK_DATA數組的RVA(相對於PE文件
起始處)。其中每個指針都指向IMAGE_IMPORT_BY_NAME結構。
TimeDateStamp:一個32位的時間標誌,可以忽略。
ForwarderChain:正向鏈接索引,一般爲0。當程序引用一個DLL中的API,而這個API又引用別的
DLL的API時使用。
NameLL名字的指針。是個以00結尾的ASCII字符的RVA地址,如"KERNEL32.DLL"。
FirstThunk:通常也是一個IMAGE_THUNK_DATA數組的RVA。如果不是一個指針,它就是該功能在
DLL中的序號。
OriginalFirstThunk與FirstThunk指向兩個本質相同的數組IMAGE_THUNK_DATA,但名稱不同,
分別是輸入名稱表(Import Name Table,INT)和輸入地址表(Import Address Table,IAT)。
IMAGE_THUNK_DATA結構是個雙字,在不同時刻有不同的含義,當雙字最高位爲1時,表示函數以
序號輸入,低位就是函數序號。當雙字最高位爲0時,表示函數以字符串類型的函數名
方式輸入,這時它是指向IMAGE_IMPORT_BY_NAME結構的RVA。
三個結構關係如下圖:

IMAGE_IMPORT_DESCRIPTOR          INT          IMAGE_IMPORT_BY_NAME    IAT
 --------------------    /-->----------------     ----------     ---------------- <--/
| OriginalFirstThunk |--/   |IMAGE_THUNK_DATA|-->|01| 函數1 |<--|IMAGE_THUNK_DATA|   |
|--------------------|      |----------------|   |----------|   |----------------|   |
|    TimeDateStamp   |      |IMAGE_THUNK_DATA|-->|02| 函數2 |<--|IMAGE_THUNK_DATA|   |
|--------------------|      |----------------|   |----------|   |----------------|   |
|    ForwarderChain  |      |      ...       |-->| n|  ...  |<--|      ...       |   |
|--------------------|       ----------------     ----------     ----------------    |
|        Name        |------>"USER32.dll"                                            |
|--------------------|                                                               |
|      FirstThunk    |---------------------------------------------------------------/
 --------------------

    在PE文件中對DLL輸出函數的調用,主要以這種形式出現:
call dword ptr[xxxxxxxx] 或
jmp [xxxxxxxx]
其中地址xxxxxxxx就是IAT中一個IMAGE_THUNK_DATA結構的地址,[xxxxxxxx]取值爲IMAGE_THUNK_DATA
的值,即IMAGE_IMPORT_BY_NAME的地址。在操作系統加載PE文件的過程中,通過IID中的Name加載相應
的DLL,然後根據INT或IAT所指向的IMAGE_IMPORT_BY_NAME中的輸入函數信息,在DLL中確定函數地址,
然後將函數地址寫到IAT中,此時IAT將不再指向IMAGE_IMPORT_BY_NAME數組。這樣[xxxxxxxx]取到的
就是真正的API地址。
    從以上分析可以看出,要攔截API的調用,可以通過改寫IAT來實現,將自己函數的地址寫到IAT中,
達到攔截目的。

    另外一種方法的原理更簡單,也更直接。我們不是要攔截嗎,先在內存中定位要攔截的API的地址,
然後改寫代碼的前幾個字節爲 jmp xxxxxxxx,其中xxxxxxxx爲我們的API的地址。這樣對欲攔截API的
調用實際上就跳轉到了咱們的API調用去了,完成了攔截。不攔截時,再改寫回來就是了。


三、實現前的準備

    兩種攔截方法,最終目的都是使程序對欲攔截API的調用跳轉到自己的API。所以我們的API代碼對
欲攔截進程必須是可見的,即我們的代碼要映射到欲攔截進程的地址空間中。

    在《隱藏進程》一文中我介紹了遠程線程注入代碼的技術,這裏我們可以採用這種方法向欲攔截進
程中注入我們的API代碼。同樣有兩種注入方式,一種是,直接將代碼WriteProcessMemory到欲攔截進
程中,寫入的代碼包括我們的API代碼和遠程線程的入口函數代碼。這種的缺點是有一些細節問題要解
決,如參數傳遞、寫入代碼大小的確定等並且由於多了一個遠程線程效率不是很高,如果要攔截所有的
進程,即必須在每個進程中注入代碼、插入線程。另一種是,注入DLL,遠程線程入口函數爲LoadLirary,
當然也存在效率的問題,但免去了一些麻煩。

    這裏我們主要介紹通過設置鉤子(Hook)來自動注入DLL到欲攔截進程。先簡單說明一下鉤子是怎麼回事。

    Hook指出了系統消息處理機制。利用Hook,可以在應用程序中安裝子程序監視系統和進程之間的消息
傳遞,這個監視過程是在消息到達目的窗口過程之前。系統支持很多不同類型的Hooks,不同的hook提供不
同的消息處理機制。比如,應用程序可以使用WH_MOUSE_hook來監視鼠標消息的傳遞。系統爲不同類型的
Hook提供單獨的Hook鏈。Hook鏈是一個指針列表,這個列表的指針指向指定的,應用程序定義的,被hook
過程調用的回調函數。當與指定的Hook類型關聯的消息發生時,系統就把這個消息傳遞到Hook過程。一些
Hook過程可以只監視消息,或者修改消息,或者停止消息的前進,避免這些消息傳遞到下一個Hook過程或
者目的窗口。
    爲了利用特殊的Hook類型,可由開發者提供了Hook過程,使用SetWindowsHookEx函數來把Hook過程安
裝到關聯的Hook鏈。Hook過程必須按照以下的語法:
    LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam);
    HookProc是應用程序定義的名字,nCode參數是Hook代碼,Hook過程使用這個參數來確定任務。這個參
數的值依賴於Hook類型,每一種Hook都有自己的Hook代碼特徵字符集。wParam和lParam參數的值依賴於
Hook代碼,但是它們的典型值是包含了關於發送或者接收消息的信息。
    SetWindowsHookEx函數總是在Hook鏈的開頭安裝Hook過程。當指定類型的Hook監視的事件發生時,系統
就調用與這個Hook關聯的Hook鏈的開頭的Hook過程。每一個Hook鏈中的Hook過程都決定是否把這個事件傳遞
到下一個Hook過程。Hook過程傳遞事件到下一個Hook過程需要調用CallNextHookEx函數。有些類型Hook的
Hook過程只能監視消息,不管是否調用了CallNextHookEx函數,系統都把消息傳遞到每一個Hook過程。全局
hook監視同一桌面的所有線程。而特定線程的Hook只能監視單獨的線程。全局Hook過程可以被同一桌面的任
何應用程序調用,就象調用線程一樣,所以這個過程必須和DLL模塊分開。特定線程Hook過程只可以被相關
線程調用。只有在有調試目的的時候才使用全局Hook,應該避免使用,全局Hook損害了系統性能。

    本文使用全局的WH_GETMESSAGE Hook,它也是經常用到的Hook,應用程序使用WH_GETMESSAGE Hook來監
視從GetMessage or PeekMessage函數返回的消息。你可以使用WH_GETMESSAGE Hook去監視鼠標和鍵盤輸入,
以及其他發送到消息隊列中的消息。關於Hook的詳細信息請參考MSDN。

    使用SetWindowsHookEx設置全局的WH_GETMESSAGE Hook,傳入DLL的映射到內存時的模塊句柄(HANDLE)
和Hook過程,這樣系統不但會將此DLL映射到當前所有進程的地址空間,並調用DllMain函數,而且也會將
此DLL映射到新創建的進程的地址空間了。也就是自動完成了代碼的注入工作,省了很多力氣,調用
UnhookWindowsHookEx卸載鉤子。


四、具體實現

    兩種實現模式:一是由一個第三方進程負責鉤子的設置和卸載,DLL導出設置和卸載函數;二是由一個
第三方進程向某一個進程插入遠程線程、注入DLL,然後由DLL負責鉤子的設置和卸載,第三方進程退出。

    兩種模型的DLL實現差別不大,封裝了鉤子設置和卸載函數,自己的API的函數等。

    先說改寫IAT方法:
定義一個保存攔截信息的結構APIHOOK32_ENTRY:
typedef struct _APIHOOK32_ENTRY
{
LPCTSTR     pszAPIName; //欲攔截API的函數名
LPCTSTR     pszCalleeModuleName;//API所在模塊的模塊名
PROC        pfnOriginApiAddress;//欲攔截API的函數地址
PROC        pfnDummyFuncAddress;//我們自己的API的函數地址
HMODULE     hModCallerModule; //調用此API的模塊名
}APIHOOK32_ENTRY, *PAPIHOOK32_ENTRY;

/////////////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "apihook32.h"

HMODULE hModDLL;
HHOOK hHook;
APIHOOK32_ENTRY hkA;
//鉤子過程,直接調用CallNextHookEx,而不做任何處理
//因爲我們只是利用設置鉤子來映射DLL
LRESULT CALLBACK GetMsgProc(int code,WPARAM wParam,LPARAM lParam)
{
return CallNextHookEx(hHook,code,wParam,lParam);
}
//我們自己的API函數
int WINAPI MyMessageBoxA(HWND hwnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType)
{
return MessageBoxA(hwnd,"It's coming from MyMessageBoxA",lpCaption,uType);
}
//設置全局鉤子,自動映射DLL到當前所有進程和新創建的進程
HHOOK InsertDll ()
{
hHook = SetWindowsHookEx(WH_GETMESSAGE,&GetMsgProc,hModDLL,0);
return hHook;
}

BOOL APIENTRY DllMain(HANDLE hModule,
  DWORD  ul_reason_for_call,
  LPVOID lpReserved
 
{
hModDLL = (HMODULE)hModule;//在32位windows系統中,DLL的hModule和hHandle是一回事

hkA.hModCallerModule = NULL;
hkA.pszAPIName = "MessageBoxA"; //攔截user32.dll中的MessageBoxA函數
hkA.pszCalleeModuleName = "user32.dll";
hkA.pfnDummyFuncAddress = (PROC) & MyMessageBoxA;
hkA.pfnOriginApiAddress = GetProcAddress(GetModuleHandle("user32.dll","MessageBoxA";

switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
// InsertDll();
SetWindowsAPIHook(&hkW);
SetWindowsAPIHook(&hkA);
break;
case DLL_THREAD_ATTACH:
break;
case DLL_PROCESS_DETACH:
UnhookWindowsAPIHooks(hkW);
UnhookWindowsAPIHooks(hkA);
// UnhookWindowsHookEx(hHook);
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;

}

/////////////////////////////////////////////////////////////////////////////////////////
//有了一上對PE文件輸入表的分析,我們將可以很好的理解下面的代碼
void _SetApiHookUp(PAPIHOOK32_ENTRY phk)
{
ULONG size;

//獲取指向PE文件中的Import表中IMAGE_DIRECTORY_DESCRIPTOR數組的指針

PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)
ImageDirectoryEntryToData(phk->hModCallerModule,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,&size);

if (pImportDesc == NULL)
return;

//查找記錄,看看有沒有我們想要的DLL
//pImportDesc->Name爲空說明IID數組結束
for (;pImportDesc->Name;pImportDesc++)
{
//pImportDesc->Name是DLL名字字符串的RVA,加上Module的基址獲得有效指針
LPSTR pszDllName = (LPSTR)((PBYTE)phk->hModCallerModule+pImportDesc->Name);
if (lstrcmpiA(pszDllName,phk->pszCalleeModuleName) == 0)
break;
}

if (pImportDesc->Name == NULL)
{
return;
}

//尋找我們想要的函數
//首先獲得IID的FirstThunk指向的IAT
PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA) ((PBYTE)phk->hModCallerModule+pImportDesc->FirstThunk);
for (;pThunk->u1.Function;pThunk++)
{
//ppfn記錄了與IAT表項相應的函數的地址

PROC * ppfn= (PROC *)&pThunk->u1.Function;
if (*ppfn == phk->pfnOriginApiAddress)
{
//如果地址相同,也就是找到了我們想要的函數,進行改寫,將其指向我們所定義的函數

WriteProcessMemory(GetCurrentProcess(),ppfn,&(phk->pfnDummyFuncAddress),sizeof(phk->pfnDummyFuncAddress),NULL);
return;
}
}
}

//***************************************************************************************//
//        SetWindowsAPIHook    掛接WindowsAPI函數  當phk->hModCallerModule == NULL       //
//                                                 會在整個系統內掛接函數                //
//                             仿照SetWindowsHookEx 建立                                 //
//***************************************************************************************//

BOOL SetWindowsAPIHook(PAPIHOOK32_ENTRY phk)
{
if (phk->pszAPIName == NULL)
{
return FALSE;
}
if (phk->pszCalleeModuleName == NULL)
{
return FALSE;
}
if (phk->pfnOriginApiAddress == NULL)
{
return FALSE;
}
if (phk->hModCallerModule == NULL)
{
MEMORY_BASIC_INFORMATION mInfo;
HMODULE hModHookDLL;
HANDLE hSnapshot;
MODULEENTRY32 me = {sizeof(MODULEENTRY32)};
//根據_SetApiHookUp函數在內存中的位置,確定DLL的映射基址,即hModule
VirtualQuery(_SetApiHookUp,&mInfo,sizeof(mInfo));
hModHookDLL=(HMODULE)mInfo.AllocationBase;
//遍歷本進程中的所有Module,除了本DLL模塊
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,0);
BOOL bOk = Module32First(hSnapshot,&me);
while (bOk)
{
if (me.hModule!=hModHookDLL)
{
phk->hModCallerModule = me.hModule;
_SetApiHookUp(phk);
}
bOk = Module32Next(hSnapshot,&me);
}
return TRUE;
}
else
{
_SetApiHookUp(phk);
return TRUE;
}
return FALSE;
}
//攔截某個某塊的API調用
void SetMyHooksHere(APIHOOK32_ENTRY hk,HMODULE hMod)
{
hk.hModCallerModule = hMod;
_SetApiHookUp(&hk);
}
//卸載API Hook,就是往IAT中寫入原地址
BOOL UnhookWindowsAPIHooks(APIHOOK32_ENTRY & hk)
{
PROC temp;
temp = hk.pfnOriginApiAddress;
hk.pfnOriginApiAddress = hk.pfnDummyFuncAddress;
hk.pfnDummyFuncAddress = temp;
return SetWindowsAPIHook(&hk);
}
///////////////////////////////////////////////////////////////////////////////////////
第三方進程調用InsertDll注入DLL(設置鉤子),調用UnhookWindowsHookEx取消攔截。


下面簡單介紹jmp xxxxxxxx方法攔截API:
攔截user32.dll中的MessageBoxA函數
FARPROC g_pfMessageBoxA = NULL;
BYTE g_OldMessageBoxACode[5] = {0}, g_NewMessageBoxACode[5] = {0};
DWORD g_dwNewProcessId = 0, g_dwOldProcessId = 0;
BOOL g_bHook = FALSE;
HMODULE g_hDll = FALSE;
HHOOK g_hHook = NULL;

BOOL WINAPI Initialize();
BOOL WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);
void WINAPI HookOn();
void WINAPI HookOff();

LRESULT WINAPI Hook(int nCode, WPARAM wParam, LPARAM lParam);
BOOL WINAPI InstallHook();
BOOL WINAPI UnInstallHook();

BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
 
{
//char szProcessID[64];
    switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
// _itoa(GetCurrentProcessId(), szProcessID, 10);
// MessageBox(NULL, szProcessID, "Remote Dll", MB_OK);
if(!g_bHook)
{
g_hDll = (HMODULE)hModule;
InstallHook();
Initialize();
// MessageBox(NULL, "Succeeded!", "Hook On", MB_OK);
}
//
MessageBox(NULL, "Process Attach", "Remote Dll", MB_OK);
break;
case DLL_THREAD_ATTACH:
// _itoa(GetCurrentProcessId(), szProcessID, 10);
// MessageBox(NULL, szProcessID, "Remote Dll", MB_OK);
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
// if(g_bHook)
// {
// HookOff();
// MessageBox(NULL, "Off!", "Hook Off", MB_OK);
// UnInstallHook();
// }
// break;
MessageBox(NULL, "Process Detach", "Remote Dll", MB_OK);
break;
    }
    return TRUE;
}

//獲得MessageBoxA的地址,然後保存代碼起始處的5個字節,並生成跳轉代碼jmp xxxxxxxx
BOOL WINAPI Initialize()
{
HMODULE hDll = LoadLibrary("user32.dll";
g_pfMessageBoxA = GetProcAddress(hDll, "MessageBoxA";//獲得MessageBoxA地址
if(g_pfMessageBoxA == NULL)
return FALSE;
_asm
{
lea edi, g_OldMessageBoxACode
mov esi, g_pfMessageBoxA
cld
movsd //將MessageBoxA地址起始的4個字節(dword)寫入g_OldMessageBoxACode
movsb //將MessageBoxA+4地址起始處的1個字節(byte)寫入g_OldMessageBoxACode+4
}
//jmp xxxxxxxx的機器碼爲e9xxxxxxxx,其中e9後的xxxxxxxx爲相對跳轉偏移,共5個字節
g_NewMessageBoxACode[0] = 0xe9;
_asm
{
lea eax, MyMessageBoxA
mov ebx, g_pfMessageBoxA
sub eax, ebx
sub eax, 5 //獲得相對跳轉偏移
mov dword ptr [g_NewMessageBoxACode + 1], eax
}

g_dwNewProcessId = GetCurrentProcessId();
g_dwOldProcessId = g_dwNewProcessId;

HookOn();

return TRUE;
}

int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
{
int nRet = 0;
char szText[128];
strcpy(szText, lpText);
strcat(szText, "/nYou have been Hooked!";
HookOff();
nRet = MessageBoxA(hWnd, szText, lpCaption, uType);
HookOn();

return nRet;
}

void WINAPI HookOn()
{
g_dwOldProcessId = g_dwNewProcessId;
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, g_dwOldProcessId);
if(hProcess == NULL)
return ;
//申請MessageBoxA地址處的寫權限,然後寫入跳轉代碼,然後恢復權限
VirtualProtectEx(hProcess, g_pfMessageBoxA, 5, PAGE_READWRITE, &g_dwOldProcessId);
WriteProcessMemory(hProcess, g_pfMessageBoxA, g_NewMessageBoxACode, 5, NULL);
VirtualProtectEx(hProcess, g_pfMessageBoxA, 5, g_dwOldProcessId, &g_dwOldProcessId);

g_bHook = TRUE;
}

void WINAPI HookOff()
{
g_dwOldProcessId = g_dwNewProcessId;
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, g_dwOldProcessId);
if(hProcess == NULL)
return ;
//寫入原MessageBoxA的5個字節代碼
VirtualProtectEx(hProcess, g_pfMessageBoxA, 5, PAGE_READWRITE, &g_dwOldProcessId);
WriteProcessMemory(hProcess, g_pfMessageBoxA, g_OldMessageBoxACode, 5, NULL);
VirtualProtectEx(hProcess, g_pfMessageBoxA, 5, g_dwOldProcessId, &g_dwOldProcessId);

g_bHook = FALSE;
}

LRESULT WINAPI Hook(int nCode, WPARAM wParam, LPARAM lParam)
{
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}

BOOL WINAPI InstallHook()
{
g_hHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)Hook, g_hDll, 0);
if(!g_hHook)
{
MessageBoxA(NULL, "Set Error!", "ERROR", MB_OK);
return FALSE;
}
return TRUE;
}

BOOL WINAPI UnInstallHook()
{
return UnhookWindowsHookEx(g_hHook);
}

如果讓DLL來負責鉤子的設置和卸載,就必須設置映射到所有進程的DLL共享的數據段,因爲DLL中的
全局數據,每個映射的DLL副本都有自己的副本,互不干擾。爲了同步鉤子的設置和卸載工作,我們
可以在DLL中設置一個共享段,如下:

#pragma data_seg("shared" //定義段名爲shared
BOOL g_bHooked = FALSE;
DWORD g_dwParentProcessID = 0;
//……
#pragma data_seg()
#pragma commnet(lib, "/Section:shared, rws";//設置段屬性爲read,write and shared

這個共享段在所有的DLL映射副本中共享,完成同步工作。
第三方進程向某個進程中注入遠程線程,遠程線程注入DLL,然後第三方進程退出。同步代碼如下:
BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
 
{
DWORD dwProcessId = GetCurrentProcessId();
    switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
if(!g_bHooked)
{
g_bHooked = TRUE;
g_dw_ParentProcessID = dwProcessId;
...//在這裏設置鉤子,hMoudle即爲DLL的Handle
}
...//在這裏完成API攔截工作
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
...//在這裏完成API的恢復工作
if(g_bHooked && (g_dwParentProcessID == dwProcessId))
{
g_bHooked = FALSE;
g_dwParentProcessID = 0;
...//在這裏卸載鉤子
}
break;
    }
    return TRUE;
}

以上關於遠程線程注入技術請參考我的另一篇《隱藏進程》的文章,以上代碼在Win2k Professional+SP2
+Visual C++6.0上測試通過,API的具體參數請參考MSDN。

    上面的代碼大多是自己機子上的一些零碎代碼,加上自己的分析和實際的應用調試,一直找不到方法
卸載DLL,無論是用設置鉤子注入DLL,還是用注入遠程線程的方法注入DLL。

 

原帖:http://blog.csdn.net/collin1211/archive/2008/07/31/2747382.aspx

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章