首页
社区
课程
招聘
[原创]记一个通用API Hook的产生.
发表于: 2009-3-7 01:38 13997

[原创]记一个通用API Hook的产生.

2009-3-7 01:38
13997

菜鸟文章, 欢迎高手指正错误之处~~

前几天一个朋友要做一个dll, 要求实现对所有的ring3 API实现拦截.
也就是通用了. 如下图所示:


他本来是这样做的, inline Hook 跳到处理函数,在处理函数里面,我们获得控制权,
做一些事情之后,要调用原函数, 他原本是打算取得控制权后先恢复原函数,
再把堆栈里面的参数重新压栈一遍,在call原函数, call完之后, 再重新修
改前5字节继续监视的.不过发现那样不能确定参数的个数, 我和朋友讨论
了会儿,一起讨论了一下几种方法:

1. IAT Hook.放弃 , 有局限性, 它只能Hook被导入的函数, 而且还要
求IAT是一份干净的未被污染的,否则Hook不到或者Hook到了他人的钩子.

1:搜索ret N指令. 硬编码.确定参数个数. 放弃, 太麻烦,而且容易误操作,因为
  C2 XX 00 ,XX%4=0, XX/4<=10 这个条件还是太宽.难免误操作,而且麻烦.

2:融入一个反汇编引擎进去,搜索ret N 得到N, 杀猪用牛刀,更不值.

3:EAT Hook了,放弃. 在ring3下要实现IAT Hook,那就要改导出表了,
    可是,可是, exe一加载的时候就从EAT中得到了地址写入了IAT, 从EAT被
   PE装载器装入内存到PE装载器写地址到IAT这中间似乎没有空隙时间,
    所以ring3下的EAT hook 我一直没实现了. 可能我认识太肤浅了~~

4:如果不是系统库,我们先改写磁盘上的文件中的EAT再被导入那应该可以
   归为EAT hook,呵呵~~   可惜要挂钩的是系统库,放弃.

5:dll jack. 这种方法比较麻烦, 还要自己重新写一个dll实现每个函数的stub, 而且
   还要目标库是可替换的, 这里系统核心库不好替换, 放弃.

6: 复制一份核心库, 映射至一个新内存地址, 我们在处理函数中处理完信息后,直接jmp过去.
    因为栈中正好保存的是参数和eip,所以直接jmp过去就OK, 这样成功的调用了原函数功能,
    也保持了对原函数的继续监视.



所以最终我选择了6这种方法, 其实这种方法在ring0一下也是有用的, 比如在Ring0 中,

因为很多AV Hook了 SSDT使得程序员一般不喜欢使用ZwXxx函数, 而喜欢使用Native API,

   不过有的Native API 并未被到处, 这时, 大牛们一般都是得到ntoskrnl导出的
  符号KeServiceDiscriptorTable的地址, 然后计算其在文件中的偏移,在读取原始的SSDT表,
   再把读取的地址加上实际装在地址与期望地址的差值.  我在此想,能不能直接复制
  一份ntoskrnl.exe然后映射内存,得基址,得原始表,得另外一个新的ZwXxx函数?? ?
   当然这个实验我马上就要去做了, 如果有人知道答案,也感谢分享.

   PS.第一次发帖, 排版和表达都欠缺, 各位大大多包含 ~~ 谢谢.


[招生]系统0day安全班,企业级设备固件漏洞挖掘,Linux平台漏洞挖掘!

上传的附件:
  • 1.jpg (11.64kb,1098次下载)
  • 2.jpg (7.45kb,1096次下载)
收藏
免费 7
支持
分享
最新回复 (19)
雪    币: 264
活跃值: (145)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
[QUOTE=;]...[/QUOTE]
沙发,学习了。
2009-3-7 10:25
0
雪    币: 229
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
不用这样复杂,不需要复制核心库,就可以办到

还有第7种方法
2009-3-7 11:56
0
雪    币: 1708
活跃值: (586)
能力值: ( LV15,RANK:670 )
在线值:
发帖
回帖
粉丝
4
倒数第六行
  不过有的Native API 并未被到处, ........
应该是
   不过有的Native API 并未被导出,.......
这里有个笔误.....
2009-3-7 12:44
0
雪    币: 1450
活跃值: (35)
能力值: (RANK:680 )
在线值:
发帖
回帖
粉丝
5
请教suisuisui ,第七种方法是什么? 谢谢指教.

谢谢LS对笔误的指出.
2009-3-7 13:40
0
雪    币: 229
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
第七种方法实际上是老方法,很多年前就有了,从时间上算,传统inlinehook后很快就出现的改进版,但奇怪的是好像大家对它漠视了

传统inlinehook,就是先hook,然后为调用原函数再次unhook,为得到控制权再hook

改进版,就是先拷贝被hook的指令,然后再hook,这样只需要hook一次
2009-3-7 13:55
0
雪    币: 370
活跃值: (15)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
7
希望早日修成正果,
HOOK UNHOOK
2009-3-7 15:24
0
雪    币: 251
活跃值: (25)
能力值: ( LV9,RANK:290 )
在线值:
发帖
回帖
粉丝
8
在分析下面的病毒时也分析出一个通用的hook方法
http://bbs.pediy.com/showthread.php?t=79363
2009-3-7 17:46
0
雪    币: 1450
活跃值: (35)
能力值: (RANK:680 )
在线值:
发帖
回帖
粉丝
9
你怎么确定拷贝多少字节了? 指令截断也是个问题啊 ,?
虽说大部分的函数都是mov edi,edi, push ebp开头的, 但是这种方法还是不通用. ntdll库中
导出的函数就不是这种特征开头的. 难不成还弄个反汇编引擎进来? 那样就不值了.
2009-3-7 19:31
0
雪    币: 1450
活跃值: (35)
能力值: (RANK:680 )
在线值:
发帖
回帖
粉丝
10
这个还是最传统的inline hook了, 该病毒最后还是要恢复指令.

其实如果针对某些函数hook的话, 利用MS的自己留下的小后门
5 个nop加mov edi,edi 可以实现比较巧妙的inline hook--
短jmp 加 长 jmp到我们的代码, 然后跳回原地址+2处, over.
2009-3-7 19:38
0
雪    币: 229
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
现在反汇编引擎很常见了,一个函数就可以解决,没有想象中那样复杂,相反很简单
2009-3-7 21:14
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
几年前用过MS的trampoline技术,是个detours的的库,印象中有源码。刚才google了一个介绍http://blog.csdn.net/xoyojank/archive/2008/04/03/2248190.aspx
2009-3-7 23:27
0
雪    币: 1450
活跃值: (35)
能力值: (RANK:680 )
在线值:
发帖
回帖
粉丝
13
恩, 同意,反汇编引擎是不难.  但要保证指令集齐全就需要一大堆数据而已,  
不过也是一种不错的方法.
2009-3-8 00:02
0
雪    币: 2067
活跃值: (82)
能力值: ( LV9,RANK:180 )
在线值:
发帖
回帖
粉丝
14
楼上还是不了解
2009-3-8 00:05
0
雪    币: 1450
活跃值: (35)
能力值: (RANK:680 )
在线值:
发帖
回帖
粉丝
15
其实我的意思是不使用第三方引擎库, 而是自己实现.
指令种类这么多, jmp , mov,push 等等, 那需要对应的数据就应该也有一些了.
应该可以把我们的指令字节序列理解为前缀编码吧 ? 不太清楚故有此疑问.

算了,我还是抽时间找份反汇编引擎代码自己好好看看,  谢谢各位的指导, 非常感谢 .
2009-3-8 01:29
0
雪    币: 229
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
想得太复杂了,我们需要的只是反汇编引擎的一部分功能,也就是指令的长度,

不用考虑具体是什么指令,我们需要的的反汇编引擎并不是一个完整功能反汇编引擎
2009-3-8 08:00
0
雪    币: 225
活跃值: (293)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
放个样品或代码
2009-3-13 16:41
0
雪    币: 217
活跃值: (68)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
18
EAT HOOK 时机在哪里呢 RING3 是个问题
2009-9-20 22:43
0
雪    币: 522
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
19
现在的一些专门用于HOOK的反汇编引擎 可以很方便的计算指令长度 函数长度
还可以检测某指令是否需要依赖当前环境 (类似JMP CALL 之类,具体地址还需根据当前上下文计算)  

只需要1个不到20K的头文件  编译后 对程序体积基本没影响
2009-9-22 16:02
0
雪    币: 224
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
最近刚写了一个
先是一个宏用来生成一个 代理裸函数
裸函数的开头是个call真正的处理函数 然后后面n个nop
至于是否要处理堆栈其实只要使用不同的函数约定可以不处理堆栈只要你别去改里面的内容
nop用于一会hook补全被冲掉的代码
改写代码和补代码都是配合反汇编引擎的
然后碰到相对跳转的代码自己重新计算下地址就ok 理论上可以实现任意位置hook
2009-9-29 23:27
0
游客
登录 | 注册 方可回帖
返回
//