# Frida Lab: Challenge 0xA and 0xB Writeup # Challenge 0xA For this challenge, I'll be using Genymotion as my Android emulator. Before we start reversing, let's install the app and check out what it looks like. ![Pasted image 20240505145949](https://hackmd.io/_uploads/Sy7n5OHMA.png) It looks like there isn't much to interact with in the application; it just has a text view with "**Hello Hackers**" in the center of the screen. Let's dig deeper. I'm going to use [jadx](https://github.com/skylot/jadx) to explore the inner workings of the app. ![img1 1](https://hackmd.io/_uploads/SkbR5OSM0.jpg) After opening the app in [jadx](https://github.com/skylot/jadx), I immediately focused on the native functions at the top. ```java public final native String stringFromJNI(); ``` This indicates that the application is using JNI, which stands for Java Native Interface. JNI is a framework that enables Java code running in a Java Virtual Machine (JVM) to interact with native applications and libraries written in other languages like C or C++. At the bottom, you can see that the native library is being loaded. ```java static { System.loadLibrary("frida0xa"); } ``` As you can see from the above snippet, the library `frida0xa` is being loaded. Let's dig even deeper. Using [apktool](https://github.com/iBotPeaches/Apktool), let's decompile the application and put `frida0xa.so` under [Ghidra](https://github.com/NationalSecurityAgency/ghidra) to see what's going on inside. You can use the following command to decompile the application. ```bash apktool d <name>.apk ``` ![Pasted image 20240505153258](https://hackmd.io/_uploads/ryQmourGR.png) After decompiling the app, you can find the library under `app-name/lib/`. ![Pasted image 20240505153530](https://hackmd.io/_uploads/SkQNs_rzA.png) Now, let's open **libfrida0xa.so** in [Ghidra](https://github.com/NationalSecurityAgency/ghidra). ![img2](https://hackmd.io/_uploads/HkQriuSGA.jpg) After opening the library, we can see two interesting functions: 1) `Java_com_ad2001_frida0xa_MainActivity_stringFromJNI`: This function is called on `MainActivity`. On line 12, you can see the string "**Hello Hackers**" being set. 2) `get_flag`: This function is another interesting one. ![Pasted image 20240505153952](https://hackmd.io/_uploads/SJ_LsurGR.png) In the function decompile window, you can see that the flag is encrypted with some sort of operation. We could take the code, reverse the operation, and get the flag. However, this is not the intended solution for the challenge. Additionally, the function takes two parameters, and the flag is only decoded if a certain `if` instruction evaluates to true. ```c if (param_1 + param_2 == 3) ``` We can simply pass ```c get_flag(1, 2); ``` If you look closely at the function, you'll notice that an Android log function is being called after decrypting the flag. ```c __android_log_print ``` Now that we know what we need to do, since the **get_flag** function is not being called, we need to call the function somehow to print the flag in the Android log. To do that, we can use [Frida](https://github.com/frida). ## What is frida? > [Frida](https://github.com/frida) is a dynamic instrumentation toolkit that allows developers, reverse engineers, and security researchers to inject JavaScript into running processes on Windows, macOS, Linux, **iOS**, and **Android**, enabling them to analyze and manipulate the behavior of applications and the operating system. [Frida](https://github.com/frida) is a powerful tool, and for this challenge, we are going to call the **get_flag** function using [Frida](https://github.com/frida). Before solving the challenge using [Frida](https://github.com/frida), we need to set it up. You can check out their [documentation](https://frida.re/docs/android/) on how to do that. Let's see if [Frida](https://github.com/frida) is working properly. By running the following command, we should see our target app starting and the [Frida](https://github.com/frida) CLI. ```shell frida -U -f "com.ad2001.frida0xa" ``` ![Pasted image 20240505161325](https://hackmd.io/_uploads/Hyrqs_HzC.png) Good! Let's now run the following command to get the `get_flag` function name. ```js Module.enumerateExports("libfrida0xa.so") ``` ![Pasted image 20240505162225](https://hackmd.io/_uploads/H1qnj_HG0.png) Great! We got the function name, which is `_Z8get_flagii`. Now we can get the address of the function and use the `NativeFunction` function to call it. ```js if (Java.available) { Java.perform(function() { let get_flag_address = Module.findExportByName("libfrida0xa.so", "_Z8get_flagii"); var get_flag = new NativeFunction(ptr(get_flag_address), "void", ["int", "int"]); send("calling get_flag()..."); get_flag(1,2); }); } ``` The final code looks something like this. Let's see what the code is doing: ```js let get_flag_address = Module.findExportByName("libfrida0xa.so", "_Z8get_flagii"); ``` It gets the address of the `get_flag` function using `Module.findExportByName`. ```js var get_flag = new NativeFunction(ptr(get_flag_address), "void", ["int", "int"]); ``` In this line, it's preparing a `NativeFunction` based on the address of `get_flag`. The second parameter is the return type of the function, which is `void`, and the last parameter is the type of the parameters we need to pass, which are both `int` as we've seen in [Ghidra](https://github.com/NationalSecurityAgency/ghidra). ```js get_flag(1,2); ``` Lastly, we call the function. Let's open logcat and see if calling the function spits out the flag for us. ![Pasted image 20240505163435](https://hackmd.io/_uploads/S14e3dSMC.png) Boom! As you can see, we get our flag. # Challenge 0xB For the final challenge, let's open the app on an emulator and see what it looks like. ![Pasted image 20240505163822](https://hackmd.io/_uploads/HkV86uSMA.png) The app looks simple enough, with a **CLICK ME** button in the center of the screen that does nothing when clicked. Let's use [jadx](https://github.com/skylot/jadx) to see what's going on. ![img3](https://hackmd.io/_uploads/rJFPaOHz0.jpg) In this challenge, the app is also using a native library. When the button is clicked, the **getFlag** function is being called, but nothing seems to be happening. Let's check the log to see if the flag is being output there. ![Pasted image 20240505164812](https://hackmd.io/_uploads/SkbdTuBfC.png) No flag yet. Let's dig deeper. Like the previous challenge, let's decompile the app using [apktool](https://github.com/iBotPeaches/Apktool) and load the library using [ghidra](https://github.com/NationalSecurityAgency/ghidra). ![Pasted image 20240505165116](https://hackmd.io/_uploads/ryJt6dSfC.png) Decompiling the `getFlag` function shows nothing. It looks like it's doing nothing. Is it not? If you check out the comments left by [ghidra](https://github.com/NationalSecurityAgency/ghidra), you can see there is some unreachable code. Let's check out the assembly code. ![Pasted image 20240505165327](https://hackmd.io/_uploads/Sy9YpOrG0.png) Okay, good. The assembly code tells us what the function is doing, and it explains why [ghidra](https://github.com/NationalSecurityAgency/ghidra) marked the function as unreachable. After the function prologue... ```assembly MOV dword ptr [RBP + local_2c],0xdeadbeef CMP dword ptr [RBP + local_2c],0x539 JNZ LAB_001171a6 ``` You can see the following instruction: it's comparing `0xdeadbeef == 0x539`, which is always **false**. The rest of the code will not be executed. To understand the code more, let's enable the option in [ghidra](https://github.com/NationalSecurityAgency/ghidra) to show the unreachable code. ![Pasted image 20240505170044](https://hackmd.io/_uploads/r1Zia_SMR.png) Unset __Eliminate unreachable code__ ![Pasted image 20240505170153](https://hackmd.io/_uploads/H1iopurGA.png) Now we can see the decompiled code a little clearer. If `0xdeadbeef == 0x539` equals true, we can see that the flag will be decrypted. Like the previous challenge, the flag will be logged. ## What we need to do 1) We need a way to patch the instruction so that it evaluates to true. 2) Call the **getFlag** function. Once again, we are going to use [frida](https://github.com/frida) with [radare2](https://github.com/radareorg/radare2) or **r2** for short. We are going to install a special plugin for **radare2** called [r2frida](https://github.com/nowsecure/r2frida). ## What is r2frida >r2frida is a plugin for the radare2 reverse engineering framework that enables interaction with Frida, a dynamic instrumentation toolkit. To install the plugin, we can use the following command: ```bash r2pm -ci r2frida ``` ![Pasted image 20240505171419](https://hackmd.io/_uploads/r1dTpOSGC.png) To verify if the plugin is installed, use the following command: ```bash r2pm -l ``` ![Pasted image 20240505171509](https://hackmd.io/_uploads/SyvCpuBMA.png) To spawn the app, use the following command: ```bash r2 'frida://launch/usb//com.ad2001.frida0xb' ``` ![Pasted image 20240505194443](https://hackmd.io/_uploads/HywkC_HzR.png) To list all the native libraries and filter for the challenge library, you can use the following command: ```bash :il~+libfri ``` ![Pasted image 20240505194619](https://hackmd.io/_uploads/SkLlCOSzA.png) To seek to the base address of the library and search for the `getFlag` function address, you can use the following commands in r2: ![Pasted image 20240505194827](https://hackmd.io/_uploads/rk_WRdSM0.png) To seek to the address of `getFlag` and view the instructions at that address, you can use the following command in r2: ```bash pd 25 ``` ![Pasted image 20240505195043](https://hackmd.io/_uploads/HkjzR_BfR.png) From the above screenshot, we can see that we're at the right address. ## Ways to Solve This Challenge 1) We can patch the instruction using [r2frida](https://github.com/nowsecure/r2frida) and trigger the function. 2) Or, using just [frida](https://github.com/frida) to patch in the correct address. ### Patching the Instruction Using r2frida The first thing we need to do is seek to the function we're patching, then press `v`. ![Pasted image 20240505195636](https://hackmd.io/_uploads/SJcmCdBGA.png) Set the instruction we're patching to the top of the line. ![Pasted image 20240505195726](https://hackmd.io/_uploads/SkXEAdHMC.png) Then `A`, type the instruction that we want to patch. ```assembly mov dword [ebp - 0x10], 0x539 ; 1337 ``` ![Pasted image 20240505195823](https://hackmd.io/_uploads/B1VrAuBfR.png) Now, save the changes and to verify the instruction is patched, let's use the `pd` command to view the instruction. ![Pasted image 20240505200023](https://hackmd.io/_uploads/SJy8RuHfC.png) Good, it's patched. Let's now open **logcat** and click on the button. ![Pasted image 20240505200114](https://hackmd.io/_uploads/ByJPCOrz0.png) Awesome! As you can see, our patch worked, and when we clicked on the button, it logged the flag. ### Using Frida Let's use the following code to get the base address of the native lib. Since we've solved the challenge using [r2frida](https://github.com/nowsecure/r2frida), we can start our app using just [Frida](https://github.com/frida), attach to the process using [r2frida](https://github.com/nowsecure/r2frida), and check if the base address of the native lib is the same. ```js Module.getBaseAddress("libfrida0xb.so") ``` ![Pasted image 20240505200538](https://hackmd.io/_uploads/r1J_CurGR.png) Now, let's attach to the process using [r2frida](https://github.com/nowsecure/r2frida) and verify that we have the same address. ![Pasted image 20240505201257](https://hackmd.io/_uploads/r15dRuSG0.png) As we can see from the above screenshot, both are showing the same base address. ```js let getFlagOffset = 0x10e00; let getFlagAddress = Module.getBaseAddress("libfrida0xb.so").add(getFlagOffset); let patchOffset = ptr(getFlagAddress).add(0x1c); ``` In the following code, we get the base address of `libfrida0xb.so`, add the offset of the **getFlag** function, and finally, we add the exact offset, which is `0x1c`, where the `0xdeadbeef` value is being **mov**ed to the stack. ```assembly mov dword [ebp - 0x10], 0xdeadbeef ``` then in this location we're going to patch the instruction, changing the value from `0xdeadbeef` to `0x539` ```js Memory.protect(patchOffset, 0x100, "rwx"); let writer = new X86Writer(patchOffset); try { writer.putMovRegOffsetPtrU32('ebp', -0x10, 0x539); writer.flush(); } finally { writer.dispose(); } ``` Let's run our code and verify using [r2frida](https://github.com/nowsecure/r2frida) to check if the instruction is patched or not. ![Pasted image 20240505202404](https://hackmd.io/_uploads/HkRcRuHGC.png) The code ran without any errors. Let's verify the patch. ![img4](https://hackmd.io/_uploads/B19iC_BfA.jpg) The instruction has been patched. Let's click on the button and see what happens. ![Pasted image 20240505202743 (copy)](https://hackmd.io/_uploads/rJH30OBGA.png) Awesome, it looks like the patch worked! **Challenge link**: https://github.com/DERE-ad2001/Frida-Labs ### Reference 1) https://frida.re/docs/home/ 2) https://www.radare.org/doc/frida/modules.html 3) https://github.com/enovella/r2frida-wiki