菜鸟文章, 欢迎高手指正错误之处~~
前几天一个朋友要做一个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.第一次发帖, 排版和表达都欠缺, 各位大大多包含 ~~ 谢谢.
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课