Windows 取证痕迹批量解析编排
负责调查流水线的第一阶段,对 sources/<asset>/ 下已经只读挂载的 Windows 卷和资产级内存镜像进行批量解析。它按卷建立 export/<asset>/<source>/<artifact>/ 镜像目录,调度 MFT、EVTX、注册表、Prefetch、Amcache、Shimcache、SRUM、LNK/Jump Lists、Shellbags、浏览器、YARA、内存和时间线等解析流程,并在 audit/<asset>/parse_state.txt 记录每个证据源、每类痕迹的 OK、EMPTY、PARTIAL、FAILED 状态,实现断点续跑。主解析器和文档化备用方案均失败时,还可查询 SIFT_SERVER_DFIR_TOOLS.json 选择受控的第三层工具路由,并把无法处理的痕迹写入失败日志。
在 AI 中使用此 Skill将本页链接复制给 AI,即可让 AI 获取完整 Skill 内容并按此执行
安全提示: 本站 Skill 均经 ChatGPT 最新模型扫描,未发现恶意脚本及危险指令、未检出已知恶意行为特征,但不保证绝对安全,使用即表示接受此风险
Skill 文件
版本 20260601 · d3c256cf689514cbbf038371acd36caa
references/
skills/
dfir-amcache/
dfir-browser/
dfir-evtx/
dfir-file-carving/
dfir-lnk-jumplists/
dfir-memory-volatility/
dfir-mft/
dfir-plaso-timeline/
dfir-prefetch/
dfir-recentfilecache/
dfir-recyclebin/
dfir-registry/
dfir-scheduled-tasks/
dfir-shellbags/
dfir-shimcache/
dfir-sleuthkit-file-recovery/
dfir-srum/
dfir-strings/
dfir-yara/
SKILL.md
---
name: case-parse
description: Orchestrate parsing of mounted Windows evidence across assets, track resumable artifact status, and route documented parser fallbacks.
---
## XingLo Standalone Package Notes
This orchestrator depends on the artifact-specific parsing instructions. They are bundled under `references/skills/<skill>/guide.md`. If a referenced `/dfir-*` command is not separately installed, use the matching local guide as the parser definition. The SIFT fallback router and tool-path configuration are also bundled under `references/`.
# Skill: case-parse — Phase 1 Artifact Parsing
## Overview
First phase of the investigation pipeline. Assumes volumes are already mounted by the operator.
Runs all forensic parsers on **each mounted Windows filesystem** (NTFS, FAT32, exFAT, …) found as
a subdirectory under `./sources/<asset>/`, writing parsed artifacts to the mirrored path
`export/<asset>/<source-dir>/<artifact>/`. Source evidence is never modified. Per-source-directory,
per-artifact status is tracked in `parse_state.txt` so re-runs resume intelligently. Invoked
standalone with `/case-parse` or as the first step of `/case-investigate`.
**Before starting:** `./context/case_context.md` must list every asset ID and the Incident Window.
Volumes must already be mounted under `./sources/<asset>/` before invoking this skill.
---
## Role & Operating Rules
**Role:** Forensic parsing orchestrator on the SANS SIFT Workstation. During the parse phase you
select and sequence the appropriate `dfir-*` skills, route their output to the correct export path,
and track per-source-directory state. Parser logic lives in the individual skills, not here.
**Rules:**
- MUST write parsed tool output only under `./export/`, and all run-records/control only under
`./audit/`. MUST NOT write to `./analysis/`, `./reports/`, `sources/`, `/mnt/`, `/media/`, or
any other location.
- MUST record only real tool output. MUST NOT fabricate or invent parsed content.
- MUST select parsers from the available `dfir-*` skills first — they are the primary, vetted
source. The tool router (`~/.claude/skills/case-parse/references/SIFT_SERVER_DFIR_TOOLS.json`) is the **only** sanctioned
source outside the skills, and only in the fallback tier (see Phase 1.5).
- MUST NOT perform Analysis, Correlation, or Reporting — those are `/case-analyze`,
`/case-correlate`, `/case-report`.
- MUST set `chmod 444` on every successful parsed artifact output file under `./export/`.
- MUST classify terminal failures along the chain **primary skill → documented fallback → router**.
Input rejected by all three is **unparseable**: logged in `audit/artifact_failures.log` and
surfaced in the report's Gaps / Unknowns section. One router attempt only; never loop. Never
fabricate output to cover a failure.
- MUST NOT treat a zero exit code as proof of success. Some tools (notably the EZ Tools — LECmd,
JLECmd — which enumerate the whole `-d` tree up front) return **exit 0 even after a fatal
enumeration/IO abort that wrote zero or a truncated file** (e.g. one unreadable inode on the mount
→ `System.IO.IOException: Input/output error`). `run_artifact` already flags a *missing* output as
`EMPTY`; beyond that, the **owning skill's verify step** must confirm output completeness against an
independent ground truth (e.g. a `find` count that walks past the bad inode) and scan the captured
tool log for `Error … / IOException / Input/output error`. A truncated-but-non-empty file passing as
`OK` is a silent failure — the skill's verify step is what catches it.
- MUST classify every parse into one of **three** outcomes, not two — `OK` / `PARTIAL` / `FAILED`.
`PARTIAL` is the middle state: zero exit **and** non-empty output **but** the tool log carries a
*non-fatal* integrity warning (e.g. `hbin header incorrect at 0x…`, a bad/recomputed `New Checksum`,
or `extra … non-zero data` past a high offset in a registry hive or ESE DB). The output is **usable
and kept as `OK`-grade evidence**, but late/high-offset entries may be missing, so it MUST NOT be
treated as a complete extraction. Handling: record a **completeness caveat** — not a hard failure —
to `audit/artifact_failures.log` (asset, artifact, the verbatim warning) using the sanctioned
single-line append (`printf '%s | %s | %s\n' "$(date -u +%FT%TZ)" "<skill>" "<warning>" >>
./audit/artifact_failures.log`); surface it under the report's Gaps / Unknowns; and **do not read the
absence of an entry as proof of absence**. This is the single source of truth for `PARTIAL`; owning
skills reference it rather than restating the rule.
- Mounting is the operator's responsibility. Do not call `/tools-mount`.
**Supported flags:**
| Flag | Behaviour |
|------|-----------|
| *(none)* | Smart resume — skip source-dirs/artifacts with `OK` status; retry `FAILED`/`EMPTY` |
| `--reparse <artifact>` | Force re-run one artifact type across all source dirs and assets |
| `--force` | Delete all `parse_state.txt` files and re-parse everything |
`MAX_PARALLEL` (env, default 2) caps concurrent assets. Within each source directory, Group A
artifact skills run in parallel (up to 4); Group B runs sequentially.
---
## Output layout
Export mirrors the source directory name exactly — the relationship between parsed output and its
origin is unambiguous at a glance.
```
sources/<asset>/
<source-dir>/ ← any operator-created subdir (mnt-NNN-<imgbase>, exported-keys/, …)
export/<asset>/
<source-dir>/ ← same name as in sources/ — one-to-one mirror
mft/ usnjrnl/ evtx/ registry/ scheduledtasks/ prefetch/
amcache/ recentfilecache/ shimcache/ srum/
lnk/ shellbags/ recyclebin/ browser/ yara/
memory-<mem-filename>/ ← Volatility output; one directory per memory capture file
audit/
.dfir_phase ← case-global phase marker (gates ./export writes)
artifact_failures.log ← case-global; failed/unparseable artifacts
decisions.log ← case-global; autonomous path choices when blocked
<asset>/
parse_state.txt ← per-asset state; one line per source-dir + artifact
parse.log ← per-asset human-readable progress log
```
`parse_state.txt` line format — `SOURCE_DIR|ARTIFACT|STATUS|ISO8601_UTC|FILE_COUNT|BYTES`:
```
mnt-001-base-dc-cdrive|mft|OK|2026-06-05T14:32:01Z|3|45233190
mnt-001-base-dc-cdrive|evtx|FAILED|2026-06-05T14:38:12Z|0|0
_asset|memory-dc01.img|OK|2026-06-05T14:50:00Z|8|10485760
```
---
## Orchestration helpers
These helpers encode output routing, state tracking, and WORM locking only. Parser selection and
tool invocation live in the `dfir-*` skills.
```bash
CASE_ROOT="$(pwd)"
source ~/.claude/skills/case-parse/references/tools.env
# run_artifact ASSET SOURCE_DIR ARTIFACT CMD [ARGS...]
# SOURCE_DIR is "_asset" for memory captures (files in sources/<asset>/, not subdirs).
run_artifact() {
local asset="$1" srcdir="$2" artifact="$3"; shift 3
local outdir state ts n b
[[ "$srcdir" == "_asset" ]] \
&& outdir="$CASE_ROOT/export/$asset/$artifact" \
|| outdir="$CASE_ROOT/export/$asset/$srcdir/$artifact"
state="$CASE_ROOT/audit/$asset/parse_state.txt"
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
mkdir -p "$outdir" "$CASE_ROOT/audit/$asset"
find "$outdir" -type f -exec chmod u+w {} + 2>/dev/null # re-parse safety
sed -i "/^${srcdir}|${artifact}|/d" "$state" 2>/dev/null # drop prior status line
if "$@"; then
n=$(find "$outdir/" -type f 2>/dev/null | wc -l)
b=$(du -sb "$outdir/" 2>/dev/null | cut -f1 || echo 0)
if [[ "$n" -eq 0 ]]; then
printf '%s|%s|EMPTY|%s|0|0\n' "$srcdir" "$artifact" "$ts" >> "$state"
printf '[EMPTY] %s/%s/%s\n' "$asset" "$srcdir" "$artifact" \
>> "$CASE_ROOT/audit/artifact_failures.log"
else
printf '%s|%s|OK|%s|%d|%d\n' "$srcdir" "$artifact" "$ts" "$n" "$b" >> "$state"
find "$outdir" -type f -exec chmod 444 {} + 2>/dev/null
fi
else
printf '%s|%s|FAILED|%s|0|0\n' "$srcdir" "$artifact" "$ts" >> "$state"
printf '[FAILED] %s/%s/%s (exit %d)\n' "$asset" "$srcdir" "$artifact" "$?" \
>> "$CASE_ROOT/audit/artifact_failures.log"
fi
}
# artifact_done ASSET SOURCE_DIR ARTIFACT — returns 0 if already OK (smart resume).
artifact_done() {
grep -q "^${2}|${3}|OK|" "$CASE_ROOT/audit/${1}/parse_state.txt" 2>/dev/null
}
```
---
## Phase 0 — Bootstrap
1. Parse flags:
- `--force`: `rm -f "$CASE_ROOT"/audit/*/parse_state.txt`
- `--reparse <artifact>`: `sed -i "/|${artifact}|/d" "$CASE_ROOT"/audit/*/parse_state.txt`
2. `source ~/.claude/skills/case-parse/references/tools.env`
3. Read `./context/case_context.md` — identify all `asset_id` values and their sources paths.
4. Read the actual directory tree: `find ./sources -maxdepth 3 | sort`. Reconcile with
`case_context.md`: assets absent from `./sources/` are skipped and logged; extra dirs not in
`case_context.md` are noted for the operator.
5. Set phase marker: `printf 'parse\n' > "$CASE_ROOT/audit/.dfir_phase"`. **This skill is the sole
owner of `./audit/.dfir_phase`** — it arms `parse` here and closes it (`parse-complete`) only at
the very end (after every asset is parsed). No artifact parser (`/dfir-mft`, `/dfir-evtx`, …) ever
writes, changes, or closes the marker; if one is invoked standalone and its `./export/` write is
blocked, the fix is to run `/case-parse` (here), not to touch the marker from the artifact skill.
---
## Phase 1 — Artifact Parsing
**Mounting is the operator's responsibility.** Do not call `/tools-mount`.
For each asset, discover source directories under `./sources/<asset>/`, excluding:
- `e01-*` — EWF FUSE containers (contain `ewf1`, not a mountable filesystem)
- `vss-*` — VSS FUSE containers (contain `vss1`/`vss2`/…, not a mountable filesystem)
All remaining directories are processed. Each artifact skill skips gracefully when its required
input files are absent — see the **Skip if** column in the tables below. No pre-probe is needed;
a directory with only exported registry hives, event logs, or other partial artifacts is valid.
Every **Skip if** presence check is **case-insensitive** (`find -ipath`, see the convention below):
a lowercase `windows/prefetch/` must not be treated as "absent".
### Case-insensitive path resolution (Linux mounts) — convention
Windows is case-insensitive, but a disk image mounted on Linux (ntfs-3g, and most loop/FUSE mounts)
is **case-sensitive**. A path the artifact skills spell in canonical Windows casing
(`Windows/System32/config/SYSTEM`) may sit on disk as `windows/system32/config/SYSTEM` or any other
mix, depending on how the image was created. Hardcoding the casing makes a present artifact look
**absent** — a silent miss, the worst failure mode.
**Rule for every artifact skill and every presence check:** never pass a hardcoded mixed-case path to
a parser. Resolve the real on-disk path first with `find -ipath`, which matches the whole path
case-insensitively (and `*` spans `/`), then use the resolved value:
```bash
SRC="./sources/<asset>/<source-dir>"
# single file (hive, db, .bcf):
HIVE="$(find "$SRC" -ipath '*/Windows/System32/config/SYSTEM' -type f 2>/dev/null | head -1)"
# directory (event logs, Prefetch, Tasks):
LOGS="$(find "$SRC" -ipath '*/Windows/System32/winevt/Logs' -type d 2>/dev/null | head -1)"
```
- **Absent** (empty result) → record the gap in `audit/artifact_failures.log`, mark EMPTY, move on.
- **Multiple hits** (e.g. a VSS copy mounted under the same source-dir) → prefer the live-volume path
and record the choice in `audit/decisions.log`.
The artifact skills each carry a self-contained `find -ipath` locate step (so they also work
standalone); this section is the canonical statement of the rule.
### Per-source-directory artifacts
Run **Group A in parallel** (up to 4 concurrent per source dir) then **Group B sequentially**.
Guard each invocation with `artifact_done` for smart resume; wrap with `run_artifact` for output
routing, state tracking, and WORM locking.
**Group A — independent inputs, safe to parallelise:**
| Artifact | Skill | Skip if |
|---|---|---|
| MFT & UsnJrnl | `/dfir-mft` | — |
| Event logs | `/dfir-evtx` | — |
| Prefetch | `/dfir-prefetch` | `Windows/Prefetch/` absent |
| Amcache | `/dfir-amcache` | `Amcache.hve` absent |
| RecentFileCache | `/dfir-recentfilecache` | `.bcf` absent (Win 7 only) |
| LNK / Jump Lists | `/dfir-lnk-jumplists` | — |
| Recycle Bin | `/dfir-recyclebin` | `$Recycle.Bin/` absent |
| Browser | `/dfir-browser` | — |
| Scheduled Tasks | `/dfir-scheduled-tasks` | `System32/Tasks/` and `Tasks/` both absent |
**Group B — share the SYSTEM hive, run sequentially:**
| Artifact | Skill | Skip if |
|---|---|---|
| Registry (machine + user hives) | `/dfir-registry` | — |
| Shimcache | `/dfir-shimcache` | — |
| SRUM | `/dfir-srum` | `sru/SRUDB.dat` absent |
| Shellbags | `/dfir-shellbags` | — |
Output for each artifact: `export/<asset>/<source-dir>/<artifact>/`.
### Per asset-level artifacts
**Memory** (`/dfir-memory-volatility`) — use `_asset` as `SOURCE_DIR` in `run_artifact`:
Memory captures are identified via a three-layer check applied to every file directly under
`./sources/<asset>/` (not subdirectories):
1. **`case_context.md` Sources Inventory (authoritative)** — if the file's row has `Type = memory`,
treat it as a memory capture. No further check needed.
2. **`file` magic-byte check (confirmation for untyped rows)** — if `Type` is blank or the file
is not listed, run `file <path>` and match known signatures:
- Contains `crash dump`, `hibernation`, `VMware`, `LiME`, or `ELF` → memory ✓
- Returns `data` (no recognizable magic) → include with a warning; Volatility will fail fast
on a non-memory file and `run_artifact` will record `FAILED` cleanly
3. **Not in Sources Inventory and `file` is inconclusive** → log as undeclared in `parse.log`,
skip. Operator must add the file to the Sources Inventory with the correct `Type`.
Each confirmed memory file gets its own output directory:
- Artifact key: `memory-<filename>` (e.g., `memory-dc01.img`)
- Output: `export/<asset>/memory-<filename>/`
- parse_state.txt key: `_asset|memory-<filename>`
---
## Phase 1.5 — Unmapped & exhausted-fallback artifacts (tool router)
When a `dfir-*` skill's primary AND documented fallback both fail/empty, **or** when the evidence
holds an artifact type no skill covers (email, archive, document, …), consult the tool router once.
**Router catalog:** `~/.claude/skills/case-parse/references/SIFT_SERVER_DFIR_TOOLS.json` — read-only, keyed by `artifact_family`.
```bash
router_tool() {
local q="$1"
if command -v jq >/dev/null 2>&1; then
jq -r --arg q "$q" '
.entries[] | select(
(.artifact_family | ascii_downcase) == ($q | ascii_downcase)
or ((.artifact + " " + (.artifact_aliases | join(" "))) | ascii_downcase | contains($q | ascii_downcase))
) | [.tool, .command, .analyst_use] | @tsv' \
"$HOME/.claude/skills/case-parse/references/SIFT_SERVER_DFIR_TOOLS.json"
else
python3 - "$HOME/.claude/skills/case-parse/references/SIFT_SERVER_DFIR_TOOLS.json" "$q" <<'PY'
import json, sys
router, q = sys.argv[1], sys.argv[2].lower()
for e in json.load(open(router))["entries"]:
hay = (e["artifact"] + " " + " ".join(e.get("artifact_aliases", []))).lower()
if e["artifact_family"].lower() == q or q in hay:
print("\t".join([e["tool"], e["command"], e["analyst_use"]]))
PY
fi
}
```
Invoke the resolved command through `run_artifact` so output routing, state tracking, and WORM
locking are applied identically to skill-sourced artifacts. Filename convention:
`<asset>-<srcdir>-<artifact>-<rtool>.ext`. If the router returns no match, or the router tool also
fails/empties, log as **unparseable** in `audit/artifact_failures.log` and stop.
---
## Phase 2 handoff
```bash
# Failure summary
if [[ -f "$CASE_ROOT/audit/artifact_failures.log" ]]; then
printf '\n[WARN] %d artifact(s) failed or produced no output:\n' \
"$(wc -l < "$CASE_ROOT/audit/artifact_failures.log")"
cat "$CASE_ROOT/audit/artifact_failures.log"
printf '\nFull log: ./audit/artifact_failures.log\n'
fi
# Lock export back to read-only; anything after parse must not write parsed evidence.
# Only /case-parse closes the phase, and only here — once every asset has been parsed.
printf 'parse-complete\n' > "$CASE_ROOT/audit/.dfir_phase"
printf '\nAll assets parsed. Next: /case-analyze\n'
```
---
## Notes
- This skill only orchestrates parsing. Mounting is an operator step done before invocation.
Analysis, correlation, and reporting are separate skills (`/case-analyze`, `/case-correlate`,
`/case-report`), chained by `/case-investigate`.
- Export path mirrors the source dir name exactly — `export/<asset>/<source-dir>/` — so parsed
output is trivially traceable to its origin without consulting any index.
- Never use Write/Edit on `export/` — the Write/Edit tools are denied there, and `evidence_guard.py`
only permits Bash writes into `./export` while `.dfir_phase` reads `parse`.
- Re-running is safe: `OK` artifacts are skipped; `FAILED`/`EMPTY` are retried. A `dfir-*` skill
whose primary and fallback both fail/empty is escalated to the tool router (Phase 1.5). If that
also fails, the artifact is logged as unparseable.
此文件不提供内嵌文本预览
请使用左侧文件行末尾的外链图标打开原始文件。
