Discussion Embedding a GUI inside a Frida script

Mesidex

Platinian
Original poster
Apr 12, 2023
23
9
3
Ankharctica
Hello,

I was wondering if anyone has been successful in embedding any kind of GUI (e.g. a WebView) inside a Frida script that can directly change the values of Frida-hooked functions. I'm currently trying to come up with solutions as such a feat would tremendously reduce the time needed on the modders end and allow for more streamlined UI customization as opposed to what other solutions (like LGL Mod Menu) offer.

Patching would ideally be done via objection as its API allows for efficient patching without having to recompile APKs multiple times (unless the overlay permission has to be added in the manifest, which could be done during the compilation process of objection) -
I have also filed a request of a feature (that is very easily achievable) on their repository to add a --skip-signing argument to skip any signing steps done by objection.
 

Vector4

Platinian
Jun 6, 2022
13
14
3
23
Ireland
It is possible, but a lot of boilerplate needs to be set up first just to create UI elements.
I wrote up an example that will create a button that when clicked, prints out a toast.
Note that this button uses the app's default style, so if you want a custom style, you'll have to do things like call setBackground.
If you want multiple views, it would be best to create a LinearLayout or some other layout and add views to that, then add the layout to the root view.
You should be able to apply this for a WebView, though.

JavaScript:
// We need to get an instance of the main activity.
var activity;

// If you know the activity class, you can replace android.app.Activity with it's class name
// (e.g. for MIUI calculator, you could use com.miui.calculator.cal.CalculatorActivity)
// Java.choose just iterates all objects until it finds one with a certain class (?)
Java.choose("android.app.Activity", {
    onMatch: (obj) => activity = obj,
    onComplete: () => {}
});

// Runs a function on the main thread, a.k.a. the UI thread.
// Any extra arguments passed will be passed to `func`.
function RunOnMainThread(func) {
    var args = Array.prototype.slice.call(arguments, 1);

    // We create our own runnable, then pass it to runOnUiThread.
    // source: https://stackoverflow.com/questions/65790594
    var runnable = Java.registerClass({
        name: "com.whatever.UIRunnable",
        implements: [ Java.use("java.lang.Runnable") ],
        methods: {
            run() {
                func.apply(null, args);
            }
        }
    }).$new();

    activity.runOnUiThread(runnable);
}

// We get the root view, and cast it to a ViewGroup. (https://developer.android.com/reference/android/view/ViewGroup)
// We can then call addView to add our own view.
var rootView = Java.cast(activity.getWindow().getDecorView().getRootView(), Java.use("android.view.ViewGroup"));

// We create a basic button (https://developer.android.com/reference/android/widget/Button), that when clicked, prints out a toast.
var Button = Java.use("android.widget.Button");
var btn = Button.$new(activity);

btn.setText(Java.use("java.lang.String").$new("Click me!"));
btn.setMinWidth(500);
btn.setMinHeight(250);
btn.setX(200.);
btn.setY(200.);
btn.setOnClickListener(Java.registerClass({
    name: "com.whatever.OnClickListener",
    implements: [ Java.use("android.view.View$OnClickListener") ],
    methods: {
        onClick(view) {
            // Already in main thread, so we don't need to do anything.
            Java.use("android.widget.Toast").makeText(activity, Java.use("java.lang.String").$new("You clicked!"), 5).show();
        }
    }
}).$new());

RunOnMainThread(() => {
    // We also need a LayoutParams (https://developer.android.com/reference/android/view/ViewGroup.LayoutParams) that describe how the view is layed out.
    rootView.addView(btn, Java.use("android.view.ViewGroup$LayoutParams").$new(500, 250));
});
 
  • Like
Reactions: hprnv and Mesidex

Mesidex

Platinian
Original poster
Apr 12, 2023
23
9
3
Ankharctica
Hello Vector4,

I'm glad to hear that Frida's API allows for this. I actually started implementing something of similar nature after talking to the author of frida-il2cpp-bridge, but your example made me understand the process much clearer as well as give more insight to the necessary API features.

I will also look into how I can implement a WebView. It could, perhaps, be made into a cross-platform utility as Objection can cross-compile the Frida script into both final iOS and Android binaries.

Thank you for your kind contribution and detailed comments, they will be of help to anyone looking for this topic.
 
  • Like
Reactions: Vector4

MAARS YT

Platinian
May 14, 2020
8
3
3
24
France
Hi @Mesidex i have been working on a frida web-view mod-menu, but i am stuck cause of method annotation.
the issue is that,i want to make the web-view JavaScript communicate with frida host, this can be done using web-view interface like shown in the android doc here but there is a catch, if you want a method of your interface class to be available on the web-view you need to to explicitly put the @JavascriptInterface annotation to your method, but i cant find any way to declare annotation from frida register class function.

by the way i have been also working in the same time to implement an ESP Manager to frida, you will find all the source in the packed module

this is what happen when i click my button
Screenshot from 2023-07-15 14-45-21.png
 

Attachments

  • Like
Reactions: Mesidex

Vector4

Platinian
Jun 6, 2022
13
14
3
23
Ireland
Hey @MAARS YT,

Unfortunately from browsing the source code, there seems to be no way to add annotations to methods.
I would suggest opening up an issue in the repository or attempting to implement the code yourself.

Although, it is possible to load .dex files from buffers using InMemoryDexClassLoader.
The simplest way to do this would be to write and compile a small bit of Java code that has a method with the JavascriptInterface annotation on it, then take the .dex file that has your class, convert it to an encoded string, load it in, hook the method's implementation to your own, and add the interface.
 

MAARS YT

Platinian
May 14, 2020
8
3
3
24
France
Well WebView is a dead end, i just started coding the menu using normal ui component, and decided to use LGL style. i might also do a full implementation/copy of imgui but only if someone join me xD, it will be too much work

 

Mesidex

Platinian
Original poster
Apr 12, 2023
23
9
3
Ankharctica
Well WebView is a dead end, i just started coding the menu using normal ui component, and decided to use LGL style. i might also do a full implementation/copy of imgui but only if someone join me xD, it will be too much work

Yeah, I went through with the route of hooking via injection since you'd skip the recompilation step entirely by only requiring the original APK to be installed (better against modded app protection) – I also felt better using QT/Dear ImGUI to handle hooking as well as the UI.

My approach, however, might require some workarounds for non-rooted devices.

There are definitely more benefits to internal mods via injection, but I don't want to make this longer than necessary lol.

Screenshot_20230721_122603_HAWK_Airplane_Space_Games.png
 

MAARS YT

Platinian
May 14, 2020
8
3
3
24
France
That look good, is that on iOS ? And why using imgui for hooking? You could just use
Frida interceptor and imgui only for handling ui. Can I get your dm discord or whatever? I think we could be exchanging some great knowledge. And by the way my approach is meant to be used with Frida on termux. So you will not pull your PC everytime xD.
 

Mesidex

Platinian
Original poster
Apr 12, 2023
23
9
3
Ankharctica
That look good, is that on iOS ? And why using imgui for hooking? You could just use
Frida interceptor and imgui only for handling ui. Can I get your dm discord or whatever? I think we could be exchanging some great knowledge. And by the way my approach is meant to be used with Frida on termux. So you will not pull your PC everytime xD.
Hi,

Haha, it seems that I used some misleading wording – apologies :)

What I mean is that the frontend is built with QT QML or Dear ImGUI, whereas the backend works by hooking the functions (via a hooking lib like And64InlineHook or a custom implementation) of a target process by utilizing BroadcastReceivers and Intents / the concept of IPC.

I'll get back to you later if you want to chat on discord or telegram lol

You might have already visited frida-snippets, but there's a section for BroadcastReceivers if you'd like to check it out. You can also check this out.
 
Sep 7, 2023
2
0
1
UTC MOON
you can just easily merge LGL team theme into it, using a module of npm, t works fine with me, but still facing 1 small issue , but the menu is working .