Android reverse series: Android APK code obfuscation
- Publish article
Android reverse series: Android APK code obfuscation
Synchronous scrolling: Open
You can attack my app, then I must have a defensive strategy. Next, let's introduce Android Obfuscation technology in
Note : The following demonstrations are all
Github Demo Address: github.com/sweetying52…
1. jadx Introduction to
Before this, I would like to introduce another decompilation tool: jadx, which is equivalent to APKtool + dex2JAR + jd-gui The combination of the combination can both decompile code and decompile resources. The key is very simple to use. You only need to drag the file in, which improves our development efficiency to a certain extent.
Github Address: github.com/skylot/jadx
1.1, jadx features
1, can decompile the code in APK, AAR, JAR, DEX, AAB, ZIP and other files into Java class
2, can decompile resources in APK, AAR, AAB, ZIP and other files
1.2, jadx Install
1, install jadx, it is recommended to use brew to install, execute the following command:
brew install jadxUse brew The advantage of installing is that mac will automatically configure environment variables for you. You only need to focus on the use of the software, wait for the installation to be completed. Verify
2, jadx Verify
In Terminal Enter the following command:
jadx --versionIf the version number is printed, it proves that the installation is successful:

1.3, jadx use
Here we use jadx directly The provided visual interface is used to operate
1. Enter the following command in Terminal:
jadx-guiAt this time, the visual interface of jadx will be opened:

2. Drag the file you need to decompile to view the decompiled code and resources, as shown in the figure below:

2. Obfuscating APK code
2.1. Preparation
First we do some preparations
1. Add some classes:
//1. Create a new Utils.java file and create Utils class public class Utils {public void methodNormal(){String logMessage = "this is normal method";logMessage = logMessage.toLowerCase();System.out.println(logMessage);}public void methodUnused(){String logMessage = "this is unused method";logMessage = logMessage.toLowerCase();System.out.println(logMessage);}}//2. Create NativeUtils.java File, create the NativeUtils class public class NativeUtils {public static native void methodNative();public static void methodNotNative(){String logMessage = "this is not native method";logMessage = logMessage.toLowerCase();System.out.println(logMessage);}}//3. Create a new MyFragment.java file, create the MyFragment class public class MyFragment extends Fragment {private String toastTips = "toast in MyFragment";@Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {View rootView = inflater.inflate(R.layout.fragment_layout,container,false);methWithGlobalVariable();methWithLocalVariable();return rootView;}private void methodWithGlobalVariable() {Toast.makeText(getActivity(), toastTips, Toast.LENGTH_SHORT).show();}private void methodWithLocalVariable() {String logMessage = "log in MyFragment";logMessage = logMessage.toLowerCase();System.out.println(logMessage);}}2, then reference in MainActivity
public class MainActivity extends AppCompatActivity {String toastTips = "toast in MainActivity";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);getSupportFragmentManager().beginTransaction().add(R.id.flFragmentContainer,new MyFragment()).commit();//1. Method call under Utils utils = new Utils();utils.methodNormal();//2. Method call under NativeUtils try {NativeUtils.methodNative();NativeUtils.methodNotNative();} catch (Throwable e) {e.printStackTrace();}//3. Method call of tool class under third-party library int result = StringUtils.getLength("erdai666");System.out.println(result);//4. The methodWithGlobalVariable method under MainActivity calls methodWithGlobalVariable();//5. The methodWithLocalVariable method under MainActivity calls methodWithLocalVariable();}private void methodWithGlobalVariable() {Toast.makeText(this, toastTips, Toast.LENGTH_SHORT).show();}private void methodWithLocalVariable() {String logMessage = "log in MainActivity";logMessage = logMessage.toLowerCase();System.out.println(logMessage);}}OK, the preparation work has been basically completed here. Next, we obfuscate the code in the APK
2.2, enable obfuscation and APK package
1, in the app Open code obfuscation in the release closure under the Android closure in the build.Gradle file:
android {buildTypes {release {// enable code obfuscation minifyEnabled trueproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}}Above we only changed minifyEnabled to true That is, code obfuscation is enabled, very simple
Also, you need to pay attention to : This is configured in the release closure, so only if the official APK is released will be obfuscated, and the debug version of APK will not be obfuscated.Of course, this is also very reasonable, because we will only use debug version APK files for internal testing, and we don’t have to worry about being cracked.
2. Next, create an official APK package
1. Click Build - Generate Signed Bundle or APK in the Android Studio navigation bar, select APK
2, then select the signature file and enter the password. If there is no signature file, create an
3. Click next to select the release package, and finally click Finish to complete the packaging
4. The generated APK will be automatically stored in the app/release/ directory
Tips: We can build.gradle in the app Add signature file configuration to the file, and you can then directly operate through the ./gradlew assembleRelease command or the Gradle visual interface on the right side of AndroidStudio:
android {//1, declare the signature file signingConfigs{release{storeFile file('../Certificate')storePassword 'erdai666' keyAlias 'key0'keyPassword 'erdai666'}}buildTypes {release {minifyEnabled trueproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'//2. Configure the signature file signingConfig signingConfigs.release}}}Note :
1. APK generated using the AndroidStudio navigation bar Generate Signed Bundle or APK. In the directory
2, use the ./gradlew assembleRelease command or AndroidStudio The APK generated by the Gradle visualization boundary on the right is
3 in the app/build/outputs/apk/ directory. Then use jadx to open the current APK, as shown in the figure below:

It is obvious that our code obfuscation of function has taken effect.
2.3. Introduction to obfuscation file
. Let's try to read the classes prepared before obfuscation:
MainActivity:

You can see:
1. MyFragment is obfuscated
2. Method calls under Utils: Directly copy the contents in the method to the call of the method
3. Method calls under NativeUtils: 1. Native method or normal call 2. Non-Native The method is to copy the contents of the method to the method call
4. The method calls of the tool class under the third-party library: directly fill the result of the method to the call
5. The member method in MainActivity: directly copy the contents of the member method to the call
6. The MainActivity class name is not confusing, and the onCreate method is not confusing, but the defined member variables, local variable is confusing
Utils 11:
Utils The class is gone directly
NativeUtils:

You can see:
1, NativeUtils class name is not obfuscated, and the method declared as native is not obfuscated
2, non-Native methods are gone directly, and the content of the method is copied to the method call
MyFragment:

You can see:
1, all method names, member variables, and local variables are obfuscated
2, MyFragment Member methods in: Directly copy the contents of the member method to the method call
Next, analyze the above obfuscation results in :
1, Utils is gone because the contents of the called method are copied directly to the method call. Another method that is not called is considered unnecessary code and is removed when packaged. Not only methods, but resources that are not called will also be removed. This benefit is that the size of the APK can be reduced. The NativeUtils class name is not obfuscated because it has a method declared as native. As long as there is a native method in a class, its class name will not be obfuscated, and the method name of the native method will not be obfuscated, because C or C++ codes need to interact through package name + class name + method name.However, other codes in the class will still be obfuscated, and its non-Native methods are gone directly because the content in the method is copied to the method call
3. MyFragment is confusing completely, with basically no reservations. Even the life cycle method is obfuscated. Fragment is considered a system component at all, and it is not ashamed of
4. MainActivity is much better than MyFragment. At least like the class name, the life cycle method is not obfuscated. This is because: all classes that need to be registered in AndroidManifest.xml and the method names rewritten from the parent class will not be obfuscated.Therefore, in addition to Activity, this rule also applies to: Service, BroadcastReceiver and ContentProvider
5. The introduced third-party library is also confused. As can be seen above, it is directly filled with the result of the method call.
2.4. Default obfuscation rules are introduced
. So where are these obfuscation rules defined? In fact, it is the proguard-android-optimize.txt file configured under the release closure of build.gradle just now. This file is stored in the Android SDK/tools/proguard/ directory:

Take a look at its specific content:
# This is a configuration file for ProGuard.# http://proguard.sourceforge.net/index.html#manual/usage.html## This file is no longer maintained and is not used by new (2.2+) versions of the# Android plugin for Gradle. Instead, the Android plugin for Gradle generates the# default rules at build time and stores them in the build directory.# Optimizations: If you don't want to optimize, use the# proguard-android.txt configuration file instead of this one, which# turn off the optimization flags.Adding optimization introductions# certain risks, since for example not all optimizations performed by# ProGuard works on all versions of Dalvik.The following flags turn# off various optimizations known to have issues, but the list may not# be complete or up to date. (The "arithmetic" optimization can be# used if you are only targeting Android 2.0 or later.)Make sure you# test thoroughly if you go this route.-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*-optimizationpasses 5-allowaccessmodification-dontpreverify# The remainder of this file is identical to the non-optimized version# of the Proguard configuration file (except that the other file has# flags to turn off optimization).-dontusemixedcaseclassnames-dontskipnonpubliclibraryclasses-verbose-keepattributes *Annotation*-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-keepclasseswithmembernames class * {native methods;}# keep setters in Views so that animations can still work.# see http://proguard.sourceforge.net/manual/examples.html#beans-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-keepclassmembers class * extends android.app.Activity { public void *(android.view.View);}# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations-keepclassmembers enum * {public static **[] values();public static ** valueOf(java.lang.String);}-keepclassmembers class * implements android.os.Parcelable {public static final android.os.Parcelable$Creator CREATOR;}-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.-dontwarn android.support.**# Understand the @Keep support annotation.-keep class android.support.annotation.Keep-keep @android.support.annotation.Keep class * {*;}-keepclasseswithmembers class * {@android.support.annotation.Keep methods;}-keepclasseswithmembers class * {@android.support.annotation.Keep fields;}-keepclasseswithmembers class * {@android.support.annotation.Keep init(...);}This is the default obfuscation configuration file. Let's explain it line by line:
# Start some configurations related to optimization# Specify a more refined level of optimization-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*# Indicates the number of times the code is optimized, generally 5-optimizationpasses 5# Allows to change scope -allowaccessmodification# Turn off pre-validation-dotpreverify# means not to use case mixed class names when obfuscating -dontusemixedcaseclassnames# means not to skip non-public classes in library -dontskipnonpubliclibraryclasses# means to print detailed information about obfuscating -verbose# means to reserve parameters in annotation - keepattributes *Annotation*# means not to confuse the two classes declared below, which are basically not used, and are used when connecting to some services native to Google -keep public class com.google.vending.licensing.ILicensingService-keep public class com.android.vending.licensing.ILicensingService# means not confusing any class name containing native methods and native method names. This is consistent with the result of verification just now -keepclasseswithmembernames class * {native methods;}# means not confusing the setXXX() and getXXX() methods in the View, because the property animation needs to have corresponding setters and getter methods implementation -keepclassmembers public class * extends android.view.View { void set*(***); *** get*();}# means not confusing the method in the Activity parameter is the View, because there is such a usage, in XML Configure the android:onClick="btnClick" attribute, and find # if you are confused - keepclassmembers class * extends android.app.Activity { public void *(android.view.View);}# means that the values() and valueOf() methods of enumeration are not confused - keepclassmembers enum * {public static **[] values();public static ** valueOf(java.lang.String);}# means that the CREATOR field in the Parcelable implementation class cannot be confused. There is no doubt that the CREATOR field cannot be changed, including upper and lower case, otherwise the whole # The working mechanism of Parcelable will be invalid - keepclassmembers class * implements android.os.Parcelable {public static final android.os.Parcelable$Creator CREATOR;}# means not obfuscating all static fields in the R file. We all know that the R file records each resource id through fields. If the field name is obfuscated, the id will not be found - keepclassmembers class **.R$* {public static fields;}# means not to warn the code under the android.support package, because all the code in the support package has made sufficient judgments on compatibility, so there is no need to worry about the code going wrong # So just ignore the warning - dontwarn android.support.**# means not confusing everything in the class android.support.annotation.Keep - keep class android.support.annotation.Keep means not confusing everything in the class annotated class android.support.Keep - keepplatseswithmembers class * {@android.support.annotation.Keep methods;}# means not confusing class names and class annotated methods in the class android.support.Keep methods;}# means not confusing class names and class annotated methods in the class android.support.Keep annotation attributes - keepclasseswithmembers class * {@android.support.annotation.Keep fields;}# indicates that the class name is not confused and the constructor method of class android.support.Keep annotation is used in the class - keepclasseswithmembers class * {@android.support.annotation.Keep init(...);}2.4.1, proguard-android-optimize.txt and proguard-android.txt The difference between some of the previous AGPs before
In the old version, the default use of our new project is: proguard-android.txt, so what is the difference between it and proguard-android-optimize.txt?
From the literal dimension, there is one more word optimization, which actually means more optimization. Proguard-android-optimize.txt enables optimization-related configurations compared to proguard-android.txt:
# proguard-android-optimize.txt The following optimization rules have been added -optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*-optimizationpasses 5-allowaccessmodification-dontpreverify# proguard-android-optimize.txt Delete the configuration of the closing optimization directive # -dontoptimize. The above is all the default configurations in the proguard-android-optimize.txt file, and our obfuscation code is also obfuscated according to the rules of these configurations.After the above explanation, I believe everyone can basically understand the content of these configurations. However, there are still several very difficult parts in the Proguard syntax. Let me share with you these difficult syntax parts.
2.5 and Proguard difficult syntax introduction
Proguard has three groups of six in the Proguard keep Many people don't understand the difference between keywords, let's take a look at them intuitively through a table:
keywords
description
keeppairs the members of the class and the class are not obfuscated or removed
keep in keep On the basis of this, if the member is not referenced, it will be removed
keepclass members not obfuscated or removed
keepclass members not obfuscated or removed
keepclass members On the basis of this, if the member is not referenced, it will be removed
keeps the members of the class and the members in the class not be obfuscated or removed, assuming that the members in the class must exist, otherwise it will still be obfuscated
keepclass with membernames
On the basis of keepclasswith members, if the member is not referenced, it will be removed
In addition, Proguard The wildcard characters are also difficult to understand, proguard-android-optimize.txt There are many wildcard characters used in it. Let's take a look at the difference between them:
wildcard characters
description
field
matches all fields in the class
method
matches all methods in the class
init
matches all constructors in the class
matches all constructors in the class
*
matches any length characters, but does not contain the separator .. For example, our completion class name is: com.dream.androidreversedemo.MainActivity, use com.* or com.dream.* cannot match because * The delimiter in the registration cannot be matched. The correct way to match is com.dream.*.* or com.dream.androidreversedemo.*
**
matches any length characters. Contains the delimiter .. The above matching rules can be used to match com.** or com.dream.** to match
***
matches any parameter type.For example, void set*(***) can match any parameter type passed in, ***get(*) can match any return value type
...
match any type parameter of any length, for example, void test(...) can match void test(String str) or void test(int a, double b) these methods
ok, and learned the difficult syntax. Let's take a exercise question: All information of the class that implements the com.dream.test.BaseJsonData interface is not confused?
A clear idea is very important. Let's analyze it carefully:
1. First, we must ensure that the com.dream.test.BaseJsonData interface is not confused
2. Then we must ensure that the class that implements the com.dream.test.BaseJsonData interface is not confused
3. Finally, it is to match all members of the class that are not confused. You can use the wildcard character *
. We can write this:
# Ensure that the com.dream.test.BaseJsonData interface is not confused - keep class com.dream.test.BaseJsonData# Ensure that the class that implements the com.dream.test.BaseJsonData interface is not confused # All members of the matching class are not obfuscated. You can use the wildcard character *-keep class * implements com.dream.test.BaseJsonData{*;}2.6. Custom obfuscating rules
. Return to the project. Although the APK just hit has been successfully obfuscated, the obfuscating rules are based on the default rules in proguard-android-optimize.txt. Of course, we can modify the rules in proguard-android-optimize.txt, but doing so will take effect on the obfuscating rules of all projects on the machine. So is there any good way to modify the obfuscating rules only for the current project?
Answer: For custom obfuscation rules for proguard-rules.pro file, you can see the configuration of the release closure under the Android closure. In fact, there are two obfuscation files. One is the default obfuscation rules we introduced earlier, and the other is the custom obfuscation rules:
android {buildTypes {release {minifyEnabled true//proguard-android-optimize.txt: Default obfuscation rules proguard-rules.pro: Custom obfuscation rules proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}}proguard-rules.pro file is located in the app directory. Next, we will use the Proguard related knowledge we just learned to modify the obfuscation rules.
Here we list the goals we want to achieve:
1. Completely retain the MyFragment class without confusing any information
2. Completely retain the MainActivity class without confusing any information
3. Keep the methods in Utils to prevent them from being confused or removing
4. Non-Native in NativeUtils Methods are retained to prevent them from being confused or removing
5, and third-party libraries from being confused or removing
. The implementation is as follows:
# The MyFragment class is fully retained without confusing any information - keep class com.dream.androidreversedemo.MyFragment{*;}# The MainActivity class is completely retained without confusing any information - keep class com.dream.androidreversedemo.MainActivity{*;}# The method in Utils is retained to prevent them from being confused or removing - keep class com.dream.androidreversedemo.Utils{*;}# Keep non-Native methods in NativeUtils to prevent them from being removed - keepclassmembers class com.dream.androidreversedemo.NativeUtils{public static void methodNotNative();}# Keep third-party libraries to prevent them from being confused or removed - keep class com.dream.androidutils.*{*;}has written custom rules, and now we will re-print a formal version of the APK File, then look at the effect in decompilation:

You can see that all the code in the classes we wrote ourselves and the third-party libraries introduced are retained. No matter the package name, the class name is not obfuscated
Then look at the specific class:
MainActivity:

Utils:

NativeUtils:

MyFragment:

can be seen that the above classes have basically been retained in
ok according to our requirements. After the above example, I believe everyone has already made it clear. I have a pretty good understanding of the usage of Proguard, so it is not difficult to write obfuscation configurations based on my own business needs, right?
has talked about the obfuscation APK code. If you want to know more about the usage of Proguard, you can refer to this article: juejin.cn/post/684490…
3. Summary
This article mainly introduces:
1. The installation of the decompilation tool jadx and the use of
jadx is equivalent to a combination of apktool + dex2jar + jd-gui. It can both decompile code and decompile resources, which to a certain extent improves our development efficiency
2. Obfuscation APK Code
1. Some classes (custom written classes, third-party libraries) have been prepared for the effect verification after obfuscation
2. In the app - build.gradle - android closure - release closure set minifyEnabled to true to enable code obfuscation
3. Use the Generate Signed Bundle or APK on the AndroidStudio navigation bar to type the release package
4. Configure the signature file in the app's build.gradle file to facilitate subsequent use of gradle command or gradle visual interface to package
5. The default obfuscation rule file is introduced line by line. Proguard-android-optimize.txt configuration
6, Proguard difficult syntax introduction
7, Custom obfuscation rules reserved class (custom written class, third-party library class) will not be confused
OK, this article ends here, I hope it can help you
Author: sweetying
Of course, this is also very reasonable, because we will only use debug version APK files for internal testing, and we don’t have to worry about being cracked.
Link: https://juejin.cn/post/7168086915445424136
Source: Rare Earth Nuggets2. Next, create an official APK package
1. Click Build - Generate Signed Bundle or APK in the Android Studio navigation bar, select APK
2, then select the signature file and enter the password. If there is no signature file, create an
3. Click next to select the release package, and finally click Finish to complete the packaging
4. The generated APK will be automatically stored in the app/release/ directory
Tips: We can build.gradle in the app Add signature file configuration to the file, and you can then directly operate through the ./gradlew assembleRelease command or the Gradle visual interface on the right side of AndroidStudio:
android {//1, declare the signature file signingConfigs{release{storeFile file('../Certificate')storePassword 'erdai666' keyAlias 'key0'keyPassword 'erdai666'}}buildTypes {release {minifyEnabled trueproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'//2. Configure the signature file signingConfig signingConfigs.release}}}Note :
1. APK generated using the AndroidStudio navigation bar Generate Signed Bundle or APK. In the directory
2, use the ./gradlew assembleRelease command or AndroidStudio The APK generated by the Gradle visualization boundary on the right is
3 in the app/build/outputs/apk/ directory. Then use jadx to open the current APK, as shown in the figure below:

It is obvious that our code obfuscation of function has taken effect.
2.3. Introduction to obfuscation file
. Let's try to read the classes prepared before obfuscation:
MainActivity:

You can see:
1. MyFragment is obfuscated
2. Method calls under Utils: Directly copy the contents in the method to the call of the method
3. Method calls under NativeUtils: 1. Native method or normal call 2. Non-Native The method is to copy the contents of the method to the method call
4. The method calls of the tool class under the third-party library: directly fill the result of the method to the call
5. The member method in MainActivity: directly copy the contents of the member method to the call
6. The MainActivity class name is not confusing, and the onCreate method is not confusing, but the defined member variables, local variable is confusing
Utils 11:
Utils The class is gone directly
NativeUtils:

You can see:
1, NativeUtils class name is not obfuscated, and the method declared as native is not obfuscated
2, non-Native methods are gone directly, and the content of the method is copied to the method call
MyFragment:

You can see:
1, all method names, member variables, and local variables are obfuscated
2, MyFragment Member methods in: Directly copy the contents of the member method to the method call
Next, analyze the above obfuscation results in :
1, Utils is gone because the contents of the called method are copied directly to the method call. Another method that is not called is considered unnecessary code and is removed when packaged. Not only methods, but resources that are not called will also be removed. This benefit is that the size of the APK can be reduced. The NativeUtils class name is not obfuscated because it has a method declared as native. As long as there is a native method in a class, its class name will not be obfuscated, and the method name of the native method will not be obfuscated, because C or C++ codes need to interact through package name + class name + method name.However, other codes in the class will still be obfuscated, and its non-Native methods are gone directly because the content in the method is copied to the method call
3. MyFragment is confusing completely, with basically no reservations. Even the life cycle method is obfuscated. Fragment is considered a system component at all, and it is not ashamed of
4. MainActivity is much better than MyFragment. At least like the class name, the life cycle method is not obfuscated. This is because: all classes that need to be registered in AndroidManifest.xml and the method names rewritten from the parent class will not be obfuscated.
Android reverse series: Android APK code obfuscation- Publish article
Android reverse series: Android APK code obfuscation
Synchronous scrolling: Open
You can attack my app, then I must have a defensive strategy. Next, let's introduce Android Obfuscation technology in
Note : The following demonstrations are all
Github Demo Address: github.com/sweetying52…
1. jadx Introduction to
Before this, I would like to introduce another decompilation tool: jadx, which is equivalent to APKtool + dex2JAR + jd-gui The combination of the combination can both decompile code and decompile resources. The key is very simple to use. You only need to drag the file in, which improves our development efficiency to a certain extent.
Github Address: github.com/skylot/jadx
1.1, jadx features
1, can decompile the code in APK, AAR, JAR, DEX, AAB, ZIP and other files into Java class
2, can decompile resources in APK, AAR, AAB, ZIP and other files
1.2, jadx Install
1, install jadx, it is recommended to use brew to install, execute the following command:
brew install jadxUse brew The advantage of installing is that mac will automatically configure environment variables for you. You only need to focus on the use of the software, wait for the installation to be completed. Verify
2, jadx Verify
In Terminal Enter the following command:
jadx --versionIf the version number is printed, it proves that the installation is successful:

1.3, jadx use
Here we use jadx directly The provided visual interface is used to operate
1. Enter the following command in Terminal:
jadx-guiAt this time, the visual interface of jadx will be opened:

2. Drag the file you need to decompile to view the decompiled code and resources, as shown in the figure below:

2. Obfuscating APK code
2.1. Preparation
First we do some preparations
1. Add some classes:
//1. Create a new Utils.java file and create Utils class public class Utils {public void methodNormal(){String logMessage = "this is normal method";logMessage = logMessage.toLowerCase();System.out.println(logMessage);}public void methodUnused(){String logMessage = "this is unused method";logMessage = logMessage.toLowerCase();System.out.println(logMessage);}}//2. Create NativeUtils.java File, create the NativeUtils class public class NativeUtils {public static native void methodNative();public static void methodNotNative(){String logMessage = "this is not native method";logMessage = logMessage.toLowerCase();System.out.println(logMessage);}}//3. Create a new MyFragment.java file, create the MyFragment class public class MyFragment extends Fragment {private String toastTips = "toast in MyFragment";@Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {View rootView = inflater.inflate(R.layout.fragment_layout,container,false);methWithGlobalVariable();methWithLocalVariable();return rootView;}private void methodWithGlobalVariable() {Toast.makeText(getActivity(), toastTips, Toast.LENGTH_SHORT).show();}private void methodWithLocalVariable() {String logMessage = "log in MyFragment";logMessage = logMessage.toLowerCase();System.out.println(logMessage);}}2, then reference in MainActivity
public class MainActivity extends AppCompatActivity {String toastTips = "toast in MainActivity";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);getSupportFragmentManager().beginTransaction().add(R.id.flFragmentContainer,new MyFragment()).commit();//1. Method call under Utils utils = new Utils();utils.methodNormal();//2. Method call under NativeUtils try {NativeUtils.methodNative();NativeUtils.methodNotNative();} catch (Throwable e) {e.printStackTrace();}//3. Method call of tool class under third-party library int result = StringUtils.getLength("erdai666");System.out.println(result);//4. The methodWithGlobalVariable method under MainActivity calls methodWithGlobalVariable();//5. The methodWithLocalVariable method under MainActivity calls methodWithLocalVariable();}private void methodWithGlobalVariable() {Toast.makeText(this, toastTips, Toast.LENGTH_SHORT).show();}private void methodWithLocalVariable() {String logMessage = "log in MainActivity";logMessage = logMessage.toLowerCase();System.out.println(logMessage);}}OK, the preparation work has been basically completed here. Next, we obfuscate the code in the APK
2.2, enable obfuscation and APK package
1, in the app Open code obfuscation in the release closure under the Android closure in the build.Gradle file:
android {buildTypes {release {// enable code obfuscation minifyEnabled trueproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}}Above we only changed minifyEnabled to true That is, code obfuscation is enabled, very simple
Also, you need to pay attention to : This is configured in the release closure, so only if the official APK is released will be obfuscated, and the debug version of APK will not be obfuscated.Of course, this is also very reasonable, because we will only use debug version APK files for internal testing, and we don’t have to worry about being cracked.
2. Next, create an official APK package
1. Click Build - Generate Signed Bundle or APK in the Android Studio navigation bar, select APK
2, then select the signature file and enter the password. If there is no signature file, create an
3. Click next to select the release package, and finally click Finish to complete the packaging
4. The generated APK will be automatically stored in the app/release/ directory
Tips: We can build.gradle in the app Add signature file configuration to the file, and you can then directly operate through the ./gradlew assembleRelease command or the Gradle visual interface on the right side of AndroidStudio:
android {//1, declare the signature file signingConfigs{release{storeFile file('../Certificate')storePassword 'erdai666' keyAlias 'key0'keyPassword 'erdai666'}}buildTypes {release {minifyEnabled trueproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'//2. Configure the signature file signingConfig signingConfigs.release}}}Note :
1. APK generated using the AndroidStudio navigation bar Generate Signed Bundle or APK. In the directory
2, use the ./gradlew assembleRelease command or AndroidStudio The APK generated by the Gradle visualization boundary on the right is
3 in the app/build/outputs/apk/ directory. Then use jadx to open the current APK, as shown in the figure below:

It is obvious that our code obfuscation of function has taken effect.
2.3. Introduction to obfuscation file
. Let's try to read the classes prepared before obfuscation:
MainActivity:

You can see:
1. MyFragment is obfuscated
2. Method calls under Utils: Directly copy the contents in the method to the call of the method
3. Method calls under NativeUtils: 1. Native method or normal call 2. Non-Native The method is to copy the contents of the method to the method call
4. The method calls of the tool class under the third-party library: directly fill the result of the method to the call
5. The member method in MainActivity: directly copy the contents of the member method to the call
6. The MainActivity class name is not confusing, and the onCreate method is not confusing, but the defined member variables, local variable is confusing
Utils 11:
Utils The class is gone directly
NativeUtils:

You can see:
1, NativeUtils class name is not obfuscated, and the method declared as native is not obfuscated
2, non-Native methods are gone directly, and the content of the method is copied to the method call
MyFragment:

You can see:
1, all method names, member variables, and local variables are obfuscated
2, MyFragment Member methods in: Directly copy the contents of the member method to the method call
Next, analyze the above obfuscation results in :
1, Utils is gone because the contents of the called method are copied directly to the method call. Another method that is not called is considered unnecessary code and is removed when packaged. Not only methods, but resources that are not called will also be removed. This benefit is that the size of the APK can be reduced. The NativeUtils class name is not obfuscated because it has a method declared as native. As long as there is a native method in a class, its class name will not be obfuscated, and the method name of the native method will not be obfuscated, because C or C++ codes need to interact through package name + class name + method name.However, other codes in the class will still be obfuscated, and its non-Native methods are gone directly because the content in the method is copied to the method call
3. MyFragment is confusing completely, with basically no reservations. Even the life cycle method is obfuscated. Fragment is considered a system component at all, and it is not ashamed of
4. MainActivity is much better than MyFragment. At least like the class name, the life cycle method is not obfuscated. This is because: all classes that need to be registered in AndroidManifest.xml and the method names rewritten from the parent class will not be obfuscated.Therefore, in addition to Activity, this rule also applies to: Service, BroadcastReceiver and ContentProvider
5. The introduced third-party library is also confused. As can be seen above, it is directly filled with the result of the method call.
2.4. Default obfuscation rules are introduced
. So where are these obfuscation rules defined? In fact, it is the proguard-android-optimize.txt file configured under the release closure of build.gradle just now. This file is stored in the Android SDK/tools/proguard/ directory:

Take a look at its specific content:
# This is a configuration file for ProGuard.# http://proguard.sourceforge.net/index.html#manual/usage.html## This file is no longer maintained and is not used by new (2.2+) versions of the# Android plugin for Gradle. Instead, the Android plugin for Gradle generates the# default rules at build time and stores them in the build directory.# Optimizations: If you don't want to optimize, use the# proguard-android.txt configuration file instead of this one, which# turn off the optimization flags.Adding optimization introductions# certain risks, since for example not all optimizations performed by# ProGuard works on all versions of Dalvik.The following flags turn# off various optimizations known to have issues, but the list may not# be complete or up to date. (The "arithmetic" optimization can be# used if you are only targeting Android 2.0 or later.)Make sure you# test thoroughly if you go this route.-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*-optimizationpasses 5-allowaccessmodification-dontpreverify# The remainder of this file is identical to the non-optimized version# of the Proguard configuration file (except that the other file has# flags to turn off optimization).-dontusemixedcaseclassnames-dontskipnonpubliclibraryclasses-verbose-keepattributes *Annotation*-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-keepclasseswithmembernames class * {native methods;}# keep setters in Views so that animations can still work.# see http://proguard.sourceforge.net/manual/examples.html#beans-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-keepclassmembers class * extends android.app.Activity { public void *(android.view.View);}# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations-keepclassmembers enum * {public static **[] values();public static ** valueOf(java.lang.String);}-keepclassmembers class * implements android.os.Parcelable {public static final android.os.Parcelable$Creator CREATOR;}-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.-dontwarn android.support.**# Understand the @Keep support annotation.-keep class android.support.annotation.Keep-keep @android.support.annotation.Keep class * {*;}-keepclasseswithmembers class * {@android.support.annotation.Keep methods;}-keepclasseswithmembers class * {@android.support.annotation.Keep fields;}-keepclasseswithmembers class * {@android.support.annotation.Keep init(...);}This is the default obfuscation configuration file. Let's explain it line by line:
# Start some configurations related to optimization# Specify a more refined level of optimization-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*# Indicates the number of times the code is optimized, generally 5-optimizationpasses 5# Allows to change scope -allowaccessmodification# Turn off pre-validation-dotpreverify# means not to use case mixed class names when obfuscating -dontusemixedcaseclassnames# means not to skip non-public classes in library -dontskipnonpubliclibraryclasses# means to print detailed information about obfuscating -verbose# means to reserve parameters in annotation - keepattributes *Annotation*# means not to confuse the two classes declared below, which are basically not used, and are used when connecting to some services native to Google -keep public class com.google.vending.licensing.ILicensingService-keep public class com.android.vending.licensing.ILicensingService# means not confusing any class name containing native methods and native method names. This is consistent with the result of verification just now -keepclasseswithmembernames class * {native methods;}# means not confusing the setXXX() and getXXX() methods in the View, because the property animation needs to have corresponding setters and getter methods implementation -keepclassmembers public class * extends android.view.View { void set*(***); *** get*();}# means not confusing the method in the Activity parameter is the View, because there is such a usage, in XML Configure the android:onClick="btnClick" attribute, and find # if you are confused - keepclassmembers class * extends android.app.Activity { public void *(android.view.View);}# means that the values() and valueOf() methods of enumeration are not confused - keepclassmembers enum * {public static **[] values();public static ** valueOf(java.lang.String);}# means that the CREATOR field in the Parcelable implementation class cannot be confused. There is no doubt that the CREATOR field cannot be changed, including upper and lower case, otherwise the whole # The working mechanism of Parcelable will be invalid - keepclassmembers class * implements android.os.Parcelable {public static final android.os.Parcelable$Creator CREATOR;}# means not obfuscating all static fields in the R file. We all know that the R file records each resource id through fields. If the field name is obfuscated, the id will not be found - keepclassmembers class **.R$* {public static fields;}# means not to warn the code under the android.support package, because all the code in the support package has made sufficient judgments on compatibility, so there is no need to worry about the code going wrong # So just ignore the warning - dontwarn android.support.**# means not confusing everything in the class android.support.annotation.Keep - keep class android.support.annotation.Keep means not confusing everything in the class annotated class android.support.Keep - keepplatseswithmembers class * {@android.support.annotation.Keep methods;}# means not confusing class names and class annotated methods in the class android.support.Keep methods;}# means not confusing class names and class annotated methods in the class android.support.Keep annotation attributes - keepclasseswithmembers class * {@android.support.annotation.Keep fields;}# indicates that the class name is not confused and the constructor method of class android.support.Keep annotation is used in the class - keepclasseswithmembers class * {@android.support.annotation.Keep init(...);}2.4.1, proguard-android-optimize.txt and proguard-android.txt The difference between some of the previous AGPs before
In the old version, the default use of our new project is: proguard-android.txt, so what is the difference between it and proguard-android-optimize.txt?
From the literal dimension, there is one more word optimization, which actually means more optimization. Proguard-android-optimize.txt enables optimization-related configurations compared to proguard-android.txt:
# proguard-android-optimize.txt The following optimization rules have been added -optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*-optimizationpasses 5-allowaccessmodification-dontpreverify# proguard-android-optimize.txt Delete the configuration of the closing optimization directive # -dontoptimize. The above is all the default configurations in the proguard-android-optimize.txt file, and our obfuscation code is also obfuscated according to the rules of these configurations.After the above explanation, I believe everyone can basically understand the content of these configurations. However, there are still several very difficult parts in the Proguard syntax. Let me share with you these difficult syntax parts.
2.5 and Proguard difficult syntax introduction
Proguard has three groups of six in the Proguard keep Many people don't understand the difference between keywords, let's take a look at them intuitively through a table:
keywords
description
keeppairs the members of the class and the class are not obfuscated or removed
keep in keep On the basis of this, if the member is not referenced, it will be removed
keepclass members not obfuscated or removed
keepclass members not obfuscated or removed
keepclass members On the basis of this, if the member is not referenced, it will be removed
keeps the members of the class and the members in the class not be obfuscated or removed, assuming that the members in the class must exist, otherwise it will still be obfuscated
keepclass with membernames
On the basis of keepclasswith members, if the member is not referenced, it will be removed
In addition, Proguard The wildcard characters are also difficult to understand, proguard-android-optimize.txt There are many wildcard characters used in it. Let's take a look at the difference between them:
wildcard characters
description
field
matches all fields in the class
method
matches all methods in the class
init
matches all constructors in the class
matches all constructors in the class
*
matches any length characters, but does not contain the separator .. For example, our completion class name is: com.dream.androidreversedemo.MainActivity, use com.* or com.dream.* cannot match because * The delimiter in the registration cannot be matched. The correct way to match is com.dream.*.* or com.dream.androidreversedemo.*
**
matches any length characters. Contains the delimiter .. The above matching rules can be used to match com.** or com.dream.** to match
***
matches any parameter type.For example, void set*(***) can match any parameter type passed in, ***get(*) can match any return value type
...
match any type parameter of any length, for example, void test(...) can match void test(String str) or void test(int a, double b) these methods
ok, and learned the difficult syntax. Let's take a exercise question: All information of the class that implements the com.dream.test.BaseJsonData interface is not confused?
A clear idea is very important. Let's analyze it carefully:
1. First, we must ensure that the com.dream.test.BaseJsonData interface is not confused
2. Then we must ensure that the class that implements the com.dream.test.BaseJsonData interface is not confused
3. Finally, it is to match all members of the class that are not confused. You can use the wildcard character *
. We can write this:
# Ensure that the com.dream.test.BaseJsonData interface is not confused - keep class com.dream.test.BaseJsonData# Ensure that the class that implements the com.dream.test.BaseJsonData interface is not confused # All members of the matching class are not obfuscated. You can use the wildcard character *-keep class * implements com.dream.test.BaseJsonData{*;}2.6. Custom obfuscating rules
. Return to the project. Although the APK just hit has been successfully obfuscated, the obfuscating rules are based on the default rules in proguard-android-optimize.txt. Of course, we can modify the rules in proguard-android-optimize.txt, but doing so will take effect on the obfuscating rules of all projects on the machine. So is there any good way to modify the obfuscating rules only for the current project?
Answer: For custom obfuscation rules for proguard-rules.pro file, you can see the configuration of the release closure under the Android closure. In fact, there are two obfuscation files. One is the default obfuscation rules we introduced earlier, and the other is the custom obfuscation rules:
android {buildTypes {release {minifyEnabled true//proguard-android-optimize.txt: Default obfuscation rules proguard-rules.pro: Custom obfuscation rules proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}}proguard-rules.pro file is located in the app directory. Next, we will use the Proguard related knowledge we just learned to modify the obfuscation rules.
Here we list the goals we want to achieve:
1. Completely retain the MyFragment class without confusing any information
2. Completely retain the MainActivity class without confusing any information
3. Keep the methods in Utils to prevent them from being confused or removing
4. Non-Native in NativeUtils Methods are retained to prevent them from being confused or removing
5, and third-party libraries from being confused or removing
. The implementation is as follows:
# The MyFragment class is fully retained without confusing any information - keep class com.dream.androidreversedemo.MyFragment{*;}# The MainActivity class is completely retained without confusing any information - keep class com.dream.androidreversedemo.MainActivity{*;}# The method in Utils is retained to prevent them from being confused or removing - keep class com.dream.androidreversedemo.Utils{*;}# Keep non-Native methods in NativeUtils to prevent them from being removed - keepclassmembers class com.dream.androidreversedemo.NativeUtils{public static void methodNotNative();}# Keep third-party libraries to prevent them from being confused or removed - keep class com.dream.androidutils.*{*;}has written custom rules, and now we will re-print a formal version of the APK File, then look at the effect in decompilation:

You can see that all the code in the classes we wrote ourselves and the third-party libraries introduced are retained. No matter the package name, the class name is not obfuscated
Then look at the specific class:
MainActivity:

Utils:

NativeUtils:

MyFragment:

can be seen that the above classes have basically been retained in
ok according to our requirements. After the above example, I believe everyone has already made it clear. I have a pretty good understanding of the usage of Proguard, so it is not difficult to write obfuscation configurations based on my own business needs, right?
has talked about the obfuscation APK code. If you want to know more about the usage of Proguard, you can refer to this article: juejin.cn/post/684490…
3. Summary
This article mainly introduces:
1. The installation of the decompilation tool jadx and the use of
jadx is equivalent to a combination of apktool + dex2jar + jd-gui. It can both decompile code and decompile resources, which to a certain extent improves our development efficiency
2. Obfuscation APK Code
1. Some classes (custom written classes, third-party libraries) have been prepared for the effect verification after obfuscation
2. In the app - build.gradle - android closure - release closure set minifyEnabled to true to enable code obfuscation
3. Use the Generate Signed Bundle or APK on the AndroidStudio navigation bar to type the release package
4. Configure the signature file in the app's build.gradle file to facilitate subsequent use of gradle command or gradle visual interface to package
5. The default obfuscation rule file is introduced line by line. Proguard-android-optimize.txt configuration
6, Proguard difficult syntax introduction
7, Custom obfuscation rules reserved class (custom written class, third-party library class) will not be confused
OK, this article ends here, I hope it can help you
Author: sweetying
After the above explanation, I believe everyone can basically understand the content of these configurations. However, there are still several very difficult parts in the Proguard syntax. Let me share with you these difficult syntax parts.
Link: https://juejin.cn/post/7168086915445424136
Source: Rare Earth Nuggets2.5 and Proguard difficult syntax introduction
Proguard has three groups of six in the Proguard keep Many people don't understand the difference between keywords, let's take a look at them intuitively through a table:
keywords
description
keeppairs the members of the class and the class are not obfuscated or removed
keep in keep On the basis of this, if the member is not referenced, it will be removed
keepclass members not obfuscated or removed
keepclass members not obfuscated or removed
keepclass members On the basis of this, if the member is not referenced, it will be removed
keeps the members of the class and the members in the class not be obfuscated or removed, assuming that the members in the class must exist, otherwise it will still be obfuscated
keepclass with membernames
On the basis of keepclasswith members, if the member is not referenced, it will be removed
In addition, Proguard The wildcard characters are also difficult to understand, proguard-android-optimize.txt There are many wildcard characters used in it. Let's take a look at the difference between them:
wildcard characters
description
field
matches all fields in the class
method
matches all methods in the class
init
matches all constructors in the class
matches all constructors in the class
*
matches any length characters, but does not contain the separator .. For example, our completion class name is: com.dream.androidreversedemo.MainActivity, use com.* or com.dream.* cannot match because * The delimiter in the registration cannot be matched. The correct way to match is com.dream.*.* or com.dream.androidreversedemo.*
**
matches any length characters. Contains the delimiter .. The above matching rules can be used to match com.** or com.dream.** to match
***
matches any parameter type.
Android reverse series: Android APK code obfuscation- Publish article
Android reverse series: Android APK code obfuscation
Synchronous scrolling: Open
You can attack my app, then I must have a defensive strategy. Next, let's introduce Android Obfuscation technology in
Note : The following demonstrations are all
Github Demo Address: github.com/sweetying52…
1. jadx Introduction to
Before this, I would like to introduce another decompilation tool: jadx, which is equivalent to APKtool + dex2JAR + jd-gui The combination of the combination can both decompile code and decompile resources. The key is very simple to use. You only need to drag the file in, which improves our development efficiency to a certain extent.
Github Address: github.com/skylot/jadx
1.1, jadx features
1, can decompile the code in APK, AAR, JAR, DEX, AAB, ZIP and other files into Java class
2, can decompile resources in APK, AAR, AAB, ZIP and other files
1.2, jadx Install
1, install jadx, it is recommended to use brew to install, execute the following command:
brew install jadxUse brew The advantage of installing is that mac will automatically configure environment variables for you. You only need to focus on the use of the software, wait for the installation to be completed. Verify
2, jadx Verify
In Terminal Enter the following command:
jadx --versionIf the version number is printed, it proves that the installation is successful:

1.3, jadx use
Here we use jadx directly The provided visual interface is used to operate
1. Enter the following command in Terminal:
jadx-guiAt this time, the visual interface of jadx will be opened:

2. Drag the file you need to decompile to view the decompiled code and resources, as shown in the figure below:

2. Obfuscating APK code
2.1. Preparation
First we do some preparations
1. Add some classes:
//1. Create a new Utils.java file and create Utils class public class Utils {public void methodNormal(){String logMessage = "this is normal method";logMessage = logMessage.toLowerCase();System.out.println(logMessage);}public void methodUnused(){String logMessage = "this is unused method";logMessage = logMessage.toLowerCase();System.out.println(logMessage);}}//2. Create NativeUtils.java File, create the NativeUtils class public class NativeUtils {public static native void methodNative();public static void methodNotNative(){String logMessage = "this is not native method";logMessage = logMessage.toLowerCase();System.out.println(logMessage);}}//3. Create a new MyFragment.java file, create the MyFragment class public class MyFragment extends Fragment {private String toastTips = "toast in MyFragment";@Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {View rootView = inflater.inflate(R.layout.fragment_layout,container,false);methWithGlobalVariable();methWithLocalVariable();return rootView;}private void methodWithGlobalVariable() {Toast.makeText(getActivity(), toastTips, Toast.LENGTH_SHORT).show();}private void methodWithLocalVariable() {String logMessage = "log in MyFragment";logMessage = logMessage.toLowerCase();System.out.println(logMessage);}}2, then reference in MainActivity
public class MainActivity extends AppCompatActivity {String toastTips = "toast in MainActivity";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);getSupportFragmentManager().beginTransaction().add(R.id.flFragmentContainer,new MyFragment()).commit();//1. Method call under Utils utils = new Utils();utils.methodNormal();//2. Method call under NativeUtils try {NativeUtils.methodNative();NativeUtils.methodNotNative();} catch (Throwable e) {e.printStackTrace();}//3. Method call of tool class under third-party library int result = StringUtils.getLength("erdai666");System.out.println(result);//4. The methodWithGlobalVariable method under MainActivity calls methodWithGlobalVariable();//5. The methodWithLocalVariable method under MainActivity calls methodWithLocalVariable();}private void methodWithGlobalVariable() {Toast.makeText(this, toastTips, Toast.LENGTH_SHORT).show();}private void methodWithLocalVariable() {String logMessage = "log in MainActivity";logMessage = logMessage.toLowerCase();System.out.println(logMessage);}}OK, the preparation work has been basically completed here. Next, we obfuscate the code in the APK
2.2, enable obfuscation and APK package
1, in the app Open code obfuscation in the release closure under the Android closure in the build.Gradle file:
android {buildTypes {release {// enable code obfuscation minifyEnabled trueproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}}Above we only changed minifyEnabled to true That is, code obfuscation is enabled, very simple
Also, you need to pay attention to : This is configured in the release closure, so only if the official APK is released will be obfuscated, and the debug version of APK will not be obfuscated.Of course, this is also very reasonable, because we will only use debug version APK files for internal testing, and we don’t have to worry about being cracked.
2. Next, create an official APK package
1. Click Build - Generate Signed Bundle or APK in the Android Studio navigation bar, select APK
2, then select the signature file and enter the password. If there is no signature file, create an
3. Click next to select the release package, and finally click Finish to complete the packaging
4. The generated APK will be automatically stored in the app/release/ directory
Tips: We can build.gradle in the app Add signature file configuration to the file, and you can then directly operate through the ./gradlew assembleRelease command or the Gradle visual interface on the right side of AndroidStudio:
android {//1, declare the signature file signingConfigs{release{storeFile file('../Certificate')storePassword 'erdai666' keyAlias 'key0'keyPassword 'erdai666'}}buildTypes {release {minifyEnabled trueproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'//2. Configure the signature file signingConfig signingConfigs.release}}}Note :
1. APK generated using the AndroidStudio navigation bar Generate Signed Bundle or APK. In the directory
2, use the ./gradlew assembleRelease command or AndroidStudio The APK generated by the Gradle visualization boundary on the right is
3 in the app/build/outputs/apk/ directory. Then use jadx to open the current APK, as shown in the figure below:

It is obvious that our code obfuscation of function has taken effect.
2.3. Introduction to obfuscation file
. Let's try to read the classes prepared before obfuscation:
MainActivity:

You can see:
1. MyFragment is obfuscated
2. Method calls under Utils: Directly copy the contents in the method to the call of the method
3. Method calls under NativeUtils: 1. Native method or normal call 2. Non-Native The method is to copy the contents of the method to the method call
4. The method calls of the tool class under the third-party library: directly fill the result of the method to the call
5. The member method in MainActivity: directly copy the contents of the member method to the call
6. The MainActivity class name is not confusing, and the onCreate method is not confusing, but the defined member variables, local variable is confusing
Utils 11:
Utils The class is gone directly
NativeUtils:

You can see:
1, NativeUtils class name is not obfuscated, and the method declared as native is not obfuscated
2, non-Native methods are gone directly, and the content of the method is copied to the method call
MyFragment:

You can see:
1, all method names, member variables, and local variables are obfuscated
2, MyFragment Member methods in: Directly copy the contents of the member method to the method call
Next, analyze the above obfuscation results in :
1, Utils is gone because the contents of the called method are copied directly to the method call. Another method that is not called is considered unnecessary code and is removed when packaged. Not only methods, but resources that are not called will also be removed. This benefit is that the size of the APK can be reduced. The NativeUtils class name is not obfuscated because it has a method declared as native. As long as there is a native method in a class, its class name will not be obfuscated, and the method name of the native method will not be obfuscated, because C or C++ codes need to interact through package name + class name + method name.However, other codes in the class will still be obfuscated, and its non-Native methods are gone directly because the content in the method is copied to the method call
3. MyFragment is confusing completely, with basically no reservations. Even the life cycle method is obfuscated. Fragment is considered a system component at all, and it is not ashamed of
4. MainActivity is much better than MyFragment. At least like the class name, the life cycle method is not obfuscated. This is because: all classes that need to be registered in AndroidManifest.xml and the method names rewritten from the parent class will not be obfuscated.Therefore, in addition to Activity, this rule also applies to: Service, BroadcastReceiver and ContentProvider
5. The introduced third-party library is also confused. As can be seen above, it is directly filled with the result of the method call.
2.4. Default obfuscation rules are introduced
. So where are these obfuscation rules defined? In fact, it is the proguard-android-optimize.txt file configured under the release closure of build.gradle just now. This file is stored in the Android SDK/tools/proguard/ directory:

Take a look at its specific content:
# This is a configuration file for ProGuard.# http://proguard.sourceforge.net/index.html#manual/usage.html## This file is no longer maintained and is not used by new (2.2+) versions of the# Android plugin for Gradle. Instead, the Android plugin for Gradle generates the# default rules at build time and stores them in the build directory.# Optimizations: If you don't want to optimize, use the# proguard-android.txt configuration file instead of this one, which# turn off the optimization flags.Adding optimization introductions# certain risks, since for example not all optimizations performed by# ProGuard works on all versions of Dalvik.The following flags turn# off various optimizations known to have issues, but the list may not# be complete or up to date. (The "arithmetic" optimization can be# used if you are only targeting Android 2.0 or later.)Make sure you# test thoroughly if you go this route.-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*-optimizationpasses 5-allowaccessmodification-dontpreverify# The remainder of this file is identical to the non-optimized version# of the Proguard configuration file (except that the other file has# flags to turn off optimization).-dontusemixedcaseclassnames-dontskipnonpubliclibraryclasses-verbose-keepattributes *Annotation*-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-keepclasseswithmembernames class * {native methods;}# keep setters in Views so that animations can still work.# see http://proguard.sourceforge.net/manual/examples.html#beans-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-keepclassmembers class * extends android.app.Activity { public void *(android.view.View);}# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations-keepclassmembers enum * {public static **[] values();public static ** valueOf(java.lang.String);}-keepclassmembers class * implements android.os.Parcelable {public static final android.os.Parcelable$Creator CREATOR;}-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.-dontwarn android.support.**# Understand the @Keep support annotation.-keep class android.support.annotation.Keep-keep @android.support.annotation.Keep class * {*;}-keepclasseswithmembers class * {@android.support.annotation.Keep methods;}-keepclasseswithmembers class * {@android.support.annotation.Keep fields;}-keepclasseswithmembers class * {@android.support.annotation.Keep init(...);}This is the default obfuscation configuration file. Let's explain it line by line:
# Start some configurations related to optimization# Specify a more refined level of optimization-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*# Indicates the number of times the code is optimized, generally 5-optimizationpasses 5# Allows to change scope -allowaccessmodification# Turn off pre-validation-dotpreverify# means not to use case mixed class names when obfuscating -dontusemixedcaseclassnames# means not to skip non-public classes in library -dontskipnonpubliclibraryclasses# means to print detailed information about obfuscating -verbose# means to reserve parameters in annotation - keepattributes *Annotation*# means not to confuse the two classes declared below, which are basically not used, and are used when connecting to some services native to Google -keep public class com.google.vending.licensing.ILicensingService-keep public class com.android.vending.licensing.ILicensingService# means not confusing any class name containing native methods and native method names. This is consistent with the result of verification just now -keepclasseswithmembernames class * {native methods;}# means not confusing the setXXX() and getXXX() methods in the View, because the property animation needs to have corresponding setters and getter methods implementation -keepclassmembers public class * extends android.view.View { void set*(***); *** get*();}# means not confusing the method in the Activity parameter is the View, because there is such a usage, in XML Configure the android:onClick="btnClick" attribute, and find # if you are confused - keepclassmembers class * extends android.app.Activity { public void *(android.view.View);}# means that the values() and valueOf() methods of enumeration are not confused - keepclassmembers enum * {public static **[] values();public static ** valueOf(java.lang.String);}# means that the CREATOR field in the Parcelable implementation class cannot be confused. There is no doubt that the CREATOR field cannot be changed, including upper and lower case, otherwise the whole # The working mechanism of Parcelable will be invalid - keepclassmembers class * implements android.os.Parcelable {public static final android.os.Parcelable$Creator CREATOR;}# means not obfuscating all static fields in the R file. We all know that the R file records each resource id through fields. If the field name is obfuscated, the id will not be found - keepclassmembers class **.R$* {public static fields;}# means not to warn the code under the android.support package, because all the code in the support package has made sufficient judgments on compatibility, so there is no need to worry about the code going wrong # So just ignore the warning - dontwarn android.support.**# means not confusing everything in the class android.support.annotation.Keep - keep class android.support.annotation.Keep means not confusing everything in the class annotated class android.support.Keep - keepplatseswithmembers class * {@android.support.annotation.Keep methods;}# means not confusing class names and class annotated methods in the class android.support.Keep methods;}# means not confusing class names and class annotated methods in the class android.support.Keep annotation attributes - keepclasseswithmembers class * {@android.support.annotation.Keep fields;}# indicates that the class name is not confused and the constructor method of class android.support.Keep annotation is used in the class - keepclasseswithmembers class * {@android.support.annotation.Keep init(...);}2.4.1, proguard-android-optimize.txt and proguard-android.txt The difference between some of the previous AGPs before
In the old version, the default use of our new project is: proguard-android.txt, so what is the difference between it and proguard-android-optimize.txt?
From the literal dimension, there is one more word optimization, which actually means more optimization. Proguard-android-optimize.txt enables optimization-related configurations compared to proguard-android.txt:
# proguard-android-optimize.txt The following optimization rules have been added -optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*-optimizationpasses 5-allowaccessmodification-dontpreverify# proguard-android-optimize.txt Delete the configuration of the closing optimization directive # -dontoptimize. The above is all the default configurations in the proguard-android-optimize.txt file, and our obfuscation code is also obfuscated according to the rules of these configurations.After the above explanation, I believe everyone can basically understand the content of these configurations. However, there are still several very difficult parts in the Proguard syntax. Let me share with you these difficult syntax parts.
2.5 and Proguard difficult syntax introduction
Proguard has three groups of six in the Proguard keep Many people don't understand the difference between keywords, let's take a look at them intuitively through a table:
keywords
description
keeppairs the members of the class and the class are not obfuscated or removed
keep in keep On the basis of this, if the member is not referenced, it will be removed
keepclass members not obfuscated or removed
keepclass members not obfuscated or removed
keepclass members On the basis of this, if the member is not referenced, it will be removed
keeps the members of the class and the members in the class not be obfuscated or removed, assuming that the members in the class must exist, otherwise it will still be obfuscated
keepclass with membernames
On the basis of keepclasswith members, if the member is not referenced, it will be removed
In addition, Proguard The wildcard characters are also difficult to understand, proguard-android-optimize.txt There are many wildcard characters used in it. Let's take a look at the difference between them:
wildcard characters
description
field
matches all fields in the class
method
matches all methods in the class
init
matches all constructors in the class
matches all constructors in the class
*
matches any length characters, but does not contain the separator .. For example, our completion class name is: com.dream.androidreversedemo.MainActivity, use com.* or com.dream.* cannot match because * The delimiter in the registration cannot be matched. The correct way to match is com.dream.*.* or com.dream.androidreversedemo.*
**
matches any length characters. Contains the delimiter .. The above matching rules can be used to match com.** or com.dream.** to match
***
matches any parameter type.For example, void set*(***) can match any parameter type passed in, ***get(*) can match any return value type
...
match any type parameter of any length, for example, void test(...) can match void test(String str) or void test(int a, double b) these methods
ok, and learned the difficult syntax. Let's take a exercise question: All information of the class that implements the com.dream.test.BaseJsonData interface is not confused?
A clear idea is very important. Let's analyze it carefully:
1. First, we must ensure that the com.dream.test.BaseJsonData interface is not confused
2. Then we must ensure that the class that implements the com.dream.test.BaseJsonData interface is not confused
3. Finally, it is to match all members of the class that are not confused. You can use the wildcard character *
. We can write this:
# Ensure that the com.dream.test.BaseJsonData interface is not confused - keep class com.dream.test.BaseJsonData# Ensure that the class that implements the com.dream.test.BaseJsonData interface is not confused # All members of the matching class are not obfuscated. You can use the wildcard character *-keep class * implements com.dream.test.BaseJsonData{*;}2.6. Custom obfuscating rules
. Return to the project. Although the APK just hit has been successfully obfuscated, the obfuscating rules are based on the default rules in proguard-android-optimize.txt. Of course, we can modify the rules in proguard-android-optimize.txt, but doing so will take effect on the obfuscating rules of all projects on the machine. So is there any good way to modify the obfuscating rules only for the current project?
Answer: For custom obfuscation rules for proguard-rules.pro file, you can see the configuration of the release closure under the Android closure. In fact, there are two obfuscation files. One is the default obfuscation rules we introduced earlier, and the other is the custom obfuscation rules:
android {buildTypes {release {minifyEnabled true//proguard-android-optimize.txt: Default obfuscation rules proguard-rules.pro: Custom obfuscation rules proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}}proguard-rules.pro file is located in the app directory. Next, we will use the Proguard related knowledge we just learned to modify the obfuscation rules.
Here we list the goals we want to achieve:
1. Completely retain the MyFragment class without confusing any information
2. Completely retain the MainActivity class without confusing any information
3. Keep the methods in Utils to prevent them from being confused or removing
4. Non-Native in NativeUtils Methods are retained to prevent them from being confused or removing
5, and third-party libraries from being confused or removing
. The implementation is as follows:
# The MyFragment class is fully retained without confusing any information - keep class com.dream.androidreversedemo.MyFragment{*;}# The MainActivity class is completely retained without confusing any information - keep class com.dream.androidreversedemo.MainActivity{*;}# The method in Utils is retained to prevent them from being confused or removing - keep class com.dream.androidreversedemo.Utils{*;}# Keep non-Native methods in NativeUtils to prevent them from being removed - keepclassmembers class com.dream.androidreversedemo.NativeUtils{public static void methodNotNative();}# Keep third-party libraries to prevent them from being confused or removed - keep class com.dream.androidutils.*{*;}has written custom rules, and now we will re-print a formal version of the APK File, then look at the effect in decompilation:

You can see that all the code in the classes we wrote ourselves and the third-party libraries introduced are retained. No matter the package name, the class name is not obfuscated
Then look at the specific class:
MainActivity:

Utils:

NativeUtils:

MyFragment:

can be seen that the above classes have basically been retained in
ok according to our requirements. After the above example, I believe everyone has already made it clear. I have a pretty good understanding of the usage of Proguard, so it is not difficult to write obfuscation configurations based on my own business needs, right?
has talked about the obfuscation APK code. If you want to know more about the usage of Proguard, you can refer to this article: juejin.cn/post/684490…
3. Summary
This article mainly introduces:
1. The installation of the decompilation tool jadx and the use of
jadx is equivalent to a combination of apktool + dex2jar + jd-gui. It can both decompile code and decompile resources, which to a certain extent improves our development efficiency
2. Obfuscation APK Code
1. Some classes (custom written classes, third-party libraries) have been prepared for the effect verification after obfuscation
2. In the app - build.gradle - android closure - release closure set minifyEnabled to true to enable code obfuscation
3. Use the Generate Signed Bundle or APK on the AndroidStudio navigation bar to type the release package
4. Configure the signature file in the app's build.gradle file to facilitate subsequent use of gradle command or gradle visual interface to package
5. The default obfuscation rule file is introduced line by line. Proguard-android-optimize.txt configuration
6, Proguard difficult syntax introduction
7, Custom obfuscation rules reserved class (custom written class, third-party library class) will not be confused
OK, this article ends here, I hope it can help you
Author: sweetying
Link: https://juejin.cn/post/7168086915445424136
Source: Rare Earth Nuggets