← Back to writing
Mobile / Android

Frida Cheatsheet

Aug 02, 2024
4 min read
lawbyte

Frida is the most powerful tool in the Android pentesting toolkit. This cheatsheet covers everything from basic method hooking to complex native code interception, organized for quick reference during engagements.

Setup

# Install Python client
pip install frida-tools

# Download frida-server for device architecture
# https://github.com/frida/frida/releases
# Match version exactly between client and server!

# Push and start server
adb push frida-server /data/local/tmp/frida-server
adb shell "chmod +x /data/local/tmp/frida-server"
adb shell "/data/local/tmp/frida-server &"

# Verify connection
frida-ps -U # list processes
frida-ps -Uai # list all installed apps

Attaching to a Process

# By package name (attach to running process)
frida -U -n com.target.app -l script.js

# Spawn app (start fresh, script runs before any Java code)
frida -U -f com.target.app -l script.js --no-pause

# By PID
frida -U -p 1234 -l script.js

# Interactive REPL (no script)
frida -U -n com.target.app

# Remote device
frida -H 192.168.1.100:27042 -n com.target.app -l script.js

Script Boilerplate

// Wrap everything in Java.perform — waits for JVM to be ready
Java.perform(function() {
console.log('[*] Script loaded');

// Your hooks here
});

Basic Java Method Hooking

Java.perform(function() {
// Get a class reference
var TargetClass = Java.use('com.target.app.LoginActivity');

// Hook a method
TargetClass.checkPassword.implementation = function(password) {
console.log('[*] checkPassword called with: ' + password);

// Call original
var result = this.checkPassword(password);
console.log('[*] Original returned: ' + result);

// Return modified value
return true; // always return true
};
});

Overloaded Methods

Java.perform(function() {
var Crypto = Java.use('com.target.app.Crypto');

// List all overloads
console.log(Crypto.encrypt.overloads);

// Hook specific overload by argument types
Crypto.encrypt.overload('java.lang.String').implementation = function(data) {
console.log('[*] encrypt(String) called: ' + data);
return this.encrypt(data);
};

Crypto.encrypt.overload('java.lang.String', 'java.lang.String').implementation = function(data, key) {
console.log('[*] encrypt(String, String): data=' + data + ' key=' + key);
return this.encrypt(data, key);
};
});

Reading and Modifying Fields

Java.perform(function() {
var Config = Java.use('com.target.app.Config');

// Static field
console.log('API URL: ' + Config.API_BASE_URL.value);
Config.API_BASE_URL.value = 'http://10.0.2.2:8080';

// Instance field — hook constructor to get instance
var Activity = Java.use('com.target.app.MainActivity');
Activity.$init.implementation = function() {
this.$init();
// Access instance field
console.log('token: ' + this._authToken.value);
this._authToken.value = 'forged_token';
};
});

Creating New Instances

Java.perform(function() {
// Instantiate a class
var SecretManager = Java.use('com.target.app.SecretManager');
var instance = SecretManager.$new();
var secret = instance.getSecret();
console.log('Secret: ' + secret);

// With constructor arguments
var key = Java.use('javax.crypto.spec.SecretKeySpec').$new(
Java.array('byte', [0x41, 0x42, 0x43, 0x44, 0x41, 0x42, 0x43, 0x44]),
'AES'
);
});

Enumerating Loaded Classes and Methods

Java.perform(function() {
// Find classes matching a pattern
Java.enumerateLoadedClasses({
onMatch: function(name) {
if (name.includes('target.app') && name.includes('Auth')) {
console.log('[*] Found: ' + name);
}
},
onComplete: function() {}
});

// List methods of a class
var clazz = Java.use('com.target.app.AuthManager');
var methods = clazz.class.getDeclaredMethods();
methods.forEach(function(m) {
console.log(m.getName() + ' → ' + m.getReturnType());
});
});

Hooking All Methods of a Class

Java.perform(function() {
var ClassName = Java.use('com.target.app.SomeClass');
var methods = ClassName.class.getDeclaredMethods();

methods.forEach(function(method) {
var name = method.getName();
try {
ClassName[name].overloads.forEach(function(overload) {
overload.implementation = function() {
var args = Array.prototype.slice.call(arguments);
console.log('[*] ' + name + '(' + args.join(', ') + ')');
return overload.apply(this, arguments);
};
});
} catch(e) {}
});
});

Native Function Hooking

// Hook by export name
var malloc = Module.findExportByName("libc.so", "malloc");
Interceptor.attach(malloc, {
onEnter: function(args) {
var size = args[0].toInt32();
// console.log('malloc(' + size + ')');
},
onLeave: function(retval) {
// retval is the pointer returned
}
});

// Hook by address
var addr = Module.findBaseAddress("libtarget.so").add(0x1234);
Interceptor.attach(addr, {
onEnter: function(args) {
console.log('Hit function at 0x1234');
console.log('arg0: ' + args[0].readUtf8String());
}
});

// Replace function entirely
Interceptor.replace(addr, new NativeCallback(function(a, b) {
return 1;
}, 'int', ['int', 'int']));

Memory Operations

// Read string from pointer
var ptr = ptr("0xdeadbeef");
console.log(ptr.readUtf8String());
console.log(ptr.readByteArray(16)); // read 16 bytes

// Write to memory
Memory.writeByteArray(ptr, [0x41, 0x42, 0x43]);

// Scan memory for pattern
Memory.scan(Module.findBaseAddress("libtarget.so"), 0x100000,
"48 65 6c 6c 6f", {
onMatch: function(address, size) {
console.log('Found at: ' + address);
},
onComplete: function() {}
});

// Allocate memory
var buf = Memory.alloc(128);
Memory.writeUtf8String(buf, "hello world");

Root Detection Bypass

Java.perform(function() {
// RootBeer
try {
var RootBeer = Java.use('com.scottyab.rootbeer.RootBeer');
RootBeer.isRooted.implementation = function() { return false; };
RootBeer.isRootedWithoutBusyBoxCheck.implementation = function() { return false; };
} catch(e) {}

// File existence checks
var File = Java.use('java.io.File');
File.exists.implementation = function() {
var path = this.getAbsolutePath();
var suspiciousPaths = ['/system/app/Superuser.apk', '/sbin/su', '/system/bin/su',
'/system/xbin/su', '/data/local/xbin/su', '/data/local/bin/su'];
if (suspiciousPaths.indexOf(path) !== -1) {
console.log('[*] Blocked file check: ' + path);
return false;
}
return this.exists();
};

// Runtime.exec() checking for su
var Runtime = Java.use('java.lang.Runtime');
Runtime.exec.overload('java.lang.String').implementation = function(cmd) {
if (cmd.indexOf('su') !== -1 || cmd.indexOf('which') !== -1) {
throw Java.use('java.io.IOException').$new('Command not found');
}
return this.exec(cmd);
};
});

Crypto Tracing

Intercept all AES encryption/decryption:

Java.perform(function() {
var Cipher = Java.use('javax.crypto.Cipher');

Cipher.doFinal.overload('[B').implementation = function(input) {
console.log('[*] Cipher.doFinal input: ' + byteArrayToHex(input));
var result = this.doFinal(input);
console.log('[*] Cipher.doFinal output: ' + byteArrayToHex(result));
return result;
};

Cipher.init.overload('int', 'java.security.Key').implementation = function(opmode, key) {
var keyBytes = key.getEncoded();
console.log('[*] Cipher.init key: ' + byteArrayToHex(keyBytes));
this.init(opmode, key);
};
});

function byteArrayToHex(arr) {
return Array.from(arr).map(b => ('0' + (b & 0xff).toString(16)).slice(-2)).join('');
}

Useful One-Liners

# Dump all HTTP traffic (hook OkHttp)
frida -U -f com.target.app --codeshare pcipolloni/universal-android-ssl-pinning-bypass-with-frida --no-pause

# List all activities
frida -U -n com.target.app -e "Java.perform(function(){Java.use('android.app.ActivityThread').currentApplication().getPackageManager().getPackageInfo('com.target.app',8).activities.forEach(function(a){send(a.name);});})"

# Dump SharedPreferences
frida -U -n com.target.app -e "Java.perform(function(){var ctx=Java.use('android.app.ActivityThread').currentApplication();var sp=ctx.getSharedPreferences('user_prefs',0);var keys=sp.getAll().keySet().toArray();keys.forEach(function(k){console.log(k+' = '+sp.getString(k,''));});});"

# Call static method directly
frida -U -n com.target.app -e "Java.perform(function(){console.log(Java.use('com.target.app.Util').getSecret());});"

Discussion

Leave a comment · All fields required · No spam

No comments yet. Be the first.