From 71d294ece16ee2abcd6e7bc054c78978a1ca9aec Mon Sep 17 00:00:00 2001 From: Sylpheed RE agent Date: Wed, 26 Aug 2026 04:37:59 +0000 Subject: [PATCH] re: narrow what the .slb header is -- four things it is not Probed the bytes before the data offset at all four values. Not a length field (no word in the first 64 bytes matches the offset, the RIFF position or the entry size, either endianness). Not a seek table or any ascending index (~50% of consecutive BE word pairs are non-decreasing, i.e. random; all words distinct, none zero). Not zero padding in general (5876 of 7358 have content). Not audio being discarded (offset 0 wins 6 of 7358). High-entropy content whose size is constant per language and subdirectory, with no self-describing length -- which points at a loader that knows the size a priori. Recorded the next step as static PE work rather than another archive pass; the byte-level evidence here is about exhausted. --- docs/re/structures/slb-data-offset.md | 35 ++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/docs/re/structures/slb-data-offset.md b/docs/re/structures/slb-data-offset.md index 087aa687..16fb743a 100644 --- a/docs/re/structures/slb-data-offset.md +++ b/docs/re/structures/slb-data-offset.md @@ -184,9 +184,9 @@ therefore conservative for the population the scan is used on**, not optimistic. ## What this does not settle -* **Why the offset takes those four values**, and what the bytes before it are. - There is no length field in the first 64 bytes — banks open on high-entropy - data — so the offset is derived, not read. +* ❔ **Why the offset takes those four values**, and what the bytes before it + are. This was probed and remains open; what is now ruled out is recorded + below. * **The 28 ties.** The scan cannot separate them and falls back to 1392, which is right for roughly a third of that population and wrong for the rest. @@ -227,3 +227,32 @@ question. readings — an authoring-time allocation that was never trimmed, or deliberate truncation of unused tails — are guesses; nothing here distinguishes them, and the game has not been observed reading one of these banks. + + +## ❔ What the header is — four things it is *not* + +The bytes before the data offset are still unexplained, but the field has been +narrowed. Probing the header of banks at each of the four offsets: + +* **Not a length field.** There is no word in the first 64 bytes equal to the + offset, the offset minus 1392, the `RIFF` position or the entry size, in + either endianness. The offset has to be derived; it is not read. +* **Not a seek table or any ascending index.** Treated as big-endian words, only + about half of consecutive pairs are non-decreasing — which is what random data + gives. Every word is distinct and none is zero, across all four offsets. +* **Not zero padding**, at least not usually: 1 482 of 7 358 banks have an + all-zero header, but **5 876 have content** in it. +* **Not audio being discarded.** Adding 0 to the offset candidates, it wins 6 of + 7 358 — noise. (Recorded above.) + +So it is high-entropy content of a size that is constant per language and +subdirectory, carrying no field that names its own length. That combination +suggests something the *loader* knows the size of a priori rather than something +self-describing. + +**First step if this is picked up again**: find the loader. `SETTINGS.PATH` is +`game:\dat\sound.pak+` and `SETTINGS.PARAM` is `Pj_Silph.xgs`, so there is code +that opens a bank by name and seeks to its data; the constant, or the table it +indexes, should be visible there. That is static PE work +(`/work/*.pe`, offset = VA − 0x82000000), not another pass over the archive — +this page has taken the byte-level evidence about as far as it goes.