tangptr@126.com 发表于 2016-2-7 15:48:49

TP的学习笔记:Inline Hook之短跳

不想多说什么直接贴代码,本文以挂钩KiInsertQueueApc为例
首先是挂钩代码:
void StartHook()
{
        PMDL pMdl;
        PVOID Msct;
        PVOID AddressOf_KeInsertQueueApc;
        UNICODE_STRING uniFuncName;
        ULONG i;
        BYTE g_HookCode={0xEB,0xF8,0x55,0x8B};
        BYTE g_PushRetCode={0x68,0,0,0,0,0xC3};
        BYTE g_JmpOrigCode={0x8B,0xFF,0xEA,0,0,0,0,0x08,0};
        RtlInitUnicodeString(&uniFuncName,L"KeInsertQueueApc");
        AddressOf_KeInsertQueueApc=MmGetSystemRoutineAddress(&uniFuncName);
        for(i=(ULONG)AddressOf_KeInsertQueueApc;i<=(ULONG)AddressOf_KeInsertQueueApc+0x40;i++)
        {
                if(*(PUSHORT)i==0xE828)
                {
                        KiInsertQueueApc=(PVOID)(*(PULONG)(i+2)+i+6);
                        Old_KiInsertQueueApc=ExAllocatePool(NonPagedPool,9);
                        *(PULONG)((ULONG)g_JmpOrigCode+3)=(ULONG)KiInsertQueueApc+2;
                        RtlCopyMemory(Old_KiInsertQueueApc,g_JmpOrigCode,9);
                        *(PULONG)((ULONG)g_PushRetCode+1)=(ULONG)fake_KiInsertQueueApc;
                        pMdl=MmCreateMdl(NULL,(PVOID)((ULONG)KiInsertQueueApc-6),10);
                        if(pMdl)
                        {
                                MmBuildMdlForNonPagedPool(pMdl);
                                __try
                                {
                                        MmProbeAndLockPages(pMdl,KernelMode,IoWriteAccess);
                                }
                                __except(EXCEPTION_EXECUTE_HANDLER)
                                {
                                        IoFreeMdl(pMdl);
                                }
                                Msct=MmMapLockedPagesSpecifyCache(pMdl,KernelMode,MmWriteCombined,NULL,FALSE,HighPagePriority);
                                RtlCopyMemory(Msct,g_PushRetCode,6);
                                InterlockedExchange((PULONG)((ULONG)Msct+6),*(PULONG)g_HookCode);
                                MmUnmapLockedPages(Msct,pMdl);
                                MmUnlockPages(pMdl);
                                IoFreeMdl(pMdl);
                        }
                        break;
                }
        }
}
然后是卸载钩子代码:
void StopHook()
{
        PMDL pMdl;
        PVOID Msct;
        ULONG Code1=0xCCCCCCCC;
        ULONG Code2=0xFF8BCCCC;
        pMdl=MmCreateMdl(NULL,(PVOID)((ULONG)KiInsertQueueApc-6),8);
        if(pMdl)
        {
                MmBuildMdlForNonPagedPool(pMdl);
                __try
                {
                        MmProbeAndLockPages(pMdl,KernelMode,IoWriteAccess);
                }
                __except(EXCEPTION_EXECUTE_HANDLER)
                {
                        IoFreeMdl(pMdl);
                }
                Msct=MmMapLockedPagesSpecifyCache(pMdl,KernelMode,MmWriteCombined,NULL,FALSE,HighPagePriority);
                InterlockedExchange((PULONG)Msct,Code1);
                InterlockedExchange((PULONG)((ULONG)Msct+4),Code2);
                MmUnmapLockedPages(Msct,pMdl);
                MmUnlockPages(pMdl);
                IoFreeMdl(pMdl);
        }
}
再然后是处理KiInsertQueueApc的代码,注意这里是__fastcall的调用约定
void __fastcall fake_KiInsertQueueApc(IN PKAPC Apc,IN KPRIORITY Increment)
{
        PEPROCESS txps;
        if(PsGetCurrentProcess()==ProtectedProcess)
        {
                Old_KiInsertQueueApc(Apc,Increment);
        }
        else
        {
                txps=IoThreadToProcess((PETHREAD)Apc->Thread);
                if(txps!=ProtectedProcess)
                {
                        Old_KiInsertQueueApc(Apc,Increment);
                }
        }
}
编译后,网上流行的Ke(i)InsertQueueApc插APC杀进程的代码将会失效,除非绕过,恢复或者自己实现插APC才能用APC法结束本文中的例子。当然咯对付本文的进程保护完全可以使用内存清零法。相比用在KiInsertQueueApc头部写上E9 XX XX XX XX的方式挂钩,这种方法更加稳定,即便老方法用上了投递DPC锁定其他核心的代码。
看看PCHunter的钩子检测结果,如图所示

很搞笑的是我明明只挂了一个钩子却显示了两行。第一行标记出了KiInsertQueueApc,可是却检测不到跳的位置,说明PCHunter无法识别短跳,第二行才把我的跳转之黑手标注出来。
本文的示例在Windows XP SP3测试通过

Tesla.Angela 发表于 2016-2-7 19:00:13

你第二个跳转是搞了啥?怎么有8个字节?

顺带WIN32下还有个讨巧1字节HOOK法。因为一般函数开头第一字节都是8B,你直接改为CD,然后挂钩IDT的0xFF中断即可。

tangptr@126.com 发表于 2016-2-7 19:53:02

本帖最后由 tangptr@126.com 于 2016-2-7 20:26 编辑

第一个短跳跳到KiInsertQueueApc-6的位置,这个位置是push-ret跳转跳到fake_KiInsertQueueApc的。至于你说的中断指令法跳转我只是听说过。。。
我估计PCHunter为了显示出几个未导出函数的钩子特地重新检测一遍KiInsertQueueApc,PspTerminateThreadByPointer等出名的未导出函数。所谓有八个字节是因为KiInsertQueueApc-6到KiInsertQueueApc+2一共有八个字节
有些函数会有局限性,比如ObpCreateHandle,前面只有五个字节是空闲的。只能放jmp指令了

376408384 发表于 2023-12-7 16:44:27

可怜的KeInsertQueueApc 被你又iat又inline
页: [1]
查看完整版本: TP的学习笔记:Inline Hook之短跳