@remnux/mcp-server 0.1.54 → 0.1.56

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/README.md +16 -1
  2. package/data/osint-resources.json +546 -0
  3. package/dist/analysis/behavior-prerequisites.d.ts +65 -0
  4. package/dist/analysis/behavior-prerequisites.d.ts.map +1 -0
  5. package/dist/analysis/behavior-prerequisites.js +186 -0
  6. package/dist/analysis/behavior-prerequisites.js.map +1 -0
  7. package/dist/analysis/file-diff.d.ts +59 -0
  8. package/dist/analysis/file-diff.d.ts.map +1 -0
  9. package/dist/analysis/file-diff.js +55 -0
  10. package/dist/analysis/file-diff.js.map +1 -0
  11. package/dist/analysis/index.d.ts +1 -1
  12. package/dist/analysis/index.d.ts.map +1 -1
  13. package/dist/analysis/index.js +1 -1
  14. package/dist/analysis/index.js.map +1 -1
  15. package/dist/analysis/string-usage.d.ts +74 -0
  16. package/dist/analysis/string-usage.d.ts.map +1 -0
  17. package/dist/analysis/string-usage.js +124 -0
  18. package/dist/analysis/string-usage.js.map +1 -0
  19. package/dist/analysis/summarizer.d.ts +22 -0
  20. package/dist/analysis/summarizer.d.ts.map +1 -1
  21. package/dist/analysis/summarizer.js +41 -0
  22. package/dist/analysis/summarizer.js.map +1 -1
  23. package/dist/connectors/docker.d.ts +1 -0
  24. package/dist/connectors/docker.d.ts.map +1 -1
  25. package/dist/connectors/docker.js +39 -5
  26. package/dist/connectors/docker.js.map +1 -1
  27. package/dist/handlers/analyze-file.d.ts.map +1 -1
  28. package/dist/handlers/analyze-file.js +19 -2
  29. package/dist/handlers/analyze-file.js.map +1 -1
  30. package/dist/handlers/check-behavior-prerequisites.d.ts +16 -0
  31. package/dist/handlers/check-behavior-prerequisites.d.ts.map +1 -0
  32. package/dist/handlers/check-behavior-prerequisites.js +132 -0
  33. package/dist/handlers/check-behavior-prerequisites.js.map +1 -0
  34. package/dist/handlers/compare-files.d.ts +10 -0
  35. package/dist/handlers/compare-files.d.ts.map +1 -0
  36. package/dist/handlers/compare-files.js +147 -0
  37. package/dist/handlers/compare-files.js.map +1 -0
  38. package/dist/handlers/extract-iocs.d.ts.map +1 -1
  39. package/dist/handlers/extract-iocs.js +6 -0
  40. package/dist/handlers/extract-iocs.js.map +1 -1
  41. package/dist/handlers/get-tool-help.d.ts.map +1 -1
  42. package/dist/handlers/get-tool-help.js +11 -0
  43. package/dist/handlers/get-tool-help.js.map +1 -1
  44. package/dist/handlers/osint.d.ts +10 -0
  45. package/dist/handlers/osint.d.ts.map +1 -0
  46. package/dist/handlers/osint.js +72 -0
  47. package/dist/handlers/osint.js.map +1 -0
  48. package/dist/handlers/report.d.ts.map +1 -1
  49. package/dist/handlers/report.js +11 -0
  50. package/dist/handlers/report.js.map +1 -1
  51. package/dist/handlers/verify-string-usage.d.ts +10 -0
  52. package/dist/handlers/verify-string-usage.d.ts.map +1 -0
  53. package/dist/handlers/verify-string-usage.js +173 -0
  54. package/dist/handlers/verify-string-usage.js.map +1 -0
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +55 -8
  57. package/dist/index.js.map +1 -1
  58. package/dist/osint/guidance.d.ts +125 -0
  59. package/dist/osint/guidance.d.ts.map +1 -0
  60. package/dist/osint/guidance.js +217 -0
  61. package/dist/osint/guidance.js.map +1 -0
  62. package/dist/osint/index.d.ts +61 -0
  63. package/dist/osint/index.d.ts.map +1 -0
  64. package/dist/osint/index.js +64 -0
  65. package/dist/osint/index.js.map +1 -0
  66. package/dist/parsers/capa.d.ts +8 -1
  67. package/dist/parsers/capa.d.ts.map +1 -1
  68. package/dist/parsers/capa.js +145 -0
  69. package/dist/parsers/capa.js.map +1 -1
  70. package/dist/parsers/imports.d.ts +36 -0
  71. package/dist/parsers/imports.d.ts.map +1 -0
  72. package/dist/parsers/imports.js +67 -0
  73. package/dist/parsers/imports.js.map +1 -0
  74. package/dist/parsers/r2.d.ts +73 -0
  75. package/dist/parsers/r2.d.ts.map +1 -0
  76. package/dist/parsers/r2.js +161 -0
  77. package/dist/parsers/r2.js.map +1 -0
  78. package/dist/parsers/types.d.ts +19 -0
  79. package/dist/parsers/types.d.ts.map +1 -1
  80. package/dist/report/triage-discipline.d.ts +28 -0
  81. package/dist/report/triage-discipline.d.ts.map +1 -0
  82. package/dist/report/triage-discipline.js +49 -0
  83. package/dist/report/triage-discipline.js.map +1 -0
  84. package/dist/schemas/tools.d.ts +56 -3
  85. package/dist/schemas/tools.d.ts.map +1 -1
  86. package/dist/schemas/tools.js +44 -2
  87. package/dist/schemas/tools.js.map +1 -1
  88. package/package.json +2 -1
@@ -0,0 +1,64 @@
1
+ /**
2
+ * OSINT resource catalog loader.
3
+ *
4
+ * Loads the contributor-editable data/osint-resources.json (maintained by pull
5
+ * request, validated in CI) and provides slicing helpers for the
6
+ * get_osint_guidance handler. Mirrors the data-file loading pattern in
7
+ * src/catalog/index.ts (data/ at package root, two levels up from dist/osint/),
8
+ * with a module-level memo since the catalog is immutable at runtime.
9
+ *
10
+ * This module reads a bundled JSON file only — no network, no API keys.
11
+ */
12
+ import { readFileSync } from "node:fs";
13
+ import { resolve, dirname } from "node:path";
14
+ import { fileURLToPath } from "node:url";
15
+ /** Sort priority: keyless programmatic services first (most agent-usable), web/GUI last. */
16
+ export const AI_ACCESS_ORDER = { api_nokey: 0, api_key: 1, web: 2 };
17
+ /** Absolute path to the bundled catalog (data/ is two levels up from dist/osint/ or src/osint/). */
18
+ export function resolveCatalogPath() {
19
+ const __dirname = dirname(fileURLToPath(import.meta.url));
20
+ return resolve(__dirname, "../../data/osint-resources.json");
21
+ }
22
+ /** Load and parse the catalog, throwing on any error. Used by the CI integrity test. */
23
+ export function loadOsintCatalogStrict() {
24
+ const raw = readFileSync(resolveCatalogPath(), "utf-8");
25
+ return JSON.parse(raw);
26
+ }
27
+ let cached = null;
28
+ /** Load the catalog with a module-level memo and a graceful fallback so a missing/corrupt file never crashes the server. */
29
+ export function loadOsintCatalog() {
30
+ if (cached)
31
+ return cached;
32
+ try {
33
+ const cat = loadOsintCatalogStrict();
34
+ // Order keyless programmatic services first so an agent sees what it can use now.
35
+ cat.resources = [...cat.resources].sort((a, b) => (AI_ACCESS_ORDER[a.ai_access] ?? 9) - (AI_ACCESS_ORDER[b.ai_access] ?? 9));
36
+ cached = cat;
37
+ }
38
+ catch (err) {
39
+ console.error("WARNING: Failed to load OSINT catalog — get_osint_guidance resources will be empty:", err);
40
+ cached = { version: "0.0.0", updated: "unknown", resources: [] };
41
+ }
42
+ return cached;
43
+ }
44
+ /** Condense one entry to the fields shown in the topic:"all" index. */
45
+ export function condense(r) {
46
+ return {
47
+ name: r.name,
48
+ ioc_types: r.ioc_types,
49
+ access: r.access,
50
+ ai_access: r.ai_access,
51
+ query_disclosing: r.query_disclosing,
52
+ content_disclosing: r.content_disclosing,
53
+ best_use: r.best_use,
54
+ };
55
+ }
56
+ /** The full catalog condensed (topic:"all"). */
57
+ export function condensedCatalog() {
58
+ return loadOsintCatalog().resources.map(condense);
59
+ }
60
+ /** Full-detail entries whose ioc_types include the given type (ioc_type slice). */
61
+ export function resourcesForIocType(iocType) {
62
+ return loadOsintCatalog().resources.filter((r) => r.ioc_types.includes(iocType));
63
+ }
64
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/osint/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAQzC,4FAA4F;AAC5F,MAAM,CAAC,MAAM,eAAe,GAA6B,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;AAmC9F,oGAAoG;AACpG,MAAM,UAAU,kBAAkB;IAChC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,OAAO,OAAO,CAAC,SAAS,EAAE,iCAAiC,CAAC,CAAC;AAC/D,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,sBAAsB;IACpC,MAAM,GAAG,GAAG,YAAY,CAAC,kBAAkB,EAAE,EAAE,OAAO,CAAC,CAAC;IACxD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAiB,CAAC;AACzC,CAAC;AAED,IAAI,MAAM,GAAwB,IAAI,CAAC;AAEvC,4HAA4H;AAC5H,MAAM,UAAU,gBAAgB;IAC9B,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,sBAAsB,EAAE,CAAC;QACrC,kFAAkF;QAClF,GAAG,CAAC,SAAS,GAAG,CAAC,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CACrC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CACpF,CAAC;QACF,MAAM,GAAG,GAAG,CAAC;IACf,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,qFAAqF,EAAE,GAAG,CAAC,CAAC;QAC1G,MAAM,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IACnE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,QAAQ,CAAC,CAAgB;IACvC,OAAO;QACL,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,SAAS,EAAE,CAAC,CAAC,SAAS;QACtB,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,SAAS,EAAE,CAAC,CAAC,SAAS;QACtB,gBAAgB,EAAE,CAAC,CAAC,gBAAgB;QACpC,kBAAkB,EAAE,CAAC,CAAC,kBAAkB;QACxC,QAAQ,EAAE,CAAC,CAAC,QAAQ;KACrB,CAAC;AACJ,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,gBAAgB;IAC9B,OAAO,gBAAgB,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AACpD,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,mBAAmB,CAAC,OAAgB;IAClD,OAAO,gBAAgB,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AACnF,CAAC"}
@@ -4,6 +4,13 @@
4
4
  * Extracts capabilities and their associated ATT&CK techniques.
5
5
  * Expects JSON output from `capa -j <file>`.
6
6
  */
7
- import type { ParsedToolOutput } from "./types.js";
7
+ import type { ParsedToolOutput, EvidenceType } from "./types.js";
8
+ /**
9
+ * Derive the evidence_types set for a single capa rule from the feature nodes
10
+ * that actually matched, plus two unambiguous namespace signals. Returns
11
+ * undefined when nothing can be determined (the caller then omits the field).
12
+ * Never throws — a malformed rule yields undefined, never a lost finding.
13
+ */
14
+ export declare function deriveEvidenceTypes(rule: Record<string, unknown>): EvidenceType[] | undefined;
8
15
  export declare function parseCapaOutput(rawOutput: string): ParsedToolOutput;
9
16
  //# sourceMappingURL=capa.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"capa.d.ts","sourceRoot":"","sources":["../../src/parsers/capa.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAW,MAAM,YAAY,CAAC;AAE5D,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,CA+DnE"}
1
+ {"version":3,"file":"capa.d.ts","sourceRoot":"","sources":["../../src/parsers/capa.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAW,YAAY,EAAE,MAAM,YAAY,CAAC;AAsG1E;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,YAAY,EAAE,GAAG,SAAS,CA4B7F;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,CAsEnE"}
@@ -4,6 +4,144 @@
4
4
  * Extracts capabilities and their associated ATT&CK techniques.
5
5
  * Expects JSON output from `capa -j <file>`.
6
6
  */
7
+ /**
8
+ * Map a capa feature-node type to the kind of evidence it represents.
9
+ *
10
+ * Deliberately conservative: only feature types whose evidence kind is
11
+ * unambiguous are mapped. A rule's namespace describes its INTENT
12
+ * (e.g. "collection/*"), not how it matched, so it is NOT used here to infer
13
+ * behavior — conflating the two is exactly the artifact-vs-behavior error this
14
+ * tagging exists to prevent.
15
+ */
16
+ const FEATURE_EVIDENCE_TYPE = {
17
+ // artifact — data/content patterns present in the binary
18
+ string: "artifact",
19
+ substring: "artifact",
20
+ regex: "artifact",
21
+ bytes: "artifact",
22
+ // behavior — code-level semantics (these feature types occur only in code)
23
+ api: "behavior",
24
+ mnemonic: "behavior",
25
+ number: "behavior",
26
+ offset: "behavior",
27
+ "operand number": "behavior",
28
+ "operand offset": "behavior",
29
+ // structural — binary layout / metadata
30
+ section: "structural",
31
+ export: "structural",
32
+ // linking — imports / library presence
33
+ import: "linking",
34
+ // Intentionally NEUTRAL (no contribution): os, arch, format, match, class,
35
+ // property, namespace, function-name. These are environment guards or
36
+ // ambiguous signals that would dilute the artifact-vs-behavior distinction
37
+ // (e.g. `os: windows` appears in many behavioral rules as a guard).
38
+ };
39
+ /**
40
+ * capa's `characteristic` feature is overloaded: some values describe binary
41
+ * structure, others describe code execution. Map by value; unknown values
42
+ * contribute nothing (conservative — a mislabel is worse than no label).
43
+ */
44
+ const CHARACTERISTIC_EVIDENCE_TYPE = {
45
+ // structural — file/layout characteristics
46
+ "embedded pe": "structural",
47
+ "mixed mode": "structural",
48
+ "forwarded export": "structural",
49
+ // artifact — string data (constructed in code, but still data)
50
+ "stack string": "artifact",
51
+ // behavior — code-execution characteristics
52
+ loop: "behavior",
53
+ "tight loop": "behavior",
54
+ "recursive call": "behavior",
55
+ nzxor: "behavior",
56
+ "peb access": "behavior",
57
+ "fs access": "behavior",
58
+ "gs access": "behavior",
59
+ "cross section flow": "behavior",
60
+ "indirect call": "behavior",
61
+ "unmanaged call": "behavior",
62
+ };
63
+ /** Stable ordering for the unordered evidence_types set (deterministic output). */
64
+ const EVIDENCE_TYPE_ORDER = ["artifact", "behavior", "structural", "linking"];
65
+ /**
66
+ * Walk a capa match-node tree and collect the feature types of nodes that
67
+ * ACTUALLY matched (success === true). capa includes non-matching branches
68
+ * (the untaken side of an `or`, the inner feature of a satisfied `not`) with
69
+ * success === false; excluding them ensures a rule that fired on a `string`
70
+ * branch is never credited with an unmatched `api` branch.
71
+ */
72
+ function collectMatchedEvidenceTypes(node, out) {
73
+ if (!node || typeof node !== "object")
74
+ return;
75
+ const n = node;
76
+ // A node that did not match contributes nothing, and NEITHER do its children.
77
+ // capa retains partially-satisfied subtrees, so a success===true feature can sit
78
+ // under a success===false statement (e.g. an `api` that matched before a sibling
79
+ // in a failed `and`). Pruning the whole failed subtree here prevents crediting a
80
+ // rule that fired on one branch with an unmatched sibling branch's features.
81
+ if (n.success !== true)
82
+ return;
83
+ const inner = n.node;
84
+ if (inner && typeof inner === "object") {
85
+ const i = inner;
86
+ if (i.type === "feature" && i.feature && typeof i.feature === "object") {
87
+ const f = i.feature;
88
+ const ft = f.type;
89
+ if (typeof ft === "string") {
90
+ if (ft === "characteristic") {
91
+ const val = typeof f.characteristic === "string" ? f.characteristic : "";
92
+ const et = CHARACTERISTIC_EVIDENCE_TYPE[val];
93
+ if (et)
94
+ out.add(et);
95
+ }
96
+ else {
97
+ const et = FEATURE_EVIDENCE_TYPE[ft];
98
+ if (et)
99
+ out.add(et);
100
+ }
101
+ }
102
+ }
103
+ }
104
+ if (Array.isArray(n.children)) {
105
+ for (const c of n.children)
106
+ collectMatchedEvidenceTypes(c, out);
107
+ }
108
+ }
109
+ /**
110
+ * Derive the evidence_types set for a single capa rule from the feature nodes
111
+ * that actually matched, plus two unambiguous namespace signals. Returns
112
+ * undefined when nothing can be determined (the caller then omits the field).
113
+ * Never throws — a malformed rule yields undefined, never a lost finding.
114
+ */
115
+ export function deriveEvidenceTypes(rule) {
116
+ try {
117
+ const types = new Set();
118
+ if (Array.isArray(rule.matches)) {
119
+ for (const m of rule.matches) {
120
+ // each match is [address, matchNode]
121
+ if (Array.isArray(m) && m.length >= 2) {
122
+ collectMatchedEvidenceTypes(m[1], types);
123
+ }
124
+ }
125
+ }
126
+ // Namespace carries an unambiguous evidence-kind signal in two cases only.
127
+ const meta = rule.meta;
128
+ if (meta && typeof meta === "object" && !Array.isArray(meta)) {
129
+ const ns = meta.namespace;
130
+ if (typeof ns === "string") {
131
+ if (ns.startsWith("linking/"))
132
+ types.add("linking");
133
+ else if (ns.startsWith("executable/"))
134
+ types.add("structural");
135
+ }
136
+ }
137
+ if (types.size === 0)
138
+ return undefined;
139
+ return EVIDENCE_TYPE_ORDER.filter((t) => types.has(t));
140
+ }
141
+ catch {
142
+ return undefined;
143
+ }
144
+ }
7
145
  export function parseCapaOutput(rawOutput) {
8
146
  const result = {
9
147
  tool: "capa",
@@ -38,6 +176,13 @@ export function parseCapaOutput(rawOutput) {
38
176
  .join(", ");
39
177
  }
40
178
  }
179
+ // Tag the kind(s) of evidence the rule actually matched on (artifact vs
180
+ // behavior vs structural vs linking). Additive and fail-soft: if this
181
+ // cannot be determined the field is simply omitted — the finding's name
182
+ // and ATT&CK evidence are never affected.
183
+ const evidenceTypes = deriveEvidenceTypes(r);
184
+ if (evidenceTypes)
185
+ finding.evidence_types = evidenceTypes;
41
186
  result.findings.push(finding);
42
187
  }
43
188
  }
@@ -1 +1 @@
1
- {"version":3,"file":"capa.js","sourceRoot":"","sources":["../../src/parsers/capa.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,UAAU,eAAe,CAAC,SAAiB;IAC/C,MAAM,MAAM,GAAqB;QAC/B,IAAI,EAAE,MAAM;QACZ,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,EAAE;QACZ,QAAQ,EAAE,EAAE;QACZ,GAAG,EAAE,SAAS;KACf,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACnC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC;QAErB,6BAA6B;QAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAChE,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;gBACjD,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;oBAAE,SAAS;gBAChD,MAAM,CAAC,GAAG,IAA+B,CAAC;gBAC1C,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC;gBACpB,MAAM,OAAO,GAAY;oBACvB,WAAW,EAAE,IAAI;oBACjB,QAAQ,EAAE,YAAY;oBACtB,QAAQ,EAAE,MAAM;iBACjB,CAAC;gBAEF,4DAA4D;gBAC5D,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC7D,MAAM,CAAC,GAAG,IAA+B,CAAC;oBAC1C,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACnD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC,MAAM;6BACxB,MAAM,CAAC,CAAC,CAAC,EAA+B,EAAE,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,CAAC;6BACtE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,SAAS,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,IAAI,GAAG,GAAG,CAAC;6BACpD,IAAI,CAAC,IAAI,CAAC,CAAC;oBAChB,CAAC;gBACH,CAAC;gBAED,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;QAED,mBAAmB;QACnB,IAAI,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC/C,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;YAC1C,MAAM,CAAC,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;QAChD,CAAC;QAED,yDAAyD;QACzD,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjC,MAAM,CAAC,QAAQ,CAAC,kBAAkB;gBAChC,mDAAmD;oBACnD,+EAA+E;oBAC/E,4DAA4D;oBAC5D,2DAA2D;oBAC3D,6CAA6C;oBAC7C,0DAA0D;oBAC1D,wEAAwE,CAAC;QAC7E,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,sCAAsC;IACxC,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"capa.js","sourceRoot":"","sources":["../../src/parsers/capa.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Parser for a PE import table from `readpe -i -f json` (pev suite).
3
+ *
4
+ * Produces a structured, queryable view of which APIs a PE statically imports.
5
+ * This is the enabling primitive for check_behavior_prerequisites: knowing the
6
+ * import surface lets us ask "can this binary even call the APIs a behavior
7
+ * requires?" — without conflating "the API is imported" with "the behavior
8
+ * runs".
9
+ *
10
+ * Note on what imports prove: a statically imported API means the binary *can*
11
+ * call it; it is not evidence the call happens on a reachable path. Absence is
12
+ * weaker still — APIs can be resolved at runtime (GetProcAddress + LoadLibrary)
13
+ * or hidden by packing.
14
+ */
15
+ export interface PeImports {
16
+ /** True when readpe produced valid JSON we could read (even if zero imports). */
17
+ parsed: boolean;
18
+ dlls: Array<{
19
+ dll: string;
20
+ functions: string[];
21
+ }>;
22
+ /** Lowercased imported function names, for case-insensitive lookup. */
23
+ functionSet: Set<string>;
24
+ /** Total number of imported functions across all DLLs. */
25
+ count: number;
26
+ }
27
+ export declare function parsePeImports(readpeJson: string): PeImports;
28
+ /**
29
+ * Whether a required API (given as a base name without the ANSI/Unicode suffix)
30
+ * is present in the import set. Matches the base plus its `...A` / `...W`
31
+ * variants — e.g. required "InternetOpenUrl" is satisfied by "InternetOpenUrlW".
32
+ * We APPEND candidate suffixes rather than stripping, because many genuine API
33
+ * names already end in 'a'/'w' (e.g. "GetClipboardData", "ShowWindow").
34
+ */
35
+ export declare function apiPresent(requiredBaseName: string, functionSet: Set<string>): boolean;
36
+ //# sourceMappingURL=imports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"imports.d.ts","sourceRoot":"","sources":["../../src/parsers/imports.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,SAAS;IACxB,iFAAiF;IACjF,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IAClD,uEAAuE;IACvE,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzB,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAC;CACf;AAMD,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAoC5D;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,gBAAgB,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,OAAO,CAGtF"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Parser for a PE import table from `readpe -i -f json` (pev suite).
3
+ *
4
+ * Produces a structured, queryable view of which APIs a PE statically imports.
5
+ * This is the enabling primitive for check_behavior_prerequisites: knowing the
6
+ * import surface lets us ask "can this binary even call the APIs a behavior
7
+ * requires?" — without conflating "the API is imported" with "the behavior
8
+ * runs".
9
+ *
10
+ * Note on what imports prove: a statically imported API means the binary *can*
11
+ * call it; it is not evidence the call happens on a reachable path. Absence is
12
+ * weaker still — APIs can be resolved at runtime (GetProcAddress + LoadLibrary)
13
+ * or hidden by packing.
14
+ */
15
+ function emptyImports(parsed) {
16
+ return { parsed, dlls: [], functionSet: new Set(), count: 0 };
17
+ }
18
+ export function parsePeImports(readpeJson) {
19
+ let data;
20
+ try {
21
+ data = JSON.parse(readpeJson);
22
+ }
23
+ catch {
24
+ return emptyImports(false);
25
+ }
26
+ if (!data || typeof data !== "object")
27
+ return emptyImports(false);
28
+ const imported = data["Imported functions"];
29
+ // Valid JSON but no import table (e.g. a PE with no imports) → parsed, empty.
30
+ if (!Array.isArray(imported))
31
+ return emptyImports(true);
32
+ const dlls = [];
33
+ const functionSet = new Set();
34
+ let count = 0;
35
+ for (const lib of imported) {
36
+ if (!lib || typeof lib !== "object")
37
+ continue;
38
+ const l = lib;
39
+ const dll = typeof l.Name === "string" ? l.Name : "";
40
+ const fns = Array.isArray(l.Functions) ? l.Functions : [];
41
+ const names = [];
42
+ for (const fn of fns) {
43
+ if (!fn || typeof fn !== "object")
44
+ continue;
45
+ const name = fn.Name;
46
+ if (typeof name === "string" && name.length > 0) {
47
+ names.push(name);
48
+ functionSet.add(name.toLowerCase());
49
+ count++;
50
+ }
51
+ }
52
+ dlls.push({ dll, functions: names });
53
+ }
54
+ return { parsed: true, dlls, functionSet, count };
55
+ }
56
+ /**
57
+ * Whether a required API (given as a base name without the ANSI/Unicode suffix)
58
+ * is present in the import set. Matches the base plus its `...A` / `...W`
59
+ * variants — e.g. required "InternetOpenUrl" is satisfied by "InternetOpenUrlW".
60
+ * We APPEND candidate suffixes rather than stripping, because many genuine API
61
+ * names already end in 'a'/'w' (e.g. "GetClipboardData", "ShowWindow").
62
+ */
63
+ export function apiPresent(requiredBaseName, functionSet) {
64
+ const base = requiredBaseName.toLowerCase();
65
+ return functionSet.has(base) || functionSet.has(base + "a") || functionSet.has(base + "w");
66
+ }
67
+ //# sourceMappingURL=imports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"imports.js","sourceRoot":"","sources":["../../src/parsers/imports.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAYH,SAAS,YAAY,CAAC,MAAe;IACnC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,UAAkB;IAC/C,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IACD,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC;IAElE,MAAM,QAAQ,GAAI,IAAgC,CAAC,oBAAoB,CAAC,CAAC;IACzE,8EAA8E;IAC9E,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;QAAE,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC;IAExD,MAAM,IAAI,GAAgD,EAAE,CAAC;IAC7D,MAAM,WAAW,GAAG,IAAI,GAAG,EAAU,CAAC;IACtC,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;YAAE,SAAS;QAC9C,MAAM,CAAC,GAAG,GAA8B,CAAC;QACzC,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1D,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;YACrB,IAAI,CAAC,EAAE,IAAI,OAAO,EAAE,KAAK,QAAQ;gBAAE,SAAS;YAC5C,MAAM,IAAI,GAAI,EAA8B,CAAC,IAAI,CAAC;YAClD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAChD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACjB,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;gBACpC,KAAK,EAAE,CAAC;YACV,CAAC;QACH,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;IACvC,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;AACpD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,gBAAwB,EAAE,WAAwB;IAC3E,MAAM,IAAI,GAAG,gBAAgB,CAAC,WAAW,EAAE,CAAC;IAC5C,OAAO,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,WAAW,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC;AAC7F,CAAC"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Pure parsers for radare2 JSON output (izj/izzj strings, iSj sections, aflj
3
+ * functions, axtj cross-references) plus the marker-split for the batched
4
+ * "Pass 2" command used by verify_string_usage.
5
+ *
6
+ * Every parser is defensive and NEVER throws — malformed/partial r2 output
7
+ * returns an empty result so the classifier can degrade to `unknown` rather
8
+ * than mistaking a parse failure for a real "no xref" answer. Field shapes were
9
+ * captured from radare2 6.1.6; alternative key names seen across versions are
10
+ * tolerated (e.g. function address as `addr` or `offset`).
11
+ */
12
+ /** Self-generated markers (emitted via `?e`) that delimit the Pass-2 sections. */
13
+ export declare const R2_MARKERS: {
14
+ readonly sections: "__R2MCP_SEC__";
15
+ readonly functions: "__R2MCP_FNS__";
16
+ readonly xref: "__R2MCP_XR__";
17
+ };
18
+ export interface R2String {
19
+ value: string;
20
+ vaddr: number;
21
+ section: string;
22
+ }
23
+ export interface R2Section {
24
+ name: string;
25
+ vaddr: number;
26
+ vaddrEnd: number;
27
+ /** True when the section is executable (perm contains 'x'). */
28
+ exec: boolean;
29
+ }
30
+ export interface R2Function {
31
+ addr: number;
32
+ name: string;
33
+ size: number;
34
+ }
35
+ export interface R2Xref {
36
+ /** Source address of the reference. */
37
+ from: number;
38
+ /** r2 reference type: STRN / DATA / CODE / CALL … */
39
+ type: string;
40
+ /** Containing function address, when r2 attributed one. */
41
+ fcnAddr?: number;
42
+ /** Containing function name, when present. */
43
+ fcnName?: string;
44
+ opcode?: string;
45
+ }
46
+ /** Parse `izj` / `izzj` string output. */
47
+ export declare function parseR2Strings(json: string): R2String[];
48
+ /** Parse `iSj` section output into ranges with an exec flag. */
49
+ export declare function parseR2Sections(json: string): R2Section[];
50
+ /** Parse `aflj` function list (address key is `addr` or `offset` across versions). */
51
+ export declare function parseR2Functions(json: string): R2Function[];
52
+ /** Parse `axtj` cross-reference output for one address. */
53
+ export declare function parseR2Xrefs(json: string): R2Xref[];
54
+ /** Extract the radare2 version string from `?V` output (first matching line). */
55
+ export declare function parseR2Version(text: string): string | undefined;
56
+ export interface SplitR2Output {
57
+ /** True if the connector truncated the output (→ treat as incomplete). */
58
+ truncated: boolean;
59
+ version?: string;
60
+ sectionsJson: string;
61
+ functionsJson: string;
62
+ /** Raw axtj JSON keyed by the queried address marker (hex string as emitted). */
63
+ xrefsByVaddr: Map<string, string>;
64
+ }
65
+ /**
66
+ * Split the batched Pass-2 stdout on the self-generated markers. The preamble
67
+ * (before the sections marker) carries the `?V` version line; sections sit
68
+ * between the sections and functions markers; functions between the functions
69
+ * marker and the first xref marker; each `__R2MCP_XR__ <addr>` block holds that
70
+ * address's axtj JSON up to the next marker or EOF.
71
+ */
72
+ export declare function splitMarkedR2Output(stdout: string): SplitR2Output;
73
+ //# sourceMappingURL=r2.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"r2.d.ts","sourceRoot":"","sources":["../../src/parsers/r2.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,kFAAkF;AAClF,eAAO,MAAM,UAAU;;;;CAIb,CAAC;AAKX,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,MAAM;IACrB,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAeD,0CAA0C;AAC1C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,EAAE,CAYvD;AAED,gEAAgE;AAChE,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,CAiBzD;AAED,sFAAsF;AACtF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,EAAE,CAU3D;AAED,2DAA2D;AAC3D,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAgBnD;AAED,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG/D;AAED,MAAM,WAAW,aAAa;IAC5B,0EAA0E;IAC1E,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,iFAAiF;IACjF,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CA4CjE"}
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Pure parsers for radare2 JSON output (izj/izzj strings, iSj sections, aflj
3
+ * functions, axtj cross-references) plus the marker-split for the batched
4
+ * "Pass 2" command used by verify_string_usage.
5
+ *
6
+ * Every parser is defensive and NEVER throws — malformed/partial r2 output
7
+ * returns an empty result so the classifier can degrade to `unknown` rather
8
+ * than mistaking a parse failure for a real "no xref" answer. Field shapes were
9
+ * captured from radare2 6.1.6; alternative key names seen across versions are
10
+ * tolerated (e.g. function address as `addr` or `offset`).
11
+ */
12
+ /** Self-generated markers (emitted via `?e`) that delimit the Pass-2 sections. */
13
+ export const R2_MARKERS = {
14
+ sections: "__R2MCP_SEC__",
15
+ functions: "__R2MCP_FNS__",
16
+ xref: "__R2MCP_XR__",
17
+ };
18
+ /** The connector caps stdout at 10MB and appends this sentinel when it does. */
19
+ const TRUNCATION_SENTINEL = "[OUTPUT TRUNCATED";
20
+ function asArray(json) {
21
+ try {
22
+ const data = JSON.parse(json);
23
+ return Array.isArray(data) ? data : [];
24
+ }
25
+ catch {
26
+ return [];
27
+ }
28
+ }
29
+ function num(v) {
30
+ return typeof v === "number" && Number.isFinite(v) ? v : undefined;
31
+ }
32
+ /** Parse `izj` / `izzj` string output. */
33
+ export function parseR2Strings(json) {
34
+ const out = [];
35
+ for (const e of asArray(json)) {
36
+ if (!e || typeof e !== "object")
37
+ continue;
38
+ const r = e;
39
+ const value = r.string;
40
+ const vaddr = num(r.vaddr);
41
+ if (typeof value === "string" && vaddr !== undefined) {
42
+ out.push({ value, vaddr, section: typeof r.section === "string" ? r.section : "" });
43
+ }
44
+ }
45
+ return out;
46
+ }
47
+ /** Parse `iSj` section output into ranges with an exec flag. */
48
+ export function parseR2Sections(json) {
49
+ const out = [];
50
+ for (const e of asArray(json)) {
51
+ if (!e || typeof e !== "object")
52
+ continue;
53
+ const r = e;
54
+ const vaddr = num(r.vaddr);
55
+ const vsize = num(r.vsize) ?? 0;
56
+ if (vaddr === undefined)
57
+ continue;
58
+ const perm = typeof r.perm === "string" ? r.perm : "";
59
+ out.push({
60
+ name: typeof r.name === "string" ? r.name : "",
61
+ vaddr,
62
+ vaddrEnd: vaddr + vsize,
63
+ exec: perm.includes("x"),
64
+ });
65
+ }
66
+ return out;
67
+ }
68
+ /** Parse `aflj` function list (address key is `addr` or `offset` across versions). */
69
+ export function parseR2Functions(json) {
70
+ const out = [];
71
+ for (const e of asArray(json)) {
72
+ if (!e || typeof e !== "object")
73
+ continue;
74
+ const r = e;
75
+ const addr = num(r.addr) ?? num(r.offset);
76
+ if (addr === undefined)
77
+ continue;
78
+ out.push({ addr, name: typeof r.name === "string" ? r.name : "", size: num(r.size) ?? 0 });
79
+ }
80
+ return out;
81
+ }
82
+ /** Parse `axtj` cross-reference output for one address. */
83
+ export function parseR2Xrefs(json) {
84
+ const out = [];
85
+ for (const e of asArray(json)) {
86
+ if (!e || typeof e !== "object")
87
+ continue;
88
+ const r = e;
89
+ const from = num(r.from);
90
+ if (from === undefined)
91
+ continue;
92
+ out.push({
93
+ from,
94
+ type: typeof r.type === "string" ? r.type : "",
95
+ fcnAddr: num(r.fcn_addr),
96
+ fcnName: typeof r.fcn_name === "string" ? r.fcn_name : undefined,
97
+ opcode: typeof r.opcode === "string" ? r.opcode : undefined,
98
+ });
99
+ }
100
+ return out;
101
+ }
102
+ /** Extract the radare2 version string from `?V` output (first matching line). */
103
+ export function parseR2Version(text) {
104
+ const m = text.match(/radare2\s+(\S+)/i);
105
+ return m ? m[1] : undefined;
106
+ }
107
+ /**
108
+ * Split the batched Pass-2 stdout on the self-generated markers. The preamble
109
+ * (before the sections marker) carries the `?V` version line; sections sit
110
+ * between the sections and functions markers; functions between the functions
111
+ * marker and the first xref marker; each `__R2MCP_XR__ <addr>` block holds that
112
+ * address's axtj JSON up to the next marker or EOF.
113
+ */
114
+ export function splitMarkedR2Output(stdout) {
115
+ const result = {
116
+ truncated: stdout.includes(TRUNCATION_SENTINEL),
117
+ sectionsJson: "",
118
+ functionsJson: "",
119
+ xrefsByVaddr: new Map(),
120
+ };
121
+ const lines = stdout.split("\n");
122
+ let bucket = { kind: "pre" };
123
+ let buf = [];
124
+ const flush = () => {
125
+ const text = buf.join("\n").trim();
126
+ if (bucket.kind === "pre") {
127
+ result.version = parseR2Version(text);
128
+ }
129
+ else if (bucket.kind === "sec") {
130
+ result.sectionsJson = text;
131
+ }
132
+ else if (bucket.kind === "fns") {
133
+ result.functionsJson = text;
134
+ }
135
+ else if (bucket.kind === "xref" && bucket.key) {
136
+ result.xrefsByVaddr.set(bucket.key, text);
137
+ }
138
+ buf = [];
139
+ };
140
+ for (const line of lines) {
141
+ const trimmed = line.trim();
142
+ if (trimmed === R2_MARKERS.sections) {
143
+ flush();
144
+ bucket = { kind: "sec" };
145
+ }
146
+ else if (trimmed === R2_MARKERS.functions) {
147
+ flush();
148
+ bucket = { kind: "fns" };
149
+ }
150
+ else if (trimmed.startsWith(R2_MARKERS.xref + " ")) {
151
+ flush();
152
+ bucket = { kind: "xref", key: trimmed.slice(R2_MARKERS.xref.length + 1).trim() };
153
+ }
154
+ else {
155
+ buf.push(line);
156
+ }
157
+ }
158
+ flush();
159
+ return result;
160
+ }
161
+ //# sourceMappingURL=r2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"r2.js","sourceRoot":"","sources":["../../src/parsers/r2.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,kFAAkF;AAClF,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,QAAQ,EAAE,eAAe;IACzB,SAAS,EAAE,eAAe;IAC1B,IAAI,EAAE,cAAc;CACZ,CAAC;AAEX,gFAAgF;AAChF,MAAM,mBAAmB,GAAG,mBAAmB,CAAC;AAkChD,SAAS,OAAO,CAAC,IAAY;IAC3B,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC9B,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAS,GAAG,CAAC,CAAU;IACrB,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACrE,CAAC;AAED,0CAA0C;AAC1C,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,GAAG,GAAe,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9B,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ;YAAE,SAAS;QAC1C,MAAM,CAAC,GAAG,CAA4B,CAAC;QACvC,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC;QACvB,MAAM,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAC3B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACrD,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACtF,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,MAAM,GAAG,GAAgB,EAAE,CAAC;IAC5B,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9B,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ;YAAE,SAAS;QAC1C,MAAM,CAAC,GAAG,CAA4B,CAAC;QACvC,MAAM,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAC3B,MAAM,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,KAAK,KAAK,SAAS;YAAE,SAAS;QAClC,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QACtD,GAAG,CAAC,IAAI,CAAC;YACP,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;YAC9C,KAAK;YACL,QAAQ,EAAE,KAAK,GAAG,KAAK;YACvB,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;SACzB,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,GAAG,GAAiB,EAAE,CAAC;IAC7B,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9B,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ;YAAE,SAAS;QAC1C,MAAM,CAAC,GAAG,CAA4B,CAAC;QACvC,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAC1C,IAAI,IAAI,KAAK,SAAS;YAAE,SAAS;QACjC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7F,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9B,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ;YAAE,SAAS;QAC1C,MAAM,CAAC,GAAG,CAA4B,CAAC;QACvC,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACzB,IAAI,IAAI,KAAK,SAAS;YAAE,SAAS;QACjC,GAAG,CAAC,IAAI,CAAC;YACP,IAAI;YACJ,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;YAC9C,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;YACxB,OAAO,EAAE,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;YAChE,MAAM,EAAE,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;SAC5D,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IACzC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC9B,CAAC;AAYD;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAc;IAChD,MAAM,MAAM,GAAkB;QAC5B,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC;QAC/C,YAAY,EAAE,EAAE;QAChB,aAAa,EAAE,EAAE;QACjB,YAAY,EAAE,IAAI,GAAG,EAAE;KACxB,CAAC;IAEF,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEjC,IAAI,MAAM,GAAW,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACrC,IAAI,GAAG,GAAa,EAAE,CAAC;IAEvB,MAAM,KAAK,GAAG,GAAG,EAAE;QACjB,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QACnC,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YAC1B,MAAM,CAAC,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;QACxC,CAAC;aAAM,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YACjC,MAAM,CAAC,YAAY,GAAG,IAAI,CAAC;QAC7B,CAAC;aAAM,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YACjC,MAAM,CAAC,aAAa,GAAG,IAAI,CAAC;QAC9B,CAAC;aAAM,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;YAChD,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC5C,CAAC;QACD,GAAG,GAAG,EAAE,CAAC;IACX,CAAC,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,OAAO,KAAK,UAAU,CAAC,QAAQ,EAAE,CAAC;YACpC,KAAK,EAAE,CAAC;YACR,MAAM,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QAC3B,CAAC;aAAM,IAAI,OAAO,KAAK,UAAU,CAAC,SAAS,EAAE,CAAC;YAC5C,KAAK,EAAE,CAAC;YACR,MAAM,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QAC3B,CAAC;aAAM,IAAI,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;YACrD,KAAK,EAAE,CAAC;YACR,MAAM,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QACnF,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjB,CAAC;IACH,CAAC;IACD,KAAK,EAAE,CAAC;IACR,OAAO,MAAM,CAAC;AAChB,CAAC"}