reverse-skills-max: initial public release (restored, redacted, hardened)

This commit is contained in:
baradok609hecl1pq6qi
2026-10-20 02:17:15 +03:00
commit da24c2bd20
2227 changed files with 443931 additions and 0 deletions

View File

@@ -0,0 +1,119 @@
---
name: re-macos
type: atomic
description: >
macOS 原生应用逆向:App Bundle/签名公证、entitlements、沙箱与 TCC、钥匙串与 Secure Enclave。
触发词:macOS逆向、mac app、entitlements、Secure Enclave、钥匙串、TCC、codesign、公证。
capabilities: [macho-parser]
---
# macOS 应用逆向
## 何时使用 / 何时不用
- 用:macOS 原生/闭源应用(.app/.dylib/.framework)、带签名公证与沙箱的目标、钥匙串/Secure Enclave 硬件密钥场景
- 用:授权/分发状态判定——签名者、公证、hardened runtime、Team ID 是谁(分发面/信任面分析)
- 用:信任链问题——Dylib Hijacking、注入面、TCC 依赖(哪些隐私能力被请求/使用)
- 不用:iOS 应用(转 [[re-ios]]);纯 Mach-O 格式解析(转 [[re-format-macho]])
- 不用:Linux/Windows 目标(各走 [[re-gdb]] / [[re-x64dbg]])
- 不用:只想抓网络流量/文件行为(无 macOS 特有面时走 [[re-behavior]] / [[re-netcap]] 通用路径)
- 注意:TCC 与钥匙串数据属系统隐私范畴,只读分析不导出内容(红线)
## 工具准备
### codesign / spctl / otool / lipo(签名与 Mach-O 工具,macOS 内置)
- macOS: 系统自带(Xcode 命令行工具 `xcode-select --install`)
- Linux: 可静态分析 Mach-O(`llvm-otool`,`brew install llvm` 或发行版 llvm 包),签名解析受限
- 验证: `codesign --version`、macOS: `otool --version`;Linux: `llvm-otool --version`
### plutil / xattr(Info.plist 与 quarantine 检查,macOS 内置)
- 验证: `plutil -help`、`xattr -h`
- 用途: Info.plist 键解析(`plutil -p`);`com.apple.quarantine` 扩展属性决定 Gatekeeper 是否拦截
### Hopper / IDA / Ghidra(反编译底座)
- 安装与验证见 [[re-ida]] / [[re-ghidra]]
### lldb(动态调试)
- 安装与验证见 [[re-lldb]];attach 前先处理 PT_DENY_ATTACH(步骤 6)
## 操作步骤
按顺序执行,每步产物存档(路径 + sha256,见 [[re-triage]])。签名/entitlements 信息按 [[re-analyze/analysis-contract]] 契约记录。
1. **包结构与签名检查**:
```sh
file Sample.app/Contents/MacOS/Sample
codesign -dv Sample.app 2>&1 | head # 签名者/Team ID(要求需 `-d -r-` 查看)
spctl -a -vv Sample.app 2>&1 # 公证状态(Gatekeeper)
defaults read Sample.app/Contents/Info.plist # Info.plist 关键键
```
- 关注:签名者(Apple 开发者/分发证书)、Team ID、CDHash、Hardened Runtime(runtime 标志)、Info.plist 的 CFBundleIdentifier/版本/最低系统版本
- 架构确认:`file` 输出/x86_64 与 arm64 通用二进制(`lipo -archs`)——决定反编译与动态环境(Apple Silicon 上 arm64e 有 PAC 差异,见 [[gotchas]])
- 公证派生检查:`spctl -a` 通过不保证本地有 staple——`xcrun stapler validate Sample.app` 查票证是否随包
- 隔离属性检查:`xattr -l Sample.app` 看 `com.apple.quarantine`(隔离标志 + 时间戳 + 责任方 App;**不含来源 URL**——来源信息在 Spotlight 属性里,用 `mdls -name kMDItemWhereFroms Sample.app` 查)
2. **entitlements 与沙箱**:
```sh
codesign -d --entitlements :- Sample.app 2>&1 | head -30
```
- 关键键分组:`com.apple.security.app-sandbox`(沙箱总开关)、`network.client/server`(网络)、`files.user-selected.*`(用户选文件)、`device.camera/microphone`(设备)、`application-groups`(组共享)、`cs.allow-dyld-environment-variables` / `cs.disable-library-validation`(注入面)、`get-task-allow`(调试权限,发布版不应有)
- 沙箱 profile 决定能力边界——分析授权逻辑与攻击面时先看 entitlements 清单,动态行为再交叉验证
- 异常信号:发布版带 `get-task-allow`(本应只用于开发调试)或越权组合(如无 UI 却开 `device.camera`)——记录为可疑项进结论
3. **TCC 权限库**:
```sh
# 用户级 TCC 库(授权记录)
ls ~/Library/Application\ Support/com.apple.TCC/
# 系统级 TCC 库
ls /Library/Application\ Support/com.apple.TCC/
```
- 前置检查:TCC.db 自身受 TCC 保护——无 Full Disk Access 时读取会权限失败,先确认授权再读
- TCC.db(SQLite)记录各 App 对隐私资源的授权;分析目标对 TCC 的依赖(请求了什么权限、何时请求、失败路径)
- 注意:TCC 数据属系统隐私数据,只读分析不导出内容(红线)
4. **钥匙串与 Secure Enclave**:
- 钥匙串条目类型(通用密码/互联网密码/密钥)与访问条件——`kSecAttrAccessible` 是**可访问性**(设备处于什么状态时可读:非锁定/首次解锁/此设备),**不是 ACL**;访问控制是 `kSecAttrAccessControl`/`SecAccessControl`(生物识别/密码门槛),macOS 传统 ACL 另有 `SecAccess`/`kSecAttrAccess`(见 [[gotchas]])
- Secure Enclave 密钥:用 `SecKeyCreateRandomKey`(属性含 `kSecAttrTokenID: kSecAttrTokenIDSecureEnclave`)在设备内生成——`SecKeyCreateWithData` 是从外部 key data 导入/恢复,SE 私钥永不出芯片、无法导入,别把它当 SE 生成接口;私钥**不可提取**(等价 Android Keystore 硬件背书,见 [[re-android-native]] Keystore 审计)
- 分析:目标读哪些钥匙串条目(SecItemCopyMatching 调用点)、密钥是否 Secure Enclave 绑定(不可提取 → 记录用途与访问条件而非找字节)
5. **dyld 加载链**:
```sh
otool -L Sample.app/Contents/MacOS/Sample | head # LC_LOAD_DYLIB 依赖
otool -l Sample.app/Contents/MacOS/Sample | grep -A4 LC_RPATH
```
- 依赖清单与 RPATH → Dylib Hijacking 面(可写目录 + 缺失依赖组合)
- 注入面:DYLD_INSERT_LIBRARIES 受 hardened runtime 限制——entitlements 无 `cs.allow-dyld-environment-variables` 时不生效;system 完整性保护下对系统路径注入无效
- 注入验证:环境变量 + 沙箱内试跑 `DYLD_INSERT_LIBRARIES=/path/to/hook.dylib ./Sample`,无效即回到静态路径([[re-ghidra]]),不硬注入
6. **反调试与保护**:
- 调试器检测:`PT_DENY_ATTACH`(ptrace 请求在 attach 时返回拒绝)——先静态定位 ptrace 调用点([[re-ghidra]] / [[re-ida]]),patch 或绕过后再 attach
- 签名校验:`SecStaticCodeCheckValidity` / `SecRequirementCheck` 类调用点——改签名或注入触发校验失败的典型点,逐点定位(坑 1)
- 对抗面记录:代码签名校验、调试器检测、反注入(DYLD_INSERT_LIBRARIES 检查)三类各自调用点与触发条件
7. **证据核对(收尾)**:签名者/Team ID/entitlements 原文、TCC 依赖点、钥匙串条目用途、dyld 依赖清单——按 [[re-analyze/analysis-contract]] 入档;动态结论与静态清单对照(能力边界以动态行为为准,见 [[decision-tree]])
## 跨域联合
- [[re-format-macho]]:Mach-O 格式底座(LC_* 解析)
- [[re-ios]]:iOS 侧互补(越狱生态与 entitlements 差异)
- [[re-lldb]]:动态调试
- [[re-frida]]:动态插桩(macOS 桌面支持)
- [[re-sandbox]] / [[re-analyze/platform-tips]]:动态执行隔离(签名/行为观察在沙箱内进行)
- [[re-analyze/analysis-contract]]:签名/entitlements 信息按数据契约传递
- [[re-patching]]:PT_DENY_ATTACH 与签名校验点的持久化处理
- Swift 层分析(mangling/witness table)→ [[re-swift]]
## 常见坑与陷阱
- **签名校验多处触发**:现象——patch 后运行即退;原因——加载/运行/更新多处校验;对策——逐点定位(步骤 6),先处理校验点再过逻辑
- **Secure Enclave 密钥不可提取**:现象——内存搜不到私钥;原因——硬件背书;对策——记录用途与访问条件,不找字节(见步骤 4)
- **TCC 权限导致功能缺失**:现象——目标功能灰掉;原因——TCC 未授权;对策——分析其请求逻辑而非绕过系统权限(红线)
- **公证检查离线不可复现**:现象——离线环境 spctl 结果异常;原因——公证需要网络查询(含吊销状态);对策——用 codesign 本地签名信息替代,标注「公证状态未验证」
- **hardened runtime 限制注入**:现象——DYLD_INSERT_LIBRARIES 无效;原因——runtime 标志未含 allow-dyld 环境变量;对策——静态分析路径([[re-ghidra]]),不硬注入
- **quarantine 干扰运行**:现象——目标下载来源时崩溃/弹窗;原因——`com.apple.quarantine` 触发 Gatekeeper 检查;对策——`xattr -dr com.apple.quarantine` 去除后重测(仅测试环境)
- **嵌套签名漏处理**:现象——patch 后运行时校验失败;原因——framework/helper/扩展各自独立签名,只重签主程序不够;对策——`codesign --deep` 或逐层重签,核对每层 CDHash
- 决策分支(动态可行性判定/数据目标分级)见 [[decision-tree]];签名/注入/TCC 边界与反例见 [[gotchas]];全部在沙箱内执行([[re-analyze/platform-tips]] 最高原则)

View File

@@ -0,0 +1,74 @@
# macOS 应用逆向决策树与证据分级
## 场景决策树(入口 → 分支)
### 1. 目标形态分支(第一级)
```
目标对象
├─ .app bundle → 解包 Contents/,先读 Info.plist 与可执行文件
├─ 单二进制(命令行工具/daemon)→ 直接 codesign/Mach-O 分析
├─ dylib / framework → 依赖关系与导出面为主(otool -L / nm)
├─ 安装包(pkg/dmg)→ 先解包提取载荷(pkgutil --expand)
└─ 无签名/adhoc 签名 → 跳过签名面,直接静态分析
```
### 2. 签名与分发状态分支(第二级,决定动态方案)
```
codesign -dv 结果
├─ Apple 开发者/分发签名
│ ├─ 公证通过(spctl -a 过)→ 正规分发;仍按恶意面分析(公证≠安全)
│ ├─ 公证失败/未公证 → Gatekeeper 会拦;本地仍可分析
│ └─ Hardened Runtime 开 → 注入受限(见分支 3)
├─ 第三方/自签 → 注入面大,但可能带自定义校验
└─ 无签名 → 最容易动态,但注意系统会拦截运行(Gatekeeper/AMFI)
```
### 3. 动态可行性分支(第三级)
```
想动态执行(lldb attach / DYLD_INSERT_LIBRARIES / frida)
├─ Hardened Runtime 且无 cs.allow-dyld-environment-variables
│ └─ DYLD 注入不可行 → lldb attach 或静态分析([[re-ghidra]])
├─ PT_DENY_ATTACH(ptrace 拦截)→ 先 patch 调用点([[re-patching]])再 attach
├─ 沙箱开启 → 动态观察被限制在沙箱能力内(以 entitlements 为准)
└─ 全无限制 → 标准 lldb / frida 流程(沙箱环境内,[[re-analyze/platform-tips]])
```
### 4. 数据目标分支(第四级)
```
要拿什么
├─ 网络行为 → 抓包([[re-netcap]])+ 沙箱网络权限确认
├─ 钥匙串条目 → 定位 SecItemCopyMatching 调用点,读用途与访问条件(可访问性/访问控制,不导出内容,红线)
├─ Secure Enclave 密钥 → 确认 tokenID,记录用途(不可提取,不找字节)
├─ 本地文件/偏好 → 容器路径(沙箱下在 ~/Library/Containers/)分析
└─ 授权/注册逻辑 → 校验 API 调用点 → [[re-license]] 方法论
```
## 证据分级表
| 级别 | 证据形态 | 示例 | 用途 |
|---|---|---|---|
| A 强 | 动态 + 静态交叉闭合 | 动态观察到网络外传,静态代码与 entitlements(network.client)一致 | 可下「恶意行为」结论 |
| B 中 | 单侧完整证据链 | 静态完整还原调用链(含触发条件),未动态确认 | 可下「高可疑」 |
| C 弱 | 静态特征 | 只有高危 entitlement(如 device.* 全开)+ 高混淆 | 只支持「需深入」 |
| 反证 | 良性解释 | 权限声明与功能相符、行为与声明一致 | 记录并存档 |
- 能力边界以动态行为为准:entitlements 声明的能力 ≠ 实际使用的能力,两者都要记录
- 签名/公证结论与恶意结论分开陈述(「分发状态」与「行为定性」是两个维度)
## 实现教训(内化)
- 先读 Info.plist + entitlements 再定动态方案——hardened runtime/沙箱直接决定注入与观察手段
- 签名信息本地可查(codesign -d -r- / -dv),公证状态需网络——离线时用本地信息替代并标注
- TCC 数据只读分析、不导出内容(红线);Full Disk Access 是读取前置,先确认授权
- Secure Enclave 密钥记用途不找字节;钥匙串条目记录访问条件与访问点而非口令内容
- 动态观察在沙箱内进行([[re-sandbox]],[[re-analyze/platform-tips]] 最高原则)
- 证据链记录:签名者/Team ID、entitlements 原文、TCC 依赖点、dyld 依赖清单、动态行为对照
## 使用注意
- 沙箱内执行动态([[re-sandbox]]);TCC/钥匙串数据只读不导出(红线)
- 结论按本表分级标注,签名/公证维度与行为维度分开陈述

View File

@@ -0,0 +1,44 @@
# macOS 逆向方法论坑与边界
## 签名与公证组(最容易误判)
- **公证通过 ≠ 安全**:公证只证明 Apple 扫描过且无已知恶意签名,带公证的恶意/灰色应用存在——「公证状态」与「行为定性」分开陈述
- **离线环境 spctl 结果不可信**:公证与吊销(OCSP)检查需要网络——离线时 `spctl -a` 可能失败或异常;用 codesign 本地签名信息替代,标注「公证未验证」
- **codesign -dv 看不到完整要求**:designated requirement 需 `codesign -d -r-` 查看;只看默认输出会漏掉额外的 requirement 校验
- **staple 与公证是两回事**:`xcrun stapler validate` 查的是票证是否随包(离线可验证);`spctl -a` 查整体评估(可能走网络)——一个失败不代表另一个也失败
- **改签名会破坏原签名链**:patch 后必须重签(`codesign -s -` adhoc 或开发者证书),且嵌套签名(framework/helper)要逐层处理;重签后公证状态丢失是预期
- **quarantine 干扰测试**:下载来源的 `com.apple.quarantine` 会触发 Gatekeeper 检查(崩溃/弹窗)——测试环境 `xattr -dr com.apple.quarantine` 去除后重测,注意这会改变来源证据
## 注入与动态组(hardened runtime 边界)
- **DYLD_INSERT_LIBRARIES 受 hardened runtime 限制**:无 `com.apple.security.cs.allow-dyld-environment-variables` entitlement 时注入不生效(Apple 签名 app 默认启用运行时保护)——别把「注入无效」当 bug,改走静态或 lldb
- **PT_DENY_ATTACH 拒绝 attach**:目标调用 `ptrace(PT_DENY_ATTACH)` 后 attach 被拒——先静态定位 ptrace 调用点 patch 掉([[re-patching]])再动态
- **AMFI/kext 级校验在用户态之外**:系统完整性保护(SIP)下对系统路径注入/挂载无效;内核级校验(kext 签名)不在本技能能力内
- **沙箱内 attach 自身受限**:沙箱环境([[re-sandbox]])的进程权限继承会影响目标行为——观察结论标注环境差异
- **Apple Silicon 差异**:arm64e 指针认证(PAC)影响 hook 与补丁(指针被签名校验);Rosetta 转译层下 x86_64 行为与原生不同——按目标架构分别验证
## TCC 与隐私组(红线边界)
- **TCC.db 自身受 TCC 保护**:无 Full Disk Access 时读 TCC.db 权限失败——先确认授权,不要试图绕过系统权限(红线)
- **TCC 数据只读不导出**:授权记录属系统隐私,只读分析(谁请求了什么权限),不导出库内容(红线)
- **TCC 记录随时间变化**:授权可被撤销/新增,快照不代表历史全貌——结论标注采样时间
- **系统级 vs 用户级 TCC**:`/Library/Application Support/com.apple.TCC/`(系统)与 `~/Library/...`(用户)覆盖范围不同,按目标归属查对应库
## 钥匙串与 Secure Enclave 组
- **Secure Enclave 密钥不可提取**:`kSecAttrTokenIDSecureEnclave` 绑定的私钥永不离开 SE——内存/文件搜索必然无果,记录用途与访问条件即可(反例:拿不到字节 ≠ 分析失败)
- **可访问性 ≠ 访问控制(别混称 ACL)**:`kSecAttrAccessible` 管设备状态(何时可读:非锁定/首次解锁/此设备);`kSecAttrAccessControl`/`SecAccessControl`(生物识别/密码门槛)才是访问控制;macOS 传统 ACL 另属 `SecAccess`/`kSecAttrAccess`——分析访问点(SecItemCopyMatching 参数)比导出内容更有价值
- **钥匙串数据敏感**:条目内容属凭据,分析只读调用面,不导出口令内容(红线)
- **钥匙串迁移**:系统升级/备份恢复后访问控制策略可能变化——历史环境复现时注意
## 反例与边界组
- **沙箱开启 ≠ 无网络面**:`com.apple.security.network.client` 存在时沙箱 app 照样外连——先看 entitlements 再判断行为面
- **entitlements 缺失 ≠ 无能力**:动态行为可能超出静态声明(漏洞利用/未声明调用)——能力边界以动态行为为准
- **签名者知名 ≠ 无恶意**:合法开发者账号可被窃取/滥用;以行为证据定性
- **无签名 app 也能分析**:Gatekeeper 拦截的是运行入口,静态分析不受影响;运行前去除隔离属性并放沙箱
## 使用注意
- 动态执行在沙箱内([[re-sandbox]],[[re-analyze/platform-tips]] 最高原则)
- TCC/钥匙串只读不导出(红线);结论按 [[decision-tree]] 分级标注,签名维度与行为维度分开