文章简介:当一个Android app 开发完成后,我们总是希望对app进行一些安全措施,防止自己开发的apk被别人二次打包和签名上传到应用市场,同时防止apk被别人拿到之后进行反编译进行二次开发。那么我们应该都做哪些防护措施呢?下面来一一说明。
1、apk签名
打正式包之前,需要对apk进行签名,如果您是用Android Studio开发工具,那么打包、签名就非常简单了。具体怎么签名,网上文章很多,这里不做详细描述。那么我们重点说说为什么要对apk进行签名呢?
(1)apk签名是应用程序作者对apk进行一个自定义的签名,和权威机构的数字证书不同,它是开发者可自由定义的、作为此apk的唯一标识符,标识了apk的来源,任何第三方进行此apk二次打包时,如果签名不一致则无法进行二次打包,并不能成功安装到手机上。
(2)当新版程序和旧版程序的数字证书相同时,Android系统才会认为这两个程序是同一个程序的不同版本。如果新版程序和旧版程序的数字证书不相同,则Android系统认为他们是不同的程序,并产生冲突,会要求新程序更改包名。
(3)Android系统允许拥有同一个数字签名的程序运行在一个进程中,Android程序会将他们视为同一个程序。所以开发者可以将自己的程序分模块开发,而用户只需要在需要的时候下载适当的模块。有利于程序的模块化设计和开发。
(4)可以通过权限(permission)的方式在多个程序间共享数据和代码。Android提供了基于数字证书的权限赋予机制,应用程序可以和其他的程序共享概功能或者数据给那那些与自己拥有相同数字证书的程序。如果某个权限(permission)的protectionLevel是signature,则这个权限就只能授予那些跟该权限所在的包拥有同一个数字证书的程序。
2、代码混淆
代码混淆的目的就是为了防止代码的二次反编译。Android apk通过反编译工具可将classes.dex 字节码转换为java源代码。为了防止看到最初的代码,通过一定的方式将代码进行混淆,混淆之后再反编译后代码就变的不可读了。此外还优化、压缩了一些无用代码、删掉日志输出等。目前随着混合开发框架的兴起,许多原生代码混淆都变得没有意义,但是,开发者或多或少的也会写一些核心的原生代码作为业务支撑,当然混淆还是必不可少的,下面就列出常用的混淆方式。
apk如何进行反编译详细步骤
2.1 混淆工具
proguard官网 官网介绍了proguar在Android项目中使用配置,下面来进行详细说明
在build.gradle中 按照如下方式进行配置 属性
/**
* android 混淆
*/
buildTypes {
release {
// 不显示Log
buildConfigField "boolean", "LOG_DEBUG", "false"
//混淆
minifyEnabled true
// 移除无用的resource文件
shrinkResources true
useProguard true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
//signingConfig signingConfigs.release
}
}
当我们开启混淆后 (minifyEnabled 为 true 时)默认使用的混淆文件是proguard-android.txt。这个文件所在的位置为 /sdk/tools/ 下。一般来说使用默认的混淆文件即可进行混淆,但是混淆之后打包出来的apk并不不能运行,因为,有些需要保留的类没有进行保留,这就需要你来自定义设置了,这时就需要掌握proguard规则。如果需要自定义设置规则,则需要在app目录下创建文件proguard-rules.pro,在这个文件中进行规则设置,下面来贴一下我混淆使用的模版(适用于混合开发框架corodva及原生框架)
这里不做过多解释,因为在模版的注释中已经详细说明。
#添加依赖
#-libraryjars libs/AMap3DMap_7.9.1_AMapSearch_7.9.0_AMapLocation_5.3.1_20210414.jar
# 不使用大小写混合类名,混淆后的类名为小写
-dontusemixedcaseclassnames
# 混淆第三方库
-dontskipnonpubliclibraryclasses
# 混淆时记录日志,有助于排查错误
-verbose
# 代码混淆使用的算法.
-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
# 跳过预检验
-dontpreverify
# 代码混淆压缩比,值在0-7之间,默认为5.
-optimizationpasses 5
# 优化时允许访问并修改有修饰符的类和类的成员
-allowaccessmodification
# 保护代码中的Annotation不被混淆
-keepattributes *Annotation*
# 避免混淆泛型, 这在JSON实体映射时非常重要
# -keepattributes Signature
# 抛出异常时保留代码行号
-keepattributes SourceFile,LineNumberTable
################################不需要混淆的#######################
# 这些类不混淆(混淆时默认保留,可不进行配置)
-keep public class * extends android.app.Activity
#-keep public class * extends android.app.Application
#-keep public class * extends android.app.Service
#-keep public class * extends android.content.BroadcastReceiver
#-keep public class * extends android.content.ContentProvider
#-keep public class * extends android.app.backup.BackupAgent
#-keep public class * extends android.preference.Preference
#-keep public class * extends android.support.v4.app.Fragment
#-keep public class * extends android.support.v4.app.DialogFragment
##-keep public class * extends com.actionbarsherlock.app.SherlockListFragment
##-keep public class * extends com.actionbarsherlock.app.SherlockFragment
##-keep public class * extends com.actionbarsherlock.app.SherlockFragmentActivity
#-keep public class * extends android.app.Fragment
#-keep public class com.android.vending.licensing.ILicensingService
# 不混淆,最后这两个类我们基本也用不上,是接入Google原生的一些服务时使用的。
-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService
# Native方法不混淆 ni方法不可混淆,因为这个方法需要和native方法保持一致;
-keepclasseswithmembernames class * {
native <methods>;
}
# 枚举类型不混淆 因为enum类的特殊性,以下两个方法会被反射调用
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# 保留Parcelable序列化类不被混淆
# Parcelable的子类和Creator静态成员变量不混淆,否则会产生Android.os.BadParcelableException异常;
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
-keepclassmembers class **.R$* {
public static <fields>;
}
# We want to keep methods in Activity that could be used in the XML attribute onClick
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
# keep setters in Views so that animations can still work.
# see http://proguard.sourceforge.net/manual/examples.html#beans
-keepclassmembers public class * extends android.view.View {
void set*(***);
*** get*();
}
# The support library contains references to newer platform versions.
# Don't warn about those in case this app is linking against an older
# platform version. We know about them, and they are safe.
# 打包时忽略警告
-dontwarn android.support.**
# Understand the @Keep support annotation.
-keep class android.support.annotation.Keep
-keep @android.support.annotation.Keep class * {*;}
-keepclasseswithmembers class * {
@android.support.annotation.Keep <methods>;
}
-keepclasseswithmembers class * {
@android.support.annotation.Keep <fields>;
}
-keepclasseswithmembers class * {
@android.support.annotation.Keep <init>(...);
}
# 保留第三方库android.support.v4不被混淆
#-keep class android.support.v4.app.** { *; }
#-keep interface android.support.v4.app.** { *; }
#使用反射的类
-keep class android.app.AivityThread {*;}
-keep interface android.content.pm.IPackageManager {*;}
-keep class com.customer.plugins.appupdate.PackageManagerHook {*;}
########################高德地图混淆处理,不混淆高德地图中已经混淆的类##############################
-dontwarn com.amap.api.**
# -dontwarn com.a.a.**
-dontwarn com.autonavi.**
-keep class com.amap.api.** {*;}
-keep class com.autonavi.** {*;}
#-keep class com.a.a.** {*;}
########################不混淆corodva相关,Cordova plugin 初始化时无法进行初始化#############################
-keep class org.apache.cordova.** { *; }
#-keep class cordova.** {*;}
#-keep class com.customer.plugins.** {*;}
-keep class * extends org.apache.cordova.CordovaPlugin
开启了混淆打包过程中可能会出现一些报错日志以及由于混淆之后出现的打包错误日志,可在如下图位置(Toggle view)查看
混淆出现的错误可参考 混淆常见错误解决方法
3、H5压缩包设置密码或从服务端拉取
如果您的应用时混合开发模式,那么就涉及到了H5代码的安全管理了。我们打包的apk,通过解压缩后就会在assets文件夹下看到我们开发的H5相关文件,如js、html、资源文件等。这些文件的核心业务代码会直接暴露出来。这里我提供两种安全思路:
(1)可将H5文件的www包进行压缩,放到Android框架中,并对压缩包设置密码,此时,如果设置了密码那么就会多做一些额外的工作;应用启动时和 apk版本升级时 都会涉及带密码的压缩包的解压。
(2)将H5相关文件存放到服务端,每次应用加载时都服务端拉取,并缓存到本地沙箱中,这样打包出来的apk就不会出现H5源码文件了。这样做的缺点在于每次在进行版本升级时需要在前端进行版本比较。
(3)当然一些加固收费的工具可以对H5进行加固,加固的目标:H5加固服务,通过将JavaScript代码进行混淆加密、压缩等手段达到对HTML5应用的反调试、反窃取、反篡改等保护行为,保护H5应用的安全。一般来说都需要收费
4、应用加固
应用加固的目的,下面摘取360基础加固服务(不收费)的图:
具体加固方式可到官网获取,步骤非常详细。应用加固的方式也有很多种,可根据需要自行选择。
5、总结
上述几步并不是并行的,一个apk的安全措施上述几步是必须要做的。下面来截几张混淆后和加固后的 反编译之后的java源码的对比图:附上
apk如何进行反编译详细步骤
(1)混淆后加固前的 字节码反编译为java源码的截图如下所示
(2)先混淆后并加固后 字节码反编译为java源码的截图如下所示
对比两图之后可发现,加固后的代码暴露的越来越少了。感兴趣的同学可以研究一下。
欢迎大家查看,有问题可留言,随时回复。