read

FridaLab

created by Ross Marks

The app is similar to bomblabs, it contains challenges suitable for a frida beginner to learn how the basics of frida works.

Download

Emulator

I prefer using Genymotion(Windows 10 with virtualbox)

Frida installation

  • pip install frida-tools
  • After installing frida-tools run the virtual anroid device
  • Then use adb start-server to start adb server then connect to the device adb connect ip:port (it automatically detects the device )
  • You can see your device using adb devices
  • Now Download Frida-server from here for android (frida-server-VER_NUM-android-x86.xz)
  • Unzip the server unxz frida-server.xz
  • Then push, set perms and run frida-server :
    • adb push frida-server /data/local/tmp/
    • adb shell "chmod 755 /data/local/tmp/frida-server"
    • adb shell "/data/local/tmp/frida-server &"

Getting Started

  • Once your frida env is ready go ahead and install the apk and start tracing the apk.
  • To install use adb install fridalab.apk
  • To start tracing frida -U -f uk.rossmarks.fridalab
  • Once you run the above commands you will get the frida shell: [img]
  • When you use %resume, it will break at the “start” and the classes would not be declared.
  • You can follow the above commands for any application you are debugging.

Decompiler

jadx - Dex to Java decompiler

Challenges

  • Challenge01: Change class challenge_01’s variable ‘chall01’ to 1
  • Challenge02: Run chall02()
  • Challenge03: Make chall03() return true
  • Challenge04: Send “frida” to chall04()
  • Challenge05: Always send “frida” to chall05()
  • Challenge06: Run chall06() after 10 seconds with correct value
  • Challenge07: Bruteforce check07Pin() then confirm with chall07()
  • Challenge08: Change ‘check’ button’s text value to ‘Confirm’

Writeup

First, we’ll begin by decompiling the APK using jadx-gui, which you can access through the provided link. Once decompiled, the majority of the source files we need to analyze will be located within the “uk.rossmarks.fridalab” directory. This directory structure holds true for other APKs as well, where the main source files can be found under the directory you’re using to trace in the Frida command. Other directories mostly contain resources or external libraries. In certain CTF challenges, there may be different directories, but those instances are rare. Additionally, there might be a separate directory related to React API, which will be covered in a different blog.

Challenge01:

So after we decompile and enter the dir uk/rossmarks/fridalab, we come across the challenge_01.java. The challenge is to change the value of the variable declared in that class. To update in java using frida, we use Java.perform the syntax for this is:

Java.perform(function f(){
    "...type your functions you want to do here ...";
});

To use a initialised class, we can use Java.use('class_path');. To use class challenge_01 we would do:

Java.perform(function f(){
    var chall1=Java.use('uk.rossmarks.fridalab.challenge_01');
});

We assign it to a var as we need to update the component of the class. We are basically calling the init() of challenge_01 now to update the var chall01:

Java.perform(function f(){
    var chall1=Java.use('uk.rossmarks.fridalab.challenge_01');
    chall1.chall01.value=1;
});

To update the value we have to use .value After running this command in the frida shell we get: remember dont put \n in frida shell it dosent accept that

Challenge02:

If you’re unable to find the “challenge02” class in the Java files, take a look at the “MainActivity” instead. Interestingly, it’s labeled as “Main activity” for unknown reasons. This class is responsible for being initiated and triggering the “onCreate” function whenever the APK starts.

In the MainActivity class you can see the chall02() function, so do we follow the same steps as challenge 1? Lets try it out, just instead of modifying a variable we are calling a function here.

Java.perform(function f(){
    var chall2=Java.use('uk.rossmarks.fridalab.MainActivity');
    chall2.chall02();
});

So, basically chall02() is an instance function and it cant be called as above method because we are not intiating a instance. We need to have a running instance, so lets create one.

var main;
Java.choose('uk.rossmarks.fridalab.MainActivity',{
  onMatch: function(instance) {
    main = instance;
  },
  onComplete: function() {}
});
main.chall02();

we are using Java.choose over here Note we will be using main variable instance for the later challenges. So lets perform the above steps and check if we succeed.

Challenge03:

The chall03() is also there in MainActivity. We need to overwite this function so that it returns true.

main.chall03.overload().implementaion=function(){
    return true;
}

Challenge04:

Since we already have our instance intialised, we just had to call the cahll04() with “frida” as the argument.

main.chall04('frida')

Challenge05:

So in this challenge we have to overload the function, which results in it calling the original function with “frida” as the argument.

main.chall05.overload('java.lang.String').implementation=function (arg1){
    this.chall05.overload('java.lang.String').call(this,'frida');
    return;
}

Challenge06:

In this challenge we need to wait 10 seconds and then submit the correct value to the validation function. Our approach here is to overwrite the return value to true so that whenever confirmchall06() is called it returns true.

Java.perform( function(){
	var chall6 = Java.use("uk.rossmarks.fridalab.challenge_06");
	chall6.confirmChall06.implementation = function(a) {
        var returnValue = this.confirmChall06(a);
        var newReturnValue = true;
        return newReturnValue;
	};
	var main_instance;
	Java.choose("uk.rossmarks.fridalab.MainActivity" , {
  		onMatch : function(instance){
    			instance.chall06(1);
			main_instance=instance;
  		},
  	onComplete:function(){}
	});
});

Challenge07:

There are 2 ways to solve this challenge: The first way is to we can just get the value of chall07.chall07 (By statically analysing the class I came to the conclusion that it is the pin).

var chall07=Java.use("uk.rossmarks.fridalab.challenge_07");
console.log(chall07.chall07.value);
main.chall07('5105');

The other way is to bruteforce the chall07.check07pin().

function pad(num, size) {
    num = num.toString();
    while (num.length < size) num = "0" + num;
    return num;
}
for(var i=9999;i>=0;i--){
  if (chall07.check07Pin()) {
    main.chall07(pad(i,4));
    break;
  }
}

Challenge08:

This Challenge is different from other challenges as it deals with modifying the UI of the apk. We saw that in check for chall08() R.id.check is used as the ui component id, which if seen in decompilation of r class is:

Now that we know the id of the component we can just cast the button on an operator by using Java.cast() and then change text using String.setText().

var button = Java.use('android.widget.Button');
var check = main.findViewById(0x7f07002f);
var confirm = Java.cast(checkid, button);
var string = Java.use('java.lang.String');
confirm.setText(string.$new("Confirm"));

Conclusion

These challenges provided a solid introduction to Android reversing for beginners. They effectively covered both the frida aspect and the fundamental structure of an apk.

Thanks to the author Ross Marks for such a cool set of challenges

Blog Logo

fug1t1ve


Published

Image

fug1t1ve blogs

Blog that will introduce you to some of the interesting topics of Reverse Engineering

Back to Overview