JavaScript / ES6+ virtual machine for https://challenge.synacor.com.
The architecture spec is bundled in this repository.
See synacor-binja-plugin for a Binary Ninja plugin capable of analyzing Synacor programs.
Install Node.js 12 or higher for your platform.
Install dependencies through npm:
npm installTo run a program (from the programs-folder) in the VM:
npm start programs/alphabet.synbinRather than typing in user input or commands manually, a scenario can be fed
directly via stdin:
cat scenarios/challenge.txt - | npm run start programs/challenge.synbinNote: - is required to ensure the VM does not terminate after the scenario is
exhausted, but rather stays alive and accepts further input.
Whenever the program in the VM is awaiting input or the debugger is interrupted,
commands prefixed with $ are executed as JavaScript code using eval.
Use this to easily inspect and mutate program state:
$ registers
[
25975, 25974, 26006,
0, 101, 0,
0, 0
]
$ address = 0xa0a
2570
For convenience the hex and hexoffset helpers are also available:
$ hexoffset(address)
0xa0a
To dump raw memory for the current program for analysis:
$ dump()
raw memory dumped to: programs/challenge-20200618T223617810Z.synbin
To analyze the official challenge binary and generate a visualization of the
Synacor world to visualizations/synacore-map.dot:
npm run analyze programs/challenge.synbinLocations annotated with '❗️' have special behaviour on entry.
Debuggers like gdb do not support arbitrary architectures like Synacor out of
the box.
However, by piggybacking on the GDB remote protocol and replicating packets
sent back and forth we can trick gdb into happily controlling a Synacor program
whilst running in a JavaScript VM within a Node.js process. 🤯
Features supported:
- Breakpoints (
break) - Control flow (stepping using
stepiandcontinue)
To debug a program and listen for "remote gdb" connections on localhost:31337:
npm run debug programs/alphabet.synbinFire up gdb in a separate shell and attach to the remote target:
(gdb) target remote :31337
Remote debugging using :31337
0x00000000 in ?? ()
(gdb) b *0x2a
Breakpoint 1 at 0x2a
(gdb) stepi
0x00000004 in ?? ()
(gdb) c
Continuing.
Breakpoint 1, 0x0000002a in ?? ()
(gdb) c
Continuing.
Program terminated with signal SIGTERM, Terminated.The debugger allows interrupting a running program by sending Ctrl+C from gdb:
(gdb) c
Continuing.
^C
Program received signal SIGTRAP, Trace/breakpoint trap.
0x00002f44 in ?? ()See synacor-binja-plugin for debugging Synacor programs using Binary Ninja.
To listen on a different host/port use GDB_HOST and GDB_PORT:
GDB_HOST=customhost GDB_PORT=1337 npm run debug programs/alphabet.synbinTo log all GDB remote protocol traffic use GDB_LOG:
GDB_LOG= npm run debug programs/alphabet.synbinTo monitor code changes and re-run programs in the VM during development:
npm run start:dev programs/alphabet.synbinSimilary, for the debugger during development:
npm run debug:dev programs/alphabet.synbin