前面的驱动编程相关内容都是在32位环境下进行的,驱动程序与应用程序不同,32位的驱动只能运行在32位系统中,64位驱动只能在64位系统中运行,在WIN32环境下,我们可以各种Hook挂钩各种系统函数,而恶意程序也可以通过加载驱动进行内核层面的破坏(Rootkit),大家都可以乱搞,把好端端的Windows系统搞得乱七八糟,严重影响了系统安全性与可靠性。

为了确保系统的安全性与稳定性,微软从 Windows Vista X64 开始对系统内核增加了一定的限制,其主要增加了两种保护措施,一是KPP (内核补丁保护),KPP是机制其利用了PG(PatchGuard)技术,PG技术在x64系统下加入了内核哨兵,用于检测系统内核是否被恶意篡改(打补丁),如果发现被打了补丁,则会导致关键结构损毁直接蓝屏,二是DSE (驱动强制签名),DSE技术则是拒绝加载不包含正确签名的驱动。

在前面的章节《X86驱动:挂接SSDT内核钩子》我们通过代码的方式直接读取 KeServiceDescriptorTable 这个被导出的表结构从而可以直接读取到SSDT表的基址,而在Win64系统中 KeServiceDescriptorTable 这个表并没有被导出,所以我们必须手动搜索到它的地址。

1.这里我们可以通过MSR(特别模块寄存器),读取C0000082寄存器,从而得到KiSystemCall64的地址,在内核调试模式下直接输入 rdmsr c0000082 即可读取到该地址,反汇编可看到 nt!KiSystemCall64 函数。

kd> rdmsr c0000082
msr[c0000082] = fffff800`03c72ec0kd> 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,r10nt!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的范围,所以无论你怎么改,都不可能跨越这个内存空间,而微软也不希望你挂钩内核的一些函数,如果非要使用的话,微软提供了一些回调函数可以实现相应的挂钩效果。

X64驱动:读取SSDT表基址相关推荐

  1. 驱动开发:内核读取SSDT表基址

    在前面的章节<X86驱动:挂接SSDT内核钩子>我们通过代码的方式直接读取 KeServiceDescriptorTable 这个被导出的表结构从而可以直接读取到SSDT表的基址,而在Wi ...

  2. 读取SSDT表和原函数地址

    读取当前地址代码(NtOpenProcess):  LONG *SSDT_Adr,t_addr,adr;  t_addr=(LONG)KeServiceDescriptorTable->Serv ...

  3. 驱动开发:如何枚举所有SSDT表地址

    在前面的博文<驱动开发:Win10内核枚举SSDT表基址>中已经教大家如何寻找SSDT表基地址了,找到后我们可根据序号获取到指定SSDT函数的原始地址,而如果需要输出所有SSDT表信息,则 ...

  4. Win7 64位的SSDTHOOK(1)---SSDT表的寻找

    最近在学习64位驱动,涉及到了SSDT的知识,结果发现64位下的SSDT和32位下的SSDT有所不同. 开始发现64位下的KeServiceDescriptorTable是未导出的函数.首先要找到Ke ...

  5. SSDT表的遍历(源码)

    //VS2005创建的工程,系统xp sp2 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ...

  6. Windows保护模式学习笔记(八)—— 页目录表基址/页表基址

    Windows保护模式学习笔记(八)-- 页目录表基址/页表基址 要点回顾 一.页目录表基址 实验:拆分线性地址C0300000,并查看其对应的物理页 第一步:打开一个进程,获得它的Cr3 第二步:查 ...

  7. 驱动层SSDT 隐藏进程

    闲着没事,便想在熟悉下之前看过的驱动编程相关知识,于是就写了这个简单的驱动曾隐藏进程程序. 要点:  在驱动层隐藏,主要还是使用SSDT挂钩的方法,相关知识,可以到网上查找,在隐藏进程时,为了能够隐藏 ...

  8. x86下windbg查看SSDT表与SHDOWSSDT

    x64下这两个表是未导出的,不能用这种 首先系统符号要加载 SSDT表: x nt!kes*des*table* kd> x nt!KeServiceDes* 83f74a00 nt!KeSer ...

  9. X64驱动开发和保护+X86X64游戏逆向分析课程

    老师教学范围和方式:木塔负责PC电脑端C语言基础和端游逆向分析部分内容,采用录制+部分直播课程教学,晚上还有专业老师讲解和指导.我要的是质量不是数量.老师备课,设计课件需要时间的. 学习周期:PC端3 ...

最新文章

  1. eclipse 3.55安装j2ee开发工具
  2. jQuery——获取当前索引值
  3. 【Android 安全】DEX 加密 ( Application 替换 | 分析 ContentProvider 组件中调用 getApplication() 获取的 Application 二 )
  4. C语言 二进制文件读取和写入
  5. python中全局变量和局部变量详解_Python全局变量与局部变量详解
  6. HTML5 CSS3的新交互特性
  7. C++的extern关键字
  8. pdm vault 使用_如何使用Key Vault连接器更好地保护Logic Apps中的秘密
  9. jquery.form.js实现将form提交转为ajax方式提交的使用方法
  10. Oauth支持的5类 grant_type 及说明 authorization_code — 授权码模式(即先登录获取code,再获取token) password — 密码模式(将用户名,密码传
  11. 计算机服务器可以开游戏吗,想买台小服务器做个人电脑,玩游戏可以吗
  12. 从零开始搭建Vue开发环境(windows)
  13. 嘻哈帝国第一季/全集Empire迅雷下载
  14. DNS被劫持如何处理?
  15. IE浏览器确定兼容性模式
  16. GSM Foxit Reader
  17. 百度新闻向左 Google新闻向右【新媒体】
  18. 手游(cocos2dx)图片资源压缩
  19. 高中计算机试题一,高中计算机考试试题集(一)
  20. JAVA设计模式什么鬼(观察者)——作者:凸凹里歐

热门文章

  1. 【论文翻译】卷积神经网络研究综述
  2. 项目经理论坛_做好项目经理,应该向华为学习
  3. 基于BIM(Revit平台)的铝合金模板设计软件的研发
  4. UI设计教程,教你用PS软件绘制个性的开始图标
  5. Python实现十进制数与二进制补码转换
  6. 启动页上点击广告跳转,退出广告页后返回继续启动的实现方法
  7. TCP/UDP协议首部格式
  8. JVM SandBox源码解析(一):启动时初始化、启动时加载模块、ModuleHttpServlet进行Http路由
  9. [导入]《没卵头家》[DVD转RMVB中字][ 台湾经典剧情片]
  10. 第十一届 “中国软件杯”百度遥感赛项:遥感变化检测预选赛0.87方案