Frida workflow¶
Use Frida as a runtime evidence engine and keep Ghidra maps as the source of truth.
Logs become machine-readable facts that we promote into analysis/ghidra/maps/name_map.json
and analysis/ghidra/maps/data_map.json after review.
1) Collect runtime logs¶
Copy the scripts into the VM share C:\share\frida (WSL path /mnt/c/share/frida).
You can override the output directory with CRIMSON_FRIDA_DIR. For grim_hooks.js,
set CRIMSON_FRIDA_CONFIG to point at a different grim_hooks_targets.json.
From WSL, you can sync the current repo scripts into the share:
scripts/frida/grim_hooks.jsscripts/frida/grim_hooks_targets.jsonscripts/frida/crimsonland_probe.jsscripts/frida/menu_logo_pivot_trace.jsscripts/frida/screen_fade_trace.jsscripts/frida/perk_prompt_trace.jsscripts/frida/ui_render_trace.jsscripts/frida/panel_state_resolution_sweep.jsscripts/frida/gameplay_state_capture.jsscripts/frida/gameplay_diff_capture.jsscripts/frida/survival_autoplay.jsscripts/frida/creature_anim_trace.jsscripts/frida/creature_render_trace.jsscripts/frida/fx_queue_render_trace.jsscripts/frida/azk_verify_no_unlock.js
Attach by process name (required; spawn caused empty textures + crash on 2026-01-18):
In a separate terminal (or a second run), attach the probe script:
Menu logo rotation trace (focused, JSONL to menu_logo_pivot_trace.jsonl):
Screen fade trace (UI/fade globals + fullscreen overlay, JSONL to screen_fade_trace.jsonl):
UI render trace (menus/panels/widgets, JSONL to ui_render_trace.jsonl):
Panel-state resolution sweep (issue #165 capture: automatic state forcing + panel/text capture; writes resolution-scoped JSONL):
Just shortcut (Windows VM):
Comprehensive gameplay/state capture (automatic snapshots + write tracing, JSONL to
gameplay_state_capture.jsonl):
Differential gameplay capture (tick-aligned checkpoints + event summaries; writes
gameplay_diff_capture.json plus quest-mode per-stage files
gameplay_diff_capture.quest_<MAJOR>_<MINOR>.json):
Shortcuts: just frida-gameplay-diff-capture (host-mode msgpack capture) or
just frida-gameplay-diff-capture-postpack (file-sink capture + postpack conversion)
Survival autoplay sidecar (manual-run helper that pins control scheme config only;
default is static movement + computer aim, JSONL to survival_autoplay.jsonl):
Shortcut: just frida-survival-autoplay
AlienZooKeeper no-unlock verifier (forces state 0x1a, resets timer to 0x2580, auto-solves board,
and logs a final verdict event to azk_verify_no_unlock.jsonl):
Shortcut: just frida-azk-verify
The UI render trace auto-inserts auto_mark events when it detects a screen/panel change.
You can disable or tune it via:
CRIMSON_UI_TRACE_AUTOMARK=0CRIMSON_UI_TRACE_AUTOMARK_MS=250CRIMSON_UI_TRACE_AUTOMARK_TEXTS=8
Creature animation phase trace (focused, JSONL to creature_anim_trace.jsonl):
Creature render trace (draw calls + alpha for dying creatures, JSONL to creature_render_trace.jsonl):
FX queue bake trace (corpse shadow/color passes into terrain RT, JSONL to fx_queue_render_trace.jsonl):
Just shortcut (Windows VM):
Optional overrides: process=crimsonland.exe, CRIMSON_FRIDA_DIR, and (for scripts with hardcoded addresses) CRIMSON_FRIDA_ADDRS / CRIMSON_FRIDA_LINK_BASE / CRIMSON_FRIDA_MODULE.
Default logs written by the scripts:
C:\share\frida\grim_hits.jsonlC:\share\frida\crimsonland_frida_hits.jsonlC:\share\frida\gameplay_diff_capture.json(if you rangameplay_diff_capture.js)C:\share\frida\gameplay_diff_capture.quest_<MAJOR>_<MINOR>.json(quest-mode runs)C:\share\frida\survival_autoplay.jsonl(if you ransurvival_autoplay.js)C:\share\frida\creature_anim_trace.jsonlC:\share\frida\ui_render_trace.jsonlC:\share\frida\panel_state_resolution_capture_<WIDTH>x<HEIGHT>_<RUNID>.jsonl(if you ranpanel_state_resolution_sweep.js)C:\share\frida\demo_trial_overlay_trace.jsonl(if you randemo_trial_overlay_trace.js)C:\share\frida\demo_idle_threshold_trace.jsonl(if you randemo_idle_threshold_trace.js)C:\share\frida\azk_verify_no_unlock.jsonl(if you ranazk_verify_no_unlock.js)
Panel-state sweep triage shortcut (issue #165):
Outputs:
analysis/frida/panel_state_resolution_capture_summary.jsonanalysis/frida/panel_state_resolution_capture_report.md
2) Copy logs into the repo¶
Store raw logs under analysis/frida/raw/:
mkdir -p analysis/frida/raw
cp /mnt/c/share/frida/grim_hits.jsonl analysis/frida/raw/
cp /mnt/c/share/frida/crimsonland_frida_hits.jsonl analysis/frida/raw/
cp /mnt/c/share/frida/gameplay_state_capture.jsonl analysis/frida/raw/ # optional
cp /mnt/c/share/frida/gameplay_diff_capture.json analysis/frida/raw/ # optional
cp /mnt/c/share/frida/gameplay_diff_capture.quest_*.json analysis/frida/raw/ # optional
cp /mnt/c/share/frida/demo_trial_overlay_trace.jsonl analysis/frida/raw/ # optional
cp /mnt/c/share/frida/demo_idle_threshold_trace.jsonl analysis/frida/raw/ # optional
Shortcut:
3) Reduce logs into evidence¶
Run the reducer to normalize facts + produce summaries:
uv run scripts/frida_reduce.py \
--log analysis/frida/raw/grim_hits.jsonl \
--log analysis/frida/raw/crimsonland_frida_hits.jsonl \
--log analysis/frida/raw/demo_trial_overlay_trace.jsonl \
--log analysis/frida/raw/demo_idle_threshold_trace.jsonl \
--out-dir analysis/frida
Shortcut:
Outputs:
analysis/frida/facts.jsonl— normalized facts (one JSON object per line).analysis/frida/evidence_summary.json— per-function evidence counts.analysis/frida/name_map_candidates.json— suggested rename candidates (review only).analysis/frida/player_unknown_offsets.json— hot unknown player offsets, if tracker ran.analysis/frida/unmapped_calls.json— callsites we couldn’t map to functions.
Optional: validate demo_trial_overlay_trace.jsonl (or the reduced facts.jsonl) against the Python demo trial model:
Note: the validator exits non-zero if the trace captured zero demo_trial_overlay_render events.
Print representative events:
uv run scripts/demo_trial_overlay_validate.py --samples 3 analysis/frida/raw/demo_trial_overlay_trace.jsonl
Shortcut:
Optional: summarize demo_idle_threshold_trace.jsonl (or the reduced facts.jsonl) to get the idle threshold:
Note: the summarizer exits non-zero if the trace captured zero demo_mode_start events (idle threshold unknown).
Include representative JSON lines:
uv run scripts/demo_idle_threshold_summarize.py --print-events analysis/frida/raw/demo_idle_threshold_trace.jsonl
Shortcut:
4) Promote evidence into Ghidra maps¶
Review the summary + candidates, then manually promote good entries into:
analysis/ghidra/maps/name_map.jsonanalysis/ghidra/maps/data_map.json
Rerun headless analysis after updates:
Tips¶
- Diagnostics tooling:
-
Legacy
originalinline diff tools have been replaced by the decoupleddbgtrace suite. Seedocs/frida/differential-playbook.mdfor updated differential parity workflows. -
Keep hooks narrow: use the Grim hot-window or limit targets in
scripts/frida/grim_hooks_targets.jsonwhen tracing draw calls. -
Turn on backtraces only when needed (
CONFIG.includeBacktrace = true). - Use
watchPlayerOffset()in the probe script to chase unknown struct fields.