[100 cases of APP reverse engineering] Frida's first experience, root detection and encrypted string location

thumbnail

statement

All the content in this article is for learning and communication only, not for any other purpose, and complete code is not provided, and the content of captured packets, sensitive URLs, data interfaces, etc. have been desensitized, and are strictly prohibited for commercial and illegal purposes, otherwise by All consequences arising from this have nothing to do with the author!

This article is prohibited from reprinting without permission, and any secondary dissemination after modification is prohibited. The author is not responsible for any accidents caused by unauthorized use of the technology explained in this article. If there is any infringement, please contact the author on the official account [] to delete it immediately!

reverse target

  • Device: Google Pixel4, Android 10, rooted
  • APP: UnCrackable-Level1.apk (can be obtained by replying to the APP on the official account)
  • The APP has detected the root. If the phone is rooted, the APP will be forced to exit. After the root detection, a string needs to be entered for verification.

Install ADB

adb (Android Debug Bridge) is the Android Debug Bridge. After installation, you can interact with the mobile phone on the computer. Tools such as Android Studio will come with adb. Sometimes we don’t want to download such a large tool, so here we introduce the Android SDK Platform -Tools, it is a component of the Android SDK, it includes tools to interact with the Android platform, mainly adb and fastboot, the official download address: https://developer.android.com/studio/releases/platform-tools, the download is complete Then add this directory to the environment variable, connect the phone with USB, set the phone to allow USB debugging, use the command adb version to view the version information, and adb devices to view the currently connected device, as shown in the following figure:

Install Frida

Frida is a Hook and debugging framework based on Python + JavaScript. First, use the command pip install frida-tools on the computer to install the frida module (this command will install the latest version of frida and frida-tools by default, such as), and then download frida-server , download address: https://github.com/frida/frida/releases

The frida-server should be selected according to the frida version installed on your computer and the CPU architecture of the mobile phone. Use the command frida --version to view the frida version, use the command adb shell to enter the mobile phone, and enter getprop ro.product.cpu.abi to view CPU architecture, as shown in the figure below, my frida version is 15.2.2, and the phone CPU is arm64, so I downloaded frida-server-15.2.2-android-arm64.xz.

Some lower versions of Android may have problems using higher versions of frida. If you encounter problems, try to lower the version of frida to solve them.

Use the adb push command to transfer the downloaded frida-server to the /data/local/tmp/ directory of the mobile phone, and give 777 permission to read, write, and execute, and then run frida-server directly. Normally, there will be no output. Of course, you can also use & etc. to make it run in the background.

Then open another cmd and use the command frida-ps -U to view the process of the phone, if there is output, it is normal.

reverse analysis

Use the adb install command to install UnCrackable-Level1.apk, open the APP, root will be detected, and a prompt of Root detected! will appear, as shown in the figure below:

Use JEB, JADX, GDA and other tools to decompile the apk, and directly search for the keyword Root detected! to locate the detected location:

You can see that there are three detection methods ca(), cb(), and cc() in the figure, one of which returns true, then Root detected! will pop up, and then there is an onClick method in front, if the OK button is clicked, System. exit(0);, that is, to exit the APP, first click on the three detection methods to see:

The a() method judges whether it is rooted by detecting whether there is a su file in the Android system environment variable;

The b() method determines whether it is rooted by detecting whether the string test-keys is contained in Build.TAGS;

The c() method determines whether it is rooted by checking whether the specified file is contained in the specified path.

So here we have a variety of methods for passing detection:

Method 1: Hook the three detection methods, let them all return false, and do not execute the subsequent method a, and the APP will not exit:

Java.perform(

function(){

console.log("[*] Hook begin")

var vantagePoint = Java.use("sg.vantagepoint.a.c")

vantagePoint.a.implementation = function(){

console.log("[*] Hook vantagepoint.a.c.a")

this.a();

return false;

}

vantagePoint.b.implementation = function(){

console.log("[*] Hook vantagepoint.a.c.b")

this.b();

return false;

}

vantagePoint.c.implementation = function(){

console.log("[*] Hook vantagepoint.a.c.c")

this.c();

return false;

}

}

Method 2: Hook a() method, set it blank, do nothing, do not pop up a dialog box, and do not exit the APP:

Java.perform(

function(){

console.log("[*] Hook begin")

var mainActivity = Java.use("sg.vantagepoint.uncrackable1.MainActivity");

mainActivity.a.implementation = function(){

console.log("[*] Hook mainActivity.a")

}

}

Method 3: Hook onClick() method. After clicking OK, it is not allowed to exit the APP. Note that this is the Hook writing method of the internal class:

Java.perform(

function(){

console.log("[*] Hook begin")

var mainActivity$1 = Java.use("sg.vantagepoint.uncrackable1.MainActivity$1");

mainActivity$1.onClick.implementation = function(){

console.log("[*] Hook mainActivity$1.onClick")

}

}

Method 4: Hook System.exit() method, click OK to prevent it from exiting the APP:

Java.perform(

function(){

console.log("[*] Hook begin")

var javaSystem = Java.use("java.lang.System");

javaSystem.exit.implementation = function(){

console.log("[*] Hook system.exit")

}

}

After the root detection is passed, the APP needs to input a character string. If the input is wrong, it will prompt That's not it. Try again., as shown in the figure below:

Analyzing the Java code, there is an if-else judgment, obj is the input string, and aa(obj) is true, which means the input is correct.

Following the aa() method, you can see that bArr is a built-in string. Use the equals() method to compare whether the input str is equal to bArr:

The value of bArr is mainly obtained after processing by the sg.vantagepoint.aaa() method. If you continue to follow up, you can find that it is the AES encryption algorithm:

Here you can directly hook sg.vantagepoint.aaa() to get the encrypted value directly, which is the correct string we want. Since the ASCII code is returned here, we also need to use String.fromCharCode in the JavaScript code () to convert it into a normal character, the Hook code is as follows:

Java.perform(

function(){

var cryptoAES = Java.use("sg.vantagepoint.a.a");

cryptoAES.a.implementation = function(bArr, bArr2){

console.log("[*] Hook cryptoAES")

var secret = "";

var decryptValue = this.a(bArr, bArr2);

console.log("[*] DecryptValue:", decryptValue)

for (var i=0; i < decryptValue.length; i++){

secret += String.fromCharCode(decryptValue[i]);

}

console.log("[*] Secret:", secret)

return decryptValue;

}

}

There are two ways to run the Hook script, one is to use it in conjunction with Python, and the other is to use the script directly through the frida command. There is also a timing problem when injecting the Hook code. Sometimes it is necessary to start the Hook when the APP starts, and sometimes you can wait for the APP to start and load. Then Hook, in this example, when passing the root detection, if you use the first and second methods, that is, the three detection methods of Hook or a method, then you need to Hook when the APP is started. If you use the third and fourth methods method, that is, Hook onClick() or System.exit() method, then Hook can be done after the APP starts.

Use with Python

Let’s first look at how to use it with Python. The JavaScript code is as follows (frida-hook.js):

/* ==================================

@Time : 2022-08-29

@Author : WeChat official account:

@FileName: frida-hook.js

@Software: PyCharm

================================== */

Java.perform(

function(){

console.log("[*] Hook begin")

// Method 1: Hook the three detection methods, let them all return false, and do not execute the subsequent a method, and will not exit the APP

// var vantagePoint = Java.use("sg.vantagepoint.a.c")

// vantagePoint.a.implementation = function(){

// console.log("[*] Hook vantagepoint.a.c.a")

// this.a();

// return false;

// }

// vantagePoint.b.implementation = function(){

// console.log("[*] Hook vantagepoint.a.c.b")

// this.b();

// return false;

// }

// vantagePoint.c.implementation = function(){

// console.log("[*] Hook vantagepoint.a.c.c")

// this.c();

// return false;

// }

// Method 2: Hook a() method, leave it empty, do nothing, do not pop up a dialog box, and do not exit the APP

// var mainActivity = Java.use("sg.vantagepoint.uncrackable1.MainActivity");

// mainActivity.a.implementation = function(){

// console.log("[*] Hook mainActivity.a")

// }

// Method 3: Hook onClick() method, not allowing it to exit the APP after clicking OK

// var mainActivity$1 = Java.use("sg.vantagepoint.uncrackable1.MainActivity$1");

// mainActivity$1.onClick.implementation = function(){

// console.log("[*] Hook mainActivity$1.onClick")

// }

// Method 4: Hook System.exit method, after clicking OK, it is not allowed to exit the APP

var javaSystem = Java.use("java.lang.System");

javaSystem.exit.implementation = function(){

console.log("[*] Hook system.exit")

}

var cryptoAES = Java.use("sg.vantagepoint.a.a");

cryptoAES.a.implementation = function(bArr, bArr2){

console.log("[*] Hook cryptoAES")

var secret = "";

var decryptValue = this.a(bArr, bArr2);

console.log("[*] DecryptValue:", decryptValue)

for (var i=0; i < decryptValue.length; i++){

secret += String.fromCharCode(decryptValue[i]);

}

console.log("[*] Secret:", secret)

return decryptValue;

}

}

The Python code is as follows (frida-hook.py):

==================================

---- coding: utf-8 ----

@Time : 2022-08-29

@Author : WeChat official account:

@FileName: frida-hook.py

@Software: PyCharm

==================================

import sys

import frida

def on_message(message, data):

if message['type'] == 'send':

print("[*] {0}".format(message['payload']))

else:

print(message)

with open("./frida-hook.js", "r", encoding="utf-8") as fp:

hook_string = fp.read()

Method 1: attach mode, already started APP

process = frida.get_usb_device(-1).attach("Uncrackable1")

script = process.create_script(hook_string)

script.on("message", on_message)

script.load()

sys.stdin.read()

Method 2, spawn mode, restart APP

device = frida.get_usb_device(-1)

pid = device.spawn(["owasp.mstg.uncrackable1"])

process = device.attach(pid)

script = process.create_script(hook_string)

script.on("message", on_message)

script.load()

device.resume(pid)

sys.stdin.read()

In the Python code, the attach mode hooks the existing process, the spawn mode will restart the APP, start a new process and suspend it, and inject the frida code at the same time when starting, which is suitable for some Hooks before the process starts, and the attach mode is passed in is the APP name, and the spawn mode passes in the APP package name. There are many ways to view the APP name and package name. Here are two frida commands, frida-ps -Uai: list the installed programs, frida-ps -Ua: List the running programs, as shown in the figure below, in this example, Uncrackable1 is the APP name, and owasp.mstg.uncrackable1 is the package name:

Run the Python code, and note that the mobile phone should also start frida-server. After passing the root detection, first input a random string, click VERIFY, and it will hook to the correct string as I want to believe, and enter the correct string again, that is Can be verified successfully.

frida command

You can also use the frida command directly without using Python. There are two modes like the previous Python. The same one is the APP name and the other is the package name:

frida -U Uncrackable1 -l .\frida-hook.js: attach mode, inject frida code after APP starts;

frida -U -f owasp.mstg.uncrackable1 -l .\frida-hook.js --no-pause: spawn mode, restart APP, and inject frida code at the same time.

So far, we have perfectly bypassed the root detection and successfully found the correct string.

Latest Programming News and Information | GeekBar

Related Posts