初探win10 x64 SSDT

  • 0x0 windbg中查看SSDT
    • 背景介绍
    • 查看SSDT
  • 0x1 代码获取SSDT表中的函数
    • 获取SSDT的地址
    • 获取SSDT中函数的地址

0x0 windbg中查看SSDT

背景介绍

学习驱动的过程中,由于涉及到SSDT HOOK相关的知识点,开始学习SSDT,关于SSDT的基本概念,这里省去,中文名是系统服务描述表,具体的理解可自行百度,由于是初步探讨,本篇只介绍方法。

查看SSDT

x64系统下,在windbg中,我们想要找到SSDT还是比较简单(x86更简单)的,如下:

  1. 首先,我们直接可以直接查看到KeServiceDescriptorTable的值是KiServiceTable的指针
0: kd> dqs nt!KeServiceDescriptorTable
fffff804`3fd72880  fffff804`3fc150e0 nt!KiServiceTable
fffff804`3fd72888  00000000`00000000
...
  1. 通过KiServiceTable我们可以看到
0: kd> dds KiServiceTable
fffff804`3fc150e0  fc292704
fffff804`3fc150e4  fc336600
fffff804`3fc150e8  01c80302
fffff804`3fc150ec  0454cc00
fffff804`3fc150f0  02245d00
fffff804`3fc150f4  fdb97a00
fffff804`3fc150f8  01f70f05
fffff804`3fc150fc  01992206
....

3.这里,借用看雪上的前辈的脚本,我们可以看到SSDT中的函数的具体情况,具体脚本请进原帖查看
Win10 X64下SSDT表中的函数地址计算公式

KeServiceDescriptorTable->KiServiceTable:  fffff8043fc150e0
KeServiceDescriptorTable->Count: 463Index Address        Func
--------------------------------[  0] fffff8043f83e350 (nt!NtAccessCheck (fffff804`3f83e350))
[  1] fffff8043f848740 (nt!NtWorkerFactoryWorkerReady (fffff804`3f848740))
[  2] fffff8043fddd110 (nt!NtAcceptConnectPort (fffff804`3fddd110))
[  3] fffff80440069da0 (nt!NtMapUserPhysicalPagesScatter (fffff804`40069da0))
[  4] fffff8043fe396b0 (nt!NtWaitForSingleObject (fffff804`3fe396b0))
[  5] fffff8043f9ce880 (nt!NtCallbackReturn (fffff804`3f9ce880))
[  6] fffff8043fe0c1d0 (nt!NtReadFile (fffff804`3fe0c1d0))
[  7] fffff8043fdae300 (nt!NtDeviceIoControlFile (fffff804`3fdae300))
[  8] fffff8043fe0b440 (nt!NtWriteFile (fffff804`3fe0b440))
[  9] fffff8043fdadda0 (nt!NtRemoveIoCompletion (fffff804`3fdadda0))
[ 10] fffff8043fe17410 (nt!NtReleaseSemaphore (fffff804`3fe17410))
[ 11] fffff8043fe5aaf0 (nt!NtReplyWaitReceivePort (fffff804`3fe5aaf0))
...
  1. 用工具查看下结果是一致的

    至此,我们顺利得到了SSDT表中函数的具体情况。

0x1 代码获取SSDT表中的函数

获取SSDT的地址

我们使用代码获取SSDT中函数地址的思路是:
SYSCALL->SSDT->SSDTFunc
为此在获取SSDT的地址前,我们需要做一点知识铺垫。
在知乎的一篇名为深入分析微软新引入的内核虚拟地址影子(KVAS)特性的文章里我们看到下面的内容:

IA32_STAR(0xC0000081):Ring 0和Ring 3段基址,以及SYSCALL的EIP。在较低的32位中存储的是SYSCALL的EIP,在第32-47位存储内核段基址,在第48-63为存储用户段基址。
IA32_CSTAR(0xC0000083):兼容模式下,SYSCALL的内核RIP相对寻址。
IA32_LSTAR(0xC0000082):长模式(Long Mode,即64位)下,SYSCALL的内核RIP相对寻址。

其中,我们看到了放在MSR寄存器上的64系统的SYSCALL,通过该寄存器,我们可以定位SYSCALL的地址,通过该地址,我们可以缩小我们需要搜索的内存范围,然后,我们在内存中查找到SSDT的特征码,只要找到特征码,我们就可以计算出SSDT的地址了。
然而,与网上其他相关文章不同的是,通过C0000082 MSR寄存器,我所得到的地址并非是nt!KiSystemCall64,而是nt!KiSystemCall64Shadow。
因此,我的权宜之计是读取地址后取一个偏移量将开始进行特征码搜索的位置重新定位到合理的位置,再在其中进行搜索,当然,这显然不是一个有效的方式,待后续解决。
获取SSDT地址的代码如下

ULONGLONG GetKeServiceDescriptorTable()
{PUCHAR StartSearchAddress = (PUCHAR)__readmsr(0xC0000082)- 0x16A000;//0x16A000是取的一个偏移量PUCHAR EndSearchAddress = StartSearchAddress + 0x500;//通常搜索范围在500字节就够了PUCHAR i = NULL;UCHAR a = 0, b = 0, c = 0;//a,b,c用来存储特征字节ULONG Temp = 0;ULONGLONG addr = 0;for (i = StartSearchAddress; i < EndSearchAddress; i++){//使用MmIsAddressValid()函数检查地址是否有页面错误,但是微软并不建议使用此函数if(MmIsAddressValid(i) && MmIsAddressValid(i+1) && MmIsAddressValid(i+2)){a = *i;b = *(i + 1);c = *(i + 2);//对比特征值//fffff804`2f678184 4c8d15f5663900  lea     r10,[nt!KeServiceDescriptorTable (fffff804`2fa0e880)]//fffff804`2f67818b 4c8d1deee73700  lea     r11, [nt!KeServiceDescriptorTableShadow(fffff804`2f9f6980)]if (a == 0x4c && b == 0x8d && c == 0x15){memcpy(&Temp, i + 3, 4);addr = (ULONGLONG)Temp + (ULONGLONG)i + 7;KdPrint(("addr为:%p", addr));return addr;}}}return  0;
}

获取SSDT中函数的地址

我们找到由SSDT获取表中相关函数的关键汇编代码如下:

fffff802`627e0139 4d8b143a        mov     r10, qword ptr[r10 + rdi]
fffff802`627e013d 4d631c82        movsxd  r11, dword ptr[r10 + rax * 4]
fffff802`627e0141 498bc3          mov     rax, r11
fffff802`627e0144 49c1fb04        sar     r11, 4
fffff802`627e0148 4d03d3          add     r10, r11
fffff802`627e014b 83ff20          cmp     edi, 20h
fffff802`627e014e 7550            jne     nt!KiSystemServiceGdiTebAccess + 0x49 (fffff802`627e01a0)
fffff802`627e0150 4c8b9bf0000000  mov     r11, qword ptr[rbx + 0F0h]

其中rax*4中的rax是索引号,将上述汇编代码翻译成C语言代码大致如下:

ServiceTableBase = KeServiceDescriptorTable->ServiceTableBase
dwoffset = ServiceTableBase[index]
if (dwoffset & 0x80000000) //判断最高位是否为1
{//如果最高位为1,则右移后最高位需要补1,补1后最高位再次是1,再次右移后最高位依然需要补1。//由于是右移四位,故需要补四次二进制的1,0y1111即为0XF,故最高位补Fdwoffset = (dwoffset >> 4) | 0xF0000000;
}
else
{dwoffset = dwoffset >> 4;
}
FuncCurAddr = dwoffset + ServiceTableBase;

这里需要注意的,sar是算数右移,如果操作数最高位为1,右移后最高位也是需要补1的,最开始误把sar当成逻辑右移,从而导致计算的结果总比使用工具得到的结果多0x10000000,当时百思不得其解,后来看到sar后终于豁然开朗。
至此,我们用代码亦可以实现获取SSDT表中函数的地址,效果图如下:

由于学习SSDT相关知识才一两天的时间,故许多认识会多有不足之处,欢迎大家谈论指正,相信随着学习的深入,肯定会有更深的理解。
To be continue…

初探win10 x64 SSDT(驱动学习笔记五)相关推荐

  1. 转载:mongoDB java驱动学习笔记

    http://www.blogjava.net/watchzerg/archive/2012/09/22/388346.html mongoDB java驱动学习笔记 指定新mongo实例: Mong ...

  2. 华清远见fs4412开发板学习笔记(五)

    fs4412开发板学习笔记(五) 作业1: 输入10个整数,按从小到大的顺序输出(选择排序) 每轮排序在未排序的集合中找到(最小/最大),将找到的数与未排序的 第一个数交换位置. 5 4 3 2 1 ...

  3. python函数是一段具有特定功能的语句组_Python学习笔记(五)函数和代码复用

    本文将为您描述Python学习笔记(五)函数和代码复用,具体完成步骤: 函数能提高应用的模块性,和代码的重复利用率.在很多高级语言中,都可以使用函数实现多种功能.在之前的学习中,相信你已经知道Pyth ...

  4. Ethernet/IP 学习笔记五

    Ethernet/IP 学习笔记五 Accessing data within a device using a non-time critical message (an explicit mess ...

  5. StackExchange.Redis学习笔记(五) 发布和订阅

    StackExchange.Redis学习笔记(五) 发布和订阅 原文:StackExchange.Redis学习笔记(五) 发布和订阅 Redis命令中的Pub/Sub Redis在 2.0之后的版 ...

  6. 吴恩达《机器学习》学习笔记五——逻辑回归

    吴恩达<机器学习>学习笔记五--逻辑回归 一. 分类(classification) 1.定义 2.阈值 二. 逻辑(logistic)回归假设函数 1.假设的表达式 2.假设表达式的意义 ...

  7. 好程序员教程分析Vue学习笔记五

    好程序员教程分析Vue学习笔记五,上次我们学习了Vue的组件,这次我们来学习一下路由的使用.在Vue中,所谓的路由其实跟其他的框架中的路由的概念差不多,即指跳转的路径. 注意:在Vue中,要使用路由, ...

  8. 【AngularJs学习笔记五】AngularJS从构建项目开始

    为什么80%的码农都做不了架构师?>>>    #0 系列目录# AngularJs学习笔记 [AngularJs学习笔记一]Bower解决js的依赖管理 [AngularJs学习笔 ...

  9. ROS学习笔记五:理解ROS topics

    ROS学习笔记五:理解ROS topics 本节主要介绍ROS topics并且使用rostopic和rqt_plot命令行工具. 例子展示 roscore 首先运行roscore系列服务,这是使用R ...

最新文章

  1. Mac下安装Node.js
  2. 贫困地区农品产销对接行动倡议书-中国农民丰收节交易会
  3. apple MacBook air m1是我认为最非常适合学生的笔记本
  4. C指针原理(6)-C内嵌汇编
  5. SSh结合Easyui实现Datagrid的分页显示
  6. 本地php后台密码恢复默认,找回wordpress后台管理密码的PHP脚本方法
  7. java poi 解析excel_Java用POI解析excel并获取所有单元格数据
  8. 安卓开发环境_我的安卓开发环境
  9. Tomcat(四):发布和优化
  10. 树莓派教程 - 2.2 树莓派CSI摄像头,raspivid、raspistill常用参数
  11. 安装oracle11g未找到文件WFMLRSVCApp.ear文件
  12. jqgrid点击搜索无法重置参数问题
  13. linux之tcpdump抓包工具
  14. opencv 二值化图像 像素统计 countNonZero
  15. Android 自定义带文字图片的view,宝马上线娱乐亚洲第一-宝马上线娱乐亚洲第一...
  16. Windows下使用Git+rsync构建文件同步工具
  17. 巴蜀1471 魔兽争霸
  18. 以太网交换机的工作原理
  19. 中科院毕业去向(硕士+博士)
  20. VJ第一周算法题(A - Mud Puddles)

热门文章

  1. post的请求body是json类型
  2. 《人人都是产品经理》内容归纳
  3. 夜幕神话TelesLi
  4. 【总结】PPT如何写的更美观
  5. 为什么App安装要做个性化
  6. Python对某视频弹幕进行爬取,完成文本数据分析
  7. 3ds Max人物女性角色模型建模教程
  8. 【Python】网络爬虫(一):pyquery一瞥
  9. win10运行cassandra-3.11.9报Problematic frame: sigar-amd64-winnt.dll+0x14ed4
  10. 记录有关达梦dm数据库中需要根据中文拼音进行排序问题