Master Frida: Hook Android Apps to Reveal Encryption and Debugging Secrets

This guide demonstrates how to use Frida for Android reverse engineering, covering essential commands, stack tracing, and practical hook scripts for common methods such as HashMap.put, Base64.encodeToString, and UI event listeners, enabling developers to locate and analyze encryption logic within apps.

Python Crawling & Data Mining
Python Crawling & Data Mining
Python Crawling & Data Mining
Master Frida: Hook Android Apps to Reveal Encryption and Debugging Secrets

Hello, I am "Code Farmer Saturday Eight". This tutorial is for learning and discussion only; any illegal use of the techniques is prohibited.

Preface

When an app encrypts strings, variable names become obfuscated, making the code hard to read. Even system‑level functions like Toast cannot be obfuscated, so by tracing clues you can eventually find a cracking point.

Common Frida Commands

frida
-U  Connect USB device
    -F  Attach to the frontmost app
    -l  Inject JS script
-o  Output to file
-f  Restart app
--no-pause  Execute immediately without pause

Printing Stack Traces

The essence of printing a stack trace is throwing an exception; the result is read from bottom to top.

Code

function printStacks() {
    console.log(
        Java.use("android.util.Log")
            .getStackTraceString(
                Java.use("java.lang.Throwable").$new()
            )
    );
}

Common Hook Snippets

Hook HashMap.put

var hashMap = Java.use("java.util.HashMap");
hashMap.put.implementation = function(a, b) {
    // a == "username" or a.equals("username") usually works
    if (a == "username") {
        console.log("hashMap.put: ", a, b);
        printStacks();
    }
    return this.put(a, b);
};

Hook ArrayList.add

var arrayList = Java.use("java.util.ArrayList");
arrayList.add.overload('java.lang.Object').implementation = function(a) {
    if (a == "username=18903916120") {
        console.log("arrayList.add: ", a);
        printStacks();
    }
    return this.add(a);
};
arrayList.add.overload('int', 'java.lang.Object').implementation = function(a, b) {
    console.log("arrayList.add: ", a, b);
    return this.add(a, b);
};

Hook TextUtils.isEmpty

var textUtils = Java.use("android.text.TextUtils");
textUtils.isEmpty.implementation = function(a) {
    if (a == "TURJNk1EQTZNREE2TURBNk1EQTZNREE9") {
        console.log("textUtils.isEmpty: ", a);
        printStacks();
    }
    return this.isEmpty(a);
};

Hook String.trim

var str = Java.use("java.lang.String");
str.trim.implementation = function() {
    console.log("str.trim: ", this);
    printStacks();
    return this.trim();
};

Hook Log.w

var log = Java.use("android.util.Log");
log.w.overload('java.lang.String', 'java.lang.String').implementation = function(tag, message) {
    console.log("log.w: ", tag, message);
    printStacks();
    return this.w(tag, message);
};

Hook EditText.getText

var editText = Java.use("android.widget.EditText");
editText.getText.overload().implementation = function() {
    var result = this.getText();
    result = Java.cast(result, Java.use("java.lang.CharSequence"));
    console.log("editText.getText: ", result.toString());
    printStacks();
    return result;
};

Hook Collections.sort

var collections = Java.use("java.util.Collections");
collections.sort.overload('java.util.List').implementation = function(a) {
    var result = Java.cast(a, Java.use("java.util.ArrayList"));
    console.log("collections.sort List: ", result.toString());
    printStacks();
    return this.sort(a);
};
collections.sort.overload('java.util.List', 'java.util.Comparator').implementation = function(a, b) {
    var result = Java.cast(a, Java.use("java.util.ArrayList"));
    console.log("collections.sort List Comparator: ", result.toString());
    printStacks();
    return this.sort(a, b);
};

Hook JSONObject.put & getString

var jSONObject = Java.use("org.json.JSONObject");
jSONObject.put.overload('java.lang.String', 'java.lang.Object').implementation = function(a, b) {
    console.log("jSONObject.put: ", a, b);
    printStacks();
    return this.put(a, b);
};
jSONObject.getString.implementation = function(a) {
    console.log("jSONObject.getString: ", a);
    var result = this.getString(a);
    console.log("jSONObject.getString result: ", result);
    printStacks();
    return result;
};

Hook Toast.show

var toast = Java.use("android.widget.Toast");
toast.show.implementation = function() {
    console.log("toast.show: ");
    printStacks();
    return this.show();
};

Hook Base64.encodeToString

var base64 = Java.use("android.util.Base64");
base64.encodeToString.overload('[B', 'int').implementation = function(a, b) {
    console.log("base64.encodeToString: ", JSON.stringify(a));
    var result = this.encodeToString(a, b);
    console.log("base64.encodeToString result: ", result);
    printStacks();
    return result;
};

Hook String.getBytes

var str = Java.use("java.lang.String");
str.getBytes.overload().implementation = function() {
    var result = this.getBytes();
    var newStr = str.$new(result);
    console.log("str.getBytes result: ", newStr);
    printStacks();
    return result;
};
str.getBytes.overload('java.lang.String').implementation = function(a) {
    var result = this.getBytes(a);
    var newStr = str.$new(result, a);
    console.log("str.getBytes result: ", newStr);
    printStacks();
    return result;
};

Finding View IDs

Use the Android SDK tool uiautomatorviewer.bat (located in <SDK directory>\tools\bin) to inspect UI components and obtain IDs such as btn_login.

Hooking the Login Button

var btn_login_id = Java.use("com.dodonew.online.R$id").btn_login.value;
console.log("btn_login_id:", btn_login_id);
var view = Java.use("android.view.View");
view.setOnClickListener.implementation = function(a) {
    if (this.getId() == btn_login_id) {
        console.log("view.id: " + this.getId());
        console.log("view.setOnClickListener is called");
        printStacks();
    }
    return this.setOnClickListener(a);
};

Simple Usage Example

In the "DuduCow" app, the final encryption uses DES and the result is displayed as Base64. Hooking the Base64 method reveals the encrypted payload.

Hook Result

Conclusion

The snippets above are common hooks used during Android reverse engineering. Depending on the target app, you may need additional hooks, but the presented examples form a solid foundation for analyzing encryption, data handling, and UI interactions.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

AndroidSecurityreverse engineeringFridaHook
Python Crawling & Data Mining
Written by

Python Crawling & Data Mining

Life's short, I code in Python. This channel shares Python web crawling, data mining, analysis, processing, visualization, automated testing, DevOps, big data, AI, cloud computing, machine learning tools, resources, news, technical articles, tutorial videos and learning materials. Join us!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.