首页
论坛
课程
招聘
[原创]打造自己的HOOK引擎 之二 --- HOOK CHAIN处理
2008-12-24 17:07 10117

[原创]打造自己的HOOK引擎 之二 --- HOOK CHAIN处理

2008-12-24 17:07
10117
打造自己的HOOK引擎 之二 --- HOOK CHAIN处理

本来第二次想做个IDT的HOOK引擎的,但是由于上次那个SSDT的引擎太搓,很多东西没处理好,最严重的问题就是对HOOK链的处理存在问题,安全性太差。

经过几位热心网友的指点,偶对HOOK引擎的理解更深一步,在这里表示感谢。

这次就对HOOK CHAIN的处理提出一些我自己的想法和实现,有一些也仅仅停留在想法上,依我现在的能力还不能做到十全十美,还希望各位提出更好的解决办法。没什么技术含量,高手见笑了。

在论坛搜了下,发现这方面的资料相当贫乏,基本上没有对这个话题进行讨论的主题。这里我相当与做个引子,提出HOOK CHAIN的概念,希望能抛砖引玉。我自己的理解也很有限,希望大家批评指正。

其实HOOK的本质大多相同,我理解的HOOK无非两种:一种我称之为地址替换,像SSDT,IDT,IAT,EAT等等等等的钩子都属于这一种,另外像jmp/call xxx型的HOOK也可以归为这一种,只是这里的地址不是以某种表的形式存在内存中,而仅仅是一个地址,这个地址可以简单的称作HOOK点,选取一个好的HOOK点是另一个重要话题。另外一种HOOK就是内联(inline),这种HOOK灵活性大,不是对地址做手脚,而是直接修改代码,将代码变成地址,尽管理论上可以在任意地方下钩,但是处理起来会有些不同,管理也会比较麻烦。

尽管存在不同形式的HOOK,但是有一点却是相同的,那就是所有的HOOK都会面临多重HOOK的情形,多重HOOK形成HOOK链,于是对HOOK链的处理便成了每种HOOK都必须处理的问题。

首先还是从上一篇的SSDT的HOOK说起吧 在这里我对SSDT HOOK做了几幅图,讨论起来更方便些吧
我们看第一张图 作为最原始的SSDT 服务函数的地址我依次用数字代替



下面我们对服务函数3下钩,下钩的函数名为hook_1,hook_1会将服务函数3的原始地址保存起来,即有original = 3,需要的时候会调用原始的函数,即在新的HOOK例程中会有这样的语句call original 即 call 3。另外不难理解,hook_1的卸载例程里需要做的事情就是将服务函数3的地址替换回去,用符号★代表SSDT中服务函数3的地址,即有★ = original = 3。



当然如果只有这么一个钩子,系统的所有安全责任由它负责就行了,那就不存在我们所说的安全隐患了。但是往往情况不是这样,对于同一个地方,你HOOK,我HOOK,他也HOOK,但是安全性呢,你管你的,我管我的,他管他的,到最后整体的安全性没有人来负责了,BSOD了应该找谁?
所以HOOK是存在风险的,下面就依次把我们的HOOK链建立起来,并提出几个存在的问题。
譬如这时另一个叫做hook_2的函数也想对服务函数3下钩,当然他可以检测出这个已经存在的HOOK的,但是检测出来了又能怎么样呢?有三种方法:第一,就此罢手,不钩了。这是最简单的方法,也最安全,但是很显然,这个多不公平啊,你想啊,同样在RING0,为什么别人就能钩我却不能钩,就因为别人先我一步?想想就不爽。而且如果那是一个很好的HOOK点,就这样放弃未免太可惜了。第二种方法,把他卸了,安装我的钩子。这种想法很简单也很暴力,相当不和谐,而且仍然存在问题,如果每个人都这样,挂钩前就把别人的卸了,别人挂钩还不是可以把我们的钩子给卸了!一个解决方法是加上定时检测,这个应该是个解决方法,后面再做讨论。第三种,不管他,我也钩上,卸载时把他还原,调用原来的函数呢就调用他。这样就形成了链,于是就有了今天的话题。

我们假设hook_2是按第三种方法对服务函数3下钩的,得到下面的示意图



然后hook_3同样要对这里下钩 得到下图



到这里钩子链已经显现出来了,但是很显然这是个单链,甚至单链都称不上。这里的链只是形象上的说法,并不是传统意义的链表,链表中通过NextNode指向下一结点,HOOK链而是通过call next_hook将所以的Hook_Routine形成一个链状结构。

我们来分析一下这个HOOK链的特点,首先一个显著的特点是:谁最后下钩,谁就最先被调用。究其原因是因为我们的HOOK都是从SSDT中的某个欲下钩的地方开始的,我们不能从HOOK链中的某点进行下钩,也就是说HOOK链不存在插入结点算法。HOOK链的另一个特点是链结构不稳定,随时都有可能出现某个结点从链中断掉,而且前面的结点并不知道,导致前面的结点仍然指向那个断掉的结点,从而导致安全问题。也就是说HOOK链也不存在删除结点算法。

这样分析下来,HOOK链的根本问题就在于不能实现或很难实现链表的两种基本算法,插入和删除。回忆一下数据结构课程中学习的链表,我们就会发现原因可以归结为一点,无论是插入和删除都需要遍历链表,所以如果实现HOOK链的遍历,那么HOOK链的管理就会大大简单化。

下面再从另外三个角度并对照上面的hook_3那幅图对HOOK链进一步讨论。
第一:卸载例程.
        这个最简单的处理方法就是写回SSDT中被HOOK的那项,然后卸载掉。存在的问题就是上面讲的,上一个HOOK例程还是调用这个函数,造成BSOD。譬如hook_2卸载了,但是hook_3的Hook Routine里仍然还是call hook_2。另外一种方法,依赖上面的遍历算法,遍历到上一HOOK例程,修改指针指向下一HOOK例程,就像从单链表中删除一个结点一样。譬如hook_1要卸载,可以从SSDT中找到hook_3的地址,再从hook_3的内存空间找到hook_2的地址,再从hook_2的内存空间找到call hook_1修改为call 3,但是,这种方法很难实现,如果能实现,对检测钩子的存在意义应该是重大的。
第二:调用原函数.
        当然这是针对需要调用原函数进行讨论的.如果不需要对原函数进行调用,显然不存在这个问题.一个保险的方法是自己编写原服务函数,但是这样也就失去了链这个概念,不用去调用下一个HOOK例程了。还有一种方法简单的方法,调用原函数前对SSDT做检查,如果SSDT中保存的是我的地址,显然没有新的HOOK加载也没有旧的HOOK卸载,即调用下一HOOK例程。如果发现SSDT中的表项已经被修改了,这个时候无法判断是有新的HOOK加载了,还是有旧的HOOK卸载了,保险的方法是调用最原始的服务函数,可以通过ntoskrnl.exe获取最原始的服务函数地址。这样下来,我们分析下这个HOOK链,hook_1检测到hook_2加载,便开始call 3,(3是最原始的服务地址)。而当hook_2检测到hook_3加载,也开始call 3,然后hook_1又卸载了,hook_3检测到以后,也开始call 3, 如此而来,整个HOOK链已经七零八落,谈不上链了。
第三:保存原函数地址
        我们可以看到,对一个钩子例程来讲,最简单的方法是将原函数地址保存起来,如果需要调用下个钩子例程,即call这个地址。对这个钩子,他不知道这个地址是合法还是非法的。现在想,如果每个钩子例程都将原函数地址保存在统一的区域,在这个区域对各个地址进行管理不是就简单了吗?但是怎么让这个区域起到作用,这个是我想到的另外一个解决方案,使用HookMgr。

最后对上面提到的两种解决方案画两幅草图,实现起来还是有很多问题,我在这里只是提出一些思路罢了,如果您有更好的方法,欢迎联系我,也可以跟帖讨论。能力有限,错误之处还请见谅。

第一种方案:定时检测



这种方案已经跟HOOK链无关了。而是和CPU的分时复用原理有些类似,将被HOOK的地方理解为CPU,每隔一段时间即被HOOK修改一次。和CPU不同的是,CPU是主动分配时间片,这里是各个HOOK去抢CPU,譬如hook_1每隔xms改一次,hook_2每隔yms改一次,hook_3每隔zms改一次,有可能会出现同时修改的情况,所以修改前要上锁。

不足之处是每个HOOK的时间都不一样,不便于管理。而且系统的开销可能很大。或许可以设计一个针对每个HOOK的时间片管理器。

第二种方案:钩子管理器



如上图所示,在每个HOOK点上建立一个钩子管理器(HookMgr),钩子管理器负责钩子例程的创建和退出,集中管理各种钩子例程。原理感觉和SetWindowsHook差不多,我没有深入研究过,偏颇之处还请见谅。当一个钩子例程创建时,可以向HookMgr发出请求,或者是某个钩子修改HookMgr所在的HOOK点时,会被HookMgr检测到,然后在管理器中自动创建HOOK链进行管理。当钩子例程卸载时,同样可以发出卸载请求,或者是某个钩子卸载时,被HookMgr检测到,HookMgr便删除相应的钩子结点。而对于调用下一个HOOK例程,可以直接调用Mgr提供的接口CallNextHook。

管理器的思路很明晰,但处理起来会面临很多很多问题,偶的能力只能分析到这里了,要实现这个钩子管理器,不是我这个初学者的能力所及的。。。

好了,分析就到此为止了。
现在才意识到钩子的管理也有这么多的问题,要编写安全的钩子,仅仅学习钩子的原理技术还是远远不够的。

本人能力有限,失误之处还望批评指正。

第五届安全开发者峰会(SDC 2021)10月23日上海召开!限时2.5折门票(含自助午餐1份)

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (12)
雪    币: 1
活跃值: 活跃值 (88)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
美丽破船 活跃值 5 2008-12-24 18:00
2
0
沙发`~~~~
雪    币: 217
活跃值: 活跃值 (24)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
heretic 活跃值 2008-12-24 19:42
3
0
一般来说管理hook是指管理你自己的hook(你自己也可能多次hook,如果你的构架比较复杂,不止是1个驱动的话)。人家的hook你是没法去管的(是指inline这些,SSDT方式单一,倒是可以管下人家的)。所以,一般来说你应该有个统一hook entry,你对系统来说,只hook一次,永远不要unhook,然后在这个hook entry里面来dispatch你自己的hook1, hook2, hook3。。。这样,不管你自己hook还是unhook,对于系统来说都没有变化,不会与其他软件发生冲突。
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xiaobenmao 活跃值 2008-12-24 21:09
4
0
看得俺一头雾水,看来俺得多向各位大哥学习一下了
雪    币: 6
活跃值: 活跃值 (12)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
easystone 活跃值 1 2008-12-24 21:35
5
0
一般来说管理hook是指管理你自己的hook(你自己也可能多次hook,如果你的构架比较复杂,不止是1个驱动的话)。人家的hook你是没法去管的(是指inline这些,SSDT方式单一,倒是可以管下人家的)。所以,一般来说你应该有个统一hook entry,你对系统来说,只hook一次,永远不要unhook,然后在这个hook entry里面来dispatch你自己的hook1, hook2, hook3。。。这样,不管你自己hook还是unhook,对于系统来说都没有变化,不会与其他软件发生冲突。


这里说的统一的hook entry应该怎么实现?
我的hook1,hook2,hoo3 。。调用后对系统没有变化,是不是就是说我的钩子全部通过hook entry来实现,那是不是要在hook entry里一次性把所有的hook点都钩上?
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yryznet 活跃值 2008-12-24 22:03
6
0
你得MS¥支持就好
雪    币: 141
活跃值: 活跃值 (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
XSJS 活跃值 2008-12-24 23:40
7
0
顶假牛一个!
雪    币: 217
活跃值: 活跃值 (24)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
heretic 活跃值 2008-12-25 01:31
8
0
也就是,你写到SSDT里的,或者inline转跳的hook entry函数并不是真正执行功能的地方,他只是做dispatch,真正的的功能hook函数由你的hook manager管理。每个要hook的函数都有一个entry函数,这个一旦hook了就不要卸载了。
雪    币: 478
活跃值: 活跃值 (640)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
sudami 活跃值 25 2008-12-25 06:50
9
0
LS要说的就是在KiFastCallEntry里面做dispatch嘛,一些安全软件是这样做的...
雪    币: 388
活跃值: 活跃值 (387)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
wowocock 活跃值 1 2008-12-25 08:30
10
0
lz的想法不错,不过解决不了根本,所以MS在VISTA X64以后引入PATCH GUARD,除了恶意攻击以外,基本天下太平了.
雪    币: 459
活跃值: 活跃值 (54)
能力值: ( LV12,RANK:420 )
在线值:
发帖
回帖
粉丝
qihoocom 活跃值 9 2008-12-25 10:23
11
0
PATCH GUARD是没用的,想天下太平是不可能的
雪    币: 6
活跃值: 活跃值 (12)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
easystone 活跃值 1 2008-12-25 14:58
12
0

额,目前还没想过做那么深入哦
刚才偶然在论坛上发现海风月影以前做过的一个HookApiLib 只是做了inline的
这才发现这个叫引擎有点过 叫做LIB还差不多
怪不得上次大菜一号说ssdt hook lib 当时还没反应过来
真是一语中的啊。。。
雪    币: 217
活跃值: 活跃值 (24)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
heretic 活跃值 2008-12-25 18:32
13
0
不是hook KiFastCallEntry。。。。我说的是hook管理框架,不是是 hook这个事情本身。
现有的hook方法就那么一些,人人都知道了,有啥子讨论头嘛。
游客
登录 | 注册 方可回帖
返回