Skip to content

Research Brief Cfilekey2

LopeKinz edited this page Oct 1, 2026 · 3 revisions

Identity

Worker w-cfilekey2-a1; task cfilekey2; research (read-only RE). Read .agent-cache/WORKER.md. Bus: python "%USERPROFILE%/.claude/skills/agent-cache-orchestrator/scripts/acbus.py" Parallel: w-idclwriter-a1 (container writer), w-savestructure-a1.

Objective

Recover the cfile key derivation for Wolfenstein II. This is now the single item on the critical path to loading a custom map.

docs/cfile.md states the reason the earlier attempt failed, and it is the one thing that changed today:

"The key is derived ... exclusively inside the SteamStub-encrypted .text. No ready-to-use key exists in a readable section."

The previous worker only ever had the PACKED executable. re_probes/runtime_87400/module.bin is a read-only capture of the RUNNING, SteamStub-unpacked process - the .text that was unreadable is now plain. Five other format problems fell to exactly this today.

Why it matters - the chain this closes

Measured at runtime today (wolfsdk_dump.txt, console session 15:48):

  • The console dispatches exactly 34 commands. map, devmap, fastmap and toggle are registered but NOT among them. Static prediction and runtime agreed 34/34 with zero deviation.
  • resourceExec IS one of the 34. Per re_probes/agent_reports/cmdtable.md it sets the restriction level to 0 and buffers its script into the unrestricted command buffer - so a script run through it should reach all 234 commands, map included.
  • resourceExec wolfsdk_test.cfg on a LOOSE file answered: WARNING: cfile:wolfsdk_test.cfg:NONE can't generate in production while loading cfile:wolfsdk_test.cfg couldn't exec resource wolfsdk_test.cfg So it resolves its argument as a cfile RESOURCE, and refuses to generate one from a loose file in a production build.
  • com_production and resource_loadLooseAssets are both registered but NOT exposed (re_probes/cvartable/cvars_tnc_v2.json), so no console cvar can change that.

Therefore the script must exist as a cfile asset inside a mounted .resources archive. Building such an archive is solved as of today (re_probes/agent_reports/idclhash.md, datahash.md). Authoring the cfile payload is not - it is encrypted, and that is your task.

Sources / starting points

  • re_probes/runtime_87400/module.bin - virtual RVA layout (file offset == RVA), sections and image base in manifest.json, .pdata for function bounds.
  • docs/cfile.md - the prior analysis. It already located the ground: the handler is idEncryptedFileResource, AES through bcrypt.dll (CNG), and it lists the error strings with their .rdata addresses, e.g. 0x026C9580 "Failed to derive key", 0x026C9688 "could not derive key", and a nearby string describing "Salt erzeugen -> Schluessel ableiten -> verschluesseln". Take the xrefs from those strings into the now-readable .text. That is the shortest path.
  • tools/cfile.py - existing, READ-ONLY for you. It has a working Aes class, PKCS7 unpad, a plaintext scorer (verify_plain, textiness) and a cfile enumerator (cfiles, head). Reuse them; do not edit that file.
  • re_probes/agent_reports/saveverify.md - a sibling worker traced the OTHER bcrypt user in this binary (the save HMAC) and found idSecureHMAC, BCryptCreateHash/HashData/FinishHash, and a key built by SHA256 over a concatenation. The cfile path likely uses the same CNG wrappers - read that report before starting, the call shapes will look familiar.
  • The 10 strings/*.lang cfiles are the corpus the earlier attempt used.
  • capstone 5.0.7 vendored: PYTHONPATH=re_probes/python_deps

Ownership

tools/probe_cfilekey.py (new), re_probes/cfilekey/ (new dir), re_probes/agent_reports/cfilekey2.md (new).

Forbidden / do not touch

No game launch, no process attach, no writes under the Steam install or "%USERPROFILE%/Saved Games". Do not edit tools/cfile.py, wolfsdk/, docs/, config.json, or any other worker's files (tools/probe_idclhash.py, probe_datahash.py, probe_cmdtable.py, probe_saveverify.py, probe_texdbkey.py, probe_cvartable.py, probe_save_structure.py, wolfsdk/idclwrite.py, re_probes/{idclhash,datahash,cmdtable,saveverify,texdbkey,cvartable,idclwriter,save_structure}/). No pip install.

Hard constraints

Python 3.11, stdlib plus vendored capstone. The decryptor must be pure stdlib (tools/cfile.py already implements AES by hand for exactly this reason). Reproducible from the command line, no running game.

Acceptance criteria

  • The derivation read out of the code: which function, what inputs, what salt, what KDF, which AES mode, with the RVAs and the xref chain that got you there.
  • Positive control at today's bar: DECRYPT real retail cfiles and show the plaintext is genuinely plaintext - all 10 strings/*.lang, n/n, verified with a structural check (the existing verify_plain/declen logic), not by eyeballing that it "looks like text".
  • Round-trip: re-encrypt a decrypted cfile and reproduce the original bytes exactly. Without that, authoring a new cfile is guesswork.
  • Negative controls: a wrong key, a flipped salt byte and a wrong mode must each fail the structural check rather than producing plausible-looking output.
  • Then the payoff: produce a NEW, valid cfile whose plaintext is map game/dlc/c02/c2v1_custom and write it to re_probes/cfilekey/. State plainly that it is untested at runtime.

Verification expectations

Every important assurance needs a check that fails if it is false. "Decrypts to something with high textiness" is weak; the round-trip is strong. Keep "key found" and "key confirmed against the corpus" apart.

Failure honesty

If the key turns out to be derived from a runtime value that is not in the image (as happened with the save .verify HMAC today - read that report, it is the cautionary case), say so immediately and name what it depends on. That is a valuable result, not a failure: it would mean the resourceExec route needs a different carrier and we should stop pushing on this one.

Coordination / deliverable

Checkpoint at milestones. Publish a bus fact as soon as you can decrypt retail cfiles, and again when you can round-trip - the container writer worker needs the second one to put your payload into an archive. Concise German report in re_probes/agent_reports/cfilekey2.md. Finish the bus task when done.

Clone this wiki locally