Android 逆向工程
1. Apk簽名
1). 建立簽名檔案
新建專案 -> build -> Generate Signed Bundle/APK... -> Create new...
圖1.png
2). 填寫簽名檔案相關資訊
點選確認會生成signed.jks檔案,將signed.jks檔案拷貝至<專案路徑>/app/
下
3). 在app/build.gradle檔案中配置
在android節點下配置signingConfigs節點,並在其節點下配置別名,密碼,檔案,檔案密碼屬性,最後在buildTypes下的release結點下配置signingConfig
android { // 簽名配置 signingConfigs { release { keyAlias 'test' keyPassword 'password' storeFile file('signed.jks') storePassword 'password' } } buildTypes { release { minifyEnabled false // 配置簽名 signingConfig signingConfigs.release proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } }
4). 打包
在<專案路徑>
下執行gradlew aR
命令打包,完成後提示資訊如圖3所示,並在<專案路徑>\app\build\outputs\apk\release\
路徑下檢視app--release.apk檔案。
5). 反編譯
工具:dex2jar
下載完成後,將dex2jar的路徑配置到環境變數中D:\Program\android\android_reverse\dex2jar;
6). 反編譯
將第4)步生成的app-release.apk解壓並進入該資料夾,並使用d2j-dex2jar classes.dex
命令將classes.dex檔案轉換為jar檔案
解壓完成後,會在當前目錄生成一個classes-dex2jar.jar
檔案,我這裡還生成了classes-error.zip檔案,是由於轉換過程中出現錯誤了,由於未影響之後的操作,所以這裡我忽略了這個錯誤。
7). 檢視classes-dex2jar.jar檔案
工具:jd-gui
使用jd-gui開啟classes-dex2jar.jar檔案
2. 混淆
1). 打包混淆
修改app/build.gradle
檔案中的android-buildTypes-release
中的minifyEnabled
屬性,設定為true,此時相關的混淆檔案有proguard-android.txt和proguard-rules.pro。
2). proguard-android.txt
位置:sdk\tools\proguard\proguard-android.txt
3). proguard-rules.pro
位置:<專案路徑>\app\proguard-rules.pro
4). 打包並讀取檔案
簽名 -> 打包 -> 反編譯, 後classes.dex中的內容如下,
圖9.png
5). 問題
此時的問題是,混淆了一些本不該混淆的檔案,那麼我們就需要自己去配置混淆規則,我們必須要自己修改proguard-rules.pro檔案
6). 新增混淆規則模板
-ignorewarnings # 忽略警告
-optimizationpasses 5 # 指定程式碼的壓縮級別
-dontusemixedcaseclassnames # 是否使用大小寫混合
-dontpreverify # 混淆時是否做預校驗
-verbose # 混淆時是否記錄日誌
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* # 混淆時所採用的演算法
# 保持子類不被混淆
-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.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
# 保持 native 方法不被混淆
-keepclasseswithmembernames class * {
native <methods>;
}
# 保持自定義控制元件類不被混淆
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
# 保持自定義控制元件類不被混淆
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
# 保持自定義控制元件類不被混淆
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
# 保持列舉 enum 類不被混淆
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
#保持Parcelable不被混淆
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
# Explicitly preserve all serialization members. The Serializable interface
# is only a marker interface, so it wouldn't save them.
# 保持序列號類不被混淆
-keep public class * implements java.io.Serializable {*;}
-keepclassmembers class * 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();
}
3.
1). 獲取簽名信息
public int getSignature() {
PackageManager packageManager = this.getPackageManager();
PackageInfo pi;
int sign = 0;
try {
pi = packageManager.getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES);
Signature[] signingInfo = pi.signatures;
sign = signingInfo[0].hashCode();
} catch (Exception ignored) {}
return sign;
}