一、函数抽取
在 Android中实现「类方法指令抽取方式」加固方案原理解析 博客中 , 首先对 Dex 字节码文件的结构进行了分析 , 函数抽取 , 主要是将 Dex 字节码文件中的函数进行抽取 , 然后在运行时再进行恢复操作 ;
抽取函数流程如下 :
① 解析 Dex 字节码文件 : 参考 https://github.com/fourbrother/parse_androiddex 项目 , 解析 Dex 字节码文件 , 将代码指令数据读取到 map 结构体中 , 键 Key 为方法签名信息 , 值 Value 为 代码结构 ; 通过 Key 方法签名数据可以获取 该方法对应的 代码结构体 数据 ;
② 确定要抽取的函数 : 根据 完整的 包名.类名 类路径 以及 方法签名 ( 方法名 + 方法参数 ) , 可以唯一确定 Dex 字节码文件中的 函数签名信息 ;
③ 查找要抽取的函数信息 : 遍历 Dex 字节码文件 , 根据 方法签名 和获取 对应函数 的 代码结构体数据 , 该结构体中存储了方法指令的 偏移地址 和 指令个数 ;
④ 使用空指令集替换函数指令 : 使用空指令集 ( 数据全为 0 的数组 ) 填充要抽取的函数指令所在位置 根据 偏移地址 和 指令个数 定位函数指令集位置 ;
⑤ 计算校验值和签名 : 替换了 Dex 字节码文件中的一些数据后 , 文件的 CRC 校验值 和 SHA 签名 需要重新进行计算 , 计算完毕后 , 将校验值和签名写会到 Dex 文件中 ;
函数抽取后 , 需要将替换的函数指令记录下来 , 之后函数还原的时候 , 还要将其恢复回去 ;
二、函数还原
函数还原流程参考
- 【Android 逆向】Dalvik 函数抽取加壳 ① ( Dalvik 下的函数指令抽取与恢复 | dex 函数指令恢复时机点 | 类加载流程 : 加载、链接、初始化 )
- 【Android 逆向】Dalvik 函数抽取加壳 ② ( 类加载流程分析 | ClassLoader#loadClass 分析 | BaseDexClassLoader#findClass 分析 )
- 【Android 逆向】Dalvik 函数抽取加壳 ③ ( 类加载流程分析 | DexPathList#findClass 函数分析 | DexFile#loadClassBinaryName函数 )
- 【Android 逆向】Dalvik 函数抽取加壳 ④ ( 类加载流程分析 | native 函数查询 | dalvik_system_DexFile.cpp#defineClassNative函数)
- 【Android 逆向】Dalvik 函数抽取加壳 ⑤ ( 类加载流程分析 | Class.cpp#findClassNoInit 函数 | DexFile.cpp#dexFindClass 函数 )
从类加载流程开始分析 , Dex 字节码中的 类 使用前 , 要先进行加载 , 链接 , 初始化操作 ;
这里我们选择将 函数进行还原的时机为 使用前 , 也就是 加载 链接 初始化 过程中的 函数 , 都是空的 , 只有在函数真正使用的时候 , 才会将 被抽取的函数替换回去 ;
恢复的时机一定要保证在 函数调用 前 恢复函数 ;
这样直接将 整体加固 的 字节码文件 从内存中 dump 出来 , 也无法得到真正的字节码文件 ;
相关参考博客
函数指令 抽取 : 进行函数抽取加壳 , 首先要熟悉 dex 文件的结构 , 需要定位 dex 字节码文件中 , 函数指令 的偏移地址 ; 将 dex 文件中的函数指令 , 先抽取出来 ;
- 参考博客 : Android中实现「类方法指令抽取方式」加固方案原理解析 , 作者 姜维 , 同时也是《Android应用安全防护和逆向分析》 作者 ;
- Android逆向之旅—解析编译之后的Dex文件格式 : 函数抽取涉及到要修改 Dex 字节码文件 , 因此必须熟悉 Dex 字节码文件的数据格式 ;
函数指令恢复 : 可以选择在 下面的 2 2 2 个时间点 , 恢复函数指令 ;
- 类加载之前恢复 : 在类加载到内存之前 , 将之前抽取出来的指令 恢复 回去 ; ( 比较简单 ) ;
- 参考博客 : Android中实现「类方法指令抽取方式」加固方案原理解析 , 作者 姜维 , 同时也是《Android应用安全防护和逆向分析》 作者 ;
- 运行时恢复 : 函数运行时 , 通过 HOOK 修改运行时的函数的指令逻辑 ;
- 参考博客 : Android免Root权限通过Hook系统函数修改程序运行时内存指令逻辑 , 作者 姜维 , 同时也是《Android应用安全防护和逆向分析》 作者 ;
- 推荐的 HOOK 框架 : https://github.com/ele7enxxh/Android-Inline-Hook , 注意该框架只支持 32 32 32 位模式 ;