【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
测试环境:
虚拟机: 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.
关键代码:
获取服务表基址
-
//获取服务表基址
-
ULONGLONG GetKeServiceDescriptorTable64()
-
{
-
PUCHAR StartSearchAddress = (PUCHAR)__readmsr(0xC0000082);
-
PUCHAR EndSearchAddress = StartSearchAddress + 0x500;
-
PUCHAR i = NULL;
-
UCHAR byte1 = 0, byte2 = 0, byte3 = 0;
-
ULONG temp = 0;
-
ULONGLONG addr = 0;
-
//开始搜索
-
for (i = StartSearchAddress;i < EndSearchAddress;i++)
-
{
-
if (MmIsAddressValid(i) && MmIsAddressValid(i + 1) && MmIsAddressValid(i + 2))
-
{
-
byte1 = *i;
-
byte2 = *(i + 1);
-
byte3 = *(i + 2);
-
if (byte1 == 0x4c && byte2 == 0x8d && byte3 == 0x15) //4c8d15
-
{
-
memcpy(&temp, i + 3, 4);
-
addr = (ULONGLONG)temp + (ULONGLONG)i + 7;
-
return addr;
-
}
-
}
-
}
-
return 0;
-
}
获取SSDT表中的函数地址
-
//获取SSDT中的函数地址
-
ULONGLONG GetSSDTFuncCurrentAddr(ULONG id)
-
{
-
LONG dwtemp = 0;
-
PULONG ServiceTableBase = NULL;
-
ServiceTableBase = (PULONG)KeServiceDescriptorTable->ServiceTableBase;
-
dwtemp = ServiceTableBase[id];
-
dwtemp = dwtemp >> 4;
-
return (LONGLONG)dwtemp + (ULONGLONG)ServiceTableBase;
-
}
开启Hook
-
//开启Hook
-
VOID HookSSDT()
-
{
-
KIRQL irql;
-
ULONGLONG dwtmp = 0;
-
PULONG ServiceTableBase = NULL;
-
//获取老函数地址
-
g_OldOpenProcess = (NTOPENPROCESS)GetSSDTFuncCurrentAddr(35);
-
//HookKeBugCheckEx
-
InlineHookKeBugCheckEx();
-
//保存地址数据,替换数据
-
ServiceTableBase = (PULONG)KeServiceDescriptorTable->ServiceTableBase;
-
OldTpVal = ServiceTableBase[35]; //保存表中的偏移变量
-
irql = WriteProtectOFFx64();
-
ServiceTableBase[35] = GetOffsetAddress((ULONGLONG)KeBugCheckEx);
-
WriteProtectONx64(irql);
-
}
HookKeBugCheckEx作为跳转
-
//InlineHook_KeBugCheckEx
-
VOID InlineHookKeBugCheckEx()
-
{
-
KIRQL irql;
-
ULONGLONG myfun;
-
UCHAR jmp_code[] = "\x48\xB8\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xE0";
-
myfun = (ULONGLONG)HookNtOpenProcess;//替换成自己的函数地址
-
memcpy(jmp_code + 2, &myfun, 8);
-
irql = WriteProtectOFFx64();
-
memset(KeBugCheckEx, 0x90, 15);
-
memcpy(KeBugCheckEx, jmp_code, 12);//拷贝12字节
-
WriteProtectONx64(irql);
-
}
测试效果:
过PG后,加载驱动,使用任务管理器结束"计算器"程序失败,提示"拒绝访问"
PCHunter64位查看,又看到驱动挂钩了NtOpenProcess函数
PS:博客的技术内容的宽度可是开的有点大了,感觉自己很难把这些坑都填完.尽力填吧,每一个技术方面都尽力去深究.不过也有自己的事要做,填坑的速度肯定是快不了的.
来源:oschina
链接:https://my.oschina.net/u/1777508/blog/1930940