-
-
[原创]基于LIEF实现InlineHook
-
2021-3-10 17:31 9032
-
前言
之前用 LIEF 最多也就是添加一个依赖so,偶然细读了一下 LIEF的文档 ,意外发现他还有一些比较好玩的操作,比如合并段,新增导出函数,修改导出函数之类的,结合一下inlinehook,于是就有了这篇文章
简介
使用ndk编译提供代码so,再使用lief合并代码进原始so,最后在对汇编代码稍作修改即可完成最原滋原味的inlinehook
具体操作
lief的简单使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | import lief def swap(obj,sym1,sym2): s1 = obj.get_symbol(sym1) s2 = obj.get_symbol(sym2) temp = s2.name s2.name = s1.name s1.name = temp if __name__ = = '__main__' : lib_src = lief.parse( "libnative-lib.so" ) lib_code = lief.parse( "libcodeProvider.so" ) print (lib_code) # 互换导出函数地址 swap(lib_src, "Java_com_lzy_lieftest_MainActivity_Test1" , "Java_com_lzy_lieftest_MainActivity_Test2" ) # libcodeProvider.so 的第二个段(包含.text节)添加进 libnative-lib.so segment_added = lib_src.add(lib_code.segments[ 1 ]) # 合并进来的两个函数依旧为其添加导出函数(方便我们查找) code_test3 = lib_code.get_symbol( "test3" ) code_innerCallFunctionRep = lib_code.get_symbol( "innerCallFunctionRep" ) lib_src.add_exported_function(segment_added.virtual_address + code_test3.value, "test3Rep" ) lib_src.add_exported_function(segment_added.virtual_address + code_innerCallFunctionRep.value, "innerCallFunctionRep" ) lib_src.write( "libnative-lib1.so" ) |
由上脚本合并so的代码段
下面介绍一下三种inlinehook姿势
使用BL替换BL
nop之间的代码就是我们正式的hook代码(ndk编译的那部分代码),这部分代码如果使用到got表的函数需要手动去修正一下,比如上截图的日志函数
这么操作的话可拓展性就非常的大,多余的参数零时变量什么的,你都可以进入hook函数的时候去申请更大的栈空间用来存放,退出的时候也记得恢复
使用B替换
在跳走的empFunction中我们就有空位随意的写入汇编指令
跳走之后被替换部分的汇编跳转记得手动修复一下跳转地址
上文中举例的Demo so很小,所以直接就用bl/b跳转,但是这里需要注意Arm的B系列指令跳转范围只有±32MB,Thumb的B系列指令跳转范围只有±256字节,遇到so比较大的情况,考虑使用 add pc 来进行跳转
另一种跳转(ldr pc)可以参考inlinehook的这篇文档http://ele7enxxh.com/Android-Arm-Inline-Hook.html
使用 add pc 替换任意位置
这里简单的讲解一下0xdf34的值是怎么算的:
代码执行到0xdf30时,pc的值应该是等0xdf38,所以0xdf34位置的值应该是 0x40b3c - 0xdf38
拓展
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | extern "C" void injectLog(){ void * v_r0; void * v_r1; void * v_r2; void * v_r3; void * v_r4; void * v_r5; void * v_r6; void * v_r7; void * v_r8; void * v_r9; void * v_r10; void * v_r11; void * v_ip; void * v_sp; void * v_lr; void * v_pc; asm( "mov %0,r0\n" "mov %1,r1\n" "mov %2,r2\n" "mov %3,r3\n" "mov %4,r4\n" "mov %5,r5\n" "mov %6,r6\n" "mov %7,r7\n" "mov %8,r8\n" "mov %9,r9\n" "mov %10,r10\n" "mov %11,r11\n" : "=r" (v_r0), "=r" (v_r1), "=r" (v_r2), "=r" (v_r3) , "=r" (v_r4), "=r" (v_r5), "=r" (v_r6), "=r" (v_r7), "=r" (v_r8), "=r" (v_r9), "=r" (v_r10), "=r" (v_r11) ); asm( "mov %0,ip\n" "mov %1,sp\n" "mov %2,lr\n" "mov %3,pc\n" : "=r" (v_ip), "=r" (v_sp), "=r" (v_lr), "=r" (v_pc) ); LOGD( "inject register log : \n" "%p\t%p\t%p\t%p\n" "%p\t%p\t%p\t%p\t%p\t%p\t%p\t%p\n" / / "%p\t%p\t%p\t%p\n" ,v_r0,v_r1,v_r2,v_r3 ,v_r4,v_r5,v_r6,v_r7,v_r8,v_r9,v_r10,v_r11 / / ,v_ip,v_sp,v_lr,v_pc ); } |
总结
用到lief做这样的inlinehook,目前还没有发现有什么好的实际用处,但是可以帮我们用实践去更好的理解inlinehook的原理,很多东西看着简单但是一操作起来就踩坑,实践大于理论,有兴趣的伙伴可以试试
附件(APK DEMO):
https://pan.baidu.com/s/176tG65p8v7s9Bzc2eiO_nQ
tcui
[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界