___ ____
/ __\ / _ | _ _ _ _ _ _
/ _\ | (_) | / _ \ / _ \ | / / | | | |
/ / / / | | | (_) | (_) || < | |_| |
\/ /_/ |_| \___/ \___/ |_|\_\ \__, |
|___/frooky is a Frida-based dynamic analysis tool for Android apps with the purpose of simplifying function hooking and runtime data decoding.
- Hook Java/Kotlin methods and native C/C++ functions
- Structured YAML input for hook declarations
- Structured NDJSON output for easy event processing
- Support for method overloads and stack trace capture
- Argument capture with various data types
- Return value capture with various data types
- Filter hooks by argument values or stack trace patterns
Requirements:
- Python 3.12 or later on the host
- A device or emulator with
frida-server - A 64-bit app process (
arm64orx86_64)
frooky is tested on Android 12 to 15.
Install the frooky CLI tool via uv or pip:
uv tool install frooky
# or
pip install frookyCreate a hook file (e.g., hooks.yaml) with the functions and/or methods you want to hook.
Read all about the Structure of a Hook File or use the documented examples as a quick starting point.
After you created the desired hook file, run frooky:
# Attach by app name and show the events on the terminal
frooky -U -n org.owasp.mastestapp resilience.yaml -e
# Attach to the frontmost application and load an additional script
frooky -U -F webview.yaml -l disable-flutter-tls.js
# Spawn and load multiple hook files (hooks are merged) and show very verbose output
frooky -U -f org.owasp.mastestapp storage.yaml crypto.yaml -vv
# Spawn and load multiple hook files using globs (hooks are merged) and use V8 JavaScript engine
frooky -U -f org.owasp.mastestapp hooks_platform_*.yaml --runtime v8
# Watch the hook files and apply changes while the app keeps running
frooky -U -f org.owasp.mastestapp biometry.yaml -wSee frooky -h for all options.
frooky uses hook files, which are structured YAML files including declarations of methods or functions to be hooked.
schemaVersion: 1 # Optional. Version of the hook-file format, default 1
metadata: # Optional and informational; may contain fields of your own
name: <name> # Name of the hook file
platform: Android # Target platform
description: <description> # Description of what the hooks capture
category: <category> # Category of the hook file
author: <author> # Your name or organization
version: <version> # Version number of the hook file (e.g., 1)
hookSettings: { ... } # Optional. Default hook settings for all hook declarations
decoderSettings: { ... } # Optional. Default decoder settings for all parameters and return values
hookCollections: # Hook collections, each for one Java class or native module
- <hook_declaration>Depending on the platform, the <hook_declaration> may look different. Please read the linked platform-specific documentation for more information.
At the moment, frooky supports these types of hooks:
| Hook Type | Platform | Description | Documentation |
|---|---|---|---|
| Java hook | Android | Hook for Java/Kotlin methods | Java Hook Declaration |
| Native hook | Android | Hook for native functions (C/C++) | Native Hook Declaration |
Note
frooky supports Android only. iOS support is planned.
frooky can decode data passed to functions or methods via arguments, including their return values.
Depending on the value types, this can be simple or more complex. frooky tries to decode arguments and return values by itself if possible. But in some cases, e.g. when the value is simply a native pointer, it is necessary to provide information about the types used. Before writing a hook declaration, it is therefore recommended to read the following documentation:
We'll use the OWASP MAS MASTG-DEMO-0106 app to demonstrate hooking a cryptographic en-/decryption method.
First you need to create a hook file, e.g., cipher_dofinal.yaml:
metadata:
name: Android Cipher doFinal Hook
platform: Android
description: Captures the plaintext/ciphertext passed to Cipher#doFinal during en-/decryption decoded as string.
category: CRYPTO
author: frooky dev team
version: 1
hookCollections:
- javaClass: javax.crypto.Cipher
hookSettings:
javaStackTrace: true
hooks:
- [doFinal, { decoder: string }]Then run frooky with the hook file against your target app:
frooky -U -f org.owasp.mastestapp cipher_dofinal.yamlEvents are written to the output file as NDJSON, one JSON event object per line (see Understanding Output Format for the full schema). A single event, pretty-printed:
{
"id": "0a6c400a-a7fe-44ab-8842-d1e4a67e0487",
"timestamp": "2026-09-16T06:20:33.163Z",
"type": "hook-java",
"javaClass": "javax.crypto.Cipher",
"method": "doFinal",
"methodType": "instance",
"argsIn": [
{
"type": "[B",
"value": ".5}....!(.L;(...KY.ly.Pd.`2.uT.....x.C?."
}
],
"argsOut": [],
"returnValue": {
"type": "[B",
"value": "We ❤️ OWASP MAS 📱"
},
"stackTrace": {
"javaStackTrace": [
"javax.crypto.Cipher.doFinal (Cipher.java:2066)",
"org.owasp.mastestapp.MastgTest.mastgTest (MastgTest.kt:58)",
"org.owasp.mastestapp.MainActivityKt.MainScreen$lambda$12$lambda$11 (MainActivity.kt:101)",
"org.owasp.mastestapp.MainActivityKt.$r8$lambda$Pm6AsbKBmypP53K-UABM21E_Xxk (MainActivity.kt:-1)",
"org.owasp.mastestapp.MainActivityKt$$ExternalSyntheticLambda3.run (D8$$SyntheticClass:0)"
],
"nativeStackTrace": []
}
}Please refer to the following documentation for more information about various topics: