———————————————————————————————————————————————————————————————————————————————————————— 本篇開始進行真槍實彈的調試,本文的最後會附上完整的源碼包,方便各位在自己的機器上演練。 如果安裝了 Windows Dri ...
————————————————————————————————————————————————————————————————————————————————————————
本篇開始進行真槍實彈的調試,本文的最後會附上完整的源碼包,方便各位在自己的機器上演練。
如果安裝了 Windows Driver Kits,在“開始”->“所有程式”中選擇類似“WDK 7600.16385.1”的項目。具體的數字取決於你
安裝的 WDK 開發環境版本而定。然後選擇“Build Environments”下麵的操作系統版本,
亦即你編譯出來的驅動要運行其上的 OS 版本,接著選擇硬體平臺體繫結構與構建類型,比如“x86 Checked Build
Environment”是用於 32 位平臺,且附帶生成包含調試符號文件的構建環境。
調試符號文件有助於調試器顯示驅動二進位文件中的函數,變數,常量名稱等信息,生成人性化的輸出。
這樣會創建一個特殊的 cmd.exe 進程,它的環境變數預配置好了各種構建相關的參數,比如頭文件,庫文件的位置;編譯器,彙編
器,鏈接器程式所在路徑。。。等等。
我們在該 cmd 視窗中切換到源碼包的解壓目錄,然後執行如下命令:
build /D /g /b /B /e /F /S /s /$ /why /v /w /y
這些指定的參數讓你能查看詳細的構建過程,比如預處理器解析頭文件的嵌套包含過程,給出可能的警告或錯誤提示。
下麵是一個樣例輸出,對於排除過程中出現的問題很有用:
D:\kmdsource_use_mdl_mapping_ssdt>build /D /g /b /B /e /F /S /s /$ /why /v /w /y BUILD: Compile and Link for x86 BUILD: Loading d:\winddk\7600.16385.1\build.dat... BUILD: Computing Include file dependencies: Scanning d:\winddk\7600.16385.1\inc\api Scanning d:\winddk\7600.16385.1\inc\ddk BUILD: Start time: Mon Jan 29 14:08:34 2018 Scanning d:\kmdsource_use_mdl_mapping_ssdt Scanning d:\winddk\7600.16385.1\inc\crt BUILD: Examining d:\kmdsource_use_mdl_mapping_ssdt directory for files to compile. d:\kmdsource_use_mdl_mapping_ssdt Invalidating OACR warning log for 'root:x86chk' 0x00000001-0x00000001/0x00000001 usemdlmappingssdt.c ntddk.h d:\winddk\7600.16385.1\inc\ddk 0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c wdm.h d:\winddk\7600.16385.1\inc\ddk 0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c excpt.h d:\winddk\7600.16385.1\inc\crt 0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c crtdefs.h d:\winddk\7600.16385.1\inc\crt 0x00000005-0x00000001/0x00000001 usemdlmappingssdt.c specstrings.h d:\winddk\7600.16385.1\inc\api 0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c sal_supp.h d:\winddk\7600.16385.1\inc\api 0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c specstrings_supp.h d:\winddk\7600.16385.1\inc\api 0x00000007-0x00000001/0x00000001 usemdlmappingssdt.c sal_supp.h d:\winddk\7600.16385.1\inc\api 0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c sal.h d:\winddk\7600.16385.1\inc\api 0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c specstrings_strict.h d:\winddk\7600.16385.1\inc\api 0x00000007-0x00000001/0x00000001 usemdlmappingssdt.c specstrings_undef.h d:\winddk\7600.16385.1\inc\api 0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c driverspecs.h d:\winddk\7600.16385.1\inc\api 0x00000007-0x00000001/0x00000001 usemdlmappingssdt.c specstrings.h d:\winddk\7600.16385.1\inc\api 0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c sal_supp.h d:\winddk\7600.16385.1\inc\api 0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c specstrings_supp.h d:\winddk\7600.16385.1\inc\api 0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c sal.h d:\winddk\7600.16385.1\inc\api 0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c specstrings_strict.h d:\winddk\7600.16385.1\inc\api 0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c sdv_driverspecs.h d:\winddk\7600.16385.1\inc\api 0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c ntdef.h d:\winddk\7600.16385.1\inc\api 0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c ctype.h d:\winddk\7600.16385.1\inc\crt 0x00000005-0x00000001/0x00000001 usemdlmappingssdt.c crtdefs.h d:\winddk\7600.16385.1\inc\crt 0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c specstrings.h d:\winddk\7600.16385.1\inc\api 0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c kernelspecs.h d:\winddk\7600.16385.1\inc\api 0x00000005-0x00000001/0x00000001 usemdlmappingssdt.c driverspecs.h d:\winddk\7600.16385.1\inc\api 0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c basetsd.h d:\winddk\7600.16385.1\inc\api 0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c guiddef.h d:\winddk\7600.16385.1\inc\api 0x00000005-0x00000001/0x00000001 usemdlmappingssdt.c string.h d:\winddk\7600.16385.1\inc\crt 0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c crtdefs.h d:\winddk\7600.16385.1\inc\crt 0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c excpt.h d:\winddk\7600.16385.1\inc\crt 0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c sdkddkver.h d:\winddk\7600.16385.1\inc\api 0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c ntstatus.h d:\winddk\7600.16385.1\inc\api 0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c bugcodes.h d:\winddk\7600.16385.1\inc\api 0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c ntiologc.h d:\winddk\7600.16385.1\inc\api 0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c mce.h d:\winddk\7600.16385.1\inc\ddk 0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c pshpack4.h d:\winddk\7600.16385.1\inc\api 0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c poppack.h d:\winddk\7600.16385.1\inc\api 0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c guiddef.h d:\winddk\7600.16385.1\inc\api 0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c pshpack1.h d:\winddk\7600.16385.1\inc\api 0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c string.h d:\winddk\7600.16385.1\inc\crt 0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c dpfilter.h d:\winddk\7600.16385.1\inc\api 0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c ktmtypes.h d:\winddk\7600.16385.1\inc\api 0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c dsfhrmports.h d:\winddk\7600.16385.1\inc\ddk Compiling - d:\kmdsource_use_mdl_mapping_ssdt\usemdlmappingssdt.c 0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c evntrace.h d:\winddk\7600.16385.1\inc\api Linking Executable - d:\kmdsource_use_mdl_mapping_ssdt\objchk_win7_x86\i386\UseMdlMappingSSDT.sys 0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c stdarg.h d:\winddk\7600.16385.1\inc\crt 0% done. 0 TLPS Time Left: 0:00:00 Files: 0 Total LLines: 0 0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c vadefs.h d:\winddk\7600.16385.1\inc\crt 0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c evntprov.h d:\winddk\7600.16385.1\inc\api 0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c devpropdef.h d:\winddk\7600.16385.1\inc\api 0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c clfslsn.h d:\winddk\7600.16385.1\inc\ddk 0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c excpt.h d:\winddk\7600.16385.1\inc\crt 0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c ntdef.h d:\winddk\7600.16385.1\inc\api 0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c ntstatus.h d:\winddk\7600.16385.1\inc\api 0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c bugcodes.h d:\winddk\7600.16385.1\inc\api 0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c ntiologc.h d:\winddk\7600.16385.1\inc\api 0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c mce.h d:\winddk\7600.16385.1\inc\ddk 0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c pshpack4.h d:\winddk\7600.16385.1\inc\api 0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c poppack.h d:\winddk\7600.16385.1\inc\api 0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c guiddef.h d:\winddk\7600.16385.1\inc\api 0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c pshpack1.h d:\winddk\7600.16385.1\inc\api 0x00000001-0x00000001/0x00000001 usemdlmappingssdt.c datatype.h d:\kmdsource_use_mdl_mapping_ssdt 0x00000001-0x00000001/0x00000001 usemdlmappingssdt.c dbgmsg.h d:\kmdsource_use_mdl_mapping_ssdt 0x00000001-0x00000001/0x00000001 usemdlmappingssdt.c ctrlcode.h d:\kmdsource_use_mdl_mapping_ssdt 0x00000001-0x00000001/0x00000001 usemdlmappingssdt.c device.h d:\kmdsource_use_mdl_mapping_ssdt 0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c ntddk.h d:\winddk\7600.16385.1\inc\ddk Compiling usemdlmappingssdt.c because .. (0x00000006) BUILD: Saving d:\winddk\7600.16385.1\build.dat... BUILD: Compiling and Linking d:\kmdsource_use_mdl_mapping_ssdt directory Configuring OACR for 'root:x86chk' - <OACR on> 1>warnings in directory d:\kmdsource_use_mdl_mapping_ssdt alSystemServicePtr' differs in levels of indirection from 'DWORD'1>d:\kmdsource_use_mdl_mapping_ssdt\usemdlmappingssdt.c(157) : warning BUILD: Finish time: Mon Jan 29 14:08:35 2018 BUILD: Done 3 files compiled - 2 Warnings 1 executable built D:\kmdsource_use_mdl_mapping_ssdt>
我在前一篇文章中說過,可以忽略源碼中 157 行造成的警告——rootkit 的實際效果不受該警告影響。
把編譯出來的 UseMdlMappingSSDT.sys 拷貝到虛擬機或另一臺真實機器上(交叉編譯的目標平臺假設是 widnows 7
或 Windows Server 2008),使用 sc.exe 載入該驅動進入內核空間,如果一切正常,宿主機上應該會觸發首個斷點,位
於 MapMdl() 中,如下圖,註意,DbgPrint() 與 DBG_TRACE 巨集的輸出信息除了可以在目標機器上用 DbgView.exe 查看外,也
會直接輸出到宿主機上調試器的控制台。我們只關心獲取到的 KiServiceTable 地址: 83CABF7C ;
分配出來的一個 nt!_MDL 結構地址:86A838A8 ;
由於之前選擇了“Checked Build”構建環境,現在調試器能夠根據“UseMdlMappingSSDT.pdb”符號文件顯示諸如 MapMdl()
之類的函數名稱:
結合源碼可知,首個斷點位於 IoAllocateMdl() 調用後不遠處,我們的意圖是檢查該調用後的一個 nt!_MDL 對象內容,前面通
過 mdl_pointer 保存的地址派上用場:
如你所見,IoAllocateMdl() 分配出來的一個 MDL 總大小(頭部加上其後的 PFN 數組)為 36 位元組;當前的標誌取值 10 進位
的 8,參見前一篇博文可知,它只對應 MDL_ALLOCATED_FIXED_SIZE;還記得嗎,我在前一篇博文指出:
僅當 _MDL 的 MdlFlags 欄位內設置了 MDL_MAPPED_TO_SYSTEM_VA 或 MDL_SOURCE_IS_NONPAGED_POOL 比特位,
MappedSystemVa 欄位才是有效的,因此上圖中的 MappedSystemVa 欄位值 0x8059d950 沒有意義。
你還看到, StartVa 欄位值為 0x83cab000,這就是 KiServiceTable(從 0x83CABF7C 開始)所在的虛擬頁起始地址,註意這個
地址是對齊在 4 KB 邊界上的,因為虛擬頁和物理頁大小正情況下均為 4 KB。
ByteOffset 欄位值為 0xf7c,亦即 KiServiceTable 的頁內偏移量—— 0x83CABF7C - 0x83cab000 = 0xf7c
ByteCount 欄位值為 0x644,亦即整張 KiServiceTable 調用表(一片緩衝區)的大小—— 1064 位元組。
在猶如醍醐灌頂的狀態下,按“g”繼續執行目標系統至第二個軟體斷點處,再次轉儲這個 nt!_MDL 對象內容:
MdlFlags 欄位值變成了 138(0x8A),對照相關的巨集定義可知,這是 MDL_WRITE_OPERATION(0x80)加
上 MDL_PAGES_LOCKED(0x02)加上 MDL_ALLOCATED_FIXED_SIZE(0x08)的組合,表明 MmProbeAndLockPages() 常式
把該 MDL 鎖在物理記憶體中,且具有了寫訪問許可權。
繼續按“g”執行目標系統至第三個軟體斷點處,再次轉儲這個 nt!_MDL 對象內容,謹記在心,此刻代表
MmGetSystemAddressForMdlSafe() 常式執行後的狀態:
首先,MdlFlags 欄位值變成了 139(0x8B),這表明追加了一個 MDL_MAPPED_TO_SYSTEM_VA 標誌,從而使得
MappedSystemVa 欄位值:0x805fbf7c 為有效,它代表把 KiServiceTable 映射到的新內核緩衝區起始地址,這與 eax 寄存器
(普遍用來存放函數調用的返回值,在此場景中由 MmGetSystemAddressForMdlSafe() 返回 )的值相符!
細心的你可能已經發現了,“舊”緩衝與新緩衝地址的後 12 位都是“f7c”,這當然不是巧合,事實上,虛擬地址的後 12 位(頁
內偏移)在地址轉譯階段被原封不動地與高 20 位的物理頁框號結合產生物理地址!這暗示它們都映射到相同的物理地址。
那麼通過它們應該訪問到同一個 KiServiceTable,如下所示,記住,當前斷點是尚未 hook KiServiceTable,因此 0x39 號系統服
務還是原來的那一個—— nt!NtCompleteConnectPort() :
前面我說過,新映射到的內核地址通常位於驅動被載入的內核空間中,下圖否決了這一點(盡信博文不如無博文!):
你可以看到,我們的 rootkit“UseMdlMappingSSDT”被載入到 9ff55000——9ff5c000 這片內核空間,占用 28 KB 左右的內
核記憶體!
而 KiServiceTable 被映射到的 805fbf7c 內核地址顯然不在其內。
事實上,KiServiceTable 被映射到的 805fbf7c 內核地址屬於“SystemPte 型(即系統頁表條目)”內核空間,此類內核空間有多
種用途,包括提供給 MDL 來把 SSDT/KiServiceTable 映射到此處。
系統頁表條目(PTEs)內核空間,用於動態地映射系統頁面,例如 I/O 空間,內核棧,以及映射記憶體描述符列表(MDLs)。
系統 PTE 的分配者除了各種執行體/內核組件外,多數是一些載入到內核空間的設備驅動程式,其中有系統自帶的,也有第三方軟
硬體供應商開發的;
它們請求在系統 PTE 區域中分配記憶體的目的都是與映射視圖,MDLs(記憶體描述符列表),適配器記憶體映射,驅動程式映像,內核
棧, I/O 映射等相關的,如下圖所示:
內核空間中有多處被劃分為 SystemPte 類型,我們把 KiServiceTable 映射到第一個 SystemPte 型內核空間,該區域大小為 4
MB。
按下“g”繼續執行,這會導致 MapMdl() 返回新映射的地址到 DriverEntry(),後者掛鉤 nt!NtCompleteConnectPort(),另一方
面,我們還可以通過計算出來的 nt!_MDL 頭部大小訪問到其後的 PFN 數組,檢查其內保存的物理頁框號是否就是虛擬地址
0x83CABF7C 和 0x805fbf7c 兩者執行地址轉譯後所在的物理頁框號,它們都被轉譯到物理地址 0x3cabf7c,頁框號為
0x03cab,虛擬地址的後 12 位偏移量(0xf7c)直接拷貝到物理地址的後 12 位偏移量;
頁框號還可以通過對 pfn_array_follow_mdl 執行指針運算並解引地址處的內容得出,也是 0x03cab;
兩者的區別在於,描述虛擬地址 0x83CABF7C 的 PTE 內容設置了只讀標記;而描述虛擬地址 0x805fbf7c 的 PTE 內容設置了可讀
寫標記,因此通過虛擬地址 0x83CABF7C 向實際的物理頁寫入就會藍屏;而通過虛擬地址 0x805fbf7c 則可以安全寫入!
訪問 KiServiceTable 中的 0x39 號系統服務,已經被替換為我們的鉤子常式:
我提供了一個 UnMapMdl() 常式,把它註冊為該 rootkit 的卸載回調,大致邏輯是,在驅動卸載時,取消映射新的內核虛擬地址,
並釋放 MDL 指針 ,如此一來,卸載 UseMdlMappingSSDT.sys 後,既不能通過新映射的地址訪問 KiServiceTable,也不能通過
指針訪問 nt!_MDL 結構(但該結構確實尚未釋放):
最後,讓我們填充前一篇博文中那張 MDL 架構圖中的占位符,以便讓各位能夠洞察整個來龍去脈。祝願你沒有被那些紅紅綠綠的
箭頭搞暈!
附上源碼包的下載地址,歡迎反饋。
https://files.cnblogs.com/files/flying-shark/kmdsource_use_mdl_mapping_ssdt.rar