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,9 @@
Apache License 2.0 — see the repository root LICENSE file for the full text.
Copyright the AnalystAIPack contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0

View File

@@ -0,0 +1,89 @@
---
name: analyzing-rich-header-and-compiler-artifacts
description: 'Analyzes the PE Rich header and related compiler artifacts to fingerprint the build
toolchain, cluster related samples, and detect inconsistencies that suggest tampering. Activates
for requests to analyze a Rich header, fingerprint the compiler/linker, or cluster samples by
build toolchain.'
domain: cybersecurity
subdomain: malware-analysis
tags:
- malware-analysis
- pe
- rich-header
- toolchain
- clustering
version: 1.0.0
author: analyst-ai-pack
license: Apache-2.0
mitre_attack:
- T1027
- T1587.001
- T1036
d3fend:
- D3-SDA
- D3-FA
references:
- 'PE Format — https://learn.microsoft.com/windows/win32/debug/pe-format'
- 'Rich header structure (public reverse-engineering research) — https://learn.microsoft.com/windows/win32/debug/pe-format'
---
# Analyzing Rich Header and Compiler Artifacts
## When to Use
- You have a Windows PE and want to fingerprint its build toolchain (compiler/linker product IDs
and build numbers) from the Rich header.
- You are clustering samples by toolchain or detecting Rich-header tampering/forgery.
**Do not use** the Rich header as definitive attribution — it can be copied or stripped. This skill
reads the PE statically and executes nothing.
## Prerequisites
- The PE sample (read inertly).
## Safety & Handling
- Read bytes statically; treat the sample as malicious data.
## Workflow
### Step 1: Parse and decode the Rich header
```bash
python scripts/analyst.py rich sample.exe
```
Locates the `Rich` marker, recovers the XOR key (the DWORD after `Rich`), decodes the `DanS`-
prefixed entries, and lists `(product_id, build_id, use_count)` tuples.
### Step 2: Fingerprint the toolchain
Map product IDs to compiler/linker products and build numbers to identify the Visual Studio
version(s) used.
### Step 3: Compute a clustering hash
Hash the decoded Rich entries to produce a toolchain fingerprint for grouping related samples.
### Step 4: Check for inconsistencies
Compare the Rich-derived linker version against the PE optional-header linker version; mismatches
suggest tampering or a copied header.
## Validation
- The XOR key correctly decodes the `DanS` signature at the start of the block.
- Decoded entries have plausible product IDs and use counts.
- The toolchain fingerprint is reproducible across identical builds.
## Pitfalls
- Samples with no Rich header (non-MSVC toolchains, stripped headers).
- Forged Rich headers copied from a benign binary.
- Confusing the Rich checksum/key handling and misdecoding entries.
## References
- See [`references/api-reference.md`](references/api-reference.md) for the parser.
- PE format documentation (linked in frontmatter).

View File

@@ -0,0 +1,39 @@
# API Reference: Analyzing Rich Header and Compiler Artifacts
## Overview
`scripts/analyst.py` parses the PE Rich header: it finds the `Rich` marker, recovers the XOR key,
locates the XOR-encoded `DanS` signature, decodes the comp.id entries into
`(product_id, build_id, use_count)` tuples, and emits a toolchain fingerprint hash. It reads bytes
statically and executes nothing.
## Dependencies
| Package | Version | Purpose |
|---------|---------|---------|
| (stdlib) | — | struct, hashlib, JSON, file IO |
## Core functions
### `rich(path)`
Returns Rich-header presence, XOR key, decoded entries, and a clustering fingerprint.
### `_find_dans(data, rich_off, key)`
Scans backward for the XOR-encoded `DanS` (`0x536E6144`) signature.
## Rich header layout
`DanS` + 3 padding DWORDs, then 8-byte entries (`comp.id` = product_id<<16 | build_id, and
use_count), all XOR'd with the key, terminated by `Rich` + key.
## Usage
```bash
python scripts/analyst.py rich sample.exe
```
## Sources
- PE Format — https://learn.microsoft.com/windows/win32/debug/pe-format
- Rich header `DanS`/comp.id structure from public PE reverse-engineering research
- Toolchain-clustering use of the Rich header from public malware-clustering practice

View File

@@ -0,0 +1,79 @@
#!/usr/bin/env python3
"""Parse and decode the PE Rich header to fingerprint the build toolchain.
Locates the 'Rich' marker, recovers the XOR key, decodes the DanS-prefixed comp.id entries, and
emits (product_id, build_id, use_count) tuples plus a clustering hash. Reads bytes statically;
executes nothing.
"""
from __future__ import annotations
import argparse
import hashlib
import json
import struct
import sys
from pathlib import Path
def _find_rich(data: bytes) -> tuple[int, int] | None:
# Rich header lives between the DOS stub and PE header (first 0x200 bytes typically).
head = data[:0x400]
rich_off = head.rfind(b"Rich")
if rich_off == -1:
return None
key = struct.unpack_from("<I", head, rich_off + 4)[0]
return rich_off, key
def _find_dans(data: bytes, rich_off: int, key: int) -> int | None:
# Scan backwards for the XOR-encoded 'DanS' (0x536e6144) signature.
for off in range(rich_off - 4, 0, -4):
if struct.unpack_from("<I", data, off)[0] ^ key == 0x536E6144:
return off
return None
def rich(path: str) -> dict:
data = Path(path).read_bytes()
if data[:2] != b"MZ":
return {"error": "not a PE"}
found = _find_rich(data)
if not found:
return {"has_rich_header": False}
rich_off, key = found
dans_off = _find_dans(data, rich_off, key)
if dans_off is None:
return {"has_rich_header": True, "error": "DanS not found", "xor_key": hex(key)}
entries = []
# Entries start after DanS + 3 padding DWORDs, run until the Rich marker.
off = dans_off + 16
while off + 8 <= rich_off:
comp = struct.unpack_from("<I", data, off)[0] ^ key
count = struct.unpack_from("<I", data, off + 4)[0] ^ key
product_id = comp >> 16
build_id = comp & 0xFFFF
entries.append({"product_id": product_id, "build_id": build_id, "use_count": count})
off += 8
fingerprint = hashlib.sha256(
json.dumps(entries, sort_keys=True).encode()).hexdigest()[:16]
return {
"has_rich_header": True,
"xor_key": hex(key),
"entry_count": len(entries),
"entries": entries,
"toolchain_fingerprint": fingerprint,
}
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description="Decode the PE Rich header")
sub = parser.add_subparsers(dest="cmd", required=True)
p = sub.add_parser("rich")
p.add_argument("file")
args = parser.parse_args(argv)
print(json.dumps(rich(args.file), indent=2))
return 0
if __name__ == "__main__":
sys.exit(main())