某国产DEX加固原理

Intro

这个加固是来自国内某个公司的作品,虽然在强度不是太高,但思路却不错,很好的平衡了性能和保护效果。目前看来,分析的这个版本只是一个很初级的框架,如果再此之上进行更多的防护和保护,强度会更好。

加固效果

加固之后,其效果是DEX中某些函数被加上ACC_NATIVE标志,原始的DEX代码已经消失,使得反编译、二次打包等功能失效。而加固之后新增的Libt**.so则负责在运行的时候,还原那些被抽取的Dalvik虚拟机代码。

相关结构

了解一下相关的结构有助于分析:

DexClassData描述了DEX文件中的某个类的相关信息,DexMethod则描述的是这个类的函数的信息。DexMethod的methodIdx是method在method_id_item中的Index,accessFlags描述了这个method的Access Control以及其他的信息,code_off是一个偏移,偏移之后的结构是DexCode结构,这个DexCode描述了method具体的信息。更多的信息可以参考Google的官方文档
以上是DEX文件中相关的结构,而DVM运行的时候,会用上述的信息构造Method,DVM使用这个结构来执行:

如果Method.accessFlags没有ACC_NATIVE标志,则insns指向Dalvik虚拟机代码,反之,表明该Method的实现在Native层,insns应该为空。

加固原理

上面说到,加固的效果是抽取了原始的Dalvik虚拟机代码,并且Method被加上了ACC_NATIVE标志。libt**.so在加载的时候,会获取这些method对应的Method结构,去掉accessFlags中的ACC_NATIVE标志,并且将insns写回这个结构。另外,DVM对insns是有要求的,代码如下:

可见insns指向的是DexCode中的insns结构,也就是有了Method.insns,就可以得到原始的DexCode结构。

脱壳

进一步分析发现,被这个加固抽取掉的DexCode信息还原封不动的保存在Data section中,而在dex的尾部,新增了一个结构用于描述DexCode和原始函数的关系。libt**.so运行的时候,就是通过这个结构来还原Method中的insns信息。
最后,在smali中加了10来行代码,成功脱掉。

总结

这个加固实现的效果有:
1. 反静态分析
即便是原始的虚拟机代码仍然保存在文件中,但是二者的关系已经被模糊,不经过修改的工具无法得知原始代码的位置。
2. 防止内存Dump
由于针对修复的对象是Method,是DVM内存中的结构体,而原始的odex并没有被修改。
3. 防止二次打包
由于这个加固在DEX尾部添加了一个自定义的结构,baksmali二次打包的时候会导致这些信息丢失,原始函数和虚拟机代码的代码也因此丢失,所以编译之后的程序无法运行。
最后,我分析的这个libt**.so有一处越界的Bug,可能会导致程序崩溃,或者直接篡改任意代码——这有点搞笑……

某国产DEX加固原理》上有1条评论

发表评论