Skip to content

cpholguera/frooky

Repository files navigation

Frooky

   ___    ____           
  / __\  / _  |    _     _    _  _   _   _
 / _\   | (_) |  / _ \ / _ \ | / /  | | | |
/ /     / / | | | (_) | (_) ||  <   | |_| |
\/     /_/  |_|  \___/ \___/ |_|\_\  \__, |
                                     |___/

frooky is a Frida-based dynamic analysis tool for Android and iOS apps based on YAML hook files.

PyPI - Version Test

  • Hook Java/Kotlin methods and native C/C++ functions
  • Simple YAML hook file format
  • 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
  • Output events in JSON Lines format for easy processing

Use it, if you know what you want to hook but you don't want to write custom Frida scripts or copy and paste them together. For example you can use it to quickly hook functions or methods based on public API documentation and quickly get insight about them.

Note

This documentation describes the intended feature set for frooky 1.0. At the time of writing this document, not all described features may have been fully implemented and there may be breaking changes to the hook file API until the release of frooky 1.0.

Feedback is always welcome.

Installation

Simply install via pip to get the frooky CLI tool:

pip3 install frooky

Usage

Create a hook file (e.g., hooks.yaml) with the functions and/or methods you want to hook.

If you are already familiar with Frida and function hooking, we recommend using the documented examples as a quick starting point. You find them in the folder docs/examples/.

For more information, read all about the structure in chapter Structure of a Hook File.

After you created the desired hook file, run frooky:

# Attach by app name
frooky android -U -n org.owasp.mastestapp hooks.yaml

# Spawn and add multiple hook files (hooks are merged)
frooky android -U -f org.owasp.mastestapp storage.yaml crypto.yaml

# Spawn and add multiple hook files using globs (hooks are merged)
frooky android -U -f org.owasp.mastestapp hooks_*.yaml

See frooky -h for more options.

Structure of a Hook File

frooky uses hook files, which are structured YAML files including declarations of methods or functions to be hooked.

A hook file consists of optional metadata and a list of hook declarations. The following YAML file describes the basic structure:

metadata:                         # All metadata is optional
  name: <name>                    # Name of the hook collection
  platform: Android|iOS           # Target platform (hooks must be platform-specific)
  description: <description>      # Description of what the hook collection does
  category: <category>            # Category of the hook collection
  author: <author>                # Your name or organization
  version: <version>              # Semantic version (e.g., v1)

hooks:                            # Collection of hook declarations
  - <hook_declaration>

Example:

The following hook file hooks all RNG initialization methods and functions on an Android device, capturing their arguments, return values, and stack trace. This information can be used to detect insecure RNG.

metadata:
  name: RNG initialization
  platform: Android
  description: Hooks all RNG initialization methods on Android (Java, kotlin, native)
  masCategory: CRYPTOGRAPHY
  author: frooky dev team
  version: v1

hooks:
  - <hook_declaration> 

Hook Declaration

Depending on the platform, the <hook_declaration> may look different. Please read the linked platform-specific documentation for more information.

frooky supports these types of hooks:

Hook Type Platform Description Documentation
JavaHook Android Hook for Java/Kotlin methods JavaHook-Declaration
ObjcHook iOS Hook for Objective-C methods ObjcHook-Declaration
NativeHook Android/iOS Hook for native functions (C/C++/Rust etc.) NativeHook-Declaration

Important

When loading a hook declaration, frooky will validate it and to detect invalid declarations. For example, it is not possible to declare a JavaHook and a ObjcHook hook in one hook file.

Parameter- and Return-Type Declaration

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 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:

Example

We'll use the OWASP MAS MASTG-DEMO-0072 app to demonstrate hooking a cryptographic key generation method.

First you need to create a hook file, e.g., keygen.yaml:

metadata:
  name: Android Key Generator Specifications
  platform: Android
  description: Captures the initialization of a KeyGenParameterSpec Builder 
  category: CRYPTO
  author: frooky dev team
  version: v1

hooks:
  - javaClass: android.security.keystore.KeyGenParameterSpec$Builder
    methods:
      - $init

Then run frooky with the hook file against your target app:

frooky android -U -n org.owasp.mastestapp keygen.yaml

Events are written to the output file in JSON Lines format (one JSON object per line, known as NDJSON).

Example Output (pretty-printed for readability):

{
  "id": "14535033-08ea-4063-897c-eacd4a885d8b",
  "type": "hook",
  "category": "CRYPTO",
  "time": "2026-01-14T16:02:21.782Z",
  "class": "android.security.keystore.KeyGenParameterSpec$Builder",
  "method": "$init",
  "instanceId": 35486102,
  "stackTrace": [
    "android.security.keystore.KeyGenParameterSpec$Builder.<init>(Native Method)",
    "org.owasp.mastestapp.MastgTest.generateKey(MastgTest.kt:97)",
    "org.owasp.mastestapp.MastgTest.mastgTest(MastgTest.kt:41)",
    "org.owasp.mastestapp.MainActivityKt.MainScreen$lambda$12$lambda$11(MainActivity.kt:101)",
    "org.owasp.mastestapp.MainActivityKt.$r8$lambda$Pm6AsbKBmypP53K-UABM21E_Xxk(Unknown Source:0)",
    "org.owasp.mastestapp.MainActivityKt$$ExternalSyntheticLambda3.run(D8$$SyntheticClass:0)",
    "java.lang.Thread.run(Thread.java:1012)"
  ],
  "inputParameters": [
    {
      "declaredType": "java.lang.String",
      "value": "MultiPurposeKey"
    },
    {
      "declaredType": "int",
      "value": 15
    }
  ],
  "returnValue": [
    {
      "declaredType": "void",
      "value": "void"
    }
  ]
}

More Information

Please refer to the following documentation for more information about various topics: