Permanent frida hacks

I’ve always wanted to make my frida scripts permanent in the applications I’ve hacked but always thought it was too difficult, well I recently revisited this idea and realized how easy it actually is. So here is a quick guide on how to do just that.

Initial hack/modification

For this demonstration I will be using “Kittycorn diary” (https://play.google.com/store/apps/details?id=pl.netigen.kittycorn) as I wanted an app that would be easy to demonstrate a hack on, it also has an odd developer choice of putting the stored password in logcat when you first open the app, which will be useful for the final demonstration.

So firstly I install the app, add a pin and click around a bit to ensure it mostly works. now time to get the apk, either through pulling it from adb or I like to use “racoon” (raccoon.onyxbits.de)

Once you have the apk simply open it with jadx-gui and find the code that compares the stored pin to the pin that the user has supplied. Right click on that and “copy as frida snippet”

Paste that into a text editor and make it so it always returns true (no matter what pin we put in it will be accepted as the correct pin). It should look as follows:

setImmediate(function() { //prevent timeout
    Java.perform(function() {

        let LoginActivityPresenter = Java.use("pl.netigen.diaryunicorn.loginactivity.LoginActivityPresenter");
        LoginActivityPresenter["equalsPin"].implementation = function () {
            console.log('equalsPin is called');
            let ret = this.equalsPin();
            console.log('equalsPin ret value is ' + ret);
            return true;
        }

    });
});

That is it, we have successfully hacked/modified the app in the way we intended. We can test this by storing it as “1.js” and running the following command:

╰» frida -U --no-pause -l 1.js -f pl.netigen.kittycorn

Now whatever pin you enter will let you in to the app.

Frida gadgets

Here’s where the magic happens allowing you to pack that .js file with the apk. Typically you inject the frida gadget library into an apk so you can use Frida without root, however it turns out you can also insert the script inside the apk and make it load automatically, without requiring the frida client.

There are 2 methods of doing this (stolen from https://fadeevab.com/frida-gadget-injection-on-android-no-root-2-methods/):

  1. Method 1: If targeted APK contains any native library (<apk>/lib/arm64-v8a/libfromapk.so), then you can inject libfrida-gadget.so as a dependency into the native library.
  2. Method 2: If APK doesn’t contain a native library, then you can inject System.loadLibrary bytecode.

I suggest you read the above blog to understand how to inject the frida gadget in both instances. When injecting the frida gadget you also supply a config file, this file can contain the location to your script i.e.

{
  "interaction": {
    "type": "script",
    "path": "/data/local/tmp/myscript.js",
    "on_change": "reload"
  }
}

Using the above you would then store your script in “/data/local/tmp/myscript.js”. This is useful for quick and constant changes as you can then modify the script on the device and re-open the app which will then load it along with the changes. this is how https://github.com/darvincisec/InjectFridaGadget works.

When I was looking for all the different ways of doing this I found what is possibly the simplest solution.

Objection

It turns out this has already been built into objection all you have to run is the “patchapk” function along with the config file and the script to inject. This will inject the script directly into the apk, however if you want to make changes in the future you will have to re-compile again. This method has the added benefit that it also automatically signs and zip-aligns the APK after it has recompiled it!

For our example firstly create “config.json” containing:

{
  "interaction": {
    "type": "script",
    "path": "libfrida-gadget.script.so"
  }
}

Then run the following command:

╰» objection patchapk -s pl.netigen.kittycorn.apk -c config.json -l 1.js 
No architecture specified. Determining it using `adb`...
Detected target device architecture as: x86_64
Using latest Github gadget version: 15.2.2
Patcher will be using Gadget version: 15.2.2
Detected apktool version as: 2.6.1
Running apktool empty-framework-dir...
I: Removing 1.apk framework file...
Unpacking pl.netigen.kittycorn.apk
App already has android.permission.INTERNET
Target class not specified, searching for launchable activity instead...
Reading smali from: /tmp/tmpknaa5qlw.apktemp/smali/pl/netigen/diaryunicorn/splash/SplashActivity.smali
Injecting loadLibrary call at line: 22
Attempting to fix the constructors .locals count
Current locals value is 0, updating to 1:
Writing patched smali back to: /tmp/tmpknaa5qlw.apktemp/smali/pl/netigen/diaryunicorn/splash/SplashActivity.smali
Copying Frida gadget to libs path...
Adding a gadget configuration file...
Copying over a custom script to use with the gadget config.
Rebuilding the APK with the frida-gadget loaded...
Built new APK with injected loadLibrary and frida-gadget
Performing zipalign
Zipalign completed
Signing new APK.
Signed the new APK
Copying final apk from /tmp/tmpknaa5qlw.apktemp.aligned.objection.apk to pl.netigen.kittycorn.objection.apk in current directory...
Cleaning up temp files...

Finally install the generated apk *note: the generated one ends with .objection.apk*

╰» adb install pl.netigen.kittycorn.objection.apk 
Performing Push Install
pl.netigen.kittycorn.objection.apk: 1 file pu...skipped. 15.1 MB/s (72033951 bytes in 4.554s)
        pkg: /data/local/tmp/pl.netigen.kittycorn.objection.apk
Success

Demo

The logcat on the left shows the actual pin code stored on the device, this is from code the developer has left in the app. The android VM on the right shows access being granted no matter what pin is entered.

I hope this has helped someone, and possibly you have learned a something from this quick blog.

Sharing is caring!

Leave a Reply