Android apk文件资源混淆原理及实现

Android apk文件资源混淆原理及实现

部分厂商的Android应用,apk文件中的res目录和里面的文件都会做混淆。里面的所有文件和文件夹的名字都是a,b,c,d等。这样做有很多好处:1,减少apk文件大小,我尝试着把微博的apk资源进行混淆,apk文件由36.5M减少到35.6M;2,增加反编译和二次打包的难度,混淆之后的apk不能用apktool之类的工具直接反编译。当然只是增加了难度,毕竟没有绝对安全;3减少运行时内存占用,在运行时各个res的key都是以String形式加载到内存中的,混淆之后key变短了很多内存占用肯定会变少。当然上述的这些优势是有在一些大体量的应用上才会比较明显,比较小的apk可能不太明显。

资源加载过程分析

言归正传,要想要实现资源混淆首先要清楚Android资源打包和加载的原理。大家都知道,在开发过程中我们通过aapt生成的R.java中的常量来使用资源,而在编译之后使用常量的地方都会被替换为常量的值。见下图。

QQ20150804-1@2x.png

也就是说我们通过Resource使用一个int数值来查找使用资源。那么Resource是怎么通过int数值找到具体的资源呢?我们解压apk可以看到里面有个resources.arsc文件,这个文件也是由aapt生成,文件中保存着资源id和资源key的映射关系。Resource就是按照这个映射关系找到资源的。

接下来我们具体看看这个arsc文件的具体内容。我们以单包名的应用来讲。结构见下图

QQ20150805-1@2x.png

其中res string pool 是res的字符串池,里面包含了字符串(就是大家开发过程中在String.xml文件增加的)和资源文件路径(包括图片,xml文件,raw文件。其中的值类似这样res/drawable/icon.png)
type string pool 是程序中使用的资源分类名称,包括 attr,anim,drawable。。。注意这里只是分类。

spec string pool 这个比较关键,这个字符串池中是所有资源的key。没有分类和config。具体的值就是R.java中各个常量的名称。

在这个字符串池后面就是各个资源分类列表,attr,anim。。。。每个分类中又包括若干config,config就是指hdpi,xhdpi,zh_rCN , land这些,大家知道android资源config有18个纬度。每个config中就是具体的res资源列表。

举例来说一下一个资源的查找过程,比如当我们调用getDrawable(R.drawable.icon)时候,先找到drawable分类,再根据当前的系统config找到匹配的config表。然后根据id找到对应的res数据。drawable在arsc文件中是当作string类型保存的。res数据中有这个资源在res string pool池中的索引。根据这个索引可以在字符串池中找到这个字符串。这个字符串其实是一个文件的路径,比如:res/drawable-hdpi/icon.png,然后读取apk中这个文件。

关于这个过程我们不做太细节的讲述,想了解细节可以看看罗升阳大神的博客,《Android资源管理框架(Asset Manager)简要介绍和学习计划》http://blog.csdn.net/luoshengyang/article/details/8738877
arsc文件格式的细节可以看看这篇博客 http://blog.csdn.net/mldxs/article/details/44956911

资源混淆原理和实现

看上面的例子,我们注意到一般情况下查找资源的过程中不会用到资源名,也就是key。当然res数据中也有当前res的key在key string pool中的索引,但一般情况下用不到。根据这个原理我们可以在打包完成之后对key进行混淆。而且刚刚说到res数据中保存的都是字符串在string pool中的索引。所以我们混淆只需要修改res string pool和spec string pool两个字符串池。其他的数据不用修改。

所以我们混淆的流程大概是这样的:1,解压apk文件;2,读取arsc文件;3,混淆spec string pool;4根据上一步混淆结果混淆res string pool;5,生成新的arsc文件;6,输出mapping文件;7,根据3,4步结果,修改res目录下所有文件名;8,重新压缩生成apk文件;9,签名;10.zipalign。

还以drawable为例,混淆前后对比如下图:

ZNALUE{I]D}S]M%2$}R`H{8.jpg

keep

再说key的问题,刚刚说一般情况下用不到res的key。但是开发中我们有时候会通过key来查找资源。也就是说需要注意,需要通过key来使用的资源的key不能混淆。

源码

Android资源混淆工具项目已经上传Github:
https://github.com/joker535/Baffle

没有更多推荐了,返回首页