← Back to list

Hooking Functions by Frida Scripting

Before we dive into the challenges, it’s important to understand the underlying concepts.

Yousseff · 2025-03-05 03:50 · 65 claps · 8.8 min read
#android-pentesting #cybersecurity #hooking #javascript #native-library
Open on Medium ↗
Wiki topics: 🌐 · Web Development 🔒 · Cybersecurity 📚 · Books & Reading

Hooking Functions by Frida Scripting

Before we dive into the challenges, it’s important to understand the underlying concepts.

How Do Classes Load in Android?

📌 Non-static methods:

  • Require an instance of the class to be called.
  • The class gets loaded into memory only when an object is created (Lazy Loading).
  • These require an instance of the class to call the method. Therefore, the app needs to start first in order to create the instance before we can inject the script.

📌 Static methods:

  • Belong to the class itself, not an instance
  • These do not require an instance, and can be accessed directly through the class itself. As a result, we can inject the script at any time after the class is loaded into memory (even if the app is already running).

📊 Frida Hooking & Memory Behavior

📝 Frida 0x1 — Static Function Hooking

🎯 Challenge Objective

The application verifies user input using a function called check(i, i2). This function compares a random number (i) generated by get_random() with the user-provided input (i2). If the condition (i * 2) + 4 == i2 is met, it reveals a flag.

Our Goal:

  1. Analyze the app’s logic using JADX.

  2. Use Frida to bypass the check and retrieve the flag.

🔍 Analyzing the Code with JADX

By decompiling the APK with JADX, we find the following logic in onCreate():

Here:

  1. i2 is entered by the user.
  2. i is a random number generated by:

The check(i, i2) function verifies the condition:

🔎 Breaking It Down

For check(i, i2) to return true, the user must enter i2 with value equals

(i * 2) + 4, Since i is random, the user cannot predict the correct i2

🚀 Exploiting the Application Using Frida

Method 1: Directly Calling check() with the Correct Values

Instead of manually guessing i2, we can use Frida to directly execute check() with valid values:

Method 2: Hooking check() to Always Pass

To avoid worrying about the random i, we can hook check() and modify i2 dynamically:

Method 3: Hook get_random() to Control i

Instead of a random number, we override get_random() to always return4:

✅ Final Execution

  1. Run Frida with the script:
frida -U -f com.ad2001.frida0x1 -l hook.js 
  • Open the app and enter 12 in the input field.
  • The flag is revealed in the TextView.

🎯 Frida 0x4 — Hooking Non-Static Methods & Memory Loading

🛠 Challenge Overview

In this challenge, we’re analyzing the Check class inside the com.ad2001.frida0x4 package. It contains a method:

Our goal is to retrieve the hidden flag inside the get_flag() method using Frida.

🔎 Step 1: Identifying Static vs. Non-Static Methods

  • The method get_flag(int a) is non-static.
  • This means that we cannot call it directly from the class; instead, we must create an instance first before calling it.

🚀 Key Difference from Previous Challenges:

  • If get_flag() were static, we could call it like this:
Java.perform(function() {
    let ref = Java.use("com.ad2001.frida0x4.Check");
    console.log(ref.get_flag(1337));
});

BUT, since it is a non-static method, we must create an instance first.

💻 Step 2: Writing the Frida Script

Since get_flag() is a non-static method, we must create an instance before calling it:

🧠 Why Do We Create an Instance?

  • Non-static methods belong to an instance of a class, not the class itself.
  • Dalvik/ART Lazy Loading: Classes are not loaded into memory until needed, so creating an instance ensures it’s available.
  • Unlike static methods, which are accessible via ClassName.methodName(), non-static methods require an object to be invoked.

Frida0x5 — Non Static Function Hooking in MainActivity

🔍 Overview

We need to extract a flag from an Android app using Frida. The flag is decrypted in flag(int code), but we can't create a MainActivity instance manually due to Android's lifecycle. Instead, we hook a running instance.

📌 Step 1: Reverse Engineering

Using JADX, we find:

Decryption in flag(int code), triggered if code == 1337.

AES/CBC/PKCS5Padding encryption with:

  • Key: "WILLIWOMNKESAWEL"
  • IV: new byte[16] (all zeroes).
  • Encrypted Data: "2Y2YINP9PtJCS/7oq189VzFynmpG8swQDmH4IC9wKAY=".

When working with Frida, a common approach is to use Java.use("com.ad2001.frida0x5.MainActivity") to create an instance. However, this doesn't work because:

there is non-static method in the MainActivity Class, so we need to find instance for MainActivityClass

Why We Can’t Create an Instance of MainActivity?

1️⃣ Android Manages Activity Instances → Android handles MainActivity lifecycle, so creating a new instance (new MainActivity()) wouldn't link it to the system correctly.

2️⃣ Needs a Valid ContextMainActivity relies on system resources (UI, services). A manually created instance won't have a proper Android context, causing failures.

Solution: Find an Existing Instance Using Java.choose()

Frida0x7 - Hooking Non-Static Functions in MainActivity with External Class Parameters

This challenge introduces an extra layer of complexity by requiring an instance of the Checker class with specific values (A.num1 > 512 && 512 < A.num2) addition to MainActivity Instance, before the flag() method decrypts the flag.

🎯 Challenge Goal

The challenge involves bypassing the conditions in an Android app that decrypts a flag using AES encryption, but only if specific conditions are met. Our goal is to retrieve the flag by bypassing these conditions using Frida.

🔍 Solution Using Frida

  • We use Java.choose() to find the running instance of MainActivity.
  • Then, we create an instance of Checker, set the required values, and pass it to flag() because
  • Once called, flag() decrypts the flag using AES.

🛠 Why Do We Need to Create an Instance of Checker to Call function: flag() ?

he method flag(Checker A) in MainActivity requires an instance of Checker as a parameter. If we don’t pass this instance correctly, the function cannot execute properly.

We Can’t Use the MainActivity Instance Instead

  • MainActivity and Checker are completely different classes.
  • The instance we find using Java.choose("com.ad2001.frida0x7.MainActivity") is for MainActivity only.
  • Checker must be created separately because it’s not automatically instantiated inside MainActivity.

🔍 Step 2: Finding MainActivity Instance

Since we cannot manually instantiate MainActivity, we need to use Frida to search for a running instance. We do this using Java.choose().

🛠 Step 3: Creating an Instance of Checker

To call flag(Checker A), we must create an instance of the Checker class and set the required values before passing it to the method.

🏴 Step 4: Writing the Frida Script

The following Frida script finds a running instance of MainActivity, creates a Checker instance, assigns the required values, and calls the flag() function.

🔑 Key Findings

  • The flag() method decrypts a Base64-encoded AES string only if: A.num1 > 512 && 512 < A.num2
  • Meaning num1 and num2 must both be greater than 512., Checker is a class that takes two numbers as input.

Method 1: Create a New Checker Instance and Inject It

🔹 Explanation:

  • Java.choose() finds an active MainActivity instance.
  • We pass parameters to newChecker(1024, 1024) Checker Class Constructor
  • The flag function is called on the instance of MainActivity, and the new Checker instance (newChecker) is passed as an argument.

Method 2: Override the Checker Constructor

By relying on overriding the constructor in the Checker class, we will not need to find the MainActivity instance.

This is because the constructor is in the Checker class, not the MainActivity class, Therefore, we can directly modify how Checker instances are created, without having to interact with MainActivity at all.

🔹 Explanation:

  • This modifies the constructor to always use 1024, 1024.
  • Every Checker instance created in the app will pass the check.

🛠 Frida0x8 — Hooking Native Functions in Shared Libraries

🎯 Challenge Goal

The challenge involves an Android application that verifies user input using a native function cmpstr(). Our goal is to bypass this check and obtain the correct input (flag) using Frida.

1️⃣ cmpstr() — Native Function:

This method is declared as native, meaning it's implemented in a native C/C++ library (frida0x8.so).

  • It returns an integer (1 if correct, otherwise 0).
  • We need to bypass this function to always return 1 or extract the correct input (flag).

App Behavior: The app takes user input (ip), It passes this input to cmpstr(ip).

  • If cmpstr() returns 1, it displays: YEY YOU GOT THE FLAG <input>, Otherwise, it shows "TRY AGAIN".

Our goal is to either:

  • Hook cmpstr() to always return 1 (indicating the input is always correct).
  • Extract the correct flag by inspecting the logic of cmpstr().

Method 1: Analyzing the Library in Ghidra

Now that we have libfrida0x8.so, we use **Ghidra**(a reverse engineering tool) to inspect its code.

  1. Open Ghidraand Import the .so File
  2. Look for Java_com_ad2001_frida0x8_MainActivity_cmpstr
  3. Check the Logic
  • If it compares the input to a hardcoded value, we can extract the correct answer.
  • If the flag is encoded, we need to debug it.

Breakdown:

  • param_3 is a Java string that’s passed into the native C/C++ function.
  • The function converts param_3 (the Java string) to a C-style string using _JNIEnv::GetStringUTFChars().
  • The function compares the user’s input to a shifted version of the string "GSJEB|OBUJWFMBOE~"It shifts each character by -1 → FRIDA_NATIVE_LAND
  • you can exploit it and put FRIDA_NATIVE_LAND it’s the correct password

Note: you can know function name from Ghidra

Also can use Frida Modules instead Ghidrato know function name, address

🚨 Disclaimer: Do not hardcode function addresses in Frida scripts. Due to ASLR (Address Space Layout Randomization), function addresses change every time the app runs. Instead, use Module.getExportByName()

Hooking Script

Why Java.perform Doesn't Work in This Case?

Java.perform is used to hook Java methods only. It works within the Java runtime and interacts with Java objects. However, our target function cmpstr is inside a native library (.so file), which Java treats as a black box.

From Java’s runtime environment

  • The cmpstr function takes only one string (user input).
  • However, inside the .so file, cmpstr also uses another hidden string that Java doesn’t see.
  • Since Java.perform hooks only Java APIs, it won’t capture the hidden string—only the user input.

Why is this a problem? If you try to hook cmpstr using Java.perform, all you can print is your own input—which is useless since you already know it. The real logic is hidden inside the native code (.so file).

How to Bypass This Limitation?

Use Frida’s Interceptor.attach → This allows you to hook native functions inside the .so file instead of just Java.

Method 2: Java Hook (Bypassing cmpstr)

Instead of guessing the correct input, we can modify how cmpstr works using Frida, a powerful Android dynamic analysis tool.

🔴 Easy but Weak Method: Java Hook (Surface-Level Bypass)

This forces cmpstr to always return 1, bypassing the validation.

Weakness: This does not help in real-world challenges where additional security checks exist.

Feel Free to Connect my Linkedin

References

Frida-Labs Repository

[embed]GitHub - DERE-ad2001/Frida-Labs: The repo contains a series of challenges for learning Frida for… The repo contains a series of challenges for learning Frida for Android Exploitation. - DERE-ad2001/Frida-Labsgithub.com

Frida CodeShare is an online platform for sharing Frida scripts and collaborating on security research.

[embed]Frida CodeShare The Frida CodeShare project is comprised of developers from around the world working together with one goal - push…codeshare.frida.re


메타데이터
post_id
e5345cac0c5a
slug
hooking-functions-with-frida-scripting-e5345cac0c5a
url
https://medium.com/@Youseef/hooking-functions-with-frida-scripting-e5345cac0c5a
canonical_url
https://medium.com/@Youseef/hooking-functions-with-frida-scripting-e5345cac0c5a
author_url
https://medium.com/@Youseef
status
ok
fetched_at
2026-07-29 19:10:59