Dll Injection 簡介

公司最近因為加上了網路控管,之前使用VPN的方式躲過,但實在是太慢了,所以又另找解法,經由強者者同事告知,原來只要製造出假Process就可以順利上網,但要創造出假的Process,我只有想到兩種方法,一種很簡單,一種很複雜,第一種就是你把隨便一隻程式改名,例如把notepad.exe,改為Orz.exe,這樣檢查程式就會以為Orz.exe已經再執行了,缺點是可能會耗一點GDI的資源,雖然執行起來之後就隱藏了,但完美主義的我總是覺得不夠漂亮。

第二種則是現在要講的稱為Dll Injection技術,先講一下用途為何,某支沒有Source的程式呼叫WindowsAPI的時候,你希望可以改寫WindowsAPI的行為,這就需要用到Dll Injection,技術上來說就是對方的程式會改為呼叫你寫的Code,至於要不要繼續呼叫WindowsAPI,就看你的Code怎麼寫。

像上面的需求,一般列出Windows,應該是用EnumWindow,所以我就需要寫一個EnumWindow的取代函式,讓其使用。但要修改這部分則沒有那麼簡單,因為OS有實做Virtual Memory的關係,每個Process都是各自的記憶體空間,所以對方的Process是無法呼叫到你的Process裡面的函式的。DLL在Windows是一個特例,因為DLL Code在記憶中是共用的,所以可以被其他Process映射過去執行。至於要怎麼映射,這裡則是我覺得學Windows API滿精彩的一部分~

當年接了一個CASE,需求是當USB裝置插入的時候,程式可以得知,一直寫不出來,但手中有一個小程式可以做到這個功能,只是他會跳出MessengeBox來,所以我把小程式隱藏,然後攔截他呼叫的MessageBox函式,再通知我的程式,這樣就OK了~

下面是我當年的筆記,其實重點就是要知道現在正在執行的Code是在哪一個空間執行,DLL裡面會實做下面幾個函式
int __stdcall HOOK_MessageBox( HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption,UINT uType)
這個是取代MessageBox的函式,也就是小程式會呼叫到這裡

int replace_IAT(const char *pDllName,const char *pApiName,bool bReplace)
此函式執行的時候已經是在小程式空間裡了,用途是把原本WindowsAPI MessageBox的指標換為上面那個函式

LRESULT CALLBACK GetMsgProc(int,WPARAM, LPARAM);
所有Window Message的Callback,給小程式使用。

extern "C" __declspec(dllexport) BOOL SetAPIHook(HWND hWndRetA,DWORD dThreadIdA )
此函式是給我的程式呼叫的,呼叫之後就會想辦法讓上面那個函式在小程式的空間執行,至於怎麼辦到的,則是使用SetWindowHookEx,這個API就看下面的註解吧,反正他會把某視窗 or 整個系統的 Window Message都丟到上面那個函式去,小程式的也不例外,所以當小程式的Window Message丟進來的時候,我們就要呼叫replace_IAT了。

但當我們SetWindowHookEx之後,如果小程式剛好都沒有Window Message進來怎麼辦,所以我們會自己使用PostMessage給小程式強迫他執行到GetMsgProc去。

// 2006/07/31 加上註解~
// 此dll的運作原理為 inject dll 至某Process內,然後再在其Process 內修改對系統Dll呼叫的函式對應表
// AP先呼叫 SetAPIHook ,接著此Dll會呼叫
// hHook = SetWindowsHookEx( WH_GETMESSAGE, GetMsgProc , hMod ,  dThreadId );
// 最後一個參數就是 要Hook的Process的 ThreadId,若是 0 的話,就是全系統
// 接著在 GetMsgProc 就會收到該Process 的所有 Message
// 但要修改該 Process 所呼叫的系統參數,還必須修改IAT表
// 所以我們必須讓 dll 在Process的空間中執行,於是PostMessage 至 該Process
// 在 GetMsgProc 中可以抓到剛剛Post 的 Message ,這時候就要替換 系統函式表了

最後,整個DLL一定會記錄一些變數,跟我們OS學的一樣,程式共用,資料各自一份,這裡是一個大大重點,如果你沒有加上這個宣告的話,那還是沒辦法跑,就是必須在Source裡面加上#pragma指名說哪些資料是共用的。我之前的Code是這樣寫的,相關語法就再查囉~

#pragma data_seg("SHARDATA")
#pragma data_seg()

//下面這個一定要  共享變數用,不然 最下面也有寫在 def的範例
#pragma data_seg(".drectve")
static char szLinkDirectiveShared[] = "-section:Shared,rws";
#pragma data_seg()
#pragma data_seg("Shared")
HWND hWndRet=NULL;
DWORD dThreadId;
HHOOK hHook;
HINSTANCE hMod;

#pragma data_seg()

This entry was posted in 工作. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s