-
-
[原创] ELF Hook总结与代码实现
-
发表于:
2019-11-17 16:14
11855
-
博客:www.wireghost.cn
Hook,中文又译为“挂钩”或“钩子”。这里可以首先从字面上做了解,钩子是干什么的呢?日常生活中,我们的钩子是用来钩住某种东西的,比如说,鱼钩是用来钓鱼的,一旦鱼咬了钩,钩子就一直钩住鱼了,任凭鱼在水里怎么游,也逃不出鱼钩的控制。同样的,Android、IOS中的钩子Hook也是用来钩东西的,比较抽象的是它是用来钩函数或者变量的。举个例子,Hook钩子钩住键盘事件相关的函数,那么当有任何相应的键盘操作时,通过Hook就能知道用户都输入了些什么,多么形象啊,把老鼠Mouse钩住了,不管你干什么,都逃不过我钩子Hook的手掌心。
掌握ELF Hook,有必要先了解下ELF文件格式,特别是对于符号表、GOT(全局偏移表)、PLT(过程链接表)、重定位表需要有个清晰的认识。至于这部分在之前的博文中就已做了详细介绍。。
So的Hook手法大体来说,一共有3种方式:导入表、导出表及Inline Hook。
前面已经提到过“.rel.dyn”和“.rel.plt”两个段中分别保存了该模块所需要导入的变量、函数符号以及其所在模块等信息,而“.got”和“.got.plt”则是保存着这些变量和函数的真正地址。所以,导入表hook的原理主要就是替换.GOT表中外部函数地址(还有一部分被保存在data数据段,比如使用全局函数指针调用外部函数时)
具体思路为:当用dlopen打开一个so时,实际返回的是一个soinfo结构体,这里已经包含了so的相关信息。之后,直接根据“.rel.plt”重定位表中的offset定位到“.got.plt”,进行修改替换即可。
如果细心观察的话,就会注意到上面的代码是有所遗漏的。它仅针对了直接调用外部函数的情况,当使用全局函数指针调用外部函数时(重定位类型为R_ARM_ABS32),用的是".rel.dyn"重定位表,其下的offset会定位到data段,数据段的该地址下保存着实际外部函数的真正地址。对应实现上,只需补个重定位类型的判断,其余代码都是类似的,将".rel.plt"换成".rel.dyn"即可,有兴趣的同学可以自己动手试试。
导入表 HOOK的本质其实就是"改自身",即修改当前应用进程下的Got表中外部符号地址。所以它的功能是很有限的,不会影响到其他进程。此外,对于通过dlopen 动态获得并调用外部符号这种情形是无效的。
特点:即时生效。因为是直接改的Got表、修改了外部函数的调用地址,所以在进行测试时是hook后可直接看到效果的。。
ELF文件中的符号表有说明该符号为导入符号还是导出符号,这点在linker.c源码中可以看到。linker将so加载到内存后,在最后阶段是有对符号进行重定位的。在重定位过程中,如果发现符号为外部符号,会去解析相应的依赖库,获取外部符号的地址。所以,导出表Hook的原理就是修改要hook的函数所在so中的符号表中的值,并对其进行替换。
具体思路为:用dlopen打开一个so,根据返回的soinfo结构体定位到符号表。在符号表中查找要hook的函数名,并修改该符号的st_value值为NewFunc – BaseAddr(st_value保存的是偏移地址)
导出表Hook和导入表Hook的代码实现其实比较类似,本质都是修改函数地址,但却能起到较好的效果。因为它是直接改的要hook的函数所在so中的符号表,其他库要调用该so中的方法,都会从它的符号表下进行引用,并填充到自身的Got表下,所以能够起到一次Hook,永久替换的效果。当然,其拦截效果还是不如inline这种方式。不过由于inline hook会受到函数字节数的轻微限制,导出表hook也可视为一种对Inline的补充。此外,导出表Hook只能Hook导出的符号,对偏移函数没有办法。
特点:不能即时生效。因为改的是符号表,当前运行的程序已经加载完成,调用外部函数时,是直接走的Got。所以进行测试时,在hook完成后,还需要再loadlibrary一次,让修改过的符号重新导入到Got表。说到这里,其实也能dlopen、dlsym来进行测试,让dlsym来检验是否已修改目标的st_value。。
Inline hook其实就是直接修改函数指令,对代码的调用流程进行替换,它的基本流程如下所示:
这部分的代码实现,个人是直接参考的https://github.com/crmulliner/adbi这个开源的hook 框架。不过,它有个bug,注意到这个问题是在http://drops.wooyun.org/tips/5409放出阿里举办的安全挑战赛的解题思路时(其实了解到adbi hook也是这个时间)。
对adbi hook源码中的这一部分进行修改后,再来分析下它的实现原理。先看看hook.h头文件中定义的hook_t结构体,具体结构如下:
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!