You are on page 1of 28

DLL Injection

使用 SetWindowsHookEx
來設定 Hook function
包含攔截 function 的
DLL

HHOOK hHook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, hinstDll, 0);

當有任何 message
指定 hook 的形式 被 post 過來 , 就會呼叫 我們指定的
我們的攔截程式 攔截程式碼
(Hook procedure)

指定要 Monitor
可以設定的值 ( 部分 )  參考 MSDN 所有的 thread
WH_CALLWNDPROC:
設定當目標收到 Message 之前 , 呼叫你的 function
WH_CALLWNDPROCRET:
當目標已經把 Message 處理完 , 呼叫你的 function
系統如何應對
SetWindowsHookEx?
把 GetMsgProc 安裝到
BOOL WINAPI SetDIPSHook(DWORD dwThreadId){
目標 process 中
// 安裝 hook function GetMsgProc 到指 定的 thread
HHOOK hHook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, hinstDll,\
dwThreadId);
} 0
Step 1:
Process B Send 一個 message
給一個視窗處理 Step 2:
系統檢查是否有
WH_GETMESSAGE 攔截被安裝

返回時 , 遞減 DLL Step 3:


counter 系統檢查 GetMsgProc
z 是否被
映射到 Process B 的位址空間中

Step 5: Step 4:
1. 呼叫 GetMsgProc () 載入 包含 GetMsgProc 的 DLL
2. 再度遞 增 DLL counter1 2 並 遞增 DLL counter 0 1
Why? 防止 Process B 在執行 GetMsgProc 時 , 有其他 thread 呼叫 UnhookWindowsHookEx, 導致 DLL UnMap
解除 Hook
• BOOL UnhookWindowsHookEx(HHOOK hhook);

Step 1:
找出系統中 , 所有 被注 入 該 DLL 的 process

Step 2:
遞減那些 process 對 DLL 的
reference counter
範例程式 : 新版本
操控程式 : SetMouseMessageHook 目標視窗 : TargetWindow

呼叫 SetHook(dwThreadID); while(GetMessage(…)){

}
Message-loop

安裝掛鉤到指定的 thread

安裝掛鉤
SetHook(dwThreadID) 實作
只要滑鼠有動作 ,
就會先呼叫 掛鉤
滑鼠訊息掛鉤程式
MyHook_MouseProc( );

DLL 掛鉤程式 : MouseProcLibrary.dll


範例程式

• 將桌面的 icon 位置存起


SimpleDIP.cpp

• 將桌面的 icon 位置讀回



修正

到底是誰在管理桌面 ?

Program Manager Progman

spy 拉到最後一項
先看看架構 : 總共有三個檔案互動 隱藏的 dialog 建立隱藏的 dialog
3
4
通知注射完成 目標 process
(Message) 6
存取資料

WinAPI WINMAIN(…){ Explorer 相關的程式碼


… (SysListView32)
SetDIPSHook
1 …
5
}
要求處理事情

SimpleDIP.exe

SetDIPSHook{ SetDIPSHook{
SetWindowsHookEx(…) SetWindowsHookEx(…)
載入 DLPSLIB.dll }
}
設定要 將 GetMsgProc()
2 ( 寄生程式 )
注射進 目標 Process
GetMsgProc(){ GetMsgProc(){
Post Message 給 process
以啟動目標 Process 呼叫 }
} GetMsgProc();
DLPSLIB.dll DLPSLIB.dll
開始寫程式嘍 !!

3
2
加入 resource
修改 ID = IDD_DIALOG1

修改 ID = IDC_RESTORE

修改 ID = IDC_SAVE
加入 Message Handle
#include <Windows.h> // Windows 程式必要的標頭檔
#include <WindowsX.h>
#include "resource.h" // 對應到你剛剛建立的 Dialog template
#include <tchar.h> // for TCHAR 字元

{ Message Handle function 的 prototype 片段


方便巨集定義的片段 …
} 自訂的
Dialog 訊息處理函式
( 見下頁 )
int WINAPI _tWinMain( ..) { 視窗主程式
TCHAR cWhatToDo;
switch (DialogBox(hinstExe, MAKEINTRESOURCE(IDD_DIALOG1),
NULL,Dlg_Proc))
{ case IDC_SAVE:
cWhatToDo = TEXT('S');
Step 1: 建立一個 Dialog 讓使用者選擇
break;
case IDC_RESTORE: 是否要將 [ 桌面的 icon] 位置存起來
cWhatToDo = TEXT('R'); 將傳回 使用者按鍵 的選項
break;
}
}
當使用者按下按鈕時
// Dialog 的訊息處理主要函式
BOOL WINAPI Dlg_Proc( HWND hwnd, UINT uMsg, …) {
switch (uMsg) {
chHANDLE_DLGMSG(hwnd, WM_COMMAND, Dlg_OnCommand);
}
return(FALSE);
}

void Dlg_OnCommand(HWND hwnd, int id, HWND hwndCtl, …) {


switch (id) {
case IDC_SAVE: 當使用者按下按鈕後 , destroys the modal
case IDC_RESTORE: Dialog box
EndDialog(hwnd, id);
break;
程式藉由 id
} 判斷到底是哪一個
} 按鈕被按下

// 方便巨集 chHANDLE_DLGMSG 定義
// 利用 SetDlgMsgResult 將 Dialog 的 message 導向指 定的
// function
#define chHANDLE_DLGMSG(hwnd, message, fn)
case (message): return (SetDlgMsgResult(hwnd, uMsg, \
HANDLE_##message((hwnd), (wParam), (lParam), (fn))))
休息一下

• 你可以把 Dialog 架框建好


將寄生的 DLL 程式注入指
定的 process
int WINAPI _tWinMain( ..) {

// Step 1: 建立視窗 , 讀取 使用者的需 求

TCHAR cWhatToDo;
switch (DialogBox(hinstExe, MAKEINTRESOURCE(IDD_DIALOG1),
NULL,Dlg_Proc))
{ case IDC_SAVE:
cWhatToDo = TEXT('S');
break;
case IDC_RESTORE:
cWhatToDo = TEXT('R');
break;
}
// Step 2 ~ 6 : 處理與 操縱 寄生的 DLL function

注入的寄生程式寫在下面
// Step 2: 取得桌 面管 理程式 (ProgMan)
HWND hwndLV = GetFirstChild(GetFirstChild(FindWindow(TEXT("Progman"),
NULL)));
// Step 3: 將 DIPLib.dll 注射到 Explorer's 位址空 間
SetDIPSHook(GetWindowThreadProcessId(hwndLV, NULL)); SysListView32

這是 DIPLib.dll 中
的一個 function

// Step 4: 等待寄生程 式的回 應


MSG msg; 也可以用 Kernel Object 做同
GetMessage(&msg, NULL, 0, 0); 步,
這裡使用 Message
// Step 5: 因為寄 生程 式會建 立一 個隱 藏的視 窗 Richter DIPS123
// 我們 將利 用這個 視窗 , 操控寄 生程式
HWND hwndDIPS = FindWindow(NULL, TEXT("Richter DIPS123"));
SendMessage(hwndDIPS, WM_APP, (WPARAM) hwndLV, (cWhatToDo ==

TEXT('S')));
// Step 6: 操作完 成 , 移除寄生 程式
SendMessage(hwndDIPS, WM_CLOSE, 0, 0);
SetDIPSHook(0);
Link DLL
互動流程 建立隱藏的 dialog
3
4
通知注射完成
(Message) 6
存取資料

WinAPI WINMAIN(…){ Explorer 相關的程式碼


… (SysListView32)
SetDIPSHook
1 …
5
}
要求處理事情

SimpleDIP.exe

SetDIPSHook{ SetDIPSHook{
SetWindowsHookEx(…) SetWindowsHookEx(…)
載入 DLPSLIB.dll }
} 2 ( 寄生程式 )
設定要 將 GetMsgProc()
注射進 目標 Process
GetMsgProc(){ GetMsgProc(){
Post Message 給 process
} 以啟動目標 Process 呼叫 }
GetMsgProc();
DLPSLIB.dll DLPSLIB.dll
互動流程

BOOL WINAPI SetDIPSHook( DWORD dwThreadId) {


// 安裝 hook function GetMsgProc 到指 定的
thread
SetWindowsHookEx(…, GetMsgProc,…,dwThreadId);
Expoler.exe
} thread id

Expoler 的視窗處理 thread 會載入


引發的一連串動作
DIPSLib.dll

Hook function 已經存在於 Expoler


的 address space
寄生在 Expoler 的
Function

呼叫 Hook function, GetMsgProc

Exploer process
也就是要被注射的

SetDIPSHook 的部分
DLL

// [ 設定 / 解除 ] 寄生 DLL
// dwThreadId == 0 則解 除
BOOL WINAPI SetDIPSHook(DWORD dwThreadId) {
BOOL fOk = FALSE;
if (dwThreadId != 0) {
// Step 1:
// 將我們的 thread ID 存起來 , 以便 當 server window 被建 立起 來時 ,
監控端的 thread // GetMsgProc 可以 post a message 回來
g_dwThreadIdDIPS = GetCurrentThreadId(); 將 hook function GetMsgProc
安裝 到指定的 thread 中
// Step 2:
g_hhook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, g_hinstDll, dwThreadId);
fOk = (g_hhook != NULL);
要注入的 function
( 見下頁 ) 目標 thread
if (fOk) {
// Step 3:
fOk = PostThreadMessage(dwThreadId, WM_NULL, 0, 0);
}
} else {
// 當 dwThreadId ==0 時 , 表示 我們 要移除 hook 了
fOk = UnhookWindowsHookEx(g_hhook);
g_hhook = NULL;
隨便送一個 no operation message, WM_NULL
} 給指定的 thread, 以便啟動 我們的 hook
return(fOk); function , GetMsgProc
}
GetMsgProc 的部分
LRESULT WINAPI GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{

static BOOL fFirstTime = TRUE;

if (fFirstTime) {
// The DLL just got injected.
fFirstTime = FALSE;

// Step 1: 建立 一個 Dialog 用來處理 client 的 request


// 所有送到這個 dialog message 都會交給 Dlg_Proc 管理
// 目前這個 Dialog 的 title = "Richter DIPS123"
CreateDialog(g_hinstDll, MAKEINTRESOURCE(IDD_DIPS), NULL,

Dlg_Proc);
監控端的// Step
thread2: 告訴 DIPS application 目前 server 已經啟動
// 並且等待接受 requests
PostThreadMessage(g_dwThreadIdDIPS, WM_NULL, 0, 0);
}

// 將 hook 資訊傳給下一個可能的 hook


return(CallNextHookEx(g_hhook, nCode, wParam, lParam));
DLPSLIB 設定為 DLL
Project

設定 dll 檔輸出位置

設定 lib 檔輸出位置
• End
延伸閱讀 :
1. Monitor system events
ms-help://MS.MSDNQTR.2004JAN.1033/winui/winui/windowsuserinterface
/windowing/hooks/usinghooks.htm#system_events
2. . TaskSwitcher application
ms-help://MS.MSDNQTR.2004JAN.1033/dnwxp/html/xpvisualstyles.htm
進一步的解析 Message 巨集

我們已經知道利用
chHANDLE_DLGMSG(hwnd, WM_COMMAND, Dlg_OnCommand);

可以將 WM_COMMAND message 轉向 呼叫我們自己


寫的 Dlg_OnCommand function 處理

現在來看看
詳細呼叫的情況
解析 chHANDLE_DLGMSG
Dialog 訊息處理函式
BOOL WINAPI Dlg_Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {

switch (uMsg) {
chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Dlg_OnInitDialog);
chHANDLE_DLGMSG(hwnd, WM_COMMAND, Dlg_OnCommand);
}
你的 function 位址
return(FALSE);
}

case (WM_COMMAND): 你的 function 位址


return(SetDlgMsgResult( hwnd, uMsg,\
HANDLE_WM_COMMAND(hwnd,wParam,lParam,Dlg_OnCommand))

#define chHANDLE_DLGMSG(hwnd, message, fn) 原型定義在 cmnhdr.h


case (message): return (SetDlgMsgResult(hwnd, uMsg,\
HANDLE_##message((hwnd), (wParam), (lParam), (fn))))

接下一頁
解析 chHANDLE_DLGMSG
case (WM_COMMAND): 你的 function 位址
return(SetDlgMsgResult( hwnd, uMsg,\
HANDLE_WM_COMMAND(hwnd,wParam,lParam,Dlg_OnCommand))

1
2

Dlg_OnCommand(hwnd, \

(int)(LOWORD(wParam,(HWND)(lParam),(UINT)HIWORD(wParam)),0L)
你的 function 位址

原型定義在 windowx.h for message crackers


#define HANDLE_WM_COMMAND(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(LOWORD(wParam)), (HWND)(lParam), (UINT)HIWORD(wParam)), 0L)

接下一頁
2 windowx.h for USER Macro APIs
#define SetDlgMsgResult(hwnd, msg, result) (( \
(msg) == WM_CTLCOLORMSGBOX || \
(msg) == WM_CTLCOLOREDIT || \
(msg) == WM_CTLCOLORLISTBOX || \
(msg) == WM_CTLCOLORBTN || \
(msg) == WM_CTLCOLORDLG || \
(msg) == WM_CTLCOLORSCROLLBAR || \
解析一下 :
(msg) == WM_CTLCOLORSTATIC || \ 若 msg 是左邊的那些 , 則直接呼叫你的 function
(msg) == WM_COMPAREITEM || \ 否則 , 利用 SetWindowLongPtr 修改 Dialog
(msg) == WM_VKEYTOITEM || \ MessageResult 屬性
(msg) == WM_CHARTOITEM || \
(msg) == WM_QUERYDRAGICON || \
(msg) == WM_INITDIALOG \
) ? (BOOL)(result) : (SetWindowLongPtr((hwnd), DWLP_MSGRESULT,
(LPARAM)(LRESULT)(result)), TRUE))

展開的結果

(SetWindowLongPtr(hwnd,DWLP_MSGRESULT,
(LPARAM)(LRESULT)(Dlg_OnCommand(hwnd, \

(int)(LOWORD(wParam,(HWND)(lParam),(UINT)HIWORD(wParam)),0L)),
指定 Dialog 的 Message 改由 Dlg_OnCommand 呼叫
TRUE))
全部合在一起
BOOL WINAPI Dlg_Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {

switch (uMsg) {
chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Dlg_OnInitDialog);
chHANDLE_DLGMSG(hwnd, WM_COMMAND, Dlg_OnCommand);
}

return(FALSE);
}

case (WM_COMMAND):
return
(SetWindowLongPtr(hwnd,DWLP_MSGRESULT,
(LPARAM)(LRESULT)(Dlg_OnCommand(hwnd, \

(int)(LOWORD(wParam,(HWND)(lParam),(UINT)HIWORD(wParam)),0L)),
TRUE)) 指定 Dialog 的 Message 改由 Dlg_OnCommand 呼叫
;

You might also like