看雪软件安全论坛



返回   看雪软件安全论坛 > 初学者园地 > 『资料导航』

发表新主题 回复
己收入精华集  
主题工具 显示模式
本站声明:看雪论坛文章版权属于作者,受法律保护。没有作者书面许可不得转载。若作者同意转载,必须以超链接形式标明文章原始出处和作者信息及本声明!
combojiang
级别:18 | 在线时长:431小时 | 升级还需:6小时级别:18 | 在线时长:431小时 | 升级还需:6小时级别:18 | 在线时长:431小时 | 升级还需:6小时

combojiang 的头像

『编程技术小组』
『编程技术小组』

资 料:
注册日期: May 2007
帖子: 736 combojiang 品行端正
精华: 26
现金: 104 Kx
1 旧 默认 【原创】rootkit hook之[三] inline hook
帅哥 combojiang 当前离线

标 题: 【原创】rootkit hook之[三] inline hook
作 者: combojiang
时 间: 2008-01-30,17:27:57
链 接: http://bbs.pediy.com/showthread.php?t=59127

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

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

先谈谈思路:

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

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

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

这15个函数,都是在cdnprot.sys中实现的。

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

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


4.  Inline hook后的恢复工作
正如2步骤3)中描述的那样。

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

附上一个例子吧:
这个例子是hook了KiInsertQueueApc,由于KiInsertQueueApc没有导出,需要在KeInsertQueueApc中找出来。
#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[i] == 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[i] + 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)[i] = ((unsigned char *)my_function_detour_KiInsertQueueApc)[i];
  }

  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)[i]) &&
      (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[i]) ) = reentry_address;
      break;
    }
  }


    oldIrql = KeRaiseIrqlToDpcLevel();
  for(i=0;i < 8;i++)
  {
    g_oricode[i] = actual_function[i];
    actual_function[i] = newcode[i];
  }
    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[i] = g_oricode[i];
  }
    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;
}

补充: 实际应用文章,可以参考sudami的干掉KV 2008, Rising等大部分杀软

------下载此贴附件最少需要拥有2Kx,方有下载权限。------
上传的附件
文件类型: rar cnnic.rar (505.8 KB, 2117 次下载) 下载此附件需要消耗2Kx,下载中会自动扣除。
此帖于 2008-04-07 17:55:04 被 combojiang 最后编辑
回复时引用此帖 返回顶端
petnt
级别:24 | 在线时长:673小时 | 升级还需:52小时级别:24 | 在线时长:673小时 | 升级还需:52小时级别:24 | 在线时长:673小时 | 升级还需:52小时

petnt 的头像

高级会员
高级会员

资 料:
注册日期: Apr 2006
帖子: 1,152 petnt 品行端正
精华: 12
现金: 345 Kx
2 旧 2008-01-30, 18:08:05 默认
petnt 当前离线

好东西啊,占座学习

回复时引用此帖 返回顶端
sudami
级别:25 | 在线时长:736小时 | 升级还需:44小时级别:25 | 在线时长:736小时 | 升级还需:44小时级别:25 | 在线时长:736小时 | 升级还需:44小时级别:25 | 在线时长:736小时 | 升级还需:44小时

sudami 的头像

高级会员
高级会员

资 料:
注册日期: Oct 2006
帖子: 1,308 sudami 品行端正
精华: 24
现金: 416 Kx
3 旧 2008-01-30, 18:13:34 默认
sudami 当前离线

学习. 

都是inline hook的SSDT中的函数呀.

用IoAllocateMdl等函数来写SSDT,也可以直接修改CR0.嘿嘿.

cnnic很流氓,它还hook了IRP_MJ_CREATE(0x00)、IRP_MJ_SET_INFORMATION(0x06)....

回复时引用此帖 返回顶端
炉子
级别:12 | 在线时长:205小时 | 升级还需:16小时级别:12 | 在线时长:205小时 | 升级还需:16小时级别:12 | 在线时长:205小时 | 升级还需:16小时

炉子 的头像

普通会员
普通会员

资 料:
注册日期: Jul 2007
帖子: 309 炉子 品行端正
精华: 3
现金: 30 Kx
4 旧 2008-01-30, 18:42:42 默认
帅哥 炉子 当前离线

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

汗,俺平时就是改cr0+sti&SpinLock的 - -

回复时引用此帖 返回顶端
xPLK
级别:18 | 在线时长:405小时 | 升级还需:32小时级别:18 | 在线时长:405小时 | 升级还需:32小时级别:18 | 在线时长:405小时 | 升级还需:32小时

xPLK 的头像

普通会员
普通会员

资 料:
注册日期: Mar 2007
帖子: 465 xPLK 品行端正
精华: 3
现金: 143 Kx
5 旧 2008-01-30, 21:53:45 默认
帅哥 xPLK 当前离线

我的就没那么严谨了。。。

回复时引用此帖 返回顶端
cvcvxk
级别:15 | 在线时长:288小时 | 升级还需:32小时级别:15 | 在线时长:288小时 | 升级还需:32小时级别:15 | 在线时长:288小时 | 升级还需:32小时级别:15 | 在线时长:288小时 | 升级还需:32小时级别:15 | 在线时长:288小时 | 升级还需:32小时级别:15 | 在线时长:288小时 | 升级还需:32小时

初级会员
初级会员

资 料:
注册日期: Jul 2006
帖子: 812 cvcvxk 品行端正
精华: 0
现金: 146 Kx
6 旧 2008-01-31, 00:07:55 默认
cvcvxk 当前离线

我改ssdt一直是mdl的,inline也mdl~

回复时引用此帖 返回顶端
sudami
级别:25 | 在线时长:736小时 | 升级还需:44小时级别:25 | 在线时长:736小时 | 升级还需:44小时级别:25 | 在线时长:736小时 | 升级还需:44小时级别:25 | 在线时长:736小时 | 升级还需:44小时

sudami 的头像

高级会员
高级会员

资 料:
注册日期: Oct 2006
帖子: 1,308 sudami 品行端正
精华: 24
现金: 416 Kx
7 旧 2008-01-31, 08:40:54 默认
sudami 当前离线

引用:
最初由 cvcvxk发布 查看帖子
我改ssdt一直是mdl的,inline也mdl~
哦. 学习V大

回复时引用此帖 返回顶端
火影
级别:9 | 在线时长:135小时 | 升级还需:5小时级别:9 | 在线时长:135小时 | 升级还需:5小时级别:9 | 在线时长:135小时 | 升级还需:5小时

火影 的头像

普通会员
普通会员

资 料:
注册日期: Apr 2006
帖子: 137 火影 品行端正
精华: 11
现金: 204 Kx
8 旧 2008-01-31, 09:26:35 默认
火影 当前离线

lz大哥不是一般的牛X

回复时引用此帖 返回顶端
sislcb
级别:6 | 在线时长:76小时 | 升级还需:1小时级别:6 | 在线时长:76小时 | 升级还需:1小时级别:6 | 在线时长:76小时 | 升级还需:1小时

『编程技术小组』
『编程技术小组』

资 料:
注册日期: Dec 2005
帖子: 134 sislcb 品行端正
精华: 7
现金: 207 Kx
9 旧 2008-01-31, 10:00:32 默认
sislcb 当前离线

用 cr0+sti&SpinLock 和 用mdl效果不一样吗?一样就无所谓了吧。。

回复时引用此帖 返回顶端
xPLK
级别:18 | 在线时长:405小时 | 升级还需:32小时级别:18 | 在线时长:405小时 | 升级还需:32小时级别:18 | 在线时长:405小时 | 升级还需:32小时

xPLK 的头像

普通会员
普通会员

资 料:
注册日期: Mar 2007
帖子: 465 xPLK 品行端正
精华: 3
现金: 143 Kx
10 旧 2008-01-31, 12:37:52 默认
帅哥 xPLK 当前离线

cr0方便
不过有点风险

回复时引用此帖 返回顶端
combojiang
级别:18 | 在线时长:431小时 | 升级还需:6小时级别:18 | 在线时长:431小时 | 升级还需:6小时级别:18 | 在线时长:431小时 | 升级还需:6小时

combojiang 的头像

『编程技术小组』
『编程技术小组』

资 料:
注册日期: May 2007
帖子: 736 combojiang 品行端正
精华: 26
现金: 104 Kx
11 旧 2008-02-01, 09:57:42 默认
帅哥 combojiang 当前离线

嗯,能不能行,建议试验下inline hook ZwQuerySystemInformation就知道了。

回复时引用此帖 返回顶端
zrhai
级别:6 | 在线时长:72小时 | 升级还需:5小时级别:6 | 在线时长:72小时 | 升级还需:5小时级别:6 | 在线时长:72小时 | 升级还需:5小时

初级会员
初级会员

资 料:
注册日期: Jan 2005
帖子: 56 zrhai 品行端正
精华: 0
现金: 185 Kx
12 旧 2008-02-24, 23:22:23 默认
zrhai 当前在线

谢谢楼主,学习!

回复时引用此帖 返回顶端
简单爱
级别:6 | 在线时长:65小时 | 升级还需:12小时级别:6 | 在线时长:65小时 | 升级还需:12小时级别:6 | 在线时长:65小时 | 升级还需:12小时

初级会员
初级会员

资 料:
注册日期: Oct 2007
帖子: 44 简单爱 品行端正
精华: 0
现金: 206 Kx
13 旧 2008-03-09, 19:30:52 默认
简单爱 当前离线

引用
“最近为了写好rootkit inline hook篇,特意A了著名的流氓软件(cdnprot.sys),”
请问A是啥意思?

回复时引用此帖 返回顶端
sudami
级别:25 | 在线时长:736小时 | 升级还需:44小时级别:25 | 在线时长:736小时 | 升级还需:44小时级别:25 | 在线时长:736小时 | 升级还需:44小时级别:25 | 在线时长:736小时 | 升级还需:44小时

sudami 的头像

高级会员
高级会员

资 料:
注册日期: Oct 2006
帖子: 1,308 sudami 品行端正
精华: 24
现金: 416 Kx
14 旧 2008-03-09, 20:02:37 默认
sudami 当前离线

A 可以理解为“逆向”或者是 “偷窃拷贝他人现成的code

回复时引用此帖 返回顶端
简单爱
级别:6 | 在线时长:65小时 | 升级还需:12小时级别:6 | 在线时长:65小时 | 升级还需:12小时级别:6 | 在线时长:65小时 | 升级还需:12小时

初级会员
初级会员

资 料:
注册日期: Oct 2007
帖子: 44 简单爱 品行端正
精华: 0
现金: 206 Kx
15 旧 2008-03-10, 16:24:27 icon3
简单爱 当前离线

引用:
最初由 sudami发布 查看帖子
A 可以理解为“逆向”或者是 “偷窃拷贝他人现成的code
第一个意思原来就知道了,第二个意思貌似也知道,但就是不知道这种叫法的出处在哪儿,用Reverse跟copy多好啊,简单明了。

回复时引用此帖 返回顶端
发表新主题 回复

书签

主题工具
显示模式

发帖规则
不可以发表新主题
不可以发表回复
不可以上传附件
不可以编辑自己的帖子
论坛启用 BB 代码
论坛启用 表情符号
论坛跳转

相似的主题
主题 主题作者 版面 回复 最后发表
【原创】SSDT Hook的妙用-对抗ring0 inline hook 堕落天才 『软件调试论坛』 147 2010-09-01 21:08:44
黑客技术与防范 【原创】RootKit hook之[二] SSDT hook combojiang 『资料导航』 29 2010-08-13 00:56:38
黑客技术与防范 【原创】RootKit hook 之[一] object hook combojiang 『资料导航』 50 2010-04-02 12:43:08
系统底层 【求助】对 SSDT Hook的妙用-对抗ring0 inline hook 的一个疑问 trkzrq 『软件调试论坛』 5 2007-09-29 13:16:56
【原创】管道应用之捕获控制台程序信息 三根火柴 『安全编程论坛』 14 2007-06-14 14:39:12


所有时间均为北京时间。现在的时间是 17:01:06


©2000-2010 PEdiy.com All rights reserved.By PEDIY
Powered by vBulletin ®Jelsoft Enterprises Ltd. 增强包制作PHP源动力.界面支持standme Studio.