Objection is a runtime mobile exploration toolkit, built on top of Frida, developed and maintained by SensePost. It was created to help security testers assess the security posture of mobile applications without requiring a jailbroken iOS device or a rooted Android device for many of its core functions (though a rooted/jailbroken device unlocks the toolkit’s full capability). Objection is not a jailbreak or root bypass tool itself — it operates within the same sandbox constraints Frida is subject to — but it dramatically simplifies dynamic instrumentation by wrapping dozens of the most common Frida-based testing tasks into short, memorable, human-readable commands.
Instead of hand-writing custom JavaScript for every routine task, a tester can launch an interactive Objection REPL session attached to a target app and simply type commands such as android sslpinning disable or ios jailbreak disable. Objection’s key capabilities include:
- Patching iOS and Android applications to embed a Frida Gadget, enabling instrumentation on non-rooted/non-jailbroken devices.
- Exploring and interacting with the application’s container file system (list, upload, download files).
- Performing memory-related tasks: listing loaded modules, dumping memory ranges, searching memory for patterns.
- Bypassing common SSL/TLS certificate pinning implementations with a single command.
- Bypassing common root/jailbreak detection checks.
- Listing, searching, and hooking (watching) Java classes and methods at runtime to dump arguments, return values, and backtraces.
- Interacting with SQLite databases, keychains (iOS), and shared preferences (Android) found within the app’s sandbox.
- Executing arbitrary shell commands within the context of the Android app (
android shell_exec). - Taking screenshots and manipulating UI-level security flags (e.g.,
FLAG_SECURE).
How to Install
Objection is distributed as a Python package and installed via pip3. It requires Frida (client tools) to already be installed, since Objection depends on the frida Python bindings.
# Ensure pip3 is installed
sudo apt update
sudo apt install python3-pip -y
# Install Objection (this will also pull in the frida Python bindings as a dependency)
pip3 install objection --break-system-packages
# To update an existing installation later
pip3 install --upgrade objection --break-system-packages
Verify installation:
$ objection version
objection: 1.11.0
Prerequisite: frida-server must be running on the target device (see the Frida section, 23.4, for full deployment instructions):
adb push frida-server /data/local/tmp/frida-server
adb shell "chmod 755 /data/local/tmp/frida-server"
adb shell "/data/local/tmp/frida-server &"
Syntax
objection [options] explore
objection --gadget <package_or_bundle_id> explore
objection -n <process_name> explore
objection patchapk -s <path_to_apk>
Once inside the interactive REPL (after explore), the syntax for in-session commands follows this general pattern:
<category> <subcategory> <action> [arguments] [--flags]
For example: android hooking watch class_method com.example.MainActivity.checkLogin --dump-args --dump-return
All Command-Line Options
Top-level objection CLI flags (used before explore):
| Option | Description |
|---|---|
-n, --network <NAME> | Attach to a running process by name (equivalent to Frida’s -n) |
-p, --pid <PID> | Attach to a running process by PID |
-g, --gadget <IDENTIFIER> | Attach to an app running an embedded Frida Gadget (used for non-rooted/patched apps) |
-h, --host <HOST> | Connect to a remote Frida server on HOST |
-P, --port <PORT> | Port for the remote Frida server connection |
-S, --serial <SERIAL> | Target a specific device serial (multiple devices connected) |
-d, --debug | Enable debug-level output for the objection session |
--startup-command <CMD> | Run a command immediately after the REPL starts (before returning control) |
--startup-script <FILE> | Run a Frida JS script immediately after the REPL starts |
objection patchapk options (embedding the Frida Gadget into an APK for non-rooted testing):
| Option | Description |
|---|---|
-s, --source <APK> | Path to the source APK to patch |
-a, --architecture <ARCH> | Target architecture of the Gadget to embed (e.g., arm, arm64, x86, x86_64) |
-n, --network | Enables network communication config patch (cleartext traffic) |
-p, --pause | Pause the app on launch, waiting for a debugger/Frida to attach |
-o, --output <FILE> | Output filename for the patched APK |
Key in-REPL command categories (subset — not an exhaustive list, as Objection has dozens of commands):
| Command | Description |
|---|---|
env | Print environment paths (data directory, cache directory, etc.) where the app is stored |
frida | Print information about the connected Frida version |
file download <remote> [local] | Download a file from the device to the host |
file upload <local> [remote] | Upload a file from the host to the device |
import <script.js> | Import and run a custom Frida JavaScript file |
jobs list | List currently running background hooks/jobs |
jobs kill <id> | Stop a specific background job |
android sslpinning disable | Attempt to bypass common Android SSL pinning implementations |
android root disable | Attempt to disable root detection checks |
android root simulate | Simulate a rooted environment for the app to detect (testing anti-tamper logic) |
android shell_exec <cmd> | Execute a shell command in the context of the app’s process |
android ui screenshot <path> | Take a screenshot of the current app UI |
android ui FLAG_SECURE false | Disable the FLAG_SECURE UI protection to allow screenshots via hardware keys |
android hooking list classes | List all currently loaded Java classes |
android hooking list class_loaders | List all active class loaders (useful for packed/dynamically loaded DEX) |
android hooking search classes <pattern> | Search loaded classes by name pattern |
android hooking list class_methods <class> | List all methods of a specific class |
android hooking watch class <class> | Watch/hook all methods of a class |
android hooking watch class_method <class.method> | Watch/hook a specific method, with optional flags |
android heap search instances <class> | Search the heap for live instances of a class |
android intent launch_activity <activity> | Launch a specific Android activity |
android keystore list | List entries in the Android KeyStore |
ios sslpinning disable | Attempt to bypass common iOS SSL pinning implementations |
ios jailbreak disable | Attempt to disable jailbreak detection checks |
ios keychain dump | Dump the iOS keychain contents |
ios nsuserdefaults get | Dump NSUserDefaults contents |
sqlite connect <db_file> | Connect to and query a SQLite database inside the app’s sandbox |
memory list modules | List loaded native modules and their base addresses |
memory dump all <destination> | Dump the entire process memory to a local file |
memory dump from_base <address> <size> <destination> | Dump a specific memory range starting at a base address |
exit / quit | Exit the Objection REPL |
--dump-args, --dump-backtrace, --dump-return are common flags appended to android hooking watch class_method to control what data is printed for each intercepted call.
Basic Usage (Expected Output in Bash)
Attach Objection to a running app (rooted device, package already running):
$ objection -g com.android.insecurebankv2 explore
_ _ _ _
| | | | | | (_)
___| |__| | ___ ___| |_ _ ___ _ __
/ __| __ |/ _ \/ __| __| |/ _ \| '_ \
\__ \ | | | __/ (__| |_| | (_) | | | |
|___/_| |_|\___|\___|\__|_|\___/|_| |_|
objection: runtime mobile exploration
by: @leonjza from @sensepost
com.android.insecurebankv2 on (google: 13) [usb] #
Run a single command against the app to check environment paths:
com.android.insecurebankv2 on (google: 13) [usb] # env
Name Path
------------------ -----------------------------------------------------
cacheDirectory /data/user/0/com.android.insecurebankv2/cache
codeCacheDirectory /data/user/0/com.android.insecurebankv2/code_cache
externalCacheDirectory /storage/emulated/0/Android/data/com.android.insecurebankv2/cache
filesDirectory /data/user/0/com.android.insecurebankv2/files
Practical Examples with Output
Example 1 — Attach to a running process by name and explore:
$ frida-ps -Uai | grep -i insecurebank
2214 InsecureBankv2 com.android.insecurebankv2
$ objection -n InsecureBankv2 explore
com.android.insecurebankv2 on (google: 13) [usb] #
Example 2 — Bypass SSL pinning with a single command:
com.android.insecurebankv2 on (google: 13) [usb] # android sslpinning disable
(agent) Custom TrustManager ready, overriding SSLContext.init()
(agent) Found okhttp3.CertificatePinner, overriding check()...
(agent) Registering job 3g7h2. Type: android-ssl-pinning-bypass
Example 3 — Attempt to disable root detection:
com.android.insecurebankv2 on (google: 13) [usb] # android root disable
(agent) Job 5f6e0 registered. Trying to bypass some root detection methods
(agent) Registering job 5f6e0. Type: android-root-detection-disable
Example 4 — List currently loaded Java classes:
com.android.insecurebankv2 on (google: 13) [usb] # android hooking list classes
com.android.insecurebankv2.LoginActivity
com.android.insecurebankv2.DoLogin
com.android.insecurebankv2.CryptoUtil
com.android.insecurebankv2.RootDetectionActivity
android.app.Activity
javax.crypto.Cipher
... (912 classes found)
Example 5 — Search for specific classes by pattern:
com.android.insecurebankv2 on (google: 13) [usb] # android hooking search classes Crypto
com.android.insecurebankv2.CryptoUtil
javax.crypto.Cipher
javax.crypto.spec.SecretKeySpec
Example 6 — List methods of a specific class:
com.android.insecurebankv2 on (google: 13) [usb] # android hooking list class_methods com.android.insecurebankv2.CryptoUtil
public static byte[] com.android.insecurebankv2.CryptoUtil.encrypt(java.lang.String,java.lang.String)
public static byte[] com.android.insecurebankv2.CryptoUtil.decrypt(java.lang.String,java.lang.String)
Example 7 — Hook and watch a method, dumping arguments, backtrace, and return value:
com.android.insecurebankv2 on (google: 13) [usb] # android hooking watch class_method com.android.insecurebankv2.CryptoUtil.decrypt --dump-args --dump-backtrace --dump-return
(agent) Job 8a1c9 registered. Method hooked: com.android.insecurebankv2.CryptoUtil.decrypt
(agent) [8a1c9] Called: com.android.insecurebankv2.CryptoUtil.decrypt(java.lang.String, java.lang.String)
(agent) [8a1c9] Arguments com.android.insecurebankv2.CryptoUtil.decrypt(java.lang.String, java.lang.String)
(agent) arg0: gk8sY3+plaintextciphertext==
(agent) arg1: MyHardcodedKey123
(agent) [8a1c9] Return Value: SuperSecretPassword1
Example 8 — Execute a shell command in the context of the app:
com.android.insecurebankv2 on (google: 13) [usb] # android shell_exec whoami
u0_a142
Example 9 — Take a screenshot, bypassing FLAG_SECURE:
com.android.insecurebankv2 on (google: 13) [usb] # android ui FLAG_SECURE false
(agent) FLAG_SECURE was successfully removed
com.android.insecurebankv2 on (google: 13) [usb] # android ui screenshot /tmp/screenshot.png
(agent) Screenshot saved to: /tmp/screenshot.png
Example 10 — Download a file from the app’s sandbox to the host:
com.android.insecurebankv2 on (google: 13) [usb] # file download /data/data/com.android.insecurebankv2/databases/users.db ./users.db
Downloading /data/data/com.android.insecurebankv2/databases/users.db to ./users.db
Streaming file from device...
Writing bytes to destination...
Successfully downloaded 20480 bytes
Example 11 — Connect to and query a SQLite database found on the device:
com.android.insecurebankv2 on (google: 13) [usb] # sqlite connect users.db
Caching local copy of users.db
Connection to SQLite database at users.db successful
SQLite @ users.db > .tables
users
sessions
com.android.insecurebankv2 on (users.db) [usb] # select * from users;
+----+----------+------------------+
| id | username | password |
+----+----------+------------------+
| 1 | dinesh | Dinesh@123$ |
| 2 | admin | Admin@123 |
+----+----------+------------------+
Example 12 — Patch an APK with a Frida Gadget for non-rooted device testing:
$ objection patchapk -s InsecureBankv2.apk -a arm64
INFO: Patching InsecureBankv2.apk with the Frida Gadget for architecture arm64
INFO: Extracting InsecureBankv2.apk to /tmp/objection-patch
INFO: Downloading Frida Gadget for arm64
INFO: Injecting Gadget into the APK
INFO: Rebuilding the APK with apktool
INFO: Signing InsecureBankv2.objection.apk
INFO: Copying final apk from /tmp/objection-patch to current directory
INFO: Cleaning up temp files...
Patching Complete. Find the patched apk here: InsecureBankv2.objection.apk
Common Use Cases
- Rapid SSL pinning and root detection bypass – Getting past common client-side protections instantly with
android sslpinning disableandandroid root disable, without writing a single line of custom Frida JS. - Non-rooted device testing – Using
objection patchapkto embed the Frida Gadget directly into a target APK, enabling full dynamic instrumentation on devices where root is not available or desired. - Runtime data extraction from insecure storage – Using
file download,sqlite connect, andandroid keystore listto pull sensitive data (session tokens, cached credentials, PII) directly from the running app’s sandbox. - Live method call auditing – Using
android hooking watch class_methodwith--dump-args/--dump-returnto trace exactly what data flows into and out of a suspicious function (e.g., a custom crypto routine) during real interaction with the app. - Anti-tampering and detection-logic testing – Using
android root simulateto verify an app’s own anti-tampering/root-detection code actually triggers correctly when a rooted environment is present, from the developer’s side of testing.
Automation with Bash
The following script automates attaching Objection to a target app and running a sequence of common bypass and reconnaissance commands using --startup-command, then chains subsequent commands via a piped command file.
#!/bin/bash
# objection_auto_recon.sh - Automated Objection bypass and recon session
PACKAGE="$1"
if [ -z "$PACKAGE" ]; then
echo "Usage: $0 <package_name>"
exit 1
fi
echo "[*] Verifying frida-server connectivity..."
frida-ps -U > /dev/null 2>&1 || { echo "[-] frida-server unreachable. Start it first."; exit 1; }
echo "[*] Confirming target app is running..."
frida-ps -Ua | grep -qi "$PACKAGE" || { echo "[-] $PACKAGE is not running on the device."; exit 1; }
echo "[*] Launching Objection with automated SSL pinning bypass and root detection bypass..."
objection -g "$PACKAGE" \
--startup-command "android sslpinning disable" \
explore <<'EOF'
android root disable
android hooking list classes
env
exit
EOF
echo "[+] Automated recon session complete."
Sample run:
$ chmod +x objection_auto_recon.sh
$ ./objection_auto_recon.sh com.android.insecurebankv2
[*] Verifying frida-server connectivity...
[*] Confirming target app is running...
[*] Launching Objection with automated SSL pinning bypass and root detection bypass...
(agent) Registering job 3g7h2. Type: android-ssl-pinning-bypass
com.android.insecurebankv2 on (google: 13) [usb] # android root disable
(agent) Registering job 5f6e0. Type: android-root-detection-disable
com.android.insecurebankv2 on (google: 13) [usb] # android hooking list classes
com.android.insecurebankv2.LoginActivity
com.android.insecurebankv2.DoLogin
...
com.android.insecurebankv2 on (google: 13) [usb] # env
Name Path
------------------ -----------------------------------------------------
filesDirectory /data/user/0/com.android.insecurebankv2/files
com.android.insecurebankv2 on (google: 13) [usb] # exit
[+] Automated recon session complete.
Tips and Best Practices
- Use
objection -n <name>or-g <gadget_identifier>for attaching to already-running processes rather than spawning, to avoid disrupting an app that’s already mid-session (e.g., already logged in). - Use
--startup-command(or--startup-scriptfor more complex logic) to run SSL pinning/root detection bypasses before the REPL finishes loading — this is critical for apps that perform these checks early, such as inApplication.onCreate(). - Combine
jobs listandjobs kill <id>to manage long-running hooks (likeandroid hooking watch class_method) without needing to exit and restart the whole session. - When
android sslpinning disabledoesn’t fully work against a custom pinning implementation, useandroid hooking list classesandandroid hooking search classesto locate the app’s specific pinning class, then write a targeted Frida script and load it withimport <script.js>. - Remember that Objection cannot instantiate new objects or call methods that require complex object arguments — for advanced manipulation beyond what Objection’s built-in commands support, drop down to raw Frida scripting.
- Always test hooking on a rooted test device or emulator first before attempting
objection patchapkworkflows on production or client-provided applications, since embedding a Gadget modifies and re-signs the APK. - Use
sqlite connectimmediately afterfile download-ing a.dbfile locally, or connect directly to the remote path, to explore local storage without needing a separate SQLite browser tool.
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
Failed to attach to process on explore | frida-server not running, or version mismatch | Verify frida-ps -U works first; confirm client/server Frida versions match |
android sslpinning disable doesn’t stop pinning errors | App uses a custom, non-standard pinning implementation | Use android hooking search classes to find the custom pinning class and write a manual Frida hook |
| Objection REPL hangs or is unresponsive | App is heavily obfuscated or crashed silently after hook injection | Restart the app, reduce the number of simultaneously active hooks, check adb logcat for a crash trace |
patchapk fails during rebuild step | Apktool not installed or resource decoding failure in the target APK | Ensure apktool is installed and up to date; try patching with -n disabled if network config injection is the failure point |
Patched APK won’t install (INSTALL_FAILED_...) | Architecture mismatch between Gadget and device, or signature conflict with an already-installed original app | Match -a to the exact device architecture; uninstall the original unpatched app first |
file download fails with permission denied | Target file is outside the app’s accessible sandbox, and device is not rooted | Ensure the device is rooted or use a Gadget-patched APK for elevated context |
| Commands appear to run but produce no visible effect on the app | The hooked class/method was not actually invoked during your test interaction | Trigger the corresponding UI action in the running app for the hook to catch the call |
References
- Objection GitHub Repository:
https://github.com/sensepost/objection - Objection Official Wiki:
https://github.com/sensepost/objection/wiki - HackTricks – Objection Tutorial:
https://hacktricks.wiki/en/mobile-pentesting/android-app-pentesting/frida-tutorial/objection-tutorial.html - HackTricks – iOS Hooking With Objection:
https://book.hacktricks.xyz/mobile-pentesting/ios-pentesting/ios-hooking-with-objection - Kali Linux Tools – Objection:
https://www.kali.org/tools/objection/ - OWASP MASTG – Dynamic Analysis and SSL Pinning Bypass:
https://mas.owasp.org/MASTG/Android/0x05c-Reverse-Engineering-and-Static-Analysis/