让InfinityHook再次伟大 – 作者:huoji120

make InfinityHook great again

前言

在我折腾InfinityHook的时候我发现2004下系统没啥作用,原因是在2004系统上 WMI_LOGGER_CONTEXT->GetCpuClock已经不是rdtsc()函数了而是一个叫做 EtwpGetLoggerTimeStamp的函数图片[1]-让InfinityHook再次伟大 – 作者:huoji120-安全小百科

EtwpGetLoggerTimeStamp函数按照WMI_LOGGER_CONTEXT->GetCpuClock的值有如下操作:
大于3抛异常
等于3用rdtsc
等于2用off_140C00A30
等于1用KeQueryPerformanceCounter
等于0用RtlGetSystemTimePrecise
3,1,0都好说,但是这个2的off_140C00A30是什么鬼?

查看引用:

1624875142_60d9a086651fa003567f3.png!small?1624875142175

他是一个在data上,指向HalpTimerQueryHostPerformanceCounter的指针

1624875156_60d9a0943734b4aedc804.png!small?1624875155856

(我虽然不知道他有什么作用,但是我非常震撼,因为他的引用就那几个…为什么还要用指针)

1624875165_60d9a09de684e6203adb3.png!small?1624875165794

当在内核遇到不是那么热度高的指针的时候,我们可以搭档尝试一下hook,因为内核里面这些指针太多,pg是管不来的.所以我尝试改一下InfinityHook,让他能在2004上支持:

干活

1.获取指针地址

1624875183_60d9a0afb5b86f4b4eca9.png!small?1624875183401

// 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:

*reinterpret_cast<uintptr_t*>((uintptr_t)CkclWmiLoggerContext + OFFSET_WMI_LOGGER_CONTEXT_CPU_CYCLE_CLOCK) = 2;

然后就是修改为自己的地址:

*((ULONG64*)PtrOff140C009E0) = (ULONG64)HookHalpTimerQueryHostPerformanceCounter;

hook函数:

extern "C" __int64 __fastcall HookHalpTimerQueryHostPerformanceCounter(ULONG64 * pTime)
{
    if (ExGetPreviousMode() != KernelMode)
    {
        //__debugbreak();
        IfhpInternalGetCpuClock();
    }

    return OldPtrOff140C009E0(pTime);
}

IfhpInternalGetCpuClock里面,就是从stack上得到syscall地址,如果是自己的就改为原来的.
ps: 第一次知道kthread里面还有syscallnum这个字段….

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:

图片[6]-让InfinityHook再次伟大 – 作者:huoji120-安全小百科

2004上至少两个小时内没有PG,但是测试了经过5个小时后,他蓝屏了

难道真的我们没办法让他great again了?

再次伟大!

在HalpTimerQueryHostPerformanceCounter中,往下看:

1624875302_60d9a12689fc66c259ac6.png!small?1624875302307

这两个指针其实就是得到系统时间..而且是唯一在HalpTimerQueryHostPerformanceCounter用到的指针…
如果之前的off_140C00A30是被PG监控的,这两个指针会不会被监控呢?能不能利用呢?
此外不仅这个off_140C00A30函数,还有几个在ETW上必call的函数指针,这些指针有没有被监控呢?

让我们跟踪这个HalpTimerQueryHostPerformanceCounter上的两个函数:

1624875312_60d9a1302bfa102f7d64b.png!small?1624875312046

微软在栈上初始化了一个数组,然后依次给这个数组赋值,根据赋值的信息,我们可以逆向推导出函数名字:

1624875321_60d9a13996f1ba89541d0.png!small?1624875321696(这个代码写的够烂的)

1624875334_60d9a146c600d649f5edd.png!small?1624875334875

从而得知如下信息:

图片[11]-让InfinityHook再次伟大 – 作者:huoji120-安全小百科

就从这个HvlGetQpcBias下手:

图片[12]-让InfinityHook再次伟大 – 作者:huoji120-安全小百科

他会查询一个HvlpReferenceTscPage表,我们手动定位:

图片[13]-让InfinityHook再次伟大 – 作者:huoji120-安全小百科

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;

之后还是老套路,但是请记住修改我们的函数:

extern "C" __int64 HookHvlGetQpcBias()
{
    //__debugbreak();
    if (ExGetPreviousMode() != KernelMode)
    {
        IfhpInternalGetCpuClock();
    }
    return *((ULONG64*)(*((ULONG64*)HvlpReferenceTscPage)) + 3);
}

测试:

图片[14]-让InfinityHook再次伟大 – 作者:huoji120-安全小百科

working,看看多久会蓝屏
暂时21: 00-0: 00没有蓝屏
21:00 – 第二天10:19

图片[15]-让InfinityHook再次伟大 – 作者:huoji120-安全小百科

继续测试满24小时看看

扩展

再除此之外,不仅仅syscall,还有一些其他的异常信息、内存分配、文件创建等都会调用存在这些指针函数的函数,能不能做一些内核异常hook?
halv这部分的函数指针在kebugcheck2中也有而且也被调用了,是不是可以从蓝屏中恢复系统?

等你来回答了,因为我时间不多

github:
https://github.com/huoji120/MakeInfinityHookGreatAgain
修正,也有人做了差不多的,不过他是HalpPerformanceCounter:
https://www.anquanke.com/post/id/206288
这洞留不久,估计再过几天就完全完蛋蛋了

来源:freebuf.com 2021-06-28 18:19:11 by: huoji120

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论