/windiff-version-diff-analysis
Generate and interpret security-research diffs between Windows versions or patch levels using this repo's WinDiff CLI and databases. Use when comparing Windows builds or binaries such as ntoskrnl.exe, ntdll.dll, win32k*.sys, ci.dll, or cng.sys to find changed syscalls, symbols,
$ npx -y skills add ergrelet/windiff --skill windiff-version-diff-analysis --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/windiff-version-diff-analysis
Context preview
The summary Claude sees to decide when to auto-load this skill.
Generate and interpret security-research diffs between Windows versions or patch levels using this repo's WinDiff CLI and databases. Use when comparing Windows builds or binaries such as ntoskrnl.exe, ntdll.dll, win32k*.sys, ci.dll, or cng.sys to find changed syscalls, symbols,
SKILL.md
windiff-version-diff-analysis.SKILL.mdname: windiff-version-diff-analysis
description: >-
Generate and interpret security-research diffs between Windows versions or patch
levels using this repo's WinDiff CLI and databases. Use when comparing Windows
builds or binaries such as ntoskrnl.exe, ntdll.dll, win32k*.sys, ci.dll, or cng.sys
to find changed syscalls, symbols, types, mitigation flags, callbacks, ETW/EtwTi
telemetry, code-integrity behavior, drivers, or attack surface. Explain likely
intent and security relevance with Windows-internals knowledge, and frame findings
for anti-malware/EDR, anti-cheat, and vulnerability-research audiences rather than
returning an uninterpreted symbol list.
WinDiff Version Diff Analysis
Compare two Windows builds and turn the raw symbol/type/syscall delta into a security-research report: what was added, what it probably *does*, and why it matters for attack surface, exploitation, or defense.
Run this skill from a **WinDiff** repository checkout. It uses `windiff_cli` to generate the per-binary JSON databases, then diffs and interprets them. The interpretation is the point: explain intent from Windows internals conventions instead of merely listing symbols.
Locate bundled resources
Resolve all `scripts/` and `references/` paths relative to this `SKILL.md`, not relative to the current working directory and not through a harness-specific directory such as `.claude/` or `.agents/`. Before running a bundled script, set `SKILL_DIR` to the absolute directory containing this file. The examples below assume that has been done:
SKILL_DIR="<absolute directory containing this SKILL.md>"
If separate shell-tool calls do not share environment, substitute that absolute path for `$SKILL_DIR` in each command instead of relying on prior shell state.
Also identify the repository root (the directory containing `windiff_cli/`, `windiff_frontend/`, and `ci/`) and run repository commands from there. Keep generated configs, databases, and analysis artifacts under its git-ignored `local/` directory.
Workflow
1. Pin down scope
Establish, asking the user only if genuinely ambiguous:
- **Two OS versions** as WinDiff triples `version / update / architecture`
(e.g. `21H2 / BASE / amd64` and `11-24H2 / KB5074105 / amd64`). `update` is `BASE` for an RTM image or a `KB...` number for a patch. The path suffix used in filenames is `version_update_architecture`, e.g. `11-24H2_KB5074105_amd64`.
- **Binaries** to compare. Default to the security-relevant core when the user is
vague: `ntoskrnl.exe`, `ntdll.dll`, `win32k.sys`, `win32kbase.sys`, `win32kfull.sys`, `ci.dll`, `cng.sys`. Read `$SKILL_DIR/references/windows-components.md` for what each one governs.
- **Focus**: syscalls, mitigation flags, new attack surface, a specific
component/feature, etc. This steers interpretation, not data generation.
`ci/db_configuration.json` is the canonical list of tracked versions and binaries — consult it for valid `version`/`update` spellings.
2. Generate the databases with windiff_cli
Write a **minimal** config containing only the two OS versions and the chosen binaries, then run the CLI into a scratch output dir (keep it under the repo's git-ignored `local/`). Use `$SKILL_DIR/scripts/make_config.py` to build the config:
python3 "$SKILL_DIR/scripts/make_config.py" \
--os "21H2:BASE:amd64" --os "11-24H2:KB5074105:amd64" \
--binary ntoskrnl.exe --binary ntdll.dll --binary win32k.sys --binary ci.dll \
> local/windiff_diff_config.json
cd windiff_cli
cargo run --release -- --low-storage-mode \
../local/windiff_diff_config.json ../local/windiff_diff_out/
This downloads PEs from Winbindex and PDBs from MSDL, so it **needs network access** and takes minutes per binary. Follow the active harness's normal permission or approval flow for networked commands. `--low-storage-mode` keeps memory bounded. If the CLI fails for one OS (a build may be missing from Winbindex), report which version/update is unavailable and suggest the nearest tracked one from `ci/db_configuration.json`.
If the user says the databases already exist (e.g. in `windiff_frontend/public/`), skip generation and point the diff script at that directory instead.
3. Diff each binary
`$SKILL_DIR/scripts/windiff_diff.py` does the deterministic set/text diff so you never hand-compute it. Run it per binary; it prints a summary to stderr and structured JSON to stdout.
python3 "$SKILL_DIR/scripts/windiff_diff.py" \
local/windiff_diff_out ntoskrnl.exe 21H2_BASE_amd64 11-24H2_KB5074105_amd64 \
> local/diff_ntoskrnl.json
Use `--list` to see available suffixes, `--kinds` to restrict (e.g. `--kinds syscalls types`). Anonymous `_unnamed_0xNNNN` types are hidden from the top-level added/removed/modified lists by default (their synthetic ids churn between builds — noise); pass `--include-anon` only if you specifically need them.
**`resolved_member_changes` — where new mitigation flags actually show up.** Bitfields like `_EPROCESS::MitigationFlagsValues`, `MitigationFlags2Values`, or `_KPROCESS` flag words are typed as *anonymous* `_unnamed_0xNNNN` structs, and the individual bits (e.g. `RedirectionTrustPolicyEnabled : 1`) live inside them. When Microsoft adds a mitigation, a new bit appears in that anonymous struct — and its synthetic id churns, so a naive diff would either hide it or show it as noise. The script resolves this for you: the `types.resolved_member_changes` array follows each anonymous member back to its named parent (across the id change) and reports the real per-member delta as `<parent>::<member>` with the added/removed declarations. **This is the first place to look for new mitigation bits and other new bitfield flags** — e.g. a new bit under `_EPROCESS::MitigationFlags2Values`, or a new `_KALPC_MESSAGE::u1::s1` flag. Resolution recurses through nested anonymous structs/unions, so the `path` may be several `::` levels deep.
**Noise to discount when reading
Read more
name: windiff-version-diff-analysis description: >- Generate and interpret security-research diffs between Windows versions or patch levels using this repo's WinDiff CLI and databases. Use when comparing Windows builds or binaries such as ntoskrnl.exe, ntdll.dll, win32k*.sys, ci.dll, or cng.sys to find changed syscalls, symbols, types, mitigation flags, callbacks, ETW/EtwTi telemetry, code-integrity behavior, drivers, or attack surface. Explain likely intent and security relevance with Windows-internals knowledge, and frame findings for anti-malware/EDR, anti-cheat, and vulnerability-research audiences rather than returning an uninterpreted symbol list.
WinDiff Version Diff Analysis
Compare two Windows builds and turn the raw symbol/type/syscall delta into a security-research report: what was added, what it probably *does*, and why it matters for attack surface, exploitation, or defense.
Run this skill from a **WinDiff** repository checkout. It uses `windiff_cli` to generate the per-binary JSON databases, then diffs and interprets them. The interpretation is the point: explain intent from Windows internals conventions instead of merely listing symbols.
Locate bundled resources
Resolve all `scripts/` and `references/` paths relative to this `SKILL.md`, not relative to the current working directory and not through a harness-specific directory such as `.claude/` or `.agents/`. Before running a bundled script, set `SKILL_DIR` to the absolute directory containing this file. The examples below assume that has been done:
SKILL_DIR="<absolute directory containing this SKILL.md>"
If separate shell-tool calls do not share environment, substitute that absolute path for `$SKILL_DIR` in each command instead of relying on prior shell state.
Also identify the repository root (the directory containing `windiff_cli/`, `windiff_frontend/`, and `ci/`) and run repository commands from there. Keep generated configs, databases, and analysis artifacts under its git-ignored `local/` directory.
Workflow
1. Pin down scope
Establish, asking the user only if genuinely ambiguous:
- **Two OS versions** as WinDiff triples `version / update / architecture`
(e.g. `21H2 / BASE / amd64` and `11-24H2 / KB5074105 / amd64`). `update` is `BASE` for an RTM image or a `KB...` number for a patch. The path suffix used in filenames is `version_update_architecture`, e.g. `11-24H2_KB5074105_amd64`.
- **Binaries** to compare. Default to the security-relevant core when the user is
vague: `ntoskrnl.exe`, `ntdll.dll`, `win32k.sys`, `win32kbase.sys`, `win32kfull.sys`, `ci.dll`, `cng.sys`. Read `$SKILL_DIR/references/windows-components.md` for what each one governs.
- **Focus**: syscalls, mitigation flags, new attack surface, a specific
component/feature, etc. This steers interpretation, not data generation.
`ci/db_configuration.json` is the canonical list of tracked versions and binaries — consult it for valid `version`/`update` spellings.
2. Generate the databases with windiff_cli
Write a **minimal** config containing only the two OS versions and the chosen binaries, then run the CLI into a scratch output dir (keep it under the repo's git-ignored `local/`). Use `$SKILL_DIR/scripts/make_config.py` to build the config:
python3 "$SKILL_DIR/scripts/make_config.py" \ --os "21H2:BASE:amd64" --os "11-24H2:KB5074105:amd64" \ --binary ntoskrnl.exe --binary ntdll.dll --binary win32k.sys --binary ci.dll \ > local/windiff_diff_config.json cd windiff_cli cargo run --release -- --low-storage-mode \ ../local/windiff_diff_config.json ../local/windiff_diff_out/
This downloads PEs from Winbindex and PDBs from MSDL, so it **needs network access** and takes minutes per binary. Follow the active harness's normal permission or approval flow for networked commands. `--low-storage-mode` keeps memory bounded. If the CLI fails for one OS (a build may be missing from Winbindex), report which version/update is unavailable and suggest the nearest tracked one from `ci/db_configuration.json`.
If the user says the databases already exist (e.g. in `windiff_frontend/public/`), skip generation and point the diff script at that directory instead.
3. Diff each binary
`$SKILL_DIR/scripts/windiff_diff.py` does the deterministic set/text diff so you never hand-compute it. Run it per binary; it prints a summary to stderr and structured JSON to stdout.
python3 "$SKILL_DIR/scripts/windiff_diff.py" \ local/windiff_diff_out ntoskrnl.exe 21H2_BASE_amd64 11-24H2_KB5074105_amd64 \ > local/diff_ntoskrnl.json
Use `--list` to see available suffixes, `--kinds` to restrict (e.g. `--kinds syscalls types`). Anonymous `_unnamed_0xNNNN` types are hidden from the top-level added/removed/modified lists by default (their synthetic ids churn between builds — noise); pass `--include-anon` only if you specifically need them.
**`resolved_member_changes` — where new mitigation flags actually show up.** Bitfields like `_EPROCESS::MitigationFlagsValues`, `MitigationFlags2Values`, or `_KPROCESS` flag words are typed as *anonymous* `_unnamed_0xNNNN` structs, and the individual bits (e.g. `RedirectionTrustPolicyEnabled : 1`) live inside them. When Microsoft adds a mitigation, a new bit appears in that anonymous struct — and its synthetic id churns, so a naive diff would either hide it or show it as noise. The script resolves this for you: the `types.resolved_member_changes` array follows each anonymous member back to its named parent (across the id change) and reports the real per-member delta as `<parent>::<member>` with the added/removed declarations. **This is the first place to look for new mitigation bits and other new bitfield flags** — e.g. a new bit under `_EPROCESS::MitigationFlags2Values`, or a new `_KALPC_MESSAGE::u1::s1` flag. Resolution recurses through nested anonymous structs/unions, so the `path` may be several `::` levels deep.
**Noise to discount when reading
Tool that allows comparing symbol, type and syscall information of Microsoft Windows binaries across different versions of the OS, using a Web UI and/or LLMs.

