360加固+美团walle多渠道自动化打包

作者: Android开发架构 | 来源:发表于2019-03-12 21:40 被阅读4次

    背景介绍

    为了防止安卓应用程序被恶意破解,植入黑客病毒或修改代码用于商业竞争等,对应用程序进行加固必不可少。接下來,本篇文章会主要讲加固的过程以及一些注意事项。

    前期准备

    首先,了解一下何为加固,加固的原理是怎样的,这有利于后面分析问题。

    简单来说,加固就是对源Apk进行加密,然后再套上一层壳。用加密算法对源Apk进行加密,再将壳Apk进行合并得到新的Dex文件,最后替换壳程序中的dex文件得到新的Apk,这个新的Apk已经不是一个完整意义上的Apk程序了,它的主要工作是负责解密源Apk,然后加载Apk,让其正常运行起来。

    目前,各大互联网公司都会自己的应用程序进行加固保护,像360公司,腾讯都有对外开放自己的服务。另外,市场上还有一些专门加固的产品,比如爱加密和梆梆加固等。好好利用这些“轮子”,专注于业务开发,來提高工作效率。

    加固工具的选择:此次使用的是360加固

    第一,从调研加固结果可见,360加固在兼容性、启动速度、体积变化上都占有优势,整体上加固效果比较好;

    第二,360公司是一家安全起家的公司,在业界的影响力也很大,加固技术还是值得信赖的!

    第三,看了很多加固工具的官网,加固的过程都是上传签名的APK包到官网页面或使用相应的桌面程序进行上传,这个过程需要人工进行上传,而360加固提供了一个加固工具包,我们可以编写脚本來调用其中的加固程序进行自动化加固。现在很多公司都是用Jenkins线上自动化打包,加固也是打包过程的一部分,最好也能是自动化的,这样整个打包流程是“一条龙”,没有人工干预,相当于在黑匣子中进行,程序员不用关心打包过程,也减少人工成本和出错几率。

    期望目标

    使用gradle脚本实现自动化加固和多渠道打包

    实现

    整个过程分成三个步骤:加固——重签名——多渠道打包

    加固

    加固过程:

    浏览了360加固官网,整个加固过程其实很简单,主要有以下的三个步骤:

    1)输入360加固平台的帐号、密码

    2)将签名文件上传到加固平台

    3)上传需要加固的apk文件进行加固

    关键加固命令行代码如下:

        commandLine "{命令执行符号}", "-c" ,"java -jar {加固jar包的位置} -login {360加固平台帐号} {360加固平台密码}"
        commandLine "{命令执行符号}", "-c" ,"java -jar {加固jar包的位置} -importsign {签名文件的位置} {签名文件存储的密码} {alias别名} {alias密码}"
        commandLine "{命令执行符号}", "-c" ,"java -jar {加固jar包的位置} -jiagu {所要加固的apk文件路径} {加固后的apk输出路径} -autosign"
    

    说明:

    1)系统环境不同,命令执行符号也会不同(Linux系统:sh ;Mac系统:bash ;windows系统:powershell);

    2)第二行上传签名文件信息是非必要的,加固平台加固后可以进行自动重新签名,而自动签名所需要的信息正是之前上传的签名信息。为了保证签名文件的保密性和安全性,不对第三方加固平台公开,那么不能执行第二行代码即可,因为加固时将原签名抹除,而第三方此时没办法获取到我们的签名信息,所以加固后需要我们本地重新签名,下文将会介绍对加固包重签名;

    3)当选择本地加固时,第三行代码不需要加上参数-autosign,因为加固平台没办法获取到签名信息进行加固;

    4)更多有关加固的命令行,请参考360官网.官网介绍中,还有关于加固后导入渠道信息的功能,此次多渠道打包并没有使用该功能,第一,项目中原先使用多渠道打包方式的是美团walle;第二,暂时不知道如何获取到360加固打包后的渠道信息,而该渠道信息会在项目中广泛被使用到,比如数据埋点,渠道统计等。

    基于上面的说明和项目的具体情况,整理一下代码,以Linux系统为例:

        /**
         * 360加固
         * @param apk 加固的原始apk File
         * @param outputPath 输出目录
         */
        def reinforceApk(File apk,outputPath) {
            println "--- 360 reinforceApk start! ---"
            println "reinforce apk:" + apk
            if(apk == null || !apk.exists()) {
                throw new FileNotFoundException('apk is not exists and cannot reinforce')
                println "---360 reinforceApk throw exception and forced stop!---"
            }
            exec {
                commandLine "sh", "-c", "java -jar ${REINFORCE_JAR} -login  ${REINFORCE_NAME} ${REINFORCE_PASSWORD}"
                commandLine "sh", "-c", "java -jar ${REINFORCE_JAR} -showsign"
                commandLine "sh", "-c", "java -jar ${REINFORCE_JAR} -jiagu ${apk} ${outputPath}"
            }
            println "--- 360 reinforce end! ---"
        }
    

    重签名

    加固工作已经完成差不多了,剩下的工作就是对加固包重新签名

    重签名的方法主要是调用AndroidSDK中的build-tools,使用工具包中对齐工具和签名工具完成签名。具体步骤如下:

    1)对齐,对Apk文件进行存档对齐优化,确保所有的未压缩数据都从文件的开始位置以指定的对齐方式排列

    2)签名,选择Signature V2

        commandLine "{命令执行符号}","-c", "{zipalign工具的文件路径} -v -p 4  {已加固的apk文件路径} {对齐后输出的apk文件路径}"
        commandLine "{命令执行符号}", "-c", "{apksigner工具的文件路径} sign --ks {签名文件的位置} --ks-key-alias {alias别名} --ks-pass pass:{签名文件存储的密码} --key-pass pass:{alias密码} --out {签名后输出的apk文件} {对齐后输出的apk文件路径}"
    

    多渠道打包

    最后,使用walle美团的多渠道打包工具

    平时使用walle多渠道打包,只需要在app/build.gradle下配置插件,指定渠道包的输出路径和渠道配置文件即可,最后在Android studio的Terminal中输入./gradlew assembleReleaseChannels,任务执行完成后在指定的输出路径下生成多个对应的渠道包。具体的流程和细节可参考官方介绍。

    这种多渠道打包方式是全自动化构建,很难去干涉到构建流程,不符合我们的需求:

    1)在app/build.gradle配置插件时,在官方介绍中并没有找到指定源APK输入路径的方式,估计打包插件默认使用的是app/build/outputs/apk/release下的apk文件,这样就没办法对不同文件路径下的已加固apk包进行多渠道打包。

    2)打包任务设置在assembleRelease之后执行,这个执行依赖封装在插件内部,外部很难修改打包任务依赖于加固任务,在加固任务之后执行。

    除了上面的多渠道打包方式之后,walle还提供了另外一种多渠道打包方式,用命令行执行walle提供的walle-cli-all.jar执行打包操作,只需要一条打包命令即可完成打包。

        commandLine "sh", "-c", "java -jar {walle-cli-all.jar文件路径} batch -f {渠道文件路径} {要加渠道的apk文件路径} {渠道包的输出路径}"
    

    walle-cli-all.jar文件下载地址:walle-cli-all.jar

    免费获取安卓开发架构的资料(包括Fultter、高级UI、性能优化、架构师课程、 NDK、Kotlin、混合式开发(ReactNative+Weex)和一线互联网公司关于android面试的题目汇总可以加:936332305 / 链接:点击链接加入【安卓开发架构】:https://jq.qq.com/?_wv=1027&k=515xp64

    整体流程

    至此,360加固+walle多渠道打包的基本工作完成了!剩下就是构建整体流程和优化代码。

    首先,将加固和打包操作封装成自动化操作,利用gradle脚本构建加固任务。为了代码解耦,我们不在app/build.gradle里面实现加固任务,而是重新建一个gradle文件來实现具体的加固和多渠道打包过程,在app/build.gradle只需要通过apply from: '×××.gradle'引用这个gradle文件即可,当需要修改加固的一些代码逻辑时,只需要在这个gradle文件里面修改。

    引入工具包。根据自己的系统环境,在加固助手网页选择对应的加固助手工具,下载后将里面的jiagu文件夹拷贝到自己项目的根目录下;在walle-cli-jar下载链接下载jar包到自己项目中。

    确定加固任务的时机。加固任务时机应该在release包生成之后,那么加固任务应该依赖于assembleRelease这个任务,并且设置在这个任务之后执行。

    接下来就是我们的基本流程了

    1)找到release包,一般在app/build/outputs/apk/release/路径下

    2)执行加固命令,将release包路径设置到命令中,并指定加固apk文件的输出路径

    3)找到已加固的apk文件,对已加固apk文件进行对齐、重签名。(360已加固的apk文件会在原有的release文件名后面加上"_jiagu")

    4)找到重新签名的apk文件,执行多渠道打包命令。(重签名后的文件名是在原有文件名后面加上"_sign")

        /**
         * 360加固 + 美团walle渠道打包
         */
        task assembleReinforceRelease() {
            group '360reinforce'
            dependsOn("assembleRelease")
        
            doLast {
                cleanFilesPath(CHANNEL_APKS_PATH)   //清空上一次生成的渠道包
                def releaseApkFile = findApkFile(SOURCE_APK_PATH,"release")  //遍历文件,寻找release包
                if(releaseApkFile != null) {
                    reinforceApk(releaseApkFile, DEFAULT_APK_PATH)   //执行加固
                    def reinforceApk = findApkFile(DEFAULT_APK_PATH, "_jiagu")  //寻找已加固的apk包
                    if(reinforceApk != null) {
                        signApkV2(reinforceApk)  //使用V2重签名
                        def signatureApk = findApkFile(DEFAULT_APK_PATH, "sign")
                        if(signatureApk != null) {   
                            buildChannelApks(signatureApk,CHANNEL_APKS_PATH)  //执行多渠道打包
                            renameChannelApkFiles(CHANNEL_APKS_PATH)  //重命名渠道包
                        }
                    }
                }
            }
        }
    

    整个流程确定后,差不多接近尾声了。

    代码优化:

    1)将流程中每个步骤封装成一个方法,使代码更加简洁易懂;

    2)任务中涉及360加固平台帐号密码等敏感信息,可以将这部分信息放到签名信息所在的文件(eg:keystore.properties)中统一管理,然后将这些信息加载到gradle文件中;

    3)各种输入输出的文件路径定义为常量,便于修改和管理;

    加固方法,重命名和渠道打包的方法类似:

        /**
         * 360加固
         * @param apk 加固的原始apk File
         * @param outputPath 输出目录
         */
        def reinforceApk(File apk,outputPath) {
            println "--- 360 reinforceApk start! ---"
            println "reinforce apk:" + apk
            if(apk == null || !apk.exists()) {
                throw new FileNotFoundException('apk is not exists and cannot reinforce')
                println "---360 reinforceApk throw exception and forced stop!---"
            }
        
            exec {
                commandLine "sh", "-c", "java -jar ${REINFORCE_JAR} -login  ${REINFORCE_NAME} ${REINFORCE_PASSWORD}"
                commandLine "sh", "-c", "java -jar ${REINFORCE_JAR} -showsign"
                commandLine "sh", "-c", "java -jar ${REINFORCE_JAR} -jiagu ${apk} ${outputPath}"
            }
            println "--- 360 reinforce end! ---"
        }
    

    任务中涉及到的各种常量,各种密钥名、路径都要根据自己的实际情况修改:

        /*加载keystore.properties信息到该gradle文件中*/
        def keystorePropertiesFile = rootProject.file("keystore.properties")
        def keystoreProperties = new Properties()
        keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
        
        ext {
            /*加固*/
            REINFORCE_JAR = "${project.rootDir}/jiagu/jiagu.jar"
            REINFORCE_NAME = keystoreProperties['360_NAME'] //360加固账号
            REINFORCE_PASSWORD = keystoreProperties['360_PASSWORD'] //360加固密码
            KEY_PATH = keystoreProperties['storeFile'] //密钥路径
            KEY_PASSWORD = keystoreProperties['storePassword'] //密钥密码
            ALIAS = keystoreProperties['keyAlias'] //密钥别名
            ALIAS_PASSWORD = keystoreProperties['keyPassword'] //别名密码
            SOURCE_APK_PATH = "${project.buildDir}/bakApk"  //源apk文件路径
            DEFAULT_APK_PATH = "${project.buildDir}/outputs/apk/release" //默认release文件路径
        
            /*多渠道打包*/
            WALLE_JAR = "${project.rootDir}/walle-cli-all.jar"
            WALLE_CHANNELS_CONFIG = "../app/channel"  //渠道配置文件
            CHANNEL_APKS_PATH = "${project.buildDir}/outputs/channels"  //渠道Apk输出路径
        }
    

    验证

    1)对比加固前release包的签名和加固后apk的签名是否一致,两者相同说明新apk能够覆盖安装

    2)用反编译工具对加固包进行反编译,看能否看到Activity这些类

    3)验证是否可以获取到渠道包,代码中获取渠道号是通过
    WalleChannelReader.getChannel(application);这个方法
    。。。

    Q&A

    1)网上传闻,360加固后无法获取到walle打包的渠道号?

    是的,360加固过程会抹去已签名release包的签名信息,假如在加固前用walle打渠道包就会造成渠道号丢失,所以我们采用的方法是先加固再多渠道打包,由于加固会破坏掉原有的签名信息,所以加固后需要重新签名。

    免费获取安卓开发架构的资料(包括Fultter、高级UI、性能优化、架构师课程、 NDK、Kotlin、混合式开发(ReactNative+Weex)和一线互联网公司关于android面试的题目汇总可以加:936332305 / 链接:点击链接加入【安卓开发架构】:https://jq.qq.com/?_wv=1027&k=515xp64

    相关文章

      网友评论

        本文标题:360加固+美团walle多渠道自动化打包

        本文链接:https://www.haomeiwen.com/subject/hppopqtx.html