[2021]让InfinityHook再次伟大 huoji hook,API HOOK,SSDT HOOK,ETW,InfinityHook 2021-06-23 4711 次浏览 5 次点赞 make InfinityHook great again ## 前言 在我折腾InfinityHook的时候我发现2004下系统没啥作用,原因是在2004系统上 WMI_LOGGER_CONTEXT->GetCpuClock已经不是rdtsc()函数了而是一个叫做 EtwpGetLoggerTimeStamp的函数 ![](https://key08.com/usr/uploads/2021/06/239927485.png) EtwpGetLoggerTimeStamp函数按照WMI_LOGGER_CONTEXT->GetCpuClock的值有如下操作: 大于3抛异常 等于3用rdtsc 等于2用off_140C00A30 等于1用KeQueryPerformanceCounter 等于0用RtlGetSystemTimePrecise 3,1,0都好说,但是这个2的off_140C00A30是什么鬼? 查看引用: ![](https://key08.com/usr/uploads/2021/06/2279045045.png) 他是一个在data上,指向HalpTimerQueryHostPerformanceCounter的指针 ![](https://key08.com/usr/uploads/2021/06/2481597528.png) (我虽然不知道他有什么作用,但是我非常震撼,因为他的引用就那几个...为什么还要用指针) ![](https://key08.com/usr/uploads/2021/06/4137616961.png) 当在内核遇到不是那么热度高的指针的时候,我们可以搭档尝试一下hook,因为内核里面这些指针太多,pg是管不来的.所以我尝试改一下InfinityHook,让他能在2004上支持: ## 干活 1.获取指针地址 ![](https://key08.com/usr/uploads/2021/06/1545574811.png) ```cpp // off_140C009E0 pattern UCHAR pattern[] = "\x48\xcc\xcc\xcc\xcc\xcc\xcc\xE8\xcc\xcc\xcc\xcc\x83\xcc\xcc\x75\xcc\x38\xcc\xcc\xcc\xcc\xcc\x75\xcc\x48\xcc\xcc\xcc\xcc\xcc\xcc\x83\xB8\xcc\xcc\xcc\xcc\xcc\x0F\xcc\xcc\xcc\xcc\xcc"; NTSTATUS status = UtilScanSection(".text", (PCUCHAR)pattern, 0xCC, sizeof(pattern) - 1, (PVOID*)&PtrOff140C009E0); if (!NT_SUCCESS(status)) { kprintf("[DebugMessAge] off_140C009E0 not found! :( \n"); return false; } PtrOff140C009E0 = PtrOff140C009E0 + *(ULONG*)(PtrOff140C009E0 + 3) + 7; ``` 2.修改这个指针 拥有指针后,记得将WMI_LOGGER_CONTEXT->GetCpuClock设置为2: ```cpp *reinterpret_cast((uintptr_t)CkclWmiLoggerContext + OFFSET_WMI_LOGGER_CONTEXT_CPU_CYCLE_CLOCK) = 2; ``` 然后就是修改为自己的地址: ```cpp *((ULONG64*)PtrOff140C009E0) = (ULONG64)HookHalpTimerQueryHostPerformanceCounter; ``` hook函数: ```cpp extern "C" __int64 __fastcall HookHalpTimerQueryHostPerformanceCounter(ULONG64 * pTime) { if (ExGetPreviousMode() != KernelMode) { //__debugbreak(); IfhpInternalGetCpuClock(); } return OldPtrOff140C009E0(pTime); } ``` IfhpInternalGetCpuClock里面,就是从stack上得到syscall地址,如果是自己的就改为原来的. ps: 第一次知道kthread里面还有syscallnum这个字段.... ```cpp static ULONG64 IfhpInternalGetCpuClock() { // // Extract the system call index (if you so desire). // PKTHREAD CurrentThread = (PKTHREAD)__readgsqword(OFFSET_KPCR_CURRENT_THREAD); unsigned int SystemCallIndex = *(unsigned int*)((uintptr_t)CurrentThread + OFFSET_KTHREAD_SYSTEM_CALL_NUMBER); PVOID* StackMax = (PVOID*)__readgsqword(OFFSET_KPCR_RSP_BASE); PVOID* StackFrame = (PVOID*)_AddressOfReturnAddress(); // // First walk backwards on the stack to find the 2 magic values. // for (PVOID* StackCurrent = StackMax; StackCurrent > StackFrame; --StackCurrent) { // // This is intentionally being read as 4-byte magic on an 8 // byte aligned boundary. // PULONG AsUlong = (PULONG)StackCurrent; if (*AsUlong != INFINITYHOOK_MAGIC_1) { continue; } // // If the first magic is set, check for the second magic. // --StackCurrent; PUSHORT AsShort = (PUSHORT)StackCurrent; if (*AsShort != INFINITYHOOK_MAGIC_2) { continue; } // // Now we reverse the direction of the stack walk. // for (; StackCurrent < StackMax; ++StackCurrent) { PULONGLONG AsUlonglong = (PULONGLONG)StackCurrent; if (!(PAGE_ALIGN(*AsUlonglong) >= SystemCallEntryPage && PAGE_ALIGN(*AsUlonglong) < (PVOID)((uintptr_t)SystemCallEntryPage + (PAGE_SIZE * 2)))) { continue; } // // If you want to "hook" this function, replace this stack memory // with a pointer to your own function. // void** SystemCallFunction = &StackCurrent[9]; if (IfhpCallback) { IfhpCallback(SystemCallIndex, SystemCallFunction); } break; } break; } return __rdtsc(); } ``` 至此魔改完毕,关闭调试器打签名上虚拟机看看会不会被pg: ![](https://key08.com/usr/uploads/2021/06/3392493777.png) **2004上至少两个小时内没有PG,但是测试了经过5个小时后,他蓝屏了** **难道真的我们没办法让他great again了?** ## 再次伟大! 在HalpTimerQueryHostPerformanceCounter中,往下看: ![](https://key08.com/usr/uploads/2021/06/2677905910.png) 这两个指针其实就是得到系统时间..而且是唯一在HalpTimerQueryHostPerformanceCounter用到的指针... 如果之前的off_140C00A30是被PG监控的,这两个指针会不会被监控呢?能不能利用呢? 此外不仅这个off_140C00A30函数,还有几个在ETW上必call的函数指针,这些指针有没有被监控呢? 让我们跟踪这个HalpTimerQueryHostPerformanceCounter上的两个函数: ![](https://key08.com/usr/uploads/2021/06/2005131878.png) 微软在栈上初始化了一个数组,然后依次给这个数组赋值,根据赋值的信息,我们可以逆向推导出函数名字: ![](https://key08.com/usr/uploads/2021/06/3784406722.png) (这个代码写的够烂的) ![](https://key08.com/usr/uploads/2021/06/2099726986.png) 从而得知如下信息: ![](https://key08.com/usr/uploads/2021/06/3284922129.png) 就从这个HvlGetQpcBias下手: ![](https://key08.com/usr/uploads/2021/06/3046536768.png) 他会查询一个HvlpReferenceTscPage表,我们手动定位: ![](https://key08.com/usr/uploads/2021/06/1464129557.png) ```cpp status = UtilScanSection(".text", (PCUCHAR)pattern_HvlpReferenceTscPage, 0xCC, sizeof(pattern_HvlpReferenceTscPage) - 1, (PVOID*)&HvlpReferenceTscPage); if (!NT_SUCCESS(status)) { kprintf("[DebugMessAge] HvlGetQpcBias not found! :( \n"); return false; } HvlpReferenceTscPage = HvlpReferenceTscPage + *(ULONG*)(HvlpReferenceTscPage + 3) + 7; ``` 之后还是老套路,但是请记住修改我们的函数: ```cpp extern "C" __int64 HookHvlGetQpcBias() { //__debugbreak(); if (ExGetPreviousMode() != KernelMode) { IfhpInternalGetCpuClock(); } return *((ULONG64*)(*((ULONG64*)HvlpReferenceTscPage)) + 3); } ``` 测试: ![](https://key08.com/usr/uploads/2021/06/880476445.png) working,看看多久会蓝屏 暂时21: 00-0: 00没有蓝屏 21:00 - 第二天10:19 ![捕获.PNG](https://key08.com/usr/uploads/2021/06/965055539.png) 继续测试满24小时看看 ## 扩展 再除此之外,不仅仅syscall,还有一些其他的异常信息、内存分配、文件创建等都会调用存在这些指针函数的函数,能不能做一些内核异常hook? halv这部分的函数指针在kebugcheck2中也有而且也被调用了,是不是可以从蓝屏中恢复系统? **等你来回答了,因为我时间不多** github: https://github.com/huoji120/MakeInfinityHookGreatAgain 修正,也有人做了差不多的,不过他是HalpPerformanceCounter: https://www.anquanke.com/post/id/206288 这洞留不久,估计再过几天就完全完蛋蛋了 本文由 huoji 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。 点赞 5
So how did u fix this issue?
I'm very stupid. Fixed. Thanks for releasing this.
Sorry i mean that it works fine on VirtualMachine but the hook never gets called in physical PC!
Any idea why the latest hook works in VM ?
I don't know. Please teach me