阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680html
本篇文章将继续从微信资源混淆AndResGuard原理来介绍APK大小优化:
微信的AndResGuard工具是用于Android资源的混淆,做用有两点:一是经过混淆资源ID长度同时利用7z深度压缩,减少了apk包大小;二是混淆后在安全性方面有一点提高,提升了逆向破解难度。本文从源码角度,来探寻AndResGuard实现原理。linux
阅读本文须要前提知识:掌握Android应用程序打包编译过程,尤为是对资源的编译和打包过程;熟悉resource.arsc文件格式。git
推荐罗升阳文章:http://blog.csdn.net/luoshengyang/article/details/8744683
微信资源混淆工具源码地址:https://github.com/shwenzhang/AndResGuard
附上来自网络神图:github
0、程序入口CliMain.main()
该函数处理命令行参数、并解析自定义配置文件,混淆工具能够根据配置项进行特定处理,具体参考config.xml内容,针对其中特定内容,咱们会在后面提到。而后进入真正混淆的入口函数resourceProgurad()正则表达式
特别说明一下解析Configuration中关键点,处理复用旧的mapping文件:
一、processOldMappingFile()缓存
该函数主要功能是:对oldmapping文件处理是按照正则表达式把“->”分隔提取两边字符串,进行hashmap缓存:安全
其1、若是有这个“/”的话,那就是res path mapping即mOldFileMapping的hashmap中:
mOldFileMapping.put(nameBefore, nameAfter);
(例如res/drawable -> r/c,最终mOldFileMapping是(“res/drawable”,”r/c”))微信
其2、不然判断若是包含“.R.”,则是resid的mapping,最后按照类别、package保存到oldResMapping的hashmap中:
namesMap.put(beforename, aftername);
(例如com.basket24.demo.R.attr.progress -> com.basket24.demo.R.attr.a,最终namesMap是(“progress”,”a”))
typeMap.put(typeName, namesMap);
(例如com.basket24.demo.R.attr.progress -> com.basket24.demo.R.attr.a,最终typeMap是(“attr”,namesMap))
mOldResMapping.put(packageName, typeMap);
(例如com.basket24.demo.R.attr.progress -> com.basket24.demo.R.attr.a,最终mOldResMapping是(“com.basket24.demo”,typeMap))网络
二、Main.resourceProguard()是混淆真正的入口。架构
混淆入口resourceProguard里功能:
其一:decodeResource();//进行混淆资源相关功能。
其二:buildApk(decoder, apkFile, signatureType);//最后buildApk生成签名包。
三、Main.decodeResource()
decodeResource核心功能就是设置相关变量,并执行ApkDecoder.decode()。
四、ApkDecoder.decode()
五、ensureFilePath()
ensureFilePath主要功能以下:
其1、在输出目录下,创建一个temp目录,用于apk解压的目录。unZipAPk解压apk,获得mCompressData压缩条目集合[compress.put(name,entry.getMethod());]
其2、根据config来修改压缩的值,将知足config的压缩类型,进行修改压缩标记为ZIP_DEFLATED
其3、判断是否将将res混淆成r
其4、建立须要混淆的temp目录(apk被解压到temp目录)等、使用FileVisitor对目录进行遍历,将原始res(”temp/res”)下路径保存到HashSet中。
其5、建立resources_temp.arsc 和最终resources.arsc等文件及最终mapping命名:resource_mapping_apkname.txt
下面回到第4步ApkDecoder.decode()中继续执行:
六、RawARSCDecoder.decode()
这一步就是解析原始resources.arsc文件,获得文件结构并缓存相关数据,如资源类型字符串池mExistTypeNames等。代码较长,且关键步骤较少,故略去代码。
继续在第4步ApkDecoder.decode()中往下执行:
七、ARSCDecoder.decode()
八、ARSCDecoder的构造函数中执行proguardFileName()
这里第8步主要功能是:
其1、其中初始化ProguardStringBuilder,创建混淆字符串池和标记集合。
其2、获取配置config内容,判断是否keeproot,是否沿用旧的mapping文件等,进行映射。
其3、generalFileResMapping把缓存的映射hashmap写入文件,造成mapping文件,其中目前只有资源目录path映射。
回到第7步中继续执行decoder.readTable()进行真正混淆
九、decoder.readTable()
readPackage()解析resources.arsc文件,其中关键步骤readEntry()以下:
十、readEntry()
readEntry函数主要实现了:
其1、判断是否启用whitelist,若是有的话,设置specname的混淆字符串为原始字符串,即不进行混淆,进行相应对象缓存。
其2、判断是否复用旧的mapping文件中id的映射,已有的继续使用旧的映射关系中的混淆字符串,不然从混淆池中获取一个新的字符串,即获得replaceString。
其3、根据新的混淆字符串,生成相应的id映射。输出到新的混淆mapping文件中(里面已经文件file的映射关系)。
readEntry继续解析arsc文件,执行到关键步骤readValue:
十一、readValue()
readValue主要实现了:
其1、mPkg.getSpecRepplace获取前面已缓存下的specName对应的混淆字符串如“a”
其2、从mOldFileName中如在(“res/drawable“,”r/c”)中找到newFilePath=”r/c”
其3、生成result如”r/c/a”
其4、建立了混淆后的res文件,把旧的资源文件内容copy到新的混淆后的资源文件中。
其5、从原始资源目录mRawResourceFiles中删除掉该已混淆的文件Path
其6、按照Value的index顺序,保存result(如”r/c/a”),即把混淆后的资源项的值缓存下来
下面回到第4步中,继续执行copyOtherResFiles():
十二、 copyOtherResFiles()
该函数主要实现了把没有纪录在resources.arsc的资源文件也拷进dest目录。
回到第4步中,继续执行ARSCDecoder.write():
1三、ARSCDecoder.write()
这一步一样是解析resource.arsc,从新修改arsc文件其中几个字符串池和对应大小,造成新的arsc文件。主要包括:
其1、资源项值字符串池修改,咱们须要把文件指向路径改变,例如res/layout/test.xml,改成res/layout/a.xml
其2、资源项key池修改,即specsname除了白名单部分所有废弃,替换成全部咱们混淆方案中用到的字符。
其3、每一个资源项entry中指向的specsname中的id修正。因为specname已混淆,咱们须要用混淆后的资源项specname的位置改写。
回到最开始第2步中,执行 buildApk(decoder, apkFile, signatureType);
1四、buildApk()
从新打包生成新的apk并签名等,这一步再也不赘述。
以上完成了对apk资源混淆的过程分析。
资源混淆核心处理过程以下:
一、生成新的资源文件目录,里面对资源文件路径进行混淆(其中涉及如何复用旧的mapping文件),例如将res/drawable/hello.png混淆为r/s/a.png,并将映射关系输出到mapping文件中。
二、对资源id进行混淆(其中涉及如何复用旧的mapping文件),并将映射关系输出到mapping文件中。
三、生成新的resources.arsc文件,里面对资源项值字符串池、资源项key字符串池、进行混淆替换,对资源项entry中引用的资源项字符串池位置进行修正、并更改相应大小,并打包生成新的apk。
原文连接https://blog.csdn.net/cg_wang/article/details/70183864
阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680