# BatmanAC.exe — Wwise Vorbis decoder notes (runtime addresses) Image base 0x400000 (no ASLR). The on-disk exe is SteamStub-packed; `.text` is decrypted at runtime (within ~0.15 s of process start). Static analysis uses the user's memory dump `ArkhamCityModding\Audio\RE\BatmanAC_dump.bin` (a *mapped* image: file offset == RVA). The Ghidra project `BAC` loaded it with raw-file section mapping, so **Ghidra address = runtime + 0xC00 in `.text`** (+0x1E00 in `.data`). All addresses below are runtime. | runtime | Ghidra | what | |---------|--------|------| | 0x010B2340 | 0x010B2F40 | stream codec state machine (reads setup across stream buffers, creates setup) | | 0x010B2C30 | 0x010B3830 | in-memory (bank) codec init | | 0x010B3400 | 0x010B4000 | `GetOrCreateCodecSetup(cache, AkSrcInfo*, ...)`: cache bucket `hash % 31`, key = full hash | | 0x010B347B | 0x010B407B | `mov ebx,[ebp+0x94]` = decode alloc size (user's crash patch site; decryption probe) | | 0x010B351A | 0x010B411A | return from setup parse (`eax`=0 OK) — harness breakpoint | | 0x010B3160 | 0x010B3D60 | per-packet synthesis (mode read as **1 bit**) | | 0x010B3600 | 0x010B4200 | decode loop | | 0x010B48F0 | 0x010B54F0 | mapping inverse | | 0x010B4D10 | 0x010B5910 | `ParseSetupHeader(info, channels, reader, pool)` | | 0x010B5140 | 0x010B5D40 | floor1 unpack | | 0x010B5A60 | 0x010B6660 | residue unpack | | 0x010B46D0 | 0x010B52D0 | mapping unpack | | 0x010B5C00 | 0x010B6800 | residue inverse | | 0x010B6340 | 0x010B6F40 | `_make_decode_table` (user called it WwiseDecodeVorbisToPCM) | | 0x010B66F0 | 0x010B72F0 | codebook unpack (Tremor-lowmem `vorbis_book_unpack`, compact Wwise form) | | 0x0158E748 | (.data) | codebook pointer table, 599 ptrs (598 books + end) | `AkSrcInfo` (arg 2 of GetOrCreate): +0x6C channel mask, +0x78.. AkVorbisInfo copy (+0x94 decode alloc, +0x98 x64 alloc, +0x9C hash, +0xA0/+0xA1 blocksizes, +0xA4 rate). total_frames reads 0 there. Pool: one bump allocator per codec setup, capacity = dwDecodeAllocSize; first 0x30 bytes = setup info; allocation failures return NULL and are not checked -> the old crash (`mov [ebx+eax*2],cx`, ebx=0). The user's patch (double capacity) masked a too-small value produced by Wwise 2011.2.2. ## Harness hooks (ackit/verify/debugger.py, used by `ackit verify --ingame`) - bp 0x010B3400: log hash/alloc of every stream/media setup (`ACKIT_SETUP`). - bp 0x010B351A: log parse result (`ACKIT_PARSE ret=`). - `sxd -c2` on AV: second-chance crash -> `ACKIT_CRASH` + registers + stack. - WinDbg Store path changes on auto-update: cdb is located via `Get-AppxPackage Microsoft.WinDbg`.