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的地址的。我们来反汇编看一下。

我们看到在这个函数里面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进程试试。

这样确实可以得到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.
观察一下进程可以看到了:

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

时间: 2024-08-14 02:51:44

Shadow SSDT详解、WinDbg查看Shadow SSDT的相关文章

挂钩SSDT详解附源代码

源代码下载地址:挂钩SSDT源代码 据微软所言,服务描述符表是一个由四个结构组成的数组,其中的每一个结构都是由四个双字项组成.因此,我们可以将服务描述符表表示为: typedef struct ServiceDescriptorTable { SDE ServiceDescriptor[4]; }SDT; 其中,其中的每一个服务描述符呈现出四个双字的形式,它的结构为: #pragma pack(1) typedef struct ServiceDescriptorEntry { unsigned

Linux系统IO分析工具之iotop参数详解(查看IO占用)

这篇文章主要介绍了Linux系统IO分析工具之iotop参数详解(查看IO占用),本文着重注解了iotop工具的参数,以及可操作命令,需要的朋友可以参考下 简介: iotop – simple top-like I/O monitoriotop是一个用来监视磁盘I/O使用状况的 top 类工具,可监测到哪一个程序使用的磁盘IO的信息(requires 2.6.20 or later) 安装: 复制代码 代码如下: yum -y install iotop 用法: 复制代码 代码如下: iotop

sqlserver锁机制详解(sqlserver查看锁)

简介 在SQL Server中,每一个查询都会找到最短路径实现自己的目标.如果数据库只接受一个连接一次只执行一个查询.那么查询当然是要多快好省的完成工作.但对于 大多数数据库来说是需要同时处理多个查询的.这些查询并不会像绅士那样排队等待执行,而是会找最短的路径执行.因此,就像十字路口需要一个红绿灯那 样,SQL Server也需要一个红绿灯来告诉查询:什么时候走,什么时候不可以走.这个红绿灯就是锁. 图1.查询可不会像绅士们那样按照次序进行排队 为什么需要锁 在开始谈锁之前,首先要简单了解一下事

linux /etc/shadow文件详解

struct spwd { char *sp_namp; /* user login name */ char *sp_pwdp; /* encrypted password */ long int sp_lstchg; /* last password change */ long int sp_min; /* days until change allowed. */ long int sp_max; /* days before change required */ long int sp

/etc/shadow文件详解

/etc/shadow文件是用于存放用户密码的,以密文形式存储.下面将详细介绍该文件. [[email protected] ~]# ls -l /etc/shadow #查看文件的详细信息 ---------- 1 root root 908 12月 14 18:20 /etc/shadow [[email protected] ~]# cat /etc/shadow #查看文件的内容 root:$6$UxT.2KHv$Z/tIQGuvGwaa/kvgNj7GpAw5lENtb.sas77yj

who命令参数及用法详解(linux查看在线用户命令)

功能说明:显示目前登入系统的用户信息.  语 法:who [-Himqsw][--help][--version][am i][记录文件]  补充说明:执行这项指令可得知目前有那些用户登入系统,单独执行who指令会列出登入帐号,使用的终端机,登入时间以及从何处登入或正在使用哪个X显示器.  参 数:  -H或--heading 显示各栏位的标题信息列. -i或-u或--idle 显示闲置时间,若该用户在前一分钟之内有进行任何动作,将标示成"."号,如果该用户已超过24小时没有任何动作,

Linux命令详解-进程查看

1.进程的查看: ps –el --e:显示所有进程,包括没有控制终端的进程 --l:以长格式显示 结果显示: PID:进程号 PPID:父进程 tty:控制终端 stat:进程当前的状态  其中S:表示休眠状态,D:不可中断的休眠  Z:僵死状态  R:正在运行 NI:查看进程优先级 Time:启动的总时间 ps –aux --a:显示所有的进程 --u:显示用户 --x:显示无终端的进程 ps –aux –sort pid 按进程号进行排序 2.杀死进程: xclock   开启时间进程 p

Linux route命令详解:查看和操作IP路由表

Linux系统的route命令用于显示和操作IP路由表(show / manipulate the IP routing table).要实现两个不同的子网之间的通信,需要一台连接两个网络的路由器,或者同时位于两个网络的网关来实现. 在Linux系统中,设置路由通常是为了解决以下问题:该Linux系统在一个局域网中,局域网中有一个网关,能够让机器访问Internet,那么就需要将这台机器的IP地址设置为Linux机器的默认路由.要注意的是,直接在命令行下执行route命令来添加路由,不会永久保存

5、linux用户和组管理详解

linux用户和组管理 类Unix系统的设计初衷就是为让多用户同时工作,所以也迫使Linux系统有了极强的安全性,在前面安装红帽RHEL7操作系统时还特别要求"设置root用户密码",而root用户是存在于所有类UNIX系统中的"超级用户". 用户管理 root账户介绍(超级管理员) root用户拥有极高的系统所有权,能够管理系统的各项功能,如添加/删除用户,启动/关闭进程,开启/禁用硬件设备等权限.虽然使用root用户工作时不会受到权限的控制,但老话讲"