reverse-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
141
vendor-new/rev-skills/.claude/skills/re-sample-acquire/SKILL.md
Normal file
141
vendor-new/rev-skills/.claude/skills/re-sample-acquire/SKILL.md
Normal file
@@ -0,0 +1,141 @@
|
||||
---
|
||||
name: re-sample-acquire
|
||||
description: >
|
||||
样本现场采集(从现象到可用样本):目标没有独立进程、样本不落盘时,以「异常执行内存 + 到达该内存的执行上下文」为核心定位载体并运行时提取。
|
||||
覆盖四种观测模型:Windows(VAD/线程/ETW)、Linux(VMA/BPF LSM)、macOS(Mach VM/Endpoint Security)、seL4(capability provenance)。
|
||||
触发词:样本获取、现场采集、没有样本、只有现象、不落盘、无文件、注入、内存马、运行时捕获、内存提取样本。
|
||||
English triggers: sample acquisition, live acquisition, no sample, fileless, injected code, memory-resident, runtime capture.
|
||||
capabilities: [sample-acquisition]
|
||||
---
|
||||
|
||||
# 样本现场采集(从现象到可用样本)
|
||||
|
||||
<CORE RULE>
|
||||
**不猜进程名、不以「找到进程」为第一目标**——找「异常执行内存」+「到达这块内存的执行上下文」。
|
||||
检测基于**最终的内存 artifact**,不依赖"样本用了哪个注入 API"(未知注入方法也可能被 artifact 检出;hook 到某个 API 不等于覆盖了全部注入方式)。
|
||||
**先问 provenance:这块可执行内存是谁创建的、通过什么路径进来的、谁持有映射权限**——再谈它属于哪个进程。
|
||||
</CORE RULE>
|
||||
|
||||
## 任务分类器(intent → 路径)
|
||||
|
||||
| 用户目的 | 路径 |
|
||||
|---|---|
|
||||
| 只有现象描述("某程序不落盘""行为异常"),没有样本文件 | → 步骤 1(异常执行区扫描)→ 2(执行上下文归属)→ 4(dump 整区) |
|
||||
| 已知进程,但磁盘上没有样本文件(注入/内存驻留) | → 步骤 2 → 4 |
|
||||
| 服务端常驻载荷(Web 中间件/Java 等,请求触发) | → 平台分支的"服务端"节(内存马) |
|
||||
| 载荷疑似驱动/内核态(读写内存类外挂/rootkit) | → [[platform-windows]] 内核侧 |
|
||||
| 嵌入式/微内核目标(seL4 系统) | → [[platform-sel4]](capability provenance 路线) |
|
||||
| 有回连/下载行为,想拿原始样本 | → 步骤 7(网络与落盘侧) |
|
||||
|
||||
## 入口判定(Decision Gate)—— 平台 × 形态
|
||||
|
||||
```
|
||||
现场采集
|
||||
├─ 已有样本文件(磁盘上有)→ 不需要本技能,直接 [[re-triage]] 初勘
|
||||
├─ Windows 目标 → [[platform-windows]](VAD/region + 线程 + 模块链 + ETW/Sysmon)
|
||||
├─ Linux 目标 → [[platform-linux]](VMA + mmap/mprotect 追踪 + process_vm_readv)
|
||||
├─ macOS 目标 → [[platform-macos]](Mach task VM + Endpoint Security)
|
||||
├─ seL4 目标 → [[platform-sel4]](capability/VSpace 审计,不是"扫描进程")
|
||||
└─ 不知平台/跨平台 → 先按步骤 1 的平台无关判据走,再进对应分支
|
||||
```
|
||||
|
||||
**平台观测模型不同,方法不能机械翻译**(下表是各分支的分工,不是同义替换):
|
||||
|
||||
| 平台 | 观测对象 | 事件源(trigger) | 读取(ground truth) | 权限模型 |
|
||||
|---|---|---|---|---|
|
||||
| Windows | 进程 VAD/region + 线程 + 模块链 | Sysmon 8/10/25、ETW(含 Threat-Intelligence)、内核回调 | `VirtualQueryEx` / `ReadProcessMemory` / PE-sieve | 管理员 + 调试权限 |
|
||||
| Linux | 进程 VMA(`/proc/<pid>/maps`) | tracepoint/kprobe、**BPF LSM**(`file_mprotect` 等 hook) | `process_vm_readv()` / ptrace / gcore | ptrace access check(含 Yama) |
|
||||
| macOS | Mach task + VM region | **Endpoint Security**(MMAP/MPROTECT/REMOTE_THREAD_CREATE/GET_TASK) | `mach_vm_read` / `mach_vm_read_overwrite`(需 task port) | SIP / Hardened Runtime / task port 授权 |
|
||||
| seL4 | capability(VSpace / frame / TCB) | **fault endpoint** + 系统构造期记录 | 无 capability 即无访问权 | capability 制(不存在"root 全读"模型) |
|
||||
|
||||
## 何时使用 / 何时不用
|
||||
|
||||
- 用:分析目标**没有可分析的文件**——只有现象(不落盘、内存驻留、寄生在别的进程里),需要先把它变成"能分析的样本"
|
||||
- 用:载荷只在内存、时机很短(一次性解密、用后自清除、缓冲复用)
|
||||
- **适用场景(不限外挂)**:无文件恶意软件 / 反射加载载荷 / 内存马(服务端)/ APT 内存驻留 / 勒索与窃密的前置加载阶段 / 游戏外挂(用户态与驱动)/ 微内核与嵌入式系统上的未授权可执行页
|
||||
- 不用:已有样本文件([[re-triage]]);整机镜像取证([[re-mem-forensics]],离线镜像的 malfind 式排查属那边);设备备份解析([[re-mobile-forensics]]);"给定 PID 怎么转储"([[re-memdump]])
|
||||
- **授权边界(红线)**:只对**自有或已获书面授权**的设备/系统采集(`RE_AUTH` = `owned` / `research`)。采集动作本身(枚举、hook、读内存、dump、加载监控组件)痕迹明显,会触发反作弊 / EDR / 业务监控;生产环境或他人设备上执行属越权,先确认授权与停止条件
|
||||
- 边界:本技能只做**采集**,不做对目标检测系统的隐匿(隐匿属 [[re-evasion]] 域,且仅限授权场景)
|
||||
|
||||
## 工具准备
|
||||
|
||||
### Windows
|
||||
|
||||
- **PE-sieve / HollowsHunter**(本技能的参考实现:按内存 artifact 检测 injected/replaced PE、shellcode、inline hooks、patches,支持线程调用栈扫描)——GitHub releases(`hasherezade/pe-sieve`、`hasherezade/hollows_hunter`),核对 release 页 sha256;验证 `pe-sieve.exe /help`
|
||||
- **System Informer**(原 Process Hacker)/ **Process Explorer**:全进程 region/线程/句柄视图
|
||||
- **procdump**(Sysinternals):`procdump -ma <pid> out.dmp`;验证 `procdump -?`
|
||||
- **Sysmon**(Event 8/10/25,见 [[re-behavior]] 行为监控一节);**frida**([[re-frida]],脚本模板 [[re-frida/frida-scripts]])
|
||||
- 详见 [[platform-windows]]
|
||||
|
||||
### Linux
|
||||
|
||||
- `/proc` 解析(python3,[[re-python]])、`gdb`/`gcore`([[re-memdump]])、`bpftrace`/`perf`/BPF LSM([[re-ebpf]])、`frida`
|
||||
- 验证: `cat /proc/<pid>/maps | head` 能看到 VMA 的地址/权限/backing pathname
|
||||
- 详见 [[platform-linux]]
|
||||
|
||||
### macOS
|
||||
|
||||
- `lldb` / `vmmap` / `otool`([[re-lldb]]、[[re-format-macho]]);Mach VM API(`mach_vm_region*` / `mach_vm_read*`,需 task port);Endpoint Security 客户端(需 entitlement 与用户授权)
|
||||
- 注意:**SIP + Hardened Runtime 下不是 root 就能读**——见 [[platform-macos]] 权限边界
|
||||
- 详见 [[platform-macos]]
|
||||
|
||||
### seL4 / 微内核
|
||||
|
||||
- 无通用现成工具:需在系统构造期由 security monitor 记录 provenance(capability 路线),方法与检查清单见 [[platform-sel4]]
|
||||
|
||||
## 操作步骤(平台无关主干)
|
||||
|
||||
各步的平台对应实现见对应平台分支;此处只列**做什么与判据**。
|
||||
|
||||
1. **扫描异常执行区**(不猜 PID,先扫面):
|
||||
- 枚举目标的执行内存单元并筛"可执行":Windows = VAD/region(`VirtualQueryEx`/`NtQueryVirtualMemory`);Linux = VMA(`/proc/<pid>/maps`,6.11+ 可用 `PROCMAP_QUERY` ioctl 高效过滤);macOS = VM region(`vm_region_recurse_64`/`mach_vm_region*`);seL4 = VSpace 映射审计(见分支)
|
||||
- 优先特征:**无 backing(匿名/私有)且可执行**;**保护属性转换**(W→X、RW→RWX→RX——转换瞬间即最佳捕获时机);高熵 / 可执行格式特征(PE/Mach-O/ELF);无已知 JIT/运行时来源
|
||||
- **不要只查"私有/无背书"**:文件背书的内存同样可被利用(Windows `MEM_IMAGE` + module stomping/DLL hollowing、COW 页仍报 `MEM_IMAGE`;Linux 文件背书映射被改写;macOS 文件背书 region 被 patch)
|
||||
- **映射来源 vs 结构记录交叉**:Windows 用 `VirtualQueryEx`+`NtQueryVirtualMemory` 取映射路径与 PEB 模块链比对("有映射无模块条目"= 被摘链隐藏);Linux 用 maps 的 pathname/inode 与 ELF 磁盘副本比对;macOS 用 dyld 记录与 VM region 比对
|
||||
2. **执行上下文归属**(线程是第二强信号,且要看栈不只入口):
|
||||
- 取每个线程的执行位置:起点(Windows `NtQueryInformationThread` + `ThreadQuerySetWin32StartAddress`;macOS thread backtrace)→ 归属到执行区;Linux 用 `/proc/<pid>/task/` 枚举线程,`stat` 的 `wchan`/`state` 作辅助线索,PC 与返回地址靠**栈回溯**(`eu-stack`/gdb)取
|
||||
- **起点正常也可能是 trampoline**:从合法模块起步后跳入无背书可执行区的做法会绕过"只看起点"的检测
|
||||
- 补三层证据:**当前 PC/RIP**、**调用栈返回地址**、**region ownership**——任一级落入异常区都提高评分
|
||||
3. **运行时相关性(trigger 与 ground truth 分工)**:
|
||||
- **事件源只作「何时 dump」的触发器**:内存分配/写入/保护转换 + 可疑线程创建 + 异常模块加载——**组合判断**,不做单点告警
|
||||
- **内存扫描是「dump 什么」的 ground truth**:直系统调用、共享段映射、覆盖已有可执行区等路径都能绕过用户态 hook
|
||||
- 平台事件源:Windows = Sysmon 8/10/25 与 ETW;Linux = tracepoint/kprobe/BPF LSM;macOS = Endpoint Security;seL4 = fault endpoint
|
||||
- **顺带抓注入方/构造方**:执行注入或映射的来源(进程/驱动/构造路径)往往比被寄生的载荷更有分析价值
|
||||
4. **Snapshot / Dump(不要只找 MZ/PE 头)**:
|
||||
- **保存整个可疑区域**:载荷可能本就没有可执行格式头,或**故意擦除头部**(经典:注入后擦 PE 头,靠区域定位再重建)
|
||||
- 内容分类(决定后续分析路径):完整 PE/Mach-O/ELF / 手工映射的镜像 / 裸 shellcode / JIT 代码 / 解密后的 code blob
|
||||
- 每区记:基址 / 大小 / 保护属性及**变更历史** / 类型 / 映射来源 / 采集时间
|
||||
- **内存副本 vs 磁盘副本差异**:同名映像的磁盘文件与内存内容比对(发现 stomping、patch、擦头、代码替换)
|
||||
5. **重建 / 误报评估 / 报告**:
|
||||
- 重建:手工映射镜像按节表重建;擦头载荷按区域内容恢复(标注"重建自内存,非原始文件")
|
||||
- **误报白名单与降权**(必做):JIT(.NET/V8/JVM/Mono)、浏览器、Wine/Proton、QEMU TCG、**安全软件自身的 hook 与 patch**、profiler、overlay、shim/hotpatch —— 它们同样产生无背书可执行内存
|
||||
- **评分而非二元判定**:无背书可执行 + 线程/PC/栈命中 + 近期 W→X + 高熵/格式特征 + 无已知运行时来源 → 高置信;单项特征不足以定性
|
||||
- 报告按 [[re-analyze/analysis-contract]] 核心字段(target_id / sha256 / evidence)——**采集方法本身也是证据**("该区在 T 时刻为 RWX""该线程起点不在任何映射来源内")
|
||||
|
||||
## 平台分支(references)
|
||||
|
||||
- [[platform-windows]] —— VAD/region 扫描、线程与调用栈归属、Sysmon/ETW/内核回调、PE-sieve 与 PE 重建、内核与驱动载体
|
||||
- [[platform-linux]] —— VMA 枚举(`/proc/<pid>/maps`、`PROCMAP_QUERY`)、mmap/mprotect 追踪(tracepoint/kprobe/BPF LSM)、`process_vm_readv` 与 ptrace dump、ELF 内存-磁盘 diff、memfd 与 deleted 映射、JIT 误报
|
||||
- [[platform-macos]] —— Mach task 与 VM region、`mach_vm_read`、Endpoint Security(MMAP/MPROTECT/REMOTE_THREAD_CREATE/GET_TASK)、Mach-O/dyld provenance、task port 与 SIP/Hardened Runtime 边界
|
||||
- [[platform-sel4]] —— capability provenance、VSpace 映射审计、可执行页策略、TCB debug 与 fault endpoint——**设计期即保留 provenance**,与前三者的"事后重建"是两条路线
|
||||
|
||||
## 跨域联合
|
||||
|
||||
- [[re-memdump]]:给定 PID 的转储执行(本技能负责"扫哪个、dump 什么")
|
||||
- [[re-mem-forensics]]:离线整机镜像的排查(本技能是在线/现场侧);[[re-fileless]] / [[re-loader]]:采集产物的分析
|
||||
- [[re-frida]]:跨平台执行层;[[re-java]]:服务端内存马;[[re-kernel]] / [[re-ebpf]]:内核与内核态观测
|
||||
- [[re-evasion]]:样本侧反检测(采集侧要知道自己会被看见);[[re-malware]]:产物分析网关;[[re-triage]]:产物初勘入口
|
||||
- [[re-rtos]] / [[re-tee]] / [[re-firmware]]:嵌入式与可信执行目标的相关分析(seL4 分支的系统构造视角与它们互补)
|
||||
|
||||
## 常见坑与陷阱(跨平台共性)
|
||||
|
||||
- **只 hook 用户态 API 就以为全覆盖**:直系统调用、共享段、覆盖已有可执行区都可绕过——事件源只当 trigger,内存扫描当 ground truth
|
||||
- **把"无背书可执行"直接当恶意**:JIT、浏览器、Wine/Proton、QEMU TCG、安全软件自身的 hook 都产生同类区域——**是 signal 不是 verdict**,要 provenance + 执行史 + 评分
|
||||
- **只查"私有/无背书"内存**:文件背书的内存同样会被利用(Windows `MEM_IMAGE`+COW,Linux/macOS 文件背书映射被改写)
|
||||
- **只按可执行格式头找载荷**:载荷可能无头或**故意擦头**——保存整个区域再分类,必要时重建
|
||||
- **只看线程入口**:trampoline、`SetThreadContext`、借模块内跳转指令等会绕过——PC 与调用栈一起看
|
||||
- **平台权限模型误判**:macOS 不是 root 就能读(SIP/Hardened Runtime/task port);seL4 根本没有"root 全读"这回事——按平台分支的权限边界设计采集方案
|
||||
- **采集晚了**:一次性解密/用后自清除——触发点命中的**瞬间** dump,不要"先记地址、回头再读"
|
||||
- **采集动作本身暴露**:枚举/hook/读内存会被反作弊、反调试与监控发现([[re-game]] / [[re-evasion]])——授权范围内作业,先在隔离环境做准备,动态采集一次完成
|
||||
- **无痕 hook 让内存视图不可信**:影子页/硬件断点实现的无痕 hook 使"读取视图"与"执行视图"分离——多视图交叉,**视图差异本身就是证据**
|
||||
- **清除早于取证**(服务端高发):重启/杀进程会一并丢失证据——先 dump 取证,再阻断植入途径与清除
|
||||
@@ -0,0 +1,73 @@
|
||||
# Linux 平台分支:VMA / mmap-mprotect 追踪 / process_vm_readv
|
||||
|
||||
观测对象是**进程的 VMA(virtual memory area)**——Windows 的 VAD 在这里叫 VMA,但事件与读取路径完全不同。
|
||||
|
||||
## 一、VMA 枚举与信号
|
||||
|
||||
- 主线:`/proc/<pid>/maps`(或 `smaps`,含更细的统计)→ 筛可执行 VMA → backing-file/provenance 判断 → 线程 PC/栈归属 → dump
|
||||
- `maps` 每行字段:`address perms offset dev inode pathname`
|
||||
- `perms` 四字符含义:`r` 读 / `w` 写 / `x` 执行 / `s` 共享 / `p` 私有(COW)
|
||||
- `pathname` 为**空 = 匿名映射**;无文件映射另显示为 `[heap]`、`[stack]`、`[vdso]`、`[anon:<名字>]`、`[anon_shmem:<名字>]`
|
||||
- **高效查询**:Linux **6.11 起**提供 `PROCMAP_QUERY` **ioctl**(`struct procmap_query`,定义在 `linux/fs.h`),可按条件过滤单个 VMA,适合程序化扫描——比解析文本更稳(内核文档:`Documentation/filesystems/proc.rst`)
|
||||
- **高价值信号**:
|
||||
- **匿名 `r-x` / `rwx` VMA**(无文件背书却可执行)
|
||||
- **`/memfd:<名字> (deleted)`** 或 "deleted" 的文件背书可执行映射(载体已从文件系统消失)
|
||||
- **正常 ELF 映射的内容与磁盘上的 ELF 不一致**(代码被改写/替换,对应 Windows 的 module stomping)
|
||||
- **heap/匿名 VMA 事后变为可执行**(W→X 转换)
|
||||
- **线程 PC/RIP 落进这些区域**;**栈上的返回地址指向这些区域**
|
||||
- |注意:**"匿名可执行"是 signal,不是 verdict**——JIT(JVM / V8 / Mono)、Wine/Proton、QEMU TCG 都产生这类 VMA;要看 provenance 与执行史(见本节末)
|
||||
|
||||
## 二、动态侧(trigger):不要只 hook libc
|
||||
|
||||
- 只 hook `libc` 的 `mmap()` / `mprotect()` 会被**直系统调用**绕过
|
||||
- 更底层的事件源:
|
||||
- **syscall tracepoint / kprobe**(`bpftrace`、`perf`)——直接看 `mmap`/`mprotect`/`memfd_create` 等系统调用
|
||||
- **BPF LSM**——把 BPF 程序挂到 LSM hook 上;内核 BPF LSM 文档(`Documentation/bpf/bpf_lsm.rst`,新版为 `prog_lsm.rst`)**正是拿 `file_mprotect` 作示例**:
|
||||
`int file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, unsigned long prot);`,示例程序 `SEC("lsm/file_mprotect")` 在命中时返回 `-EPERM`(即可审计、也可拦截)
|
||||
- 可挂 hook 的清单见内核 `include/linux/lsm_hooks.h`(新版在 `security/security.c`);挂载用 `BPF_RAW_TRACEPOINT_OPEN` 或 libbpf `bpf_program__attach_lsm`;需特权(文档提到 `CAP_MAC_ADMIN` 与 `CAP_SYS_ADMIN`)
|
||||
- 采集侧只需要 **executable protection transition** 这类事件作 trigger,落点即 dump 时机(见 [[re-ebpf]] 的 eBPF 侧细节)
|
||||
|
||||
## 三、执行上下文归属
|
||||
|
||||
- 线程:枚举 `/proc/<pid>/task/`;读 `stat`/`status` 得到状态与位置线索;对可疑线程做栈回溯(gdb/`eu-stack`)取返回地址
|
||||
- 判据:线程 PC 或栈上返回地址落在**匿名/已删除背书的可执行 VMA** 内
|
||||
|
||||
## 四、Dump
|
||||
|
||||
- **`process_vm_readv()`**:跨进程地址空间读取,直接按 [基址, 长度] 取区域;权限受 **ptrace access check** 约束(含 Yama `ptrace_scope`,见 [[re-memdump]] 坑)
|
||||
- 其他路径:`ptrace`(`PTRACE_ATTACH` + `PTRACE_PEEKDATA`/`process_vm_readv`)、`gcore`(整进程 core,注意它是单进程镜像不是整机镜像)、`/proc/<pid>/mem`(同样受 ptrace 权限约束)
|
||||
- Linux 的可执行格式是 ELF:**擦头/无头的载荷同样存在**——保存整区后按内容分类(完整 ELF / 手工映射 ELF / 裸 shellcode / JIT code / 解密 blob)
|
||||
- **内存 vs 磁盘 diff**:`/proc/<pid>/maps` 给出 backing 路径的,取磁盘副本与内存内容逐页/摘要比对(发现代码被替换);配 `[[re-variant]]` 思路做差异定位
|
||||
|
||||
## 五、误报与白名单
|
||||
|
||||
- 白名单/降权:JVM、V8/Node、Mono/.NET、Wine/Proton、QEMU TCG、解释器生成的 trampoline、安全软件自身的探针
|
||||
- 评分与 Windows 分支同构:匿名可执行 + 线程 PC/栈命中 + 近期 W→X + 内容熵/ELF 特征 + 无已知运行时来源
|
||||
|
||||
## 工具与验证
|
||||
|
||||
- 基础:`cat /proc/<pid>/maps`(验证能看到 address/perms/pathname 三段);`smaps` 看 `Rss`/`Private_Dirty` 等
|
||||
- 事件:`bpftrace -l 'tracepoint:syscalls:*mprotect*'` 应与目标内核实际提供的 tracepoint 对得上;BPF LSM 需内核 `CONFIG_BPF_LSM` 与 BTF(验证 `ls /sys/kernel/btf/vmlinux`)
|
||||
- 采集:`python3 -c "import ctypes; ..."` 或直接用 gdb `dump memory` 验证 `process_vm_readv` 路径可达
|
||||
|
||||
## 该平台的坑
|
||||
|
||||
- **只 hook libc 就以为覆盖**:直系统调用绕过——用 tracepoint/kprobe 或 BPF LSM
|
||||
- **把 VMA 当 VAD 直接翻译**:Linux 没有"模块链与 VAD 交叉"那套(模块 = 文件背书映射),替代物是 maps 的 pathname/inode 与磁盘文件比对
|
||||
- **`process_vm_readv` 报 EPERM**:先看 Yama ptrace_scope 与目标进程关系([[re-memdump]] 坑),不要误判为载荷消失
|
||||
- **把匿名可执行当恶意**:JIT/Wine/TCG 大量产生——先基线、再评分
|
||||
|
||||
## 六、内核态载荷(LKM / rootkit)的采集
|
||||
|
||||
用户态扫描看不到的内核态载荷,采集逻辑与用户态同构但要换观测面(分析方法见 [[re-kernel]] 的 Linux 分支):
|
||||
|
||||
- **cross-view 是前提**:`lsmod` / `/proc/modules` 干净**不构成结论**(rootkit 可把模块从链表摘掉,模块仍在运行)。交叉比对:
|
||||
- 模块视图:`/proc/modules`、`/sys/module/<name>/`
|
||||
- 符号视图:`/proc/kallsyms`(受 `kptr_restrict` 影响)
|
||||
- 节地址视图:`/sys/module/<name>/sections/`
|
||||
- 内核可执行内存区间(离线镜像侧见 [[re-mem-forensics]];在线侧需要内核态手段,属授权场景)
|
||||
- 视图互相矛盾时,**优先信任离线内存取证**,而不是被分析系统自己给出的输出
|
||||
- **inline text patch 的发现**:内核 text 与磁盘 `vmlinux` / 模块副本逐段比对(函数头被改写但地址不变——与用户态的 inline hook 同构)
|
||||
- **hook 落点不止 syscall table**:`file_operations`、`seq_operations`、proc handlers、网络协议回调、ftrace、kprobes 都被用过——"syscall table 干净"不是结论
|
||||
- **采集时机**:内核态载荷同样有"用后清除"(模块自卸、hook 复原)——命中即 dump
|
||||
- 授权边界:内核态采集通常需要加载自己的模块 / 用 kprobe 一类机制,**只在自有或已授权设备上做**,并记录停止条件
|
||||
@@ -0,0 +1,71 @@
|
||||
# macOS 平台分支:Mach task / VM region / Endpoint Security
|
||||
|
||||
观测对象是 **Mach task + VM region**(不是 `/proc`,也不是 Windows 的 VAD 模型)。核心区别在于**权限**:macOS 上"有权限"取决于 task port 与签名状态,不是 uid。
|
||||
|
||||
## 一、静态主线
|
||||
|
||||
```
|
||||
task 端口 → VM regions → RX/RWX/private region 筛 → Mach-O/dyld provenance → 线程 PC/backtrace → dump
|
||||
```
|
||||
|
||||
- 遍历 region:`vm_region_recurse_64()` / `mach_vm_region*()`——返回区域的地址范围、**protection**、sharing、resident/private 等属性
|
||||
- 读取内容:`mach_vm_read()` / `mach_vm_read_overwrite()`(需目标 task 的 read 权限)
|
||||
- 归属判断:线程 PC 与回溯是否落在"无 Mach-O/dyld 背书的可执行 region"内
|
||||
- 相关 API 一族(都需要 task port):`task_for_pid`、`mach_vm_region`、`mach_vm_read` / `mach_vm_read_overwrite`、`vm_region_recurse_64`、`mach_vm_protect`
|
||||
|
||||
## 二、权限边界(本平台最容易误判的地方)
|
||||
|
||||
- **SIP**(System Integrity Protection,10.11 起):对 SIP 保护的进程,`task_for_pid()` / `processor_set_tasks()` 返回 **EPERM**;需要 Apple 内部的特殊 entitlement(不对外提供)。SIP 下 Mach 特殊端口在 `exec` 时被重置、dyld 环境变量被忽略、DTrace 探针不可用
|
||||
- **Hardened Runtime**(公证要求):默认**吊销** `task_for_pid` 权限,并拒绝动态库注入、`mprotect(PROT_EXEC)` 标记任意页可执行、`task_set_exception_ports` 等——除非 App 声明了例外 entitlement
|
||||
- `com.apple.security.get-task-allow`(调试工具 entitlement):**目标进程**带此 entitlement 时才允许被 attach / 取 task port(发布版不该有,出现即可疑信号)
|
||||
- 结论:**不是 root 就能读**。采集前先确认目标是否 SIP 保护、是否 Hardened Runtime、是否可 attach——不可读时明确标注"权限不足",不要当成"内存里没有东西"(禁用 SIP 需进恢复模式,且会削弱多项系统防护,非授权研究场景不建议)
|
||||
|
||||
## 三、动态侧(trigger):Endpoint Security
|
||||
|
||||
macOS 上不需要(也不应该)写成"hook `mprotect()`"——系统提供了正规的观测接口 **Endpoint Security(ES)**:
|
||||
|
||||
- 与内存/执行相关的**已文档化事件**:
|
||||
- `ES_EVENT_TYPE_NOTIFY_MMAP` —— 进程**把文件映射进内存**
|
||||
- `ES_EVENT_TYPE_NOTIFY_MPROTECT` —— 进程**改变内存映射页的保护属性**(RWX/可执行化信号)
|
||||
- `ES_EVENT_TYPE_NOTIFY_REMOTE_THREAD_CREATE` —— 进程**在别的进程里创建线程**(macOS 11.0+)
|
||||
- `ES_EVENT_TYPE_NOTIFY_GET_TASK` —— 进程**获取别的进程的 task 控制端口**(macOS 10.15.4+;另有 `GET_TASK_NAME` / `GET_TASK_READ` / `GET_TASK_INSPECT`,11.0/11.3+)
|
||||
- **NOTIFY 与 AUTH 两类**:`NOTIFY_*` 只观测;`AUTH_*`(如 `AUTH_MMAP` / `AUTH_MPROTECT` / `AUTH_GET_TASK`)可**允许或拒绝**操作——授权场景下可做阻断式采集(先取证再放行/拒绝)
|
||||
- 事件订阅通过 `es_subscribe` 注册(常量类型 `es_event_type_t`,可用项随 macOS 版本 gating,按目标 SDK 头文件核对)
|
||||
- 采集侧的分工,与 Windows/Linux 同构:**ES 负责"何时"触发,Mach VM 负责"是什么"的事实确认**
|
||||
|
||||
**高置信组合**(多事件相关,而不是单点告警):
|
||||
|
||||
```
|
||||
REMOTE_THREAD_CREATE(在他进程建线程)
|
||||
+ GET_TASK(先取了 task port)
|
||||
+ MPROTECT(W→X 保护转换)
|
||||
+ 匿名/私有可执行 VM region(Mach VM 侧确认)
|
||||
```
|
||||
|
||||
## 四、代码完整性对比(发现 patch / 替换)
|
||||
|
||||
- **Mach-O `__TEXT` 内存页与磁盘副本比对**(按页/摘要):代码段被改写(patch、inline hook、模块替换)时两者不一致
|
||||
- 结合 [[re-format-macho]] 的段/签名解析与 [[re-macos]] 的签名公证视图(CDHash、签名者)判断"内存中的镜像是否仍是签名时那份"
|
||||
|
||||
## 五、工具与验证
|
||||
|
||||
- `lldb`([[re-lldb]]):attach 目标后 `image list`、`memory region`、`process save-core`
|
||||
- `vmmap` / `otool` / `codesign -d`:region 视图、Mach-O 结构、签名与 entitlement 核对
|
||||
- ES 客户端:需相应 entitlement 与用户授权(系统设置中批准),验证方式是先订阅 `MPROTECT` 事件看能否收到系统内正常进程的事件
|
||||
|
||||
## 该平台的坑
|
||||
|
||||
- **以为 root 能读一切**:SIP / Hardened Runtime 下 `task_for_pid` 直接 EPERM——先判断权限,再设计采集方式;读不到不是"没有异常"
|
||||
- **照搬 hook 思路**:macOS 上有 ES 这类正规接口,优先用事件而不是用户态 hook(hook 在 Hardened Runtime/SIP 下也更容易失效)
|
||||
- **忽略 AUTH 与 NOTIFY 的区别**:只有 AUTH 类事件能拦;NOTIFY 类只能观测(采集取证通常够用)
|
||||
- **ES 事件随版本 gating**:新事件常量在旧系统不可用——按目标系统版本与 SDK 头文件核对可用集
|
||||
|
||||
## 六、内核态载荷(KEXT / DEXT)的采集
|
||||
|
||||
macOS 上"内核态载荷"分两代,采集路径完全不同(分析方法见 [[re-kernel]] 的 macOS 分支):
|
||||
|
||||
- **DEXT(System Extension / DriverKit)——按用户态进程处理**:它跑在用户空间,所以正常走本文件的用户态路径(进程枚举、`mach_vm_read` 等),不需要内核态手段;注意先确认 **activation 状态与 entitlement**(未激活/entitlement 不匹配时进程根本起不来,别误判为"没有载荷")
|
||||
- **KEXT(legacy)——先确认运行版本**:macOS 11+ 第三方 kext 并入 **AuxKC 在启动时加载**,更新后重启前**旧版本可能仍在运行**——采集前记录 **disk bundle version / AuxKC version / running version / boot time**,否则会采到/分析到"不是正在跑的那一份"
|
||||
- **kext 列表的 cross-view**:磁盘 kext 目录 / `kmutil` 视图 / IORegistry 绑定关系 交叉比对(与 Linux 的模块列表交叉同构)
|
||||
- **内核内存读取的现实**:SIP 与 Hardened Runtime 下 `task_for_pid` 对受保护目标 EPERM(见本文件第二节)——内核内存采集通常需要关闭 SIP 或用具备相应授权的机制,属授权研究场景,先确认权限与合规要求
|
||||
- 采集产物按 [[re-analyze/analysis-contract]] 入档,并标注"采集自磁盘 / AuxKC / 运行内存"三者中的哪一份
|
||||
@@ -0,0 +1,75 @@
|
||||
# seL4 平台分支:capability provenance(不是"扫描进程")
|
||||
|
||||
seL4 上**观测模型与前三个平台根本不同**,因此方法不能翻译过来:这里**没有"root 枚举全系统进程、偷看别人内存"这回事**。
|
||||
|
||||
## 一、为什么不同
|
||||
|
||||
- **无 capability 即无访问权**:一切操作都必须由持有**不可伪造的 capability** 的线程发起。内核对象(TCB、VSpace、CNode、Endpoint、Notification、frame/page)全部是 capability 控制的资源
|
||||
- 初始 **root task** 在启动时获得系统资源的 caps;此后资源通过 capability 派生/授予分发
|
||||
- Microkit 的 **protection domain(PD)** 默认只有自己的 ELF/VSpace 与**显式授予**的资源(每个 PD = 自己的 CSpace + VSpace + TCB,入口点 `init`/`notified`/`protected`/`fault`)
|
||||
- 因此"从一个被注入的 PD 内部往外看"与"从系统外扫面"这两条路都不成立——**能观察什么,完全由你持有的 capability 决定**
|
||||
|
||||
## 二、正确路线:构造期记录 provenance
|
||||
|
||||
不要做"扫描 → 猜哪个 PD 被注入",而是**在系统构造期就让 security monitor 掌握 provenance**:
|
||||
|
||||
```
|
||||
root task / system monitor
|
||||
├── TCB caps(线程上下文)
|
||||
├── frame/page caps(物理页来源)
|
||||
├── VSpace 构造记录(谁映射了什么、什么权限)
|
||||
├── 可执行页策略(哪些 frame 允许被映射为可执行)
|
||||
├── fault endpoints(异常事件入口)
|
||||
└── loader provenance(ELF loader / 可信组件登记的镜像)
|
||||
↓
|
||||
execution provenance graph(可执行页 ← 来源 frame ← 映射者 ← 授权链)
|
||||
```
|
||||
|
||||
- seL4 的**页映射本身就是显式的 capability invocation**:一个 frame/page 被映射进哪个 VSpace、以什么权限映射,都是系统构造过程的一部分,因此天然可记录
|
||||
- 由此可回答前三个平台很难回答的问题:**"这个可执行页是谁创建的、来自哪个 untyped/frame、被映射进哪个 VSpace、谁持有映射权限"**
|
||||
- 检测/采集逻辑(策略驱动,优于定时轮询):
|
||||
|
||||
```
|
||||
ELF loader / 可信组件登记合法可执行 frames
|
||||
↓
|
||||
出现任何新的可执行映射
|
||||
↓
|
||||
校验 frame provenance + capability 路径
|
||||
↓
|
||||
不合策略 → 阻止 / 触发 fault / 现场快照(snapshot)
|
||||
```
|
||||
|
||||
## 三、提问方式的转变
|
||||
|
||||
- 前三个平台问:"恶意代码藏在哪个进程里?"(事后从复杂共享系统里**恢复** provenance)
|
||||
- seL4 上应该问:**"哪个 capability flow 让未授权代码获得了 executable authority?"**(provenance 在设计期就**保留**下来了)
|
||||
- 这两条路线的对照本身很有价值:前三者是"事后重建",seL4 是"设计即保留"——同一技能里并列,能覆盖两类系统的采集思路
|
||||
|
||||
## 四、可用的内核设施(前提:monitor 持有相应 cap)
|
||||
|
||||
- **TCB debug API**(硬件调试能力,需以 `-DHardwareDebugAPI=1` 构建;不支持的平台内核启动即 abort):
|
||||
- `seL4_TCB_SetBreakpoint` / `seL4_TCB_UnsetBreakpoint` / `seL4_TCB_GetBreakpoint` —— 按虚拟地址设置**断点/观察点**(指令或数据、读/写/读写、范围)
|
||||
- `seL4_TCB_ConfigureSingleStepping` —— 单步(每 N 条指令中断一次;`num_instructions=0` 关闭),**每次触发都向该线程的 fault endpoint 发消息**,回复 fault 消息即继续执行
|
||||
- 这些 invocation 都要**指向目标 TCB 的 capability**——再次说明:能调试谁,取决于你持有什么
|
||||
- **fault 是一等事件**:VM fault、debug fault 等按配置发送到**fault endpoint**;Microkit 中 PD 的 `fault` 入口由 monitor 的 fault handler 处理
|
||||
- 监视器可据此把"异常执行"变成**事件驱动**(而不是采样扫描)
|
||||
|
||||
## 五、落地清单(按目标系统构造裁剪)
|
||||
|
||||
1. 确认系统构造:root task / monitor 结构、各 PD 的资源与通道(Microkit 的 system 描述文件是权威来源)
|
||||
2. 收集 provenance 来源:loader 记录、VSpace 构造 invocation 记录、可执行页策略、fault endpoint 订阅
|
||||
3. 定义"合法可执行页"集合(哪些 frame/VSpace/权限组合是构造期认可的)
|
||||
4. 建立运行时校验:新可执行映射 → 回溯 frame provenance 与 capability 路径 → 判定
|
||||
5. 处置:阻止(策略拒绝)/ 触发 fault 进入监视器 / 现场快照(保存涉事 frame 与映射记录)——**先取证再处置**
|
||||
6. 记录输出按 [[re-analyze/analysis-contract]] 的字段(target_id 用系统/PD 标识;evidence 用 capability 路径与映射记录)
|
||||
|
||||
## 方法侧入口
|
||||
|
||||
本篇是**采集/监视视角**(假定你是有权限的一方,在系统构造期记录 provenance)。若目标是一个**已有的 seL4 系统**(要逆向它、理解它的对象图与 IPC 拓扑),走 [[re-kernel]] 的 [[re-kernel/sel4-kernel]] 分支——那边给的是"capability 系统怎么读、哪些现象不能按普通 OS 判"。
|
||||
|
||||
## 该平台的坑
|
||||
|
||||
- **套用前三平台的思路**:从"root 扫面"或"注入检测工具"出发在 seL4 上没有对应物——先明确"我持有哪些 capability"
|
||||
- **把 seL4 当"Linux 的特殊版本"**:观测边界完全不同,方法要从 capability 模型重推
|
||||
- **忽略构建期配置**:TCB debug API 需显式构建开关;不同平台支持度不同(不支持的平台内核启动即 abort)
|
||||
- **只做周期性扫描**:capability 路径与 fault endpoint 本来就能给出事件与来源,定时轮询是退化用法
|
||||
@@ -0,0 +1,58 @@
|
||||
# Windows 平台分支:VAD / 线程 / 事件 / 内核
|
||||
|
||||
观测对象是**进程的 VAD(虚拟地址描述符)与 region + 线程 + 模块链**;进程只是容器。
|
||||
|
||||
## 一、异常执行区扫描(不猜 PID)
|
||||
|
||||
- 遍历:`VirtualQueryEx` / `NtQueryVirtualMemory` 走目标地址空间;全进程扫面用 HollowsHunter(PE-sieve 引擎)
|
||||
- **优先特征**:
|
||||
- `State=MEM_COMMIT` + `Type=MEM_PRIVATE` + 保护含执行位(Volatility `malfind` 的经典判据:private + committed + executable)
|
||||
- **保护属性转换**:W→X、RW→RWX→RX——先写后改可执行是最强信号;转换瞬间即最佳捕获时机(步骤三的 hook 点)
|
||||
- 保护值参考:`PAGE_EXECUTE_READWRITE`(0x40)、`PAGE_EXECUTE_READ`(0x20)、`PAGE_EXECUTE_WRITECOPY`(0x80)
|
||||
- **`MEM_IMAGE` 不能判白**:
|
||||
- module stomping / DLL hollowing 把 payload 塞进看似合法的 DLL 映射(映射类型仍是 `MEM_IMAGE`)
|
||||
- copy-on-write 的 image 页在 `VirtualQueryEx` 里**仍报 `MEM_IMAGE`**——要判断它是否已成本进程私有修改页,需查 **Working Set 的 `.Shared` 位**(`K32QueryWorkingSetEx`);该位也是发现**内联 hook** 的手段(写钩子触发 COW 私有化)
|
||||
- **模块链交叉(Missing PEB module)**:用 `VirtualQueryEx` + `NtQueryVirtualMemory` 取 `MEM_IMAGE` 的映射文件路径,与 PEB 加载模块列表比对——"有映射、无 PEB 条目"= 被摘链隐藏的模块(`GetModuleHandle` / `EnumProcessModules` 看不到它,内存视图能看到)
|
||||
|
||||
## 二、执行上下文归属
|
||||
|
||||
- 线程起点:`NtQueryInformationThread(hThread, 9 /* ThreadQuerySetWin32StartAddress */, &addr, sizeof(addr), NULL)` → `VirtualQueryEx` 查该地址所在 region:`MEM_COMMIT && Type != MEM_IMAGE` 即可疑(Get-InjectedThread 类脚本的判据)
|
||||
- **只看起点会漏**(已知绕过):① LoadLibrary/DLL 注入(代码落在 `MEM_IMAGE`);② `SetThreadContext` 改写 RIP(起点显示在合法模块);③ `jmp rcx` 类 gadget(借模块内已有跳转指令作入口);④ Win11 经 `_beginthreadex` 的线程起点落在 msvcrt;⑤ 从合法 DLL 起跳后 trampoline 进 private 可执行区
|
||||
- **补三层证据**:当前 RIP、**调用栈返回地址**、region ownership——PE-sieve `/threads` 专扫线程调用栈(可抓 shellcode 与 sleeping beacon)
|
||||
|
||||
## 三、事件侧(trigger,不是 ground truth)
|
||||
|
||||
- **Sysmon**:Event 10(ProcessAccess——谁打开了目标)、Event 8(CreateRemoteThread,带 `StartAddress` / `StartModule` / `StartFunction`)、Event 25(ProcessTampering / image hollowing)
|
||||
- **ETW**:Threat-Intelligence 提供者可暴露直系统调用、内存分配与线程上下文改写(驱动/EDR 实现侧见 [[re-evasion]])
|
||||
- **内核回调**(有驱动条件时):`PsSetCreateProcessNotifyRoutine` / `PsSetCreateThreadNotifyRoutine` / `PsSetLoadImageNotifyRoutine`——LoadImage 发现"无对应磁盘文件的可执行映射"、线程起点不在任何模块内,都是强证据
|
||||
- 与内存扫描的分工:事件源回答"**何时** dump",内存扫描回答"**dump 什么**";直系统调用 / 共享 section / 覆盖已有 RX 区可绕过用户态 hook
|
||||
|
||||
## 四、Dump 与重建
|
||||
|
||||
- 工具:`pe-sieve.exe /pid <pid> /shellc /hooks /imp /dmode unmap`(注入 PE 自动解映射重建)、`/minidmp`、`procdump -ma <pid> out.dmp`
|
||||
- **保存整个可疑 region**,不要只按 `MZ` 筛:载荷可能无 PE 头或故意擦头(经典案例:注入后擦 PE 头 → 靠区域定位 → dump 后按节重建 PE)
|
||||
- 内容分类:完整 PE / 手工映射 PE / 裸 shellcode / JIT 代码 / 解密后的 code blob
|
||||
- **模块内存 vs 磁盘差异**:同名模块的磁盘副本与内存副本比对(发现 stomping、patch、擦头);PE-sieve 的 `/dmode unmap|realign` 与导入表恢复(`/imp`)就是为重建服务
|
||||
|
||||
## 五、内核与驱动载体(外挂 / rootkit 常见)
|
||||
|
||||
- 内核可执行内存扫描 + **驱动加载前后对比**定位无模块驱动(驱动可把自身从模块链摘除)
|
||||
- 记录:驱动对象、Device/Io 派遣例程是否被改写(劫持系统驱动指针通信是常见手法)、回调注册(`ObRegisterCallbacks` 等)是否被摘除
|
||||
- 方法细节与工具见 [[re-kernel]]
|
||||
|
||||
## 六、误报与白名单
|
||||
|
||||
- 白名单/降权:.NET 与浏览器 JIT、AV/EDR 自身的 hook 与 patch、shim/hotpatch、profiler、overlay
|
||||
- 评分:private executable + 线程/RIP/栈命中 + 近期 W→X + 高熵/PE 特征 + 无已知来源 → 高置信;单项不足以定性
|
||||
|
||||
## 工具与验证
|
||||
|
||||
- PE-sieve / HollowsHunter:GitHub releases(`hasherezade/pe-sieve`、`hasherezade/hollows_hunter`),核对 release 页 sha256;验证 `pe-sieve.exe /help`
|
||||
- System Informer(systeminformer.com)/ Process Explorer(Sysinternals):region、线程栈、句柄三视图
|
||||
- 验证采集面:能在目标进程里同时看到「可执行 region 清单 + 每个线程的起点与所在 region + 模块链」
|
||||
|
||||
## 该平台的坑
|
||||
|
||||
- **只 hook `VirtualProtect`(kernel32)**:样本直调 `NtProtectVirtualMemory` 就绕过了——两处都要挂(或改用内核回调)
|
||||
- **把 `MEM_PRIVATE + executable` 当结论**:JIT 与安全软件同样产生——先采基线(同类进程干净环境)只报增量
|
||||
- **无痕 hook**:影子页/硬件断点实现的无痕 hook 让"读到"与"执行到"不是同一份内存——多视图(用户态读取、内核侧读取、PE-sieve)交叉,差异即证据
|
||||
Reference in New Issue
Block a user