一、前言
我们在做项目的时候,加固和多渠道是必不可少一部分。
为了防止安卓应用程序被恶意破解,植入黑客病毒或修改代码用于商业竞争等,就必须要对应用程序进行加固。
Android市场有万万千,如果我们要统计市场的下载量等一些信息,那么就要多渠道打包了。
期望目标
使用gradle脚本实现自动化加固和多渠道打包
二、加固
首先,了解一下何为加固,加固的原理是怎样的,这有利于后面分析问题。
1、加固的原理
简单来说,加固就是对源Apk进行加密,然后再套上一层壳。用加密算法对源Apk进行加密,再将壳Apk进行合并得到新的Dex文件,最后替换壳程序中的dex文件得到新的Apk,这个新的Apk已经不是一个完整意义上的Apk程序了,它的主要工作是负责解密源Apk,然后加载Apk,让其正常运行起来。
2、360加固
目前,各大互联网公司都会自己的应用程序进行加固保护,像360公司,腾讯都有对外开放自己的服务。另外,市场上还有一些专门加固的产品,比如爱加密和梆梆加固等。好好利用这些“轮子”,专注于业务开发,來提高工作效率。
出于成本考虑,选择360加固,因为它是免费的。当然并不能因为它是免费而觉得它不够专业,相反,它还是相当靠谱的。
360加固保是为移动应用安全提供专业保护的平台,盗版APP通常是将正版APP进行破解、篡改后重新打包生成的应用。如果手机APP能够具备防反编译、防反破解能力,就可以有效的防止APP被盗版。
360加固保专为开发者的应用提供免费安全加固服务,独创了多重防护方式,对应用程序深度加密处理;独有的程序文字信息加密功能,能有效防止应用被反编译和恶意篡改,保护应用不被二次打包,保护数据信息不会被黑客窃取。开发者无需任何开发成本,一键上传,即可在5分钟内完成应用加固,从而彻底防止应用在上线后被反编译、调试、破解、二次打包和内存截取等多种威胁。给予官方应用最强保护,从源头消灭恶意盗版应用,保护开发者收入。
360加固保在为APP提供加固服务的同时,还为开发者提供APP数据分析、崩溃日志分析、盗版监测和漏洞扫描等服务,全方位帮助开发者了解数据健康与运行状况。截止2015年第二季度,已使用360加固保的应用达30万,应用所覆盖的用户超过10亿,360加固保已经成为国内最大的移动应用保护平台。
3、360加固保特点
1.加固零成本:线上加固,无开发成本,一键拥有顶级安全保护
2.应用零风险:防止应用被二次打包、恶意篡改、内存截取等风险
3.大小零增加:独创隐形压缩技术,加固后文件大小零增加
4.使用零影响:完美兼容各版本安卓系统,对应用功能、性能零影响
5.安装启动更快速:提高应用安装速度,ART模式下启动更快速
4、360加固保功能
1.反篡改:通过签名校验,有效避免应用被二次打包,杜绝盗版应用
2.反窃取:对内存数据进行变换处理和动态跟踪,防止内存数据被修改和获取
3.反逆向:进行代码加密压缩,防止还原真实代码逻辑,避免应用被复制
4.反调试:多重手段防止代码注入,避免外挂、木马或窃取账号密码等恶意行为
5、加固过程:
参考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官网.官网介绍中。
加固就简单介绍到这里,下面我们开始实现我们的目标
三 实现360加固+多渠道自动化打包
基于上面的说明和项目的具体情况, 我们要做的事情:
1. 打包过程
- 登录360加固
commandLine "bash", "-c", "java -jar ${360加固包.jar} -login ${登录名} ${登录密码}"
- 导入签名相关
// 导入
commandLine "bash", "-c", "java -jar ${360加固包.jar} -importsign ${签名文件路径} ${签名密码} ${别名} ${别名密码}"
// 查看签名信息
commandLine "bash", "-c", "java -jar ${360加固包.jar} -showsign"
- 导入渠道文件
commandLine "bash", "-c", "java -jar ${360加固包.jar} -importmulpkg ${渠道文件}"
// 查看渠道信息
commandLine "bash", "-c", "java -jar ${360加固包.jar} -showmulpkg"
- 执行加固+多渠道打包
commandLine "bash", "-c", "java -jar ${360加固包.jar} -jiagu ${被加固基础包} ${打包文件输出目录} -autosign -automulpkg"
2、变量整理
上面已经把打包的思路及关键代码整理出来了,但是里面有不少需要根据自己实际情况做适当调整的变量,为了在修改变量时,不对代码的逻辑产生不利影响,我们需要把便利独立出来,这样就只需要修改变量,就OK了
整理如下:
ext {
/加固/
FIRST_JIAGU = false // 首次加固
JIAGU_ROOT = "${project.rootDir}/360jiagu"
REINFORCE_JAR = "${JIAGU_ROOT}/jiagu/jiagu.jar" // 360加固助手炸药包
REINFORCE_NAME = "13416318220" //360加固账号
REINFORCE_PASSWORD = "ybyj1314" //360加固密码
KEY_PATH ="../keystore/yufenfen.keystore" //密钥路径
KEY_PASSWORD = "1234567" //密钥密码
ALIAS = "debug" //密钥别名
ALIAS_PASSWORD = "1234567" //别名密码
WALLE_CHANNELS_CONFIG = "${JIAGU_ROOT}/jiagu/channels"//渠道配置文件
IN_APK_PATH = "${project.projectDir}/release/module_net-release.apk"// 需要加固的apk的输入路径
OUT_APK_PATH = "${JIAGU_ROOT}/release"// 加固后多渠道apk输出路径
CHANNEL_APKS_PATH = "${OUT_APK_PATH}"//渠道Apk输出路径
}
3. 添加任务
添加task,方便gradle命令调用,自动打包
/**
* 360加固 + 多渠道打包
*/
task assembleRelease360jiagu() {
group '360reinforce'
// dependsOn("assembleRelease")
doLast {
cleanTargetFiles(CHANNEL_APKS_PATH) //清空上一次生成的渠道包
// 360加固多渠道
reinforceApk()
}
}
4. 下载->实现->调用
OK,经过前面几部,已经把基本的脉络讲清楚了,那么,我们来整理一下整个过程,以Mac系统为例,从下载->实现->调用。
4.1. 下载加固包
- 到项目的根目录下添加文件夹"360jiagu";
- 下载360加固包,并解压文件,把”jiagu"目录拷贝到"360jiagu"中;
- 按照”jiagu"目录下的渠道文件格式,添加相应的渠道
4.2. 定义实现“360jiagu.gradle"配置
- 在项目根目录下添加配置文件“360jiagu.gradle"
- 整理代码到配置文件“360jiagu.gradle"中
ext {
/加固/
FIRST_JIAGU = false // 首次加固
JIAGU_ROOT = "${project.rootDir}/360jiagu"
REINFORCE_JAR = "${JIAGU_ROOT}/jiagu/jiagu.jar" // 360加固助手炸药包
REINFORCE_NAME = "13416318220" //360加固账号
REINFORCE_PASSWORD = "ybyj1314" //360加固密码
KEY_PATH ="../keystore/yufenfen.keystore" //密钥路径
KEY_PASSWORD = "1234567" //密钥密码
ALIAS = "debug" //密钥别名
ALIAS_PASSWORD = "1234567" //别名密码
WALLE_CHANNELS_CONFIG = "${JIAGU_ROOT}/jiagu/channels"//渠道配置文件
IN_APK_PATH = "${project.projectDir}/release/module_net-release.apk"// 需要加固的apk的输入路径
OUT_APK_PATH = "${JIAGU_ROOT}/release"// 加固后多渠道apk输出路径
CHANNEL_APKS_PATH = "${OUT_APK_PATH}"//渠道Apk输出路径
}
/**
* 360加固 + 多渠道打包
*/
task assembleRelease360jiagu() {
group '360reinforce'
// dependsOn("assembleRelease")
doLast {
cleanTargetFiles(CHANNEL_APKS_PATH) //清空上一次生成的渠道包
// 360加固多渠道
reinforceApk()
}
}
/**
* 加固 + 多渠道
*/
def reinforceApk() {
println "--- 360 reinforceApk start! ---"
println "reinforce apk: ${IN_APK_PATH}"
exec {
println "reinforce apk login by : ${REINFORCE_NAME}"
// 登录
commandLine "bash", "-c", "java -jar ${REINFORCE_JAR} -login ${REINFORCE_NAME} ${REINFORCE_PASSWORD}"
// 需要先上传sign文件、渠道文件
if(project.ext.FIRST_JIAGU){
println "reinforce import sign file : ${KEY_PATH}"
//sign 文件
commandLine "bash", "-c", "java -jar ${REINFORCE_JAR} -importsign ${KEY_PATH} ${KEY_PASSWORD}" +
" ${ALIAS} ${ALIAS_PASSWORD}"
println "reinforce import channels file : ${WALLE_CHANNELS_CONFIG}"
// 渠道文件
commandLine "bash", "-c", "java -jar ${REINFORCE_JAR} -importmulpkg ${WALLE_CHANNELS_CONFIG}"
}
// 签名信息
commandLine "bash", "-c", "java -jar ${REINFORCE_JAR} -showsign"
println "reinforce 开始加固、多渠道打包"
// 加固apk 多渠道
commandLine "bash", "-c", "java -jar ${REINFORCE_JAR} -jiagu ${IN_APK_PATH} ${OUT_APK_PATH} -autosign -automulpkg"
}
4.3 引入“360jiagu.gradle"
在项目中,进入我们的module,并在module的配置"build.gradle"中引入我们的“360jiagu.gradle"
// build.gradle文件
apply plugin: 'com.android.application'
apply from: "${project.rootDir}/360jiagu.gradle"
……
……
……
4.4 使用
- 编译项目,并且生成release包
- 在Android studio的命令模式下
./gradlew assembleReinforceRelease
- 坐等加固的渠道包生成,速度也非常快,我20多个渠道,20多秒完成。
四、 验证
1)对比加固前release包的签名和加固后apk的签名是否一致,两者相同说明新apk能够覆盖安装
2)用反编译工具对加固包进行反编译,看能否看到Activity这些类
3)验证是否可以获取到渠道包,
360加固包中的渠道编号是AndroidManifest中的 meta-date 标签的 android value,一般填写相关 channel id,让我们看看我们调整的channels文件中的key值:
UMENG_CHANNEL 360应用平台 1
没错就是每行前面的 ”UMENG_CHANNEL“,于是,我们就可以在代码中读取它的值:
/**
* 获取渠道名
* @return 如果没有获取成功,那么返回值为空
*/
public String getChannelName() {
String channelName = null;
try {
PackageManager packageManager = this.getPackageManager();
if (packageManager != null) {
//注意此处为ApplicationInfo 而不是 ActivityInfo,因为友盟设置的meta-data是在application标签中,而不是某activity标签中,所以用ApplicationInfo
ApplicationInfo applicationInfo = packageManager.
getApplicationInfo(this.getPackageName(), PackageManager.GET_META_DATA);
if (applicationInfo != null) {
if (applicationInfo.metaData != null) {
channelName = String.valueOf(applicationInfo.metaData.get("UMENG_CHANNEL"));
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
Log.i("MyApplication", "360加固渠道名:" + channelName);
return channelName;
}