找回密码
 加入我们

QQ登录

只需一步,快速开始

搜索
查看: 4632|回复: 3

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

[复制链接]

78

主题

190

回帖

9

精华

贵宾会员

积分
15605
发表于 2016-2-7 15:48:49 | 显示全部楼层 |阅读模式
不想多说什么直接贴代码,本文以挂钩KiInsertQueueApc为例
首先是挂钩代码:
  1. void StartHook()
  2. {
  3.         PMDL pMdl;
  4.         PVOID Msct;
  5.         PVOID AddressOf_KeInsertQueueApc;
  6.         UNICODE_STRING uniFuncName;
  7.         ULONG i;
  8.         BYTE g_HookCode[4]={0xEB,0xF8,0x55,0x8B};
  9.         BYTE g_PushRetCode[6]={0x68,0,0,0,0,0xC3};
  10.         BYTE g_JmpOrigCode[9]={0x8B,0xFF,0xEA,0,0,0,0,0x08,0};
  11.         RtlInitUnicodeString(&uniFuncName,L"KeInsertQueueApc");
  12.         AddressOf_KeInsertQueueApc=MmGetSystemRoutineAddress(&uniFuncName);
  13.         for(i=(ULONG)AddressOf_KeInsertQueueApc;i<=(ULONG)AddressOf_KeInsertQueueApc+0x40;i++)
  14.         {
  15.                 if(*(PUSHORT)i==0xE828)
  16.                 {
  17.                         KiInsertQueueApc=(PVOID)(*(PULONG)(i+2)+i+6);
  18.                         Old_KiInsertQueueApc=ExAllocatePool(NonPagedPool,9);
  19.                         *(PULONG)((ULONG)g_JmpOrigCode+3)=(ULONG)KiInsertQueueApc+2;
  20.                         RtlCopyMemory(Old_KiInsertQueueApc,g_JmpOrigCode,9);
  21.                         *(PULONG)((ULONG)g_PushRetCode+1)=(ULONG)fake_KiInsertQueueApc;
  22.                         pMdl=MmCreateMdl(NULL,(PVOID)((ULONG)KiInsertQueueApc-6),10);
  23.                         if(pMdl)
  24.                         {
  25.                                 MmBuildMdlForNonPagedPool(pMdl);
  26.                                 __try
  27.                                 {
  28.                                         MmProbeAndLockPages(pMdl,KernelMode,IoWriteAccess);
  29.                                 }
  30.                                 __except(EXCEPTION_EXECUTE_HANDLER)
  31.                                 {
  32.                                         IoFreeMdl(pMdl);
  33.                                 }
  34.                                 Msct=MmMapLockedPagesSpecifyCache(pMdl,KernelMode,MmWriteCombined,NULL,FALSE,HighPagePriority);
  35.                                 RtlCopyMemory(Msct,g_PushRetCode,6);
  36.                                 InterlockedExchange((PULONG)((ULONG)Msct+6),*(PULONG)g_HookCode);
  37.                                 MmUnmapLockedPages(Msct,pMdl);
  38.                                 MmUnlockPages(pMdl);
  39.                                 IoFreeMdl(pMdl);
  40.                         }
  41.                         break;
  42.                 }
  43.         }
  44. }
复制代码

然后是卸载钩子代码:
  1. void StopHook()
  2. {
  3.         PMDL pMdl;
  4.         PVOID Msct;
  5.         ULONG Code1=0xCCCCCCCC;
  6.         ULONG Code2=0xFF8BCCCC;
  7.         pMdl=MmCreateMdl(NULL,(PVOID)((ULONG)KiInsertQueueApc-6),8);
  8.         if(pMdl)
  9.         {
  10.                 MmBuildMdlForNonPagedPool(pMdl);
  11.                 __try
  12.                 {
  13.                         MmProbeAndLockPages(pMdl,KernelMode,IoWriteAccess);
  14.                 }
  15.                 __except(EXCEPTION_EXECUTE_HANDLER)
  16.                 {
  17.                         IoFreeMdl(pMdl);
  18.                 }
  19.                 Msct=MmMapLockedPagesSpecifyCache(pMdl,KernelMode,MmWriteCombined,NULL,FALSE,HighPagePriority);
  20.                 InterlockedExchange((PULONG)Msct,Code1);
  21.                 InterlockedExchange((PULONG)((ULONG)Msct+4),Code2);
  22.                 MmUnmapLockedPages(Msct,pMdl);
  23.                 MmUnlockPages(pMdl);
  24.                 IoFreeMdl(pMdl);
  25.         }
  26. }
复制代码

再然后是处理KiInsertQueueApc的代码,注意这里是__fastcall的调用约定
  1. void __fastcall fake_KiInsertQueueApc(IN PKAPC Apc,IN KPRIORITY Increment)
  2. {
  3.         PEPROCESS txps;
  4.         if(PsGetCurrentProcess()==ProtectedProcess)
  5.         {
  6.                 Old_KiInsertQueueApc(Apc,Increment);
  7.         }
  8.         else
  9.         {
  10.                 txps=IoThreadToProcess((PETHREAD)Apc->Thread);
  11.                 if(txps!=ProtectedProcess)
  12.                 {
  13.                         Old_KiInsertQueueApc(Apc,Increment);
  14.                 }
  15.         }
  16. }
复制代码

编译后,网上流行的Ke(i)InsertQueueApc插APC杀进程的代码将会失效,除非绕过,恢复或者自己实现插APC才能用APC法结束本文中的例子。当然咯对付本文的进程保护完全可以使用内存清零法。相比用在KiInsertQueueApc头部写上E9 XX XX XX XX的方式挂钩,这种方法更加稳定,即便老方法用上了投递DPC锁定其他核心的代码。
看看PCHunter的钩子检测结果,如图所示

钩子检测

钩子检测

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

HookKiInsertQueueApc.zip

110.69 KB, 下载次数: 3094

下载代码不回帖是一种很欠扁的行为

评分

参与人数 1水晶币 +60 收起 理由
Tesla.Angela + 60 赞一个!

查看全部评分

857

主题

2632

回帖

2

精华

管理员

此生无悔入华夏,  长居日耳曼尼亚。  

积分
36130
发表于 2016-2-7 19:00:13 | 显示全部楼层
你第二个跳转是搞了啥?怎么有8个字节?

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

78

主题

190

回帖

9

精华

贵宾会员

积分
15605
 楼主| 发表于 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指令了

5

主题

116

回帖

0

精华

铜牌会员

积分
174
发表于 2023-12-7 16:44:27 | 显示全部楼层
可怜的KeInsertQueueApc 被你又iat又inline
您需要登录后才可以回帖 登录 | 加入我们

本版积分规则

快速回复 返回顶部 返回列表