- Implemented a Python script to extract data from the EUSECODE.FLX file format. - Defined data structures for candidate entries and extracted chunks using dataclasses. - Added functions to read and parse the FLX table, extract candidate data, and generate human-readable output files. - Included functionality for analyzing extracted data, including generating summaries, descriptors, and event family reports. - Implemented utilities for calculating printable ratios, zero ratios, and identifying text-like data. - Added support for writing various output formats, including JSON, TSV, and Markdown.
7.3 KiB
7.3 KiB
| applyTo |
|---|
| ** |
Crusader Ghidra Workflow
- Active target is the raw full-EXE Ghidra program
CRUSADER-RAW.EXEunless explicitly stated otherwise. - Use Ghidra MCP tools for analysis, decompilation, renaming, comments, and xref work.
- Avoid speculative renames. Prefer names that are supported by one of these:
- verified raw mapping from standalone segment work
- direct string evidence
- clear call/field behavior in decompiler or disassembly
- xref relationships to already-named functions
- When porting names from standalone segment extracts into
CRUSADER-RAW.EXE, use only verified base mappings.
Verified Raw Mapping Rules
seg001raw base =0x6E570seg021raw base =0x87170- Porting formula:
raw_full_exe_flat = verified_segment_base + standalone_segment_relative_offset seg001andseg021both contain a keyboard handler; keep the seg001 name asseg001_input_keyboard_handlerto avoid collision.
Working Method
- Prefer a single decompile call first.
- If the decompiler collapses to thunk-heavy output, use one disassembly lookup to confirm the wrapper or parameter setup.
- When
decompile_functionoutput is too large (>~50KB), the result is written to a temp JSON file thatread_filereturns as empty{}. Usedisassemble_functioninstead — it returns inline assembly directly and is fully navigable for large functions. - Add a short decompiler comment when a rename is mapped from verified notes so the provenance stays visible in Ghidra.
- Keep
crusader_decompilation_notes.mdupdated after each verified batch. That file is now a short index — append new analysis to the appropriate file indocs/and add a row to the index table if a new file is created. - Keep
crusader_segment_coverage_ledger.csvupdated after each verified batch whenever a segment can be promoted or reclassified. - Keep the progress section in
plan-mid.mdupdated after each verified batch so the next pass can resume from the exact stopping point. - Keep
ghidra_mcp_wishlist.mdupdated whenever the workflow hits a missing MCP capability and has to fall back to PyGhidra or another local-only path. - Each wishlist entry should be short and concrete: what MCP lacked, what command/script/tool had to replace it, and what a useful MCP endpoint or behavior would look like.
- Record raw-import addresses alongside original segment-relative offsets when porting names.
- Always use
rename_function_by_address—rename_function(by name) fails with "must have required property 'old_name'" and is broken. Use"function_address": "000c:XXXX"format. - For substantive RE batches, end with at least 6 concrete future steps unless the task is fully closed and there are genuinely fewer defensible next actions.
- When a batch analyzes currently unnamed Ghidra functions and the behavior is clear enough, rename them in Ghidra instead of leaving them as positional
FUN_xxxx_xxxxplaceholders.
PyGhidra Fallback
- Use the local PyGhidra toolkit in
tools/pyghidra_crusaderwhen MCP is missing an operation such as function creation, deletion, or batched scripted edits. - When PyGhidra is needed because MCP lacks a required operation, append a note to
ghidra_mcp_wishlist.mdin the same batch if the gap is not already documented. - The workspace-local Python environment for this toolkit is
.venv-pyghidra311, created fromC:\Users\Maddo\.pyenv\pyenv-win\versions\3.11.6\python.exeand installed from the bundled Ghidra 11.3.2 offline packages. - Default install dir for the toolkit is
I:\Apps\ghidra_11.3.2_PUBLIC. - Invoke the toolkit with
\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader ...from the repo root. - Keep PyGhidra batches small too: prefer one focused repair plan or 1-5 direct edits at a time.
- Write operations require the Ghidra project to open successfully. If
Crusader.lockis present because the GUI owns the project, close Ghidra first or operate on a project copy. - If the workflow needs the user to change Ghidra state, use the ask-questions tool with a yes/no confirmation prompt instead of plain text. Ask the user to close Ghidra before PyGhidra write commands, and ask the user to open the Ghidra project before MCP server commands. The prompt should briefly describe exactly what to do and instruct the user to answer
Yesonly after the action is complete.
Current Verified Raw-Import Ports
0006:e5d0=cursor_update_hoverfrom seg0010x00600008:7377=entity_count_by_type_afrom seg0210x02070007:28ce=shot_entity_allocfrom seg0010x435e0007:2a19=shot_entity_freefrom seg0010x44a90007:2bc9=projectile_init_vectorfrom seg0010x46590007:3001=entity_fire_weaponfrom seg0010x4a910007:3088=fire_weapon_from_cursorfrom seg0010x4b180007:30e8=projectile_check_hitfrom seg0010x4b780007:319e=projectile_step_updatefrom seg0010x4c2e0007:3298=projectile_trace_rayfrom seg0010x4d280007:371d=projectile_update_tickfrom seg0010x51ad0007:4009=projectile_apply_hitfrom seg0010x5a99
Named 000e: Functions (direct analysis — not segment-ported)
Parser Cluster (000e:34xx–38xx)
000e:345e=record_table_init000e:34cc=record_table_destroy000e:35c6=record_table_release_buffer000e:35ef=record_table_next_slot000e:3639=record_table_parse_buffer000e:3798=record_parser_read_line000e:38f8=record_parser_find_marker
RIFF/Animation Cluster (000e:03xx–2xxx)
000e:2a28=riff_find_chunk_by_type(RIFF LIST/RIFF walker; FourCC match at chunk+8)000e:2104=animation_start(finds "movi" chunk, inits timing ring buffer, kicks advance)000e:12f4=animation_advance_frame(fixed-point 0x1000 timer stepper, ring buffer update)000e:103f=animation_tick(guard wrapper — checks +0xd4 != -1, calls advance_frame)000e:06f7=anim_load_audio_frame(checks "01wb" chunk tag 0x62773130, copies audio into ring buffer)
Constructor/Assert Helpers (000e:22xx–29xx)
000e:223d=assert_alive_sentinel(expects +0xd4 == -1; traps on mismatch)000e:2777=animation_ctor_variant_a(alloc + init flags + chained init/assert/finalize)000e:2860=animation_ctor_variant_b(variant A with extra +0x109 init)000e:2969=animation_ctor_variant_c(default static flag profile +0x4c=0xd)
Documentation Structure
Detailed RE notes live in the docs/ folder. crusader_decompilation_notes.md is a short index.
| File | Topic |
|---|---|
docs/overview.md |
Binary overview, address layout, segment map, next steps |
docs/phar-lap-extender.md |
DOS extender functions and string references |
docs/ne-segment1.md |
NE Segment 1: entity system, cheat system, full game logic analysis |
docs/raw-porting-progress.md |
seg091 RNG, 0x4588 callbacks, 0007 gameplay batches, snap_entity_to_ground |
docs/raw-000e.md |
000e parser cluster and RIFF/animation subsystem |
docs/raw-0007-rendering.md |
Draw list, scroll/camera, coordinate transforms, tile visibility |
docs/raw-0008-000c.md |
0008 dispatch helpers and 000c state machine |
docs/raw-000a-000d.md |
Tracked handles, cache manager, seg082 allocator, palette helpers, seg004/005 startup |
docs/far-call-targets.md |
Top-104 far-call targets (Tiers 1–5), supporting functions, analysis gaps |