首页
社区
课程
招聘
[原创]NT内核下的inline hook,附完整的代码和工程文件
发表于: 2008-4-28 14:57 16710

[原创]NT内核下的inline hook,附完整的代码和工程文件

2008-4-28 14:57
16710
原理上很简单的东西,但我想很多新手都苦于找不到完整的示例 代码,下面就是一份完整的代码
  inline hook原理大概如下:
     修改被HOOK函数A的头5个字节,使其跳转到我们自定义的函数B,函数B的类型与函数A要相同。因为我们是使用JMP直接跳转到函数B,
而不是使用正常的CALL指令。在函数B内,我们可以检查函数参数,然后可以直接返回。也可以再调用函数A的一个副本。这个副本在HOOK动作发生的同时,就保存下来了。
     代码非常简单,工程打包供大家学习。高手飘过

/*
* krembo.c, Demonstration of inline hooking (aka. Detouring) within driver/kernel.
* - izik@tty64.org
*/

#include <ntddk.h>

// Assembly JMP opcode value

#ifndef X86_JMP
#define X86_JMP 0xE9
#endif

// Number of bytes to overwrite

#ifndef JMP_LENGTH
#define JMP_LENGTH sizeof(X86_JMP) + sizeof(int)
#endif

// Size of a page (4k)

#ifndef PAGE_SIZE
#define PAGE_SIZE 0x1000
#endif

// Pointers macros

#define PAGE_MASK(ptr) (ptr & 0xFFFFF000)

#define OFFSET_IN_PAGE(ptr) (ptr - (ptr & 0xFFFFF000))

// RtlRandom pointer prototype

typedef unsigned long (*RTLRANDOM)(
        unsigned long *seed
);

// Pointers to duplicated (original) and current versions of RtlRandom

RTLRANDOM pDupRtlRandom;
RTLRANDOM pCurRtlRandom;

/*
* DetourFunction, Detour a function (Install Detour)
* * pFcnAddr, Pointer to the soon-to-be-detoured function
* * iHookAddr, Address of the hook function
* * iPoolType, Pool type of allocated memory
*/

void *DetourFunction(char *pFcnAddr, int iHookAddr, int iPoolType) {
        void *pOrigPage;
               
        // Allocate a `PAGE_SIZE` for the original function (duplicate)
       
        pOrigPage = ExAllocatePoolWithTag(iPoolType, PAGE_SIZE, 0xdeadbeef);//分配一页内存,该函数在WIN 2000下可能不存在,XP下没问题
       
        // Is there enough resources?
       
        if (pOrigPage == NULL) {
                return NULL;
        }
       
        // Duplicate the entire page
       
        RtlCopyMemory(pOrigPage, (char *)PAGE_MASK((int)pFcnAddr), PAGE_SIZE);//拷贝函数内容,把函数所在的一整页都拷贝下来。如果函数不仅仅占据一页呢?
       
        // Calculate the relocation to `iHookAddr`
       
        iHookAddr -= ((int)pFcnAddr + 5);//iHookAddr = iHookAddr - (pFcnAddr +5)  iHookAddr是跳转的相对地址
       
        _asm
        {
                CLI                                        // disable interrupt
                MOV EAX, CR0                // move CR0 register into EAX
                AND EAX, NOT 10000H // disable WP bit
                MOV CR0, EAX                // write register back
        }
       
        // Overwrite the first `JMP_LENGTH` bytes of pFcnAddr (Detour it)
       
        *(pFcnAddr) = X86_JMP;
        *(pFcnAddr+1) = (iHookAddr & 0xFF);
        *(pFcnAddr+2) = (iHookAddr >> 8) & 0xFF;
        *(pFcnAddr+3) = (iHookAddr >> 16) & 0xFF;
        *(pFcnAddr+4) = (iHookAddr >> 24) & 0xFF;
       
        _asm
        {
                MOV EAX, CR0                // move CR0 register into EAX
                OR EAX, 10000H                // enable WP bit
                MOV CR0, EAX                // write register back
                STI                                        // enable interrupt
        }
       
        // Return pointer to the duplicate function (within the duplicate page)
       
        return (void *)((int)pOrigPage + OFFSET_IN_PAGE((int)pFcnAddr));//返回我们保存的函数副本地址(原件)
}

/*
* MyRtlRandom, RtlRandom hook
* * seed, given seed
*/

unsigned long MyRtlRandom(unsigned long *seed) {//HOOK发生时,原始函数跳转到该函数位置,★该函数的类型与原始函数相同
        unsigned long retval;

        DbgPrint(("MyRtlRandom invoked "));
       
        retval = pDupRtlRandom(seed);  //retval 是被HOOK函数的原件的地址,见DriverEntry(),在该函数内部又调用原始函数的原件(副本)
       
        //DbgPrint(("Returning value = %d, from OldRtlRandom(%d)\n"));
       
        return retval;
}

/*
* RestoreDetouredFunction, Restore a detoured function (Remove detour)
* * pDupFcn, Pointer to the duplicated function
* * pOrigFcn, Pointer to the original function
*/

void RestoreDetouredFunction(char *pOrigFcn, char *pDupFcn) { //移除HOOK
        int offset;
       
        _asm
        {
                CLI                                        // disable interrupt
                MOV EAX, CR0                // move CR0 register into EAX
                AND EAX, NOT 10000H // disable WP bit
                MOV CR0, EAX                // write register back
        }

        // Uninstall the detour, Restore `JMP_LENGHT` bytes from the duplicate function.
       
        for (offset = 0; offset < JMP_LENGTH; offset++) {
                pOrigFcn[offset] = pDupFcn[offset];
        }
       
        _asm
        {
                MOV EAX, CR0                // move CR0 register into EAX
                OR EAX, 10000H                // enable WP bit
                MOV CR0, EAX                // write register back
                STI                                        // enable interrupt
        }
       
        // Deallocate the duplicate page
       
        ExFreePoolWithTag((void *)((int)pDupFcn - OFFSET_IN_PAGE((int)pOrigFcn)), 0xdeadbeef);
       
        return ;
}

/*
* DriverUnload, Driver unload point
* * DriverObject, self (Driver)
*/

void DriverUnload(IN PDRIVER_OBJECT DriverObject) {
        unsigned long seed;

        if (pDupRtlRandom != NULL) { //pDupRtlRandom为我们保存的原始函数原件

                DbgPrint(("Removeing detour from RtlRandom\n"));

                // Remove detour

                RestoreDetouredFunction((char *)pCurRtlRandom, (char *)pDupRtlRandom);       

                // Do another self-test

                seed = 31337;

                pCurRtlRandom(&seed);
               
                // No bugcheck? ;-)
        }
       
        //DbgPrint(("Krembo unloaded!\n"));
       
        return ;
}

/*
* DriverEntry, Driver Single Entry Point
* * DriverObject, self (Driver)
* * RegistryPath, given RegistryPath
*/

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) {
        UNICODE_STRING pFcnName;
        unsigned long seed;

        //DbgPrint(("Krembo loaded!\n"));
       
        // Register unload routine
       
        DriverObject->DriverUnload = DriverUnload;
       
        // Lookup RtlRandom address
       
        RtlInitUnicodeString(&pFcnName, L"RtlRandom");
       
        pCurRtlRandom = MmGetSystemRoutineAddress(&pFcnName);
       
        //DbgPrint(("Found RtlRandom @ 0x%08x\n", pCurRtlRandom));
       
        // Detour RtlRandom

        pDupRtlRandom = DetourFunction((char *)pCurRtlRandom, (int)MyRtlRandom, (int)NonPagedPool);

        // Detour status?

        if (pDupRtlRandom == NULL) {
               
                // Unable to detour
         
                DbgPrint(("Unable to detour RtlRandom! (Not enough resources?)\n"));
       
        } else {
       
                //DbgPrint(("Duplicate Function @ 0x%08x\n", pDupRtlRandom));

                // Detour installed, do a self-test
       
                DbgPrint(("Detour installed, going into a self-test ...\n"));
                ////DbgPrint(("Detour installed, going into a self-test ...\n"));
               
                // Dummy seed for the self-test
               
                seed = 31337;

                pCurRtlRandom(&seed);
               
        }
       
        return STATUS_SUCCESS;
}

晕,不知道怎么添加附件。firefox 功能就是不如IE。不过代码都在这里了,COPY下然后编译就OK了

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (26)
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
先支持一个....
最近被C++累的 他们把代码贴出来,自己就是不会建立工程去编译..........
先大概问一下很弱的问题...这个是建立什么工程来编译的?

额...如果觉得太菜了就不好意思了...偶慢慢来...
2008-4-28 15:21
0
雪    币: 250
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
可以归入rootkit专栏
学习!
2008-4-28 16:44
0
雪    币: 209
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
这个代码太挫了。。。太挫了。。。

代码里面有个低级错误。。。

试试HOOK别的函数就知道了
2008-4-28 18:13
0
雪    币: 197
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
什么错误啊,请一定要不吝赐教啊。楼上的,我还打算用它来HOOK别的函数呢

是这句吗?
RtlCopyMemory(pOrigPage, (char *)PAGE_MASK((int)pFcnAddr), PAGE_SIZE);

或者请您提供一份更好的可以吗?发个链接也行啊
2008-4-28 18:20
0
雪    币: 709
活跃值: (2420)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
6
代码不仅不简洁美观。
而且你若尝试在自己的fake 函数中处理一些操作时,会发生不可遇见的堆栈问题,自己试下就知道了。

网上inline hook 内核函数的完整code很多,kanxue上也有,都比这份code好得多。

《Rootkits:Subverting the XXX》中也有完整的代码。

LZ费这么大劲,效果不好...
2008-4-28 18:42
0
雪    币: 197
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
楼上的批评很尖锐,我很喜欢。
2008-4-28 18:55
0
雪    币: 722
活跃值: (123)
能力值: ( LV12,RANK:300 )
在线值:
发帖
回帖
粉丝
8
retval = pDupRtlRandom(seed);  //retval 是被HOOK函数的原件的地址,见DriverEntry(),在该函数内部又调用原始函数的原件(副本)

我的天啊,楼主不懂汇编语言?!

仅仅把一条函数的内容全部直接copy到另一个地方,你就以为就能够跟原来一样正常运行了?!那里面的call啊jmp啊都得重定位的!!

inline hook中copy的,只是原函数头几个字节(被jmp覆盖掉了),这几个字节一般只是处理寄存器的,不涉及到call和jmp,就不会有重定位的麻烦。假设如果原来的头几个字节就有call和jmp的话,也是需要自己重定位的。现在楼主异想天开,把整个函数copy过去,你就等着蓝吧!
2008-4-28 22:21
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
学习     
2008-4-29 00:42
0
雪    币: 197
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
是这理,我把这岔给忘了,谢谢轩辕小聪的指点。

那我们搜索所有的JMP ,CALL指令,提取后面的跳转地址,然后将原始的跳转地址 减去 我们保存副本的偏移量,可以得出当前的跳转地址吗?不知你是否明白我的意思...是否可行

重定位是这个方法吗?
2008-4-29 09:03
0
雪    币: 209
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
为什么一定要用这个代码?

这个代码的作者之所以选择RtlRandom会成功,反汇编该函数就知道了

而他却没有说明被HOOK的函数不能有相对的跳转或call之类

所以说他太挫了

这份代码可以从你的硬盘Delete了,没价值
2008-4-29 09:21
0
雪    币: 108
活跃值: (141)
能力值: ( LV9,RANK:490 )
在线值:
发帖
回帖
粉丝
12
去看看Detours的代码吧
2008-4-29 10:46
0
雪    币: 197
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
detours 是个人名?还是一种技术总称?如果是后者的话,去哪儿找呢?给点提示

这代码毕竟我测试成功过,有些地方还是有 COPY 的价值的,嘿嘿。不删
2008-4-29 11:26
0
雪    币: 209
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
你成功是因为代码作者精心挑选了那个函数

你HOOK别的函数试试。。。作者没有说明就是在忽悠你

detours :
http://research.microsoft.com/sn/detours/
2008-4-29 12:03
0
雪    币: 197
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
我可以 重定位  函数副本内的JMP 与 CALL 的地址啊
2008-4-29 16:26
0
雪    币: 209
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
那你必须得Scan你要Hook的函数

效率太低了
2008-4-29 17:41
0
雪    币: 709
活跃值: (2420)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
17
哪儿有这么费劲的。

我传一分 inline hook的完整code吧。

subverting the windows kernel 里面的 migboot。

对inline hook 内核函数不懂的都参照这个改改吧。
上传的附件:
2008-4-29 22:02
0
雪    币: 581
活跃值: (149)
能力值: ( LV12,RANK:600 )
在线值:
发帖
回帖
粉丝
18
subverting the windows kernel 里面的 migboot。
这份来HOOK一些没导出的???可能不行了
2008-4-29 22:04
0
雪    币: 227
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
去微软官方网站下detours看看吧
2008-4-29 22:09
0
雪    币: 722
活跃值: (123)
能力值: ( LV12,RANK:300 )
在线值:
发帖
回帖
粉丝
20
lkd> uf RtlRandom
nt!RtlRandom:
80581878 8bff            mov     edi,edi
8058187a 55              push    ebp
8058187b 8bec            mov     ebp,esp
8058187d 53              push    ebx
8058187e 56              push    esi
8058187f 8b7508          mov     esi,dword ptr [ebp+8]
80581882 8b06            mov     eax,dword ptr [esi]
80581884 69c0edffff7f    imul    eax,eax,7FFFFFEDh
8058188a 57              push    edi
8058188b b9c3ffff7f      mov     ecx,7FFFFFC3h
80581890 03c1            add     eax,ecx
80581892 bfffffff7f      mov     edi,7FFFFFFFh
80581897 33d2            xor     edx,edx
80581899 8bdf            mov     ebx,edi
8058189b f7f3            div     eax,ebx
8058189d 8bda            mov     ebx,edx
8058189f 8bc2            mov     eax,edx
805818a1 69c0edffff7f    imul    eax,eax,7FFFFFEDh
805818a7 03c1            add     eax,ecx
805818a9 33d2            xor     edx,edx
805818ab f7f7            div     eax,edi
805818ad 5f              pop     edi
805818ae 8916            mov     dword ptr [esi],edx
805818b0 83e27f          and     edx,7Fh
805818b3 8d0c9530e06880  lea     ecx,nt!RtlpRandomConstantVector (8068e030)[edx*4]
805818ba 8b01            mov     eax,dword ptr [ecx]
805818bc 5e              pop     esi
805818bd 8919            mov     dword ptr [ecx],ebx
805818bf 5b              pop     ebx
805818c0 5d              pop     ebp
805818c1 c20400          ret     4

果然没有一句相对jmp或call……
2008-4-29 23:30
0
雪    币: 722
活跃值: (123)
能力值: ( LV12,RANK:300 )
在线值:
发帖
回帖
粉丝
21
这个源代码只是一个例子,它展示了inline hook的标准作法,或者说“中心思想”:
将被HOOK函数开头代码改为一个远跳,跳到自定义函数开头。
而自定义函数(做一些自己想要的操作之后),实现被HOOK函数开头的N行代码,然后再用一个远跳,跳回原函数第N+1行代码。

而对于未导出的函数,hook的前提是先要定位它的位置。另外,如果不确定函数开头的代码是什么样的,就应该加一个反汇编计算代码长度的函数,然后再copy原函数中的代码。

如果hook的函数比较特殊或比较底层,在其中做操作时,可能引起重入的话,又要再做处理。

然而这个例子显示的是骨架,而以上的枝叶,都是可以在这个基础上,按照实际操作中的特殊需要再进一步完善的。
2008-4-29 23:51
0
雪    币: 197
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
谢谢大家的热心回帖。谢谢sudami的代码。
其实 inline hook 就那点事儿。我最近在搞NP,所以我现在的面临的问题,并不是要inline hook,而是要过别人(NP)的inline hook。

我的另一篇帖子 http://bbs.pediy.com/showthread.php?t=63920
中发布的代码
应该可以对 已经被别人 inline hook 的函数,再inline hook 一遍。
对一个函数的多重 inline hook ,大家有什么高见?
2008-4-30 00:36
0
雪    币: 169
活跃值: (22)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
算了, 不打击学习的精神了.
感觉就是贴代码.  贴的什么呢? 不知道.
2008-7-17 01:42
0
雪    币: 230
活跃值: (149)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
嗯,不错~~ 呵呵
2008-7-20 16:23
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
危险端口关闭工具(蠕虫防范)

下载地址:服务器1

本人翻译. 有不完整地方请多多见量!
2008-7-21 01:05
0
游客
登录 | 注册 方可回帖
返回
//