找回密码
 加入我们

QQ登录

只需一步,快速开始

搜索
查看: 4437|回复: 1

SSDT入门篇---------------转帖

[复制链接]

90

主题

473

回帖

2

精华

钻石会员

积分
3261
发表于 2010-8-26 09:57:46 | 显示全部楼层 |阅读模式
本帖最后由 ok100fen 于 2010-8-26 10:00 编辑

SSDT入门


【图System Module
Dependencies】揭示了系统各模块之间的依赖关系(有所简化)
从图中可以看出,所有的Win32
API调用最后都转移到了ntdll.dll,而ntdll.dll又将其转移到了ntoskrnl.exe。ntdll.dll是一个操作系统组件,它 为Native
API准确地提供服务,ntdll.dll是Native
API在用户模式下的前端,真正的接口在ntoskrnl.exe中实现。ntoskrnl.exe是NT操作系统内核,内核模式驱动程序对系统服务的请
求多数时候都会进入该模块。
例如,由kernel32.dll导出的Win32
API函数DeviceIoControl()最终会调用由ntdll.dll导出的NtDeviceIoControlFile()。
NtDeviceIoControlFile:
mov   eax, 38h
lea  
edx, [esp+4]
int   2Eh
ret   28h
"魔术"数字0x38是一个分派ID;INT 2Eh指令将跳转到中断描述符表(Interrupt Descriptor
Table,IDT)的0x2e位置上存放的中断处理例程(interrupt
handler)中,分配器(dispatcher)利用它从用户模式进入内核模式。
从NtDeviceIoControlFile示例给出的反汇编代码可看出,INT
2Eh随同传入CPU寄存器EAX和EDX的两个参数一起被调用。处理INT
2Eh的代码必须确定每个调用将被分配到哪个函数。这就是提供EAX中的"魔术"数字--分派ID的原因。位于ntoskrnl.exe中的中断处理例程
将EAX中的数值作为一个索引来查询一个特定的表。这个表被称作系统服务表(System Service Table,
SST)该表对应的C结构体---SYSTEM_SERVICE_TABLE:
typedef struct
_SYSTEM_SERVICE_TABLE
{
   
PNTPROC  ServiceTable;   // array of entry points
  
  PDOWRD  CounterTable;   // array of usage
counters
    DWORD   ServiceLimit;    // number
of table entries
    PBYTE   
ArgumentTable;  // array of byte
counts
}SYSTEM_SERVICE_TABLE,*PSYSTEM_SERVICE_TABLE,**PPSYSTEM_SERVICE_TABLE;
但是SST并不是源头,而且内核中还存在多个SST表,所以内核维护着另外一个表结构,该结构共有四个SST类型的数组,其中的前两个用于特定目的,头两
个数组保留给了ntoskrnl.exe和Win32子系统(位于win32k.sys)中的内核模式部分(来自gdi32.dll和
user32.dll的调用都通过Win32k的系统服务表(SST)进行分派)。ntolkrnl.exe导出了一个指针(符号为
KeServiceDescriptorTable)指向其主服务描述符表(Main
SDT),内核还维护了一个替代的SDT,其名称为KeServiceDescriptorTableShadow,但这个SDT并没有被导出。
这个表被称作服务描述符表(The
Service Descriptor Tables, SDT)该表对应的C结构体---SERVICE_DESCRIPTOR_TABLE:
typedef struct _SERVICE_DESCRIPTOR_TABLE
{
   
SYSTEM_SERVICE_TABLE ntoskrnl;  // ntoskrnl.exe ( native api
)
    SYSTEM_SERVICE_TABLE win32k;    // win32k.sys
(gdi/user support)
    SYSTEM_SERVICE_TABLE Table3;    //
not used
    SYSTEM_SERVICE_TABLE Table4;    // not
used
}SYSTEM_DESCRIPTOR_TABLE,*PSYSTEM_DESCRIPTOR_TABLE,**PPSYSTEM_DESCRIPTOR_TABLE;
啰啰嗦嗦一大堆,简单说,内核维护着_SERVICE_DESCRIPTOR_TABLE这样一个SDT结构数据,即
KeServiceDescriptorTable,里面保存着ntoskrnl.exe的SST结构数据(当然还包括其他SST),其中
ServiceTable指向的是由ServiceLimit个函数指针构成的数组;当执行前面提到的NtDeviceIoControlFile示例代
码时,内核找到KeServiceDescriptorTable,接着找到ntoskrnl.ServiceTable,该地址是函数指针数组的首地
址,所以NtDeviceIoControlFile函数地址为[ServiceTable+0x38*4]。

【图 SSDT Call
Process】SSDT查找函数地址过程
二:内核调试
对SSDT的观察与相关调试,需要使用到内核调试工具,当了解了内核调试,你也许就不会把下面这样的字符串看作是天外飞仙了:
kd> dd KeServiceDescriptorTable
“Debugging Tools
for
Windows”是Microsoft调试器套件,它对Windows系统的符号支持要好一些,我一般是使用图形界面的Windbg,下载安装即可。【2】
内核调试最方便的应该是用虚拟机做调试,可以很方便的重启系统,搭建一个WinDbg和VMware的内核调试环境网上有很多资料可供参考。【3】
需要指出的是在配置虚拟操作系统boot.ini文件时需要特别注意,否则启动系统时会报“Virtual
machine kernel stack fault”此样的错误且无法启动系统。
启动Windbg和虚拟操作系统,Windows XP
SP2系统为例:
等待连接被调试内核
>>Opened
\\.\pipe\com_1
>>Waiting to reconnect...
连接被调试内核
>>Connected to Windows XP 2600 x86
compatible target at (Sun Jun  7 21:48:35.875 2009 (GMT+8)), ptr64
FALSE
>>Kernel Debugger connection established.  (Initial
Breakpoint requested)
成功连接被调试内核后,中断下来等待命令
>>nt!RtlpBreakWithStatusInstruction:
>>8052b5d8
cc              int  
   3
三:SSDT观察分析与操作
当内核中断下来时,系统内核已经启动,这时可以观察SSDT数据:
nt!RtlpBreakWithStatusInstruction:
8052b5d8 cc     
         int  
   3
kd> dd
keServiceDescriptorTable
8055c6e0  80504734 00000000 0000011c
80504ba8
8055c6f0  00000000 00000000 00000000
00000000
8055c700  00000000 00000000 00000000
00000000
8055c710  00000000 00000000 00000000
00000000
8055c720  00000002 00002710 00000000
00000000
8055c730  8055c730 8055c730 806f5040
806f5040
8055c740  00000000 00000000 00000000
00000000
8055c750  00000000 00000000 00000000 00000000
根据SDT的结构定义,ntoskrnl.ServiceTable=0x80504734;


【图
NtCreateProcess_ID】NtCreateProcess
ID号
以NtCreateProcess为例,反汇编ntdll.dll,可以看出其编号是0x2F,从图【图
NtCreateProcess_ID】可以看出这一点,0x80504734+0x2F*4=0x805047F0, 所以
kd> dd 80504734 805047f0
80504734  805a4054 805f02d8
805f3b0e 805f030a
80504744  805f3b48 805f0340 805f3b8c
805f3bd0
80504754  80614adc 8061581e 805eb67a
805eb2d2
80504764  805d430c 805d42bc 80615102
805b593a
80504774  8061471e 805a84de 805aff5e
805d5dd0
80504784  80501c00 80615810 80576900
80538bbc
80504794  8060dd26 805bbeb4 805f4048
80622c18
805047a4  805f853a 805a4742 80622e6c
805a3ff4
805047b4  80544e5c 80640e5a 805bdd68
8060dd76
805047c4  80616094 80578e5e 805776f0
805d4d94
805047d4  805d4acc 80623048 80578f6c
8061648c
805047e4  80578e98 805ab414 805a4b10 805d0a1c
在反汇编窗口输入805d0a1c可得:
nt!NtCreateProcess:
805d0a1c 8bff        
    mov     edi,edi
805d0a1e 55  
            push   
ebp
805d0a1f 8bec           
mov     ebp,esp
805d0a21 33c0     
       xor     eax,eax
805d0a23
f6451c01        test    byte ptr
[ebp+1Ch],1
805d0a27 7401           
je      nt!NtCreateProcess+0xe (805d0a2a)
805d0a29
40              inc  
   eax
805d0a2a f6452001     
   test    byte ptr [ebp+20h],1
805d0a2e 7403  
          je     
nt!NtCreateProcess+0x17 (805d0a33)
805d0a30 83c802     
     or      eax,2
805d0a33 807d1800  
      cmp     byte ptr
[ebp+18h],0
805d0a37 7403           
je      nt!NtCreateProcess+0x20 (805d0a3c)
805d0a39
83c804          or      eax,4
或是执行命令ln 805d0a1c可得
kd> ln
805d0a1c
(805d0a1c)   nt!NtCreateProcess  
|  (805d0a62)   nt!NtQueueApcThread
所以可以证实,[0x805047f0]=0x805d0a1c,该值就是NtCreateProcess的入口地址。
该虚拟操作系统中安装有安全防护软件,具有进程监控的功能,应该会Hook
NtCreateProcess操作,可以看看会有何变化:
让虚拟系统退出中断,继续运行
kd>
g
当系统正常完成启动后再次进行中断执行命令
nt!RtlpBreakWithStatusInstruction:
8052b5d8 cc     
         int  
   3
kd> dd
keServiceDescriptorTable
8055c6e0  80504734 00000000 0000011c
80504ba8
8055c6f0  00000000 00000000 00000000
00000000
8055c700  00000000 00000000 00000000
00000000
8055c710  00000000 00000000 00000000
00000000
8055c720  00000002 00002710 bf80da45
00000000
8055c730  f8b70a80 824bd220 823fca90
806f5040
8055c740  00000000 00000000 0b50f518
00000000
8055c750  c7c06c58 01c9e5b6 00000000 00000000
kd> dd 80504734
805047f0
80504734  805a4054 805f02d8 805f3b0e
805f030a
80504744  805f3b48 805f0340 805f3b8c
805f3bd0
80504754  80614adc 8061581e 805eb67a
805eb2d2
80504764  805d430c 805d42bc 80615102
805b593a
80504774  8061471e 805a84de 805aff5e
805d5dd0
80504784  80501c00 80615810 80576900
80538bbc
80504794  8060dd26 805bbeb4 805f4048
80622c18
805047a4  805f853a 805a4742 80622e6c
805a3ff4
805047b4  80544e5c 80640e5a 805bdd68
8060dd76
805047c4  80616094 80578e5e 805776f0
805d4d94
805047d4  805d4acc 820ffbe0 80578f6c
8061648c
805047e4  80578e98 805ab414 805a4b10 820ff0e0
可以看到,[0x805047f0]已经被更改为0x820ff0e0,即NtCreateProcess操作被Hook了。
这就是SSDT
Hook,而且也可以从IceSword中得到肯定的答案。


【图
IceSword】IceSword检测到NtCreateProcess被Hook
四:SSDT访问
也许你现在已经迫不及待的想要操控一下SSDT,好消息是,ntolkrnl.exe导出了一个指针(符号为
KeServiceDescriptorTable)指向其主服务描述符表(Main
SDT),从处于内核模式的模块中访问主服务描述符表是非常容易,你只需要两个C指令,首先是由extern关键字修饰的变量说明,这告诉链接器该变量并
不包含在此模块中,而且不需要在链接时解析相应的符号名称,当该模块被加载到进程的地址空间后,针对该符号的引用才会动态连接到相应的模块中:
// Import SDT pointer
extern PSERVICE_DESCRIPTOR_TABLE
KeServiceDescriptorTable;
其次是创建一个对KeServiceDescriptorTable的引用:
// Create
SDT reference
PSERVICE_DESCRIPTOR_TABLE psdt =
KeServiceDescriptorTable;
现在,你的内核模块就可以访问SSDT数据了。
到此为止,不再深入,因为文章和文章的作者都是入门级的,至于后续SSDT
Hook之类的话题,你就自己玩吧。【4】

五:附录

对SSDT也只是有个初步了解,得益于一些参考资料:
【1】本文关于SSDT的描述,基本源于>一书的第二章,所以针对的是Windows 2000系统,其中文翻译参见
【Undocumented
Windows 2000 Secrets 中文翻译】http://blog.csdn.net/Kendiv/category/88780.aspx
【2】内核调试工具安装包和符号文件安装包,参见
【Debugging Tools for Windows】http://www.microsoft.com/whdc/DevTools/Debugging/default.mspx
【3】搭建Windbg和VMware的内核调试环境,参见
【使用WinDbg和VMware调试NDIS中间层驱动程序】http://www.cppblog.com/aurain/archive/2009/01/04/71138.html
【4】关于SSDT
Hook的文章比较多,>是其中一篇,比较容易理解,参见
【简单说说SSDT】http://icylife.net/yunshu/show.php?id=435

280

主题

203

回帖

0

精华

版主

积分
1808
发表于 2010-8-26 16:54:00 | 显示全部楼层
膜拜
顶贴
拿分
走人
您需要登录后才可以回帖 登录 | 加入我们

本版积分规则

快速回复 返回顶部 返回列表