# iOS Frida Configuration

{% hint style="success" %}
Learn & practice AWS Hacking:<img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-ce8af1068db7be4ad9003f8ddb02fea8f943f1a4%2Farte.png?alt=media" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-ce8af1068db7be4ad9003f8ddb02fea8f943f1a4%2Farte.png?alt=media" alt="" data-size="line">\
Learn & practice GCP Hacking: <img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-54ee1fb931f39d1e6f50150361b6aa1927f4ee88%2Fgrte.png?alt=media" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-54ee1fb931f39d1e6f50150361b6aa1927f4ee88%2Fgrte.png?alt=media" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)

<details>

<summary>Support HackTricks</summary>

* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.

</details>
{% endhint %}

## Installing Frida

**Steps to install Frida on a Jailbroken device:**

1. Open Cydia/Sileo app.
2. Navigate to Manage -> Sources -> Edit -> Add.
3. Enter "<https://build.frida.re>" as the URL.
4. Go to the newly added Frida source.
5. Install the Frida package.

If you are using **Corellium** you will need to download the Frida release from <https://github.com/frida/frida/releases> (`frida-gadget-[yourversion]-ios-universal.dylib.gz`) and unpack and copy to the dylib location Frida asks for, e.g.: `/Users/[youruser]/.cache/frida/gadget-ios.dylib`

After installed, you can use in your PC the command **`frida-ls-devices`** and check that the device appears (your PC needs to be able to access it).\
Execute also **`frida-ps -Uia`** to check the running processes of the phone.

## Frida without Jailbroken device & without patching the app

Check this blog post about how to use Frida in non-jailbroken devices without patching the app: <https://mrbypass.medium.com/unlocking-potential-exploring-frida-objection-on-non-jailbroken-devices-without-application-ed0367a84f07>

## Frida Client Installation

Install **frida tools**:

```bash
pip install frida-tools
pip install frida
```

With the Frida server installed and the device running and connected, **check** if the client is **working**:

```bash
frida-ls-devices  # List devices
frida-ps -Uia     # Get running processes
```

## Frida Trace

```bash
# Functions
## Trace all functions with the word "log" in their name
frida-trace -U <program> -i "*log*"
frida-trace -U <program> -i "*log*" | swift demangle # Demangle names

# Objective-C
## Trace all methods of all classes
frida-trace -U <program> -m "*[* *]"

## Trace all methods with the word "authentication" from classes that start with "NE"
frida-trace -U <program> -m "*[NE* *authentication*]"

# Plug-In
## To hook a plugin that is momentarely executed prepare Frida indicating the ID of the Plugin binary
frida-trace -U -W <if-plugin-bin> -m '*[* *]'
```

### Get all classes and methods

* Auto complete: Just execute `frida -U <program>`

<figure><img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-f43bee669c8ffdf1074f646b5c35e7f3bce9bc27%2Fimage%20(1159).png?alt=media" alt=""><figcaption></figcaption></figure>

* Get **all** available **classes** (filter by string)

{% code title="/tmp/script.js" %}

```javascript
// frida -U <program> -l /tmp/script.js

var filterClass = "filterstring";

if (ObjC.available) {
    for (var className in ObjC.classes) {
        if (ObjC.classes.hasOwnProperty(className)) {
            if (!filterClass || className.includes(filterClass)) {
                console.log(className);
            }
        }
    }
} else {
    console.log("Objective-C runtime is not available.");
}
```

{% endcode %}

* Get **all** **methods** of a **class** (filter by string)

{% code title="/tmp/script.js" %}

```javascript
// frida -U <program> -l /tmp/script.js

var specificClass = "YourClassName";
var filterMethod = "filtermethod";

if (ObjC.available) {
    if (ObjC.classes.hasOwnProperty(specificClass)) {
        var methods = ObjC.classes[specificClass].$ownMethods;
        for (var i = 0; i < methods.length; i++) {
            if (!filterMethod || methods[i].includes(filterClass)) {
                console.log(specificClass + ': ' + methods[i]);
            }
        }
    } else {
        console.log("Class not found.");
    }
} else {
    console.log("Objective-C runtime is not available.");
}
```

{% endcode %}

* **Call a function**

```javascript
// Find the address of the function to call
const func_addr = Module.findExportByName("<Prog Name>", "<Func Name>");
// Declare the function to call
const func = new NativeFunction(
   func_addr,
   "void", ["pointer", "pointer", "pointer"], {
});

var arg0 = null;

// In this case to call this function we need to intercept a call to it to copy arg0
Interceptor.attach(wg_log_addr, {
   onEnter: function(args) {
       arg0 = new NativePointer(args[0]);
   }
});

// Wait untill a call to the func occurs 
while (! arg0) {
   Thread.sleep(1);
   console.log("waiting for ptr");
}


var arg1 = Memory.allocUtf8String('arg1');
var txt = Memory.allocUtf8String('Some text for arg2');
wg_log(arg0, arg1, txt);

console.log("loaded");
```

## Frida Fuzzing

### Frida Stalker

[From the docs](https://frida.re/docs/stalker/): Stalker is Frida’s code **tracing engine**. It allows threads to be **followed**, **capturing** every function, **every block**, even every instruction which is executed.

You have an example implementing Frida Stalker in <https://github.com/poxyran/misc/blob/master/frida-stalker-example.py>

This is another example to attach Frida Stalker every time a function is called:

```javascript
console.log("loading");
const wg_log_addr = Module.findExportByName("<Program>", "<function_name>");
const wg_log = new NativeFunction(
    wg_log_addr,
    "void", ["pointer", "pointer", "pointer"], {
});

Interceptor.attach(wg_log_addr, {
    onEnter: function(args) {
        console.log(`logging the following message: ${args[2].readCString()}`);
        
        Stalker.follow({ 
            events: {
                // only collect coverage for newly encountered blocks
                compile: true,
            },
            onReceive: function (events) {
                const bbs = Stalker.parse(events, {
                    stringify: false,
                    annotate: false
                });
                console.log("Stalker trace of write_msg_to_log: \n" + bbs.flat().map(DebugSymbol.fromAddress).join('\n'));
            }
        });
    },
    onLeave: function(retval) {
        Stalker.unfollow();
        Stalker.flush();  // this is important to get all events  
    }
});
```

{% hint style="danger" %}
This is interesting from debugging purposes but for fuzzing, to be constantly **`.follow()`** and **`.unfollow()`** is very inefficient.
{% endhint %}

## [Fpicker](https://github.com/ttdennis/fpicker)

[**fpicker**](https://github.com/ttdennis/fpicker) is a **Frida-based fuzzing suite** that offers a variety of fuzzing modes for in-process fuzzing, such as an AFL++ mode or a passive tracing mode. It should run on all platforms that are supported by Frida.

* [**Install fpicker**](https://github.com/ttdennis/fpicker#requirements-and-installation) **& radamsa**

```bash
# Get fpicker
git clone https://github.com/ttdennis/fpicker
cd fpicker

# Get Frida core devkit and prepare fpicker
wget https://github.com/frida/frida/releases/download/16.1.4/frida-core-devkit-16.1.4-[yourOS]-[yourarchitecture].tar.xz
# e.g. https://github.com/frida/frida/releases/download/16.1.4/frida-core-devkit-16.1.4-macos-arm64.tar.xz 
tar -xf ./*tar.xz
cp libfrida-core.a libfrida-core-[yourOS].a #libfrida-core-macos.a

# Install fpicker
make fpicker-[yourOS] # fpicker-macos
# This generates ./fpicker

# Install radamsa (fuzzer generator)
brew install radamsa
```

* **Prepare the FS:**

```bash
# From inside fpicker clone
mkdir -p examples/wg-log # Where the fuzzing script will be
mkdir -p examples/wg-log/out # For code coverage and crashes
mkdir -p examples/wg-log/in # For starting inputs

# Create at least 1 input for the fuzzer
echo Hello World > examples/wg-log/in/0
```

* **Fuzzer script** (`examples/wg-log/myfuzzer.js`):

{% code title="examples/wg-log/myfuzzer.js" %}

```javascript
// Import the fuzzer base class
import { Fuzzer } from "../../harness/fuzzer.js";

class WGLogFuzzer extends Fuzzer {

    constructor() {
        console.log("WGLogFuzzer constructor called")

        // Get and declare the function we are going to fuzz
        var wg_log_addr = Module.findExportByName("<Program name>", "<func name to fuzz>");
        var wg_log_func = new NativeFunction(
            wg_log_addr,
            "void", ["pointer", "pointer", "pointer"], {
        });

        // Initialize the object
        super("<Program nane>", wg_log_addr, wg_log_func);
        this.wg_log_addr = wg_log_addr; // We cannot use "this" before calling "super"
        
        console.log("WGLogFuzzer in the middle");
        
        // Prepare the second argument to pass to the fuzz function
        this.tag = Memory.allocUtf8String("arg2");
        
        // Get the first argument we need to pass from a call to the functino we want to fuzz
        var wg_log_global_ptr = null;
        console.log(this.wg_log_addr);
        Interceptor.attach(this.wg_log_addr, {
            onEnter: function(args) {
                console.log("Entering in the function to get the first argument");
                wg_log_global_ptr = new NativePointer(args[0]);
            }
         });

        while (! wg_log_global_ptr) {
            Thread.sleep(1)
        }
        this.wg_log_global_ptr = wg_log_global_ptr;
        console.log("WGLogFuzzer prepare ended")
    }


    // This function is called by the fuzzer with the first argument being a pointer into memory
    // where the payload is stored and the second the length of the input.
    fuzz(payload, len) {
        // Get a pointer to payload being a valid C string (with a null byte at the end)
        var payload_cstring = payload.readCString(len);
        this.payload = Memory.allocUtf8String(payload_cstring);

        // Debug and fuzz
        this.debug_log(this.payload, len);
        // Pass the 2 first arguments we know the function needs and finally the payload to fuzz
        this.target_function(this.wg_log_global_ptr, this.tag, this.payload);
    }
}

const f = new WGLogFuzzer();
rpc.exports.fuzzer = f;
```

{% endcode %}

* **Compile** the fuzzer:

```bash
# From inside fpicker clone
## Compile from "myfuzzer.js" to "harness.js"
frida-compile examples/wg-log/myfuzzer.js -o harness.js
```

* Call fuzzer **`fpicker`** using **`radamsa`**:

{% code overflow="wrap" %}

```bash
# Indicate fpicker to fuzz a program with the harness.js script and which folders to use
fpicker -v --fuzzer-mode active -e attach -p <Program to fuzz> -D usb -o examples/wg-log/out/ -i examples/wg-log/in/ -f harness.js --standalone-mutator cmd --mutator-command "radamsa"
# You can find code coverage and crashes in examples/wg-log/out/
```

{% endcode %}

{% hint style="danger" %}
In this case we **aren't restarting the app or restoring the state** after each payload. So, if Frida finds a **crash** the **next inputs** after that payload might also **crash the app** (because the app is in a unstable state) even if the **input shouldn't crash** the app.

Moreover, Frida will hook into exception signals of iOS, so when **Frida finds a crash**, probably an **iOS crash reports won't be generated**.

To prevent this, for example, we could restart the app after each Frida crash.
{% endhint %}

### Logs & Crashes

You can check the **macOS console** or the **`log`** cli to check macOS logs.\
You can check also the logs from iOS using **`idevicesyslog`**.\
Some logs will omit information adding **`<private>`**. To show all the info you need to install some profile from <https://developer.apple.com/bug-reporting/profiles-and-logs/> to enable that private info.

If you don't know what to do:

```sh
vim /Library/Preferences/Logging/com.apple.system.logging.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>Enable-Private-Data</key>
        <true/>
</dict>
</plist>

killall -9 logd
```

You can check the crashes in:

* **iOS**
  * Settings → Privacy → Analytics & Improvements → Analytics Data
  * `/private/var/mobile/Library/Logs/CrashReporter/`
* **macOS**:
  * `/Library/Logs/DiagnosticReports/`
  * `~/Library/Logs/DiagnosticReports`

{% hint style="warning" %}
iOS only stores 25 crashes of the same app, so you need to clean that or iOS will stop creating crashes.
{% endhint %}

## Frida Android Tutorials

{% content-ref url="../android-app-pentesting/frida-tutorial" %}
[frida-tutorial](https://angelica.gitbook.io/hacktricks/mobile-pentesting/android-app-pentesting/frida-tutorial)
{% endcontent-ref %}

## References

* <https://www.briskinfosec.com/blogs/blogsdetail/Getting-Started-with-Frida>

{% hint style="success" %}
Learn & practice AWS Hacking:<img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-ce8af1068db7be4ad9003f8ddb02fea8f943f1a4%2Farte.png?alt=media" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-ce8af1068db7be4ad9003f8ddb02fea8f943f1a4%2Farte.png?alt=media" alt="" data-size="line">\
Learn & practice GCP Hacking: <img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-54ee1fb931f39d1e6f50150361b6aa1927f4ee88%2Fgrte.png?alt=media" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="https://4053168017-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbkAZDoSuRHGdNlWHdyKs%2Fuploads%2Fgit-blob-54ee1fb931f39d1e6f50150361b6aa1927f4ee88%2Fgrte.png?alt=media" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)

<details>

<summary>Support HackTricks</summary>

* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.

</details>
{% endhint %}
