| name | frida-instrumentation |
| description | Operate Frida — a dynamic instrumentation toolkit for hooking and modifying running processes. Use when performing runtime analysis of desktop or mobile applications, bypassing SSL pinning or root detection, hooking native/Java/Objective-C functions, reversing mobile apps (Android/iOS), or automating instrumentation with Objection. Covers installation, JavaScript API (Interceptor, Module, Memory, NativeFunction), frida-trace, RPC exports, Objection integration, Android/iOS setup with frida-server, and end-to-end mobile app pentesting workflows.
|
| license | LGPL-2.1 |
| metadata | {"author":"redhoundinfosec","version":"1.0","repo":"https://github.com/frida/frida"} |
frida-instrumentation Agent Skill
When to Use This Skill
Use this skill when:
- Bypassing SSL certificate pinning in Android or iOS apps during DAST
- Hooking Java/Kotlin/Objective-C/Swift methods at runtime without modifying APK/IPA
- Tracing native function calls in a running process
- Reversing mobile app encryption, license checks, or anti-tampering mechanisms
- Bypassing root detection, emulator detection, or jailbreak detection
- Automating mobile app pentesting with Objection
- Building dynamic analysis scripts for malware or binary research
What Frida Does
Frida is a cross-platform dynamic instrumentation framework that injects a JavaScript engine
(V8/Duktape) into a target process at runtime. It enables reading/writing memory, hooking
arbitrary functions, intercepting calls across Java, Objective-C, and native code layers,
and exporting RPC interfaces for external control — all without recompilation or source
access. It runs on Windows, macOS, Linux, Android, and iOS, making it the primary tool
for mobile application security testing and runtime analysis.
Installation
frida-tools (host machine)
pip install frida-tools
frida --version
frida-ps --version
pip install -U frida-tools
pip install frida==16.2.1 frida-tools==12.4.3
frida-server (Android device)
adb shell getprop ro.product.cpu.abi
xz -d frida-server-16.2.1-android-arm64.xz
adb push frida-server-16.2.1-android-arm64 /data/local/tmp/frida-server
adb shell chmod +x /data/local/tmp/frida-server
adb shell /data/local/tmp/frida-server &
frida-ps -U
frida-ps -U | grep -i target_app
frida-server (iOS device — jailbroken)
frida-ps -U
frida-ps -H 192.168.1.50:27042
frida-gadget (non-rooted / non-jailbroken)
objection patchapk -s target.apk
Core Concepts
Attach vs Spawn
frida -U -n "com.target.app"
frida -U -p 1234
frida -U -f com.target.app --no-pause
frida -U -f com.target.app
frida -U -f com.target.app -l hook.js --no-pause
Script execution modes
frida -U -n com.target.app
frida -U -n com.target.app -l script.js
frida -U -n com.target.app -e "Java.perform(function(){ console.log('hi'); })"
JavaScript API Reference
Java API (Android)
Java.perform(function() {
var MainActivity = Java.use('com.target.app.MainActivity');
MainActivity.checkPin.implementation = function(pin) {
console.log('[*] checkPin called with: ' + pin);
var result = this.checkPin(pin);
console.log('[*] checkPin result: ' + result);
return result;
};
MainActivity.isRooted.implementation = function() {
console.log('[*] isRooted hooked — returning false');
return false;
};
var String = Java.use('java.lang.String');
String.equals.overload('java.lang.String').implementation = function(other) {
var result = this.equals(other);
if (this.toString().indexOf('password') !== -1) {
console.log('[*] String.equals: ' + this + ' == ' + other + ' → ' + result);
}
return result;
};
Java.enumerateLoadedClasses({
onMatch: function(className) {
if (className.indexOf('target') !== -1) {
console.log('[*] Found class: ' + className);
}
},
onComplete: function() {}
});
var SecretClass = Java.use('com.target.app.SecretClass');
var instance = SecretClass.$new('arg1');
console.log(instance.getSecret());
console.log(MainActivity.SECRET_KEY.value);
MainActivity.checkPin.implementation = function(pin) {
this.mMaxAttempts.value = 9999;
return this.checkPin(pin);
};
});
Interceptor API (Native / C functions)
Interceptor.attach(Module.findExportByName('libc.so', 'strcmp'), {
onEnter: function(args) {
var s1 = args[0].readUtf8String();
var s2 = args[1].readUtf8String();
if (s1 !== null && s2 !== null) {
console.log('[strcmp] "' + s1 + '" vs "' + s2 + '"');
}
this.s2 = s2;
},
onLeave: function(retval) {
console.log('[strcmp] returned: ' + retval);
retval.replace(0);
}
});
var targetAddr = Module.findBaseAddress('libapp.so').add(0x1234);
Interceptor.attach(targetAddr, {
onEnter: function(args) {
console.log('[*] hit target function, arg0 = ' + args[0]);
},
onLeave: function(retval) {
retval.replace(ptr(1));
}
});
Interceptor.replace(targetAddr, new NativeCallback(function(a, b) {
console.log('[*] replaced function called');
return 1;
}, 'int', ['int', 'int']));
Module API
Process.enumerateModules().forEach(function(m) {
console.log(m.name, m.base, m.size);
});
var lib = Process.findModuleByName('libssl.so');
console.log('Base:', lib.base);
Module.enumerateExports('libc.so').forEach(function(exp) {
if (exp.name.indexOf('SSL') !== -1) {
console.log(exp.name, exp.address);
}
});
var base = Module.findBaseAddress('libapp.so');
console.log('libapp.so base:', base);
Module.enumerateSymbols('libapp.so').forEach(function(sym) {
if (sym.name.indexOf('check') !== -1) {
console.log(sym.name, sym.address);
}
});
Memory API
var addr = ptr('0x7f001234');
console.log(addr.readU8());
console.log(addr.readU32());
console.log(addr.readUtf8String());
console.log(addr.readByteArray(16));
addr.writeU8(0x90);
addr.writeByteArray([0x90, 0x90]);
addr.writeUtf8String('patched');
var buf = Memory.alloc(64);
buf.writeUtf8String('injected_string');
Memory.scan(base, 0x1000, '41 42 43 ?? 45', {
onMatch: function(address, size) {
console.log('[*] Pattern at: ' + address);
},
onComplete: function() {}
});
Memory.protect(ptr('0x401000'), 0x1000, 'rwx');
NativeFunction and NativeCallback
var strlen = new NativeFunction(
Module.findExportByName('libc.so', 'strlen'),
'size_t',
['pointer']
);
var len = strlen(Memory.allocUtf8String('hello'));
console.log('length:', len);
var myCallback = new NativeCallback(function(data, len) {
console.log('[*] callback triggered, len =', len);
return 0;
}, 'int', ['pointer', 'int']);
var setCallback = new NativeFunction(
Module.findExportByName('libapp.so', 'register_callback'),
'void',
['pointer']
);
setCallback(myCallback);
ObjC API (iOS)
var className = 'AppDelegate';
var methodName = '- validateLicense:';
if (ObjC.available) {
var klass = ObjC.classes[className];
var method = klass[methodName];
Interceptor.attach(method.implementation, {
onEnter: function(args) {
var licenseKey = ObjC.Object(args[2]).toString();
console.log('[*] validateLicense called: ' + licenseKey);
},
onLeave: function(retval) {
retval.replace(ptr(1));
}
});
klass.$ownMethods.forEach(function(method) {
console.log(method);
});
}
frida-trace — Automatic Hooking
frida-trace -U -n com.target.app -i "Java_*"
frida-trace -U -n com.target.app -i "SSL_*"
frida-trace -U -n com.target.app -i "strcmp"
frida-trace -U -n TargetApp -m "-[AppDelegate *]"
frida-trace -U -n TargetApp -m "*validate*"
frida-trace -U -f com.target.app -i "open*" -m "-[NSURLSession *]" --no-pause
frida-trace -U -n com.target.app -i "SSL_read" -o ./handlers
RPC Exports (Calling Frida from Python)
rpc.exports = {
dumpStrings: function() {
var results = [];
Java.perform(function() {
Java.enumerateLoadedClasses({
onMatch: function(c) { results.push(c); },
onComplete: function() {}
});
});
return results;
},
callDecrypt: function(ciphertext) {
var result = null;
Java.perform(function() {
var Crypto = Java.use('com.target.app.CryptoUtils');
result = Crypto.decrypt(Java.use('java.lang.String').$new(ciphertext));
});
return result ? result.toString() : null;
}
};
import frida, sys
def on_message(message, data):
print('[msg]', message)
device = frida.get_usb_device()
session = device.attach('com.target.app')
with open('script.js', 'r') as f:
script = session.create_script(f.read())
script.on('message', on_message)
script.load()
api = script.exports
classes = api.dump_strings()
print(f'Found {len(classes)} classes')
plaintext = api.call_decrypt('U2FsdGVkX1+...')
print('Decrypted:', plaintext)
Common Workflows
SSL Pinning Bypass (Android)
Java.perform(function() {
var TrustManagerImpl = Java.use('com.android.org.conscrypt.TrustManagerImpl');
TrustManagerImpl.verifyChain.implementation = function(untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) {
console.log('[*] TrustManagerImpl.verifyChain bypassed for: ' + host);
return untrustedChain;
};
try {
var CertificatePinner = Java.use('okhttp3.CertificatePinner');
CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function(hostname, certs) {
console.log('[*] OkHttp3 CertificatePinner.check bypassed for: ' + hostname);
};
} catch(e) { console.log('[!] OkHttp3 not found: ' + e); }
var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
var TrustAllManager = Java.registerClass({
name: 'com.frida.TrustAll',
implements: [X509TrustManager],
methods: {
checkClientTrusted: function(chain, authType) {},
checkServerTrusted: function(chain, authType) {},
getAcceptedIssuers: function() { return []; }
}
});
var SSLContext = Java.use('javax.net.ssl.SSLContext');
var ctx = SSLContext.getInstance('TLS');
ctx.init(null, [TrustAllManager.$new()], null);
SSLContext.getDefault.implementation = function() { return ctx; };
});
objection --gadget com.target.app explore
objection> android sslpinning disable
Root Detection Bypass
Java.perform(function() {
var classes = [
'com.scottyab.rootbeer.RootBeer',
'com.topjohnwu.superuser.Shell',
];
classes.forEach(function(cls) {
try {
var c = Java.use(cls);
if (c.isRooted) {
c.isRooted.implementation = function() { return false; };
console.log('[*] Hooked ' + cls + '.isRooted');
}
} catch(e) {}
});
var File = Java.use('java.io.File');
File.exists.implementation = function() {
var path = this.getAbsolutePath();
var rootPaths = ['/su', '/system/bin/su', '/sbin/su', '/system/xbin/su'];
if (rootPaths.indexOf(path) !== -1) {
console.log('[*] File.exists blocked for: ' + path);
return false;
}
return this.exists();
};
var Runtime = Java.use('java.lang.Runtime');
Runtime.exec.overload('[Ljava.lang.String;').implementation = function(cmd) {
var command = cmd.join(' ');
if (command.indexOf('su') !== -1 || command.indexOf('which') !== -1) {
console.log('[*] Blocked exec: ' + command);
throw Java.use('java.io.IOException').$new('File not found');
}
return this.exec(cmd);
};
});
Crypto Key Extraction
Java.perform(function() {
var SecretKeySpec = Java.use('javax.crypto.SecretKeySpec');
SecretKeySpec.$init.overload('[B', 'java.lang.String').implementation = function(keyBytes, algorithm) {
console.log('[*] SecretKeySpec created:');
console.log(' Algorithm: ' + algorithm);
console.log(' Key (hex): ' + bytesToHex(keyBytes));
return this.$init(keyBytes, algorithm);
};
var Cipher = Java.use('javax.crypto.Cipher');
Cipher.doFinal.overload('[B').implementation = function(input) {
var result = this.doFinal(input);
console.log('[Cipher.doFinal]');
console.log(' Input: ' + bytesToHex(input));
console.log(' Output: ' + bytesToHex(result));
return result;
};
});
function bytesToHex(bytes) {
var hex = '';
for (var i = 0; i < bytes.length; i++) {
hex += ('0' + (bytes[i] & 0xFF).toString(16)).slice(-2);
}
return hex;
}
iOS Jailbreak Detection Bypass
if (ObjC.available) {
Interceptor.attach(Module.findExportByName('libc.dylib', 'access'), {
onEnter: function(args) {
var path = args[0].readUtf8String();
var jbPaths = ['/Applications/Cydia.app', '/bin/bash', '/usr/sbin/sshd',
'/etc/apt', '/private/var/lib/apt'];
if (jbPaths.some(p => path && path.includes(p))) {
console.log('[*] access() blocked for: ' + path);
args[0] = Memory.allocUtf8String('/nonexistent');
}
}
});
Interceptor.attach(Module.findExportByName('libSystem.B.dylib', 'stat'), {
onEnter: function(args) {
var path = args[0].readUtf8String();
if (path && path.includes('Cydia')) {
args[0] = Memory.allocUtf8String('/nonexistent');
}
}
});
var NSFileManager = ObjC.classes.NSFileManager;
Interceptor.attach(NSFileManager['- fileExistsAtPath:'].implementation, {
onEnter: function(args) {
var path = ObjC.Object(args[2]).toString();
if (path.includes('Cydia') || path.includes('substrate')) {
console.log('[*] fileExistsAtPath blocked: ' + path);
this.block = true;
}
},
onLeave: function(retval) {
if (this.block) retval.replace(ptr(0));
}
});
}
Objection Framework Integration
Objection is a runtime exploration toolkit built on Frida that provides common pentest
operations as simple commands without writing scripts.
pip install objection
objection --gadget com.target.app explore
objection --gadget com.target.app --startup-command 'android sslpinning disable' explore
android sslpinning disable
android root disable
android keystore list
android keystore dump
android intent launch_activity <class>
android hooking list classes
android hooking list class_methods <cls>
android hooking watch class <cls>
android hooking watch method <cls>.<method> --dump-args --dump-return
android hooking search classes <term>
android heap instances of <class>
android heap evaluate <cls> this.<method>()
ios sslpinning disable
ios jailbreak disable
ios keychain dump
ios plist cat <path>
ios hooking list classes
ios hooking watch method "+[ClassName method:]" --dump-args
jobs list
jobs kill <id>
memory dump all <outfile>
memory search "<hex pattern>"
Troubleshooting
frida-server not found / connection refused
adb shell ps | grep frida-server
adb shell pkill frida-server
adb shell /data/local/tmp/frida-server &
frida --version
adb shell /data/local/tmp/frida-server --version
Unable to find application with identifier 'com.target.app'
frida-ps -Ua
frida -U -f com.target.app --no-pause -l hook.js
Script not responding / Java.perform callback never fires
setImmediate(function() {
Java.perform(function() {
});
});
ClassNotFoundException for target class
Java.enumerateClassLoaders({
onMatch: function(loader) {
try {
var cls = loader.loadClass('com.target.app.HiddenClass');
Java.use('com.target.app.HiddenClass');
} catch(e) {}
},
onComplete: function() {}
});
Frida detected / anti-Frida bypasses
adb shell cp /data/local/tmp/frida-server /data/local/tmp/svchost
adb shell /data/local/tmp/svchost &
EPERM when attaching to system process
adb shell su -c '/data/local/tmp/frida-server &'
Built by Red Hound InfoSec — On-demand offensive security expertise for SMBs.
20+ years of Fortune 500 experience. Penetration testing, attack surface analysis, and security consulting.
redhound.us | GitHub | Book a consultation