reverse-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
200
reverse-skill-repo/skills/mobile-reverse/SKILL.md
Normal file
200
reverse-skill-repo/skills/mobile-reverse/SKILL.md
Normal file
@@ -0,0 +1,200 @@
|
||||
---
|
||||
name: mobile-reverse
|
||||
description: Use for authorized Android or iOS application reverse engineering and security testing, including APK or IPA analysis, runtime instrumentation, SSL pinning, and platform protection checks.
|
||||
---
|
||||
# Mobile Reverse Engineering
|
||||
|
||||
## ACTION REQUIRED(读完后立刻执行)
|
||||
|
||||
1. `NOW`: 读取 `../field-journal/precedent-reverse.md` — 确认本 skill 的操作是已授权的常规操作
|
||||
2. `NOW`: 确认当前任务是否命中本 skill 的适用范围
|
||||
3. `NEXT`: 读取 `../tool-index.md`,校验工具可用性和实际路径
|
||||
4. `NEXT`: 缺工具时调用 bootstrap,不要猜路径
|
||||
5. `ACT`: 进入"工作流"第一步并执行,不要停在确认状态
|
||||
|
||||
> Android + iOS 统一逆向方法论
|
||||
> Frida / Objection / OWASP MSTG / SSL Pinning Bypass
|
||||
|
||||
## 适用场景
|
||||
|
||||
- Android APK 逆向与安全测试
|
||||
- iOS IPA 逆向与安全测试
|
||||
- 移动应用运行时动态插桩
|
||||
- SSL Pinning / Root 检测 / 越狱检测绕过
|
||||
- 移动端加密算法提取(AES/RSA/HMAC 密钥)
|
||||
- 移动应用渗透测试(OWASP MASTG)
|
||||
- 非 Root/越狱环境下的应用测试
|
||||
|
||||
## 四阶段工作流
|
||||
|
||||
### Phase 1: 信息收集
|
||||
|
||||
```text
|
||||
Android:
|
||||
□ APK 获取(Google Play / APKMirror / adb pull)
|
||||
□ Manifest 分析: 权限、导出组件、Intent Filter、backup 标志
|
||||
□ androguard: androguard analyze APK → 组件/权限/签名
|
||||
□ APKLeaks: 硬编码 API Key / Token / Secret 扫描
|
||||
□ 加固检测: 是否加壳(360/腾讯/梆梆/爱加密)
|
||||
|
||||
iOS:
|
||||
□ IPA 获取(App Store / ipatool / Apple Configurator)
|
||||
□ 解密 App Store 二进制: frida-ios-dump / Clutch
|
||||
□ Info.plist 分析: ATS 配置、URL Scheme、Queries Schemes
|
||||
□ class-dump: 导出 ObjC 类结构
|
||||
□ 加固检测: 是否使用 Swift/ObjC 混淆
|
||||
```
|
||||
|
||||
### Phase 2: 静态分析
|
||||
|
||||
```text
|
||||
跨平台:
|
||||
□ JADX-GUI: APK → Java 源码(Android)
|
||||
□ Ghidra / Hopper: .so / Mach-O 反编译
|
||||
□ radare2 / Cutter: CLI 快速侦察
|
||||
|
||||
Android 专项:
|
||||
□ apktool d app.apk → smali 代码 + 资源
|
||||
□ dex2jar: DEX → JAR → JD-GUI
|
||||
□ smali/baksmali: Dalvik 字节码修改
|
||||
|
||||
iOS 专项:
|
||||
□ class-dump: 导出 ObjC 头文件
|
||||
□ Swift 符号恢复: swift-demangle
|
||||
□ dsymutil: 调试符号提取
|
||||
□ otool -L: 查看动态库依赖
|
||||
□ jtool2: Mach-O 分析
|
||||
```
|
||||
|
||||
### Phase 3: 动态分析
|
||||
|
||||
```text
|
||||
Frida — 通用动态插桩:
|
||||
□ frida-ps -U: 列出设备进程
|
||||
□ frida-trace -U -i "open*" com.app: 追踪函数调用
|
||||
□ 自定义 Hook 脚本: 修改参数/返回值、调用私有方法
|
||||
|
||||
Objection — Frida 增强层(无需写脚本):
|
||||
□ objection -g "com.app" explore
|
||||
□ android root disable / ios jailbreak disable
|
||||
□ android sslpinning disable / ios sslpinning disable
|
||||
□ android keystore list / ios keychain dump
|
||||
□ env / ls / sqlite connect
|
||||
|
||||
Frida Gadget(免 Root/越狱):
|
||||
□ 注入 frida-gadget.so / FridaGadget.dylib 到 APK/IPA
|
||||
□ 重新签名 → 安装 → 无需设备权限即可 Hook
|
||||
□ objection patchapk --source app.apk(全自动)
|
||||
```
|
||||
|
||||
### Phase 4: 网络分析
|
||||
|
||||
```text
|
||||
□ Burp Suite: 拦截 HTTP/HTTPS,修改请求/响应
|
||||
□ mitmproxy: 脚本化代理(Python API)
|
||||
□ Wireshark: PCAP 抓包分析
|
||||
□ 证书安装: Android 用户证书 → 系统证书(Magisk + MoveCert)
|
||||
□ SSL Pinning 绕过: Frida/Objection/Xposed/SSL Kill Switch 2
|
||||
□ WebSocket / gRPC 流量分析
|
||||
```
|
||||
|
||||
## 常见绕过速查
|
||||
|
||||
### SSL Pinning
|
||||
|
||||
```bash
|
||||
# Objection(最简)
|
||||
objection -g "com.app" explore
|
||||
android sslpinning disable
|
||||
|
||||
# Frida 通用脚本
|
||||
frida -U -l ssl_pinning_bypass.js -f com.app
|
||||
|
||||
# Xposed(Android)
|
||||
TrustMeAlready 模块 → 全局禁用证书校验
|
||||
```
|
||||
|
||||
### Root / 越狱检测
|
||||
|
||||
```bash
|
||||
# Objection
|
||||
android root disable
|
||||
ios jailbreak disable
|
||||
|
||||
# Frida 自定义(多层检测)
|
||||
Java.perform(function() {
|
||||
var RootBeer = Java.use("com.scottyab.rootbeer.RootBeer");
|
||||
RootBeer.isRooted.implementation = function() { return false; };
|
||||
// 额外绕过: Magisk su 检测、frida-server 检测、/proc/self/maps 检测
|
||||
});
|
||||
```
|
||||
|
||||
### 反调试
|
||||
|
||||
```bash
|
||||
# Android
|
||||
frida -U -l anti_debug_bypass.js -f com.app
|
||||
# 绕过: ptrace(TracerPid)、/proc/self/status、isDebuggerConnected()
|
||||
|
||||
# iOS
|
||||
# 绕过: PT_DENY_ATTACH、sysctl CTL_KERN/KERN_PROC/KERN_PROC_PID
|
||||
frida -U -l ios_anti_debug.js -f com.app
|
||||
```
|
||||
|
||||
## 移动端加密提取
|
||||
|
||||
```javascript
|
||||
// Android — Hook Cipher.getInstance 获取密钥+算法
|
||||
Java.perform(function() {
|
||||
var Cipher = Java.use("javax.crypto.Cipher");
|
||||
Cipher.getInstance.overload('java.lang.String').implementation = function(algo) {
|
||||
console.log("[Cipher] Algorithm: " + algo);
|
||||
return this.getInstance(algo);
|
||||
};
|
||||
Cipher.init.overload('int', 'java.security.Key').implementation = function(mode, key) {
|
||||
console.log("[Cipher] Key: " + bytesToHex(key.getEncoded()));
|
||||
return this.init(mode, key);
|
||||
};
|
||||
});
|
||||
|
||||
// iOS — Hook CCCrypt
|
||||
Interceptor.attach(Module.findExportByName("libcommonCrypto.dylib", "CCCrypt"), {
|
||||
onEnter: function(args) {
|
||||
console.log("CCCrypt op: " + args[0] + " alg: " + args[1]);
|
||||
console.log("Key: " + hexdump(args[3], { length: args[4].toInt32() }));
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 工具链
|
||||
|
||||
| 工具 | 平台 | 用途 |
|
||||
|------|:--:|------|
|
||||
| JADX-GUI | A | Java 反编译 |
|
||||
| apktool | A | APK 解包/重建 |
|
||||
| Ghidra | A+I | 多架构反编译 |
|
||||
| Hopper | I | iOS 专用反汇编 |
|
||||
| Frida | A+I | 动态插桩 |
|
||||
| Objection | A+I | Frida REPL 增强 |
|
||||
| MobSF | A+I | 自动化 SAST+DAST |
|
||||
| class-dump | I | ObjC 类导出 |
|
||||
| frida-ios-dump | I | IPA 解密 |
|
||||
| jtool2 | I | Mach-O 分析 |
|
||||
| Burp Suite | A+I | HTTP 拦截 |
|
||||
| mitmproxy | A+I | 脚本化代理 |
|
||||
|
||||
> A=Android, I=iOS
|
||||
|
||||
## 参考
|
||||
|
||||
- `references/frida-objection-deep.md` — Frida + Objection 深度用法
|
||||
- `references/ios-reverse-guide.md` — iOS 逆向专项
|
||||
- `references/anti-detection-bypass.md` — Root/越狱/反调试/SSL Pinning 绕过
|
||||
|
||||
|
||||
## 任务完成自检(声称完成前 MUST 通过)
|
||||
|
||||
- [ ] 我是否执行了工作流中的每一步(而不是只阅读)?
|
||||
- [ ] 我是否基于 `tool-index` 使用了真实工具路径?
|
||||
- [ ] 我是否产出了可复现证据(命令/脚本/截图/报告)?
|
||||
- [ ] 我是否完成并回写了 RULES 要求的 Checklist 项?
|
||||
@@ -0,0 +1,182 @@
|
||||
# Root / 越狱 / 反调试 / SSL Pinning 绕过
|
||||
|
||||
## 检测层次模型
|
||||
|
||||
```
|
||||
Layer 1: 静态检测(安装时/启动时)
|
||||
├─ 包管理器检测(Cydia, apt, Magisk)
|
||||
├─ 文件检测(su, busybox, frida-server)
|
||||
└─ 权限检测(ro.debuggable, ro.secure)
|
||||
|
||||
Layer 2: 运行时检测(持续)
|
||||
├─ 进程检测(frida-server, magiskd)
|
||||
├─ 端口检测(27042 frida default)
|
||||
├─ 内存检测(/proc/self/maps 注入痕迹)
|
||||
└─ 堆栈检测(Frida 调用帧)
|
||||
|
||||
Layer 3: 环境检测(按需触发)
|
||||
├─ ptrace 检测(TracerPid)
|
||||
├─ /proc/self/status 检测
|
||||
├─ build.prop 检测(test-keys)
|
||||
└─ syscall 直接检测(绕过 libc)
|
||||
```
|
||||
|
||||
## Android Root 检测绕过
|
||||
|
||||
### 常见检测库及绕过
|
||||
|
||||
| 检测库 | 检测方法 | 绕过方式 |
|
||||
|--------|---------|---------|
|
||||
| RootBeer | 8 种检测组合 | Hook 每个检测方法返回 false |
|
||||
| SafetyNet | Google Play Services 远程认证 | 使用 Magisk Hide / Shamiko / Play Integrity Fix |
|
||||
| Google Play Integrity | 替换 SafetyNet | Trickystore + PIF |
|
||||
| 自定义 native 检测 | syscall 读取 /proc/self/status | Hook syscall 或修改 /proc 挂载 |
|
||||
|
||||
### Frida 综合绕过
|
||||
|
||||
```javascript
|
||||
Java.perform(function() {
|
||||
// RootBeer
|
||||
var RootBeer = Java.use("com.scottyab.rootbeer.RootBeer");
|
||||
var methods = ["isRooted", "isRootedWithBusyBox", "checkSuExists",
|
||||
"detectRootManagementApps", "detectPotentiallyDangerousApps",
|
||||
"detectTestKeys", "checkForDangerousProps", "checkForRWPaths"];
|
||||
methods.forEach(function(m) {
|
||||
RootBeer[m].implementation = function() { return false; };
|
||||
});
|
||||
|
||||
// 通用 Build.TAGS 检测
|
||||
var Build = Java.use("android.os.Build");
|
||||
var original = Build.TAGS.value;
|
||||
Build.TAGS.value = "release-keys";
|
||||
|
||||
// PackageManager → 隐藏包名
|
||||
var PackageManager = Java.use("android.content.pm.PackageManager");
|
||||
PackageManager.getPackageInfo.overload('java.lang.String', 'int').implementation = function(pkg, flags) {
|
||||
if (pkg == "de.robv.android.xposed.installer" ||
|
||||
pkg.includes("magisk") || pkg.includes("frida")) {
|
||||
throw Java.use("android.content.pm.PackageManager$NameNotFoundException").$new();
|
||||
}
|
||||
return this.getPackageInfo(pkg, flags);
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
## iOS 越狱检测绕过
|
||||
|
||||
### 多层 Frida Hook
|
||||
|
||||
```javascript
|
||||
// 1. 文件系统检测
|
||||
var NSFileManager = ObjC.classes.NSFileManager;
|
||||
var paths = [
|
||||
"/Applications/Cydia.app", "/var/lib/apt", "/bin/bash",
|
||||
"/usr/sbin/sshd", "/etc/apt", "/Library/MobileSubstrate"
|
||||
];
|
||||
// Hook fileExistsAtPath 返回 NO
|
||||
|
||||
// 2. fork 检测(沙箱内禁止)
|
||||
var fork_ptr = Module.findExportByName("libSystem.B.dylib", "fork");
|
||||
Interceptor.replace(fork_ptr, new NativeCallback(function() {
|
||||
return -1;
|
||||
}, 'int', []));
|
||||
|
||||
// 3. Scheme 检测
|
||||
// 通过 MobileSubstrate hook
|
||||
var LSApplicationWorkspace = ObjC.classes.LSApplicationWorkspace;
|
||||
// Hook defaultWorkspace → canOpenURL → 对 cydia:// 返回 NO
|
||||
|
||||
// 4. 签名检测
|
||||
var MISValidateSignature = Module.findExportByName(null, "MISValidateSignature");
|
||||
Interceptor.attach(MISValidateSignature, {
|
||||
onLeave: function(retval) { retval.replace(0); }
|
||||
});
|
||||
```
|
||||
|
||||
## 反调试绕过
|
||||
|
||||
### Android
|
||||
|
||||
```javascript
|
||||
// 1. ptrace 自身 → 防止附加
|
||||
// Native: ptrace(PTRACE_TRACEME, 0, NULL, 0)
|
||||
// 绕过: Hook ptrace → 返回 0
|
||||
|
||||
// 2. TracerPid 检测
|
||||
// /proc/self/status → TracerPid: 0
|
||||
var fopen = Module.findExportByName(null, "fopen");
|
||||
Interceptor.attach(fopen, {
|
||||
onEnter: function(args) {
|
||||
this.path = Memory.readUtf8String(args[0]);
|
||||
},
|
||||
onLeave: function(retval) {
|
||||
if (this.path && this.path.includes("status")) {
|
||||
// 修改返回的 FILE*,返回伪造内容
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 3. isDebuggerConnected (Java)
|
||||
var Debug = Java.use("android.os.Debug");
|
||||
Debug.isDebuggerConnected.implementation = function() { return false; };
|
||||
```
|
||||
|
||||
### iOS
|
||||
|
||||
```javascript
|
||||
// 1. PT_DENY_ATTACH
|
||||
// ptrace(PT_DENY_ATTACH, 0, NULL, 0) → 防止调试器附加
|
||||
var ptrace = Module.findExportByName(null, "ptrace");
|
||||
Interceptor.replace(ptrace, new NativeCallback(function(request, pid, addr, data) {
|
||||
if (request == 31) return 0; // PT_DENY_ATTACH → 忽略
|
||||
return ptrace(request, pid, addr, data);
|
||||
}, 'int', ['int', 'int', 'pointer', 'int']));
|
||||
|
||||
// 2. sysctl 检测
|
||||
var sysctl = Module.findExportByName(null, "sysctl");
|
||||
Interceptor.attach(sysctl, {
|
||||
onLeave: function(retval) {
|
||||
// 修改 kinfo_proc 的 p_flag 字段 → 清除 P_TRACED
|
||||
}
|
||||
});
|
||||
|
||||
// 3. getppid 检测(检查父进程是否为 launchd)
|
||||
// 调试时 getppid() != 1
|
||||
```
|
||||
|
||||
## SSL Pinning 绕过
|
||||
|
||||
### Android 五层绕过
|
||||
|
||||
```text
|
||||
层 1 — TrustManager: 接受所有证书
|
||||
层 2 — OkHttp CertificatePinner: Hook 清空 pins 列表
|
||||
层 3 — WebView SSL Error Handler: 忽略证书错误
|
||||
层 4 — Network Security Config: 修改 xml → 信任用户证书
|
||||
层 5 — Native SSL (OpenSSL/BoringSSL): Hook SSL_get_verify_result → X509_V_OK
|
||||
```
|
||||
|
||||
### iOS 四层绕过
|
||||
|
||||
```text
|
||||
层 1 — NSURLSession: Hook SecTrustEvaluate → kSecTrustResultProceed
|
||||
层 2 — Alamofire: Hook ServerTrustManager
|
||||
层 3 — AFNetworking: Hook AFSecurityPolicy
|
||||
层 4 — libcurl: LD_PRELOAD 替换 SSL 验证回调
|
||||
```
|
||||
|
||||
### 通用 Objection 命令
|
||||
|
||||
```bash
|
||||
# Android
|
||||
objection -g "com.app" explore
|
||||
android sslpinning disable
|
||||
# 等价于: 自动 Hook 上述 5 层
|
||||
|
||||
# iOS
|
||||
objection -g "com.app" explore
|
||||
ios sslpinning disable
|
||||
# 等价于: 自动 Hook 上述 4 层
|
||||
```
|
||||
|
||||
Source: OWASP MSTG, Frida CodeShare, objection wiki
|
||||
@@ -0,0 +1,218 @@
|
||||
# Frida + Objection 深度用法
|
||||
|
||||
## Frida 核心 API
|
||||
|
||||
### Java 运行时 (Android)
|
||||
|
||||
```javascript
|
||||
Java.perform(function() {
|
||||
// 获取类实例
|
||||
var String = Java.use("java.lang.String");
|
||||
|
||||
// Hook 静态方法
|
||||
var System = Java.use("java.lang.System");
|
||||
System.getProperty.overload('java.lang.String').implementation = function(key) {
|
||||
console.log("System.getProperty: " + key);
|
||||
return this.getProperty(key);
|
||||
};
|
||||
|
||||
// Hook 构造函数
|
||||
var File = Java.use("java.io.File");
|
||||
File.$init.overload('java.lang.String').implementation = function(path) {
|
||||
console.log("File opened: " + path);
|
||||
return this.$init(path);
|
||||
};
|
||||
|
||||
// 枚举已加载类
|
||||
Java.enumerateLoadedClasses({
|
||||
onMatch: function(className) { console.log(className); },
|
||||
onComplete: function() {}
|
||||
});
|
||||
|
||||
// 修改返回值
|
||||
var RootDetector = Java.use("com.app.security.RootDetector");
|
||||
RootDetector.isDeviceRooted.implementation = function() {
|
||||
return false;
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
### Native 层 (Android + iOS)
|
||||
|
||||
```javascript
|
||||
// Hook 导出函数
|
||||
Interceptor.attach(Module.findExportByName(null, "open"), {
|
||||
onEnter: function(args) {
|
||||
this.path = Memory.readUtf8String(args[0]);
|
||||
},
|
||||
onLeave: function(retval) {
|
||||
console.log("open(" + this.path + ") = " + retval);
|
||||
}
|
||||
});
|
||||
|
||||
// Hook 任意地址(通过偏移)
|
||||
var base = Module.findBaseAddress("libnative.so");
|
||||
var target = base.add(0x12345);
|
||||
Interceptor.attach(target, {
|
||||
onEnter: function(args) {
|
||||
console.log("Function called from: " + Thread.backtrace(this.context, Backtracer.ACCURATE)
|
||||
.map(DebugSymbol.fromAddress).join('\n'));
|
||||
}
|
||||
});
|
||||
|
||||
// 修改返回值
|
||||
Interceptor.attach(Module.findExportByName(null, "strcmp"), {
|
||||
onLeave: function(retval) {
|
||||
if (retval.toInt32() === 0) return; // strings equal, skip
|
||||
// Force match
|
||||
retval.replace(0);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### ObjC 运行时 (iOS)
|
||||
|
||||
```javascript
|
||||
// Hook ObjC 方法
|
||||
var hook = ObjC.classes.ViewController["- viewDidLoad"];
|
||||
Interceptor.attach(hook.implementation, {
|
||||
onEnter: function(args) {
|
||||
console.log("viewDidLoad called");
|
||||
}
|
||||
});
|
||||
|
||||
// 枚举所有类
|
||||
ObjC.enumerateLoadedClasses({
|
||||
onMatch: function(className) { console.log(className); },
|
||||
onComplete: function() {}
|
||||
});
|
||||
|
||||
// 调用 ObjC 方法
|
||||
var NSString = ObjC.classes.NSString;
|
||||
var str = NSString.stringWithString_("Hello from Frida");
|
||||
```
|
||||
|
||||
## Objection 命令速查
|
||||
|
||||
### 通用
|
||||
|
||||
```bash
|
||||
objection -g "com.app" explore # 启动
|
||||
objection -g "com.app" explore -q # 静默启动(只注入不等待)
|
||||
objection patchapk --source app.apk # 自动注入 Frida Gadget
|
||||
objection signapk --source app.apk # 仅签名
|
||||
|
||||
# 文件系统
|
||||
env # 应用数据目录
|
||||
ls # 列出文件
|
||||
file download /path/to/file # 下载文件
|
||||
file upload local.txt /remote/path # 上传文件
|
||||
|
||||
# SQLite
|
||||
sqlite connect /path/to/db.sqlite
|
||||
.tables # 列出表
|
||||
select * from users; # 查询
|
||||
```
|
||||
|
||||
### Android 专用
|
||||
|
||||
```bash
|
||||
android root disable # 绕过 Root 检测
|
||||
android sslpinning disable # 绕过 SSL Pinning
|
||||
android hooking list classes # 枚举类
|
||||
android hooking list class_methods com.app.Main # 枚举方法
|
||||
android hooking watch class com.app.Main # Hook 所有方法
|
||||
android intent launch_activity com.app.MainActivity # 启动 Activity
|
||||
android heap search instances com.app.User # 堆搜索
|
||||
android keystore list # Keystore 条目
|
||||
```
|
||||
|
||||
### iOS 专用
|
||||
|
||||
```bash
|
||||
ios jailbreak disable # 绕过越狱检测
|
||||
ios sslpinning disable # 绕过 SSL Pinning
|
||||
ios keychain dump # 导出 Keychain
|
||||
ios nsuserdefaults get # NSUserDefaults
|
||||
ios nsurlcache dump # HTTP 缓存
|
||||
ios cookies get # 读取 Cookies
|
||||
ios pasteboard monitor # 监听剪贴板
|
||||
ios ui dump # UI 层次结构
|
||||
ios plist cat Info.plist # 读取 plist
|
||||
```
|
||||
|
||||
## 免 Root/越狱部署
|
||||
|
||||
### Android — Frida Gadget 注入
|
||||
|
||||
```bash
|
||||
# 1. 解包 APK
|
||||
apktool d app.apk -o app_unpacked
|
||||
|
||||
# 2. 下载 frida-gadget 并放入 lib 目录
|
||||
cp frida-gadget-17.x.x-android-arm64.so \
|
||||
app_unpacked/lib/arm64-v8a/libfrida-gadget.so
|
||||
|
||||
# 3. 在 smali 中注入 System.loadLibrary("frida-gadget")
|
||||
# 修改主 Activity 的 onCreate 或 attachBaseContext
|
||||
|
||||
# 4. 重建并签名
|
||||
apktool b app_unpacked -o app_patched.apk
|
||||
uber-apk-signer -a app_patched.apk
|
||||
|
||||
# 5. Objection 自动化
|
||||
objection patchapk --source app.apk --skip-resources
|
||||
```
|
||||
|
||||
### iOS — Frida Gadget 注入
|
||||
|
||||
```bash
|
||||
# 1. 解密 App Store IPA
|
||||
python3 frida-ios-dump.py -u -p com.app.target
|
||||
|
||||
# 2. 注入 FridaGadget.dylib
|
||||
# 修改 Mach-O Load Commands,添加 @executable_path/FridaGadget.dylib
|
||||
|
||||
# 3. 重签名
|
||||
codesign -f -s "Apple Development" Payload/App.app
|
||||
|
||||
# 4. 通过 Xcode sideload 或 AltStore 安装
|
||||
```
|
||||
|
||||
## SSL Pinning 绕过进阶
|
||||
|
||||
### 多层绕过(Android)
|
||||
|
||||
```javascript
|
||||
// 1. OkHttp CertificatePinner
|
||||
var CertificatePinner = Java.use("okhttp3.CertificatePinner");
|
||||
CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function() {};
|
||||
|
||||
// 2. TrustManager 自定义
|
||||
var TrustManagerImpl = Java.use("com.android.org.conscrypt.TrustManagerImpl");
|
||||
TrustManagerImpl.verifyChain.implementation = function() { return []; };
|
||||
|
||||
// 3. WebView SSL Error
|
||||
var SslErrorHandler = Java.use("android.webkit.SslErrorHandler");
|
||||
SslErrorHandler.proceed.implementation = function() { return this.proceed(); };
|
||||
|
||||
// 4. Network Security Config
|
||||
// 需要修改 AndroidManifest.xml → android:networkSecurityConfig="@xml/network_security_config"
|
||||
// xml 中添加信任用户证书
|
||||
```
|
||||
|
||||
### 多层绕过(iOS)
|
||||
|
||||
```javascript
|
||||
// 1. NSURLSession
|
||||
var SecTrustEvaluate = Module.findExportByName("Security", "SecTrustEvaluate");
|
||||
Interceptor.replace(SecTrustEvaluate, new NativeCallback(function(trust, result) {
|
||||
Memory.writeU32(result, 1); // kSecTrustResultProceed = 1
|
||||
return 0; // errSecSuccess
|
||||
}, 'int', ['pointer', 'pointer']));
|
||||
|
||||
// 2. Alamofire
|
||||
// Hook ServerTrustManager.evaluate → 始终返回 success
|
||||
```
|
||||
|
||||
Source: Frida docs, Objection wiki, OWASP MSTG
|
||||
@@ -0,0 +1,177 @@
|
||||
# iOS 逆向工程专项
|
||||
|
||||
## IPA 获取与解密
|
||||
|
||||
```bash
|
||||
# 从 App Store 下载
|
||||
ipatool search "Target App"
|
||||
ipatool purchase -b com.target.app
|
||||
ipatool download -b com.target.app -o app.ipa
|
||||
|
||||
# 从设备提取已安装应用
|
||||
# 越狱设备
|
||||
scp root@device:/private/var/containers/Bundle/Application/*/Target.app .
|
||||
|
||||
# 解密(App Store 二进制为加密 FAT 格式)
|
||||
# frida-ios-dump(推荐)
|
||||
python3 dump.py com.target.app -o decrypted.ipa
|
||||
|
||||
# Clutch
|
||||
Clutch -i # 列出已安装
|
||||
Clutch -d 1 # 解密第 1 个
|
||||
|
||||
# dumpdecrypted
|
||||
DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /path/to/App
|
||||
```
|
||||
|
||||
## Mach-O 分析
|
||||
|
||||
```bash
|
||||
# 基本信息
|
||||
otool -l TargetBinary | grep crypt # 加密状态
|
||||
otool -L TargetBinary # 动态库依赖
|
||||
otool -hv TargetBinary # 头部信息
|
||||
jtool2 --pages TargetBinary # 内存页信息
|
||||
|
||||
# Fat Binary 瘦身
|
||||
lipo -info TargetBinary
|
||||
lipo TargetBinary -thin arm64 -output TargetBinary_arm64
|
||||
|
||||
# 符号分析
|
||||
nm -g TargetBinary # 导出符号
|
||||
nm -a TargetBinary # 全部符号
|
||||
swift-demangle <mangled_name> # Swift 符号还原
|
||||
|
||||
# class-dump
|
||||
class-dump -H TargetBinary -o headers/
|
||||
# 导出 ObjC 类及方法声明到 headers/ 目录
|
||||
```
|
||||
|
||||
## Objective-C 运行时分析
|
||||
|
||||
```text
|
||||
消息传递机制:
|
||||
objc_msgSend(id self, SEL op, ...) → 动态方法派发
|
||||
↓
|
||||
运行时查找:
|
||||
1. 类方法列表 cache
|
||||
2. 类方法列表
|
||||
3. 逐级父类查找
|
||||
4. +resolveInstanceMethod / +resolveClassMethod
|
||||
5. forwardingTargetForSelector
|
||||
6. methodSignatureForSelector + forwardInvocation
|
||||
```
|
||||
|
||||
### Frida ObjC Hook
|
||||
|
||||
```javascript
|
||||
// Hook 实例方法
|
||||
var hook = ObjC.classes.ClassName["- instanceMethod:"];
|
||||
Interceptor.attach(hook.implementation, {
|
||||
onEnter: function(args) {
|
||||
// args[0] = self, args[1] = selector, args[2+] = method args
|
||||
console.log("self: " + new ObjC.Object(args[0]));
|
||||
console.log("arg: " + args[2].toInt32());
|
||||
}
|
||||
});
|
||||
|
||||
// Hook 类方法
|
||||
var hook = ObjC.classes.ClassName["+ classMethod:"];
|
||||
Interceptor.attach(hook.implementation, { ... });
|
||||
|
||||
// 调用 ObjC 方法
|
||||
var NSString = ObjC.classes.NSString;
|
||||
var str = NSString.stringWithString_("test");
|
||||
console.log(str.UTF8String());
|
||||
```
|
||||
|
||||
## Swift 逆向
|
||||
|
||||
```text
|
||||
Swift 名称修饰(Name Mangling):
|
||||
$s10ModuleName5ClassC6method3argSi_tF
|
||||
│ │ │ │ │ │ │ └─ 参数类型
|
||||
│ │ │ │ │ │ └───── 返回类型
|
||||
│ │ │ │ │ └──────── 参数名
|
||||
│ │ │ │ └─────────────── 方法名
|
||||
│ │ │ └──────────────── 类名(长度+名称)
|
||||
│ │ └────────────────────── 模块名
|
||||
│ └──────────────────────────────── 标识符标识
|
||||
└────────────────────────────────── 全局标识
|
||||
|
||||
工具: swift-demangle, Hopper (自动还原)
|
||||
```
|
||||
|
||||
## 越狱检测绕过
|
||||
|
||||
```text
|
||||
检测方法分类:
|
||||
|
||||
1. 文件系统检查:
|
||||
□ /Applications/Cydia.app
|
||||
□ /var/lib/apt/
|
||||
□ /bin/bash
|
||||
□ /usr/sbin/sshd
|
||||
→ Hook NSFileManager.fileExistsAtPath:
|
||||
|
||||
2. 沙箱逃逸检测:
|
||||
□ fork() 是否成功(沙箱内禁止)
|
||||
□ system() 调用
|
||||
→ Hook fork → 返回 -1
|
||||
|
||||
3. Dyld 注入检测:
|
||||
□ _dyld_get_image_count > 限制值
|
||||
→ 限制返回值在合理范围
|
||||
|
||||
4. Scheme 检测:
|
||||
□ cydia:// URL Scheme
|
||||
→ Hook UIApplication.canOpenURL:
|
||||
|
||||
5. sysctl 检测:
|
||||
□ CTL_KERN/KERN_PROC/KERN_PROC_PID → kinfo_proc
|
||||
→ Hook sysctl → 清空 p_flag P_TRACED 位
|
||||
```
|
||||
|
||||
### Frida 统一绕过脚本
|
||||
|
||||
```javascript
|
||||
// 文件检测绕过
|
||||
var NSFileManager = ObjC.classes.NSFileManager;
|
||||
var defaultManager = NSFileManager.defaultManager();
|
||||
Interceptor.attach(defaultManager["- fileExistsAtPath:"].implementation, {
|
||||
onLeave: function(retval) {
|
||||
var path = ObjC.Object(args[2]).toString();
|
||||
if (path.includes("Cydia") || path.includes("apt") ||
|
||||
path.includes("sshd") || path.includes("bash")) {
|
||||
retval.replace(0); // false
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// fork 绕过
|
||||
Interceptor.replace(Module.findExportByName(null, "fork"),
|
||||
new NativeCallback(function() { return -1; }, 'int', []));
|
||||
|
||||
// dyld 绕过
|
||||
var _dyld_get_image_count = Module.findExportByName(null, "_dyld_get_image_count");
|
||||
Interceptor.attach(_dyld_get_image_count, {
|
||||
onLeave: function(retval) {
|
||||
if (retval.toInt32() > 200) retval.replace(200);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 关键防护绕过清单
|
||||
|
||||
| 防护 | iOS 绕过方法 |
|
||||
|------|-------------|
|
||||
| App Store 加密 | frida-ios-dump / Clutch |
|
||||
| SSL Pinning | Objection `ios sslpinning disable` / SSL Kill Switch 2 |
|
||||
| 越狱检测 | Objection `ios jailbreak disable` / 自定义 Frida Hook |
|
||||
| 反调试 (PT_DENY_ATTACH) | Frida 启动后注入 / debugserver |
|
||||
| 完整性校验 | Hook MAC 检查 / 代码签名验证 |
|
||||
| 反注入 | 修改 Mach-O 去除 __RESTRICT 段 |
|
||||
| Swift 混淆 | swift-demangle + LLM 辅助语义恢复 |
|
||||
| 屏幕截图防护 | Hook UIScreen.mainScreen.snapshotViewAfterScreenUpdates |
|
||||
|
||||
Source: OWASP MSTG, frida-ios-dump, The iPhone Wiki
|
||||
Reference in New Issue
Block a user