驱动开发:内核读取SSDT表基址
在前面的章节《X86驱动:挂接SSDT内核钩子》
我们通过代码的方式直接读取 KeServiceDescriptorTable
这个被导出的表结构从而可以直接读取到SSDT表的基址,而在Win64系统中 KeServiceDescriptorTable
这个表并没有被导出,所以我们必须手动搜索到它的地址。
为了确保系统的安全性与稳定性,微软从 Windows Vista X64 开始对系统内核增加了一定的限制,其主要增加了两种保护措施,一是KPP (内核补丁保护),KPP是机制其利用了PG(PatchGuard)技术,PG技术在x64系统下加入了内核哨兵,用于检测系统内核是否被恶意篡改(打补丁),如果发现被打了补丁,则会导致关键结构损毁直接蓝屏,二是DSE (驱动强制签名),DSE技术则是拒绝加载不包含正确签名的驱动。
1.这里我们可以通过MSR(特别模块寄存器),读取C0000082寄存器,从而得到KiSystemCall64的地址,在内核调试模式下直接输入 rdmsr c0000082
即可读取到该地址,反汇编可看到 nt!KiSystemCall64
函数。
kd> rdmsr c0000082 msr[c0000082] = fffff800`03c72ec0 kd> u fffff800`03c72ec0 nt!KiSystemCall64: fffff800`03c72ec0 0f01f8 swapgs fffff800`03c72ec3 654889242510000000 mov qword ptr gs:[10h],rsp fffff800`03c72ecc 65488b2425a8010000 mov rsp,qword ptr gs:[1A8h] fffff800`03c72ed5 6a2b push 2Bh fffff800`03c72ed7 65ff342510000000 push qword ptr gs:[10h] fffff800`03c72edf 4153 push r11 fffff800`03c72ee1 6a33 push 33h fffff800`03c72ee3 51 push rcx
2.接着我们从 KiSystemCall64
函数地址开始向下反汇编,可以看到最后 nt!KiSystemServiceRepeat
这个函数里面包含了 nt!KeServiceDescriptorTable (fffff80003eaa840)
,通过 03c72ff2 减去03c72ec0 即可得到SDT表结构与KiSystemCall64函数之间的偏移值 132 (306)
kd> uf KiSystemCall64 Flow analysis was incomplete, some code may be missing nt!KiSystemCall64: fffff800`03c72ec0 0f01f8 swapgs fffff800`03c72ec3 654889242510000000 mov qword ptr gs:[10h],rsp fffff800`03c72ecc 65488b2425a8010000 mov rsp,qword ptr gs:[1A8h] fffff800`03c72ed5 6a2b push 2Bh fffff800`03c72ed7 65ff342510000000 push qword ptr gs:[10h] fffff800`03c72edf 4153 push r11 fffff800`03c72ee1 6a33 push 33h fffff800`03c72ee3 51 push rcx fffff800`03c72ee4 498bca mov rcx,r10 nt!KiSystemServiceRepeat: fffff800`03c72ff2 4c8d1547782300 lea r10,[nt!KeServiceDescriptorTable (fffff800`03eaa840)] fffff800`03c72ff9 4c8d1d80782300 lea r11,[nt!KeServiceDescriptorTableShadow (fffff800`03eaa880)] fffff800`03c73000 f7830001000080000000 test dword ptr [rbx+100h],80h fffff800`03c7300a 4d0f45d3 cmovne r10,r11 fffff800`03c7300e 423b441710 cmp eax,dword ptr [rdi+r10+10h] fffff800`03c73013 0f83e9020000 jae nt!KiSystemServiceExit+0x1a7 (fffff800`03c73302) Branch
总结一下:我们通过读取C0000082寄存器,能够得到KiSystemCall64的地址,然后从KiSystemCall64的地址开始,往下搜索0x150字节左右(特征码4c8d15),就能得到KeServiceDescriptorTable的地址。
#include <ntddk.h> #include <windef.h> #include <intrin.h> #pragma intrinsic(__readmsr) VOID UnDriver(PDRIVER_OBJECT driver) { DbgPrint(("驱动程序卸载成功! \n")); } ULONGLONG Get_SSTD_Base() { PUCHAR Base = (PUCHAR)__readmsr(0xC0000082); // 读取C0000082寄存器 PUCHAR Address = Base + 0x150; // 相加偏移 PUCHAR i = NULL; UCHAR b1 = 0, b2 = 0, b3 = 0; // 保存特征码 ULONG templong = 0; ULONGLONG addr = 0; // 最后获取到的地址 for (i = Base; i<Address; i++) { if (MmIsAddressValid(i) && MmIsAddressValid(i + 1) && MmIsAddressValid(i + 2)) { b1 = *i; b2 = *(i + 1); b3 = *(i + 2); if (b1 == 0x4c && b2 == 0x8d && b3 == 0x15) // 判断是否=4c8d15 { memcpy(&templong, i + 3, 4); // 在i+3位置拷贝,拷贝4字节 addr = (ULONGLONG)templong + (ULONGLONG)i + 7; return addr; } } } return 0; } NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { DbgPrint("SSTD Base= %11x", Get_SSTD_Base()); DriverObject->DriverUnload = UnDriver; return STATUS_SUCCESS; }
3.接着我们则需要获取到SSDT中某个函数的序号,这里以OpenProcess
为例:
0:000> u ntdll!NtOpenProcess ntdll!NtOpenProcess: 77820700 b826000000 mov eax,23h 77820705 bac04f8377 mov edx,offset ntdll!Wow64SystemServiceCall (77834fc0) 7782070a ffd2 call edx 7782070c c21000 ret 10h 7782070f 90 nop
4.读取代码如下.
#include <ntddk.h> #include <windef.h> #include <intrin.h> #pragma intrinsic(__readmsr) VOID UnDriver(PDRIVER_OBJECT driver) { DbgPrint(("驱动程序卸载成功! \n")); } ULONGLONG Get_SSDT_Base() { PUCHAR Base = (PUCHAR)__readmsr(0xC0000082); // 读取C0000082寄存器 PUCHAR Address = Base + 0x150; // 相加偏移 PUCHAR i = NULL; UCHAR b1 = 0, b2 = 0, b3 = 0; // 保存特征码 ULONG templong = 0; ULONGLONG addr = 0; // 最后获取到的地址 for (i = Base; i<Address; i++) { if (MmIsAddressValid(i) && MmIsAddressValid(i + 1) && MmIsAddressValid(i + 2)) { b1 = *i; b2 = *(i + 1); b3 = *(i + 2); if (b1 == 0x4c && b2 == 0x8d && b3 == 0x15) // 判断是否=4c8d15 { memcpy(&templong, i + 3, 4); // 在i+3位置拷贝,拷贝4字节 addr = (ULONGLONG)templong + (ULONGLONG)i + 7; return addr; } } } return 0; } typedef struct _SYSTEM_SERVICE_TABLE{ PVOID ServiceTableBase; PVOID ServiceCounterTableBase; ULONGLONG NumberOfServices; PVOID ParamTableBase; } SYSTEM_SERVICE_TABLE, *PSYSTEM_SERVICE_TABLE; ULONGLONG GetSSDTFunction(ULONGLONG Index) { LONG dwTemp = 0; ULONGLONG qwTemp = 0, stb = 0, ret = 0; PSYSTEM_SERVICE_TABLE ssdt = (PSYSTEM_SERVICE_TABLE)Get_SSDT_Base(); stb = (ULONGLONG)(ssdt->ServiceTableBase); qwTemp = stb + 4 * Index; dwTemp = *(PLONG)qwTemp; dwTemp = dwTemp >> 4; ret = stb + (LONG64)dwTemp; return ret; } NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { DbgPrint("OpenProcess=%llx", GetSSDTFunction(0x23)); DriverObject->DriverUnload = UnDriver; return STATUS_SUCCESS; }
在64位环境下想要任意Hook系统函数是不可能的,因为64位中每个驱动程序都不在同一个4GB空间里,而4字节的整数只能表示4GB的范围,所以无论你怎么改,都不可能跨越这个内存空间,而微软也不希望你挂钩内核的一些函数,如果非要使用的话,微软提供了一些回调函数可以实现相应的挂钩效果。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
好未来基于北极星的注册中心最佳实践
业务背景 好未来是一家以智慧教育和开放平台为主体,在全球范围内服务公办教育,助力民办教育,探索未来教育新模式的科技教育公司,旗下拥有学而思素养、学而思网校等品牌。作为国家新一代人工智能开放创新平台在教育行业的代表,好未来深耕教育场景,目前已积累15大类共计170余种AI能力,覆盖视觉、语音、自然语言处理等多个方向,引领教育+AI发展的同时,助力中小行业伙伴的成长,推动教育新生态建设。 2021年好未来 AI 中台业务规模激增,日调用量超6亿,总调用量上千亿。相比2020年增长约9倍,并持续呈现增长趋势。业务规模井喷式增长,给平台带来的稳定性技术挑战也越发强烈,好未来AI中台的现有架构,无论是业务支撑还是架构设计,均存在一定的风险和隐患。 痛点分析与解决方案 好未来采用SpringCloud全家桶和Kubernetes构建云原生的 AI 中台。整体采用单集群部署。这种部署架构随着业务规模的激增,带来资源和性能瓶颈,如 VPC 中的 IP 资源、Node节点、apiserver性能等问题进而影响现网业务。另一方面,也带来集群层面的单点问题,如:完全依赖某一家云厂商、没有灾备集群、升级困难等...
- 下一篇
驱动开发:内核封装TDI网络通信接口
在上一篇文章《驱动开发:内核封装WSK网络通信接口》中,LyShark已经带大家看过了如何通过WSK接口实现套接字通信,但WSK实现的通信是内核与内核模块之间的,而如果需要内核与应用层之间通信则使用TDK会更好一些因为它更接近应用层,本章将使用TDK实现,TDI全称传输驱动接口,其主要负责连接Socket和协议驱动,用于实现访问传输层的功能,该接口比NDIS更接近于应用层,在早期Win系统中常用于实现过滤防火墙,同样经过封装后也可实现通信功能,本章将运用TDI接口实现驱动与应用层之间传输字符串,结构体,多线程收发等技术。 TDI传输字符串 TDI多线程收发 TDI传数结构实现认证 TDI 传输字符串: 服务端在应用层侦听,客户端是驱动程序,驱动程序加载后自动连接应用层并发送消息。 首先来看应用层(服务端)代码,具体我就不说了,来看教程的都是有基础的。 // 署名权 // right to sign one's name on a piece of work // PowerBy: LyShark // Email: me@lyshark.com #define _CRT_SECURE_...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS8编译安装MySQL8.0.19
- CentOS6,CentOS7官方镜像安装Oracle11G
- CentOS7,8上快速安装Gitea,搭建Git服务器
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- MySQL8.0.19开启GTID主从同步CentOS8
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Red5直播服务器,属于Java语言的直播服务器
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7