Android 代码混淆、调试及反编译

最近抽空研究了下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      #指定代码的压缩级别0-7

-dontusemixedcaseclassnames    #是否使用大小写混合

-dontpreverify          #混淆时是否做预校验

-verbose#        混淆时是否记录日志

-optimizations!code/simplification/arithmetic,!field/*,!class/merging/*      #混淆时所采用的算法

-printmapping     proguardMapping.txt

-keepattributes *Annotation*,InnerClasses

-keepattributes  Signature

-keepattributes  SourceFile,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

注意:在此过程中尽可能剔除所有不需要混淆的类,避免不必要的闪退。

运行时注意在release模式下,进行正常的签名打包。代码混淆过之后可以反编译一下,看看效果,如果暴露了一些重要信息,可再次修改proguard-rules.pro文件混淆重要信息。


对于第三方jar,或者依赖的项目,不需要混淆,通用写法参考如下:

-dontwarn 主要是避免警告,-keep 主要是保留不被混淆


混淆后崩溃调试

通常情况下,写好混淆代码以后安装release版本的apk到手机有时根本运行不起来,有时启动了瞬间崩溃,其实原因很简单我们应用的库或者第三方jar被混淆了导致无法正常调用,那怎么查找是哪些不该混淆了的被混淆了?



在Android studio 中生成release包的同时 build\outputs\mapping\release文件夹下也生成了4个文件

分别有以下文件:

+ dump.txt 描述apk文件中所有类文件间的内部结构。

+ mapping.txt 列出了原始的类,方法,和字段名与混淆后代码之间的映射。

+ seeds.txt 列出了未被混淆的类和成员

+ usage.txt 列出了从apk中删除的代码


一般情况下,我们直接看mapping 和seeds这2个文件夹就可以了,在我调试过程中,使用notedpad打开mapping文件,将近12万行,怪不得用txt打开瞬间崩溃卡死。

mapping文件记录了所有的混淆前后的映射关系,告诉你混淆前后,据我分析,混淆后文件会变成abc,有些库你可能忽略,但是mapping会记录所有,你会发现 不改映射的第三方包 也变成abc了,这里就是出错的根本,不该混淆的被混淆了,一一找出,在proguard-rules.pro中-dontwarn 包名,-keep class 包名 就可以顺利解决。12万行并不是让你一行一行去看的,点击对应包的关键字滚动查看。一一过滤。

seeds文件夹是帮你查看是否需要混淆的类没有被混淆,当然都是可以修改的,查看过程中会有errormessage,搜索一下,没有最好,有了解决掉,也许不应该混淆的被你混淆掉。


混淆过后,app顺利运行,这种感觉超爽。

最终检验

反编译一下看看是否成功混淆?

Android反编译工具套装:

我们需要工具dex2jar-2.0, jd-gui-windows-1.4.0,还需要一个apk 文件,dapp.apk,首先重命名为dapp.zip,解压缩得到dapp文件夹,得到dapp文件下的dex文件,将dex文件复制到dex2jar-2.0文件夹下。按下shift键的同时点击鼠标右键 打开命令窗口 ,在命令窗口中输入d2j-dex2jar.bat classes.dex 命令即可生成classes-dex2jar.jar文件。用jd-jui打开即可查看混淆后的代码。







至此就大功告成了,简单的代码混淆和反编译真的没有想象中那么难!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342