Shadow SSDT詳解、WinDbg查看Shadow SSDT


一、獲取ShadowSSDT

好吧,我們已經在R3獲取SSDT的原始地址及SDT、SST、KiServiceTbale的關系里面提到:所有的SST都保存在系統服務描述表(SDT)中。系統中一共有兩個SDT,一個是ServiceDescriptorTable,另一個是ServiceDescriptorTableShadow。ServiceDescriptor中只有指向KiServiceTable的SST,而ServiceDescriptorTableShadow則包含了所有的兩個SST。SSDT是可以訪問的,而SSDTShadow是不公開的。

所以結論是ServiceDescriptorTable是導出的,而ServiceDescriptorTableShadow是未導出的。那我們是不是就獲取不了ServiceDescriptorTableShadow的地址呢?未導出未必就不能得到。其實在KeAddSystemServiceTable這個導出函數里面是有ServiceDescriptorTableShadow的地址的。我們來反匯編看一下。

image

我們看到在這個函數里面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里面保存的函數數組。

image

我們看到KeServiceDescriptorTableShadow里面既有ntoskrnl.exe 的服務函數表也有win32k.sys 的服務函數表。

然后我們來看看win32k.sys 的服務函數表里面的數組。

image

一大堆????????是因為訪問不到ShadowSSDT的里面的函數地址。

網上很多說法是只有GUI進程才能訪問ShadowSSDT。我們切換到explorer.exe進程試試。

image這樣確實可以得到ShadowSSDT的函數地址。

引用黑月教主文章里面的一段話。

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.
觀察一下進程可以看到了:

image

也就是說,除了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


免責聲明!

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



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