(1) GOT_HOOK
(2) LDPRELOAD_HOOK
(3)
INLINE_HOOK
(4)
异常HOOK
(5) ELF依赖库篡改注入
(6)
LINKER_HOOK
(7) UNICOR仿真器HOOK
(8) 实现代码
···HOOK原理
···
:
篡改导入表中存储的,外部符号地址。
···
检测手段
···
:
(1)硬编码记录导入符号在外部SO中的偏移值,计算外部SO的模块基址相加后得到地址,与GOT表项值进行对比。
(缺点是外部SO可能更新地址发生变化)
(2)将硬编码改为动态解析,使用dlsmy()函数或自己实现地址解析后得到地址,与GOT表项值对比。
(没有第一种的缺点,灵活一些)
(3)一般在链接后GOT表值不会发生改变,可在初始化完成时,使用前面两个方法逐个校验,然后整体计算此时的GOT表的HASH值,
在后期运行时进行HASH校验。
(相比逐个校验,提高了执行效率、代码动作更小、增加了隐蔽性,甚至还可选择MD5 CRC以外的迷你HASH、或跳跃字节校验HASH)
···
实现 ···
:
有了GOT项下标,符号名,所属库名,再过滤出哪些需要检测的重点GOT项,即可实现检测。
···
HOOK原理
··· :
我没有实际测试过这种HOOK,
但可以想到,当导入了虚假的导入函数,GOT表项值会和真正的值不同
和GOT_HOOK表现的结果差不多。
··· 检测手段 ··· :
这样的话,检测LDPRELOAD_HOOK就类似检测GOT_HOOK
可以使用检测GOT时的第一种硬编码方法,
记录导入函数在导入SO中的偏移量然后加基址进行校验。
对于无法获取硬编码偏移量的系统库呢,
比如导入了虚假的fopen什么的,
我觉得可以预设一个重点库重点函数名单,
比如弄一个libc.so的IO之类的高频函数列表,
手动算偏移来解决。
···
HOOK原理
··· :
通过篡改函数的指令内容实现,
应该是最为通用有效的HOOK手段,
可以想到,通常的HOOK框架与工具,
最后应该都会通过这种原理来实现。
去检测框架特征肯定不如检测INLINE_HOOK有效,
就是搞起来会比较麻烦。
··· 检测手段 ··· :
计算一份函数体的HASH,运行时/调用前/对被调函数做完整性校验。
原理并不复杂,但实际工程有很繁琐的问题,场景对灵活性要求很多,
例如:
A
: 怎么确定哪些函数需要做HASH检测?
(人为设定?静态分析?动态沙箱统计?)
C : 什么时机做检测?如何在没有源代码的情况下插入检测代码,做到运行时每次调用前都会执行校验逻辑?
(
方案:
基于静态动态分析的结果进行HOOK?或者直接VMP?)
B
: 这些函数有的是非导出没有符号或是C++名称粉碎的,怎么获取它们的地址范围?
(
方案:
全部函数都计算HASH一把梭?)
D
: 如何跟壳与进行结合?
(
方案:
例如VMP?)
E: 准备的函数HASH数据存储在哪?
(
方案:
把检测逻辑单独写成一个库,HASH数据也放库里?放在外部配置文件中?在被检测库开辟的BUFFER中?)
F: 系统库没法提前知道HASH,被INLINE_HOOK了怎么检测?
(
方案:
把导入库的libcso符号替换为自己静态编译的libc内容?预设一份高频系统库函数名单在函数体中查跳转特征?)
G: 被检测的库更新了怎么办?
··· 实现 ··· :
基础的信息是函数所属库名称、函数的起始结束地址、函数得HASH值
··· HOOK原理 ··· :
我没有实际测试过这种HOOK手段,
不过看到异常HOOK也会篡改函数指令内容,
所以检测异常HOOK可以使用检测INLINE_HOOK的方式,
应该是这样的。
··· HOOK原理 ··· :
修改ELF中的DYNAMIC结构,
添加一个DT_NEEDED,
从而增加额外的导入SO
··· 检测手段 ··· :
篡改内容的这种,都可以做完整性校验。
也是提前计算好SO的关键区段的HASH,
运行时再次计算来对比,校验时机的问题,和INLINE_HOOK类似。
(感觉吧被注入这种事避免不了的,
别人HOOK我的代码还能检测检测,
别人想往进程里加载SO这个机会可太多了,
不改ELF也有N种方法,没什么办法)
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2020-5-13 06:08
被爱吃菠菜编辑
,原因: