Enigma 1.01: authentic static unpacking; dynamic closure remains unproven

All ten retained original PE32 modules passed authentic UPX integrity tests and decompressed successfully to separate diagnostic files. Their recovered normal imports bind: 849 entries, 40 module edges, 192 packaged export references. The packed tables exposed only 81 import entries over the same 40 edges. This is static diagnostic acceptance. It proves neither full dynamic closure, emulator API implementation nor menu/gameplay readiness. No guest was executed.

The exact starting commit is b9450836983365a8f7f90d3f9f8213bf7f629f31, from the assigned original-task donor, not main. This branch adds a separate helper, tests and evidence only. The original verifier and its tests are byte-identical to that commit. The original verifier still reports BLOCKED_PACKED_IMPORTS. Its full read-only archive/asset recheck passed for all 2,460 files. Original manifest SHA256 before and after is 74a65c35b0742c00f0a53f4590fe1c888715e6b59acae8f0349d1d98c1dbb574.

Provenance, bytes and recovered tables

Official release: https://github.com/upx/upx/releases/tag/v5.0.2. The retained primary API response is https://api.github.com/repos/upx/upx/releases/tags/v5.0.2. The selected Linux x86-64 asset is https://github.com/upx/upx/releases/download/v5.0.2/upx-5.0.2-amd64_linux.tar.xz. Its official API digest and independently measured 626,608-byte download agree: ddc2654063fe4dc80d95b420788494e4db078ebb01a650692d623b5a9906e61e. Extracted upx SHA256 is 992aa498ea367409359e424da5afdca8b2818eb55486ffcf7d4a63576cde4501. --version reported 5.0.2. No mirror, package installer or compiler was used. Acquisition had no denied request or retry. Both local guard failures prevented their sentinel before the first metadata/download operation. Each production predecessor's status gated its successor. Exact argv/status/log hashes remain in metadata-fetch.json, tool-fetch.json and each module binding.

Task root: /tmp/enigma-authentic-static-unpack-oct24/. Only ten named PE files were copied from the standing read-only original tree; no archive or assets were copied. Inputs total 2,177,024 bytes. Outputs total 7,828,992 bytes; all inputs retain their original SHA256. Binaries, complete UPX distribution and primary metadata are retained separately from Git. They are recovery material, not remotely backed up by the task commit.

Each module has original path/hash, release/tool hash, exact -t and -d -o NEW_PATH ORIGINAL_COPY command, zero exit status, log hash, output length/hash and recovered entrypoint/sections in enigma-unpacked-evidence-20261024.json. No replacement or injected library was produced. UPX's test covers its packed payload, not arbitrary overlay data or program behavior; full-file input/output hashes supply the independent byte binding.

The new parser bounds PE32 headers, section raw/virtual extents and overlaps, entrypoint backing/executable flag, RVA reads, import tables and export targets. It rejects remaining UPX section names and delay imports needing extra handling. The old parser deliberately remains untouched: decompressed files contain legitimate repeated descriptors for msvcrt.dll which it rejects. The separate diagnostic parser merges these descriptors while retaining their counts.

All packaged module imports are traversed, including modules outside the EXE's direct static graph. Named exports and ordinals are represented separately; forwarders recursively resolve with cycle rejection and ordinal support. These actual files contain no ordinal imports or forwarded exports; dedicated positive and rejecting graph controls exercise those resolver branches. The normal system boundary is kernel32, advapi32, gdi32, user32, msvcrt, winmm and ws2_32. Their required names are recorded, without asserting emulator support.

Dynamic loads: decoded evidence and remaining gates

The verifier decodes six fixed-name codec initializers, checking literal stack arguments, relative calls, import thunks, IAT identities, saved module handles, and all 74 literal function-name requests. It also checks exported SDL bridge parameter flow into Windows LoadLibraryA and GetProcAddress.

Caller Fixed DLL Lookups Static result
SDL_image jpeg.dll 9 Packaged exports bind
SDL_image libpng12-0.dll 16 Packaged exports bind
SDL_image libtiff-3.dll 5 DLL absent
SDL_mixer mikmod.dll 25 Packaged exports bind
SDL_mixer libvorbisfile-3.dll 6 DLL absent
SDL_mixer smpeg.dll 13 DLL absent

These are supported code paths, not DLL-string guesses. The JPEG/PNG/MikMod function requests all bind, but static existence does not establish which initializers a particular asset or configuration invokes. TIFF, Vorbis and MPEG codec availability, their recursive dependencies and necessity for this package remain unproven. Do not silently fetch or substitute those libraries.

Bounded disassembly also supports Enigma's literal shfolder.dll, DDRAW.DLL and extensionless WSOCK32 requests, and SDL's DINPUT/DDRAW/DSOUND requests. The evidence labels their bounded operand windows and call sites. These are Windows provider boundaries, not bundled-code closure or implemented emulator APIs. SDL's OpenGL loader accepts a caller-provided filename; OPENGL32.DLL also appears as a string, which alone does not prove a default execution path. Enigma's load at VA 0x5ab960 passes a register-supplied name. Its subsequent GetProcAddress, SDL's generic load/function and GL lookup paths, driver-selected APIs, and any computed names/indirect calls remain unproven. Direct-call byte scanning is a candidate finder, not an exhaustive control-flow proof. This task does not establish a complete symbol contract for those system/dynamic paths.

Future coordinator-assigned work must establish required dynamic loads and emulator support, writable configuration, initialization and actual menu/level/ input behavior. Static success grants no registry, deployment or runtime status.

Verification and recovery recipe

From this private checkout, with retained task material:

python3 test/enigma-unpacked-closure.test.py /tmp/enigma-authentic-static-unpack-oct24
python3 tools/enigma-unpacked-closure.py verify \
  /tmp/enigma-authentic-static-unpack-oct24/module-bindings.json \
  /tmp/enigma-authentic-static-unpack-oct24/outputs \
  /tmp/enigma-authentic-static-unpack-oct24/inputs \
  /tmp/enigma-authentic-static-unpack-oct24/tool-identity.json

The final full suite passed 14 substantive rejecting controls plus two guard/ sentinel controls. Missing DLL, changed output, wrong original binding, wrong tool identity, failed UPX check, changed command, unresolved DLL/export, unresolved forwarded ordinal, forward cycle, invalid entrypoint/section bounds, packed input and changed codec instruction all reject. No pass-on-skip: invoking the test without the task root runs only its clearly labelled pre-download tests. Final CLI verification also passed with dynamic_closure: UNPROVEN.

For lost diagnostic outputs, first repeat resource/memory admission, preserve the standing originals and verify every pinned hash in the committed evidence. Copy only its ten original paths into a new owned inputs/, using their original case. Recover the tool only from the official pinned asset above using the retained sequencer/guards, finite 2 MiB download bound and 60-second process group bound. Verify the archive SHA, inventory before extraction (no links/path escapes; full expanded bound 6 MiB), then executable SHA before execution. Read the retained cli-doc-slice.txt: -t tests packed payload; -d decompresses; -o file selects a new output. Remove the UPX environment override.

For each original copy, run the exact commands in module-bindings.json, mapped to the new owned paths, through the helper's bounded run(argv, log). Gate -d on -t returning zero; stop on the first substantive error. Update receipt paths, statuses/log hashes and output lengths/hashes; the verifier pins all ten original and diagnostic hashes, so changing receipts cannot bless other bytes. Keep the tool/version identity receipt's argv path consistent. It is intentional that receipts from one output directory cannot authorize a different directory. Retain original archive/asset verifier evidence separately; never replace its original hashes with diagnostic hashes. The full tables in unpacked-closure.json and recovered-tables.json can be regenerated with Python verify/pe; the CLI prints compact module summaries to bound capture.

Resource and lifecycle

Admission was 52,764,672 / 67,108,864 bytes including 8 MiB reserve, tool archive and extraction overlap, all ten input/output copies, Git/source/evidence and 16 MiB future external-history/SQLite growth allowance. Actual directory blocks, full external session/events, positive SQLite growth and cumulative capture are measured by the single retained resource.py; the final receipt retains the initial projection. Largest owned file is 6,287,872 bytes, below 25 MiB. Installed tool identities/standing footprints are separate; every newly acquired UPX byte is charged. Fresh memory gates and CPU/wall process bounds passed. No Node, compiler, full build, browser, guest, box or lifecycle operation occurred. Mount argv and box ID/state/expiry: N/A. Coordinator retains lifecycle ownership. Root tracked files/index/refs and all donor stores remained read-only; root board updates were append-only. This worker stops after publishing the bounded result.