一、獲取ShadowSSDT
好吧,我們已經在R3獲取SSDT的原始地址及SDT、SST、KiServiceTbale的關系里面提到:所有的SST都保存在系統服務描述表(SDT)中。系統中一共有兩個SDT,一個是ServiceDescriptorTable,另一個是ServiceDescriptorTableShadow。ServiceDescriptor中只有指向KiServiceTable的SST,而ServiceDescriptorTableShadow則包含了所有的兩個SST。SSDT是可以訪問的,而SSDTShadow是不公開的。
所以結論是ServiceDescriptorTable是導出的,而ServiceDescriptorTableShadow是未導出的。那我們是不是就獲取不了ServiceDescriptorTableShadow的地址呢?未導出未必就不能得到。其實在KeAddSystemServiceTable這個導出函數里面是有ServiceDescriptorTableShadow的地址的。我們來反匯編看一下。
我們看到在這個函數里面ServiceDescriptorTable的地址和ServiceDescriptorTableShadow都是可以找到的。
其實 KeServiceDescriptorTableShadow包含4個子結構,其中第一個就是ntoskrnl.exe ( native api ),和KeServiceDescriptorTable指向一樣 我們真正需要獲得的是第二個win32k.sys (gdi/user support),第三個和第四個一般不使用。
如何定位ServiceDescriptorTableShadow呢?
①硬編碼:
//for xp
if(gKernelVersion==WINXP)
KeServiceDescriptorTableShadow=KeServiceDescriptorTable-0×40;
//for 2k
if(gKernelVersion==WIN2K)
KeServiceDescriptorTableShadow=KeServiceDescriptorTable+0xE0;
//for win7 32
if(gKernelVersion==WIN7X86)
KeServiceDescriptorTableShadow=KeServiceDescriptorTable+0×40;
②根據KeAddSystemServiceTable來搜索
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
ULONG GetAddressOfShadowTable
(
)
{ ULONG i ; UCHAR * p ; ULONG dwordatbyte ; UNICODE_STRING usKeAddSystemServiceTable ; RtlInitUnicodeString ( &usKeAddSystemServiceTable , L "KeAddSystemServiceTable" ) ; p = (UCHAR * )MmGetSystemRoutineAddress ( &usKeAddSystemServiceTable ) ; for (i = 0 ; i < 4096 ; i ++,p ++ ) { __try { dwordatbyte = * (ULONG * )p ; }__except (EXCEPTION_EXECUTE_HANDLER ) { return 0 ; } if (MmIsAddressValid ( (PVOID )dwordatbyte ) ) { if ( memcmp ( (PVOID )dwordatbyte , KeServiceDescriptorTable , 16 ) == 0 ) //比較的是地址指向的內容 { if ( (PVOID )dwordatbyte == KeServiceDescriptorTable ) { continue ; } return dwordatbyte ; } } } return 0 ; } |
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
PULONG GetAddressOfShadowTable2
(
)
{ PUCHAR Buff ; PUCHAR p ; UNICODE_STRING usKeAddSystemServiceTable ; PULONG ShadowTable = NULL ; RtlInitUnicodeString ( &usKeAddSystemServiceTable , L "KeAddSystemServiceTable" ) ; Buff = (PUCHAR )MmGetSystemRoutineAddress ( &usKeAddSystemServiceTable ) ; for (p = Buff ; p < Buff + PAGE_SIZE ; p ++ ) { if (MmIsAddressValid ( (PVOID )p ) ) { if ( ( * (PUSHORT )p == 0x888D ) && ( * (p + 6 ) == 0x83 ) ) { ShadowTable = (PULONG ) (p + 2 ) ; break ; } } } return ShadowTable ? ShadowTable : NULL ; } |
獲取到KeServiceDescriptorTableShadow的地址后,我們用windbg來看一下ShadowSSDT里面保存的函數數組。
我們看到KeServiceDescriptorTableShadow里面既有ntoskrnl.exe 的服務函數表也有win32k.sys 的服務函數表。
然后我們來看看win32k.sys 的服務函數表里面的數組。
一大堆????????是因為訪問不到ShadowSSDT的里面的函數地址。
網上很多說法是只有GUI進程才能訪問ShadowSSDT。我們切換到explorer.exe進程試試。
引用黑月教主文章里面的一段話。
MJ說win32k.sys和Session有關,也就是說,win32k.sys在Session Leader(Csrss.exe)及屬於該Session的任何一個進程空間中都可以訪問。
WindowsXP下系統服務和第一個登錄用戶共享同一個Session,即Session 0,Vista/Win7中采用了Session隔離,系統服務使用Session 0,第一個用戶使用Session 1,其它依次類推。
在這兩種系統中,都是遵守這個規則的。但是有一個特殊的不屬於任何Session的進程,就是Session Manager(Smss.exe)。
切換到Smss.exe進程空間看一看:
kd> dt_eprocess 8501d3e8 ImageFileName
nt!_EPROCESS
+0x16c ImageFileName : [15] “smss.exe”
kd> .process 8501d3e8
Implicit process is now 8501d3e8
WARNING: .cache forcedecodeuser is not enabled
kd> dd 8fc25000
bf800000 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
bf800010 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
bf800020 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
bf800030 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
bf800040 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
bf800050 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
bf800060 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
bf800070 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
kd> !pte 8fc25000
VA 8fc25000
PDE at C06023F0 PTE at C047E128
contains 0000000000000000
not valid
在Session Manager的進程空間中,win32k.sys也是無法訪問的,因為它不屬於任何一個Session.
觀察一下進程可以看到了:
也就是說,除了System進程和Smss進程,在其它任何一個屬於某個Session進程內都可以訪問win32k.sys,並非只有GUI進程才能訪問。
二、如何HOOK?
似乎這個問題並不大,shadow ssdt和ssdt本質上都是1個地址表,最為簡單的方法是把你的函數替換地址表的對應項,具體hook代碼甚至可以完全照抄ssdt的,這里只說下幾個遇到的小問題。
1。win32k.sys不是常在內存的,如果不是GUI線程,shadow ssdt地址無效
解決辦法:
1。在driverdispatch中hook
driverdispatch是位於執行driveriocontrol的線程上下文的
我們使用1個GUI線程去driveriocontrol
2。attachtoprocess
這里我們使用explorer.exe進程。
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
VOID KeAttachCsrss
(
)
{ NTSTATUS status ; PEPROCESS exlorerEproc ; PKAPC_STATE ApcState ; ULONG i ; DbgPrint ( "GetExplorerIdByEnumProcess ==> %d" , GetExplorerIdByEnumProcess ( ) ) ; DbgPrint ( "KeServiceDescriptorTableShadow=%x \r\n" ,KeServiceDescriptorTableShadow ) ; DbgPrint ( "Count=%x \r\n" ,KeServiceDescriptorTableShadow ->win32k. NumberOfService ) ; DbgPrint ( "ServiceTableBase=%x \r\n" ,KeServiceDescriptorTableShadow ->win32k. ServiceTableBase ) ; status = PsLookupProcessByProcessId ( (HANDLE )GetExplorerIdByEnumProcess ( ) , &exlorerEproc ) ; if ( !NT_SUCCESS ( status ) ) { DbgPrint ( "PsLookupProcessByProcessId() error\n" ) ; return ; } ApcState = (PKAPC_STATE )ExAllocatePool (NonPagedPool , sizeof (KAPC_STATE ) ) ; KeStackAttachProcess (exlorerEproc , ApcState ) ; for (i = 0 ;i <KeServiceDescriptorTableShadow ->win32k. NumberOfService ;i ++ ) { DbgPrint ( "索引:%d,地址:%x,原始地址:%8x \r\n" ,i ,KeServiceDescriptorTableShadow ->win32k. ServiceTableBase [i ] , GetShadowSSDTFunctionOriAddr (i ) ) ; } KeUnstackDetachProcess (ApcState ) ; } |
其中GetExplorerIdByEnumProcess這個方法的實現,只需要簡單的遍歷進程活動鏈表即可。
三、獲取ShadowSSDT函數名
比較簡單的應該算是設計張函數名表和用symbol的方法。
這辦法簡單的原因是我只需要一個win32k.sys,win32k.pdb,以及調用不到10個的API就能完成工作。
1.調用SymInitialize初始化Dbghelp這系列的函數。
2.調用ImageLoad讀取文件win32.sys。
3.調用SymLoadModule來讀取pdb文件。
4.調用SymEnumSymbols枚舉符號,其中一個參數是回調函數SymEnumSymbolsProc,that’s the key。
SymEnumSymbolsProc中有一個系統會幫忙填充一個為PSYMBOL_INFO結構的參數。在這個結構中我主要用到的是Name和Address。
5.調用ImageUnload和SymCleanup做一些清理工作。
首先是獲得W32pServiceTable的地址。熟悉ShadowSSDT都知道,W32pServiceTable是在內核初始化用來填充ShadowSSDT的表。
然后,知道了W32pServiceTable的地址,后面的事情也很容易。用SymEnumSymbolsProc把ShadowSSDT每個函數的地址和函數名保存下來。
但是我並不推薦使用這種方法來獲取ShadowSSDT的函數地址。pdb文件也有幾M吧,還需要去請求pdb文件,還得看網絡環境。
所以還不如使用硬編碼吧。。。
本文鏈接:http://www.blogfshare.com/shadowssdt-explain-in-detail.html
jpg 改 rar