Deep Analysis of Android Rootnik Malware Using Advanced Anti-Debug and Anti-Hook, Part I: Debugging in The Scope of Native Layer

Recently, we found a new Android rootnik malware which uses open-sourced Android root exploit tools and the MTK root scheme from the dashi root tool to gain root access on an Android device. The malware disguises itself as a file helper app and then uses very advanced anti-debug and anti-hook techniques to prevent it from being reverse engineered. It also uses a multidex scheme to load a secondary dex file. After successfully gaining root privileges on the device, the rootnik malware can perform several malicious behaviors, including app and ad promotion, pushing porn, creating shortcuts on the home screen, silent app installation, pushing notification, etc.  In this blog, I’ll provide a deep analysis of this malware.

A Quick Look at the Malware

The malware app looks like a legitimate file helper app that manages your files and other resources stored on your Android phone.

Figure 1. The malware app icon installed

Figure 2. A view of the malware app

We decompiled the APK file, as shown in Figure 3.

Figure 3. Decompile the malware app’s apk file

Its package name is com.web.sdfile. First, let’s look at its AndroidManifest.xml file.

Figure 4. AndroidManifest.xml file inside the malware app’s apk file

We can’t find the main activity com.sd.clip.activity.FileManagerActivity, service class, or broadcast class in Figure 4.  Obviously, the main logic of the file helper app is not located in the classes.dex.  After analysis, it was discovered that the malware app uses the multidex scheme to dynamically load a secondary dex file and execute it.

How Rootnik Works

I. Workflow of Rootnik

The following is the workflow of the android rootnik malware.

Figure 5. An overview of the android rootnik malware’s workflow

II. Going deep into the first dex file

The following is a code snippet of the class SecAppWrapper.

Figure 6. A code snippet of the class SecAppWrapper

The execution flow is shown below.

Static code block -> attachBaseContext -> onCreate

The static code block loads the dynamic link library libSecShell.so into the folder assets, and the program enters into the native layer, performs several anti-debug operations, decrypts the secondary dex file, and then uses a multidex scheme to load the decrypted secondary dex file, which is actually the main logic of the real application.

The class DexInstall is actually the class MultiDex, and it refers to

https://android.googlesource.com/platform/frameworks/multidex/+/d79604bd38c101b54e41745f85ddc2e04d978af2/library/src/android/support/multidex/MultiDex.java

The program then invokes the method install of DexInstall to load the secondary dex file.  The invoking of the method install of DexInstall is executed in native layer.

Figure 7. Installing the secondary dex file

In function attachBaseContext, the program loads the class com.sd.clip.base.MyApplication, which is the execution entry of the secondary dex. The method attach of Helper is a native method.

In function onCreate, the program executes the method onCreate of the class com.sd.clip.base.MyApplication.

That’s it. The first dex file is rather simple. Next, we’ll do a deep analysis of the native layer code, which is very complicated and tricky.

III. The scope of the native layer code

As described above, the native layer code uses some advanced anti-debug and anti-hook techniques, and also uses several decryption algorithms to decrypt some byte arrays to get the plain text string.

The following is part of the export functions in libSecShell.so.  It becomes harder to analyze due to obfuscated function names.

Figure 8. Part of export functions in libSecShell.so

All anti-debug native code is located in function JNI_Onload.

As described in the last section, the method attach of class Helper in java scope is a native method. The program dynamically registers this method in native layer.  The following is a snippet of the ARM assembly code that registers native method in native layer.

Figure 9. Dynamically register native method in native layer

The function RegisterNatives is used to register a native method. Its prototype is shown below.

jint RegisterNatives(JNIEnv *env,jclass clazz, const JNINativeMethod* methods,jint nMethods)

The definition of JNINativeMethod is shown below.

typedef struct {
const char* name;
const char* signature;
void* fnPtr;
} JNINativeMethod;

The first variable name is the method name in Java. Here, it’s the string “attach”. The third variable, fnPtr, is a function pointer that points to a function in C code. 

We next need to find the location of the anti-debug code and bypass it, analyze how the secondary dex file is decrypted, and the dump the decrypted secondary dex file from memory.

Let’s look at the following code in IDA:

Figure 10. Code snippet around anti-debug code

Based on our deep analysis, the instruction at address 0xF832 is a jump to address loc_F924.

After tracing some code, we found the anti-debug code.

Figure 11. The location of the anti-debug code

The function p7E7056598F77DFCC42AE68DF7F0151CA() performs the anti-debug operations.

The following is its graphic execution flow, which is very complicated.

Figure 12. The graphic execution flow of anti-debug code

The following are some methods of anti-debug and anti-hook used in the malware.

1. Detect some popular hook frameworks, such as Xposed, substrate, adbi, ddi, dexposed. Once found, hook it using these popular hook frameworks. It then kills the related process.

Figure 13. Detection of Xposed hook framwork

Figure 14. Finding the hook feature

2. It then uses an kind of multi-process ptrace to implement anti-debug, which is tricky a little.  Here we don’t plan to provide a deailed analysis of the anti-debugging implementation mechanism, but only give some simple explanations.

We can see that there are two processes named com.web.sdfile.

Figure 15. Two processes named com.web.sdfile

    The following is a snippet of multi-process anti-debug code.

Figure 16. A snippet of anti-debug code

3. The program also uses inotify to monitor the memory and pagemap of the main process. It causes the memory dumping to be incomplete.  The two processes use pipe to communicate with each other.

In short, these anti-debug and anti-hook methods create a big obstacle for reversing engineering.  So bypassing these anti- methods is our first task. 

Let’s try to bypass them.

As described in Figure 10, the instruction at offset 0x0000F832 jumps to loc_F924, and then the program executes these anti-debug codes. We can dynamically modify the values of some registers or some ARM instructions to change the execution flow of the program when dynamically debugging.  When the program executes the instruction “SUBS R1, R0, #0” at offset 0xF828, we modify the value of register R0 to a non-zero value, which makes the condition of the instruciotn “BNE  loc_F834” become true. This allows the program to jump to loc_F834.  

Figure 17. How to bypass the anti-debug code

Next, we dynamically debug it, bypass the anti-debug, and then dump the decrypted secondary dex file. The dynamic debugging is shown below.

Figure 18. Modifying the value of R0 to non-zero

Figure 19. Jump to local_75178834

Next,  jump to local_751788D8, as follows.

Figure 20. Decryption function for the secondary dex

The function p34D946B85C4E13BE6E95110517F61C41 is the decryption function. The register R0 points to the memory storing the encrypted dex file, and the value of R1 is the size of file and is equal to 0x94A3E(608830). The encrypted dex file is secData0.jar in the folder assets in the apk package. The following is the file secData0.jar.

Figure 21. The file secData0.jar in the folder assets in the apk package

Figure 22.  The content of the decrypted secondary apk file in memory

We can now dump the memory of the decrypted file to the file decrypt.dump.

The decrypted file is a zip format file, and it contains the secondary dex file. After decryption, the program decompresses the decrypted secondary apk to a dex file. The function p3CBBD6F30D91F38FCD0A378BE7E54877 is used to decompress the file.

Next, the function unk_75176334 invokes the java method install of class com.secshell.shellwrapper.DexInstall to load the secondary dex.

Figure 23. Decompressing the decrypted secondary apk and loading the secondary dex file

Figure 24. Calling the method install via Jni

Here we finish the analysis of native layer and get the decrypted the secondary apk file, then will analyze the apk file in the part II of this blog.

The Decryption Function That Decrypts secData0.jar in Native Layer:

https://blog.fortinet.com/feed