Android 代碼混淆、調(diào)試及反編譯

最近抽空研究了下android 加殼技術(shù),發(fā)現(xiàn)關(guān)于加殼的源代碼特別少,即使有也不能做到版本兼容,問題又特別多,對app加殼感覺遠(yuǎn)沒有當(dāng)初想的那么簡單,而現(xiàn)階段成熟的加密軟件多是收費(fèi)的,愛加密,梆梆加固等。收費(fèi)就暫不考慮了,咱們只能曲線救國,也試過騰訊御安全,認(rèn)證通過了,也能查看安全報告,就是無法加固,試了很久一直再刷新,最終也沒有加固成功;試過網(wǎng)易云易盾,只是申請一下試用,打了幾個電話做廣告,最終也沒有同意申請。第三方加密平臺沒有money看來是行不通了!

我們都知道,常見的APP加密方法包括偽加密、混淆、運(yùn)行驗證和第三方加密平臺APP加密。

偽加密

偽加密是Android4.2.x系統(tǒng)發(fā)布前的加密方式之一,通過java代碼對APK(壓縮文件)進(jìn)行偽加密,其修改原理是修改連續(xù)4位字節(jié)標(biāo)記為”P K 01 02”的后第5位字節(jié),奇數(shù)表示不加密偶數(shù)表示加密。雖然偽加密可以起到一定防破解作用,但也會出現(xiàn)問題,首先使用偽加密對其APK加密后市場無法對其進(jìn)行安全檢測,導(dǎo)致部分市場會拒絕這類APK上傳;其次,偽加密的加密方式和解密方式也早已公布導(dǎo)致它的安全程度也大大降低;再次,Android4.2.x系統(tǒng)無法安裝偽加密的APK;最后偽加密只是對APK做簡單保護(hù),在java層源碼加殼保護(hù)、核心so庫、資源文件、主配文件、第三方架包方面卻沒有任何保護(hù)處理。

注意:高版本不支持這樣的方法,所以還是不要嘗試使用這樣的加密方式了?,F(xiàn)在Android 版本系統(tǒng)一般都是4.4以上的了,高版本也不支持,pass掉該加密方式。


驗證

APP加密之運(yùn)行時驗證,主要是指在代碼啟動的時候本地獲取簽名信息然后對簽名信息進(jìn)行檢驗來判斷自己的應(yīng)用是否是正版,如果簽名信息不是正版則提示盜版或者直接崩潰。當(dāng)然你可以把必要的數(shù)據(jù)放在服務(wù)器端。破解:找到smali文件中,判斷是否相等的部分。改為常量true,即失效??傊淳幾g一些apk之后,只要是java代碼寫的總會有smil文件。對于smil文件,如果耐心讀的話,還是可以查看到一些關(guān)鍵代碼的。




混淆

APP加密之混淆,混淆是把原來有具體含義的類名,變量名,方法名,修改成讓人看不懂的名字,例如方法名getUserName編程了方法名。代碼混淆只是增加APP代碼的閱讀難度,對APP安全起不到實質(zhì)的作用,但其是APP加密之前的一個必要步驟。

個人覺得混淆還是比較有用的,加密之前提供初步的保護(hù),就稍微研究了一下。



初步配置

大致:構(gòu)建類型有debug 和release版本,我們在發(fā)布版本的時候指定 minifyEnabled=true; 設(shè)置啟用代碼混淆,混淆規(guī)則記錄在proguard-rules.pro這個文件中,

buildTypes{

release{

minifyEnabled true

proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}

指定混淆規(guī)則

混淆規(guī)則是用來指定是否混淆的規(guī)則,聽起來像廢話,在這個proguard-rules.pro中我們需要指定不需要混淆的類。哪些不需要混淆呢,我們分為基本指令區(qū)和定制指令區(qū),基本指令區(qū)包括如下部分:



#-----------------------------基本指令區(qū)-------------------------------------------------------------

-optimizationpasses5 ? ? ?#指定代碼的壓縮級別0-7

-dontusemixedcaseclassnames ? ?#是否使用大小寫混合

-dontpreverify ? ? ? ? ?#混淆時是否做預(yù)校驗

-verbose# ? ? ? ?混淆時是否記錄日志

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

-printmapping ? ? proguardMapping.txt

-keepattributes *Annotation*,InnerClasses

-keepattributes ?Signature

-keepattributes ?SourceFile,LineNumberTable

#-------------------------四大組件默認(rèn)保留區(qū)---------------------------------------------------------

-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 顧名思義 :保留不需要混淆。除了基本指令區(qū)的需要保留,我們還有定制指令區(qū)需要保留,例如:實體類,json,webview,反射相關(guān)的類和方法,第三方j(luò)ar文件,與js互相調(diào)用的類等。


//實體類 :保留該包下的類及子類,子類中方法等不混淆

-keep public class 包名.**{*;}

#zxing-第三方j(luò)ar包 保留不被混淆

-libraryjars libs/zxing.jar

-dontwarn com.google.zxing.**

-keep class com.google.zxing.**{*;}

//so文件保留不被混淆,一般編譯過程中會自動忽略混淆。不需要單獨(dú)列出。

-libraryjars libs/x86/liblocSDK7a.so

注意:在此過程中盡可能剔除所有不需要混淆的類,避免不必要的閃退。

運(yùn)行時注意在release模式下,進(jìn)行正常的簽名打包。代碼混淆過之后可以反編譯一下,看看效果,如果暴露了一些重要信息,可再次修改proguard-rules.pro文件混淆重要信息。


對于第三方j(luò)ar,或者依賴的項目,不需要混淆,通用寫法參考如下:

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


混淆后崩潰調(diào)試

通常情況下,寫好混淆代碼以后安裝release版本的apk到手機(jī)有時根本運(yùn)行不起來,有時啟動了瞬間崩潰,其實原因很簡單我們應(yīng)用的庫或者第三方j(luò)ar被混淆了導(dǎo)致無法正常調(diào)用,那怎么查找是哪些不該混淆了的被混淆了?



在Android studio 中生成release包的同時 build\outputs\mapping\release文件夾下也生成了4個文件

分別有以下文件:

+ dump.txt 描述apk文件中所有類文件間的內(nèi)部結(jié)構(gòu)。

+ mapping.txt 列出了原始的類,方法,和字段名與混淆后代碼之間的映射。

+ seeds.txt 列出了未被混淆的類和成員

+ usage.txt 列出了從apk中刪除的代碼


一般情況下,我們直接看mapping 和seeds這2個文件夾就可以了,在我調(diào)試過程中,使用notedpad打開mapping文件,將近12萬行,怪不得用txt打開瞬間崩潰卡死。

mapping文件記錄了所有的混淆前后的映射關(guān)系,告訴你混淆前后,據(jù)我分析,混淆后文件會變成abc,有些庫你可能忽略,但是mapping會記錄所有,你會發(fā)現(xiàn) 不改映射的第三方包 也變成abc了,這里就是出錯的根本,不該混淆的被混淆了,一一找出,在proguard-rules.pro中-dontwarn 包名,-keep class 包名 就可以順利解決。12萬行并不是讓你一行一行去看的,點擊對應(yīng)包的關(guān)鍵字滾動查看。一一過濾。

seeds文件夾是幫你查看是否需要混淆的類沒有被混淆,當(dāng)然都是可以修改的,查看過程中會有errormessage,搜索一下,沒有最好,有了解決掉,也許不應(yīng)該混淆的被你混淆掉。


混淆過后,app順利運(yùn)行,這種感覺超爽。

最終檢驗

反編譯一下看看是否成功混淆?

Android反編譯工具套裝:

我們需要工具dex2jar-2.0, jd-gui-windows-1.4.0,還需要一個apk 文件,dapp.apk,首先重命名為dapp.zip,解壓縮得到dapp文件夾,得到dapp文件下的dex文件,將dex文件復(fù)制到dex2jar-2.0文件夾下。按下shift鍵的同時點擊鼠標(biāo)右鍵 打開命令窗口 ,在命令窗口中輸入d2j-dex2jar.bat classes.dex 命令即可生成classes-dex2jar.jar文件。用jd-jui打開即可查看混淆后的代碼。







至此就大功告成了,簡單的代碼混淆和反編譯真的沒有想象中那么難!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容