------- 軟件調試——還原 QQ 過濾驅動對關鍵內核設施所做的修改 -------


————————————————————————————————————————————————————————————————————————————————

在前一篇博文中,我們已經處理完最棘手的部分:殺掉 QQFrmMgr.sys 創建的系統線程。剩余的工作就輕松多了——移除 QQFrmMgr.sys 和 QQProtect.sys

安裝的 SSDT(系統服務調度表)鈎子與 SSDT Shadow 鈎子、銷毀它們注冊的事件通知 callback,從而將系統恢復至干凈狀態。

在此之前,按照慣例,還是先來檢查一下這兩個 QQ 驅動是否 attach 到了其它設備棧中的設備上,因為 rootkit 或惡意軟件通常會掛載到其它合法驅動創建的

設備上,以便攔截或修改途經的 IRP(I/O 請求包)中攜帶的敏感數據,比如用戶的擊鍵數據。

如果發現了任何掛載跡象,則可以通過前一篇介紹的 APC 機制結合 IoDetachDevice() 例程,把惡意設備從設備棧中清理掉。

由於這兩個 QQ 驅動會向 Windows 對象管理器維護的全局名稱空間中,注冊相應的設備對象名,如下圖所示:

 

 

————————————————————————————————————————————————————————————————

Windows I/O 管理器導出的兩個例程 IoCreateDevice()IoCreateSymbolicLink() 普遍被驅動程序用來向 NT 名稱空間中注冊設備對象名,以及相應的符

號鏈接。用戶態進程使用符號鏈接訪問該對象;而在內核空間中,可以直接通過對象名進行訪問,所以我們先用內核調試器的“!devstack”擴展命令,后接這

兩個 QQ 設備對象的名稱,查詢它們是否掛載到了任何系統現存的設備棧上:

 

如你所見,這兩個設備對象各自所在的設備棧中,都只有它們自身——如果它們掛載到了任何其它設備上,“!devstack”的輸出中就會含有那些“受害”的

設備。其中,“!DevObj”欄位下的 4 字節 16 進制數是該設備對象的“nt!_DEVICE_OBJECT”結構地址;“!DrvObj”欄位下的則是創建它們的驅動對象名

稱。其實這兩個 QQ 設備對象還算是“良性”的——某些 rootkit 創建設備對象時,根本不注冊名字到 NT 名稱空間(通過向 IoCreateDevice() 的第三個參

數傳入 NULL,就可以做到這一點),對於此類“惡性”的匿名設備,需要獲悉它的“nt!_DEVICE_OBJECT”結構地址,然后才能用“!devstack”遍歷設備

棧,這個難度就不小了。

 

言歸正傳,接下來先檢查系統的 SSDT,尋找有無被掛鈎的系統服務,如下圖,SSDT 的起始地址為 0x83c80f7c,一共有 0x191(401)個系統服務,其中一

部分已經被替換成 QQFrmMgr.sys 的鈎子函數:

 

 

 

 

本來可以利用“!chkimg”擴展命令執行自動化檢查,將 nt 模塊(ntoskrnl.exe)的內存映像與磁盤文件比較,從而找出那些被修改了的部分,但不知為何我

的宿主機上 WinDbg 無法對 nt 模塊實施檢查,總是提示 ntkrpamp.exe/ntoskrnl.exe 的版本不匹配。(——還請成功執行“!chkimg”命令檢查 nt 模塊的

各位提供經驗——)

一種最原始的方法就是先記錄下受感染機器上 QQFrmMgr.sys 的鈎子函數在 SSDT 中的位置,然后把它與另一個干凈系統上的 SSDT 對比,以得知被 hook

的是哪個系統服務——前面那張截圖就是用這種臟累的體力活實現的。

 

注意,系統每次初始化時,SSDT 的基地址,以及其中的系統服務入口點地址都是隨機變化的,因而我們不能記錄它們的內核地址,而是要記錄函數名,在復

原前用反匯編指令“u”,即可強制解析原始系統服務在本次啟動時分配到的內核地址,然后以“eb”指令編輯還原被 hook 的表項——言詞蒼白無力,還是

看圖有真相吧:

 

 

 

注意,Intel x86/x64 體系結構的微處理器采用“小端字節序”在內存中放置數據,換言之,一個“雙字”(DWORD)數據的最低有效字節位於連續的四字節

存儲空間中的最小地址處;最高有效位則存放在最大地址處。以上圖為例,系統服務“nt!NtCreateSection”的入口點地址——83e5583b,其中最低有效字

節是“3b”,所以我們在編輯時把它放在最前面(最小地址處)。

 

這個游戲規則是處理器硬件廠商規定的,如果不遵守它來辦事就無法正確地恢復被掛鈎的系統函數!

 

此外,通過分析我們還得知:QQFrmMgr.sys 利用“inline hook”技術硬掛鈎了 KeUserModeCallback() 內核例程中的正常函數調用

,由於我機器上的“!chkimg”不能工作,無法依賴它檢測處掛鈎前的原始函數調用,但是我們可以用 IDA PRO 逆向 ntkrpamp.exe/ntoskrnl.exe 的磁盤文

件,定位到 KeUserModeCallback() 中的原始函數調用——這種不修改函數指針數組(如 SSDT,一般位於 .data section),而是修改特定函數(一般位於

.text section)中的調用邏輯,就稱為“inline hook”。

 

如下兩張截圖,手工比較“ntkrnlpa.exe”的磁盤文件與內存映像,兩者的 KeUserModeCallback() 初始邏輯(機器指令序列)基本相同,

除了內存映像中的首條 call 指令目標被替換成了“QQFrmMgr+0x503e”之外。。。。。

 

 

 

 

擊敗“inline hook”的方法也是用前面介紹過的“eb”內存編輯指令,根據上圖 IDA PRO 中的原始信息來還原。同樣需要留心字節序的問題!

(事實上,“!chkimg”有一個開關選項為“-f”,能夠把二進制文件的內存映像中所有被篡改或損壞之處還原成與磁盤文件上的一致,

“一鍵還原所有 hook”,無需前面介紹的繁雜手工操作;但既然該指令用在 nt 模塊上如此令人蛋疼,這里也就無法演示了,請各位自行測試!)

——————————————————————————————————————————————————————————————————————————————————————

清理完 SSDT 中的病毒后,讓我們來關注 SSDT Shadow——內核全局變量“KeServiceDescriptorTableShadow”持有該表的基地址,

該表由 Win32 子系統的內核模式部分—— Win32k.sys 填寫,負責實現 GUI 線程請求的所有涉及窗口繪圖,鼠標指針,以及其它圖形操作。

由於多數正規應用程序為了與用戶交互,都會請求圖形操作,因此該表也成了 rootkit 們重點 hook 的系統數據結構之一。

如下圖所示,我們在檢查 SSDT Shadow 中的函數時遇到了無效的內存地址(顯示為問號),這是因為斷入調試器的當前線程不是一個“GUI 線程”,所以它

的 SSDT Shadow 起始虛擬地址(圖中的 9a94c000)沒有映射到物理內存中的實際 SSDT Shadow(您可以看到

 

描述該虛擬地址的頁表條目是非法的)

 

如果當前線程的“nt!_KTHREAD”結構的“Win32Thread”字段為“NULL”,那么它就不是一個 GUI 線程,從而它的頁表中,描述

SSDT Shadow 虛擬地址的那一項 PTE 就是無效的,沒法用來轉譯物理地址:

 

 

為了“看見”Win32k.sys 實現的 SSDT Shadow,我們可以在絕大多數用戶、內核模式線程都頻繁調用的例程—— nt!NtWaitForSingleObject()

下一個條件斷點,僅在調用線程的“Win32Thread”字段不為空時,才斷入內核調試器,這樣我們就能夠窺視 SSDT Shadow 了!

如下一系列截圖所示:

 

 

 

 

綜上截圖所述,QQFrmMgr.sys 在 SSDT Shadow 中僅安裝了一枚鈎子,我們計算出該鈎子例程在整個 Win32k.sys 內存映像中的偏移量為

0x20c630——該信息相當關鍵,它用於在 Win32k.sys 磁盤文件中定位原始的 SSDT Shadow 函數入口地址。

 

再次以 IDA PRO 打開 Win32k.sys,從該模塊的描述信息可知,它的基地址為 0xBF800000,把這個值加上 0x20c630 得出

0xBFA0C630——也就是持有“受害”函數入口點的位置,於是我們在 IDA PRO 中執行“Jump to address”菜單選項,跳轉到該地址,

真相大白,被 hook 的就是“win32k!NtUserFindWindowEx”,請注意它的前后兩個例程與內存映像中鈎子例程的前后兩個完全一致。

反匯編“win32k!NtUserFindWindowEx”來獲取它在本次引導實例中的內核地址,然后用“eb”移除掉可惡的 QQ 鈎子函數,至此大功告成!

 

 

 

 

—————————————————————————————————————————————————————————————————————————————————————————

小結:本篇博文演示了如何通過調試手段,將被惡意修改的關鍵系統設施還原成初始狀態。

限於篇幅,最后一部分內容——銷毀 QQ 驅動注冊的事件通知回調函數——將放在下一篇博文中介紹,有任何疑問或者建議請在下方評論處反饋。

—————————————————————————————————————————————————————————————————————————————————————————

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM