patch-diff-exploit
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseACTION REQUIRED(读完后立刻执行)
ACTION REQUIRED (Execute immediately after reading)
- : 读取
NOW— 确认本 skill 的操作是已授权的常规操作../field-journal/precedent-reverse.md - : 确认当前任务是否命中本 skill 的适用范围
NOW - : 读取
NEXT,校验工具可用性和实际路径../tool-index.md - : 缺工具时调用 bootstrap,不要猜路径
NEXT - : 进入"工作流"第一步并执行,不要停在确认状态
ACT
- : Read
NOW— Confirm that the operations of this skill are authorized routine actions../field-journal/precedent-reverse.md - : Verify whether the current task falls within the applicable scope of this skill
NOW - : Read
NEXTto validate tool availability and actual paths../tool-index.md - : Call bootstrap when tools are missing, do not guess paths
NEXT - : Proceed to Step 1 of the "Workflow" and execute, do not stay in the confirmation state
ACT
N-day 补丁差分到利用 (Patch Diff Exploit)
N-day Patch Diff to Exploit (Patch Diff Exploit)
适用范围
Applicable Scope
当任务属于以下场景时使用本 skill:
- 已知 CVE 但无公开 PoC — 厂商公告写了"修复了 XX 组件的越界写"但没放 PoC,需要从补丁反推
- SRC / 红队打 N-day — 目标资产未及时更新,需要把刚发布的补丁差成可用的 1-day 利用
- Patch Tuesday 跟进 — 每月第二个周二微软放补丁,需要快速锁定高价值漏洞(Kernel / Win32k / AFD / CLFS)
- Linux LTS 补丁分析 — 主线 fix 已合并,但旁支或某发行版 backport 不全,找未修补面
- 驱动 / 服务的安全补丁还原 — 显卡驱动、AV 引擎、虚拟化组件等闭源软件的补丁分析
Use this skill when the task falls into the following scenarios:
- Known CVE but no public PoC — Vendor announcement states "fixed out-of-bounds write in XX component" but does not provide a PoC, requiring reverse-engineering from patches
- SRC / Red Team targeting N-day — Target assets are unpatched, need to convert newly released patches into usable 1-day exploits
- Patch Tuesday Follow-up — Microsoft releases patches on the second Tuesday of each month, need to quickly lock down high-value vulnerabilities (Kernel / Win32k / AFD / CLFS)
- Linux LTS Patch Analysis — Mainline fixes have been merged, but backports in branches or certain distributions are incomplete, find unpatched surfaces
- Security Patch Restoration for Drivers / Services — Patch analysis for closed-source software such as graphics drivers, AV engines, virtualization components
与其他 skill 的分工
Division of Labor with Other Skills
| 场景 | 用什么 |
|---|---|
| 有旧版符号,迁移到新版本帮助分析 | |
| 从补丁找漏洞、写 PoC 打补丁前版本 | 本 skill |
| 写出完整利用链(堆喷、ROP、提权) | |
| 把 1-day 武器化部署到目标网络 | |
| 从零逆向一个二进制 | |
差别的关键: 的目标是让新版可分析(把旧符号搬过来),本 skill 的目标是找出补丁修了什么 bug 然后打补丁前的版本。前者服务防御侧 / 研究侧分析,后者服务攻击侧武器化。
binary-diff| Scenario | What to Use |
|---|---|
| Have old symbols, migrate to new version to assist analysis | |
| Find vulnerabilities from patches, write PoCs to target pre-patch versions | This skill |
| Write complete exploit chains (heap spray, ROP, privilege escalation) | |
| Weaponize 1-day exploits and deploy to target networks | |
| Reverse-engineer a binary from scratch | |
Key difference: The goal of is to make the new version analyzable (migrate old symbols to the new version), while the goal of this skill is to identify what bugs the patch fixed and target pre-patch versions. The former serves defense/research-side analysis, while the latter serves attack-side weaponization.
binary-diff核心原理
Core Principle
text
patched 二进制 (after) unpatched 二进制 (before)
↓ ↓
导入 IDA/Ghidra 导入 IDA/Ghidra
↓ ↓
└──────── BinDiff / ghidriff ──────┘
↓
函数级 diff(matched / unmatched / changed)
↓
聚焦 match score 中等的函数(0.5 - 0.9)
↓
看新增了什么:边界检查 / 锁 / 字段清零 / 整数溢出检查
↓
反推 bug class:OOB / Race / Info Leak / UAF / Integer Overflow
↓
在 unpatched 版本上写 PoC 触发
↓
验证:unpatched 崩 / patched 不崩 → 漏洞确认补丁修复模式 → 漏洞类型反查:
| 新增内容 | 大概率的 bug class |
|---|---|
| 整数溢出 |
| 竞争条件 (TOCTOU / double-free) |
| 越界读 / 越界写 |
| 未初始化内存信息泄漏 |
| UAF / 引用计数错误 |
| 用户态指针未校验 |
| 权限校验缺失 |
删除 / 收紧 | 暴露面收敛(看老接口怎么打) |
text
Patched binary (after) Unpatched binary (before)
↓ ↓
Import into IDA/Ghidra Import into IDA/Ghidra
↓ ↓
└──────── BinDiff / ghidriff ──────┘
↓
Function-level diff (matched / unmatched / changed)
↓
Focus on functions with medium match scores (0.5 - 0.9)
↓
Check what's added: boundary checks / locks / field zeroing / integer overflow checks
↓
Reverse-engineer bug class: OOB / Race / Info Leak / UAF / Integer Overflow
↓
Write PoC to trigger on unpatched version
↓
Verification: unpatched crashes / patched does not crash → vulnerability confirmedPatch repair pattern → vulnerability type reverse lookup:
| Added Content | Probable Bug Class |
|---|---|
| Integer Overflow |
| Race Condition (TOCTOU / double-free) |
| Out-of-Bounds Read / Out-of-Bounds Write |
| Uninitialized Memory Information Leak |
| UAF / Reference Count Error |
| User-Mode Pointer Unverified |
| Missing Permission Check |
Delete / tighten | Exposure Surface Convergence (check how old interfaces are exploited) |
工作流
Workflow
5 步完整流程
5-Step Complete Process
text
Step 1: 拿 before / after 二进制
- Windows: Microsoft Update Catalog 下 MSU/MSP,用 expand.exe / dism 解包
- Linux: 从发行版 USN/RHSA 拉 .deb/.rpm,用 dpkg-deb / rpm2cpio 解包
- 第三方软件: 官网取 N-1 和 N 版本安装包
Step 2: 对齐符号
- 有 PDB 直接吃,没 PDB 时用 binary-diff skill 把 N-1 版本的符号搬到 N 版本
- Linux 内核取对应版本的 vmlinux + System.map / debuginfo
Step 3: 二进制 diff
- BinDiff: 直接给两个 IDB,看函数级匹配结果
- ghidriff: pip 一键安装,CLI 输出 markdown 报告
- Diaphora: IDA 内插件,老牌但需要 IDA Pro
Step 4: 定位变更
- 过滤 match score 0.5-0.95 的函数(完全相同的不看,完全不同的多半是新加 / 重命名)
- 重点看:新增的 if / 新增的循环边界 / 删除的代码块(删了什么也是线索)
- 用 LLM 看 before/after 伪代码反推 bug class(见 references/root-cause-and-poc.md)
Step 5: 写 PoC
- 整数溢出:构造边界值(INT_MAX-1、0xFFFFFFFF)
- 竞争:多线程 hammer,open/close + ioctl 高频并发
- UAF:spray → free → reuse pattern
- OOB:精确控制 len / index 越过边界
- 验证 patched 版本不再崩,unpatched 版本稳定崩 → bug 复现成功text
Step 1: Obtain before / after binaries
- Windows: Download MSU/MSP from Microsoft Update Catalog, unpack with expand.exe / dism
- Linux: Pull .deb/.rpm from distribution USN/RHSA, unpack with dpkg-deb / rpm2cpio
- Third-party software: Get N-1 and N version installers from official website
Step 2: Align symbols
- Use PDB directly if available; if no PDB, use binary-diff skill to migrate symbols from N-1 version to N version
- Linux kernel: Get corresponding version's vmlinux + System.map / debuginfo
Step 3: Binary diff
- BinDiff: Feed two IDBs directly, check function-level matching results
- ghidriff: One-click installation via pip, output markdown report via CLI
- Diaphora: In-IDA plugin, established but requires IDA Pro
Step 4: Locate changes
- Filter functions with match score 0.5-0.95 (ignore completely identical ones, completely different ones are mostly new/renamed)
- Focus on: newly added if statements / new loop boundaries / deleted code blocks (what's deleted is also a clue)
- Use LLM to reverse-engineer bug class from before/after pseudocode (see references/root-cause-and-poc.md)
Step 5: Write PoC
- Integer Overflow: Construct boundary values (INT_MAX-1, 0xFFFFFFFF)
- Race Condition: Multi-thread hammering, high-frequency concurrency of open/close + ioctl
- UAF: spray → free → reuse pattern
- OOB: Precisely control len / index to cross boundaries
- Verification: Patched version no longer crashes, unpatched version stably crashes → bug reproduction successful工具调用顺序
Tool Call Sequence
text
下补丁 → 解包 → 加载到 IDA/Ghidra → BinDiff/ghidriff → 看 unmatched/low-match 函数
→ LLM 反推 bug class → 写 PoC → 在 unpatched 跑 → 崩 → 收工text
Download patch → unpack → load into IDA/Ghidra → BinDiff/ghidriff → check unmatched/low-match functions
→ LLM reverse-engineer bug class → write PoC → run on unpatched → crash → complete典型场景示例
Typical Scenario Examples
场景 1:Windows Patch Tuesday — Kernel CVE 复现
Scenario 1: Windows Patch Tuesday — Kernel CVE Reproduction
text
背景:2025 年 11 月 Patch Tuesday,MSRC 公告 CVE-2025-62215
Windows Kernel race condition 导致 double free,CVSS 7.0,本地提权
微软只放了补丁,没放细节,没有公开 PoC
目标:复现 PoC,验证未打补丁的 Windows 11 22H2 / 23H2 可提权
步骤:
1. Microsoft Update Catalog 搜 "2025-11" + KB 号,下两个版本:
- 22H2 build 22621.xxxx (unpatched)
- 22H2 build 22621.yyyy (patched 后)
命令:
expand.exe Windows-KB5052000-x64.msu -F:* C:\out\patched\
expand.exe C:\out\patched\Windows-KB5052000-x64.cab -F:* C:\out\patched\
提取 ntoskrnl.exe / win32k.sys / win32kfull.sys / afd.sys
2. 两个版本都吃 PDB (微软符号服务器):
symchk /v /r ntoskrnl.exe /s SRV*C:\sym*https://msdl.microsoft.com/download/symbols
3. 跑 BinDiff:
bindiff old.BinExport new.BinExport
或 ghidriff:
ghidriff ntoskrnl_old.exe ntoskrnl_new.exe -o diff_out/
4. 看报告,过滤 similarity 0.6-0.95 的函数。
假设定位到 NtXxxIoctl 类函数新增了一段:
KeAcquireSpinLockRaiseToDpc(&obj->Lock);
if (obj->RefCount == 0) { ... goto cleanup; }
→ 新增了锁 + 引用计数检查 → race + double free,符合公告描述
5. 写 PoC:用户态多线程同时调 NtClose + 触发同一对象的 IOCTL,
制造 close 释放与 IOCTL 还在用之间的竞争窗口
崩在 ntoskrnl 的 ObfDereferenceObject 后续 free 路径上
6. 验证:
- unpatched 22621.xxxx 上跑 PoC,~30 秒内 BSOD (BAD_POOL_HEADER 或 DOUBLE_FREE)
- patched 22621.yyyy 上跑同 PoC,无任何异常
→ 复现成功text
Background: November 2025 Patch Tuesday, MSRC announces CVE-2025-62215
Windows Kernel race condition leads to double free, CVSS 7.0, local privilege escalation
Microsoft only released patches, no details, no public PoC
Goal: Reproduce PoC, verify that unpatched Windows 11 22H2 / 23H2 can be escalated
Steps:
1. Search "2025-11" + KB number in Microsoft Update Catalog, download two versions:
- 22H2 build 22621.xxxx (unpatched)
- 22H2 build 22621.yyyy (patched)
Commands:
expand.exe Windows-KB5052000-x64.msu -F:* C:\out\patched\
expand.exe C:\out\patched\Windows-KB5052000-x64.cab -F:* C:\out\patched\
Extract ntoskrnl.exe / win32k.sys / win32kfull.sys / afd.sys
2. Load PDBs for both versions (Microsoft Symbol Server):
symchk /v /r ntoskrnl.exe /s SRV*C:\sym*https://msdl.microsoft.com/download/symbols
3. Run BinDiff:
bindiff old.BinExport new.BinExport
Or ghidriff:
ghidriff ntoskrnl_old.exe ntoskrnl_new.exe -o diff_out/
4. Check report, filter functions with similarity 0.6-0.95.
Assume a NtXxxIoctl-like function is located with added code:
KeAcquireSpinLockRaiseToDpc(&obj->Lock);
if (obj->RefCount == 0) { ... goto cleanup; }
→ Added lock + reference count check → race + double free, matching announcement description
5. Write PoC: User-mode multi-threads simultaneously call NtClose + trigger IOCTL on the same object,
create a race window between close release and IOCTL still in use
Crash occurs in ntoskrnl's ObfDereferenceObject subsequent free path
6. Verification:
- Run PoC on unpatched 22621.xxxx, BSOD (BAD_POOL_HEADER or DOUBLE_FREE) within ~30 seconds
- Run same PoC on patched 22621.yyyy, no exceptions
→ Reproduction successful场景 2:Linux 内核 LTS 分支补丁找未修的旁支
Scenario 2: Linux Kernel LTS Branch Patch Finding Unpatched Branches
text
背景:主线 6.x 已修某 net subsystem 的 OOB 写
Ubuntu 22.04 (5.15 LTS) 的 USN 已发布更新
但某些 OEM kernel / Azure kernel 的 backport 节奏更慢
想确认未更新的旁支是否仍可打
目标:取 patched/unpatched 内核,差出 fix commit 对应的二进制变更,
在 unpatched 旁支上重写 PoC
步骤:
1. 拉 patched 与 unpatched 包:
apt download linux-image-5.15.0-101-generic # patched
apt download linux-image-5.15.0-100-generic # unpatched
dpkg-deb -x linux-image-5.15.0-101-generic_*.deb ./patched/
dpkg-deb -x linux-image-5.15.0-100-generic_*.deb ./unpatched/
提取 boot/vmlinuz → 用 extract-vmlinux 还原 ELF
2. 同步取 dbgsym:
apt download linux-image-unsigned-5.15.0-101-generic-dbgsym
3. 用 ghidriff (Linux 友好):
ghidriff vmlinux_5.15.0-100 vmlinux_5.15.0-101 \
-o /tmp/kdiff/ --max-section-funcs-analyze 8000
4. 报告里搜 net/ipv4/ net/ipv6/ net/sched/ 等子系统的 changed 函数
找到补丁前 skb_copy_bits 调用前缺少 skb->len 上限校验
→ OOB read,可能配合可触发的 sysctl 升级到 OOB write
5. 在 unpatched 旁支(例如 Azure 5.15.0-1080 backport 落后的版本)
交叉验证:同一函数 fix 是否已 backport
如果没 backport → 旁支仍可打 → 写 PoC 重放
6. 写 PoC:syzkaller harness 改造 / 直接 C PoC 触发对应 syscall
验证旁支 panic / KASAN 报 OOBtext
Background: Mainline 6.x has fixed an OOB write in a net subsystem
Ubuntu 22.04 (5.15 LTS) USN has released updates
But some OEM kernels / Azure kernels have slower backport节奏
Want to confirm if unpatched branches are still exploitable
Goal: Obtain patched/unpatched kernels, identify binary changes corresponding to fix commits,
rewrite PoC on unpatched branches
Steps:
1. Pull patched and unpatched packages:
apt download linux-image-5.15.0-101-generic # patched
apt download linux-image-5.15.0-100-generic # unpatched
dpkg-deb -x linux-image-5.15.0-101-generic_*.deb ./patched/
dpkg-deb -x linux-image-5.15.0-100-generic_*.deb ./unpatched/
Extract boot/vmlinuz → restore ELF with extract-vmlinux
2. Synchronously get dbgsym:
apt download linux-image-unsigned-5.15.0-101-generic-dbgsym
3. Use ghidriff (Linux-friendly):
ghidriff vmlinux_5.15.0-100 vmlinux_5.15.0-101 \
-o /tmp/kdiff/ --max-section-funcs-analyze 8000
4. Search changed functions in subsystems like net/ipv4/ net/ipv6/ net/sched/ in the report
Found that skb->len upper limit check was missing before skb_copy_bits call in pre-patch version
→ OOB read, may be upgraded to OOB write with triggerable sysctl
5. Cross-verify on unpatched branches (e.g., Azure 5.15.0-1080 with delayed backport)
Check if the same function fix has been backported
If not backported → branch is still exploitable → rewrite and replay PoC
6. Write PoC: Modify syzkaller harness / directly write C PoC to trigger corresponding syscall
Verify branch panic / KASAN reports OOB注意事项
Notes
- 法律边界 — 武器化 N-day 必须在授权范围内(SRC / Bug Bounty / 自有靶机 / CTF)。对生产环境直接打 1-day 等同入侵
- 补丁可能只是"减小爆炸半径" — 看到 patch 不一定就是完整修复,有可能只是补一个利用路径,原始 bug 仍可从别的路径触发(一鱼多吃)
- 变量名/类型不要被欺骗 — Windows 补丁经常顺手做 cleanup / rename,看似变更很大但实际无关。要看控制流和数据流,不要看 token 级 diff
- 微软的补丁可能加了 mitigation 而不是 fix — 看到 这种 CFG 强化不要当成 fix,那是 mitigation
_guard_xfg_dispatch_icall_fptr - 匿名化 — writeup / PoC 公开时脱敏目标机器名、内网 IP、用户名(写
{target_ip}占位){username} - patched 版本上要能跑通无害化测试 — 别只在 unpatched 上跑,否则可能是环境因素导致的崩溃,不是漏洞
- 二进制 diff 不万能 — 编译器升级 / 优化等级变化也会让函数 layout 大变,先用 N 版本和 N-1 版本(同一编译器)对比,不要跨大版本
- Legal Boundary — Weaponizing N-day must be within authorized scope (SRC / Bug Bounty / own target machines / CTF). Directly exploiting 1-day on production environments equals intrusion
- Patches may only "reduce blast radius" — Seeing a patch does not mean it's a complete fix; it may only block one exploit path, while the original bug can still be triggered from other paths (one bug, multiple exploits)
- Don't be deceived by variable names/types — Windows patches often do cleanup/renaming along the way; seemingly large changes may be irrelevant. Focus on control flow and data flow, not token-level diff
- Microsoft patches may add mitigation instead of fix — Seeing CFG enhancements like is not a fix, it's a mitigation
_guard_xfg_dispatch_icall_fptr - Anonymization — Desensitize target machine names, internal IPs, usernames when publishing writeups/PoCs (use placeholders like
{target_ip}){username} - Run harmless tests on patched versions — Don't only run on unpatched versions; otherwise, crashes may be caused by environmental factors, not vulnerabilities
- Binary diff is not omnipotent — Compiler upgrades / optimization level changes can drastically alter function layout. Compare N and N-1 versions (same compiler) first, don't cross major versions
按需自举(On-Demand Bootstrap)
On-Demand Bootstrap
工具依赖
Tool Dependencies
| 工具 | 用途 | 可自动安装 |
|---|---|---|
| BinDiff (Google, 5.x+) | 函数级二进制 diff,IDA/Ghidra 插件 | ✓ (有官方 .deb / .msi) |
| Diaphora | IDA 老牌 diff 插件,需要 IDA Pro | ✓ (git clone) |
| ghidriff | Ghidra headless CLI diff,输出 markdown | ✓ (pip install ghidriff) |
| DeepDiff (商业) | 新一代 diff 工具,准确度更高 | ✗ (商业授权) |
| Ghidra | ghidriff 的运行底座 | ✓ |
| IDA Pro | BinDiff / Diaphora 的运行底座 | ✗ (商业) |
| Microsoft Update Catalog | 下 MSU/MSP 补丁包 | 在线服务 |
| wsuspect-proxy | 透明拦截 Windows Update 流量取补丁 | ✓ (git clone) |
| expand.exe / dism | 解 MSU / cab | ✓ (Windows 自带) |
| rpm2cpio / dpkg-deb | 解 Linux 发行版包 | ✓ |
| symchk | 从微软符号服务器拉 PDB | ✓ (Windows SDK) |
| Tool | Purpose | Auto-Installable |
|---|---|---|
| BinDiff (Google, 5.x+) | Function-level binary diff, IDA/Ghidra plugin | ✓ (official .deb / .msi available) |
| Diaphora | Established IDA diff plugin, requires IDA Pro | ✓ (git clone) |
| ghidriff | Ghidra headless CLI diff, outputs markdown | ✓ (pip install ghidriff) |
| DeepDiff (Commercial) | Next-generation diff tool, higher accuracy | ✗ (commercial license required) |
| Ghidra | Runtime base for ghidriff | ✓ |
| IDA Pro | Runtime base for BinDiff / Diaphora | ✗ (commercial) |
| Microsoft Update Catalog | Download MSU/MSP patch packages | Online service |
| wsuspect-proxy | Transparently intercept Windows Update traffic to get patches | ✓ (git clone) |
| expand.exe / dism | Unpack MSU / cab | ✓ (built into Windows) |
| rpm2cpio / dpkg-deb | Unpack Linux distribution packages | ✓ |
| symchk | Pull PDB from Microsoft Symbol Server | ✓ (Windows SDK) |
自举命令
Bootstrap Command
powershell
powershell -NoProfile -ExecutionPolicy Bypass -File "<SKILL_ROOT>\skills\scripts\bootstrap-reverse.ps1" -Capability @('bindiff','ghidriff','ghidra','wsuspect-proxy') -StartServices详细工具对比与命令见 。
详细 Patch Tuesday 工作流见 。
根因反推与 PoC 模板见 。
references/diff-tools-comparison.mdreferences/patch-tuesday-workflow.mdreferences/root-cause-and-poc.mdpowershell
powershell -NoProfile -ExecutionPolicy Bypass -File "<SKILL_ROOT>\skills\scripts\bootstrap-reverse.ps1" -Capability @('bindiff','ghidriff','ghidra','wsuspect-proxy') -StartServicesDetailed tool comparisons and commands are in .
Detailed Patch Tuesday workflow is in .
Root cause reverse-engineering and PoC templates are in .
references/diff-tools-comparison.mdreferences/patch-tuesday-workflow.mdreferences/root-cause-and-poc.md路由上下文
Routing Context
上游入口: (总控)、
skills/SKILL.mdrouting.md上游 skill:
- — 在做 diff 之前可能要先理解目标二进制的整体结构
reverse-engineering/ - — 如果补丁后版本无符号、补丁前有符号,先用 binary-diff 搬符号过来
binary-diff/
下游 skill:
- — 反推出 bug class 后,需要写完整利用(堆喷、ROP、SMEP/SMAP 绕过、提权 payload)
pwn-chain/ - — 把 N-day 武器化部署到目标网络(包装成可投递载荷、对接 C2)
pentest-tools/network-attack-defense/ - — 把这一个 N-day 串到完整攻击链里(初始访问 → 提权 → 横向)
attack-chain/
触发条件: 任务包含"N-day"、"补丁"、"CVE 复现"、"找补丁修了什么"、"打未更新主机" 等意图
Upstream Entry: (master control),
skills/SKILL.mdrouting.mdUpstream Skills:
- — May need to understand the overall structure of the target binary before performing diff
reverse-engineering/ - — If the post-patch version has no symbols but the pre-patch version does, use binary-diff to migrate symbols first
binary-diff/
Downstream Skills:
- — After reverse-engineering the bug class, need to write complete exploits (heap spray, ROP, SMEP/SMAP bypass, privilege escalation payload)
pwn-chain/ - — Weaponize N-day exploits and deploy to target networks (package as deliverable payload, integrate with C2)
pentest-tools/network-attack-defense/ - — Integrate this N-day into a complete attack chain (initial access → privilege escalation → lateral movement)
attack-chain/
Trigger Conditions: Task contains intents like "N-day", "patch", "CVE reproduction", "find what the patch fixed", "target unpatched hosts" etc.
任务完成自检(声称完成前 MUST 通过)
Task Completion Self-Check (MUST pass before claiming completion)
- 我是否执行了工作流中的每一步(而不是只阅读)?
- 我是否基于 使用了真实工具路径?
tool-index - 我是否产出了可复现证据(命令/脚本/截图/报告)?
- 我是否完成并回写了 RULES 要求的 Checklist 项?
- Have I executed every step in the workflow (instead of just reading)?
- Have I used real tool paths based on ?
tool-index - Have I produced reproducible evidence (commands/scripts/screenshots/reports)?
- Have I completed and written back the Checklist items required by RULES?