zoukankan      html  css  js  c++  java
  • 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 ",KeServiceDescriptorTableShadow);
        DbgPrint("Count=%x ",KeServiceDescriptorTableShadow->win32k.NumberOfService);
        DbgPrint("ServiceTableBase=%x ",KeServiceDescriptorTableShadow->win32k.ServiceTableBase);

        status = PsLookupProcessByProcessId((HANDLE)GetExplorerIdByEnumProcess(), &exlorerEproc);

        if (!NT_SUCCESS( status ))
        {
            DbgPrint("PsLookupProcessByProcessId() error ");
            return ;
        }
        ApcState = (PKAPC_STATE)ExAllocatePool(NonPagedPool, sizeof(KAPC_STATE));
        KeStackAttachProcess(exlorerEproc, ApcState);

        for (i=0;i<KeServiceDescriptorTableShadow->win32k.NumberOfService;i++)
        {
            DbgPrint("索引:%d,地址:%x,原始地址:%8x ",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

  • 相关阅读:
    struts2 easyui实现datagrid的crud
    Codeforces 10A-Power Consumption Calculation(模拟)
    Java5新特性之枚举
    [总结]视音频编解码技术零基础学习方法
    (三 )kafka-jstorm集群实时日志分析 之 ---------jstorm集成spring 续(代码)
    codeforces Looksery Cup 2015 H Degenerate Matrix 二分 注意浮点数陷阱
    NHibernate3剖析:Query篇之NHibernate.Linq增强查询
    hdoj 1013Digital Roots
    小Y的难题
    【前端JS】radio 可单选可点击取消选中
  • 原文地址:https://www.cnblogs.com/kuangke/p/5761586.html
Copyright © 2011-2022 走看看