OpenZT2 Reconstruction Dashboard

The outer perimeter of the original Zoo Tycoon 2 binary and the reconstruction's coverage of it — the denominator. Counts from the stripped executable; full tables on the Binary Perimeter.

How the project is structured

Phase 1 Red team — adversarial analysis

The project began as an adversarial reverse-engineering investigation of the retail zt.exe, captured across ~11 sub-phase records. Cursory triage (PE-structure dump, section walk, string extraction) exposed the executable's shape and large runs of human-readable strings that seeded the first focus; radare2 disassembly showed several sections were obfuscated/encrypted, and GDB dynamic analysis recovered the execution flow and identified the packer as Macrovision SafeDisc 4.90.10 (the “SecServ” wrapper family). A legal moratorium then identified the rights-holders — copyright and patents — for SafeDisc (summarized in legal.md) and concluded the investigation could continue.

The protection was fully characterized (see the Byte Range Map): a SafeDisc overlay appended to the PE on disc, a record scanner that carves protected records, unpacking of those records into temporary files (the SecServ ~df394b.tmp and AuthServ ~de37fc.tmp services and the PfdRun.pfd sidecar), and decryption + decompression of the encrypted sections into the true runtime static image. The packing algorithms were reverse-engineered into a freestanding, independent unpacker: AES for the encrypted .text and SecServ .txt/.txt2 sections, PKWARE DCL (implode/explode) and zlib inflate/deflate for compressed payloads, and TEA for the PfdRun.pfd heap-trampoline package.

Five indirection mechanisms were characterized — direct .stxt774 function-pointer obfuscation; .rdata import-slot indirection (call [slot]); heap trampolines built from the PfdRun.pfd sidecar record tables; a cookie-parameterized SecServ dispatcher; and the .stxt table-routed call path. The 11-pronged anti-debug block was neutralized to permit dynamic analysis, and every indirected call was traced from callsite to final API. Each caller was then rewritten to a freestanding resolver installed in a code cave at the back of the .stxt sections (leaving PE record sizes unchanged); an independent import loader and IAT thunk table were reconstructed into the same cave to replace the wrapper's import loading; the wrapper overlay was resected entirely and the PE header pointers rewritten to begin execution directly at the CRT/WinMain entrypoint; finally each callsite was stepped through to reconcile the stack-frame and return contract for every resolver until functionality was restored — yielding the freestanding unwrapped → depeppered → stripped image used for all further analysis.

Prior Art

Before treating the red-team archive as original recovery work, we checked the relevant public reference projects. Zoo-Tycoon-2-Libraries is useful as an archive of decompiled compiled-Lua scenario, UI, photo, and gameplay helper scripts. It preserves script-facing names such as queryObject, BFGManager, BFScenarioMgr, UI_*, and BFAI_* messages, and it helps identify authored scenario logic. It does not recover the native managers behind those calls, the executable wrapper, type registries, vtables, object ownership, runtime message implementations, or the SecServ materialization path; many recovered scripts also retain decompiler gaps.

SafeDiscLoader2 is likewise a helpful SafeDisc-family runtime loader and comparison reference. It provided orientation for version detection, the SecServ/AuthServ naming pattern, temporary service DLLs, and some SafeDisc table-repair idioms. It is not a Zoo Tycoon 2 engine reconstruction and did not supply the ZT2-specific SafeDisc 4.90.10 contract: PfdRun.pfd sidecar semantics, slot/trampoline/.stxt call paths, callsite-by-callsite resolver contracts, stripped import reconstruction, or the BlueFang/Gamebryo class and manager perimeter. These projects were useful landmarks, but they left the deep wrapper and engine architecture to be recovered locally.

Subsequent campaigns used r2ghidra to recover the original BlueFang and Zoo Tycoon 2 classes — from the polymorphic vtables, the register_type global type-getter cache, and constructor/reference topology (MSVC RTTI could not be used: the linker stripped the Complete Object Locators and class-hierarchy descriptors, leaving only 99 type-descriptor strings) — together with inheritance graphs, the type system, the BFXML document model, and per-domain reference indexes. The binary perimeter tracked understanding across the full function and global/static surfaces, and the search space was reduced by de-duplicating polymorphic functions and bounding middleware that did not require decompilation: the NetImmerse/Gamebryo engine identified by NiSystem NetImmerse Version 10.0.1.0, NiAnimation NetImmerse Version 10.0.1.0, NiDX9 NetImmerse Version 10.0.1.0, $NiCollision NetImmerse Version 10.0.1.0, and NiMain NetImmerse Version 10.0.1.0, plus the Lua runtime. All original binary artifacts were then removed, presenting a clean red-team ledger to the green team.

Phase 2 Green team — specification

From that red-team archive — and nothing else — the green team authored the detailed functional specification (specification.md). Working only from the recovered structure (classes, fields, vtable shapes, the type registry, the document model, and the per-domain reference indexes), it describes what each subsystem does — the entity/component model, economy, AI, terrain, UI, scripting, and save formats — as concept models rather than transcribed code. The deliverable is a specification carrying zero content derived from the original implementation, establishing the clean-room boundary that separates analysis from re-implementation.

Phase 3 Blue team — re-implementation

The blue team rebuilds the game from the specification in a different language, target, and paradigm: Rust instead of C++, a 64-bit target instead of 32-bit, a data-oriented ECS architecture instead of the original's polymorphic object graph, and the Bevy engine as the foundation instead of Gamebryo. The Reimplementation Plan covers how the 2008 single-threaded object model is adapted to a parallel, cache-friendly ECS while preserving the game's observable behaviour.

Clean-room project — analysis and re-implementation are kept strictly separated.