# iOS Frida Konfiguration
{{#include ../../banners/hacktricks-training.md}}
Vertiefen Sie Ihr Fachwissen in **Mobile Security** mit der 8kSec Academy. Meistern Sie die Sicherheit von iOS und Android durch unsere selbstgesteuerten Kurse und erhalten Sie ein Zertifikat:
{% embed url="https://academy.8ksec.io/" %}
## Frida installieren
**Schritte zur Installation von Frida auf einem Jailbroken-Gerät:**
1. Öffnen Sie die Cydia/Sileo-App.
2. Navigieren Sie zu Verwalten -> Quellen -> Bearbeiten -> Hinzufügen.
3. Geben Sie "https://build.frida.re" als URL ein.
4. Gehen Sie zur neu hinzugefügten Frida-Quelle.
5. Installieren Sie das Frida-Paket.
Wenn Sie **Corellium** verwenden, müssen Sie die Frida-Version von [https://github.com/frida/frida/releases](https://github.com/frida/frida/releases) herunterladen (`frida-gadget-[yourversion]-ios-universal.dylib.gz`) und entpacken und an den von Frida angeforderten dylib-Standort kopieren, z.B.: `/Users/[youruser]/.cache/frida/gadget-ios.dylib`
Nach der Installation können Sie auf Ihrem PC den Befehl **`frida-ls-devices`** verwenden und überprüfen, ob das Gerät angezeigt wird (Ihr PC muss darauf zugreifen können).\
Führen Sie auch **`frida-ps -Uia`** aus, um die laufenden Prozesse des Telefons zu überprüfen.
## Frida ohne Jailbroken-Gerät & ohne Patchen der App
Überprüfen Sie diesen Blogbeitrag, wie Sie Frida auf nicht-jailbroken Geräten ohne Patchen der App verwenden können: [https://mrbypass.medium.com/unlocking-potential-exploring-frida-objection-on-non-jailbroken-devices-without-application-ed0367a84f07](https://mrbypass.medium.com/unlocking-potential-exploring-frida-objection-on-non-jailbroken-devices-without-application-ed0367a84f07)
## Frida Client Installation
Installieren Sie **frida tools**:
```bash
pip install frida-tools
pip install frida
```
Mit dem installierten Frida-Server und dem laufenden und verbundenen Gerät, **prüfen** Sie, ob der Client **funktioniert**:
```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 -i "*log*"
frida-trace -U -i "*log*" | swift demangle # Demangle names
# Objective-C
## Trace all methods of all classes
frida-trace -U -m "*[* *]"
## Trace all methods with the word "authentication" from classes that start with "NE"
frida-trace -U -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 -m '*[* *]'
```
### Alle Klassen und Methoden abrufen
- Auto vervollständigen: Führen Sie einfach `frida -U ` aus
- Alle verfügbaren **Klassen** abrufen (nach Zeichenfolge filtern)
```javascript:/tmp/script.js
// frida -U -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.")
}
```
- Alle **Methoden** einer **Klasse** abrufen (nach Zeichenfolge filtern)
```javascript:/tmp/script.js
// frida -U -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.")
}
```
- **Rufe eine Funktion auf**
```javascript
// Find the address of the function to call
const func_addr = Module.findExportByName("", "")
// 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 ist Fridas **Code-Trace-Engine**. Es ermöglicht das **Verfolgen** von Threads, **erfasst** jede Funktion, **jeden Block**, sogar jede Anweisung, die ausgeführt wird.
Sie haben ein Beispiel, das Frida Stalker implementiert, in [https://github.com/poxyran/misc/blob/master/frida-stalker-example.py](https://github.com/poxyran/misc/blob/master/frida-stalker-example.py)
Dies ist ein weiteres Beispiel, um Frida Stalker jedes Mal anzuhängen, wenn eine Funktion aufgerufen wird:
```javascript
console.log("loading")
const wg_log_addr = Module.findExportByName("", "")
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
},
})
```
> [!CAUTION]
> Dies ist interessant aus Debugging-Gründen, aber für Fuzzing ist es sehr ineffizient, ständig **`.follow()`** und **`.unfollow()`** zu verwenden.
## [Fpicker](https://github.com/ttdennis/fpicker)
[**fpicker**](https://github.com/ttdennis/fpicker) ist eine **Frida-basierte Fuzzing-Suite**, die eine Vielzahl von Fuzzing-Modi für In-Process-Fuzzing bietet, wie z.B. einen AFL++-Modus oder einen passiven Tracing-Modus. Es sollte auf allen Plattformen laufen, die von Frida unterstützt werden.
- [**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
```
- **Bereite das FS vor:**
```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-Skript** (`examples/wg-log/myfuzzer.js`):
```javascript:examples/wg-log/myfuzzer.js
// 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(
"",
""
)
var wg_log_func = new NativeFunction(
wg_log_addr,
"void",
["pointer", "pointer", "pointer"],
{}
)
// Initialize the object
super("", 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
```
- **Kompiliere** den Fuzzer:
```bash
# From inside fpicker clone
## Compile from "myfuzzer.js" to "harness.js"
frida-compile examples/wg-log/myfuzzer.js -o harness.js
```
- Rufen Sie den Fuzzer **`fpicker`** mit **`radamsa`** auf:
```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 -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/
```
> [!CAUTION]
> In diesem Fall **starten wir die App nicht neu oder stellen den Zustand nicht wieder her** nach jedem Payload. Wenn Frida also einen **Absturz** findet, könnten die **nächsten Eingaben** nach diesem Payload ebenfalls die **App zum Absturz bringen** (weil die App sich in einem instabilen Zustand befindet), selbst wenn die **Eingabe die App nicht zum Absturz bringen sollte**.
>
> Darüber hinaus wird Frida in die Ausnahme-Signale von iOS einhaken, sodass, wenn **Frida einen Absturz findet**, wahrscheinlich **keine iOS-Absturzberichte generiert werden**.
>
> Um dies zu verhindern, könnten wir beispielsweise die App nach jedem Frida-Absturz neu starten.
### Protokolle & Abstürze
Sie können die **macOS-Konsole** oder die **`log`**-CLI überprüfen, um die macOS-Protokolle zu überprüfen.\
Sie können auch die Protokolle von iOS mit **`idevicesyslog`** überprüfen.\
Einige Protokolle werden Informationen auslassen und **``** hinzufügen. Um alle Informationen anzuzeigen, müssen Sie ein Profil von [https://developer.apple.com/bug-reporting/profiles-and-logs/](https://developer.apple.com/bug-reporting/profiles-and-logs/) installieren, um diese privaten Informationen zu aktivieren.
Wenn Sie nicht wissen, was zu tun ist:
```sh
vim /Library/Preferences/Logging/com.apple.system.logging.plist
Enable-Private-Data
killall -9 logd
```
Sie können die Abstürze überprüfen in:
- **iOS**
- Einstellungen → Datenschutz → Analysen & Verbesserungen → Analysedaten
- `/private/var/mobile/Library/Logs/CrashReporter/`
- **macOS**:
- `/Library/Logs/DiagnosticReports/`
- `~/Library/Logs/DiagnosticReports`
> [!WARNING]
> iOS speichert nur 25 Abstürze der gleichen App, daher müssen Sie das bereinigen, sonst hört iOS auf, Abstürze zu erstellen.
## Frida Android Tutorials
{{#ref}}
../android-app-pentesting/frida-tutorial/
{{#endref}}
## References
- [https://www.briskinfosec.com/blogs/blogsdetail/Getting-Started-with-Frida](https://www.briskinfosec.com/blogs/blogsdetail/Getting-Started-with-Frida)
Vertiefen Sie Ihr Fachwissen in **Mobile Security** mit der 8kSec Academy. Meistern Sie die Sicherheit von iOS und Android durch unsere selbstgesteuerten Kurse und erhalten Sie ein Zertifikat:
{% embed url="https://academy.8ksec.io/" %}
{{#include ../../banners/hacktricks-training.md}}