Andorid APK anti-Reverse Solution --- exploring the principle of zookeeper reinforcement

Source: Internet
Author: User

I. Preface

 


At present, the Android market is flooded with a large number of pirated software, and developers' official applications are maliciously tampered with by the "package party. How to protect the program code from pirated tampering has become a top priority for developers, today we will analyze a good solution-Zookeeper reinforcement (http://www.secneo.com/appProtect ).


Reinforce and protect apps. Zookeeper can effectively prevent mobile applications from being cracked, pirated, repackaged, injected, and decompiled during operation and promotion, and ensure the security and stability of the program, protects the overall logical structure of mobile apps, ensuring the user experience of mobile apps.

 


Ii. Reverse Analysis Process of zookeeper reinforcement


 

First, we can compare the structure of the files before and after APK reinforcement to understand how zookeeper reinforcement processes the APK files. In order to make the analysis process simple enough, I created a simple test program and uploaded it to zookeeper for reinforcement. The whole reinforcement process takes about four days to complete, this is a long waiting process.

The test program contains Activity, Service, ContentProvider, BroadcastRecevier, Application, common class, Jni call, and other 7 types of objects. The purpose is to fully understand the reinforcement effect of zookeeper.

 


1. Comparison and Analysis of Static file structures and dynamic runtime before and after apk reinforcement

 


(1) static file structure changes before and after reinforcement (before reinforcement on the left and after reinforcement on the right)

 

 


 


The following files are added to the reinforced apk:

Assets \ meta-data \ manifest. mf // SHA1-Digest of the APK file list

Assets \ meta-data \ rsa. pub // RSA public key information

Assets \ meta-data \ rsa. sig // Digital Signature File

Assets \ classes. jar // The original classes. dex file is encrypted.

Assets \ com. example. hellojni // binary executable file of the ARM platform

Assets \ com. example. hellojni. x86 // x86 functions are the same as above

Libs \ armeabi \ libsecexe. so // share library files on the ARM platform

Libs \ x86 \ libsecexe. so // x86 functions are the same as above

Modify the file after reinforcement:

AndroidMainfest. xml // (if the Application is configured with Application information, the file is same before and after reinforcement. If Application information is not configured for the Application, the file is different before and after reinforcement, zookeeper configures the Application information for its own implementation class)

Classes. dex

 


Decompile classes. dex to observe the changes in the Code tree structure: (left before reinforcement, right after reinforcement)

 


(2) Dynamic runtime changes before and after reinforcement

 


Run the original program. The system creates only one related process, but the reinforced program creates three related processes for it at the same time:

Process startup sequence: 597 Process Creation 605 process, 605 Process Creation 607 Process

 

 

 


 

Obtain the 597 process ing file information by viewing the maps file.

 


The map file shows that the 597 process is the main process, and android components run in the process.

The 605 and 607 processes do not have any file information related to the apk file. You can view the startup parameters through cmdline:

 

 

 

 

 

 

It is initially suspected that the process is assets \ com. example. hellojni Executable File running result.

 


2. Effect Analysis of zookeeper reinforcement Protection

 


We use reverse analysis to reinforce the app to see the protection effect of the app.

The first execution point of the program code is the Application object. First, view the TestApplication class object.

The Util class of the program completes most java-layer logic,

 

 

 


The ACall class mainly calls libsecexe. so JNI:

 

 


Check the libsecexe. so file export function, and find that all function names are encrypted, which is different from the function names generated by jni calls. The function name generated by jni should be in this format: Java_com_secapk_wrapper_ACall _ {function name}

 

Anti-static analysis:

The Util class uses MyClassLoader to dynamically load the encrypted classes. jar, decrypts classes. jar in the memory, and completes dynamic loading.

Obfuscation of The so function name corresponding to the jni method.

Anti-dynamic debugging:

When IDA is used to dynamically debug the program, the program cannot establish a connection for debugging.

 

Zookeeper reinforcement can be an effective and commonly used reverse analysis method.

 


Iii. Key Point Conjecture of zookeeper Reinforcement Technology

(1) how to enable DexClassLoader to dynamically load components with a lifecycle?

According to whether the Applicaiton information is configured in the AndroidManifest. xml file of the APK file, Zookeeper reinforcement performs different operations:

By uploading the APK file of different configurations of Applicaiton, we find that:

When the APK is configured with Applicaition information, Zookeeper reinforces and overrides the Application class.

When the APK does not configure Application information, Zookeeper reinforces the new class and configures its own Application class in AndroidManifest. xml.

 
 


Therefore, Applicaiton is the first execution point of the program.


We know that the class loaded by DexClassLoader has no component lifecycle, that is, even if the DexClassLoader completes the loading of the component class by dynamically loading dex, when the system starts the component, an exception occurs when the class fails to be loaded. I am already working on the "Android APK shelling technical solution"

(Http://blog.csdn.net/jiazhijun/article/details/8809542) proposed a method to make DexClassLoader load component class has a life cycle.

Run the reinforced program and use the Mat memory analysis tool to view the class loading status:

 


As shown in, the loading class of the component class has been modified to com. secapk. wrapper. myClassLoader class, you can draw a conclusion that this method is basically the same as the method I proposed, implemented by modifying the system component class ClassLoader.

 


(2) How to confuse the correspondence between native methods in the so library functions?

Two jni method registration methods are available,

1. Use javah to generate function headers. This method has a fixed format. This method makes it easier for reverse analysts to obtain the local method corresponding to the native method of the java layer.

2. Manually register the jni method in the JNI_OnLoad method, so it is difficult to find the corresponding relationship.

The second method can be used to implement the correspondence between the native method at the java layer and the so function.

[Cpp] # include <string. h>
# Include <jni. h>
 
JNIEXPORT jstring JNICALL abcdefghijklmn (JNIEnv * env, jobject thiz)
{
Return (* env)-> NewStringUTF (env, "Hello from JNI! ");
}
 
JNIEXPORT jint JNICALL JNI_OnLoad (JavaVM * vm, void * reserved)
{
JNIEnv * env = NULL;
Jint result =-1;
 
If (* vm)-> GetEnv (vm, (void **) & env, JNI_VERSION_1_4 )! = JNI_ OK ){
Return JNI_ERR;
}
JNINativeMethod gMethods [] = {
{"StringFromJNI", "() Ljava/lang/String;", (void *) abcdefghijklmn },
};
Jclass clazz = (* env)-> FindClass (env, "com/example/hellojni/HelloJni ");

If (clazz = NULL ){
Return JNI_ERR;
}
If (* env)-> RegisterNatives (env, clazz, gMethods, sizeof (gMethods)/sizeof (gMethods [0]) <0 ){
Return JNI_ERR;
}
/* Success -- return valid version number */
Result = JNI_VERSION_1_4;
Return result;
}

# Include <string. h>
# Include <jni. h>

JNIEXPORT jstring JNICALL abcdefghijklmn (JNIEnv * env, jobject thiz)
{
Return (* env)-> NewStringUTF (env, "Hello from JNI! ");
}

JNIEXPORT jint JNICALL JNI_OnLoad (JavaVM * vm, void * reserved)
{
JNIEnv * env = NULL;
Jint result =-1;

If (* vm)-> GetEnv (vm, (void **) & env, JNI_VERSION_1_4 )! = JNI_ OK ){
Return JNI_ERR;
}
JNINativeMethod gMethods [] = {
{"StringFromJNI", "() Ljava/lang/String;", (void *) abcdefghijklmn },
};
Jclass clazz = (* env)-> FindClass (env, "com/example/hellojni/HelloJni ");
 
If (clazz = NULL ){
Return JNI_ERR;
}
If (* env)-> RegisterNatives (env, clazz, gMethods, sizeof (gMethods)/sizeof (gMethods [0]) <0 ){
Return JNI_ERR;
}
/* Success -- return valid version number */
Result = JNI_VERSION_1_4;
Return result;
} The strings in the above Code are all plain text (for example, "stringFromJNI"). If these civilized strings are all converted into ciphertext, then they are decrypted at runtime, and the corresponding relationship is more difficult to see.


(3) How can I load an encrypted dex file with DexClassLoader?

Although I don't know how zookeeper reinforcement works, I guess a feasible implementation scheme by analyzing its running logic: to understand this solution, you must have a clear understanding of the entire loading process of Android DexClassLoader.

First, it is inferred that assets \ classes. jar is an encrypted jar package.

The normal DexClassLoader loading process is as follows: there will be a DexOpt to generate the odex Process

However, the DexClassLoader loading process after the zookeeper reinforcement does not have the log information of the process.

It is inferred that the encrypted jar package contains odex files. If it is not an odex file, DexClassLoader will certainly release unencrypted odex files to the directory at runtime, in this way, the protected logic will be leaked.

The DexClassLoader loading process generates different data structures in the java and C layers. The java layer does not have any substantive data, and all the data is stored in the c layer, we can use the underlying code generation to parse dex data. Underlying dex analysis supports byte [] arrays. It decrypts odex data and passes it over. In this way, the java layer can be called.

The following are the steps to implement the pseudo-code:

Int loadDex (char * dexFileName)
{
Char * dvm_lib_path = "/system/lib/libdvm. so ";
Void * handle;
DvmGlobals gDvm;
Handle = dlopen (dvm_lib_path, int mode );


1. Read the content of the dexFileName file and decrypt it to the byte array.
2. Call the dexFileParse function to parse the byte array as DexFile
\ Dalvik \ libdex \ DexFile. c
DexFile * dexFileParse (const u1 * data, size_t length, int flags) // dlsym (handle, "dexFileParse ");

3. Call allocateAuxStructures to convert DexFile to DvmDex. (because the method is static, it must be implemented according to its logic)
\ Dalvik \ vm \ DvmDex. c
Static DvmDex * allocateAuxStructures (DexFile * pDexFile)

4. Add DvmDex to gDvm. userDexFiles
\ Dalvik \ vm \ Init. c
Struct DvmGlobals gDvm; // gDvm = dlsym (handle, "gDvm ");

5. Modify the mCookie value of the mDexs object in MyDexClassLoader. mCookie is mainly used to map the underlying DvmDex data.
DexClassLoader. mDexs [0]. mCookie Value

}

(4) How does so implement program anti-debugging?
Similar to the basic principles of linux anti-debugging, here we provide a way to call the ptrace method in JNI_Onload. ptrace is widely used for debugging (such as IDA) and process code injection (such as LBE, kingsoft and Other permission management functions), a process can only be one process ptrace, if you call ptarce, so that other programs can not debug through ptrace or inject code to your program process.
Ptrace (PTRACE_TRACEME, 0, 0, 0 );
Through my own experiments, this method can implement anti-debugging of so.
Iii. Summary
Through the above analysis, Zookeeper reinforcement can effectively prevent mobile applications from cracking, piracy, secondary packaging, injection, decompilation, and other damages during operation and promotion, however, if Android malware also reinforces protection in this way, this will pose a huge challenge to mobile security analysts, because the code static logic analysis and dynamic debugging analysis that security analysts often use are invalid in this case.
Zookeeper officially claims that it will not reinforce the malicious software. It is indeed found that security software scanning information and cloud testing and processing procedures exist during the reinforcement process, however, these measures can only be reduced, rather than completely prevent malware from being reinforced by the zookeeper. How to avoid being exploited by malware is a problem that zookeeper needs to solve.

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.