Skip to content

Research Report Chunklist

LopeKinz edited this page Oct 1, 2026 · 2 revisions

packagechunklist.json in TNC-Retail: Clear Negative

Short Answer: Retail reads the file correctly; therefore, it is not merely a dev path. However, its contents end up only in the idStreamingInstallManager table. This table holds console metadata for streaming install, following the pattern chunkid → dependent packagechunks. On PC, this manager sleeps: its active flag is never set anywhere in the code, and IsChunkInstalled always returns true. No code mounts a chunk because of this file. dlc_5 cannot be mounted via it before the main menu. Nothing installs.

Tools: python tools/probe_chunklist.py yields 10 PASS results and "ALL TESTS OK". Details are in re_probes/chunklist/result.json. The installed EXE has the same SHA-256 as runtime_87400/manifest.json (68e6c21a…18c3). Thus, this analysis applies to the installed game.

Findings (RVA in module.bin)

# Finding Evidence
1 The string appears only once (0x26e63a8). There is exactly one Xref, 0xb763aa, in the reader 0xb76330. c_string_and_xref
2 Call chain: idCommonLocal::Init (0xa638b0) → Log "time 20" → fileSystem->Init (vtable+8) → 0xb765f0 (call at 0xa64a2e) → "Executing build.cfg". This occurs before SearchDLC and before idResourceManagerLocal::Init2. At this point, no container has been mounted yet. c_call_chain_and_time, Log Z. 3–23
3 Switch: 0xb765f0 reads only if sys_installToHDD ≠ 0 (Default "1", Help text "if 1, allow streaming install to HDD"). Live value: 1. c_gate
4 Location: ReadJsonFile (0x1217d10) calls fileSystem vtable+0xd0. This is idFileSystemLocal::ReadFile (0x1248630), called with the naked name packagechunklist.json, without a path prefix. For comparison: packagemapspec.json receives a DLC prefix at 0xac5910. The name is resolved against the search path from the log: 1. %USERPROFILE%/Saved Games/MachineGames/Wolfenstein II The New Colossus/base/, 2. <Steam library>/steamapps/common/Wolfenstein.II.The.New.Colossus/base/. The order comes from the log. I did not trace OpenFileReadFlags (0x124d880). c_readjson_is_filesystem, c_log
5 The warning appears twice, but the reader runs only once. The second line merely repeats the first in the block "Warnings during … initialization" ("1 warnings"). c_log

Schema (from the reader 0xb76330)

{"chunks": [{"chunkid": <int>, "packagechunks": [<int>, ...]}]}
  • chunkid is a direct index into an idList with 0x48 bytes per entry. Offset +0 is a bool "valid" (set to 1), Offset +8 is an idList<int> containing the packagechunks. Other keys are ignored.
  • If the file is missing, the table remains empty (live: ptr 0, num 0). There is no built-in default list that could replace the file.
  • chunkid is only checked upwards (cmp/jl against num). A sign check is missing (js/jns do not appear). Therefore, a negative chunkid writes before the table start, potentially corrupting the heap or causing a crash. A huge chunkid triggers a huge allocation.

What Happens to the Content

After reading, 0xb765f0 sets byte 0x2f5d371 to 1. No one reads this byte. Additionally, the function allocates a 1-byte object (0x2f5d378) that is never used except for atexit cleanup. Then it collects all packagechunks without duplicates into a list and immediately frees them again, without any intervening call. The platform hook is stripped from the PC build.

I scanned all RIP-relative accesses to 0x2f5d360..0x2f5d3a0 and decoded the hits linearly with correct width. The table is used thereafter only by these functions:

Function Role Effect
0xb767e0 IsChunkInstalled Predicate Always returns 1. The table serves only for the "invalid chunk" warning, and only when the Manager is active.
0xb76820 / 0xb76cd0 PrioritizeChunk(s) Change order, printf Called only when the Manager is active
0xabf6a0 GetIsChunkForMapInstalled Predicate during map loading Table used only for the "invalid chunk" warning when the Manager is active; result comes from IsChunkInstalled (= 1)
0x1e2c3f0 atexit Free memory
  • Active flag 0x2f5d370: 4 read accesses, all cmp, and 0 writers. Even a wider write access from the neighbor CVar sys_debugGameInstall (up to 0x2f5d36f) does not reach into the flag. The only place holding its address is a reloc'ted .rdata pointer at 0x20abf80, and no code reads it. Live value: 0.
  • All direct calls from these functions go only to JSON-, list-, heap-, and log helpers, or to the Manager functions themselves. Indirect calls are only Free via the allocator 0x4124cc0 and the destructor of the JSON value. No call leads into the Resource Manager or to mounting.

Why this cannot damage Retail Chunks (in case someone uploads the file)

A file with valid, non-negative IDs fills only the sleeping table. No standard list is replaced, no container is touched. Therefore, Retail Chunks do not need to be listed. The only danger is a negative or absurdly large chunkid (see above).

Implication for the Master

The path via packagechunklist.json is closed. DLC chunks continue to be mounted only when loading a map from the DLC (see dlc_primary.md, map_selection.md). For resourceExec in the main menu, the carrier must reside in a container that is already mounted there. I have not investigated this here; see docs/patchvorrang.md.

Optional runtime counter-check (not necessary, refutes this report if it yields differently)

File: re_probes/chunklist/optional_gegenprobe/packagechunklist.json = {"chunks":[{"chunkid":26,"packagechunks":[26]}]}. These are valid IDs, so harmless according to the code. Expectation:

  1. The line ReadJsonFile: could not read file: packagechunklist.json is missing. This confirms the found location.
  2. resourceExec wolfsdk_test.cfg in the main menu continues to fail with can't generate in production. This confirms that nothing is mounted.

If 1 does not occur, the found location is incorrect. If 2 works, the analysis is incorrect.

Tests (each FAILs if the statement is false)

python tools/probe_chunklist.py:

  • c_exe_matches: installed EXE = Snapshot
  • c_string_and_xref: String exists only once, single xref in 0xb76330
  • c_schema: Keys in order chunks/chunkid/packagechunks, Name goes directly to ReadJsonFile, entry 0x48, no sign check
  • c_readjson_is_filesystem: vtable+0xd0 = idFileSystemLocal::ReadFile
  • c_call_chain_and_time: exactly one caller, between FS-init and build.cfg
  • c_gate: Switch sys_installToHDD, live 1
  • c_consumers: complete list of references with positive control, no writer on the active flag, live 0
  • c_is_installed_constant: every return path runs via mov al, 1
  • c_no_mount_calls: List of allowed callees
  • c_log: 1 read access plus 1 repetition in the summary, errors from resourceExec (Log copy re_probes/chunklist/condump_wolfsdk_test3.txt)

Mutation test (manual): Setting ACTIVE to 0x2f5d371, IsChunkInstalled to another function, GATE incorrect, or allocator incorrect will each fail the corresponding test.

Clone this wiki locally