最近抽空研究了下android 加壳技术,发现关于加壳的源代码特别少,即使有也不能做到版本兼容,问题又特别多!
对app加壳感觉远没有当初想的那么简单,而现阶段成熟的加密软件多是收费的,爱加密,梆梆加固等。收费就暂不考虑了!
咱们只能曲线救国,也试过腾讯御安全,认证通过了,也能查看安全报告,就是无法加固,试了很久一直再刷新,最终也没有加固成功;试过网易云易盾,只是申请一下试用,打了几个电话做广告,最终也没有同意申请。第三方加密平台没有money看来是行不通了!
我们都知道,常见的APP加密方法包括伪加密、混淆、运行验证和第三方加密平台APP加密。
伪加密是Android4.2.x系统发布前的加密方式之一,通过java代码对APK(压缩文件)进行伪加密,其修改原理是修改连续4位字节标记为”P K 01 02”的后第5位字节,奇数表示不加密偶数表示加密。
虽然伪加密可以起到一定防破解作用,但也会出现问题。
首先使用伪加密对其APK加密后市场无法对其进行安全检测,导致部分市场会拒绝这类APK上传;
其次,伪加密的加密方式和解密方式也早已公布导致它的安全程度也大大降低;再次,Android4.2.x系统无法安装伪加密的APK;最后伪加密只是对APK做简单保护,在java层源码加壳保护、核心so库、资源文件、主配文件、第三方架包方面却没有任何保护处理。
注意:高版本不支持这样的方法,所以还是不要尝试使用这样的加密方式了。现在Android 版本系统一般都是4.4以上的了,高版本也不支持,pass掉该加密方式。
APP加密之运行时验证,主要是指在代码启动的时候本地获取签名信息然后对签名信息进行检验来判断自己的应用是否是正版,如果签名信息不是正版则提示盗版或者直接崩溃。
当然你可以把必要的数据放在服务器端。破解:找到smali文件中,判断是否相等的部分。改为常量true,即失效。总之,反编译一些apk之后,只要是java代码写的总会有smil文件。对于smil文件,如果耐心读的话,还是可以查看到一些关键代码的。
APP加密之混淆,混淆是把原来有具体含义的类名,变量名,方法名,修改成让人看不懂的名字,例如方法名getUserName编程了方法名。代码混淆只是增加APP代码的阅读难度,对APP安全起不到实质的作用,但其是APP加密之前的一个必要步骤。
个人觉得混淆还是比较有用的,加密之前提供初步的保护,就稍微研究了一下。
初步配置
大致:构建类型有debug 和release版本,我们在发布版本的时候指定 minifyEnabled=true; 设置启用代码混淆,混淆规则记录在proguard-rules.pro这个文件中,
buildTypes{
release{
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}
}
指定混淆规则
混淆规则是用来指定是否混淆的规则,听起来像废话,在这个proguard-rules.pro中我们需要指定不需要混淆的类。哪些不需要混淆呢,我们分为基本指令区和定制指令区,基本指令区包括如下部分:
#-----------------------------基本指令区-------------------------------------------------------------
-optimizationpasses5#指定代码的压缩级别
-dontusemixedcaseclassnames#是否使用大小写混合
-dontpreverify#混淆时是否做预校验
-verbose#混淆时是否记录日志
-optimizations!code/simplification/arithmetic,!field/*,!class/merging/*#混淆时所采用的算法
-printmappingproguardMapping.txt
-keepattributes*Annotation*,InnerClasses
-keepattributesSignature
-keepattributesSourceFile,LineNumberTable
#-------------------------四大组件默认保留区---------------------------------------------------------
-keeppublic class * extends android.app.Activity
-keeppublic class * extends android.app.Application
-keeppublic class * extends android.app.Service
-keeppublic class * extends android.content.BroadcastReceiver
-keeppublic class * extends android.content.ContentProvider
-keeppublic class * extends android.app.backup.BackupAgentHelper
-keeppublic class * extends android.preference.Preference
-keeppublic class com.android.vending.licensing.ILicensingService
-keepclass android.support.** {*;}
#------------------------------------------------------------------------------------------------
-keepclasseswithmembernamesclass * {
native ;
}
-keepclasseswithmembersclass * {
public (android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembersclass * {
public (android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembersclass * extends android.app.Activity {
public void *(android.view.View);
}
#---------------------------------------------------------------------------------------------------
-keepclassmembersenum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keeppublic class * extends android.view.View{
*** get*();
void set*(***);
public (android.content.Context);
public (android.content.Context, android.util.AttributeSet);
public (android.content.Context, android.util.AttributeSet, int);
}
-keepclasseswithmembersclass * {
public (android.content.Context, android.util.AttributeSet);
public (android.content.Context, android.util.AttributeSet, int);
}
-keepclass * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
-keepclassmembersclass * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
-keepclass **.R$* {
*;
}
-keepclassmembersclass * {
void *(**On*Event);
}
#---------------------------------webview------------------------------------
-keepclassmembersclass fqcn.of.javascript.interface.for.Webview {
public *;
}
-keepclassmembersclass * extends android.webkit.WebViewClient {
public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
public boolean *(android.webkit.WebView, java.lang.String);
}
-keepclassmembersclass * extends android.webkit.WebViewClient {
public void *(android.webkit.WebView, jav.lang.String);
}
-keep 顾名思义 保留即 保留不需要混淆。除了基本指令区的需要保留,我们还有定制指令区需要保留,例如:实体类,json,webview,反射相关的类和方法,第三方jar文件,与js互相调用的类等。
//实体类 :保留该包下的类及子类,子类中方法等不混淆
-keep public class 包名.**{*;}
#zxing-第三方jar包 保留不被混淆
-libraryjars libs/zxing.jar
-dontwarn com.google.zxing.**
-keep class com.google.zxing.**{*;}
//so文件保留不被混淆
-libraryjars libs/x86/liblocSDK7a.so
注意:在此过程中尽可能剔除所有不需要混淆的类,避免不必要的闪退。