bla-agents 1.1.0 → 1.6.0
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.
- package/.agents/skills/blind-llm-agents/SKILL.md +20 -14
- package/DISCLAIMER.md +15 -7
- package/README.md +153 -198
- package/dist/bundler/index.d.ts +19 -2
- package/dist/bundler/index.d.ts.map +1 -1
- package/dist/bundler/index.js +47 -4
- package/dist/bundler/index.js.map +1 -1
- package/dist/cli.d.ts +5 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +123 -18
- package/dist/cli.js.map +1 -1
- package/dist/core/config.d.ts +54 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +160 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/coverage-contract.d.ts +97 -0
- package/dist/core/coverage-contract.d.ts.map +1 -0
- package/dist/core/coverage-contract.js +164 -0
- package/dist/core/coverage-contract.js.map +1 -0
- package/dist/core/debug-posture.d.ts +40 -0
- package/dist/core/debug-posture.d.ts.map +1 -0
- package/dist/core/debug-posture.js +197 -0
- package/dist/core/debug-posture.js.map +1 -0
- package/dist/core/detector.d.ts.map +1 -1
- package/dist/core/detector.js +58 -6
- package/dist/core/detector.js.map +1 -1
- package/dist/core/identifiers.d.ts +32 -0
- package/dist/core/identifiers.d.ts.map +1 -0
- package/dist/core/identifiers.js +263 -0
- package/dist/core/identifiers.js.map +1 -0
- package/dist/core/llm-directives.d.ts +12 -0
- package/dist/core/llm-directives.d.ts.map +1 -0
- package/dist/core/llm-directives.js +23 -0
- package/dist/core/llm-directives.js.map +1 -0
- package/dist/core/prng.d.ts +10 -1
- package/dist/core/prng.d.ts.map +1 -1
- package/dist/core/prng.js +27 -2
- package/dist/core/prng.js.map +1 -1
- package/dist/core/release-exposure.d.ts.map +1 -1
- package/dist/core/release-exposure.js +13 -2
- package/dist/core/release-exposure.js.map +1 -1
- package/dist/core/release-plan.d.ts +68 -0
- package/dist/core/release-plan.d.ts.map +1 -0
- package/dist/core/release-plan.js +244 -0
- package/dist/core/release-plan.js.map +1 -0
- package/dist/core/sarif.d.ts +53 -0
- package/dist/core/sarif.d.ts.map +1 -0
- package/dist/core/sarif.js +95 -0
- package/dist/core/sarif.js.map +1 -0
- package/dist/core/sqlite-runtime.d.ts +13 -0
- package/dist/core/sqlite-runtime.d.ts.map +1 -1
- package/dist/core/sqlite-runtime.js +38 -8
- package/dist/core/sqlite-runtime.js.map +1 -1
- package/dist/core/types.d.ts +7 -2
- package/dist/core/types.d.ts.map +1 -1
- package/dist/engine/auditor.d.ts.map +1 -1
- package/dist/engine/auditor.js +380 -19
- package/dist/engine/auditor.js.map +1 -1
- package/dist/engine/benchmark.d.ts +1 -1
- package/dist/engine/benchmark.d.ts.map +1 -1
- package/dist/engine/benchmark.js +121 -41
- package/dist/engine/benchmark.js.map +1 -1
- package/dist/engine/defender.d.ts +1 -0
- package/dist/engine/defender.d.ts.map +1 -1
- package/dist/engine/defender.js +7 -1
- package/dist/engine/defender.js.map +1 -1
- package/dist/engine/harden.d.ts +61 -0
- package/dist/engine/harden.d.ts.map +1 -0
- package/dist/engine/harden.js +294 -0
- package/dist/engine/harden.js.map +1 -0
- package/dist/engine/protector.d.ts.map +1 -1
- package/dist/engine/protector.js +242 -26
- package/dist/engine/protector.js.map +1 -1
- package/dist/identity.d.ts +112 -2
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +112 -2
- package/dist/identity.js.map +1 -1
- package/dist/index.d.ts +26 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -9
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.d.ts +59 -152
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +466 -50
- package/dist/mcp/server.js.map +1 -1
- package/dist/setup/clients.d.ts +49 -1
- package/dist/setup/clients.d.ts.map +1 -1
- package/dist/setup/clients.js +1193 -20
- package/dist/setup/clients.js.map +1 -1
- package/dist/setup/doctor.d.ts +58 -14
- package/dist/setup/doctor.d.ts.map +1 -1
- package/dist/setup/doctor.js +316 -22
- package/dist/setup/doctor.js.map +1 -1
- package/dist/setup/setup.d.ts +77 -7
- package/dist/setup/setup.d.ts.map +1 -1
- package/dist/setup/setup.js +591 -62
- package/dist/setup/setup.js.map +1 -1
- package/dist/shields/chaff/chaff-generator.d.ts.map +1 -1
- package/dist/shields/chaff/chaff-generator.js +12 -3
- package/dist/shields/chaff/chaff-generator.js.map +1 -1
- package/dist/shields/deception/architecture-mirage.js +1 -1
- package/dist/shields/deception/architecture-mirage.js.map +1 -1
- package/dist/shields/deception/canary-honeypot.d.ts +33 -0
- package/dist/shields/deception/canary-honeypot.d.ts.map +1 -0
- package/dist/shields/deception/canary-honeypot.js +95 -0
- package/dist/shields/deception/canary-honeypot.js.map +1 -0
- package/dist/shields/deception/cognitive-armor-trigger.d.ts +43 -0
- package/dist/shields/deception/cognitive-armor-trigger.d.ts.map +1 -0
- package/dist/shields/deception/cognitive-armor-trigger.js +204 -0
- package/dist/shields/deception/cognitive-armor-trigger.js.map +1 -0
- package/dist/shields/deception/crash-trace-decoy.js +1 -1
- package/dist/shields/deception/crash-trace-decoy.js.map +1 -1
- package/dist/shields/deception/decompiler-illusion.js +1 -1
- package/dist/shields/deception/decompiler-illusion.js.map +1 -1
- package/dist/shields/deception/diff-noise-injector.js +1 -1
- package/dist/shields/deception/diff-noise-injector.js.map +1 -1
- package/dist/shields/deception/evidence-contract-poison.js +5 -5
- package/dist/shields/deception/evidence-contract-poison.js.map +1 -1
- package/dist/shields/deception/format-payloads.d.ts +21 -0
- package/dist/shields/deception/format-payloads.d.ts.map +1 -0
- package/dist/shields/deception/format-payloads.js +24 -0
- package/dist/shields/deception/format-payloads.js.map +1 -0
- package/dist/shields/deception/index.d.ts +10 -2
- package/dist/shields/deception/index.d.ts.map +1 -1
- package/dist/shields/deception/index.js +20 -3
- package/dist/shields/deception/index.js.map +1 -1
- package/dist/shields/deception/prompt-completion-poison.d.ts +3 -2
- package/dist/shields/deception/prompt-completion-poison.d.ts.map +1 -1
- package/dist/shields/deception/prompt-completion-poison.js +6 -3
- package/dist/shields/deception/prompt-completion-poison.js.map +1 -1
- package/dist/shields/deception/shadow-business-logic.js +4 -4
- package/dist/shields/deception/shadow-business-logic.js.map +1 -1
- package/dist/shields/deception/system-diagnostic-decoy.d.ts +36 -0
- package/dist/shields/deception/system-diagnostic-decoy.d.ts.map +1 -0
- package/dist/shields/deception/system-diagnostic-decoy.js +101 -0
- package/dist/shields/deception/system-diagnostic-decoy.js.map +1 -0
- package/dist/shields/exhaustion/asar-header-amplifier.d.ts +12 -3
- package/dist/shields/exhaustion/asar-header-amplifier.d.ts.map +1 -1
- package/dist/shields/exhaustion/asar-header-amplifier.js +30 -8
- package/dist/shields/exhaustion/asar-header-amplifier.js.map +1 -1
- package/dist/shields/exhaustion/bpe-token-amplifier.js +2 -2
- package/dist/shields/exhaustion/bpe-token-amplifier.js.map +1 -1
- package/dist/shields/exhaustion/callgraph-labyrinth.js +2 -2
- package/dist/shields/exhaustion/callgraph-labyrinth.js.map +1 -1
- package/dist/shields/exhaustion/cdp-shape-budget-breaker.js +1 -1
- package/dist/shields/exhaustion/cdp-shape-budget-breaker.js.map +1 -1
- package/dist/shields/exhaustion/frida-capture-saturation.d.ts +10 -5
- package/dist/shields/exhaustion/frida-capture-saturation.d.ts.map +1 -1
- package/dist/shields/exhaustion/frida-capture-saturation.js +21 -8
- package/dist/shields/exhaustion/frida-capture-saturation.js.map +1 -1
- package/dist/shields/exhaustion/index.d.ts +2 -2
- package/dist/shields/exhaustion/index.d.ts.map +1 -1
- package/dist/shields/exhaustion/index.js +2 -2
- package/dist/shields/exhaustion/index.js.map +1 -1
- package/dist/shields/exhaustion/obligation-flooder.d.ts +23 -6
- package/dist/shields/exhaustion/obligation-flooder.d.ts.map +1 -1
- package/dist/shields/exhaustion/obligation-flooder.js +29 -12
- package/dist/shields/exhaustion/obligation-flooder.js.map +1 -1
- package/dist/shields/exhaustion/rea-budget-matrix.d.ts +8 -2
- package/dist/shields/exhaustion/rea-budget-matrix.d.ts.map +1 -1
- package/dist/shields/exhaustion/rea-budget-matrix.js +139 -16
- package/dist/shields/exhaustion/rea-budget-matrix.js.map +1 -1
- package/dist/shields/exhaustion/regex-worker-tarpit.d.ts.map +1 -1
- package/dist/shields/exhaustion/regex-worker-tarpit.js +2 -1
- package/dist/shields/exhaustion/regex-worker-tarpit.js.map +1 -1
- package/dist/shields/exhaustion/wasm-interface-exhaustion.d.ts +7 -4
- package/dist/shields/exhaustion/wasm-interface-exhaustion.d.ts.map +1 -1
- package/dist/shields/exhaustion/wasm-interface-exhaustion.js +16 -7
- package/dist/shields/exhaustion/wasm-interface-exhaustion.js.map +1 -1
- package/dist/shields/formats/android-dex-xref.d.ts +19 -0
- package/dist/shields/formats/android-dex-xref.d.ts.map +1 -0
- package/dist/shields/formats/android-dex-xref.js +427 -0
- package/dist/shields/formats/android-dex-xref.js.map +1 -0
- package/dist/shields/formats/android-manifest.d.ts +44 -0
- package/dist/shields/formats/android-manifest.d.ts.map +1 -0
- package/dist/shields/formats/android-manifest.js +240 -0
- package/dist/shields/formats/android-manifest.js.map +1 -0
- package/dist/shields/formats/android-r8.d.ts +44 -0
- package/dist/shields/formats/android-r8.d.ts.map +1 -0
- package/dist/shields/formats/android-r8.js +246 -0
- package/dist/shields/formats/android-r8.js.map +1 -0
- package/dist/shields/formats/apple-plist.d.ts +15 -0
- package/dist/shields/formats/apple-plist.d.ts.map +1 -1
- package/dist/shields/formats/apple-plist.js +59 -1
- package/dist/shields/formats/apple-plist.js.map +1 -1
- package/dist/shields/formats/archive.d.ts +27 -6
- package/dist/shields/formats/archive.d.ts.map +1 -1
- package/dist/shields/formats/archive.js +247 -45
- package/dist/shields/formats/archive.js.map +1 -1
- package/dist/shields/formats/asar.d.ts +50 -10
- package/dist/shields/formats/asar.d.ts.map +1 -1
- package/dist/shields/formats/asar.js +265 -39
- package/dist/shields/formats/asar.js.map +1 -1
- package/dist/shields/formats/bun-standalone.d.ts +78 -0
- package/dist/shields/formats/bun-standalone.d.ts.map +1 -0
- package/dist/shields/formats/bun-standalone.js +272 -0
- package/dist/shields/formats/bun-standalone.js.map +1 -0
- package/dist/shields/formats/dotnet-managed.d.ts +9 -0
- package/dist/shields/formats/dotnet-managed.d.ts.map +1 -1
- package/dist/shields/formats/dotnet-managed.js +26 -1
- package/dist/shields/formats/dotnet-managed.js.map +1 -1
- package/dist/shields/formats/electron-fuses.d.ts +63 -8
- package/dist/shields/formats/electron-fuses.d.ts.map +1 -1
- package/dist/shields/formats/electron-fuses.js +297 -65
- package/dist/shields/formats/electron-fuses.js.map +1 -1
- package/dist/shields/formats/erlang-beam.d.ts +34 -0
- package/dist/shields/formats/erlang-beam.d.ts.map +1 -0
- package/dist/shields/formats/erlang-beam.js +319 -0
- package/dist/shields/formats/erlang-beam.js.map +1 -0
- package/dist/shields/formats/evm-bytecode.d.ts +28 -0
- package/dist/shields/formats/evm-bytecode.d.ts.map +1 -0
- package/dist/shields/formats/evm-bytecode.js +124 -0
- package/dist/shields/formats/evm-bytecode.js.map +1 -0
- package/dist/shields/formats/go-flutter-exhaustion.d.ts +55 -0
- package/dist/shields/formats/go-flutter-exhaustion.d.ts.map +1 -0
- package/dist/shields/formats/go-flutter-exhaustion.js +346 -0
- package/dist/shields/formats/go-flutter-exhaustion.js.map +1 -0
- package/dist/shields/formats/gpu-ptx.d.ts +40 -0
- package/dist/shields/formats/gpu-ptx.d.ts.map +1 -0
- package/dist/shields/formats/gpu-ptx.js +62 -0
- package/dist/shields/formats/gpu-ptx.js.map +1 -0
- package/dist/shields/formats/headers.d.ts.map +1 -1
- package/dist/shields/formats/headers.js +54 -14
- package/dist/shields/formats/headers.js.map +1 -1
- package/dist/shields/formats/jvm-bytecode.d.ts +20 -0
- package/dist/shields/formats/jvm-bytecode.d.ts.map +1 -0
- package/dist/shields/formats/jvm-bytecode.js +134 -0
- package/dist/shields/formats/jvm-bytecode.js.map +1 -0
- package/dist/shields/formats/mobile-game.d.ts +4 -0
- package/dist/shields/formats/mobile-game.d.ts.map +1 -1
- package/dist/shields/formats/mobile-game.js +16 -0
- package/dist/shields/formats/mobile-game.js.map +1 -1
- package/dist/shields/formats/model.d.ts +22 -8
- package/dist/shields/formats/model.d.ts.map +1 -1
- package/dist/shields/formats/model.js +231 -59
- package/dist/shields/formats/model.js.map +1 -1
- package/dist/shields/formats/native.d.ts +74 -11
- package/dist/shields/formats/native.d.ts.map +1 -1
- package/dist/shields/formats/native.js +557 -109
- package/dist/shields/formats/native.js.map +1 -1
- package/dist/shields/formats/pcap-capture.d.ts +27 -0
- package/dist/shields/formats/pcap-capture.d.ts.map +1 -0
- package/dist/shields/formats/pcap-capture.js +201 -0
- package/dist/shields/formats/pcap-capture.js.map +1 -0
- package/dist/shields/formats/python.d.ts +22 -1
- package/dist/shields/formats/python.d.ts.map +1 -1
- package/dist/shields/formats/python.js +568 -27
- package/dist/shields/formats/python.js.map +1 -1
- package/dist/shields/formats/sourcemap.d.ts.map +1 -1
- package/dist/shields/formats/sourcemap.js +2 -0
- package/dist/shields/formats/sourcemap.js.map +1 -1
- package/dist/shields/formats/sqlite.d.ts +87 -15
- package/dist/shields/formats/sqlite.d.ts.map +1 -1
- package/dist/shields/formats/sqlite.js +377 -42
- package/dist/shields/formats/sqlite.js.map +1 -1
- package/dist/shields/formats/wasm.d.ts +6 -0
- package/dist/shields/formats/wasm.d.ts.map +1 -1
- package/dist/shields/formats/wasm.js +118 -3
- package/dist/shields/formats/wasm.js.map +1 -1
- package/dist/shields/javascript/ast-shield.d.ts +26 -5
- package/dist/shields/javascript/ast-shield.d.ts.map +1 -1
- package/dist/shields/javascript/ast-shield.js +748 -104
- package/dist/shields/javascript/ast-shield.js.map +1 -1
- package/dist/shields/runtime/memory-diff-shield.d.ts +56 -0
- package/dist/shields/runtime/memory-diff-shield.d.ts.map +1 -0
- package/dist/shields/runtime/memory-diff-shield.js +170 -0
- package/dist/shields/runtime/memory-diff-shield.js.map +1 -0
- package/dist/shields/runtime/runtime-shield.d.ts +12 -16
- package/dist/shields/runtime/runtime-shield.d.ts.map +1 -1
- package/dist/shields/runtime/runtime-shield.js +30 -24
- package/dist/shields/runtime/runtime-shield.js.map +1 -1
- package/dist/shields/tarpit/opaque-predicates.d.ts.map +1 -1
- package/dist/shields/tarpit/opaque-predicates.js +3 -3
- package/dist/shields/tarpit/opaque-predicates.js.map +1 -1
- package/dist/shields/tarpit/tarpit-generator.d.ts +9 -4
- package/dist/shields/tarpit/tarpit-generator.d.ts.map +1 -1
- package/dist/shields/tarpit/tarpit-generator.js +30 -23
- package/dist/shields/tarpit/tarpit-generator.js.map +1 -1
- package/package.json +13 -6
|
@@ -1,8 +1,196 @@
|
|
|
1
|
+
import { detectBunStandaloneGraph, } from "./bun-standalone.js";
|
|
1
2
|
import { deflateSync } from "node:zlib";
|
|
2
3
|
import { REA_INTERNAL_LIMITS } from "../../identity.js";
|
|
3
4
|
import { SeededPrng } from "../../core/prng.js";
|
|
4
5
|
import { generateChaffPayloads } from "../chaff/chaff-generator.js";
|
|
5
|
-
import {
|
|
6
|
+
import { generateCanaryHoneypot } from "../deception/canary-honeypot.js";
|
|
7
|
+
import { generateSystemDiagnosticDecoy } from "../deception/system-diagnostic-decoy.js";
|
|
8
|
+
import { generateCognitiveArmorTrigger } from "../deception/cognitive-armor-trigger.js";
|
|
9
|
+
import { buildDecoyElectronFuseSentinels, hardenElectronFusesWithContext, inspectElectronFusesInBuffer, } from "./electron-fuses.js";
|
|
10
|
+
import { buildGoBuildInfoExhaustionPayload, buildFlutterPoolExhaustionPayload, buildMappedGoBuildInfoPlant, buildMappedFlutterIsolatePoolPlant, } from "./go-flutter-exhaustion.js";
|
|
11
|
+
export class InvalidNativeBinaryError extends Error {
|
|
12
|
+
constructor(message) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = "InvalidNativeBinaryError";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const MAX_SAFE_BIGINT = BigInt(Number.MAX_SAFE_INTEGER);
|
|
18
|
+
/**
|
|
19
|
+
* Validates ELF64 little-endian header, program headers (`PT_LOAD`, `p_filesz <= p_memsz`,
|
|
20
|
+
* non-overlapping virtual address ranges, in-bounds file ranges), and section headers
|
|
21
|
+
* (in-bounds file ranges, valid `e_shstrndx`, non-overlapping file-backed sections).
|
|
22
|
+
*/
|
|
23
|
+
export function validateElf64Layout(bytes) {
|
|
24
|
+
if (bytes.length < 64 ||
|
|
25
|
+
bytes[0] !== 0x7f ||
|
|
26
|
+
bytes[1] !== 0x45 ||
|
|
27
|
+
bytes[2] !== 0x4c ||
|
|
28
|
+
bytes[3] !== 0x46) {
|
|
29
|
+
throw new InvalidNativeBinaryError("Invalid or truncated ELF header (minimum 64 bytes required)");
|
|
30
|
+
}
|
|
31
|
+
if (bytes[4] !== 2 || bytes[5] !== 1) {
|
|
32
|
+
throw new InvalidNativeBinaryError("Unsupported ELF class or endianness (expected ELF64 little-endian)");
|
|
33
|
+
}
|
|
34
|
+
const phoffBig = bytes.readBigUInt64LE(32);
|
|
35
|
+
const shoffBig = bytes.readBigUInt64LE(40);
|
|
36
|
+
const ehsize = bytes.readUInt16LE(52);
|
|
37
|
+
const phentsize = bytes.readUInt16LE(54);
|
|
38
|
+
const phnum = bytes.readUInt16LE(56);
|
|
39
|
+
const shentsize = bytes.readUInt16LE(58);
|
|
40
|
+
const shnum = bytes.readUInt16LE(60);
|
|
41
|
+
const shstrndx = bytes.readUInt16LE(62);
|
|
42
|
+
if (ehsize !== 0 && (ehsize < 64 || ehsize > bytes.length)) {
|
|
43
|
+
throw new InvalidNativeBinaryError(`Invalid ELF64 e_ehsize: ${ehsize}`);
|
|
44
|
+
}
|
|
45
|
+
if (phoffBig > MAX_SAFE_BIGINT || shoffBig > MAX_SAFE_BIGINT) {
|
|
46
|
+
throw new InvalidNativeBinaryError("ELF64 header table offsets exceed safe integer range");
|
|
47
|
+
}
|
|
48
|
+
const phoff = Number(phoffBig);
|
|
49
|
+
const shoff = Number(shoffBig);
|
|
50
|
+
const programHeaders = [];
|
|
51
|
+
const phTableEnd = phnum > 0 ? phoff + phnum * phentsize : 0;
|
|
52
|
+
if (phnum > 0) {
|
|
53
|
+
if (phentsize < 56 ||
|
|
54
|
+
phoff < 64 ||
|
|
55
|
+
!Number.isSafeInteger(phTableEnd) ||
|
|
56
|
+
phTableEnd > bytes.length) {
|
|
57
|
+
throw new InvalidNativeBinaryError("ELF64 program header table out of bounds or malformed");
|
|
58
|
+
}
|
|
59
|
+
for (let i = 0; i < phnum; i++) {
|
|
60
|
+
const phdr = phoff + i * phentsize;
|
|
61
|
+
const pType = bytes.readUInt32LE(phdr);
|
|
62
|
+
const pFlags = bytes.readUInt32LE(phdr + 4);
|
|
63
|
+
const pOffsetBig = bytes.readBigUInt64LE(phdr + 8);
|
|
64
|
+
const pVaddrBig = bytes.readBigUInt64LE(phdr + 16);
|
|
65
|
+
const pPaddrBig = bytes.readBigUInt64LE(phdr + 24);
|
|
66
|
+
const pFileszBig = bytes.readBigUInt64LE(phdr + 32);
|
|
67
|
+
const pMemszBig = bytes.readBigUInt64LE(phdr + 40);
|
|
68
|
+
const pAlignBig = bytes.readBigUInt64LE(phdr + 48);
|
|
69
|
+
if (pOffsetBig > MAX_SAFE_BIGINT || pFileszBig > MAX_SAFE_BIGINT) {
|
|
70
|
+
throw new InvalidNativeBinaryError(`ELF64 program header ${i} file offset/size exceeds safe integer range`);
|
|
71
|
+
}
|
|
72
|
+
const pOffset = Number(pOffsetBig);
|
|
73
|
+
const pFilesz = Number(pFileszBig);
|
|
74
|
+
if (!Number.isSafeInteger(pOffset + pFilesz) ||
|
|
75
|
+
pOffset + pFilesz > bytes.length) {
|
|
76
|
+
throw new InvalidNativeBinaryError(`ELF64 program header ${i} file range [${pOffset}, ${pOffset + pFilesz}) out of bounds (${bytes.length})`);
|
|
77
|
+
}
|
|
78
|
+
if (pType === 1) {
|
|
79
|
+
// PT_LOAD
|
|
80
|
+
if (pMemszBig < pFileszBig) {
|
|
81
|
+
throw new InvalidNativeBinaryError(`ELF64 PT_LOAD segment ${i} has p_memsz (${pMemszBig}) < p_filesz (${pFileszBig})`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
programHeaders.push({
|
|
85
|
+
index: i,
|
|
86
|
+
type: pType,
|
|
87
|
+
flags: pFlags,
|
|
88
|
+
offset: pOffset,
|
|
89
|
+
vaddr: pVaddrBig,
|
|
90
|
+
paddr: pPaddrBig,
|
|
91
|
+
filesz: pFilesz,
|
|
92
|
+
memsz: pMemszBig,
|
|
93
|
+
align: pAlignBig,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
// Verify no two PT_LOAD segments have overlapping virtual address ranges
|
|
97
|
+
const loadSegments = programHeaders.filter((ph) => ph.type === 1 && ph.memsz > 0n);
|
|
98
|
+
for (let i = 0; i < loadSegments.length; i++) {
|
|
99
|
+
const a = loadSegments[i];
|
|
100
|
+
const aEnd = a.vaddr + a.memsz;
|
|
101
|
+
for (let j = i + 1; j < loadSegments.length; j++) {
|
|
102
|
+
const b = loadSegments[j];
|
|
103
|
+
const bEnd = b.vaddr + b.memsz;
|
|
104
|
+
if (a.vaddr < bEnd && b.vaddr < aEnd) {
|
|
105
|
+
throw new InvalidNativeBinaryError(`ELF64 PT_LOAD segments ${a.index} and ${b.index} have overlapping virtual address ranges`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const sectionHeaders = [];
|
|
111
|
+
const shTableEnd = shnum > 0 ? shoff + shnum * shentsize : 0;
|
|
112
|
+
if (shnum > 0) {
|
|
113
|
+
if (shentsize < 64 ||
|
|
114
|
+
shoff < 64 ||
|
|
115
|
+
!Number.isSafeInteger(shTableEnd) ||
|
|
116
|
+
shTableEnd > bytes.length) {
|
|
117
|
+
throw new InvalidNativeBinaryError("ELF64 section header table out of bounds or malformed");
|
|
118
|
+
}
|
|
119
|
+
if (phnum > 0 && phoff < shTableEnd && shoff < phTableEnd) {
|
|
120
|
+
throw new InvalidNativeBinaryError("ELF64 section header table overlaps program header table");
|
|
121
|
+
}
|
|
122
|
+
if (shstrndx !== 0 && shstrndx >= shnum) {
|
|
123
|
+
throw new InvalidNativeBinaryError(`ELF64 e_shstrndx (${shstrndx}) out of bounds for e_shnum (${shnum})`);
|
|
124
|
+
}
|
|
125
|
+
for (let s = 0; s < shnum; s++) {
|
|
126
|
+
const shdr = shoff + s * shentsize;
|
|
127
|
+
const shName = bytes.readUInt32LE(shdr);
|
|
128
|
+
const shType = bytes.readUInt32LE(shdr + 4);
|
|
129
|
+
const shFlags = bytes.readBigUInt64LE(shdr + 8);
|
|
130
|
+
const shAddr = bytes.readBigUInt64LE(shdr + 16);
|
|
131
|
+
const shOffsetBig = bytes.readBigUInt64LE(shdr + 24);
|
|
132
|
+
const shSizeBig = bytes.readBigUInt64LE(shdr + 32);
|
|
133
|
+
if (shOffsetBig > MAX_SAFE_BIGINT || shSizeBig > MAX_SAFE_BIGINT) {
|
|
134
|
+
throw new InvalidNativeBinaryError(`ELF64 section ${s} offset/size exceeds safe integer range`);
|
|
135
|
+
}
|
|
136
|
+
const shOffset = Number(shOffsetBig);
|
|
137
|
+
const shSize = Number(shSizeBig);
|
|
138
|
+
// File-backed sections: not SHT_NULL (0) and not SHT_NOBITS (8)
|
|
139
|
+
if (s >= 1 && shType !== 0 && shType !== 8) {
|
|
140
|
+
if (!Number.isSafeInteger(shOffset + shSize) ||
|
|
141
|
+
shOffset + shSize > bytes.length) {
|
|
142
|
+
throw new InvalidNativeBinaryError(`ELF64 section ${s} file range [${shOffset}, ${shOffset + shSize}) out of bounds (${bytes.length})`);
|
|
143
|
+
}
|
|
144
|
+
if (shSize > 0) {
|
|
145
|
+
if (shOffset < 64) {
|
|
146
|
+
throw new InvalidNativeBinaryError(`ELF64 section ${s} overlaps ELF64 header`);
|
|
147
|
+
}
|
|
148
|
+
if (phnum > 0 &&
|
|
149
|
+
shOffset < phTableEnd &&
|
|
150
|
+
phoff < shOffset + shSize) {
|
|
151
|
+
throw new InvalidNativeBinaryError(`ELF64 section ${s} overlaps program header table`);
|
|
152
|
+
}
|
|
153
|
+
if (shOffset < shTableEnd && shoff < shOffset + shSize) {
|
|
154
|
+
throw new InvalidNativeBinaryError(`ELF64 section ${s} overlaps section header table`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
sectionHeaders.push({
|
|
159
|
+
index: s,
|
|
160
|
+
nameOffset: shName,
|
|
161
|
+
type: shType,
|
|
162
|
+
flags: shFlags,
|
|
163
|
+
addr: shAddr,
|
|
164
|
+
offset: shOffset,
|
|
165
|
+
size: shSize,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
// Verify no two non-empty file-backed sections overlap in file range
|
|
169
|
+
const fileBackedSections = sectionHeaders.filter((sec) => sec.index >= 1 && sec.type !== 0 && sec.type !== 8 && sec.size > 0);
|
|
170
|
+
for (let i = 0; i < fileBackedSections.length; i++) {
|
|
171
|
+
const a = fileBackedSections[i];
|
|
172
|
+
const aEnd = a.offset + a.size;
|
|
173
|
+
for (let j = i + 1; j < fileBackedSections.length; j++) {
|
|
174
|
+
const b = fileBackedSections[j];
|
|
175
|
+
const bEnd = b.offset + b.size;
|
|
176
|
+
if (a.offset < bEnd && b.offset < aEnd) {
|
|
177
|
+
throw new InvalidNativeBinaryError(`ELF64 sections ${a.index} and ${b.index} have overlapping file ranges`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
phoff,
|
|
184
|
+
phentsize,
|
|
185
|
+
phnum,
|
|
186
|
+
shoff,
|
|
187
|
+
shentsize,
|
|
188
|
+
shnum,
|
|
189
|
+
shstrndx,
|
|
190
|
+
programHeaders,
|
|
191
|
+
sectionHeaders,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
6
194
|
export function inspectNativeBinary(bytes) {
|
|
7
195
|
let format = "unknown";
|
|
8
196
|
let bits = 64;
|
|
@@ -65,12 +253,29 @@ export function inspectNativeBinary(bytes) {
|
|
|
65
253
|
const hasRustDepV0 = textLatin1.includes(".dep-v0");
|
|
66
254
|
const hasGoBuildInfo = textLatin1.includes(".go.buildinfo") ||
|
|
67
255
|
textLatin1.includes("__go_buildinfo") ||
|
|
68
|
-
textLatin1.includes("\xff Go buildinf:")
|
|
256
|
+
textLatin1.includes("\xff Go buildinf:") ||
|
|
257
|
+
textLatin1.includes("[BLA-GO-BUILDINFO]");
|
|
258
|
+
const goBuildInfoFramed = textLatin1.includes("[BLA-GO-BUILDINFO]") ||
|
|
259
|
+
textLatin1.includes(".gopclntab") ||
|
|
260
|
+
textLatin1.includes("runtime.moduledata");
|
|
261
|
+
let dartPoolPackageUriCount = 0;
|
|
262
|
+
let dartPoolTokenCount = 0;
|
|
263
|
+
for (const run of textLatin1.split("\0")) {
|
|
264
|
+
if (run.startsWith("package:") || run.startsWith("dart:")) {
|
|
265
|
+
dartPoolPackageUriCount++;
|
|
266
|
+
}
|
|
267
|
+
else if (run.length >= 5 &&
|
|
268
|
+
run.length <= 128 &&
|
|
269
|
+
/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(run)) {
|
|
270
|
+
dartPoolTokenCount++;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
69
273
|
const printableMatches = textLatin1.match(/[A-Za-z0-9_/:.-]{6,}/g) ?? [];
|
|
70
274
|
const blaProtected = textLatin1.includes("BLA-NATIVE-SHIELD") ||
|
|
71
275
|
rustcMatches.size > REA_INTERNAL_LIMITS.RUST_MAX_COMMIT_HASHES ||
|
|
72
276
|
fuseInspection.exceedsReaSentinelLimit ||
|
|
73
|
-
dartSnapshotHashesCount >
|
|
277
|
+
dartSnapshotHashesCount >
|
|
278
|
+
REA_INTERNAL_LIMITS.DART_MAX_SNAPSHOT_HASH_CANDIDATES ||
|
|
74
279
|
textLatin1.includes("Architecture Notice: Core business logic");
|
|
75
280
|
return {
|
|
76
281
|
format,
|
|
@@ -79,8 +284,11 @@ export function inspectNativeBinary(bytes) {
|
|
|
79
284
|
rustcCommitHashesCount: rustcMatches.size,
|
|
80
285
|
electronFuseSentinelsCount: fuseInspection.sentinelCount,
|
|
81
286
|
dartSnapshotHashesCount,
|
|
287
|
+
dartPoolPackageUriCount,
|
|
288
|
+
dartPoolTokenCount,
|
|
82
289
|
hasRustDepV0,
|
|
83
290
|
hasGoBuildInfo,
|
|
291
|
+
goBuildInfoFramed,
|
|
84
292
|
extractedStringsCount: printableMatches.length,
|
|
85
293
|
blaProtected,
|
|
86
294
|
};
|
|
@@ -122,60 +330,305 @@ export function buildDecoyRustAuditablePayload(prng) {
|
|
|
122
330
|
];
|
|
123
331
|
return deflateSync(Buffer.from(JSON.stringify({ format: 1, packages }), "utf8"));
|
|
124
332
|
}
|
|
333
|
+
/** Resolve ELF64 section names from the section-header string table. */
|
|
334
|
+
export function resolveElf64SectionNames(bytes, layout) {
|
|
335
|
+
const map = new Map();
|
|
336
|
+
if (layout.shnum === 0 ||
|
|
337
|
+
layout.shstrndx === 0 ||
|
|
338
|
+
layout.shstrndx >= layout.shnum) {
|
|
339
|
+
return map;
|
|
340
|
+
}
|
|
341
|
+
const strSec = layout.sectionHeaders[layout.shstrndx];
|
|
342
|
+
if (!strSec || strSec.size === 0 || strSec.offset + strSec.size > bytes.length) {
|
|
343
|
+
return map;
|
|
344
|
+
}
|
|
345
|
+
const strtab = bytes.subarray(strSec.offset, strSec.offset + strSec.size);
|
|
346
|
+
for (const sh of layout.sectionHeaders) {
|
|
347
|
+
if (sh.index === 0)
|
|
348
|
+
continue;
|
|
349
|
+
if (sh.nameOffset >= strtab.length)
|
|
350
|
+
continue;
|
|
351
|
+
let end = sh.nameOffset;
|
|
352
|
+
while (end < strtab.length && strtab[end] !== 0)
|
|
353
|
+
end++;
|
|
354
|
+
const name = strtab.subarray(sh.nameOffset, end).toString("utf8");
|
|
355
|
+
if (name.length > 0)
|
|
356
|
+
map.set(name, sh);
|
|
357
|
+
}
|
|
358
|
+
return map;
|
|
359
|
+
}
|
|
125
360
|
/**
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
361
|
+
* Plant framed Go buildinfo into `.go.buildinfo` (preferred) or the first
|
|
362
|
+
* writable non-executable PT_LOAD file range so REA's mapped parser trips.
|
|
363
|
+
* Never mutates program/section header fields — only file-backed bytes.
|
|
129
364
|
*/
|
|
130
|
-
function
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
365
|
+
function injectMappedGoBuildInfo(working, layout, intensity) {
|
|
366
|
+
// Only mutate a named `.go.buildinfo` PROGBITS section. Generic PT_LOAD
|
|
367
|
+
// fallback would rewrite arbitrary ELF fixtures and violate the
|
|
368
|
+
// trailer-only / section-integrity red line for non-Go binaries.
|
|
369
|
+
const names = resolveElf64SectionNames(working, layout);
|
|
370
|
+
const named = names.get(".go.buildinfo");
|
|
371
|
+
if (!named || named.type !== 1 || named.size < 48) {
|
|
372
|
+
return { planted: false, tripsMax: false, offset: -1, size: 0 };
|
|
373
|
+
}
|
|
374
|
+
const alignPad = Number((16n - (named.addr % 16n)) % 16n);
|
|
375
|
+
const writeAt = named.offset + alignPad;
|
|
376
|
+
const room = named.size - alignPad;
|
|
377
|
+
if (room < 48) {
|
|
378
|
+
return { planted: false, tripsMax: false, offset: -1, size: 0 };
|
|
379
|
+
}
|
|
380
|
+
const plant = buildMappedGoBuildInfoPlant(intensity, room);
|
|
381
|
+
if (plant.buffer.length === 0) {
|
|
382
|
+
return { planted: false, tripsMax: false, offset: -1, size: 0 };
|
|
383
|
+
}
|
|
384
|
+
// Clear the section then plant so prior padding cannot confuse parsers.
|
|
385
|
+
working.fill(0, named.offset, named.offset + named.size);
|
|
386
|
+
plant.buffer.copy(working, writeAt);
|
|
387
|
+
return {
|
|
388
|
+
planted: true,
|
|
389
|
+
tripsMax: plant.tripsMaxBuildInfoBytes,
|
|
390
|
+
offset: writeAt,
|
|
391
|
+
size: plant.buffer.length,
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Plant Flutter pool strings inside `.isolate` / isolate snapshot data regions
|
|
396
|
+
* (or after an embedded Dart snapshot magic) so REA's string-pool projection
|
|
397
|
+
* from isolate data observes the decoys.
|
|
398
|
+
*/
|
|
399
|
+
function injectMappedFlutterIsolatePool(working, layout, prng) {
|
|
400
|
+
// Only plant into an explicitly named `.isolate` section so generic
|
|
401
|
+
// `.rodata` / ELF fixtures stay byte-identical under trailer-only protect.
|
|
402
|
+
const names = resolveElf64SectionNames(working, layout);
|
|
403
|
+
const named = names.get(".isolate");
|
|
404
|
+
if (!named || named.type !== 1 || named.size < 64) {
|
|
405
|
+
return { planted: false, uris: 0, tokens: 0, offset: -1 };
|
|
406
|
+
}
|
|
407
|
+
let plantAt = named.offset;
|
|
408
|
+
let includeHeader = true;
|
|
409
|
+
if (named.size >= 52 &&
|
|
410
|
+
working[named.offset] === 0xf5 &&
|
|
411
|
+
working[named.offset + 1] === 0xf5 &&
|
|
412
|
+
working[named.offset + 2] === 0xdc &&
|
|
413
|
+
working[named.offset + 3] === 0xdc) {
|
|
414
|
+
plantAt = named.offset + 52;
|
|
415
|
+
includeHeader = false;
|
|
416
|
+
}
|
|
417
|
+
const capacity = named.offset + named.size - plantAt;
|
|
418
|
+
if (capacity < 64) {
|
|
419
|
+
return { planted: false, uris: 0, tokens: 0, offset: -1 };
|
|
420
|
+
}
|
|
421
|
+
const plant = buildMappedFlutterIsolatePoolPlant(capacity, prng, {
|
|
422
|
+
includeSnapshotHeader: includeHeader,
|
|
423
|
+
});
|
|
424
|
+
if (plant.buffer.length === 0) {
|
|
425
|
+
return { planted: false, uris: 0, tokens: 0, offset: -1 };
|
|
426
|
+
}
|
|
427
|
+
plant.buffer.copy(working, plantAt);
|
|
428
|
+
return {
|
|
429
|
+
planted: true,
|
|
430
|
+
uris: plant.packageAndDartUris,
|
|
431
|
+
tokens: plant.classLikeTokens,
|
|
432
|
+
offset: plantAt,
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
const PYINSTALLER_COOKIE_MAGIC = Buffer.from([
|
|
436
|
+
0x4d, 0x45, 0x49, 0x0c, 0x0b, 0x0a, 0x0b, 0x0e,
|
|
437
|
+
]);
|
|
438
|
+
const DENO_STANDALONE_MAGIC = Buffer.from("d3n0l4nd", "ascii");
|
|
439
|
+
function machoSliceHasCodeSignature(bytes, sliceOffset, sliceLength) {
|
|
440
|
+
if (sliceOffset < 0 || sliceLength < 32 || sliceOffset + sliceLength > bytes.length) {
|
|
441
|
+
return false;
|
|
442
|
+
}
|
|
443
|
+
const magicBE = bytes.readUInt32BE(sliceOffset);
|
|
444
|
+
const is64LE = magicBE === 0xcffaedfe;
|
|
445
|
+
const is64BE = magicBE === 0xfeedfacf;
|
|
446
|
+
const is32LE = magicBE === 0xcefaedfe;
|
|
447
|
+
const is32BE = magicBE === 0xfeedface;
|
|
448
|
+
if (!is64LE && !is64BE && !is32LE && !is32BE)
|
|
449
|
+
return false;
|
|
450
|
+
const isLE = is64LE || is32LE;
|
|
451
|
+
const headerSize = is64LE || is64BE ? 32 : 28;
|
|
452
|
+
const readU32 = (off) => isLE ? bytes.readUInt32LE(off) : bytes.readUInt32BE(off);
|
|
453
|
+
const ncmds = readU32(sliceOffset + 16);
|
|
454
|
+
const sizeofcmds = readU32(sliceOffset + 20);
|
|
455
|
+
if (ncmds === 0 || ncmds > 4096 || headerSize + sizeofcmds > sliceLength) {
|
|
456
|
+
return false;
|
|
457
|
+
}
|
|
458
|
+
let cur = sliceOffset + headerSize;
|
|
459
|
+
const end = cur + sizeofcmds;
|
|
460
|
+
for (let i = 0; i < ncmds && cur + 8 <= end; i++) {
|
|
461
|
+
const cmd = readU32(cur);
|
|
462
|
+
const cmdsize = readU32(cur + 4);
|
|
463
|
+
if (cmdsize < 8 || cur + cmdsize > end)
|
|
464
|
+
break;
|
|
465
|
+
// LC_CODE_SIGNATURE === 0x1d (29)
|
|
466
|
+
if (cmd === 0x1d)
|
|
467
|
+
return true;
|
|
468
|
+
cur += cmdsize;
|
|
469
|
+
}
|
|
470
|
+
return false;
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Detects native executable formats where appending a raw EOF trailer would
|
|
474
|
+
* invalidate OS code-signing (`codesign --strict` / `WinVerifyTrust`) or break
|
|
475
|
+
* EOF-relative standalone runtime archives (PyInstaller, `deno compile`, ZIP-SFX).
|
|
476
|
+
*/
|
|
477
|
+
export function detectNativeEofAppendHazard(bytes) {
|
|
478
|
+
if (bytes.length < 16)
|
|
479
|
+
return "none";
|
|
480
|
+
// 1. Mach-O thin or Universal Fat binary carrying LC_CODE_SIGNATURE (0x1d)
|
|
481
|
+
const magicBE = bytes.readUInt32BE(0);
|
|
482
|
+
if (magicBE === 0xcffaedfe ||
|
|
483
|
+
magicBE === 0xfeedfacf ||
|
|
484
|
+
magicBE === 0xcefaedfe ||
|
|
485
|
+
magicBE === 0xfeedface) {
|
|
486
|
+
if (machoSliceHasCodeSignature(bytes, 0, bytes.length)) {
|
|
487
|
+
return "macho-code-signature";
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
else if (magicBE === 0xcafebabe && bytes.length >= 28) {
|
|
491
|
+
const nfat = bytes.readUInt32BE(4);
|
|
492
|
+
if (nfat >= 1 && nfat <= 30 && 8 + nfat * 20 <= bytes.length) {
|
|
493
|
+
for (let i = 0; i < nfat; i++) {
|
|
494
|
+
const entryOff = 8 + i * 20;
|
|
495
|
+
const sliceOff = bytes.readUInt32BE(entryOff + 8);
|
|
496
|
+
const sliceSize = bytes.readUInt32BE(entryOff + 12);
|
|
497
|
+
if (machoSliceHasCodeSignature(bytes, sliceOff, sliceSize)) {
|
|
498
|
+
return "macho-code-signature";
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
// 2. PE32 / PE32+ carrying Authenticode IMAGE_DIRECTORY_ENTRY_SECURITY (DataDirectory[4])
|
|
504
|
+
if (bytes[0] === 0x4d && bytes[1] === 0x5a && bytes.length >= 0x40) {
|
|
505
|
+
const lfanew = bytes.readUInt32LE(0x3c);
|
|
506
|
+
if (lfanew >= 0x40 &&
|
|
507
|
+
lfanew + 26 <= bytes.length &&
|
|
508
|
+
bytes.readUInt32LE(lfanew) === 0x00004550) {
|
|
509
|
+
const optOff = lfanew + 24;
|
|
510
|
+
const optMagic = bytes.readUInt16LE(optOff);
|
|
511
|
+
const rvaCountOff = optMagic === 0x10b ? optOff + 92 : optMagic === 0x20b ? optOff + 108 : -1;
|
|
512
|
+
const dd4Off = optMagic === 0x10b ? optOff + 128 : optMagic === 0x20b ? optOff + 144 : -1;
|
|
513
|
+
if (rvaCountOff > 0 && dd4Off + 8 <= bytes.length) {
|
|
514
|
+
const numRva = bytes.readUInt32LE(rvaCountOff);
|
|
515
|
+
if (numRva >= 5) {
|
|
516
|
+
const certOffset = bytes.readUInt32LE(dd4Off);
|
|
517
|
+
const certSize = bytes.readUInt32LE(dd4Off + 4);
|
|
518
|
+
if (certOffset > 0 && certSize > 0) {
|
|
519
|
+
return "pe-authenticode-signature";
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
// 3. Deno `deno compile` standalone trailer (`d3n0l4nd` in trailing 64 bytes)
|
|
526
|
+
const tail64 = bytes.subarray(Math.max(0, bytes.length - 64));
|
|
527
|
+
if (tail64.includes(DENO_STANDALONE_MAGIC)) {
|
|
528
|
+
return "deno-standalone";
|
|
529
|
+
}
|
|
530
|
+
// 4. PyInstaller onefile CArchive cookie (`MEI\x0c\x0b\x0a\x0b\x0e` in trailing 64 KiB)
|
|
531
|
+
const tail64k = bytes.subarray(Math.max(0, bytes.length - 65_536));
|
|
532
|
+
if (tail64k.includes(PYINSTALLER_COOKIE_MAGIC)) {
|
|
533
|
+
return "pyinstaller-archive";
|
|
534
|
+
}
|
|
535
|
+
// 5. Self-extracting ZIP / AppImage with exact EOCD (`PK\x05\x06`) reaching EOF
|
|
536
|
+
if (bytes.length >= 22) {
|
|
537
|
+
const searchStart = Math.max(0, bytes.length - 65_557);
|
|
538
|
+
for (let pos = bytes.length - 22; pos >= searchStart; pos--) {
|
|
539
|
+
if (bytes[pos] === 0x50 &&
|
|
540
|
+
bytes[pos + 1] === 0x4b &&
|
|
541
|
+
bytes[pos + 2] === 0x05 &&
|
|
542
|
+
bytes[pos + 3] === 0x06) {
|
|
543
|
+
const commentLen = bytes.readUInt16LE(pos + 20);
|
|
544
|
+
if (pos + 22 + commentLen === bytes.length) {
|
|
545
|
+
return "zip-sfx-trailer";
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
return "none";
|
|
158
551
|
}
|
|
159
552
|
/**
|
|
160
|
-
* Protects a Native Binary (ELF / Mach-O / PE) against
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
* 3. **Go (`GoBuildInfoSearch.ts` / `GoModuleText.ts`)**: Embeds decoy Go module table entries (`mod\t`, `dep\t`).
|
|
165
|
-
* 4. **Electron Fuses (`ElectronFuseReader.ts`)**: Hardens any real Electron Fuse V1 wire in-place AND injects
|
|
166
|
-
* 34 decoy `dL7pKGdnNz796PbbjQWNKmHXBZaB9tsX` sentinels (`> maximumSentinelsPerSlice = 32`)!
|
|
167
|
-
* 5. **Flutter / Dart AOT (`FlutterPayloadScan.ts`)**: Injects 66 Dart snapshot magic records (`> 64` cap) and
|
|
168
|
-
* 6 LLVM toolchain lines (`> 4` cap).
|
|
169
|
-
* 6. **ELF64 `.rodata` Extension**: Extends the read-only `.rodata` section and `PT_LOAD` segment so
|
|
170
|
-
* REA's `mergedReadOnlyFileRanges` and slice scanners read the entire defensive trailer.
|
|
553
|
+
* Protects a Native Binary (ELF / Mach-O / PE) against REA's native & desktop analyzers
|
|
554
|
+
* while strictly preserving ELF64 `PT_LOAD` (`p_offset`, `p_filesz`, `p_memsz` / BSS) and
|
|
555
|
+
* section header boundaries. Real Electron fuses are only mutated when an explicit
|
|
556
|
+
* verified `electronHardeningContext` is provided.
|
|
171
557
|
*/
|
|
172
558
|
export function protectNativeBinary(bytes, options = {}) {
|
|
559
|
+
const bunCarrier = detectBunStandaloneGraph(bytes);
|
|
560
|
+
if (bunCarrier.kind === "appended-trailer" ||
|
|
561
|
+
bunCarrier.kind === "appended-trailer-sized") {
|
|
562
|
+
return {
|
|
563
|
+
buffer: Buffer.from(bytes),
|
|
564
|
+
rustcHashesInjected: 0,
|
|
565
|
+
electronFuseSentinelsInjected: 0,
|
|
566
|
+
dartSnapshotHashesInjected: 0,
|
|
567
|
+
dartPoolUrisInjected: 0,
|
|
568
|
+
dartPoolTokensInjected: 0,
|
|
569
|
+
goBuildInfoExceedsLimit: false,
|
|
570
|
+
mappedGoBuildInfoPlanted: false,
|
|
571
|
+
mappedFlutterPoolPlanted: false,
|
|
572
|
+
chaffPayloadsEmbedded: 0,
|
|
573
|
+
binarySectionsPatched: 0,
|
|
574
|
+
bunStandaloneCarrier: bunCarrier.kind,
|
|
575
|
+
bunStandaloneGraphPreserved: true,
|
|
576
|
+
nativeAppendHazard: "none",
|
|
577
|
+
nativeBinaryPreserved: true,
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
const appendHazard = options.electronHardeningContext
|
|
581
|
+
? "none"
|
|
582
|
+
: detectNativeEofAppendHazard(bytes);
|
|
583
|
+
if (appendHazard !== "none") {
|
|
584
|
+
return {
|
|
585
|
+
buffer: Buffer.from(bytes),
|
|
586
|
+
rustcHashesInjected: 0,
|
|
587
|
+
electronFuseSentinelsInjected: 0,
|
|
588
|
+
dartSnapshotHashesInjected: 0,
|
|
589
|
+
dartPoolUrisInjected: 0,
|
|
590
|
+
dartPoolTokensInjected: 0,
|
|
591
|
+
goBuildInfoExceedsLimit: false,
|
|
592
|
+
mappedGoBuildInfoPlanted: false,
|
|
593
|
+
mappedFlutterPoolPlanted: false,
|
|
594
|
+
chaffPayloadsEmbedded: 0,
|
|
595
|
+
binarySectionsPatched: 0,
|
|
596
|
+
bunStandaloneCarrier: bunCarrier.kind,
|
|
597
|
+
bunStandaloneGraphPreserved: false,
|
|
598
|
+
nativeAppendHazard: appendHazard,
|
|
599
|
+
nativeBinaryPreserved: true,
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
const isElfMagic = bytes.length >= 4 &&
|
|
603
|
+
bytes[0] === 0x7f &&
|
|
604
|
+
bytes[1] === 0x45 &&
|
|
605
|
+
bytes[2] === 0x4c &&
|
|
606
|
+
bytes[3] === 0x46;
|
|
607
|
+
const elfBefore = isElfMagic ? validateElf64Layout(bytes) : undefined;
|
|
173
608
|
const intensity = options.intensity ?? "balanced";
|
|
174
609
|
const prng = new SeededPrng(options.seed ?? "bla-native-shield-v1");
|
|
175
610
|
const chaffPayloads = generateChaffPayloads(prng, intensity);
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
611
|
+
let workingInput = Buffer.from(bytes);
|
|
612
|
+
let electronHardeningReport;
|
|
613
|
+
let patchedInPlaceCount = 0;
|
|
614
|
+
if (options.electronHardeningContext) {
|
|
615
|
+
electronHardeningReport = hardenElectronFusesWithContext(workingInput, options.electronHardeningContext);
|
|
616
|
+
workingInput = Buffer.from(electronHardeningReport.buffer);
|
|
617
|
+
patchedInPlaceCount =
|
|
618
|
+
electronHardeningReport.mutatedFuses.length > 0 ? 1 : 0;
|
|
619
|
+
}
|
|
620
|
+
const decoySentinelsInjected = 34;
|
|
621
|
+
const decoySentinelsBuffer = buildDecoyElectronFuseSentinels(prng, decoySentinelsInjected);
|
|
622
|
+
let mappedGoBuildInfoPlanted = false;
|
|
623
|
+
let mappedFlutterPoolPlanted = false;
|
|
624
|
+
let mappedGoTripsMax = false;
|
|
625
|
+
if (elfBefore) {
|
|
626
|
+
const goPlant = injectMappedGoBuildInfo(workingInput, elfBefore, intensity);
|
|
627
|
+
mappedGoBuildInfoPlanted = goPlant.planted;
|
|
628
|
+
mappedGoTripsMax = goPlant.tripsMax;
|
|
629
|
+
const flutterPlant = injectMappedFlutterIsolatePool(workingInput, elfBefore, prng);
|
|
630
|
+
mappedFlutterPoolPlanted = flutterPlant.planted;
|
|
631
|
+
}
|
|
179
632
|
// 1. Generate 68 distinct `/rustc/<40-hex>/` strings (> REA's MAX_RUSTC_HASHES = 64!)
|
|
180
633
|
const rustcCount = 68;
|
|
181
634
|
const rustcLines = [];
|
|
@@ -183,86 +636,81 @@ export function protectNativeBinary(bytes, options = {}) {
|
|
|
183
636
|
const hash = i.toString(16).padStart(8, "0") + prng.hex(32);
|
|
184
637
|
rustcLines.push(`/rustc/${hash}/library/core/src/enclave_guard.rs\0`);
|
|
185
638
|
}
|
|
186
|
-
// 2.
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
639
|
+
// 2. Framed Go buildinfo + pclntab/moduledata bait
|
|
640
|
+
const goBuildInfo = buildGoBuildInfoExhaustionPayload(prng, intensity);
|
|
641
|
+
// 3. Generate architectural chaff strings + Canary Honeypot + System-Diagnostic Rabbit Holes for Ghidra/Hopper/IDA
|
|
642
|
+
const chaffBlock = chaffPayloads
|
|
643
|
+
.map((p) => `${p.symbolName}: ${p.rawText}\0`)
|
|
644
|
+
.join("");
|
|
645
|
+
const canaryHoneypot = generateCanaryHoneypot(prng, intensity);
|
|
646
|
+
const systemDiagnostics = generateSystemDiagnosticDecoy(prng, intensity);
|
|
647
|
+
const cognitiveArmor = generateCognitiveArmorTrigger(prng, intensity);
|
|
648
|
+
const canaryAndDiagnosticBlock = [
|
|
649
|
+
...canaryHoneypot.syntheticCanaryTokens.map((tok) => `PROTECTED_CANARY_CREDENTIAL=${tok}\0`),
|
|
650
|
+
...canaryHoneypot.ambiguousCredentialUrls.map((url) => `TRANSPORT_ENDPOINT=${url}\0`),
|
|
651
|
+
...systemDiagnostics.diagnosticsInjected.map((d) => `[${d.subsystem}] ${d.errorClass} (${d.systemCode}): ${d.diagnosticMessage} Remediation: ${d.remediationRabbitHole}\0`),
|
|
652
|
+
...cognitiveArmor.triggersInjected.map((t) => `[COGNITIVE_ARMOR_INTERLOCK:${t.classifierDomain}] ${t.coupledAnchorSymbol} => ${t.triggerPayload.replace(/\r?\n/g, " ")}\0`),
|
|
194
653
|
].join("");
|
|
195
|
-
// 3. Generate architectural chaff strings for Ghidra / Hopper / IDA string tables
|
|
196
|
-
const chaffBlock = chaffPayloads.map((p) => `${p.symbolName}: ${p.rawText}\0`).join("");
|
|
197
654
|
const depV0Payload = buildDecoyRustAuditablePayload(prng);
|
|
198
|
-
const
|
|
655
|
+
const flutterPool = buildFlutterPoolExhaustionPayload(prng);
|
|
656
|
+
const dartOverflowPayload = flutterPool.buffer;
|
|
199
657
|
const shieldTrailer = Buffer.concat([
|
|
200
658
|
Buffer.from("\0[BLA-NATIVE-SHIELD-V1]\0.dep-v0\0", "utf8"),
|
|
201
659
|
Buffer.from(rustcLines.join(""), "latin1"),
|
|
202
|
-
|
|
203
|
-
|
|
660
|
+
goBuildInfo.buffer,
|
|
661
|
+
decoySentinelsBuffer,
|
|
204
662
|
dartOverflowPayload,
|
|
205
663
|
Buffer.from(chaffBlock, "utf8"),
|
|
664
|
+
Buffer.from(canaryAndDiagnosticBlock, "utf8"),
|
|
206
665
|
depV0Payload,
|
|
207
666
|
]);
|
|
208
667
|
const outBytes = Buffer.concat([workingInput, shieldTrailer]);
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const phnum = outBytes.readUInt16LE(56);
|
|
225
|
-
for (let p = 0; p < phnum; p++) {
|
|
226
|
-
const phdr = phoff + p * phentsize;
|
|
227
|
-
if (phdr + 56 <= outBytes.length) {
|
|
228
|
-
const pType = outBytes.readUInt32LE(phdr);
|
|
229
|
-
const pOffset = Number(outBytes.readBigUInt64LE(phdr + 8));
|
|
230
|
-
const pFilesz = Number(outBytes.readBigUInt64LE(phdr + 32));
|
|
231
|
-
if (pType === 1 && pOffset + pFilesz === workingInput.length) {
|
|
232
|
-
outBytes.writeBigUInt64LE(BigInt(outBytes.length - pOffset), phdr + 32);
|
|
233
|
-
outBytes.writeBigUInt64LE(BigInt(outBytes.length - pOffset), phdr + 40);
|
|
234
|
-
binarySectionsPatched++;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
for (let s = 1; s < shnum; s++) {
|
|
239
|
-
const shdr = shoff + s * shentsize;
|
|
240
|
-
if (shdr + 64 <= outBytes.length) {
|
|
241
|
-
const shType = outBytes.readUInt32LE(shdr + 4);
|
|
242
|
-
const shFlags = Number(outBytes.readBigUInt64LE(shdr + 8));
|
|
243
|
-
const shOffset = Number(outBytes.readBigUInt64LE(shdr + 24));
|
|
244
|
-
const shSize = Number(outBytes.readBigUInt64LE(shdr + 32));
|
|
245
|
-
const isReadOnlyProgbits = shType === 1 && (shFlags & 1) === 0 && (shFlags & 4) === 0;
|
|
246
|
-
if (isReadOnlyProgbits && shOffset + shSize <= workingInput.length) {
|
|
247
|
-
const newSize = outBytes.length - shOffset;
|
|
248
|
-
outBytes.writeBigUInt64LE(BigInt(newSize), shdr + 32);
|
|
249
|
-
binarySectionsPatched++;
|
|
250
|
-
break;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
668
|
+
const binarySectionsPatched = 1 + patchedInPlaceCount + (elfBefore ? 2 : 0);
|
|
669
|
+
if (elfBefore) {
|
|
670
|
+
const elfAfter = validateElf64Layout(outBytes);
|
|
671
|
+
for (let i = 0; i < elfBefore.programHeaders.length; i++) {
|
|
672
|
+
const beforePh = elfBefore.programHeaders[i];
|
|
673
|
+
const afterPh = elfAfter.programHeaders[i];
|
|
674
|
+
if (beforePh.type !== afterPh.type ||
|
|
675
|
+
beforePh.flags !== afterPh.flags ||
|
|
676
|
+
beforePh.offset !== afterPh.offset ||
|
|
677
|
+
beforePh.vaddr !== afterPh.vaddr ||
|
|
678
|
+
beforePh.paddr !== afterPh.paddr ||
|
|
679
|
+
beforePh.filesz !== afterPh.filesz ||
|
|
680
|
+
beforePh.memsz !== afterPh.memsz ||
|
|
681
|
+
beforePh.align !== afterPh.align) {
|
|
682
|
+
throw new InvalidNativeBinaryError(`ELF64 program header ${i} was mutated during protection`);
|
|
253
683
|
}
|
|
254
684
|
}
|
|
255
|
-
|
|
256
|
-
|
|
685
|
+
for (let s = 0; s < elfBefore.sectionHeaders.length; s++) {
|
|
686
|
+
const beforeSh = elfBefore.sectionHeaders[s];
|
|
687
|
+
const afterSh = elfAfter.sectionHeaders[s];
|
|
688
|
+
if (beforeSh.type !== afterSh.type ||
|
|
689
|
+
beforeSh.flags !== afterSh.flags ||
|
|
690
|
+
beforeSh.addr !== afterSh.addr ||
|
|
691
|
+
beforeSh.offset !== afterSh.offset ||
|
|
692
|
+
beforeSh.size !== afterSh.size) {
|
|
693
|
+
throw new InvalidNativeBinaryError(`ELF64 section header ${s} was mutated during protection`);
|
|
694
|
+
}
|
|
257
695
|
}
|
|
258
696
|
}
|
|
259
697
|
return {
|
|
260
698
|
buffer: outBytes,
|
|
261
699
|
rustcHashesInjected: rustcCount,
|
|
262
|
-
electronFuseSentinelsInjected:
|
|
263
|
-
dartSnapshotHashesInjected:
|
|
700
|
+
electronFuseSentinelsInjected: decoySentinelsInjected,
|
|
701
|
+
dartSnapshotHashesInjected: flutterPool.snapshotHashes,
|
|
702
|
+
dartPoolUrisInjected: flutterPool.packageAndDartUris,
|
|
703
|
+
dartPoolTokensInjected: flutterPool.classLikeTokens,
|
|
704
|
+
goBuildInfoExceedsLimit: goBuildInfo.exceedsMaxBuildInfoBytes || mappedGoTripsMax,
|
|
705
|
+
mappedGoBuildInfoPlanted,
|
|
706
|
+
mappedFlutterPoolPlanted,
|
|
264
707
|
chaffPayloadsEmbedded: chaffPayloads.length,
|
|
265
708
|
binarySectionsPatched,
|
|
709
|
+
...(electronHardeningReport ? { electronHardeningReport } : {}),
|
|
710
|
+
bunStandaloneCarrier: bunCarrier.kind,
|
|
711
|
+
bunStandaloneGraphPreserved: bunCarrier.kind !== "none",
|
|
712
|
+
nativeAppendHazard: "none",
|
|
713
|
+
nativeBinaryPreserved: false,
|
|
266
714
|
};
|
|
267
715
|
}
|
|
268
716
|
export function detectNativeFormatName(format) {
|