Windows核心新手上路3——掛鉤KeUserModeCallBack
Windows核心新手上路3——掛鉤KeUserModeCallBack
1. 簡介
在Windows系統中,提供了幾種方式從R0呼叫位於R3的函式,其中一種方式是KeUserModeCallBack,此函式流程如下:
nt!KeUserModeCallback->nt!KiCallUserMode->nt!KiServiceExit->ntdll!KiUserCallbackDispatcher->回撥函式-> int2B->nt!KiCallbackReturn-> nt!KeUserModeCallback(呼叫後)這是一個 ring0->ring3->ring0的過程,在堆疊準備完畢後,借用KiServiceExit的力量回到了ring3,它的著陸點是 KiUserCallbackDispatcher,然後KiUserCallbackDispatcher從PEB中取出 KernelCallbackTable的基址,再以ApiIndex作為索引在這個表中查詢對應的回撥函式並呼叫,呼叫完之後再int2B觸發 nt!KiCallbackReturn再次進入核心,修正堆疊後跳回KeUserModeCallback,完成呼叫。
系統所有的訊息鉤子回撥都是利用KeUserModeCallBack完成的。所以可以通過掛鉤KeUserModeCallback用來過濾對鉤子的呼叫。
1.1 inline hook
KeUserModeCallback沒有對應的R3呼叫介面,所以沒有在SSDT SHADOW中出現,需要用另外的方式來HOOK,可以採用的Inline Hook,即在函式頭部加入一條JMP指令(機器碼E9)跳入代理函式,然後過濾之後決定是否呼叫真實的KeUserModeCallback函式。掛鉤過程如下:
ULONG StartHookKeyUserModeCallBack() { ULONG tmp; memset (Ori_Func, 0x90, 100); // nop Ori_Func[50] = 0xE9; tmp = (ULONG)ProxyFunc - (ULONG)KeUserModeCallback - 5; memcpy(jmp_bytes+1, &tmp, 4); HeadLen = GetPatchSize (KeUserModeCallback, 5); memcpy(Ori_Func, (PVOID)KeUserModeCallback, HeadLen); //原始位元組 //中間跳 tmp = (ULONG)KeUserModeCallback + HeadLen - (ULONG)(&Ori_Func[50]) - 5; memcpy(&Ori_Func[51], &tmp, 4); // 去掉記憶體保護 __asm { cli mov eax, cr0 and eax, not 10000h mov cr0, eax } memcpy(KeUserModeCallback, jmp_bytes, 5); // 恢復記憶體保護 __asm { mov eax, cr0 or eax, 10000h mov cr0, eax sti } return TRUE; } |
程式碼1 掛鉤KeUserModeCallback
代理函式ProxyFunc程式碼如程式碼2:
__declspec(naked) VOID ProxyFunc(VOID) { __asm { MOV EAX, ESP PUSHAD
PUSH [EAX+4*5] PUSH [EAX+4*4] PUSH [EAX+4*3] PUSH [EAX+4*2] PUSH [EAX+4] LEA EAX, MyKeUserModeCallback CALL EAX
TEST EAX, EAX JZ continue_exe //return STATUS_SUCCESS
POPAD RETN 0x14
continue_exe: POPAD LEA EAX, Ori_Func //跳回原始函式 JMP EAX } } |
程式碼2 代理函式ProxyFunc
首先呼叫自定義的過濾函式MyKeUserModeCallback,然後判斷返回值是否是STATUS_SUCCESS,如果是,則呼叫真實的KeUserModeCallback,否則直接返回,拒絕呼叫R3的回撥用函式。
1.2 MyKeUserModeCallback
下面分部分講解MyKeUserModeCallback對鉤子的過濾操作,其中涉及到很多未公開技術,其程式碼通過逆向工程技術得到。
1.2.1 過濾WH_KEYBOARD_LL型別鉤子
在Windows作業系統中,按鍵訊息到達具體的視窗訊息佇列之前會呼叫WH_KEYBOARD_LL鉤子函式,可以利用此類鉤子擷取鍵盤輸入。虛擬碼如程式碼3所示。
判斷ApiNumber是否是KBD_LL_HOOK_API_NUM 將InputBuffer轉換為PFNHKINLPKBDLLHOOKSTRUCTMSG 填充SYS_EVENT_STRUCT結構,通知R3控制程式作出判斷 如果使用者允許該呼叫則返回STATUS_SUCCESS 否則返回STATUS_UNSUCCESSFUL |
虛擬碼3 WH_KEYBOARD_LL過濾
在對WH_KEYBOARD_LL的過濾過程中,還有一點需要做特殊處理。現在有很多的軟體採用WH_KEYBOARD_LL鉤子來做安全輸入控制元件,而不是通過傳統的EDIT控制元件,所以在返回的時候需要將虛擬鍵盤產生的虛假的按鍵修正為真實的按鍵。
1.2.2 過濾WH_KEYBOARD鉤子
在Windows作業系統中,按鍵訊息到達具體的視窗訊息佇列之前會呼叫WH_KEYBOARD鉤子函式,可以利用此類鉤子擷取鍵盤輸入。過濾的虛擬碼如程式碼4所示。
判斷ApiNumber是否是KBD_HOOK_API_NUM 將InputBuffer轉為PFNHKINLPKBDLLHOOKSTRUCTMSG結構 判斷PFNHKINLPKBDLLHOOKSTRUCTMSG結構中GeneralHookHeader成員的nCode成員的值是否為0x20000 如果是則是WH_KEYBOARD鉤子 填充SYS_EVENT_STRUCT結構,通知R3控制程式作出判斷 如果使用者允許該呼叫則返回STATUS_SUCCESS 否則返回STATUS_UNSUCCESSFUL
|
虛擬碼4 WH_KEYBOARD鉤子過濾
WH_KEYBOARD鉤子會同其他一些回撥共用一個ApiNumber,這裡要做進一步的判斷,而且全域性的WH_KEYBOARD鉤子需要在其他程式中LoadLibrary。
同WH_KEYBOARD_LL鉤子,有的程式會利用WH_KEYBOARD鉤子做安全輸入控制元件,在返回時需要將虛擬鍵盤產生的虛假按鍵修正為真實的按鍵。
1.2.3 WH_DEBUG鉤子過濾
在Windows作業系統中,呼叫其他型別的鉤子函式之前,會首先呼叫WH_DEBUG鉤子函式,用於鉤子除錯。惡意程式利用WH_DEBUG型別鉤子可以獲取鍵盤輸入。過濾虛擬碼如程式碼5所示。
判斷ApiNumber是否是DEBUG_HOOK_API_NUM 判斷此DEBUG資訊中的鉤子型別是否包含鍵盤輸入資訊 如果包含,則填充SYS_EVENT_STRUCT結構,通知R3控制程式作出判斷 如果使用者允許該呼叫則返回STATUS_SUCCESS 否則返回STATUS_UNSUCCESSFUL
|
虛擬碼5 WH_DEBUG鉤子過濾
同WH_KEYBOARD_LL WH_KEYBOARD型別的鉤子,有些程式會使用WH_DEBUG鉤子實現安全輸入控制元件,在返回時,需要將虛擬鍵盤產生的虛假按鍵修正為真實的按鍵。
1.2.4 Ke_LoadLibrary過濾
在Windows作業系統中,除了WH_KEYBOARD_LL鉤子外,其他型別的全域性訊息鉤子都需要有DLL被載入進入目標程式(WH_KEYBOARD_LL鉤子只是一次執行緒切換,詳細資訊可以檢視MSDN)。所以過濾Ke_LoadLibrary可以阻止大部分的訊息鉤子(事實上,目前所有的密碼保護程式都通過此方法過濾訊息鉤子,用來保護密碼,但是此方法對WH_KEYBOARD_LL型別的鉤子無效)。過濾虛擬碼如程式碼6所示。
判斷ApiNumber是否LOAD_LIBRARY_API_NUM 如果是,獲取引數資訊(包括DLL路徑) 填充SYS_EVENT_STRUCT結構,通知R3控制程式作出判斷 如果使用者允許該呼叫則返回STATUS_SUCCESS 否則返回STATUS_UNSUCCESSFUL |
虛擬碼6 Ke_LoadLibrary過濾
1.2.5 WH_JOURNALRECORD過濾
在Windows作業系統中,WH_JOURNALRECORD設計的初衷是做訊息的記錄和回放,但是惡意程式利用此型別的鉤子可以獲取鍵盤輸入訊息,從而達到記錄密碼的目的。過濾虛擬碼如程式碼7所示。
判斷ApiNumber是否EVENT_MSG_HOOK_API_NUM 進一步判斷訊息型別是否是按鍵訊息 填充SYS_EVENT_STRUCT結構,通知R3控制程式作出判斷 如果使用者允許該呼叫則返回STATUS_SUCCESS 否則返回STATUS_UNSUCCESSFUL |
虛擬碼7 WH_JOURNALRECORD過濾
相關文章
- Windows核心新手上路1——掛鉤SSDTWindows
- Windows核心新手上路2——掛鉤shadow SSDTWindows
- ROS新手上路-3ROS
- Windows核心驅動學習(六)程式碼注入與核心掛鉤Windows
- Linux新手渣渣上路史Linux
- 專案管理新手上路(轉)專案管理
- 懵懂新手上路經驗總結
- 「新手上路」Go 微博授權登入Go
- 新手上路之如何選擇Java版本Java
- 新手上路:Oracle基礎工具簡介(轉)Oracle
- Sublime Text 3 新手上路:必要的安裝、設定與基本使用教學
- 阿里雲ECS雲伺服器新手上路阿里伺服器
- 往linux核心掛鉤子–什麼應該什麼不應該Linux
- Windows訊息鉤取Windows
- WINDOWS鍵盤事件的掛鉤監控原理及其應用技術Windows事件
- “龍井”開箱評測 |Alibaba Dragonwell 新手上路指南Go
- 簡易撲克牌遊戲JAVA原始碼_新手上路遊戲Java原始碼
- WINDOWS鉤子函式(轉)Windows函式
- 新手上路:三分鐘搭建 golang 開發環境Golang開發環境
- 用 Thunk 實現 COM 的掛鉤
- 7- Windows訊息鉤取Windows
- 外掛移植後,鉤子不起作用。
- 「Window平臺」異常掛鉤大法(1)
- 新手安裝控制皮膚+掛載硬碟3條命令直接搞定硬碟
- Pycharm常用的小技巧彙總,Python新手上路必備,快上車!PyCharmPython
- 軟體專案經理新手上路2 – 力量從哪裡來?薦
- Windows核心Windows
- Windows訊息鉤取(簡單DLL注入)Windows
- 與遊戲頻繁掛鉤的SCP是什麼?遊戲
- Windows NT 核心Windows
- Windows Terminal 新手入門Windows
- 有關windows鉤子使用的兩篇文章Windows
- Node.js新手上路——動手擼一個靜態資源伺服器Node.js伺服器
- 軟體專案經理新手上路7 – 再序 – 多點兒人味兒薦
- 軟體專案經理新手上路11 – 找不到自己,看不見別人薦
- 鉤子裡找不到新增外掛名稱的位置
- Windows 核心攻擊Windows
- windows核心程式設計--核心物件Windows程式設計物件