譯者:myswsun
預估稿費:100RMB
投稿方式:發送郵件至linwei#360.cn,或登陸網頁版在線投稿
0x00 前言
回顧第一部分,我們總結了4種Windows用戶模式的鍵盤記錄的方法,今天我們將分析每種技術的檢測方式。
測試機器:

0x01 SetWindowsHookEx
當我們使用SetWindowsHookEx註冊消息鉤子時,系統將我們的鉤子處理函數保存在鉤子鏈(是一個指針列表)中。因為我們能註冊任何消息類型的鉤子,因此,每種消息類型都有一個鉤子鏈。因此我們的目標是:
系統內存中鉤子鏈的位置(WH_KEYBOARD和WH_KEYBOARD_LL)
如何找到鉤子的進程名
對於鉤子鏈的位置,可以參考如下:
1 | nt!_ETHREAD |
每個結構都很清楚(感謝Windows符號)。Offset值是我的測試機器的,不同的Windows版本和構建版本會不同(ntoskrnl和win32k.sys)。
從nt!_ETHREAD看,它一定是一個GUI線程。我們能從explorer.exe中得到GUI線程,或者自己創建。
在上面,我們能得到系統所有的全局鉤子鏈的位置。這個有16個tagHOOK的數組指針,數組索引是WH_*消息類型的值(實際上是index=WH_*+1)。如果條目是空,我們能找到一個全局鉤子鏈。

從tagHook中的_THRDESKHEAD看,我們能得到設置鉤子的進程的tagTHREADINFO。因此我們能得到進程ID和進程名:
1 | processIdOfHooker = PsGetProcessId(IoThreadToProcess((PETHREAD)(*pCurHook->head.pti))); |
掃描結果:

好了,查找Windows全局消息鉤子可以了。那麼本地鉤子怎麼辦?
下面是本地鉤子:
1 | nt!_ETHREAD + 0x0 => nt!_KTHREAD + 0x088 => nt!_TEB + 0x40 => win32k!tagTHREADINFO + 0x198 => win32k!tagHOOK |
和全局鉤子很相似,但是你能看見本地鉤子鏈的位置是在進程的tagTHREADINFO結構體中的,它是進程相關的。tagDESKTOPINFO中的鉤子鏈是相同桌面下所有進程的。
0x02 輪詢
我確實不知道怎麼掃描這種方式。為什麼?因為它直接從內部結構讀取鍵的狀態,似乎沒有方式來檢測。

針對GetAsyncKeyState(), GetKeyboardState() API hook?可以,我們可以通過API來檢測,但是我不想用它,因為針對系統所有進程全局APIhook不是個好方法。使用API HOOK,我們能檢查頻率和鍵盤記錄鍵的範圍。
0x03 Raw Input
我從分析user32.dll中的RegisterRawInputDevices函數開始。這個API將調用win32k.sys中的
NtUserRegisterRawInputDevices。

在一些檢查之後,進入_RegisterRawInputDevices


這裡非常清楚。
PsGetCurrentProcessWin32Process返回win32k!tagPROCESSINFO結構體。使用WinDbg查看偏移0x1A4:

有個指針指向win32k!tagPROCESS_HID_TABLE。
20-34行,驗證註冊的數據(HID請求)。
36-47行,如果不存在分配HID表。意味着,如果tagPROCESSINFO->pHidTable為空,進程中沒有註冊設備。
48-71行,設置HID請求到HID表中。
剩下的就是更新標誌和重啟HID設備。
讓我們看下SetProcDeviceRequest函數:

系統分配一個HID請求,將它插入到HID表中

這裡有2個HID請求的列表,分別是InclusionList, UsagePageList and ExclusionList。插入哪個列表取決於調用RegisterRawInputDevices的tagRAWINPUTDEVICE的dwFlags值。

對於鍵盤記錄,我使用RIDEV_NOLEGACY | RIDEV_INPUTSINK標誌,因此是InclusionList。最後一個結構體是win32k!tagPROCESS_HID_REQUEST

能看到usUsagePage, usUsage and spwndTarget是tagRAWINPUTDEVICE的參數。
對於原始輸入的檢測:
1. 枚舉系統所有的進程
2. 針對每個進程,遍歷pID -> PEPROCESS -> tagPROCESSINFO -> tagPROCESS_HID_TABLE -> tagPROCESS_HID_REQUEST
3. 如果我們找到usUsagePage = 1的條目(通常是桌面控制)和usUsage = 6(鍵盤),這個進程就是用來鍵盤記錄的。
掃描結果:

0x04 Direct Input
當檢測direct input時,我發現了註冊鉤子進程中的一些有趣的特徵。


針對MSIAfterburner.exe,我發現了一些與direct input(Mutant, Section, Key)相關的句柄。從運行的線程中,我們也能發現DINPUT8.dll(微軟DirectInput庫)。
對於direct input的檢測:
1. 枚舉系統所有進程
2. 對於每個進程,枚舉所有的mutant、section、key,以匹配句柄特徵
3. 如果所有的特徵都匹配了,我們得到進程的所有的線程的起始地址。如果起始地址在DINPUT8.DLL的地址空間中,則找到了鍵盤記錄。
掃描結果:

0x05 總結
總結掃描方式如下:

原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/278224.html