WINDOWS 64位SSDT定位思路

在32位Windows中我们有很多定位SSDT的方法,最直接的就是利用导出符号来找到SSDT。再有就是通过在nt!KeAddSystemServiceTable函数中进行反汇编搜索。可是在64位WINDOWS中这两种方法都行不通。在64位Windows中不在导出SSDT了,同时nt!KeAddSystemServiceTable中也不再出SSDT了(此处说明有误,应该为不出现直接的SSDT地址了,个人水平有限感觉计算太麻烦。)。这样要HOOK SSDT表就出现了第一个问题如何找到它?我想了三种思路。
思路1:
对每种版本的系统确定一个ntoskrnl到SSDT的硬编码偏移。呵呵,这种方法可能比较傻但最简单直接有效。就是维护起来比较非常麻烦,要对每一个版本进单独处理,如果不同补丁版本有变化也要处理。
思路2:
64位WINDOWS中存放着每个服务例程的入口偏移(这个偏移是相对于SSDT的开始地址的)。我取一个一般不被HOOK的服务例程入口偏移,然后从ntoskrnl的开始地址一直搜索到结束来查找这四个字节,然后根据服务例程的索引定位到SSDT的开始位置。可能对不同版本的操作系统其偏移和索引是不同的需要分别进行处理,但是相比第一种思路要通用一些。
思路3:
还是利用反汇编的方法,但是nt!KeAddSystemServiceTable函数中已经找不到直接的SSDT地址了。后来我想能不能映像搜索到SSDT的地址。
kd> dq nt!KeServiceDescriptorTable
fffff800`03eab840  fffff800`03c75b00 00000000`00000000
fffff800`03eab850  00000000`00000191 fffff800`03c7678c
fffff800`03eab860  00000000`00000000 00000000`00000000
fffff800`03eab870  00000000`00000000 00000000`00000000
fffff800`03eab880  fffff800`03c75b00 00000000`00000000
fffff800`03eab890  00000000`00000191 fffff800`03c7678c
fffff800`03eab8a0  fffff960`00111c00 00000000`00000000
fffff800`03eab8b0  00000000`0000033b fffff960`0011391c
kd> lm m nt
start             end                 module name
fffff800`03c03000 fffff800`041e0000   nt         (pdb symbols)
kd> s -q fffff800`03c03000 l600000 fffff800`03eab840
很不幸我没有找到任何相关的信息。呵呵,但是我贼心不是死,相信肯定在某处会有引用的。于是我搜索了一下所有名称中含有Service单词的符号。
kd> x nt!Ki*Service*
fffff800`03c73e40 nt!KiServiceInternal = <no type information>
fffff800`03c7415b nt!KiSystemServiceExit = <no type information>
fffff800`03c73fde nt!KiSystemServiceStart = <no type information>
fffff800`03c76788 nt!KiServiceLimit = <no type information>
fffff800`03c73b00 nt!KiDebugServiceTrap = <no type information>
fffff800`03c74140 nt!KiSystemServiceCopyEnd = <no type information>
fffff800`03c75b00 nt!KiServiceTable = <no type information>
fffff800`03c74037 nt!KiSystemServiceGdiTebAccess = <no type information>
fffff800`03c73ff2 nt!KiSystemServiceRepeat = <no type information>
fffff800`03c740d0 nt!KiSystemServiceCopyStart = <no type information>
fffff800`03c706f0 nt!KiServiceLinkage = <no type information>
fffff800`03c73d40 nt!KiSystemServiceHandler = <no type information>
终于在nt!KiSystemServiceRepeat 中找到SSDT的信息。
nt!KiSystemServiceRepeat:
fffff800`03c73ff2 4c8d1547782300  lea     r10,[nt!KeServiceDescriptorTable (fffff800`03eab840)]
fffff800`03c73ff9 4c8d1d80782300  lea     r11,[nt!KeServiceDescriptorTableShadow (fffff800`03eab880)]
fffff800`03c74000 f7830001000080000000 test dword ptr [rbx+100h],80h
fffff800`03c7400a 4d0f45d3        cmovne  r10,r11
fffff800`03c7400e 423b441710      cmp     eax,dword ptr [rdi+r10+10h]
fffff800`03c74013 0f83e9020000    jae     nt!KiSystemServiceExit+0x1a7 (fffff800`03c74302)
fffff800`03c74019 4e8b1417        mov     r10,qword ptr [rdi+r10]
fffff800`03c7401d 4d631c82        movsxd  r11,dword ptr [r10+rax*4]
但是一个新的问题也同时产生了,nt!KiSystemServiceRepeat并不是系统的一个导出函数。那我怎么找到它呢?后来一想虽然它不导出但应该至少存在一条从外部到它的一个调用路径吧!那我就通过这条路径找到它不就行了。想到此就对它下了个断点看看都是谁会调用它。结果和我想的一样,不过发现我真是一个菜鸟,找到SSDT值太高兴竟没有仔细看它的汇编代码。nt!KiSystemServiceRepeat就是完成根据调用号从SSDT中获得服务例程入口并调用的。那就说每一个ZwXXX类的函数都会调用到它,而Zw类的函数是系统导出的这样我们可以通过任何一个Zw类的函数来找到nt!KiSystemServiceRepeat从而定位到SSDT。于是我手工尝试了一下。下面是尝试的过程。
kd> u nt!ZwClose l20
nt!ZwClose:
fffff800`03c6d640 488bc4          mov     rax,rsp
fffff800`03c6d643 fa              cli
fffff800`03c6d644 4883ec10        sub     rsp,10h
fffff800`03c6d648 50              push    rax
fffff800`03c6d649 9c              pushfq
fffff800`03c6d64a 6a10            push    10h
fffff800`03c6d64c 488d059d300000  lea     rax,[nt!KiServiceLinkage (fffff800`03c706f0)]
fffff800`03c6d653 50              push    rax
fffff800`03c6d654 b80c000000      mov     eax,0Ch
fffff800`03c6d659 e9e2670000      jmp     nt!KiServiceInternal (fffff800`03c73e40)
fffff800`03c6d65e 6690            xchg    ax,ax
在ZwClose中(其它类似)跳转到了nt!KiServiceInternal 我们再跟踪nt!KiServiceInternal 
nt!KiServiceInternal:
fffff800`03c73e40 4883ec08        sub     rsp,8
fffff800`03c73e44 55              push    rbp
fffff800`03c73e45 4881ec58010000  sub     rsp,158h
fffff800`03c73e4c 488dac2480000000 lea     rbp,[rsp+80h]
fffff800`03c73e54 48899dc0000000  mov     qword ptr [rbp+0C0h],rbx
fffff800`03c73e5b 4889bdc8000000  mov     qword ptr [rbp+0C8h],rdi
fffff800`03c73e62 4889b5d0000000  mov     qword ptr [rbp+0D0h],rsi
fffff800`03c73e69 fb              sti
fffff800`03c73e6a 65488b1c2588010000 mov   rbx,qword ptr gs:[188h]
fffff800`03c73e73 0f0d8bd8010000  prefetchw [rbx+1D8h]
fffff800`03c73e7a 0fb6bbf6010000  movzx   edi,byte ptr [rbx+1F6h]
fffff800`03c73e81 40887da8        mov     byte ptr [rbp-58h],dil
fffff800`03c73e85 c683f601000000  mov     byte ptr [rbx+1F6h],0
fffff800`03c73e8c 4c8b93d8010000  mov     r10,qword ptr [rbx+1D8h]
fffff800`03c73e93 4c8995b8000000  mov     qword ptr [rbp+0B8h],r10
fffff800`03c73e9a 4c8d1d3d010000  lea     r11,[nt!KiSystemServiceStart (fffff800`03c73fde)]
fffff800`03c73ea1 41ffe3          jmp     r11
fffff800`03c73ea4 666666666666660f1f840000000000 nop word ptr [rax+rax]
fffff800`03c73eb3 66666666660f1f840000000000 nop word ptr [rax+rax]

在这个函数中又跳转到了nt!KiSystemServiceStart,这里4c8d1d3d010000 这条指令需要参考一下x64汇编中有关Rex.w前缀及Mod r/m寻址方面的知识来解释这个偏移。在这里就是fffff800`03c73ea1+013d就是nt!KiSystemServiceStart入口地址。接下来再从这个地址开始反汇编。
nt!KiSystemServiceStart:
fffff800`03c73fde 4889a3d8010000  mov     qword ptr [rbx+1D8h],rsp
fffff800`03c73fe5 8bf8            mov     edi,eax
fffff800`03c73fe7 c1ef07          shr     edi,7
fffff800`03c73fea 83e720          and     edi,20h
fffff800`03c73fed 25ff0f0000      and     eax,0FFFh
nt!KiSystemServiceRepeat:
fffff800`03c73ff2 4c8d1547782300  lea     r10,[nt!KeServiceDescriptorTable (fffff800`03eab840)]
fffff800`03c73ff9 4c8d1d80782300  lea     r11,[nt!KeServiceDescriptorTableShadow (fffff800`03eab880)]
fffff800`03c74000 f7830001000080000000 test dword ptr [rbx+100h],80h
fffff800`03c7400a 4d0f45d3        cmovne  r10,r11
fffff800`03c7400e 423b441710      cmp     eax,dword ptr [rdi+r10+10h]
fffff800`03c74013 0f83e9020000    jae     nt!KiSystemServiceExit+0x1a7 (fffff800`03c74302)
fffff800`03c74019 4e8b1417        mov     r10,qword ptr [rdi+r10]
fffff800`03c7401d 4d631c82        movsxd  r11,dword ptr [r10+rax*4]
fffff800`03c74021 498bc3          mov     rax,r11
fffff800`03c74024 49c1fb04        sar     r11,4
fffff800`03c74028 4d03d3          add     r10,r11
fffff800`03c7402b 83ff20          cmp     edi,20h
fffff800`03c7402e 7550            jne     nt!KiSystemServiceGdiTebAccess+0x49 (fffff800`03c74080)
fffff800`03c74030 4c8b9bb8000000  mov     r11,qword ptr [rbx+0B8h]
终于找到我们要找到函数了,4c8d1547782300,4c8d1d80782300根据这两条指令我就可以定位到SSDT的位置了。终于拨云见日了。这两条指令都加了REX.W前缀的根据具体字段的意义解释它就可找到SSDT,4c8d1547782300这条指令的64立即数寻址应该是fffff800`03c73ff9+237847这样来扩展,就是RIP+偏移。相类似4c8d1d80782300指令中的立即数应该被扩展成fffff800`03c74000+237880,通过DQ命令查看就是SSDT的内容。
kd> dq fffff800`03c74000+237880
fffff800`03eab880  fffff800`03c75b00 00000000`00000000
fffff800`03eab890  00000000`00000191 fffff800`03c7678c
fffff800`03eab8a0  fffff960`00111c00 00000000`00000000
fffff800`03eab8b0  00000000`0000033b fffff960`0011391c
fffff800`03eab8c0  00000000`7771fdd6 00000000`00000000
fffff800`03eab8d0  fffff800`00a01400 fffff800`00a013b0
fffff800`03eab8e0  00000000`00000002 00000000`00005bdb
fffff800`03eab8f0  00000000`00023f05 00000000`00000000
kd> dq nt!KeServiceDescriptorTableShadow
fffff800`03eab880  fffff800`03c75b00 00000000`00000000
fffff800`03eab890  00000000`00000191 fffff800`03c7678c
fffff800`03eab8a0  fffff960`00111c00 00000000`00000000
fffff800`03eab8b0  00000000`0000033b fffff960`0011391c
fffff800`03eab8c0  00000000`7771fdd6 00000000`00000000
fffff800`03eab8d0  fffff800`00a01400 fffff800`00a013b0
fffff800`03eab8e0  00000000`00000002 00000000`00005bdb
fffff800`03eab8f0  00000000`00023f05 00000000`00000000
两种方法找到位置一样。我这里的输出都针对WIN7 64位系统的调用,通过对2003进行调试发现这样的方法也适用。因为没有暂时没有其它版本操作系统。在其它操作系统上的适用性怎么样就无从知道了。个人推测XP,VISTA也应该差不多但需要事实证明。不过Win7与2003中SSDT表项内容略有不同,虽然都是四个节最后四位是例程的参数个数,但在2003上偏移的计算是SSDT基址+表项值&0xFFFFFFF0,而win7上则变成了SSDT基址+表项值>>4。如果HOOK表项还是要做一个分别对待。我是第一次发帖,大家轻拍啊。上面阐述如有错误请个位大侠多多指教,小弟不胜感激。

时间: 2024-10-11 03:29:28

WINDOWS 64位SSDT定位思路的相关文章

手把手教你写Windows 64位平台调试器

本文网页排版有些差,已上传了doc,可以下载阅读.本文中的所有代码已打包,下载地址在此. -------------------------------------------------------------------------------------------------------------------------------------------------------------- 手写一个调试器有助于我们理解hook.进程注入等底层黑客技术具体实现,在编写过程中需要涉及大

Windows(64位IIS)未在本地计算机上注册“Microsoft.Jet.OLEDB.4.0”提供程序 解决方法

环境:windows server 2008r2 64位  IIS access 2003 问题:Windows(64位IIS)未在本地计算机上注册“Microsoft.Jet.OLEDB.4.0”提供程序 解决方法:网上找的 在Windows 7(32位)用.Net开发的Excel导入数据表功能,测试后一切正常,站点发布挪到Windows Server 2008(64位)上就意外了,出现错误提示,运行程序,抛出异常:未在本地计算机上注册 Microsoft.Jet.OLEDB.4.0 提供程序

IIS7+windows 64位配置注意事项

问题和解决办法 1  如果网站为Asp:再asp中注意启用父路径 2  操作必须使用一个可更新的查询:给用户iis_iusrs 一个完全控制的权限 3  Windows(64位IIS)未在本地计算机上注册“Microsoft.Jet.OLEDB.4.0”提供程序 :在对应的 IIS 应用程序池中,“设置应用程序池默认属性”/“常规”/”启用32位应用程序”,设置为 true. IIS7.5安装后ASP+access数据库连接错误的问题解决办法     0 推荐 第一步.安装IIS. 开始——控制

Windows 64 位 Matlab R2013a 环境下安装 libsvm

在这种环境下, 安装 libsvm 可以说是傻瓜似的了, 但就我搜出的 libsvm 安装教程来看, 以前的 libsvm 安装起来是有点麻烦的 目前最新版本是 libsvm 3.18, 按照 [1] 的描述, 将 libsvm 的 windows 目录放到 matlab 目录中, 我想博主说的这个目录应该不是 matlab 的当前工作目录, 而是 matlab 的搜索目录. 因为当前工作目录只有一个, 你把它设为 windows, 那么 libsvm 目录下的 heart_scale 数据集就

Windows 64位系统安装Apache2.4

Windows 64位系统安装Apache2.4 来自:百度经验:jingyan.baidu.com 现在大部分一键安装包多是32位的,并不支持64位,直接在64位的系统上使用会报错的,所以我这里就来说说windows 64位系统如何建立Apache+PHP+MySQL环境的! 我这里演示用的windows 2008 64位简体中文版,apache,php,mysql多用的是64位的版本.建立的是本地环境,所以我用的是默认设置. 下载PHP.Apache和Mysql软件以及VC库. 下面分别是P

Windows 64位程序编译及检测

Windows 64位程序编译及检测 1.64位程序编译 采用vs2010可以比较方便的编译出64位的程序. 调整编译配置为x64即可. 配置完成,编译出来的程序即为64位. 2.64位程序检测 检测一个程序是否为64位,可以采用dumpbin工具,这是vs自带的小工具. 步骤如下. 对应命令依次是: 进入vc目录:cd D:\Program Files\Microsoft Visual Studio 10.0\VC 配置vc命令环境:vcvarsall.bat 检测exe是否为64位:dump

Windows 64 位系统下 Python 环境的搭建

Windows 64 位开发环境 注意:本教程适用于 Windows 7 64 位操作系统 及 Windows 10 64 位操作系统,其他系统尚未经过校验. 安装 IDE PyCharm 下载:https://www.jetbrains.com/pycharm/ 安装 Python 环境 Python2.7 下载:https://www.python.org/downloads/ Python2.7 的默认安装目录在 C:/Python27/,安装目录请勿转移到其他盘!有C盘洁癖症的患者请特别

Windows 64位 安装Oracle instantclient 官方绿色版和PL/SQL Developer 总结

原文: http://blog.csdn.net/kimsoft/article/details/8751267 操作系统:Windows 7 64位旗舰 要求,安装PL/SQL Developer用于开发 一.下载Oracle官方精简绿色版 http://www.oracle.com/technetwork/topics/winsoft-085727.html 特别注意,要下载32位的,因为PL/SQL Developer目前只有32位的版本 二.安装配置instantclient 下载后,解

windows 64位系统下 apache+php+mysql

环境搭建 第一步: 64位系统下的 apache.php .mysql软件下载 apache2.4 http://www.apachelounge.com/download/win64/ php5.5 http://windows.php.net/qa/ PHP 5.5 (5.5.17RC1) 就这个版本 mysql http://www.mysql.com/downloads/mysql/ MySQL Community Server 5.6.20 这个是安装版当然你下载zip包的也可以 第二