对抗静态分析——运行时修复dex
本文来源:i春秋社区-分享你的技术,为安全加点温度
零、写在前面
这个系列本来题目想写对抗反编译,可是想想对抗反编译的这个范围有点大,总结如下
灵魂作图
<ignore_js_op>
自己比较熟悉的是静态分析,所以就从这里入手吧,省的吹大了,挖了坑填不上那就不好了。当然也会写些动态分析的东西。
废话少说,开始吧,最近又把脱壳拿出来看了,就从这里开始吧
一、理论(总要解释一下)
壳是一个比较大的概念,发展的比较迅速。未来(或者现在?)加壳的主流会逐渐变为第四代壳,也就是VMP,各个厂商自己搞一套解释器,但是这种方式对运行效率影响比较大(有多大我没有详细的数据,也可能现在已经拿出来的VMP加壳方案已经解决了很大程度上的效率问题?这个不清楚)。
这篇讲的是一种采用比较多的办法,在运行时对dex进行修改。针对源APK(也就是真正运行的APK),将dex文件中的某部分指令提取出来,保存为一个文件。然后将dex文件中的这部分指令修改为错误的字节码,比如0x00 0x00 0x00 0x00 0x00 。。。运行时,壳程序将这部分指令修复。修复的方法简单点可以直接替换回去,如果复杂点可以在dex文件的范围外new一块区域,然后将原本指向这部分指令的指针指向new出来的区域(也就是在dex外部),这样即便你通过动态分析对dvmDexFileOpenPartial这样的API下断能dump出dex文件,还是没有办法正确反编译,因为正确的指令还是没有加入进来。
整个过程分为两个阶段
第一阶段:提取、替换正确的dex中的指令
第二阶段:运行时修复替换之后错误的dex文件
1、定位——提取——替换
首先,在dex中定位code的位置,我们看看android源码是怎么写的
源码位置dalvik\libdex\dexFile.h
[AppleScript] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
/ *
* Direct - mapped "code_item" .
*
* The "catches" table is used when throwing an exception ,
* "debugInfo" is used when displaying an exception stack trace or
* debugging. An offset of zero indicates that there are no entries .
* /
struct DexCode {
u 2 registersSize;
u 2 insSize;
u 2 outsSize;
u 2 triesSize;
u 4 debugInfoOff; / * file offset to debug info stream * /
u 4 insnsSize; / * size of the insns array , in u 2 units * /
u 2 insns[ 1 ];
/ * followed by optional u 2 padding * /
/ * followed by try_item[triesSize] * /
/ * followed by uleb 128 handlersSize * /
/ * followed by catch_handler_item[handlersSize] * /
} ;
|
这个结构,从上到下分别表示
~~~~~~~~~~~~~~
该函数寄存器的数目
传入的参数个数
调用其他函数时需要的参数个数
try结构的数目
debug信息的偏移
指令列表大小
该函数的指令
~~~~~~~~~~~~~~
看注释,这个结构我们一般不叫它DexCode,而是code_item(关于各种item,在深入Androguard源码中有解释)
而指向它的指针,位于encoded_method结构中的codeoff(源码位置dalvik\libdex\DexClass.h)
[AppleScript] 纯文本查看 复制代码
1
2
3
4
5
6
|
/ * expanded form of encoded_method * /
struct DexMethod {
u 4 methodIdx; / * index to a method_id_item * /
u 4 accessFlags;
u 4 codeOff; / * file offset to a code_item * /
} ;
|
那么这个DexMethod来自于哪里呢?在这里(同一文件下)
..............................................略