Post

Dynamic Instrumentation

Dynamic Instrumentation

1- To inject Frida into an APK we can use objection:

1
objection patchapk -s apk_name.apk

Objection will extract, patch, re-pack, align and sign the application, and so it’s a very fast and easy way to get Frida running.

Note that the application will wait on launch for Frida to connect to it, so to start the application we have to run:

1
frida -U FridaTarget

The -U here specifies that we want to connect by USB.

2- If you have a rooted device, you can also run frida-server instead of patching the APK. You can download frida-server on the Github Releases Page of Frida. Note that it comes xz compressed, so you have to extract it (xz -d on unixoid systems, 7zip on for example Windows).

To install it in an emulator we can adb push the server over:

1
adb push frida-server /data/local/tmp/

We chose this path because other parts, such as /sdcard, are commonly mounted no-exec.

Afterwards we want to run adb as root, and also make the server executable:

  1. adb root
  2. adb shell
  3. cd /data/local/tmp
  4. chmod +x frida-server

And then we are ready to go: We can launch the server by running

1
./frida-server

Now we can connect to the application by running:

1
frida -U FridaTarget

3- The Frida REPL (Read-Eval-Print-Loop) is a JavaScript interpreter, and so we can directly run JavaScript statements:

1
for(var i=0; i < 5; i++) { console.log(i); }

To create multi-line statements, suffix each line with a \ backslash:

1
2
3
for(var i=0; i < 5; i++) {\
    console.log(i);\
}

Check-out the full Frida JavaScript API documentation here!

To load scripts with Frida, we can just start Frida with the -l option:

1
frida -U -l test.js FridaTarget

We can enable and disable auto-reload by doing:

1
%autoreload on/off

To manually reload all scripts, we can just run %reload in the REPL.

4- We can get JavaScript wrappers for Java classes by using Java.use:

1
Java.use("java.lang.String")

We can then instantiate those classes by calling $new:

1
2
3
var string_class = Java.use("java.lang.String");
var string_instance = string_class.$new("Teststring");
string_instance.charAt(0);

We can dispose of instances (for example to free up memory) using $dispose(), however this is almost never required, as the Garbage Collector should collect unused instances.

We can also replace the implementation of a method by overwriting it on the class:

1
2
3
4
string_class.charAt.implementation = (c) => {
    console.log("charAt overridden!");
    return "X";
}

5- Example to call function that return decrypted flag:

1
2
3
4
5
6
Java.perform(() => {
    let ExampleClass = Java.use("io.hextree.fridatarget.FlagClass");
    let ExampleInstance = ExampleClass.$new();
    console.log(ExampleInstance.flagFromStaticMethod());
    console.log(ExampleInstance.flagIfYouCallMeWithSesame("sesame"));// this function take pass paramter
})

Tracing Activities

1
2
3
4
5
6
7
8
Java.perform(() => {
    let ActivityClass = Java.use("android.app.Activity");
    ActivityClass.onResume.implementation = function() {
        console.log("Activity resumed:", this.getClass().getName());
        // Call original onResume method
        this.onResume();
    }
})

Trace By fragments:

1
2
3
4
5
6
7
8
Java.perform(() => {
    let FragmentClass = Java.use("androidx.fragment.app.Fragment");
    FragmentClass.onResume.implementation = function() {
        console.log("Fragment resumed:", this.getClass().getName());
        // Call original onResume method
        this.onResume();
    }
})

Frida-trace

Frida trace allows us to directly trace function calls.

To trace specific Method on io.hextree.*, we can do:

1
frida-trace -U -j 'io.hextree.<ClassName>!<MethodName> <apkName>

To trace all calls on io.hextree.*, we can do:

1
frida-trace -U -j 'io.hextree.*!*' <apkName>

To exclude Class on io.hextree.*, we can do:

1
frida-trace -U -j 'io.hextree.*!*' -J <anoyingClass> <apkName>

We can also trace into native objects, by specifing the -I option:

1
frida-trace -U -I 'libhextree.so' -j 'io.hextree.*!*' FridaTarget

We can also trace into native objects, by specifing the -I option:

1
frida-trace -U -I 'libhextree.so' -j 'io.hextree.*!*' FridaTarget

Frida Interception Basics

We can use Frida to intercept function calls and return values. For example, to replace the return value of InterceptionFragment.function_to_intercept, we can just write a simple script:

1
2
3
4
5
6
7
Java.perform(() => {
    var InterceptionFragment = Java.use("io.hextree.fridatarget.ui.InterceptionFragment");
    InterceptionFragment.function_to_intercept.implementation = function(argument) {
        this.function_to_intercept(argument);
        return "SOMETHING DIFFERENT";
    }
})

To get method name :

1
2
Java.enumerateMethods("*okhttp*Builder!*")
Java.enumerateMethods("*Platform!*checkServerTrusted*")

And the above Classes you can get it through frida-trace:

1
2
frida-trace.exe -U -j "*!*okhttp3*" FridaTarget
frida-trace.exe -U -j "*!*checkServerTrusted*" FridaTarget

Then to bypass SSL pining and network config:

1
2
3
4
5
6
7
Java.perform (() => {

    var ssl_bypass = Java.use("com.android.org.conscrypt.Platform");
    ssl_bypass.checkServerTrusted.overload('javax.net.ssl.X509TrustManager', '[Ljava.security.cert.X509Certificate;', 'java.lang.String', 'com.android.org.conscrypt.ConscryptEngine').implementation = function(){
        console.log("Check Server Trusted");
    }
})

For OKHTTP3-based pinning we need to combine the script of the previous video, and a small new one that prevents the SSLPinner from being added to the OkHttpClient:

1
2
3
4
5
6
7
Java.perform(() => {
    var BuilderClass = Java.use("okhttp3.OkHttpClient$Builder");
    BuilderClass.certificatePinner.implementation = function() {
        console.log("Certificate pinner called");
        return this;
    }
})

THANKS FOR READING ❤️

This post is licensed under CC BY 4.0 by the author.