Wolfenstein Modloader Buy me a coffeeKaffee spendieren

Wiki / Latest research roundsNeueste Forschungsrunden

Appending Brand-New Decl Entries: Independent Re-Verification

Partly solvedTeilweise gelöst Original page in the GitHub wikiOriginalseite im GitHub-Wiki

In plain wordsIn einfachen Worten

This report re-checked from raw bytes an earlier claim that new entries can be appended to a copied Wolfenstein II: The New Colossus archive. The claim holds: 52 field-level checks pass, entry order does not matter, and the game code builds a case-insensitive name index when it loads an archive. A complete new weapon made of 7 cloned decls was built and verified offline, but nothing in this report was tested in the running game yet.

  • 52 independent field-level checks pass for both original test cases.
  • The game looks up entry names without caring about case, so two names that differ only by case will collide.
  • Correction: changing the entry count without updating the two integrity checksums makes the archive fail to load.
  • A 7-decl weapon chain (pickup, item, weapon, ammo, projectile and more) was cloned from the pistol and verified offline.
  • Limit: kill stats and the weapon-wheel flash slot must reuse existing values; new ones cannot be created from data.

Dieser Bericht hat eine frühere Behauptung Byte für Byte nachgeprüft: dass sich neue Einträge an ein kopiertes Archiv von Wolfenstein II: The New Colossus anhängen lassen. Die Behauptung hält: 52 Prüfungen auf Feldebene bestehen, die Reihenfolge der Einträge ist egal, und der Spielcode baut beim Laden eines Archivs einen Namensindex, der Groß-/Kleinschreibung ignoriert. Eine komplette neue Waffe aus 7 geklonten Decls wurde offline gebaut und geprüft, aber nichts aus diesem Bericht wurde bisher im laufenden Spiel getestet.

  • 52 unabhängige Prüfungen auf Feldebene bestehen für beide ursprünglichen Testfälle.
  • Das Spiel sucht Eintragsnamen ohne Rücksicht auf Groß-/Kleinschreibung; zwei Namen, die sich nur darin unterscheiden, kollidieren.
  • Korrektur: Wer die Eintragsanzahl ändert, ohne die beiden Prüfsummen anzupassen, bekommt ein Archiv, das nicht lädt.
  • Eine Waffenkette aus 7 Decls (Pickup, Gegenstand, Waffe, Munition, Projektil und mehr) wurde von der Pistole geklont und offline geprüft.
  • Grenze: Kill-Statistik und Aufleucht-Platz im Waffenrad müssen vorhandene Werte nutzen; neue lassen sich nicht aus Daten erzeugen.

Technical detailsTechnische Details

Der technische Teil ist auf Englisch – so, wie er im Wiki steht. Unterstrichene Begriffe haben eine Erklärung auf Deutsch.

An earlier report claimed that appending a brand-new (type, name) entry to a copied archive is structurally sound, but its own verification step never actually ran. This pass independently re-derives and re-checks every one of that claim's field-level details from raw bytes (not just trusting pass/fail output), tries four new ways to break the technique, and goes further by building a complete, cross-referencing 7-decl new weapon from scratch. The original claim holds up, and new disassembly of the game's own archive-mounting code found a previously-undocumented in-memory name-lookup index the engine builds at mount time — good news for the technique, since nothing about it cares about entry order. One earlier claim in this same track (that corrupting the entry count alone would be silently tolerated by the real engine) was wrong and is corrected below; everything else in this report is static/structural verification only, with a concrete in-game test proposed at the end.

What's confirmed about appending new entries

  • 52 independent field-level checks (byte ranges re-derived from scratch, not through the existing reader library) pass for both of the original report's test cases.
  • Entry table order does not matter. A new entry's row was moved to table position 0 while its payload stayed physically at the end of the file; it still parses, still resolves by name, and both archive-integrity hashes still validate. "Table order = file offset order" is a writer convenience, not a format or engine requirement.
  • String-table order does not matter either. None of the 24 retail archives checked have alphabetically sorted string tables — there's no sort convention to accidentally violate.
  • The archive-mounting code builds a real, in-memory, case-insensitive hash index over entry names at mount time (new disassembly this pass, .text region 0xACC15C–0xACC2CB) — a classic chained hash table keyed by a lowercased, multiplicative hash of each entry's name. Its loop bound is exactly the header's entry-count field, which the append technique already keeps correct. A located consumer of this same index (a second disassembled function) confirms the lookup is case-insensitive end to end, not just at the hashing step — meaning two asset names differing only by case will collide and are not safely distinguishable, a real naming hazard for new content.
  • Correction to an earlier claim in this track: simply editing the entry-count field without recomputing the archive's two integrity hashes is not silently tolerated by the real engine — both hashes are checked before the engine ever reaches the lookup-index code, and a mismatch is a hard mount failure. The project's own writer tooling already always keeps the count and both hashes consistent, so this correction doesn't change how new content should be built — it only corrects what an intentionally mismatched file would do.
  • A field that is never read by this project's own reader (num_strings) still can't be corrupted "for free" — any byte in an entry row is covered by the mandatory integrity-hash check regardless of whether anything downstream actually uses that field.

A complete new weapon, structurally

A 7-decl chain (two weapon entries, ammo, projectile, propItem, two entityDef entries) was cloned from the retail pistol's own reference graph, appended to a copied archive with every cross-reference renamed and checked, and passes all of the above verification. This traces, with concrete field names, the full donor chain a weapon pickup needs:

entityDef (pickup prop) → propItem (grants inventory item) → weapon (visual/handling)
    → entityDef (world-held weapon entity) and weapon_nomesh (stats: fire rate, upgrades, slot)
    → ammo → projectile → damage

One genuine ceiling found this pass: three weapon fields — progIndex, killStat, weaponSlotFlash — are drawn from small, closed value sets (8–12 distinct values across ~68 retail weapons) that also exist as literal strings baked into the executable itself, unlike every other cross-reference field checked (which are free text). A brand-new weapon decl can be appended with a new name, but its kill-stat tracking and HUD weapon-wheel flash slot must alias one of the existing values — there is no way to invent a new one purely from decl data.

What this still needs to become a real, equippable weapon

Per a related report on weapon anatomy: an entity placed in a map whose class is the new pickup entityDef (an already-proven technique: retarget an existing pickup entity's reference, rather than inserting a brand-new entity block, which nobody has built yet), and reusing one of the existing weapon-wheel slots (there is no 9th slot to invent without touching the unwritable UI binary).

In-game test (two steps, from cheapest to most complete)

  1. Decl chain only: append a new ammo entry under a name that doesn't exist in retail, with a distinctive clipSize, and point the existing pistol at it via the usual decl-edit mechanism. Load the custom map, pick up the pistol, read the magazine size off the HUD. A changed number confirms a genuinely new archive entry was found and loaded at mount time — the one thing that can't be settled from a desk.
  2. Full new weapon: build the 7-entry weapon-set container, retarget one of the custom map's already-proven pickup entities to point at the new pickup entityDef, load the map, pick up the item, and confirm it's selectable, fires, and shows the expected ammo count.