Is your Android application secure?

Keywords: Android simulator Java Database

Preface

As you all know, most Android s are written in Java language at present. Even now Google highly recommends kotlin, there are still many projects written in Java. After all, it takes time to replace a language. Therefore, it is well known that Java code is easy to be decompiled, so the prevention of decompilation itself still needs attention.

Mainly from four aspects to introduce this article:

1.Proguard confusion

2. Anti-decompilation tools

3. Anti-Android Simulator

4. Anti-apk repackaging

Proguard confusion

Proguard Foundation

Proguard is an open source project for obfuscating code. The main function of Proguard is obfuscation. Of course, it also has the functions of reducing the size and optimizing bytecode. My main concern is obfuscation.

concept

The following two pictures are confused and not confused (pictures found online):

It can be seen that there is a big difference between confusion and no confusion. The class name changes completely after using obfuscation. Naturally, if obfuscation occurs, it is still effective for decompilation.

Basic grammar:

- include {filename} reads configuration parameters from a given file   
- basedirectory {directoryname} specifies the base directory as the relative file name for the future   
- injars {class_path} specifies the application jar,war,ear, and directory to be processed   
- outjars {class_path} specifies the name of the jar,war,ear, and directory to be output after processing.   
- libraryjars {classpath} specifies the library files required by the application jar,war,ear, and directory to be processed   
- dontskip nonpubliclibraryclasses specifies that non-public library classes are not ignored.   
- dontskip nonpubliclibraryclass members specify that members of library classes that do not ignore package visibility.  


Reserved options   
- keep {Modifier} {class_specification} protects specified class files and class members   
- Keep class members {modifier} {class_specification} protect members of a specified class, and they will protect better if such classes are protected  
- keep classes with memberships {class_specification} protects members of specified classes and classes, provided that all specified classes and class members exist.   
- keepnames {class_specification} protects the name of the specified class and its members (if they do not compress steps to delete)   
- keep class membernames {class_specification} protects the name of the member of the specified class (if they do not compress steps to delete)   
- keep classes with member names {class_specification} protects the name of the specified class and class members if all the specified class members are present (after the compression step)   
- printseeds {filename} lists the member-keep options for classes and classes, which are standard output to a given file   

compress   
- dontshrink uncompressed input class file   
-printusage {filename}   
-whyareyoukeeping {class_specification}       

optimization   
- dontoptimize does not optimize input class files   
- assumenosideeffects {class_specification} optimization assumes the specified method without any side effects   
- allowaccessmodification optimization allows access to and modification of modifier classes and class members   

confusion   
- dontobfuscate does not confuse input class files   
-printmapping {filename}   
- Apply mapping {filename} Reuse mapping increases confusion   
- obfuscation dictionary {filename} uses keywords in a given file as the name of the method to be obfuscated   
- Application of intrusive overload in overload aggressivity confusion   
- useuniqueclass membernames identifies the name of the member of the unified obfuscation class to increase obfuscation   
- Flatten package hierarchy {package_name} repackages all renamed packages and places them in a given single package   
- repackage class {package_name} repackage all renamed class files in a given single package   
- Dontusemixed class names do not produce a variety of class names when confused   
- Keep attributes {attribute_name,...} protect given optional attributes, such as LineNumberTable, LocalVariable Table, SourceFile, Deprecated, Synthetic, Signature, and   

InnerClasses.   
- renamesourcefileattribute {string} sets the string constants given in the source file

Actual code:

-ignorewarnings                     # Ignore warnings to avoid certain warnings when packaging  
-optimizationpasses 5               # Specify the compression level of the code  
-dontusemixedcaseclassnames         # Whether to use case mixing or not  
-dontskipnonpubliclibraryclasses    # Is third party jar confused  
-dontpreverify                      # Whether to do pre-checking in confusion  
-verbose                            # Whether to log in case of confusion  
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*        # The algorithm used in confusion  

-libraryjars   libs/treecore.jar  

-dontwarn android.support.v4.**     #The default proguard checks that every reference is correct, but there are often classes in third-party libraries that are not used and that are not referenced correctly. If not configured, the system will report an error.  
-dontwarn android.os.**  
-keep class android.support.v4.** { *; }        # What classes should be kept unambiguous  
-keep class com.baidu.** { *; }    
-keep class vi.com.gdi.bgl.android.**{*;}  
-keep class android.os.**{*;}  

-keep interface android.support.v4.app.** { *; }    
-keep public class * extends android.support.v4.**    
-keep public class * extends android.app.Fragment  

-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.support.v4.widget  
-keep public class * extends com.sqlcrypt.database  
-keep public class * extends com.sqlcrypt.database.sqlite  
-keep public class * extends com.treecore.**  
-keep public class * extends de.greenrobot.dao.**  


-keepclasseswithmembernames class * {       # Keep the native approach unambiguous  
   native <methods>;  
}  

-keepclasseswithmembers class * {            # Keep custom control classes unambiguous  
   public <init>(android.content.Context, android.util.AttributeSet);  
}  

-keepclasseswithmembers class * {            # Keep custom control classes unambiguous  
   public <init>(android.content.Context, android.util.AttributeSet, int);  
}  

-keepclassmembers class * extends android.app.Activity { //Keep class members  
  public void *(android.view.View);  
}  

-keepclassmembers enum * {                  # Keep enum classes unambiguous  
   public static **[] values();  
   public static ** valueOf(java.lang.String);  
}  

-keep class * implements android.os.Parcelable {    # Keep Parcelable unambiguous  
 public static final android.os.Parcelable$Creator *;  
}  

-keep class MyClass;                              # Keep your defined classes unambiguous

Be careful:
Some parts of Android can't be confused. After confusion, anomalies will occur:

  1. The four components can not be confused because they are registered in Mainfiest.
  2. Java Interface Method Called by jin
  3. System Interface Method
  4. Obfuscation of R files can lead to reference errors (if reflex mechanism is used somewhere, R files will not find resources after obfuscation)

Preventing Decompilation

Anti-decompilation methods

1. Proguard obfuscation can not only obfuscate code, but also decompile tool failure or ruin

2. Using the current domestic APK reinforcement methods, as far as I know, if you want to release applications in 360 and Tencent markets, you must use their corresponding market reinforcement methods: 360 reinforcement and Legu reinforcement.

What are the commonly used decompilation tools?

  • apkTool
  • baksmali
  • dex2.jar
  • JEB

Through the above two methods, we can make these decompilation tools decompile hard to read and even make the decompilation tools invalid or invalid.

Because the confusion method mentioned above is not to be elaborated, the domestic APK reinforcement method is simpler. It can be strengthened by the designated download tool on the official website, and the document description is very detailed.

Preventing Simulator

Preventing Simulator Reverse Analysis

Reason: Generally, the reverse analysis state is run in the Android simulator, so we just need to judge in the code whether our current APK is running in the simulator.

Is the detection simulator?
Generally there are several ways:

  • Detection of Several Special Files on Simulator
  • Detection of special numbers on simulators
  • Is IDS the "000000000000000"?
  • Check if there are sensors, Bluetooth
  • Detecting Hardware Information on Mobile Phones
  • Testing Mobile Operators

Let me demonstrate with code:

  • Check IDS
/**
    * Check IDS
    *
    * @param context
    * @return
    */
   public static boolean chechDeviceIDS(Context context) {
       @SuppressLint("ServiceCast")
       TelephonyManager telecomManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
       @SuppressLint("MissingPermission")
       String deviceId = telecomManager.getDeviceId();
       if (deviceId.equalsIgnoreCase(DEVICE_ID)) {
           Log.e(TAG, "chechDeviceIDS==" + DEVICE_ID);
           return true;
       }
       return false;
   }
  • Check Simulator Specific Files
/**
    * Check Simulator Specific Files
    *
    * @param context
    * @return
    */
   public static boolean chechDeviceFile(Context context) {
       for (int i = 0; i < DEVICE_FILE.length; i++) {
           String file_name = DEVICE_FILE[i];
           File qemu_file = new File(file_name);
           if (qemu_file.exists()) {
               Log.e(TAG, "chechDeviceFile==" + true);
               return true;
           }
       }
       return false;
   }
  • Check the unique number of the simulator
/**
    * Check the unique telephone number
    *
    * @param context
    * @return
    */
   public static boolean chechDevicePhone(Context context) {
       @SuppressLint("ServiceCast")
       TelephonyManager telecomManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
       @SuppressLint("MissingPermission")
       String phoneNumber = telecomManager.getLine1Number();
       for (String phone : DEVICE_PHONE) {
           if (phone.equalsIgnoreCase(phoneNumber)) {
               Log.e(TAG, "chechDevicePhone==" + phoneNumber);
               return true;
           }
       }
       return false;
   }
  • Check if the simulator contains these devices
/**
    * Check whether special equipment is included
    *
    * @param context
    * @return
    */
   public static boolean chechDeviceBuild(Context context) {
       String board = Build.BOARD;
       String bootloader = Build.BOOTLOADER;
       String brand = Build.BRAND;
       String device = Build.DEVICE;
       String hardware = Build.HARDWARE;
       String model = Build.MODEL;
       String product = Build.PRODUCT;

       if (board.equalsIgnoreCase("unknown") || bootloader.equalsIgnoreCase("unknown")
               || brand.equalsIgnoreCase("generic") || model.equalsIgnoreCase("sdk")
               || product.equalsIgnoreCase("goldfish")) {
           Log.e(TAG, "chechDeviceBuild==" + "find emulatorBuild");
           return true;
       }
       return false;
   }

Operation results:

We can see that the print results are all displayed as simulators, and remind us not to forget to add permissions when obtaining this information:

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

From the above we can judge whether it is an emulator or not, then we can kill APP or the process in which APP is located by judging.

Two pack

Preventing secondary packing

  • What is secondary packaging?

The smali code is obtained by decompiling tool, and then the smali code is repackaged to form APK. Finally, the smali code can be re-signed to run.

If the program is cracked, then our APK must be running on the real machine or simulator, and must be re-signed, then the signature and the original signature must be inconsistent, we can judge our signature at the entrance of the program, in order to judge the second packaging.

The code is as follows:

public class MainActivity extends AppCompatActivity {
   private static final String TAG = "MainActivity";

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       Log.e(TAG, "getSignature=="+getSignature("demo.lt.com.repacking"));
   }

   private int getSignature(String packageName) {
       PackageManager packageManager = this.getPackageManager();
       PackageInfo info = null;
       int sig = 0;
       try {
           info = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
           Signature[] signatures = info.signatures;
           sig = signatures[0].hashCode();
       } catch (Exception e) {
           sig = 0;
           e.printStackTrace();
       }

       return sig;
   }
}

Getting the signature hashCode is the only value:

So we only need to add more code to judge the second packaging:

public class MainActivity extends AppCompatActivity {
   private static final String TAG = "MainActivity";

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       Log.e(TAG, "getSignature==" + getSignature("demo.lt.com.repacking"));
       if (getSignature("demo.lt.com.repacking") != -567503403) {
           Log.e(TAG, "Repackaged");
       }
   }

   private int getSignature(String packageName) {
       PackageManager packageManager = this.getPackageManager();
       PackageInfo info = null;
       int sig = 0;
       try {
           info = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
           Signature[] signatures = info.signatures;
           sig = signatures[0].hashCode();
       } catch (Exception e) {
           sig = 0;
           e.printStackTrace();
       }

       return sig;
   }
}

Here's just a Log printed, which can either end the process or kill the APP in the actual code.

One sentence summary

These are the knowledge points of today's Android protection, not how proficient you are in Android protection, but we as an Android developer must know these knowledge points, I believe it will be useful for you.

Originality is not easy. If I feel that I write well, scanning code and paying attention to a few praises is my greatest motivation.

Pay attention to me, there will be something unexpected waiting for you: Android, Java, big data and other video resources, books waiting for you to pick up.
Focus on sharing Android and JAVA dried goods every day


Note: Program Circle LT

Posted by keyser soze on Sat, 18 May 2019 17:33:45 -0700