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

转载于:https://www.cnblogs.com/kuangke/p/5761586.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值