From 5fce78d798fe798447f300b885f48a7850b7c632 Mon Sep 17 00:00:00 2001
From: LR <2830244143@qq.com>
Date: Sun, 27 Sep 2026 16:10:11 +0800
Subject: [PATCH 01/16] Add synthetic detector-evasion benchmark
---
research/evasion_benchmark.py | 155 ++++++++++++++++++++++++++++++++++
1 file changed, 155 insertions(+)
create mode 100644 research/evasion_benchmark.py
diff --git a/research/evasion_benchmark.py b/research/evasion_benchmark.py
new file mode 100644
index 0000000..fb6a9f9
--- /dev/null
+++ b/research/evasion_benchmark.py
@@ -0,0 +1,155 @@
+#!/usr/bin/env python3
+"""Synthetic detector-evasion benchmark for defensive research.
+
+This module never loads, mutates, executes, or emits real payloads/binaries.
+It operates only on abstract feature vectors so experiments are reproducible
+without providing a path to bypass production AV/EDR.
+"""
+from __future__ import annotations
+import argparse
+import json
+import math
+import random
+from dataclasses import dataclass, asdict
+from pathlib import Path
+
+FEATURES = ("exec_surface", "io_surface", "network_surface", "persistence_surface", "entropy", "token_overlap")
+WEIGHTS = {
+ "exec_surface": 1.25,
+ "io_surface": 0.75,
+ "network_surface": 1.10,
+ "persistence_surface": 1.50,
+ "entropy": 0.55,
+ "token_overlap": 1.35,
+}
+BIAS = -2.65
+THRESHOLD = 0.50
+
+@dataclass
+class Sample:
+ sample_id: str
+ label: int
+ features: dict[str, float]
+
+def sigmoid(x: float) -> float:
+ return 1.0 / (1.0 + math.exp(-x))
+
+def score(features: dict[str, float]) -> float:
+ z = BIAS + sum(WEIGHTS[k] * features[k] for k in FEATURES)
+ return sigmoid(z)
+
+def detected(features: dict[str, float]) -> bool:
+ return score(features) >= THRESHOLD
+
+def clamp(v: float) -> float:
+ return max(0.0, min(1.0, v))
+
+def generate(seed: int = 2026, n: int = 240) -> list[Sample]:
+ rng = random.Random(seed)
+ rows: list[Sample] = []
+ for i in range(n):
+ label = 1 if i < n // 2 else 0
+ center = 0.68 if label else 0.28
+ f = {}
+ for name in FEATURES:
+ jitter = rng.uniform(-0.22, 0.22)
+ feature_center = center
+ if name == "entropy":
+ feature_center += 0.08 if label else -0.02
+ if name == "persistence_surface":
+ feature_center += 0.10 if label else -0.06
+ f[name] = clamp(feature_center + jitter)
+ rows.append(Sample(f"S{i:04d}", label, f))
+ return rows
+
+def perturb(features: dict[str, float], profile: str) -> dict[str, float]:
+ """Apply abstract, non-operational feature-space perturbations only."""
+ f = dict(features)
+ if profile == "P1":
+ f["token_overlap"] = clamp(f["token_overlap"] - 0.18)
+ f["entropy"] = clamp(f["entropy"] + 0.07)
+ elif profile == "P2":
+ f["exec_surface"] = clamp(f["exec_surface"] - 0.12)
+ f["io_surface"] = clamp(f["io_surface"] - 0.10)
+ f["entropy"] = clamp(f["entropy"] + 0.10)
+ elif profile == "P3":
+ f["token_overlap"] = clamp(f["token_overlap"] - 0.16)
+ f["network_surface"] = clamp(f["network_surface"] - 0.10)
+ f["persistence_surface"] = clamp(f["persistence_surface"] - 0.08)
+ elif profile != "baseline":
+ raise ValueError(f"unknown profile: {profile}")
+ return f
+
+def metrics(samples: list[Sample], profile: str) -> dict:
+ tp = fp = tn = fn = 0
+ scores: list[float] = []
+ for s in samples:
+ f = perturb(s.features, profile)
+ pred = detected(f)
+ scores.append(score(f))
+ if s.label and pred: tp += 1
+ elif s.label and not pred: fn += 1
+ elif not s.label and pred: fp += 1
+ else: tn += 1
+ recall = tp / (tp + fn) if tp + fn else 0.0
+ fpr = fp / (fp + tn) if fp + tn else 0.0
+ return {
+ "profile": profile,
+ "tp": tp, "fn": fn, "fp": fp, "tn": tn,
+ "recall": round(recall, 4),
+ "false_positive_rate": round(fpr, 4),
+ "mean_score": round(sum(scores) / len(scores), 4),
+ }
+
+def sensitivity(samples: list[Sample]) -> list[dict]:
+ out = []
+ positives = [s for s in samples if s.label == 1]
+ for name in FEATURES:
+ changed = 0
+ delta_sum = 0.0
+ for s in positives:
+ base = score(s.features)
+ f = dict(s.features)
+ f[name] = clamp(f[name] - 0.15)
+ after = score(f)
+ delta_sum += base - after
+ changed += int(detected(s.features) and not detected(f))
+ out.append({
+ "feature": name,
+ "mean_score_drop": round(delta_sum / max(1, len(positives)), 4),
+ "decision_flips": changed,
+ })
+ return sorted(out, key=lambda x: (x["decision_flips"], x["mean_score_drop"]), reverse=True)
+
+def run(seed: int, n: int) -> dict:
+ samples = generate(seed, n)
+ profiles = ["baseline", "P1", "P2", "P3"]
+ results = [metrics(samples, p) for p in profiles]
+ baseline_recall = results[0]["recall"]
+ for row in results:
+ row["recall_delta_vs_baseline"] = round(row["recall"] - baseline_recall, 4)
+ return {
+ "schema": "lr-payload-lab/synthetic-evasion-benchmark-v1",
+ "seed": seed,
+ "samples": n,
+ "scope": "synthetic feature vectors only; no executable payloads or production AV bypass",
+ "detector": {"threshold": THRESHOLD, "weights": WEIGHTS, "bias": BIAS},
+ "results": results,
+ "sensitivity": sensitivity(samples),
+ }
+
+def main() -> int:
+ ap = argparse.ArgumentParser(description="Run the synthetic detector-evasion benchmark")
+ ap.add_argument("--seed", type=int, default=2026)
+ ap.add_argument("--samples", type=int, default=240)
+ ap.add_argument("--json", type=Path)
+ args = ap.parse_args()
+ report = run(args.seed, args.samples)
+ text = json.dumps(report, ensure_ascii=False, indent=2)
+ if args.json:
+ args.json.write_text(text + "\n", encoding="utf-8")
+ print(text)
+ return 0
+
+if __name__ == "__main__":
+ raise SystemExit(main())
From 4601e2ee590f4d9a1e7eb148a65c694b650ac89b Mon Sep 17 00:00:00 2001
From: LR <2830244143@qq.com>
Date: Sun, 27 Sep 2026 16:10:13 +0800
Subject: [PATCH 02/16] Document safe detection-evasion research track
---
docs/detection-evasion-study.md | 59 +++++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
create mode 100644 docs/detection-evasion-study.md
diff --git a/docs/detection-evasion-study.md b/docs/detection-evasion-study.md
new file mode 100644
index 0000000..81d2c6b
--- /dev/null
+++ b/docs/detection-evasion-study.md
@@ -0,0 +1,59 @@
+# Detection Evasion Study — Safe Research Track
+
+这个实验用于展示 **“检测器在输入特征发生扰动后是否仍然稳定”**,而不是提供真实杀软绕过能力。
+
+## 研究问题
+
+1. 一个检测器过度依赖哪些特征?
+2. 当这些特征发生小幅变化时,召回率下降多少?
+3. 哪些扰动最容易造成 decision flip?
+4. 如何通过特征多样化、阈值校准与规则组合提高鲁棒性?
+
+## 实验设计
+
+`research/evasion_benchmark.py` 只生成合成特征向量,不读取 PE/ELF,不执行载荷,也不调用 Defender/EDR。
+
+每个样本由 6 个抽象维度组成:
+
+- `exec_surface`
+- `io_surface`
+- `network_surface`
+- `persistence_surface`
+- `entropy`
+- `token_overlap`
+
+检测器是固定权重的可解释模型。P1/P2/P3 是 **纯特征空间扰动**,不对应真实混淆、注入、打包或规避技术。
+
+## 运行
+
+```bash
+python research/evasion_benchmark.py
+python research/evasion_benchmark.py --samples 1000 --json report.json
+```
+
+输出包括:
+
+- baseline / P1 / P2 / P3 的 TP、FN、FP、TN
+- Recall 与 False Positive Rate
+- 相比 baseline 的 recall delta
+- 每个特征的平均分数下降和 decision flips
+
+## 导师展示建议
+
+把重点放在 **“为什么检测器漏掉了”** 和 **“怎么把它修好”**:
+
+```text
+Synthetic Sample
+ ↓
+Explainable Detector
+ ↓
+Feature-space Perturbation
+ ↓
+Recall / FPR / Decision Flip
+ ↓
+Sensitivity Analysis
+ ↓
+Detector Hardening
+```
+
+这条路线能体现检测对抗、实验设计、指标评估和可解释性,同时不会把仓库变成真实 AV/EDR 规避工具。
From 0d50b4bd9d3988f60098c398124eb1f482975746 Mon Sep 17 00:00:00 2001
From: LR <2830244143@qq.com>
Date: Sun, 27 Sep 2026 16:10:18 +0800
Subject: [PATCH 03/16] Test synthetic evasion benchmark
---
tests/test_evasion_benchmark.py | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
create mode 100644 tests/test_evasion_benchmark.py
diff --git a/tests/test_evasion_benchmark.py b/tests/test_evasion_benchmark.py
new file mode 100644
index 0000000..d299b4c
--- /dev/null
+++ b/tests/test_evasion_benchmark.py
@@ -0,0 +1,27 @@
+import unittest
+from pathlib import Path
+import importlib.util
+
+MODULE = Path(__file__).resolve().parents[1] / "research" / "evasion_benchmark.py"
+spec = importlib.util.spec_from_file_location("evasion_benchmark", MODULE)
+m = importlib.util.module_from_spec(spec)
+assert spec and spec.loader
+spec.loader.exec_module(m)
+
+class EvasionBenchmarkTests(unittest.TestCase):
+ def test_reproducible(self):
+ self.assertEqual(m.run(2026, 120), m.run(2026, 120))
+
+ def test_profiles_present(self):
+ r = m.run(2026, 120)
+ self.assertEqual([x["profile"] for x in r["results"]], ["baseline", "P1", "P2", "P3"])
+ self.assertEqual(len(r["sensitivity"]), 6)
+
+ def test_feature_bounds(self):
+ for s in m.generate(1, 20):
+ for value in s.features.values():
+ self.assertGreaterEqual(value, 0.0)
+ self.assertLessEqual(value, 1.0)
+
+if __name__ == "__main__":
+ unittest.main()
From 80876fcb8a70389666a78dafbe68ded82df139f4 Mon Sep 17 00:00:00 2001
From: LR <2830244143@qq.com>
Date: Sun, 27 Sep 2026 16:11:05 +0800
Subject: [PATCH 04/16] Present detector-evasion research workflow
---
README.md | 59 ++++++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 47 insertions(+), 12 deletions(-)
diff --git a/README.md b/README.md
index 53e7126..f08b7b1 100644
--- a/README.md
+++ b/README.md
@@ -2,19 +2,26 @@


-Bounded payloads. Verifiable research.
-Auditable endpoint telemetry scenarios with receipts and rollback.
-

+Payload telemetry × Detection evasion research × Reproducible experiments.
+把“载荷是否能被检测、检测为什么失效、怎样加固检测器”做成一套可复现实验链。
+

## 30 秒看懂
-用 JSON 描述研究行为,平台先检查动作白名单、路径边界和资源上限,再执行并生成逐动作回执。`rollback` 根据回执清理实验文件。
+LR-PayloadLab 现在包含两条研究链:
```text
+Track A
Manifest → Policy validation → Bounded execution → Receipt → Rollback
+
+Track B
+Synthetic Sample → Explainable Detector → Feature Perturbation
+ → Recall / FPR / Decision Flip → Sensitivity Analysis
```
-## 5 分钟 Demo
+Track A 用来生成可审计、可回滚的无害遥测场景;Track B 用来研究“检测器面对载荷特征变化时为什么会漏报”。
+
+## 载荷实验
```bash
python -m pip install -e .
@@ -24,17 +31,45 @@ payload-lab rollback receipt.json
payload-lab build examples/telemetry-demo.json --output generated-payload.py
```
-示例只包含临时标记、无害子进程、文件哈希、50ms 计算与延迟。生成文件的 SHA-256 会写入输出,便于实验复现。
+示例只产生临时标记、无害子进程、文件哈希、短时计算与延迟,并记录 SHA-256 和逐动作回执。
+
+## Detection Evasion Benchmark
+
+```bash
+python research/evasion_benchmark.py
+python research/evasion_benchmark.py --samples 1000 --json report.json
+```
+
+这部分用于导师展示“免杀/检测对抗”研究方法,但实验对象是 **合成特征向量**,不会生成或修改真实恶意程序,也不会调用生产环境 AV/EDR。
+
+输出包括:
+
+- baseline / P1 / P2 / P3 的 TP、FN、FP、TN
+- Recall / False Positive Rate
+- 相比 baseline 的 recall delta
+- 特征敏感度与 decision flips
+- 固定 seed 的可复现实验结果
+
+详细设计见 [Detection Evasion Study](./docs/detection-evasion-study.md)。
## 研究价值
-- **可审计载荷**:行为在 Manifest 中完整列出,生成脚本不隐藏动作。
-- **遥测验证**:可观察文件、进程、计算和时间行为是否被采集。
-- **安全约束**:拒绝未知动作、目录逃逸、长时间计算;无网络、持久化、凭据访问与规避模块。
-- **回滚回执**:实验产生的文件记录在回执中,按工作区边界清理。
+- **可审计 Payload**:Manifest 完整描述实验行为,执行结果有回执。
+- **检测对抗评估**:不只展示“能不能检出”,还量化检测率随特征扰动如何变化。
+- **可解释性**:直接输出哪些特征最容易导致 decision flip。
+- **可复现性**:固定模型、固定随机种子、自动化测试。
+- **安全边界**:不包含真实 AV/EDR 绕过、注入、持久化、凭据访问或隐蔽远控能力。
+
+## 导师展示路线
-## 研究路线
+建议现场只演示三步:
+
+```text
+1. 运行 benign payload,展示 receipt / rollback
+2. 运行 detection-evasion benchmark,展示 recall 下降
+3. 打开 sensitivity 结果,解释“检测器为什么漏、应该怎么加固”
+```
-下一步计划加入跨平台遥测适配器、Sigma 规则回放、实验签名、容器隔离和检测覆盖矩阵。欢迎提交新的**无害、可回滚、可观测**场景。
+这比单纯做一个“免杀程序”更适合研究型项目:既能体现攻防思维,也能留下完整实验方法、指标和代码证据。
作者:LLR6 · MIT License
From 3b975be15d01a2cde55d0f91503880e1128467cd Mon Sep 17 00:00:00 2001
From: LR <2830244143@qq.com>
Date: Sun, 27 Sep 2026 16:11:07 +0800
Subject: [PATCH 05/16] Fix benchmark test module loading
---
tests/test_evasion_benchmark.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/tests/test_evasion_benchmark.py b/tests/test_evasion_benchmark.py
index d299b4c..d4e08a4 100644
--- a/tests/test_evasion_benchmark.py
+++ b/tests/test_evasion_benchmark.py
@@ -1,11 +1,13 @@
import unittest
from pathlib import Path
import importlib.util
+import sys
MODULE = Path(__file__).resolve().parents[1] / "research" / "evasion_benchmark.py"
spec = importlib.util.spec_from_file_location("evasion_benchmark", MODULE)
-m = importlib.util.module_from_spec(spec)
assert spec and spec.loader
+m = importlib.util.module_from_spec(spec)
+sys.modules[spec.name] = m
spec.loader.exec_module(m)
class EvasionBenchmarkTests(unittest.TestCase):
From 0f2f22371f51be3ee135fb123c1625910951c497 Mon Sep 17 00:00:00 2001
From: LR <2830244143@qq.com>
Date: Sun, 27 Sep 2026 16:22:40 +0800
Subject: [PATCH 06/16] Add IcedID ATT&CK research manifest
---
research/icedid_case_study.json | 68 +++++++++++++++++++++++++++++++++
1 file changed, 68 insertions(+)
create mode 100644 research/icedid_case_study.json
diff --git a/research/icedid_case_study.json b/research/icedid_case_study.json
new file mode 100644
index 0000000..ff99ea6
--- /dev/null
+++ b/research/icedid_case_study.json
@@ -0,0 +1,68 @@
+{
+ "family": "IcedID",
+ "attack_id": "S0483",
+ "platform": "Windows",
+ "scope": "public ATT&CK mapping + safe adversary-emulation coverage research",
+ "techniques": [
+ [
+ "T1071.001",
+ "Application Layer Protocol: Web Protocols",
+ "C2 over HTTPS"
+ ],
+ [
+ "T1547.001",
+ "Registry Run Keys / Startup Folder",
+ "persistence"
+ ],
+ [
+ "T1055.004",
+ "Process Injection: Asynchronous Procedure Call",
+ "remote process injection"
+ ],
+ [
+ "T1055.012",
+ "Process Injection: Process Hollowing",
+ "process hollowing"
+ ],
+ [
+ "T1082",
+ "System Information Discovery",
+ "host discovery"
+ ],
+ [
+ "T1016",
+ "System Network Configuration Discovery",
+ "network discovery"
+ ],
+ [
+ "T1518.001",
+ "Security Software Discovery",
+ "AV discovery"
+ ],
+ [
+ "T1218.007",
+ "System Binary Proxy Execution: Msiexec",
+ "proxy execution"
+ ],
+ [
+ "T1218.011",
+ "System Binary Proxy Execution: Rundll32",
+ "proxy execution"
+ ],
+ [
+ "T1053.005",
+ "Scheduled Task/Job: Scheduled Task",
+ "persistence"
+ ],
+ [
+ "T1497",
+ "Virtualization/Sandbox Evasion",
+ "sandbox filtering"
+ ],
+ [
+ "T1047",
+ "Windows Management Instrumentation",
+ "execution"
+ ]
+ ]
+}
From c739104d7f43688f25d58aa03ae53b1184080094 Mon Sep 17 00:00:00 2001
From: LR <2830244143@qq.com>
Date: Sun, 27 Sep 2026 16:22:42 +0800
Subject: [PATCH 07/16] Add IcedID coverage analyzer
---
research/icedid_coverage.py | 44 +++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
create mode 100644 research/icedid_coverage.py
diff --git a/research/icedid_coverage.py b/research/icedid_coverage.py
new file mode 100644
index 0000000..8815d19
--- /dev/null
+++ b/research/icedid_coverage.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python3
+import json
+from pathlib import Path
+
+DATA = Path(__file__).with_name("icedid_case_study.json")
+
+TACTIC_HINTS = {
+ "T1071.001": "command-and-control",
+ "T1547.001": "persistence",
+ "T1055.004": "defense-evasion",
+ "T1055.012": "defense-evasion",
+ "T1082": "discovery",
+ "T1016": "discovery",
+ "T1518.001": "discovery",
+ "T1218.007": "defense-evasion",
+ "T1218.011": "defense-evasion",
+ "T1053.005": "persistence",
+ "T1497": "defense-evasion",
+ "T1047": "execution",
+}
+
+def load():
+ return json.loads(DATA.read_text(encoding="utf-8"))
+
+def summarize(doc):
+ by_tactic = {}
+ for tid, name, note in doc["techniques"]:
+ tactic = TACTIC_HINTS.get(tid, "other")
+ by_tactic.setdefault(tactic, []).append({"id": tid, "name": name, "note": note})
+ return {
+ "family": doc["family"],
+ "attack_id": doc["attack_id"],
+ "technique_count": len(doc["techniques"]),
+ "by_tactic": by_tactic,
+ "research_questions": [
+ "Which IcedID behaviors are observable with endpoint telemetry?",
+ "Which ATT&CK behaviors have safe Atomic Red Team equivalents?",
+ "Which detections remain stable when benign telemetry changes?",
+ "Where are coverage gaps between behavior, telemetry, and detection?"
+ ]
+ }
+
+if __name__ == "__main__":
+ print(json.dumps(summarize(load()), ensure_ascii=False, indent=2))
From 266841c188f8051677e1c4c70aed97eab1196b64 Mon Sep 17 00:00:00 2001
From: LR <2830244143@qq.com>
Date: Sun, 27 Sep 2026 16:22:45 +0800
Subject: [PATCH 08/16] Document IcedID adversary-emulation case study
---
docs/icedid-case-study.md | 87 +++++++++++++++++++++++++++++++++++++++
1 file changed, 87 insertions(+)
create mode 100644 docs/icedid-case-study.md
diff --git a/docs/icedid-case-study.md b/docs/icedid-case-study.md
new file mode 100644
index 0000000..ffe7440
--- /dev/null
+++ b/docs/icedid-case-study.md
@@ -0,0 +1,87 @@
+# IcedID(S0483)行为研究 Case Study
+
+## 为什么选 IcedID
+
+IcedID 是 MITRE ATT&CK 收录的真实 Windows 恶意软件家族(S0483)。本项目不保存或分发 IcedID 恶意二进制,而是把公开威胁情报里的行为映射成可复现的检测研究对象。
+
+研究链:
+
+```text
+IcedID public threat intelligence
+ ↓
+MITRE ATT&CK technique mapping
+ ↓
+Atomic Red Team / safe emulation coverage
+ ↓
+endpoint telemetry
+ ↓
+detection rules
+ ↓
+robustness / false-negative analysis
+```
+
+## 重点行为
+
+当前 case study 选择 12 个适合做检测研究的行为:
+
+| ATT&CK | 行为 | 研究重点 |
+|---|---|---|
+| T1071.001 | Web Protocols | HTTPS C2 的网络遥测 |
+| T1547.001 | Registry Run Keys / Startup Folder | 启动持久化检测 |
+| T1055.004 | APC Injection | 注入行为的事件关联 |
+| T1055.012 | Process Hollowing | 父子进程与内存遥测 |
+| T1082 | System Information Discovery | 主机信息发现 |
+| T1016 | System Network Configuration Discovery | 网络配置发现 |
+| T1518.001 | Security Software Discovery | 安全软件枚举 |
+| T1218.007 | Msiexec | 系统二进制代理执行 |
+| T1218.011 | Rundll32 | DLL 代理执行 |
+| T1053.005 | Scheduled Task | 任务计划持久化 |
+| T1497 | Virtualization/Sandbox Evasion | 沙箱/分析环境识别 |
+| T1047 | WMI | WMI 执行行为 |
+
+## 和 Atomic Red Team 怎么结合
+
+Atomic Red Team 的测试按 ATT&CK technique 组织,每个 technique 都有结构化 YAML/Markdown 定义,并可由 Invoke-AtomicRedTeam 执行。
+
+这里的研究原则是:
+
+1. 先从 IcedID 的 ATT&CK technique 列表出发。
+2. 找到相同 technique 的 Atomic Test。
+3. 阅读 prerequisite / attack / cleanup 定义。
+4. 只在授权、隔离测试机运行。
+5. 保存 EDR/Sysmon/Windows Event Log 遥测。
+6. 把测试结果喂给 LR-PayloadLab 的 detection-resilience 分析。
+
+## 导师演示
+
+```text
+IcedID (S0483)
+ │
+ ├── T1082 System Information Discovery
+ ├── T1016 Network Configuration Discovery
+ ├── T1218.011 Rundll32
+ ├── T1053.005 Scheduled Task
+ └── ...
+ ↓
+Atomic Red Team equivalent
+ ↓
+Windows telemetry
+ ↓
+Detection / missed detection
+ ↓
+Feature sensitivity + detector hardening
+```
+
+重点不是声称“仓库里放了 IcedID 木马”,而是说明:
+
+> 我选取真实恶意软件家族 IcedID 作为威胁模型,根据 ATT&CK 的公开行为证据建立可复现实验,并研究不同检测器对这些行为的覆盖和鲁棒性。
+
+## 数据文件
+
+- `research/icedid_case_study.json`:研究行为清单
+- `research/icedid_coverage.py`:按研究战术聚合行为
+- `research/evasion_benchmark.py`:检测鲁棒性实验
+
+## 安全边界
+
+仓库不收录真实 IcedID 二进制、不实现凭据窃取/C2/持久化/注入载荷,也不实现 AV/EDR 绕过;实验聚焦公开行为证据、授权对手模拟、遥测与检测工程。
From b73a1fdf2e65bd29eab292d804c0eda2ae6a5304 Mon Sep 17 00:00:00 2001
From: LR <2830244143@qq.com>
Date: Sun, 27 Sep 2026 16:22:47 +0800
Subject: [PATCH 09/16] Test IcedID research mapping
---
tests/test_icedid_coverage.py | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
create mode 100644 tests/test_icedid_coverage.py
diff --git a/tests/test_icedid_coverage.py b/tests/test_icedid_coverage.py
new file mode 100644
index 0000000..3f3d160
--- /dev/null
+++ b/tests/test_icedid_coverage.py
@@ -0,0 +1,27 @@
+import importlib.util
+import sys
+import unittest
+from pathlib import Path
+
+P = Path(__file__).resolve().parents[1] / "research" / "icedid_coverage.py"
+spec = importlib.util.spec_from_file_location("icedid_coverage", P)
+assert spec and spec.loader
+m = importlib.util.module_from_spec(spec)
+sys.modules[spec.name] = m
+spec.loader.exec_module(m)
+
+class IcedIDCoverageTests(unittest.TestCase):
+ def test_case_study_shape(self):
+ d = m.load()
+ self.assertEqual(d["attack_id"], "S0483")
+ self.assertEqual(d["platform"], "Windows")
+ self.assertGreaterEqual(len(d["techniques"]), 10)
+
+ def test_summary_groups(self):
+ s = m.summarize(m.load())
+ self.assertIn("discovery", s["by_tactic"])
+ self.assertIn("defense-evasion", s["by_tactic"])
+ self.assertEqual(s["technique_count"], 12)
+
+if __name__ == "__main__":
+ unittest.main()
From 95a2c340ba5eea67c3f5fec7b697aca73afc2ad6 Mon Sep 17 00:00:00 2001
From: LR <2830244143@qq.com>
Date: Sun, 27 Sep 2026 16:23:18 +0800
Subject: [PATCH 10/16] Add IcedID real-threat-model research track
---
README.md | 44 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/README.md b/README.md
index f08b7b1..a2057e2 100644
--- a/README.md
+++ b/README.md
@@ -52,6 +52,50 @@ python research/evasion_benchmark.py --samples 1000 --json report.json
详细设计见 [Detection Evasion Study](./docs/detection-evasion-study.md)。
+
+## Real Threat Model: IcedID (S0483)
+
+为了让实验不只停留在“自造样本”,项目现在加入 **IcedID** 作为真实威胁模型。研究数据来自公开 ATT&CK 行为证据,并映射到可安全复现的 Atomic Red Team / adversary-emulation 流程。
+
+当前覆盖 12 个重点技术,包括:
+
+- T1071.001 Web Protocols
+- T1547.001 Registry Run Keys / Startup Folder
+- T1055.004 APC Injection
+- T1055.012 Process Hollowing
+- T1082 System Information Discovery
+- T1016 System Network Configuration Discovery
+- T1518.001 Security Software Discovery
+- T1218.007 Msiexec
+- T1218.011 Rundll32
+- T1053.005 Scheduled Task
+- T1497 Virtualization/Sandbox Evasion
+- T1047 Windows Management Instrumentation
+
+运行:
+
+```bash
+python research/icedid_coverage.py
+```
+
+详细案例见 [IcedID Case Study](./docs/icedid-case-study.md)。
+
+这条链用于回答一个更接近实战的问题:
+
+```text
+真实恶意软件家族
+ ↓
+公开 ATT&CK 行为证据
+ ↓
+授权对手模拟
+ ↓
+真实终端遥测
+ ↓
+检测覆盖 / 漏报
+ ↓
+检测器加固
+```
+
## 研究价值
- **可审计 Payload**:Manifest 完整描述实验行为,执行结果有回执。
From fc6009e44a11a2774895245a6b69ea46904bae63 Mon Sep 17 00:00:00 2001
From: LR <2830244143@qq.com>
Date: Sun, 27 Sep 2026 16:30:04 +0800
Subject: [PATCH 11/16] Add Atomic Red Team coverage metadata
---
research/atomic_coverage_map.json | 120 ++++++++++++++++++++++++++++++
1 file changed, 120 insertions(+)
create mode 100644 research/atomic_coverage_map.json
diff --git a/research/atomic_coverage_map.json b/research/atomic_coverage_map.json
new file mode 100644
index 0000000..d2307ab
--- /dev/null
+++ b/research/atomic_coverage_map.json
@@ -0,0 +1,120 @@
+{
+ "schema": "lr-payload-lab/atomic-coverage-map-v1",
+ "threat_model": {
+ "family": "IcedID",
+ "attack_id": "S0483",
+ "platform": "Windows"
+ },
+ "generated_from": "redcanaryco/atomic-red-team public technique YAML metadata",
+ "mappings": [
+ {
+ "technique_id": "T1071.001",
+ "technique_name": "Application Layer Protocol: Web Protocols",
+ "exact_atomic": true,
+ "atomic_guid": "81c13829-f6c9-45b8-85a6-053366d55297",
+ "atomic_name": "Malicious User Agents - Powershell",
+ "execution_policy": "isolated-lab",
+ "source_url": "https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1071.001/T1071.001.yaml"
+ },
+ {
+ "technique_id": "T1547.001",
+ "technique_name": "Registry Run Keys / Startup Folder",
+ "exact_atomic": true,
+ "atomic_guid": "e55be3fd-3521-4610-9d1a-e210e42dcf05",
+ "atomic_name": "Reg Key Run",
+ "execution_policy": "isolated-lab",
+ "source_url": "https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1547.001/T1547.001.yaml"
+ },
+ {
+ "technique_id": "T1055.004",
+ "technique_name": "Process Injection: Asynchronous Procedure Call",
+ "exact_atomic": true,
+ "atomic_guid": "611b39b7-e243-4c81-87a4-7145a90358b1",
+ "atomic_name": "Process Injection via C#",
+ "execution_policy": "metadata-only",
+ "source_url": "https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1055.004/T1055.004.yaml"
+ },
+ {
+ "technique_id": "T1055.012",
+ "technique_name": "Process Injection: Process Hollowing",
+ "exact_atomic": true,
+ "atomic_guid": "562427b4-39ef-4e8c-af88-463a78e70b9c",
+ "atomic_name": "Process Hollowing using PowerShell",
+ "execution_policy": "metadata-only",
+ "source_url": "https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1055.012/T1055.012.yaml"
+ },
+ {
+ "technique_id": "T1082",
+ "technique_name": "System Information Discovery",
+ "exact_atomic": true,
+ "atomic_guid": "66703791-c902-4560-8770-42b8a91f7667",
+ "atomic_name": "System Information Discovery",
+ "execution_policy": "isolated-lab",
+ "source_url": "https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1082/T1082.yaml"
+ },
+ {
+ "technique_id": "T1016",
+ "technique_name": "System Network Configuration Discovery",
+ "exact_atomic": true,
+ "atomic_guid": "970ab6a1-0157-4f3f-9a73-ec4166754b23",
+ "atomic_name": "System Network Configuration Discovery on Windows",
+ "execution_policy": "isolated-lab",
+ "source_url": "https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1016/T1016.yaml"
+ },
+ {
+ "technique_id": "T1518.001",
+ "technique_name": "Security Software Discovery",
+ "exact_atomic": true,
+ "atomic_guid": "f92a380f-ced9-491f-b338-95a991418ce2",
+ "atomic_name": "Security Software Discovery",
+ "execution_policy": "isolated-lab",
+ "source_url": "https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1518.001/T1518.001.yaml"
+ },
+ {
+ "technique_id": "T1218.007",
+ "technique_name": "Signed Binary Proxy Execution: Msiexec",
+ "exact_atomic": true,
+ "atomic_guid": "a059b6c4-e7d6-4b2e-bcd7-9b2b33191a04",
+ "atomic_name": "Msiexec.exe - Execute Local MSI file with embedded JScript",
+ "execution_policy": "metadata-only",
+ "source_url": "https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1218.007/T1218.007.yaml"
+ },
+ {
+ "technique_id": "T1218.011",
+ "technique_name": "Signed Binary Proxy Execution: Rundll32",
+ "exact_atomic": true,
+ "atomic_guid": "57ba4ce9-ee7a-4f27-9928-3c70c489b59d",
+ "atomic_name": "Rundll32 execute JavaScript Remote Payload With GetObject",
+ "execution_policy": "metadata-only",
+ "source_url": "https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1218.011/T1218.011.yaml"
+ },
+ {
+ "technique_id": "T1053.005",
+ "technique_name": "Scheduled Task/Job: Scheduled Task",
+ "exact_atomic": true,
+ "atomic_guid": "fec27f65-db86-4c2d-b66c-61945aee87c2",
+ "atomic_name": "Scheduled Task Startup Script",
+ "execution_policy": "isolated-lab",
+ "source_url": "https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1053.005/T1053.005.yaml"
+ },
+ {
+ "technique_id": "T1497",
+ "technique_name": "Virtualization/Sandbox Evasion",
+ "exact_atomic": false,
+ "atomic_guid": null,
+ "atomic_name": null,
+ "execution_policy": "needs-representative-subtechnique",
+ "source_url": "https://attack.mitre.org/techniques/T1497/",
+ "note": "Atomic Red Team has no exact parent-level T1497 YAML; do not count this as covered until a representative sub-technique is selected and justified."
+ },
+ {
+ "technique_id": "T1047",
+ "technique_name": "Windows Management Instrumentation",
+ "exact_atomic": true,
+ "atomic_guid": "c107778c-dcf5-47c5-af2e-1d058a3df3ea",
+ "atomic_name": "WMI Reconnaissance Users",
+ "execution_policy": "isolated-lab",
+ "source_url": "https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1047/T1047.yaml"
+ }
+ ]
+}
From e38f3fdbaf2d3e799805fae40a98f8f938dc9a8c Mon Sep 17 00:00:00 2001
From: LR <2830244143@qq.com>
Date: Sun, 27 Sep 2026 16:30:06 +0800
Subject: [PATCH 12/16] Add IcedID Atomic coverage matrix generator
---
research/atomic_coverage_matrix.py | 127 +++++++++++++++++++++++++++++
1 file changed, 127 insertions(+)
create mode 100644 research/atomic_coverage_matrix.py
diff --git a/research/atomic_coverage_matrix.py b/research/atomic_coverage_matrix.py
new file mode 100644
index 0000000..64f0cb7
--- /dev/null
+++ b/research/atomic_coverage_matrix.py
@@ -0,0 +1,127 @@
+#!/usr/bin/env python3
+import argparse
+import json
+from pathlib import Path
+
+HERE = Path(__file__).resolve().parent
+DEFAULT_MAP = HERE / "atomic_coverage_map.json"
+RUN_STATES = {"not_run", "passed", "failed", "skipped"}
+DETECTION_STATES = {"not_evaluated", "detected", "missed", "partial"}
+
+def load_json(path: Path):
+ return json.loads(path.read_text(encoding="utf-8"))
+
+def validate_results(doc, mapping):
+ if doc.get("schema") != "lr-payload-lab/atomic-results-v1":
+ raise ValueError("unsupported results schema")
+ known = {(x["technique_id"], x.get("atomic_guid")) for x in mapping["mappings"]}
+ seen = set()
+ for i, row in enumerate(doc.get("results", [])):
+ key = (row.get("technique_id"), row.get("atomic_guid"))
+ if key in seen:
+ raise ValueError(f"duplicate result at index {i}: {key}")
+ seen.add(key)
+ if key not in known:
+ raise ValueError(f"unknown technique/guid pair at index {i}: {key}")
+ if row.get("run_status", "not_run") not in RUN_STATES:
+ raise ValueError(f"invalid run_status at index {i}")
+ if row.get("detection", "not_evaluated") not in DETECTION_STATES:
+ raise ValueError(f"invalid detection at index {i}")
+ return doc
+
+def build_report(mapping, results=None):
+ result_by_key = {}
+ if results:
+ validate_results(results, mapping)
+ result_by_key = {(x["technique_id"], x.get("atomic_guid")): x for x in results.get("results", [])}
+
+ rows = []
+ for item in mapping["mappings"]:
+ key = (item["technique_id"], item.get("atomic_guid"))
+ observed = result_by_key.get(key, {})
+ rows.append({
+ **item,
+ "run_status": observed.get("run_status", "not_run"),
+ "detection": observed.get("detection", "not_evaluated"),
+ "telemetry": observed.get("telemetry", []),
+ "evidence": observed.get("evidence", ""),
+ "notes": observed.get("notes", item.get("note", "")),
+ })
+
+ exact = sum(1 for x in rows if x["exact_atomic"])
+ run = sum(1 for x in rows if x["run_status"] != "not_run")
+ evaluated = [x for x in rows if x["detection"] != "not_evaluated"]
+ detected = sum(1 for x in evaluated if x["detection"] == "detected")
+ missed = sum(1 for x in evaluated if x["detection"] == "missed")
+ partial = sum(1 for x in evaluated if x["detection"] == "partial")
+
+ return {
+ "schema": "lr-payload-lab/atomic-coverage-report-v1",
+ "threat_model": mapping["threat_model"],
+ "summary": {
+ "ttp_total": len(rows),
+ "exact_atomic_mappings": exact,
+ "no_exact_atomic": len(rows) - exact,
+ "experiments_recorded": run,
+ "detections_evaluated": len(evaluated),
+ "detected": detected,
+ "missed": missed,
+ "partial": partial,
+ },
+ "rows": rows,
+ }
+
+def render_markdown(report):
+ s = report["summary"]
+ lines = [
+ "# IcedID Atomic Coverage Matrix",
+ "",
+ f"- Threat model: **{report['threat_model']['family']} ({report['threat_model']['attack_id']})**",
+ f"- TTPs in study: **{s['ttp_total']}**",
+ f"- Exact Atomic mappings: **{s['exact_atomic_mappings']}**",
+ f"- No exact Atomic mapping: **{s['no_exact_atomic']}**",
+ f"- Experiments recorded: **{s['experiments_recorded']}**",
+ f"- Detections evaluated: **{s['detections_evaluated']}**",
+ "",
+ "| ATT&CK | Atomic test | Policy | Run | Detection | Telemetry |",
+ "|---|---|---|---|---|---|",
+ ]
+ for row in report["rows"]:
+ atomic = row["atomic_name"] or "No exact parent-level Atomic"
+ telemetry = ", ".join(row["telemetry"]) if row["telemetry"] else "-"
+ lines.append(
+ f"| {row['technique_id']} | {atomic} | {row['execution_policy']} | "
+ f"{row['run_status']} | {row['detection']} | {telemetry} |"
+ )
+ lines += [
+ "",
+ "## Reading the matrix",
+ "",
+ "- metadata-only: mapped for research and coverage analysis, but this project does not provide an execution wrapper.",
+ "- isolated-lab: suitable for an authorized isolated test host after reviewing upstream prerequisites and cleanup.",
+ "- needs-representative-subtechnique: parent ATT&CK technique without an exact parent-level Atomic test.",
+ "- not_run / not_evaluated: no experimental claim is being made yet.",
+ "",
+ "This report records evidence; it does not execute Atomic Red Team tests.",
+ ]
+ return "\n".join(lines) + "\n"
+
+def main():
+ ap = argparse.ArgumentParser(description="Build an IcedID ATT&CK / Atomic Red Team coverage matrix")
+ ap.add_argument("--map", type=Path, default=DEFAULT_MAP)
+ ap.add_argument("--results", type=Path)
+ ap.add_argument("--markdown", type=Path)
+ ap.add_argument("--json", type=Path)
+ args = ap.parse_args()
+ mapping = load_json(args.map)
+ results = load_json(args.results) if args.results else None
+ report = build_report(mapping, results)
+ if args.markdown:
+ args.markdown.write_text(render_markdown(report), encoding="utf-8")
+ if args.json:
+ args.json.write_text(json.dumps(report, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
+ print(json.dumps(report["summary"], ensure_ascii=False, indent=2))
+ return 0
+
+if __name__ == "__main__":
+ raise SystemExit(main())
From 27b265fff2ae4b239ac054d6810f1a70cc8939c1 Mon Sep 17 00:00:00 2001
From: LR <2830244143@qq.com>
Date: Sun, 27 Sep 2026 16:30:08 +0800
Subject: [PATCH 13/16] Add honest lab results template
---
examples/icedid-lab-results.template.json | 119 ++++++++++++++++++++++
1 file changed, 119 insertions(+)
create mode 100644 examples/icedid-lab-results.template.json
diff --git a/examples/icedid-lab-results.template.json b/examples/icedid-lab-results.template.json
new file mode 100644
index 0000000..4c5bb98
--- /dev/null
+++ b/examples/icedid-lab-results.template.json
@@ -0,0 +1,119 @@
+{
+ "schema": "lr-payload-lab/atomic-results-v1",
+ "lab": {
+ "name": "replace-with-lab-name",
+ "host": "isolated-windows-test-host",
+ "edr": "replace-with-product",
+ "date": "YYYY-MM-DD"
+ },
+ "results": [
+ {
+ "technique_id": "T1071.001",
+ "atomic_guid": "81c13829-f6c9-45b8-85a6-053366d55297",
+ "run_status": "not_run",
+ "detection": "not_evaluated",
+ "telemetry": [],
+ "evidence": "",
+ "notes": ""
+ },
+ {
+ "technique_id": "T1547.001",
+ "atomic_guid": "e55be3fd-3521-4610-9d1a-e210e42dcf05",
+ "run_status": "not_run",
+ "detection": "not_evaluated",
+ "telemetry": [],
+ "evidence": "",
+ "notes": ""
+ },
+ {
+ "technique_id": "T1055.004",
+ "atomic_guid": "611b39b7-e243-4c81-87a4-7145a90358b1",
+ "run_status": "not_run",
+ "detection": "not_evaluated",
+ "telemetry": [],
+ "evidence": "",
+ "notes": ""
+ },
+ {
+ "technique_id": "T1055.012",
+ "atomic_guid": "562427b4-39ef-4e8c-af88-463a78e70b9c",
+ "run_status": "not_run",
+ "detection": "not_evaluated",
+ "telemetry": [],
+ "evidence": "",
+ "notes": ""
+ },
+ {
+ "technique_id": "T1082",
+ "atomic_guid": "66703791-c902-4560-8770-42b8a91f7667",
+ "run_status": "not_run",
+ "detection": "not_evaluated",
+ "telemetry": [],
+ "evidence": "",
+ "notes": ""
+ },
+ {
+ "technique_id": "T1016",
+ "atomic_guid": "970ab6a1-0157-4f3f-9a73-ec4166754b23",
+ "run_status": "not_run",
+ "detection": "not_evaluated",
+ "telemetry": [],
+ "evidence": "",
+ "notes": ""
+ },
+ {
+ "technique_id": "T1518.001",
+ "atomic_guid": "f92a380f-ced9-491f-b338-95a991418ce2",
+ "run_status": "not_run",
+ "detection": "not_evaluated",
+ "telemetry": [],
+ "evidence": "",
+ "notes": ""
+ },
+ {
+ "technique_id": "T1218.007",
+ "atomic_guid": "a059b6c4-e7d6-4b2e-bcd7-9b2b33191a04",
+ "run_status": "not_run",
+ "detection": "not_evaluated",
+ "telemetry": [],
+ "evidence": "",
+ "notes": ""
+ },
+ {
+ "technique_id": "T1218.011",
+ "atomic_guid": "57ba4ce9-ee7a-4f27-9928-3c70c489b59d",
+ "run_status": "not_run",
+ "detection": "not_evaluated",
+ "telemetry": [],
+ "evidence": "",
+ "notes": ""
+ },
+ {
+ "technique_id": "T1053.005",
+ "atomic_guid": "fec27f65-db86-4c2d-b66c-61945aee87c2",
+ "run_status": "not_run",
+ "detection": "not_evaluated",
+ "telemetry": [],
+ "evidence": "",
+ "notes": ""
+ },
+ {
+ "technique_id": "T1497",
+ "atomic_guid": null,
+ "run_status": "not_run",
+ "detection": "not_evaluated",
+ "telemetry": [],
+ "evidence": "",
+ "notes": "No exact parent-level Atomic mapping; select and justify a representative sub-technique before running."
+ },
+ {
+ "technique_id": "T1047",
+ "atomic_guid": "c107778c-dcf5-47c5-af2e-1d058a3df3ea",
+ "run_status": "not_run",
+ "detection": "not_evaluated",
+ "telemetry": [],
+ "evidence": "",
+ "notes": ""
+ }
+ ]
+}
From a8f7133293e20f6c947a5b02cfaac16e51f29395 Mon Sep 17 00:00:00 2001
From: LR <2830244143@qq.com>
Date: Sun, 27 Sep 2026 16:30:10 +0800
Subject: [PATCH 14/16] Document IcedID Atomic coverage workflow
---
docs/icedid-atomic-coverage.md | 46 ++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
create mode 100644 docs/icedid-atomic-coverage.md
diff --git a/docs/icedid-atomic-coverage.md b/docs/icedid-atomic-coverage.md
new file mode 100644
index 0000000..36f588b
--- /dev/null
+++ b/docs/icedid-atomic-coverage.md
@@ -0,0 +1,46 @@
+# IcedID × Atomic Red Team Coverage Matrix
+
+这个模块把真实威胁模型、Atomic Red Team 元数据和实验结果统一成一张 Coverage Matrix。
+
+## 当前映射
+
+- IcedID 研究 TTP:12
+- 可找到同 ID Atomic YAML:11
+- 无 exact parent-level Atomic:1(T1497)
+- 高风险/容易被误用的 Atomic 只记录 metadata,不在 LR-PayloadLab 中封装执行命令。
+
+## 生成矩阵
+
+先复制 examples/icedid-lab-results.template.json 并填写真实实验结果。
+
+然后运行:
+
+ python research/atomic_coverage_matrix.py --results icedid-lab-results.json --markdown icedid-coverage.md --json icedid-coverage.json
+
+## 实验结果字段
+
+- run_status: not_run / passed / failed / skipped
+- detection: not_evaluated / detected / missed / partial
+- telemetry: 实际拿到的日志源,例如 Sysmon EID 1、Windows Security、EDR alert
+- evidence: 截图、日志文件、事件编号或报告路径
+- notes: 失败原因、前置条件、清理情况等
+
+## 为什么不直接执行所有 Atomic
+
+Process Injection、Process Hollowing、Msiexec/Rundll32 等测试可能产生高风险行为。这个仓库负责研究映射、证据记录和检测覆盖分析,不会再封装一层一键执行器。
+
+对于 discovery、WMI、Run Key、Scheduled Task 等项目,也应只在有授权的隔离 Windows 测试主机上,阅读 upstream prerequisite / cleanup 后运行。
+
+导师展示链路:
+
+ IcedID TTP
+ ↓
+ Exact Atomic metadata
+ ↓
+ Authorized isolated execution
+ ↓
+ Telemetry evidence
+ ↓
+ Detection result
+ ↓
+ Coverage Matrix
From 8a5f6cacaba3e80e3ad7341f87848065632da0ce Mon Sep 17 00:00:00 2001
From: LR <2830244143@qq.com>
Date: Sun, 27 Sep 2026 16:30:12 +0800
Subject: [PATCH 15/16] Test Atomic coverage matrix
---
tests/test_atomic_coverage_matrix.py | 59 ++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
create mode 100644 tests/test_atomic_coverage_matrix.py
diff --git a/tests/test_atomic_coverage_matrix.py b/tests/test_atomic_coverage_matrix.py
new file mode 100644
index 0000000..0ae2335
--- /dev/null
+++ b/tests/test_atomic_coverage_matrix.py
@@ -0,0 +1,59 @@
+import importlib.util
+import sys
+import unittest
+from pathlib import Path
+
+ROOT = Path(__file__).resolve().parents[1]
+P = ROOT / "research" / "atomic_coverage_matrix.py"
+spec = importlib.util.spec_from_file_location("atomic_coverage_matrix", P)
+assert spec and spec.loader
+m = importlib.util.module_from_spec(spec)
+sys.modules[spec.name] = m
+spec.loader.exec_module(m)
+
+class AtomicCoverageMatrixTests(unittest.TestCase):
+ def setUp(self):
+ self.mapping = m.load_json(ROOT / "research" / "atomic_coverage_map.json")
+
+ def test_mapping_counts(self):
+ report = m.build_report(self.mapping)
+ self.assertEqual(report["summary"]["ttp_total"], 12)
+ self.assertEqual(report["summary"]["exact_atomic_mappings"], 11)
+ self.assertEqual(report["summary"]["no_exact_atomic"], 1)
+
+ def test_default_is_not_run(self):
+ report = m.build_report(self.mapping)
+ self.assertTrue(all(x["run_status"] == "not_run" for x in report["rows"]))
+ self.assertEqual(report["summary"]["detections_evaluated"], 0)
+
+ def test_real_result_merge(self):
+ first = self.mapping["mappings"][0]
+ results = {
+ "schema": "lr-payload-lab/atomic-results-v1",
+ "results": [{
+ "technique_id": first["technique_id"],
+ "atomic_guid": first["atomic_guid"],
+ "run_status": "passed",
+ "detection": "detected",
+ "telemetry": ["example-log"]
+ }]
+ }
+ report = m.build_report(self.mapping, results)
+ self.assertEqual(report["summary"]["experiments_recorded"], 1)
+ self.assertEqual(report["summary"]["detected"], 1)
+
+ def test_unknown_result_rejected(self):
+ results = {
+ "schema": "lr-payload-lab/atomic-results-v1",
+ "results": [{
+ "technique_id": "T0000",
+ "atomic_guid": None,
+ "run_status": "passed",
+ "detection": "detected"
+ }]
+ }
+ with self.assertRaises(ValueError):
+ m.build_report(self.mapping, results)
+
+if __name__ == "__main__":
+ unittest.main()
From ec0c71dc4ef13b5b9f44b561737440414685c8ad Mon Sep 17 00:00:00 2001
From: LR <2830244143@qq.com>
Date: Sun, 27 Sep 2026 16:30:26 +0800
Subject: [PATCH 16/16] Expose IcedID Atomic coverage matrix workflow
---
README.md | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/README.md b/README.md
index a2057e2..e7c2765 100644
--- a/README.md
+++ b/README.md
@@ -96,6 +96,23 @@ python research/icedid_coverage.py
检测器加固
```
+
+## IcedID × Atomic Coverage Matrix
+
+项目已经把 12 个 IcedID 研究 TTP 与 Atomic Red Team 元数据接起来:
+
+- 11 个 TTP 存在同 ID 的 Atomic YAML
+- T1497 是父级技术,当前没有 exact parent-level Atomic,因此不会虚报为“已覆盖”
+- Process Injection / Process Hollowing / Msiexec / Rundll32 等高风险项只保留 metadata,不提供二次封装执行器
+- 实验结果默认全部 not_run,只有填入真实遥测和检测证据后才计入覆盖率
+
+生成矩阵:
+
+ python research/atomic_coverage_matrix.py --results examples/icedid-lab-results.template.json --markdown icedid-coverage.md --json icedid-coverage.json
+
+详情见 [IcedID × Atomic Coverage](./docs/icedid-atomic-coverage.md)。
+
+
## 研究价值
- **可审计 Payload**:Manifest 完整描述实验行为,执行结果有回执。