#!/usr/bin/env python3 """WRITE to the live guest memory of a running Xenia Canary. The read-side companion is `gmem.py`, and this shares its guest-VA → file-offset table. Canary backs the whole guest address space with one shared-memory file (`/dev/shm/xenia_memory_*`), so a write here lands in the running guest with no debugger and no pause. gpoke.py w32 [...] write big-endian u32s at consecutive VAs gpoke.py r32 [n] read back n big-endian u32s (verify) Values and addresses accept `0x` form. Every write prints the before/after word, because a poke you cannot see is a poke you cannot trust. ⚠️ This mutates a running game. It is a research tool: there is no undo, and a wrong address will corrupt whatever it lands on. Read back before believing. """ import os import struct import sys from gmem import MAP, va_to_off # noqa: F401 (MAP re-exported for callers) def shm_path(): cands = [f"/dev/shm/{n}" for n in os.listdir("/dev/shm") if n.startswith("xenia_memory")] if not cands: raise SystemExit("no /dev/shm/xenia_memory_* — is Canary running?") if len(cands) > 1: raise SystemExit(f"several guest images, refusing to guess: {cands}") return cands[0] def read32(f, va): f.seek(va_to_off(va)) return struct.unpack(">I", f.read(4))[0] def main(): if len(sys.argv) < 3: print(__doc__) return 1 cmd = sys.argv[1] path = shm_path() if cmd == "r32": va = int(sys.argv[2], 0) n = int(sys.argv[3], 0) if len(sys.argv) > 3 else 1 with open(path, "rb") as f: for i in range(n): a = va + 4 * i print(f" {a:#010x} = {read32(f, a):#010x}") return 0 if cmd == "w32": va = int(sys.argv[2], 0) vals = [int(v, 0) for v in sys.argv[3:]] if not vals: print("nothing to write") return 1 with open(path, "r+b") as f: for i, v in enumerate(vals): a = va + 4 * i before = read32(f, a) f.seek(va_to_off(a)) f.write(struct.pack(">I", v)) f.flush() after = read32(f, a) ok = "OK" if after == v else "!! MISMATCH" print(f" {a:#010x}: {before:#010x} -> {after:#010x} {ok}") return 0 print(f"unknown command {cmd!r}") return 1 if __name__ == "__main__": raise SystemExit(main())