日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

Android混淆解析

發(fā)布時(shí)間:2025/7/25 Android 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android混淆解析 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

此文章轉(zhuǎn)載來(lái)源https://www.jianshu.com/p/84114b7feb38點(diǎn)擊打開(kāi)鏈接


Android混淆解析

?

一、混淆的目的

??????? 一款發(fā)布到市場(chǎng)的軟件原則上都應(yīng)該做代碼混淆。

??????? 通過(guò)代碼混淆可以將項(xiàng)目中的類(lèi)、方法、變量等信息進(jìn)行重命名,變成一些無(wú)意義的簡(jiǎn)短名字,同時(shí)也可以移除未被使用的類(lèi)、方法、變量等。所以直觀的看,通過(guò)混淆可以提高程序的安全性,增加逆向工程的難度,同時(shí)也有效縮減了apk的體積。一起來(lái)get這個(gè)技能吧!

?

二、開(kāi)啟混淆

??????? 在基于Android Studio項(xiàng)目的app module的build.gradle中有如下默認(rèn)代碼片段:

buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'signingConfig signingConfigs.release} }

??????? 代表要發(fā)布的release包的混淆配置,默認(rèn)不開(kāi)啟混淆,要開(kāi)啟混淆首先做如下修改:

minifyEnabled true

??????? 開(kāi)啟混淆后還可以添加shrinkResourcestrue配置,代表開(kāi)啟資源文件壓縮。

??????? 這樣就在release模式下開(kāi)啟了混淆。一般在debug模式下不開(kāi)啟混淆,因?yàn)榛煜龝?huì)導(dǎo)致編譯時(shí)間變長(zhǎng)、無(wú)法debug問(wèn)題,畢竟也是內(nèi)部測(cè)試嘛,沒(méi)必要!

??????? 開(kāi)啟混淆后,接下來(lái)就是用混淆配置文件來(lái)設(shè)置混淆規(guī)則:

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

·????????proguard-android.txt代表系統(tǒng)默認(rèn)的混淆規(guī)則配置文件,該文件在<AndroidSDK目錄>/tools/proguard下,一般不要更改該配置文件,因?yàn)橐矔?huì)作用于其它項(xiàng)目,除非你能確保所做的更改不影響其它項(xiàng)目的混淆。

·????????proguard-rules.pro代碼表當(dāng)前project的混淆配置文件,在app module下,可以通過(guò)修改該文件來(lái)添加適用當(dāng)前項(xiàng)目的混淆規(guī)則。

?

三、編寫(xiě)混淆配置文件

??????? 為了更好的編寫(xiě)proguard-rules.pro,先學(xué)習(xí)下系統(tǒng)的proguard-android.txt

# This is a configuration file for ProGuard. # http://proguard.sourceforge.net/index.html#manual/usage.html # 混淆時(shí)不使用大小寫(xiě)混合類(lèi)名 -dontusemixedcaseclassnames # 不跳過(guò)library中的非public的類(lèi) -dontskipnonpubliclibraryclasses # 打印混淆的詳細(xì)信息 -verbose # Optimization is turned off by default. Dex does not like code run # through the ProGuard optimize and preverify steps (and performs some # of these optimizations on its own). # 關(guān)閉優(yōu)化(原因見(jiàn)上邊的原英文注釋) -dontoptimize # 不進(jìn)行預(yù)校驗(yàn),可加快混淆速度 -dontpreverify # Note that if you want to enable optimization, you cannot just # include optimization flags in your own project configuration file; # instead you will need to point to the # "proguard-android-optimize.txt" file instead of this one from your # project.properties file. # 保留注解中的參數(shù) -keepattributes *Annotation* # 不混淆如下兩個(gè)谷歌服務(wù)類(lèi) -keep public class com.google.vending.licensing.ILicensingService -keep public class com.android.vending.licensing.ILicensingService # For native methods, see http://proguard.sourceforge.net/manual/examples.html#native # 不混淆包含native方法的類(lèi)的類(lèi)名以及native方法名 -keepclasseswithmembernames class * { ??? native <methods>; } # keep setters in Views so that animations can still work. # see http://proguard.sourceforge.net/manual/examples.html#beans # 不混淆View中的setXxx()和getXxx()方法,以保證屬性動(dòng)畫(huà)正常工作 -keepclassmembers public class * extends android.view.View { ?? void set*(***);*** get*(); } # We want to keep methods in Activity that could be used in the XML attribute onClick # 不混淆Activity中參數(shù)是View的方法,例如,一個(gè)控件通過(guò)android:onClick="clickMethodName"綁定點(diǎn)擊事件,混淆后會(huì)導(dǎo)致點(diǎn)擊事件失效 -keepclassmembers class * extends android.app.Activity { ?? public void *(android.view.View); } # For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations # 不混淆枚舉類(lèi)中的values()和valueOf()方法 -keepclassmembers enum * { ??? public static **[] values();public static ** valueOf(java.lang.String); } # 不混淆Parcelable實(shí)現(xiàn)類(lèi)中的CREATOR字段,以保證Parcelable機(jī)制正常工作 -keepclassmembers class * implements android.os.Parcelable { ? public static final android.os.Parcelable$Creator CREATOR; } # 不混淆R文件中的所有靜態(tài)字段,以保證正確找到每個(gè)資源的id -keepclassmembers class **.R$* { ??? public static <fields>; } # 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. # 不對(duì)android.support包下的代碼警告(如果我們打包的版本低于support包下某些類(lèi)的使用版本,會(huì)出現(xiàn)警告的問(wèn)題) -dontwarn android.support.** # Understand the @Keep support annotation. # 不混淆Keep類(lèi) -keep class android.support.annotation.Keep # 不混淆使用了注解的類(lèi)及類(lèi)成員 -keep @android.support.annotation.Keep class * {*;} # 如果類(lèi)中有使用了注解的方法,則不混淆類(lèi)和類(lèi)成員 -keepclasseswithmembers class * { ??? @android.support.annotation.Keep <methods>; } # 如果類(lèi)中有使用了注解的字段,則不混淆類(lèi)和類(lèi)成員 -keepclasseswithmembers class * { ??? @android.support.annotation.Keep <fields>; } # 如果類(lèi)中有使用了注解的構(gòu)造函數(shù),則不混淆類(lèi)和類(lèi)成員 -keepclasseswithmembers class * { ??? @android.support.annotation.Keep <init>(...); }

?

??????? 可以看出proguard-android.txt主要作用是防止指定內(nèi)容被混淆,其中使用了以-開(kāi)頭,結(jié)合keep類(lèi)關(guān)鍵字,*、<>等通配符的語(yǔ)法,先get這些語(yǔ)法吧!

·????????首先看keep類(lèi)關(guān)鍵字:

關(guān)鍵字?

含義

keep

保留類(lèi)和類(lèi)成員,防止被混淆或移除

Keepnames

保留類(lèi)和類(lèi)成員,防止被混淆,但沒(méi)有被引用的類(lèi)成員會(huì)被移除

keepclassmembers

只保留類(lèi)成員,防止被混淆或移除

keepclassmembernames?

只保留類(lèi)成員,防止被混淆,但沒(méi)有被引用的成員會(huì)被移除

keepclasseswithmembers

保留類(lèi)和類(lèi)成員,防止被混淆或移除,如果指定的類(lèi)成員不存在還是會(huì)被混淆

keepclasseswithmembernames

保留類(lèi)和類(lèi)成員,防止被混淆,如果指定的類(lèi)成員不存在還是會(huì)被混淆,沒(méi)有被引用的類(lèi)成員會(huì)被移除

?

?


·????????相關(guān)通配符:

通配符

?含義

*

匹配任意長(zhǎng)度字符,但不含包名分隔符.。例如一個(gè)類(lèi)的全包名路徑是com.othershe.test.Person,使用com.othershe.test.*com.othershe.test.*都是可以匹配的,但com.othershe.*就不能匹配

**?

匹配任意長(zhǎng)度字符,并包含包名分隔符.。例如要匹配com.othershe.test.**包下的所有內(nèi)容

***

?匹配任意參數(shù)類(lèi)型。例如*** getName(***)可匹配String getName(String)

...?

匹配任意長(zhǎng)度的任意類(lèi)型參數(shù)。例如void setName(...)可匹配void setName(String firstName, String secondName)

<fileds>

匹配類(lèi)、接口中所有字段

<methods>

匹配類(lèi)、接口中所有方法

<init>

匹配類(lèi)中所有構(gòu)造函數(shù)


??????? 到這里對(duì)混淆已經(jīng)有了基本的了解,系統(tǒng)的proguard-android.txt已經(jīng)為我們完成了大部分基礎(chǔ)的混淆配置工作,至于編寫(xiě)當(dāng)前appmodule下的proguard-rules.pro,只需要針對(duì)當(dāng)前項(xiàng)目添加一些特有的配置,避免某些重要的東西被混淆掉導(dǎo)致錯(cuò)誤,我們主要考慮以下幾點(diǎn):

· ? ? ? ?①、在AndroidManifest.xml中注冊(cè)的繼承四大組件的子類(lèi)的類(lèi)名以及重寫(xiě)的方法名都不會(huì)被混淆。如果希望項(xiàng)目中android.support.v4.app.Fragment子類(lèi)的類(lèi)名和重寫(xiě)父類(lèi)的方法名不被混淆可以添加如下配置:

# 不混淆Fragment的子類(lèi)類(lèi)名以及onCreate()、onCreateView()方法名 -keep public class * extends android.support.v4.app.Fragment { ??? public void onCreate(android.os.Bundle);public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle); }

· ? ? ? ?②、不混淆某個(gè)特定的類(lèi)和類(lèi)中所有成員

-keep class com.othershe.test.utils.CommonUtil { *; }

· ? ? ? ?③、不混淆某個(gè)目錄下的文件,例如使用Gson時(shí),數(shù)據(jù)bean不能被混淆,需要如下配置:

# com.othershe.test.model代表數(shù)據(jù)bean所在的全包名目錄 -keep class com.othershe.test.model.** { *; }

· ? ? ? ?④、上一條的具體原因是因?yàn)?span style="background:#D9D9D9">Gson用到了反射。如果我們自己使用了反射,例如

Field field = service.getField("BASE_URL");

注:BASE_URLservice所屬類(lèi)的一個(gè)字段名,則該字段不能被混淆。

· ? ? ? ?⑤、保留泛型

-keepattributes Signature

· ? ? ? ?⑥、保留用于調(diào)試堆棧跟蹤的行號(hào)信息(為了后期調(diào)試方便,建議配置)

-keepattributes SourceFile,LineNumberTable

· ? ? ? ?⑦、如果使用了上一行配置,還需要添加如下配置將源文件重命名為SourceFile,以便通過(guò)鼠標(biāo)點(diǎn)擊直達(dá)源文件:

-renamesourcefileattribute SourceFile

· ? ? ? ⑧、 WebView中使用了JS調(diào)用,需要添加如下配置:

-keepclassmembers class fqcn.of.javascript.interface.for.webview { ?? public *; }

· ? ? ? ?⑨、項(xiàng)目中使用的第三方library混淆規(guī)則,列舉了幾個(gè)常用的:

# okhttp -dontwarn okhttp3.** -dontwarn okio.** -dontwarn javax.annotation.** -keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase# Retrofit -dontwarn okio.** -dontwarn javax.annotation.** -dontnote retrofit2.Platform -dontwarn retrofit2.Platform$Java8 -keepattributes Signature -keepattributes Exceptions# RxJava RxAndroid -dontwarn sun.misc.** -keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* { ??? long producerIndex;long consumerIndex; } -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef { ??? rx.internal.util.atomic.LinkedQueueNode producerNode; } -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef { ??? rx.internal.util.atomic.LinkedQueueNode consumerNode; }# Gson -keep class com.google.gson.stream.** { *; } -keepattributes EnclosingMethod # xxx代表model類(lèi)的全包名路徑 -keep class xxx.** { *; }# butterknie -keep class butterknife.** { *; } -dontwarn butterknife.internal.** -keep class **$$ViewBinder { *; } -keepclasseswithmembernames class * { ??? @butterknife.* <fields>; } -keepclasseswithmembernames class * { ??? @butterknife.* <methods>; }# eventbus -keepattributes *Annotation* -keepclassmembers class ** { ??? @org.greenrobot.eventbus.Subscribe <methods>; } -keep enum org.greenrobot.eventbus.ThreadMode { *; } # Only required if you use AsyncExecutor -keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent { ??? <init>(java.lang.Throwable); }

以上這些可以按需添加到proguard-rules.pro

?

四、查看混淆結(jié)果

?

??????? 混淆后打包,會(huì)在appmodule/build/outputs/mapping/release目錄下生成如下文件(動(dòng)不動(dòng)就幾萬(wàn)行,是在沒(méi)法看):


·????????dump.txt:描述apk文件中所有類(lèi)的內(nèi)部結(jié)構(gòu)

·????????mapping.txt:混淆前后的類(lèi)、類(lèi)成員、方法的對(duì)照關(guān)系(重要,追溯Crash堆棧信息要用到)

·????????resources.txt:資源文件的壓縮信息

·????????seeds.txt:未被混淆的類(lèi)和成員

·????????usage.txt:被移除的代碼

混淆后的apk包,需要系統(tǒng)的測(cè)試,防止混淆導(dǎo)致的潛在bug

?

我們還是有必要看一下混淆后的代碼結(jié)構(gòu),驗(yàn)證混淆是否成功。一個(gè)簡(jiǎn)單的辦法,Android StudioBuild菜單下有一個(gè)Analyze APK選項(xiàng),只需要先選擇要分析的apk包,在之后的界面點(diǎn)擊classes.dex即可看到混淆后的代碼結(jié)構(gòu):


但是這樣只能看到一個(gè)類(lèi)的成員變量和方法的結(jié)構(gòu),如果要看一個(gè)類(lèi)的具體內(nèi)容,就需要反編譯apk包了,具體可參考Android apk反編譯及重新打包流程,希望一切順利!

?

五、 追溯Crash堆棧信息

代碼混淆后,也會(huì)導(dǎo)致Crash堆棧信息被混淆,難以閱讀,增加定位問(wèn)題位置的難度,一個(gè)混淆后的Crash堆棧信息類(lèi)似這樣,核心的信息都沒(méi)了:


為了解決這個(gè)問(wèn)題,可以使用<SDK目錄>\tools\proguard\bin下的proguardgui.bat腳本將Crash堆棧信息還原到混淆前的狀態(tài)。步驟如下:

1.?雙擊打開(kāi)腳本,選擇左邊的ReTrace選項(xiàng)

2.?選擇Mappingfile文件,也就是混淆后打包后在appmodule/build/outputs/mapping/release下生成的mapping.txt

3.?拷貝混淆后的堆棧信息

4.?點(diǎn)擊右下角的ReTrace!按鈕,完成Crash堆棧信息的追溯

?

如下圖中間部分就是追溯到的原Crash堆棧信息:


代碼混淆常用的內(nèi)容就這些了,重點(diǎn)還是要理解混淆的相關(guān)語(yǔ)法,靈活運(yùn)用!混淆一定程度增加逆向工程的難度,但還是能被破解的,如果你的代碼有價(jià)值,也難免被有心的人利用!除了混淆之外,一些廠商也提供了apk加固的服務(wù)來(lái)保證軟件的安全性,但也是可以被脫殼的!有興趣的可自行了解!

總結(jié)

以上是生活随笔為你收集整理的Android混淆解析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。