hacktricks/mobile-pentesting/ios-pentesting/frida-configuration-in-ios.md

359 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# iOS Frida配置
<details>
<summary><strong>从零开始学习AWS黑客技术成为专家</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTEHackTricks AWS红队专家</strong></a><strong></strong></summary>
支持HackTricks的其他方式
* 如果您想看到您的**公司在HackTricks中做广告**或**下载PDF格式的HackTricks**,请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
* 获取[**官方PEASS & HackTricks周边产品**](https://peass.creator-spring.com)
* 探索[**PEASS家族**](https://opensea.io/collection/the-peass-family),我们的独家[**NFTs**](https://opensea.io/collection/the-peass-family)
* **加入** 💬 [**Discord群**](https://discord.gg/hRep4RUj7f) 或 [**电报群**](https://t.me/peass) 或 **关注**我们的**Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**。**
* 通过向[**HackTricks**](https://github.com/carlospolop/hacktricks)和[**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github仓库提交PR来分享您的黑客技巧。
</details>
## 安装Frida
**在越狱设备上安装Frida的步骤**
1. 打开Cydia/Sileo应用。
2. 转到Manage -> Sources -> Edit -> Add。
3. 输入"https://build.frida.re"作为URL。
4. 进入新添加的Frida源。
5. 安装Frida软件包。
如果您使用**Corellium**,您需要从[https://github.com/frida/frida/releases](https://github.com/frida/frida/releases)下载Frida版本`frida-gadget-[yourversion]-ios-universal.dylib.gz`并解压缩并复制到Frida要求的dylib位置例如`/Users/[youruser]/.cache/frida/gadget-ios.dylib`
安装完成后您可以在PC上使用命令**`frida-ls-devices`**检查设备是否显示您的PC需要能够访问它。\
还可以执行**`frida-ps -Uia`**来检查手机的运行进程。
## 无需越狱设备和无需对应用程序打补丁的Frida
查看这篇关于如何在非越狱设备上使用Frida而无需对应用程序打补丁的博文[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客户端
安装**Frida工具**
```bash
pip install frida-tools
pip install frida
```
安装了Frida服务器并连接设备后**检查**客户端是否**正常工作**
```bash
frida-ls-devices # List devices
frida-ps -Uia # Get running processes
```
## Frida跟踪
```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 '*[* *]'
```
### 获取所有类和方法
* 自动完成:只需执行 `frida -U <program>`
<figure><img src="../../.gitbook/assets/image (687).png" alt=""><figcaption></figcaption></figure>
* 获取**所有**可用的**类**(按字符串过滤)
{% 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 %}
* 获取类的所有方法(按字符串过滤)
{% 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 %}
* **调用函数**
```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模糊测试
### Frida Stalker
[官方文档](https://frida.re/docs/stalker/#:~:text=Stalker%20is%20Frida's%20code%20tracing,every%20instruction%20which%20is%20executed.): Stalker是Frida的代码**追踪引擎**。它允许跟踪线程,**捕获**每个函数,**每个代码块**,甚至每个执行的指令。
你可以在[https://github.com/poxyran/misc/blob/master/frida-stalker-example.py](https://github.com/poxyran/misc/blob/master/frida-stalker-example.py)找到一个实现Frida Stalker的示例。
这是另一个示例每次调用函数时都会附加Frida Stalker
```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" %}
这对于调试目的很有趣,但对于模糊测试来说,不断地**`.follow()`**和**`.unfollow()`**是非常低效的。
{% endhint %}
## [Fpicker](https://github.com/ttdennis/fpicker)
[**fpicker**](https://github.com/ttdennis/fpicker) 是一个基于**Frida的模糊测试套件**提供各种模糊测试模式如AFL++模式或被动跟踪模式。它应该在所有Frida支持的平台上运行。
* [**安装 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
```
* **准备文件系统:**
```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脚本** (`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 %}
* **编译** fuzzer
```bash
# From inside fpicker clone
## Compile from "myfuzzer.js" to "harness.js"
frida-compile examples/wg-log/myfuzzer.js -o harness.js
```
* 使用 **`radamsa`** 调用模糊器 **`fpicker`**
{% 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" %}
在这种情况下,我们在每个有效负载之后**不重新启动应用程序或恢复状态**。因此如果Frida发现一个**崩溃**,那么在该有效负载之后的**下一个输入**可能也会**导致应用程序崩溃**(因为应用程序处于不稳定状态),即使**输入不应导致**应用程序崩溃。
此外Frida将钩入iOS的异常信号因此当**Frida发现崩溃**时,可能**不会生成iOS崩溃报告**。
为了防止这种情况例如我们可以在每次Frida崩溃后重新启动应用程序。
{% endhint %}
### 日志和崩溃
您可以检查**macOS控制台**或**`log`** cli来查看macOS日志。\
您还可以使用**`idevicesyslog`**来检查iOS的日志。\
一些日志将省略添加**`<private>`**的信息。要显示所有信息,您需要从[https://developer.apple.com/bug-reporting/profiles-and-logs/](https://developer.apple.com/bug-reporting/profiles-and-logs/)安装一些配置文件以启用私人信息。
如果您不知道该怎么办:
```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
```
您可以在以下位置检查崩溃情况:
- **iOS**
- 设置 → 隐私 → 分析与改进 → 分析数据
- `/private/var/mobile/Library/Logs/CrashReporter/`
- **macOS**:
- `/Library/Logs/DiagnosticReports/`
- `~/Library/Logs/DiagnosticReports`
{% hint style="warning" %}
iOS仅存储同一应用的25个崩溃情况因此您需要清理否则iOS将停止创建崩溃报告。
{% endhint %}
## Frida Android 教程
{% content-ref url="../android-app-pentesting/frida-tutorial/" %}
[frida-tutorial](../android-app-pentesting/frida-tutorial/)
{% endcontent-ref %}
## 参考资料
- [https://www.briskinfosec.com/blogs/blogsdetail/Getting-Started-with-Frida](https://www.briskinfosec.com/blogs/blogsdetail/Getting-Started-with-Frida)