之前的篇章已經有說明什麼是SSDT(System Service Descriptor Table),接下來我們要做更有趣的事情。此篇的主要目的是要攔劫(Hooking)OpenProcess,然後讓計算機程式(calc.exe)運行不起來,並且回傳存取失敗,最後實現控制OpenProcess的存取限制。
* 32 Bits和64 Bits的差別
如果想要在64 Bits去Hooking SSDT的難度會比較高,因為SSDT並沒有被Export,需要從初始化SSDT相關的記憶體找出它的位址,甚至有PatchGuard在檢測Kernel的記憶體是否有被修改,只要有被修改就會讓系統崩潰(藍底白字),因此必須要繞過PatchGuard,不過新手要分析PatchGuard的架構會非常困難,因為它初始化是利用除法運算讓商溢位產生Exception,然後初始化並運行DPC(Deferred Procedure Call),並且定時檢測Kernel記憶體是否有被竄改,相對32 Bits就相當能讓初學者比較好上手。
一、獲取SSDT起始位址
在32 Bits的系統裡,SSDT的結構有被導出,它的名稱叫做KeServiceDescriptorTable。
獲取SSDT結構位址。
其中ServiceTableBase就是SSDT的起始位址。
二、獲取OpenProcess起始位址
因為我們要知道OpenProcess是在SSDT的第幾個位置,這樣我們需要知道系統是如何調用它的,所以我們可以觀察ZwOpenProcess的程式碼,從而得知,可以在ZwOpenProcess的位址加1,就能抓取它的位置(0xBE)。
SSDT的陣列每格是4 Bytes的長度,因此需要位置(0xBE)乘上4,然後再獲取OpenProcess的起始位址。
三、修改CR0 (Control register)
如果要修改Kernel記憶體,我們需要改變CR0(特殊暫存器)的第16 Bits數值,它是決定是否可以寫入Kernel記憶體。
四、Hooking OpenProcess
Hooking OpenProcess,只要將SSDT上的OpenProcess的位址覆蓋成自己的函式就可以達到此效果。
五、控制OpenProcess的回傳值
通常在Hooking OpenProcess時,我們需要知道當前是哪個Process,因此會利用ZwQueryInformationProcess來獲取Process的名稱,這樣就能讓計算機程式(calc.exe)運行失敗。
六、執行結果
在運行計算機程式時,被我們寫的Hooking OpenProcess偵測到有被運行,然後將它強制關閉Process,這樣計算機程式就永遠運行失敗。