x64技术之SSDT_Hook

测试环境:

虚拟机: Windows 7 64bit

过PG工具

驱动加载工具

PCHunter64

系统自带的计算器和任务管理器等

实现思路:

实际思路与win32的思路一样.都是替换SSDT表里边的函数地址.不过微软被搞怕了,所以在x64上做了一些手脚.

具体手脚就是x64通过SSDT得到的函数地址,不是真实的函数绝对地址了,而是加密了的.

HOOK

1.得到系统服务表基址

2.保存需要Hook的函数地址(实际为偏移)

3.使内存可写,把表中要Hook的地址替换成KeBugCheckEx的地址,还原内存属性

4.HookKeBugCheckEx函数,在其开始处jmp到我们自己的函数地址.

5.自己实现Hook的函数,在其中做处理.

注:

简单说一下,win10x64th2及之前的版本,原始地址的保存方式是八字节的,每个地址是需要重定向的绝对地址,但从win10x64rs1开始,原始地址保存方式是四字节的,每个地址是不需要重定向的相对地址。
简单说公式就是
original_address=image_base+address_read_from_file
其中original_address和image_base是八字节整形,address_read_from_file是四字节整形
之前的公式是:
original_address=image_base+(address_read_from_file-file_image_base)
这四个变量都是八字节整形,括号内计算的是重定向

Tesla.Angela 则给出了新的计算公式

VA = KiServiceTable - NtosBase + ReloadedNtosBase;
OriAddr = getdword(VA+Index*4) + NtosBase;

x64要Hook的函数地址是 ServiceTableBase[Index]>>4 + ServiceTableBase

此处Hook了NtOpenProcess,导出序号是35号.处理了结束计算器进程的时候,禁止结束.

还原Hook的时候不需要还原KeBugCheckEx,因为这个函数就是崩溃蓝屏需要执行的函数.

这篇文章不会讲述过PG.

关键代码:

获取服务表基址

 
  1. //获取服务表基址

  2. ULONGLONG GetKeServiceDescriptorTable64()

  3. {

  4. PUCHAR StartSearchAddress = (PUCHAR)__readmsr(0xC0000082);

  5. PUCHAR EndSearchAddress = StartSearchAddress + 0x500;

  6. PUCHAR i = NULL;

  7. UCHAR byte1 = 0, byte2 = 0, byte3 = 0;

  8. ULONG temp = 0;

  9. ULONGLONG addr = 0;

  10. //开始搜索

  11. for (i = StartSearchAddress;i < EndSearchAddress;i++)

  12. {

  13. if (MmIsAddressValid(i) && MmIsAddressValid(i + 1) && MmIsAddressValid(i + 2))

  14. {

  15. byte1 = *i;

  16. byte2 = *(i + 1);

  17. byte3 = *(i + 2);

  18. if (byte1 == 0x4c && byte2 == 0x8d && byte3 == 0x15) //4c8d15

  19. {

  20. memcpy(&temp, i + 3, 4);

  21. addr = (ULONGLONG)temp + (ULONGLONG)i + 7;

  22. return addr;

  23. }

  24. }

  25. }

  26. return 0;

  27. }

获取SSDT表中的函数地址

 
  1. //获取SSDT中的函数地址

  2. ULONGLONG GetSSDTFuncCurrentAddr(ULONG id)

  3. {

  4. LONG dwtemp = 0;

  5. PULONG ServiceTableBase = NULL;

  6. ServiceTableBase = (PULONG)KeServiceDescriptorTable->ServiceTableBase;

  7. dwtemp = ServiceTableBase[id];

  8. dwtemp = dwtemp >> 4;

  9. return (LONGLONG)dwtemp + (ULONGLONG)ServiceTableBase;

  10. }

开启Hook

 
  1. //开启Hook

  2. VOID HookSSDT()

  3. {

  4. KIRQL irql;

  5. ULONGLONG dwtmp = 0;

  6. PULONG ServiceTableBase = NULL;

  7. //获取老函数地址

  8. g_OldOpenProcess = (NTOPENPROCESS)GetSSDTFuncCurrentAddr(35);

  9. //HookKeBugCheckEx

  10. InlineHookKeBugCheckEx();

  11. //保存地址数据,替换数据

  12. ServiceTableBase = (PULONG)KeServiceDescriptorTable->ServiceTableBase;

  13. OldTpVal = ServiceTableBase[35]; //保存表中的偏移变量

  14. irql = WriteProtectOFFx64();

  15. ServiceTableBase[35] = GetOffsetAddress((ULONGLONG)KeBugCheckEx);

  16. WriteProtectONx64(irql);

  17. }

HookKeBugCheckEx作为跳转

 
  1. //InlineHook_KeBugCheckEx

  2. VOID InlineHookKeBugCheckEx()

  3. {

  4. KIRQL irql;

  5. ULONGLONG myfun;

  6. UCHAR jmp_code[] = "\x48\xB8\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xE0";

  7. myfun = (ULONGLONG)HookNtOpenProcess;//替换成自己的函数地址

  8. memcpy(jmp_code + 2, &myfun, 8);

  9. irql = WriteProtectOFFx64();

  10. memset(KeBugCheckEx, 0x90, 15);

  11. memcpy(KeBugCheckEx, jmp_code, 12);//拷贝12字节

  12. WriteProtectONx64(irql);

  13. }

测试效果:

过PG后,加载驱动,使用任务管理器结束"计算器"程序失败,提示"拒绝访问"

 

PCHunter64位查看,又看到驱动挂钩了NtOpenProcess函数

PS:博客的技术内容的宽度可是开的有点大了,感觉自己很难把这些坑都填完.尽力填吧,每一个技术方面都尽力去深究.不过也有自己的事要做,填坑的速度肯定是快不了的.

转载于:https://my.oschina.net/u/1777508/blog/1930940

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值