Build RE baseline and initial Rust workspace
This commit is contained in:
parent
8d1f280e2e
commit
ffaf155ef0
39 changed files with 5974 additions and 8 deletions
123
docs/README.md
Normal file
123
docs/README.md
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
# RT3 Reverse-Engineering Handbook
|
||||
|
||||
This handbook is the project bootstrap for reverse-engineering and rewriting Railroad Tycoon 3.
|
||||
It is written for future us first: enough structure to resume work quickly, without pretending the
|
||||
project is already mature.
|
||||
|
||||
## Canonical Target
|
||||
|
||||
- Canonical executable: `rt3_wineprefix/drive_c/rt3/RT3.exe` (patch 1.06)
|
||||
- Reference executable: `rt3_wineprefix/drive_c/rt3_105/RT3.exe` (patch 1.05)
|
||||
- Canonical SHA-256: `01b0d2496cddefd80e7e8678930e00b13eb8607dd4960096f527564f02af36d4`
|
||||
- Reference SHA-256: `9e96b0695cb722a700f99c8dce498d34da7235e562b1e275bcc1764f8c9b7eb1`
|
||||
|
||||
## Documents
|
||||
|
||||
- `setup-workstation.md`: toolchain baseline and local environment setup.
|
||||
- `re-workflow.md`: how to analyze the binary, record findings, and export reusable artifacts.
|
||||
- `function-map.md`: canonical schema and conventions for function-by-function mapping.
|
||||
- `control-loop-atlas.md`: curated atlas of top-level loops, gateways, and subsystem handoffs.
|
||||
|
||||
## Repo Conventions
|
||||
|
||||
- `docs/`: stable project guidance and durable design notes.
|
||||
- `tools/py/`: committed Python helpers for analysis and validation.
|
||||
- `artifacts/exports/`: committed derived outputs that can be regenerated.
|
||||
- Local-only state stays untracked: `.venv/`, Ghidra projects, Rizin databases, crash dumps, and other
|
||||
bulky/generated working files.
|
||||
|
||||
## Current Baseline
|
||||
|
||||
The current technical milestone is a repeatable loop-mapping workflow for the 1.06 executable.
|
||||
Before injection work or deep file-format work, we capture:
|
||||
|
||||
- executable hashes and PE metadata
|
||||
- section layout, imports, and notable strings
|
||||
- a starter subsystem inventory plus a control-loop atlas
|
||||
- focused address and string context exports for branch-deepening passes
|
||||
- a reusable CLI RE kit for branch dossiers where the atlas needs deeper grounding
|
||||
- a stable curated function ledger in `artifacts/exports/rt3-1.06/function-map.csv`
|
||||
|
||||
Current coverage is broad enough to support future sessions without rediscovery, especially in:
|
||||
|
||||
- CRT startup and bootstrap handoff
|
||||
- shell frame, layout, presentation, deferred-message, and frontend overlay flow
|
||||
- Multiplayer.win UI, chat, session-event, and transport ownership
|
||||
- map/scenario load and text-export paths
|
||||
- shared support layers such as intrusive queues, vectors, hashed stores, and tracked heaps
|
||||
|
||||
README maintenance rule:
|
||||
|
||||
- Keep this section at subsystem level only.
|
||||
- Do not mirror per-pass function additions here.
|
||||
- Detailed mapping progress belongs in `artifacts/exports/rt3-1.06/function-map.csv` and the derived branch artifacts under `artifacts/exports/rt3-1.06/`.
|
||||
|
||||
Current local tool status:
|
||||
|
||||
- Ghidra is installed at `~/software/ghidra`
|
||||
- `~/software/ghidra/ghidraRun` launches successfully in an interactive shell
|
||||
- Rizin is installed and available on `PATH`
|
||||
- `winedbg` works with `rt3_wineprefix`
|
||||
- RT3 launches under `/opt/wine-stable/bin/wine` when started from `rt3_wineprefix/drive_c/rt3`
|
||||
|
||||
## Next Focus
|
||||
|
||||
The next milestone is breadth first. The highest-value passes are:
|
||||
|
||||
- promote `docs/control-loop-atlas.md` into the primary human-readable artifact for high-level flow
|
||||
- name and connect the major loop roots and gateways for startup, shell/UI, frame or presentation,
|
||||
simulation, map/scenario load, input, save/load, and multiplayer/network
|
||||
- use `export_startup_map.py` and `export_analysis_context.py` to widen breadth around candidate loop
|
||||
dispatchers before doing deep leaf naming
|
||||
- keep the pending-template and multiplayer transport dossiers available, but treat them as targeted
|
||||
deep-dive tools once a missing atlas edge needs branch-specific grounding
|
||||
- stand up the Rust workspace so artifacts can be validated in code and a minimal hook DLL can be
|
||||
built as soon as the 32-bit linker is present
|
||||
|
||||
Regenerate the initial exports with:
|
||||
|
||||
```bash
|
||||
python3 tools/py/collect_pe_artifacts.py \
|
||||
rt3_wineprefix/drive_c/rt3/RT3.exe \
|
||||
artifacts/exports/rt3-1.06
|
||||
```
|
||||
|
||||
Regenerate the startup-focused Ghidra exports with:
|
||||
|
||||
```bash
|
||||
python3 tools/py/export_startup_map.py \
|
||||
rt3_wineprefix/drive_c/rt3/RT3.exe \
|
||||
artifacts/exports/rt3-1.06
|
||||
```
|
||||
|
||||
That default export now walks two roots:
|
||||
|
||||
- `entry:0x005a313b`
|
||||
- `bootstrap:0x00484440`
|
||||
|
||||
For a focused branch-deepening pass, regenerate the analysis context exports with:
|
||||
|
||||
```bash
|
||||
python3 tools/py/export_analysis_context.py \
|
||||
rt3_wineprefix/drive_c/rt3/RT3.exe \
|
||||
artifacts/exports/rt3-1.06 \
|
||||
--addr 0x00444dd0 \
|
||||
--addr 0x00508730 \
|
||||
--addr 0x00508880 \
|
||||
--string gpdLabelDB \
|
||||
--string gpdCityDB \
|
||||
--string 2DLabel.imb \
|
||||
--string 2DCity.imb \
|
||||
--string "Geographic Labels"
|
||||
```
|
||||
|
||||
For the pending-template dispatch-store branch, regenerate the new branch dossier with:
|
||||
|
||||
```bash
|
||||
python3 tools/py/rt3_rekit.py \
|
||||
pending-template-store \
|
||||
rt3_wineprefix/drive_c/rt3/RT3.exe \
|
||||
artifacts/exports/rt3-1.06
|
||||
```
|
||||
|
||||
That dossier is now a targeted follow-up tool, not the default first pass.
|
||||
83
docs/control-loop-atlas.md
Normal file
83
docs/control-loop-atlas.md
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
# Control-Loop Atlas
|
||||
|
||||
This atlas is the high-level map for RT3 1.06. It is intentionally broader than the function map:
|
||||
each section explains who owns a loop, where it starts, what dispatches it, which state blocks
|
||||
anchor it, and where control is handed to neighboring subsystems.
|
||||
|
||||
## CRT and Process Startup
|
||||
|
||||
- Roots: `entry` at `0x005a313b`, CRT helpers in the `0x005a2d..0x005ad4..` range, and `app_bootstrap_main` at `0x00484440`.
|
||||
- Trigger/Cadence: single process startup path before shell or engine services exist.
|
||||
- Key Dispatchers: `startup_init_tls_state`, `startup_init_file_handle_table`, `startup_run_init_callback_table`, `__setenvp`, `startup_build_argv`, `___crtGetEnvironmentStringsA`, then `app_bootstrap_main`.
|
||||
- State Anchors: CRT heap and file-handle tables; process environment and argv storage.
|
||||
- Subsystem Handoffs: exits the generic CRT path at `app_bootstrap_main`, which becomes the first RT3-owned coordinator.
|
||||
- Evidence: `artifacts/exports/rt3-1.06/startup-call-chain.md`, `artifacts/exports/rt3-1.06/function-map.csv`.
|
||||
- Open Questions: exact ownership boundary between compiler CRT shims and the first game-owned bootstrap helper; whether any nontrivial startup callbacks seed game globals before `app_bootstrap_main`.
|
||||
|
||||
## Bootstrap and Shell Service Bring-Up
|
||||
|
||||
- Roots: `app_bootstrap_main` at `0x00484440` and `bootstrap_init_shell_window_services` at `0x004840e0`.
|
||||
- Trigger/Cadence: one-time bootstrap handoff immediately after CRT completion.
|
||||
- Key Dispatchers: `app_bootstrap_main`, `bootstrap_init_shell_window_services`, graphics config load or default-init helpers, runtime capability probes, and early shell service initializers under the `0x004610..0x0053f0..` branch.
|
||||
- State Anchors: shell service bundle rooted at `0x006d4024`, display/runtime globals under `0x006d4024` and `0x006d4030`, host capability flags gathered by `bootstrap_probe_system_profile`.
|
||||
- Subsystem Handoffs: hands control into shell/UI configuration, presentation defaults, and later per-frame shell work.
|
||||
- Evidence: `startup-call-chain.md`, function-map rows for `app_bootstrap_main`, `bootstrap_init_shell_window_services`, `shell_load_graphics_config_or_init_defaults`, `shell_reset_display_runtime_defaults`, and related graphics setup helpers.
|
||||
- Open Questions: where the first persistent main-loop owner object becomes stable; whether `0x0046c230` or one of the unnamed bootstrap children is the shell's first long-lived coordinator.
|
||||
|
||||
## Shell UI Command and Deferred Work Flow
|
||||
|
||||
- Roots: shell callback paths that converge on `shell_dispatch_ui_command` at `0x00464410`.
|
||||
- Trigger/Cadence: event-driven UI command dispatch plus deferred-message queue flushing during shell activity.
|
||||
- Key Dispatchers: `shell_dispatch_ui_command`, `shell_enqueue_deferred_work_message`, `shell_post_deferred_message_type5`, `shell_post_deferred_message_type6`, `shell_enqueue_deferred_message_type4`, `shell_enqueue_deferred_message_type1`.
|
||||
- State Anchors: shell object at `0x0062be68`, queue roots around `[this+0x11369d]`, `[this+0x1136a1]`, and `[this+0x1136a5]`, plus global routing gates at `0x006d4034`.
|
||||
- Subsystem Handoffs: routes into graphics config, scenario-text export, overlay generation, multiplayer UI, and presentation-facing deferred work.
|
||||
- Evidence: function-map shell rows around `0x00464410` and `0x0051f1d0..0x0051f460`.
|
||||
- Open Questions: where the deferred queues are drained in the wider frame loop; whether the shell command dispatcher is also used by hotkeys or only by UI callback tables.
|
||||
|
||||
## Presentation, Overlay, and Frame Timing
|
||||
|
||||
- Roots: shell display runtime setup and the frame-time history path under `shell_update_frame_time_history` at `0x0051fd70`.
|
||||
- Trigger/Cadence: recurring shell or presentation update loop once the window and display runtime are live.
|
||||
- Key Dispatchers: `shell_update_frame_time_history`, `shell_set_gamma_ramp_scalar`, overlay builders such as `shell_queue_single_world_anchor_overlay`, `shell_queue_world_anchor_overlay_list`, and `shell_queue_indexed_world_anchor_marker`.
|
||||
- State Anchors: shell frame history ring at `0x006d403c`, display/runtime state inside the shell block near `[this+0x114282]` and `[this+0x11428a]`, presentation service pointer at `[this+0x0c]`.
|
||||
- Subsystem Handoffs: consumes world/object state for overlays and pushes deferred presentation messages back through shell queues.
|
||||
- Evidence: function-map rows for shell frame history, gamma ramp, world-anchor overlay builders, and graphics runtime helpers.
|
||||
- Open Questions: the exact outer frame pump is still unnamed; simulation cadence and shell presentation cadence may be separate loops that only rendezvous through shared shell state.
|
||||
|
||||
## Map and Scenario Content Load
|
||||
|
||||
- Roots: reference-database setup via `map_bundle_open_reference_databases` at `0x00444dd0`, followed by narrower loaders such as `map_load_geographic_label_database` and `map_load_city_database`.
|
||||
- Trigger/Cadence: map or scenario open paths and scenario-text export commands.
|
||||
- Key Dispatchers: `map_bundle_open_reference_databases`, `map_load_geographic_label_database`, `map_load_city_database`, `scenario_text_export_build_language_file`, `scenario_text_export_report_language_file`, `scenario_text_export_batch_process_maps`.
|
||||
- State Anchors: map bundle state allocated through `0x00530c80`, geography tables rooted at `0x0062b2fc` and `0x0062b268`, shell-side map-selection context.
|
||||
- Subsystem Handoffs: feeds shell preview panels, scenario export tooling, and later gameplay map state.
|
||||
- Evidence: function-map map/scenario rows, analysis-context exports for geographic-label and city database strings.
|
||||
- Open Questions: the main gameplay map-load entrypoint is still broader than the currently grounded reference-database loaders; scenario load versus scenario-text export remain only partially overlapped.
|
||||
|
||||
## Multiplayer Session and Transport Flow
|
||||
|
||||
- Roots: Multiplayer.win session-event callback table around `0x00468de0..0x004691d0`, plus the transport object and pending-template paths around `0x00597880..0x0059caf0`.
|
||||
- Trigger/Cadence: event-driven session callbacks, registered-name updates, and repeated socket I/O service steps.
|
||||
- Key Dispatchers: session-event wrappers for actions `1`, `2`, `4`, `7`, `8`; `multiplayer_transport_text_stream_service_io`; `multiplayer_transport_dispatch_pending_template_node`; `multiplayer_transport_service_pending_template_dispatch_store`.
|
||||
- State Anchors: live session globals at `0x006d40d0`, status latch at `0x006cd974`, pending-template list at `[this+0x550]`, dispatch store at `[this+0x55c]`, text-stream buffers at `[this+0x108]` and `[this+0x114]`.
|
||||
- Subsystem Handoffs: bridges shell/UI status presentation, transport text streams, session state changes, and pending-template completion callbacks.
|
||||
- Evidence: `function-map.csv`, `pending-template-store-management.md`, `pending-template-store-functions.csv`.
|
||||
- Open Questions: unresolved request-id semantics for `1`, `2`, `4`, and `7`; the exact owner loop that repeatedly services transport I/O; and how multiplayer preview data ties back into the shell flow.
|
||||
|
||||
## Input, Save/Load, and Simulation
|
||||
|
||||
- Roots: not yet cleanly named in the current ledger.
|
||||
- Trigger/Cadence: expected recurring gameplay or shell-driven loops, but the current evidence is still indirect.
|
||||
- Key Dispatchers: currently unresolved; nearest grounded hints are `bootstrap_capture_keyboard_state`, filesystem-related strings, and shell pathways that save graphics config rather than gameplay state.
|
||||
- State Anchors: input DLL import `DINPUT8.dll`, save/load path strings under `.\Saved Games\`, and map/scenario globals already observed elsewhere.
|
||||
- Subsystem Handoffs: likely connect shell/UI into gameplay state, but not yet strongly evidenced in committed exports.
|
||||
- Evidence: `binary-summary.json`, `imported-dlls.txt`, `subsystem-inventory.md`, and broad strings in `interesting-strings.txt`.
|
||||
- Open Questions: first real input pump, first gameplay save/load dispatcher, first simulation tick owner, and the exact boundary between shell frame work and gameplay world stepping.
|
||||
|
||||
## Next Mapping Passes
|
||||
|
||||
- Name the first stable owner of the outer shell or presentation loop above the existing frame-history helpers.
|
||||
- Connect the map bundle open path to the broader map/scenario load coordinator instead of only the database leaves.
|
||||
- Identify the owner loop that repeatedly services multiplayer transport I/O and dispatch-store work.
|
||||
- Ground the first real input ingest path and the first gameplay save/load dispatcher.
|
||||
- Keep detailed pending-template or transport work scoped to the specific atlas edges that remain unresolved.
|
||||
75
docs/function-map.md
Normal file
75
docs/function-map.md
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
# Function Map
|
||||
|
||||
The function map is the canonical ledger for reverse-engineering progress. It should be updated even
|
||||
when the understanding is partial, because partial structure is still useful if it is explicit about
|
||||
confidence.
|
||||
|
||||
The handbook index in `docs/README.md` should stay high-level. Per-pass function additions and
|
||||
renames belong here and in the derived export artifacts, not in the README. High-level control-loop
|
||||
and subsystem flow belongs in `docs/control-loop-atlas.md`, with this file staying function-centric.
|
||||
|
||||
## Canonical Schema
|
||||
|
||||
The committed CSV header is:
|
||||
|
||||
```text
|
||||
address,size,name,subsystem,calling_convention,prototype_status,source_tool,confidence,notes,verified_against
|
||||
```
|
||||
|
||||
Field meanings:
|
||||
|
||||
- `address`: virtual address in the canonical 1.06 executable
|
||||
- `size`: best current size in bytes; leave blank if unknown
|
||||
- `name`: current best function name
|
||||
- `subsystem`: coarse ownership bucket such as `startup`, `bootstrap`, `support`, `render`, `audio`, `ui`, `map`, `save`, `network`
|
||||
- `calling_convention`: `cdecl`, `stdcall`, `thiscall`, `fastcall`, or `unknown`
|
||||
- `prototype_status`: `unknown`, `inferred`, or `confirmed`
|
||||
- `source_tool`: primary tool or source behind the current row
|
||||
- `confidence`: integer from `1` to `5`
|
||||
- `notes`: short justification, ambiguity, or follow-up
|
||||
- `verified_against`: hash, runtime trace, second tool, or other corroboration
|
||||
|
||||
## Update Rules
|
||||
|
||||
- New rows must always include `address`, `name`, `subsystem`, `source_tool`, and `confidence`.
|
||||
- If a rename is speculative, state that directly in `notes`.
|
||||
- When two tools disagree on function boundaries, preserve the ambiguity in `notes` instead of hiding it.
|
||||
- Prefer one row per concrete function, not per guessed feature.
|
||||
|
||||
## Starter Subsystems
|
||||
|
||||
Use these buckets until the map needs finer structure:
|
||||
|
||||
- `startup`
|
||||
- `bootstrap`
|
||||
- `shell`
|
||||
- `support`
|
||||
- `ui`
|
||||
- `render`
|
||||
- `audio`
|
||||
- `input`
|
||||
- `network`
|
||||
- `filesystem`
|
||||
- `resource`
|
||||
- `map`
|
||||
- `scenario`
|
||||
- `save`
|
||||
- `simulation`
|
||||
- `unknown`
|
||||
|
||||
## Verification Sources
|
||||
|
||||
Examples for `verified_against`:
|
||||
|
||||
- `sha256:01b0... + objdump`
|
||||
- `ghidra + rizin`
|
||||
- `ghidra + string xref`
|
||||
- `runtime trace under winedbg`
|
||||
|
||||
## Exit Criteria For The Milestone
|
||||
|
||||
The first function-mapping milestone is complete when the repo has:
|
||||
|
||||
- a stable starter map for the canonical binary
|
||||
- named anchors for startup and a few obvious subsystem gateways
|
||||
- enough notes and exports that a future session can continue without rediscovery
|
||||
217
docs/re-workflow.md
Normal file
217
docs/re-workflow.md
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
# Reverse-Engineering Workflow
|
||||
|
||||
## Goal
|
||||
|
||||
Produce durable, version-safe analysis that first explains high-level control loops and subsystem
|
||||
handoffs, then feeds the function-by-function Rust rewrite and later DLL-based replacement work.
|
||||
|
||||
## Standard Loop
|
||||
|
||||
1. Confirm the target binary and record its hash.
|
||||
2. Refresh the exported baseline artifacts.
|
||||
3. Update `docs/control-loop-atlas.md` with newly grounded loop roots, dispatchers, cadence points,
|
||||
state anchors, or subsystem handoffs.
|
||||
4. Analyze in Ghidra.
|
||||
5. Cross-check suspicious findings in Rizin or with CLI tools.
|
||||
6. Update the function map with names, prototypes, ownership, confidence, and loop-relevant notes.
|
||||
7. Commit regenerated exports and notes that would help future sessions.
|
||||
|
||||
## Baseline Export
|
||||
|
||||
Use the committed helper:
|
||||
|
||||
```bash
|
||||
python3 tools/py/collect_pe_artifacts.py \
|
||||
rt3_wineprefix/drive_c/rt3/RT3.exe \
|
||||
artifacts/exports/rt3-1.06
|
||||
```
|
||||
|
||||
This export pass is expected to produce:
|
||||
|
||||
- `binary-summary.json`
|
||||
- `sections.csv`
|
||||
- `imported-dlls.txt`
|
||||
- `imported-functions.csv`
|
||||
- `interesting-strings.txt`
|
||||
- `subsystem-inventory.md`
|
||||
- `function-map.csv`
|
||||
|
||||
For the startup-init milestone, run the Ghidra headless export as well:
|
||||
|
||||
```bash
|
||||
python3 tools/py/export_startup_map.py \
|
||||
rt3_wineprefix/drive_c/rt3/RT3.exe \
|
||||
artifacts/exports/rt3-1.06
|
||||
```
|
||||
|
||||
Optional flags:
|
||||
|
||||
```bash
|
||||
python3 tools/py/export_startup_map.py \
|
||||
rt3_wineprefix/drive_c/rt3/RT3.exe \
|
||||
artifacts/exports/rt3-1.06 \
|
||||
--depth 2 \
|
||||
--root entry:0x005a313b \
|
||||
--root bootstrap:0x00484440
|
||||
```
|
||||
|
||||
This startup pass is expected to add:
|
||||
|
||||
- `ghidra-startup-functions.csv`
|
||||
- `startup-call-chain.md`
|
||||
|
||||
The raw CSV now includes root provenance columns:
|
||||
|
||||
- `root_name`
|
||||
- `root_address`
|
||||
|
||||
## Context Export
|
||||
|
||||
For branch-deepening passes after the initial root mapping, use the committed context exporter:
|
||||
|
||||
```bash
|
||||
python3 tools/py/export_analysis_context.py \
|
||||
rt3_wineprefix/drive_c/rt3/RT3.exe \
|
||||
artifacts/exports/rt3-1.06 \
|
||||
--addr 0x00444dd0 \
|
||||
--addr 0x00508730 \
|
||||
--addr 0x00508880 \
|
||||
--string gpdLabelDB \
|
||||
--string gpdCityDB \
|
||||
--string 2DLabel.imb \
|
||||
--string 2DCity.imb \
|
||||
--string "Geographic Labels"
|
||||
```
|
||||
|
||||
This pass is expected to add:
|
||||
|
||||
- `analysis-context-functions.csv`
|
||||
- `analysis-context-strings.csv`
|
||||
- `analysis-context.md`
|
||||
|
||||
The function CSV captures target function metadata plus caller callee and data-ref summaries.
|
||||
The string CSV captures matched strings plus their code or data xrefs.
|
||||
The Markdown report keeps the human-readable disassembly excerpts that are useful for the next naming pass.
|
||||
|
||||
Use this exporter to close missing edges in the atlas before using it for leaf-function refinement.
|
||||
|
||||
## Branch RE Kit
|
||||
|
||||
For deeper branch work after the atlas identifies a narrow unknown, use the CLI RE kit:
|
||||
|
||||
```bash
|
||||
python3 tools/py/rt3_rekit.py \
|
||||
pending-template-store \
|
||||
rt3_wineprefix/drive_c/rt3/RT3.exe \
|
||||
artifacts/exports/rt3-1.06
|
||||
```
|
||||
|
||||
Optional seed override:
|
||||
|
||||
```bash
|
||||
python3 tools/py/rt3_rekit.py \
|
||||
pending-template-store \
|
||||
rt3_wineprefix/drive_c/rt3/RT3.exe \
|
||||
artifacts/exports/rt3-1.06 \
|
||||
--seed-addr 0x0059c470 \
|
||||
--seed-addr 0x0059c540
|
||||
```
|
||||
|
||||
This pass is expected to add:
|
||||
|
||||
- `pending-template-store-functions.csv`
|
||||
- `pending-template-store-record-kinds.csv`
|
||||
- `pending-template-store-management.md`
|
||||
|
||||
The function CSV captures the seed cluster plus adjacent discovered helpers in the same branch.
|
||||
The record-kinds CSV captures the pending-template dispatch-record destructor switch cases and their
|
||||
inferred payload cleanup shapes.
|
||||
The Markdown dossier groups the branch into lifecycle buckets such as init destroy lookup prune and
|
||||
dispatch.
|
||||
|
||||
This branch dossier is intentionally narrower than the atlas. Reach for it only when the broad
|
||||
loop map is already clear enough that a missing branch blocks the next high-level conclusion.
|
||||
|
||||
## Ghidra Workflow
|
||||
|
||||
- Create a local project for the canonical 1.06 executable.
|
||||
- Name the project after the binary version, not just `RT3`, so address notes stay version-safe.
|
||||
- Import the executable without modifying repo-tracked files.
|
||||
- Treat Ghidra as the primary source for function boundaries, control flow, and decompilation.
|
||||
- Local launcher on this host: `~/software/ghidra/ghidraRun`
|
||||
- Local headless entrypoint on this host: `~/software/ghidra/support/analyzeHeadless`
|
||||
- Headless project state should live under `ghidra_projects/` and remain untracked.
|
||||
- The committed wrapper defaults to the `entry` and `bootstrap` roots but can be pointed at additional roots when a milestone needs it.
|
||||
|
||||
## Rizin Workflow
|
||||
|
||||
Use Rizin as the fast second opinion when you need to:
|
||||
|
||||
- check section layout, entrypoints, and imports from the CLI
|
||||
- confirm function boundaries or calling conventions
|
||||
- script quick address-oriented inspections without reopening the GUI
|
||||
|
||||
## Runtime Debugging
|
||||
|
||||
Static analysis comes first. Use `winedbg` only after the local Wine runtime is confirmed to work with
|
||||
the project prefix and a 32-bit target process. Runtime traces should be recorded back into the
|
||||
function map as corroborating evidence, not treated as a replacement for static exports.
|
||||
|
||||
Current host note:
|
||||
|
||||
- `env WINEPREFIX=/home/jan/projects/rrt/rt3_wineprefix winedbg --help` works.
|
||||
- RT3 launches successfully under `/opt/wine-stable/bin/wine` when the current directory is
|
||||
`rt3_wineprefix/drive_c/rt3`.
|
||||
- Launching from the wrong working directory can make the process exit cleanly because the game expects
|
||||
its relative asset paths to resolve under `C:\\rt3`.
|
||||
|
||||
That means runtime work can proceed, but startup commands should always be recorded with the working
|
||||
directory included.
|
||||
|
||||
## Naming Rules
|
||||
|
||||
- Names should prefer behavior over implementation detail when behavior is known.
|
||||
- If behavior is only partly known, keep a neutral prefix such as `subsystem_` or `unk_`.
|
||||
- Address-derived placeholder names are acceptable, but only as temporary rows.
|
||||
- Every renamed function should keep a short note explaining why the name is justified.
|
||||
- For high-level passes, prioritize names that clarify loop role, ownership, or handoff semantics
|
||||
over names that only describe a local helper's mechanics.
|
||||
|
||||
## Confidence Rules
|
||||
|
||||
- `1`: address exists, purpose unknown
|
||||
- `2`: rough subsystem guess only
|
||||
- `3`: behavior inferred from control flow or strings
|
||||
- `4`: prototype or side effects mostly understood
|
||||
- `5`: confirmed by multiple sources or runtime evidence
|
||||
|
||||
## Export Policy
|
||||
|
||||
Commit exports that are cheap to diff and useful to reuse:
|
||||
|
||||
- JSON, CSV, TXT, and Markdown summaries
|
||||
- function maps and subsystem inventories
|
||||
- small command outputs that anchor a finding
|
||||
- raw startup discovery exports from headless Ghidra
|
||||
|
||||
Keep these local-only:
|
||||
|
||||
- Ghidra projects and caches
|
||||
- repo-local Ghidra runtime state under `.ghidra/`
|
||||
- Rizin databases and ephemeral sessions
|
||||
- temporary dumps and scratch notebooks that have not been curated
|
||||
|
||||
Keep the ownership split explicit:
|
||||
|
||||
- raw Ghidra or Rizin discovery output is derived data
|
||||
- `function-map.csv` is the curated ledger and may intentionally diverge from auto-generated names
|
||||
|
||||
## Exit Criteria For The Broad-Mapping Milestone
|
||||
|
||||
The current breadth-first milestone is complete when the repo has:
|
||||
|
||||
- a stable starter map for the canonical binary
|
||||
- a control-loop atlas covering the major top-level loops and handoff points
|
||||
- named anchors for startup, shell/UI, frame/presentation, simulation, map/load, input, save/load,
|
||||
and multiplayer/network flow
|
||||
- enough notes and exports that a future session can continue without rediscovery
|
||||
138
docs/setup-workstation.md
Normal file
138
docs/setup-workstation.md
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
# Workstation Setup
|
||||
|
||||
This project targets a Linux host with Wine. The current workspace is a Debian unstable machine with
|
||||
`python3`, `cargo`, `wine`, `winedbg`, `gdb`, `objdump`, `llvm-objdump`, `strings`, and Java already
|
||||
present.
|
||||
|
||||
## Current Local State
|
||||
|
||||
- Ghidra install: `~/software/ghidra`
|
||||
- Ghidra launcher: `~/software/ghidra/ghidraRun`
|
||||
- Current Ghidra status: launches successfully in an interactive shell
|
||||
- Rizin binaries: `/usr/local/bin/rizin`, `/usr/local/bin/rz-bin`, `/usr/local/bin/rz-asm`
|
||||
- Project Wine prefix: `rt3_wineprefix/`
|
||||
- Current prefix architecture marker: `win64`
|
||||
- Preferred Wine runtime: `/opt/wine-stable/bin/wine` (`wine-11.0`)
|
||||
- Current runtime status: `winedbg` works with the project prefix and RT3 launches under Wine 11 when
|
||||
started from the install directory
|
||||
|
||||
## Required Baseline
|
||||
|
||||
- Linux host with Wine capable of running the RT3 install in `rt3_wineprefix/`
|
||||
- A Wine setup that can run 32-bit Windows targets through the chosen prefix
|
||||
- Java 21+ for Ghidra
|
||||
- Python 3.13+ with `venv`
|
||||
- Rust toolchain for the long-term rewrite, validation CLI, and hook DLL
|
||||
- Binutils / LLVM CLI tools for quick inspection
|
||||
- 32-bit MinGW linker support for `i686-pc-windows-gnu`
|
||||
|
||||
## Preferred Reverse-Engineering Stack
|
||||
|
||||
- Ghidra as the primary GUI disassembler/decompiler
|
||||
- Rizin as the secondary CLI-first analysis stack
|
||||
- Existing system tools for quick checks: `objdump`, `llvm-objdump`, `strings`, `gdb`, `winedbg`
|
||||
|
||||
## Install Policy
|
||||
|
||||
- Prefer upstream Ghidra releases over distro packages on this host.
|
||||
- Prefer upstream Rizin releases or source builds on this host.
|
||||
- Do not commit tool project databases or local installs into the repo.
|
||||
- Commit only exported analysis outputs that can be regenerated.
|
||||
|
||||
## Local Python Environment
|
||||
|
||||
Create a repo-local virtual environment for committed helper scripts and quick experiments:
|
||||
|
||||
```bash
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
python -V
|
||||
```
|
||||
|
||||
Start stdlib-only when possible. Add a dependency manifest only when a non-stdlib package becomes
|
||||
necessary.
|
||||
|
||||
## Rust Toolchain
|
||||
|
||||
This host uses a user-local Rust install. Source it before running cargo or rustup:
|
||||
|
||||
```bash
|
||||
. ~/.local/share/cargo/env
|
||||
cargo --version
|
||||
rustup target list --installed
|
||||
```
|
||||
|
||||
The workspace expects:
|
||||
|
||||
- `x86_64-unknown-linux-gnu` for host tools such as `rrt-cli`
|
||||
- `i686-pc-windows-gnu` for the `rrt-hook` DLL
|
||||
|
||||
The current missing piece on this host is the 32-bit linker driver. Install `i686-w64-mingw32-gcc`
|
||||
and keep the workspace linker config pointed at that binary.
|
||||
|
||||
## Suggested Host Layout
|
||||
|
||||
- Ghidra install: `~/software/ghidra/`
|
||||
- Rizin install: system package path such as `/usr/local/bin/`
|
||||
- Repo-local Python environment: `.venv/`
|
||||
- Local Ghidra projects: `ghidra_projects/` in the repo root or a sibling workspace
|
||||
|
||||
## Basic Verification
|
||||
|
||||
These commands should work before starting analysis:
|
||||
|
||||
```bash
|
||||
java -version
|
||||
/opt/wine-stable/bin/wine --version
|
||||
objdump --version | head -n 1
|
||||
llvm-objdump --version | head -n 1
|
||||
python3 -m venv --help >/dev/null
|
||||
```
|
||||
|
||||
Rust-specific verification:
|
||||
|
||||
```bash
|
||||
. ~/.local/share/cargo/env
|
||||
cargo test -p rrt-model -p rrt-cli
|
||||
cargo build -p rrt-hook --target i686-pc-windows-gnu
|
||||
```
|
||||
|
||||
If the hook build fails with `linker i686-w64-mingw32-gcc not found`, the Rust target is installed
|
||||
but the MinGW PE32 linker is still missing from the host.
|
||||
|
||||
For the current end-to-end runtime smoke test, use:
|
||||
|
||||
```bash
|
||||
tools/run_hook_smoke_test.sh
|
||||
```
|
||||
|
||||
That script builds the `dinput8.dll` proxy, copies it into the local RT3 install, and launches RT3
|
||||
briefly with `WINEDLLOVERRIDES=dinput8=n,b` so Wine prefers the native proxy before the builtin DLL.
|
||||
|
||||
`winedbg` is now part of the known-good runtime toolchain for this prefix. Verify it with:
|
||||
|
||||
```bash
|
||||
env WINEPREFIX=/home/jan/projects/rrt/rt3_wineprefix winedbg --help
|
||||
```
|
||||
|
||||
## Launch Pattern
|
||||
|
||||
RT3 is sensitive to its working directory because it uses relative paths under `.\Data\`, `.\Maps\`,
|
||||
and `.\Saved Games\`. Launching it from the repo root can make it start and then exit cleanly without
|
||||
showing a usable game window.
|
||||
|
||||
Use this exact pattern:
|
||||
|
||||
```bash
|
||||
cd /home/jan/projects/rrt/rt3_wineprefix/drive_c/rt3
|
||||
WINEPREFIX=/home/jan/projects/rrt/rt3_wineprefix /opt/wine-stable/bin/wine RT3.exe
|
||||
```
|
||||
|
||||
If the game appears to fail immediately, check the working directory before assuming a Wine or wow64
|
||||
regression.
|
||||
|
||||
## Canonical Inputs
|
||||
|
||||
- Analyze `rt3_wineprefix/drive_c/rt3/RT3.exe` by default.
|
||||
- Treat `rt3_wineprefix/drive_c/rt3_105/RT3.exe` as a reference build for later diffs.
|
||||
- Record hashes before trusting any symbol map, address note, or decompilation export.
|
||||
Loading…
Add table
Add a link
Reference in a new issue