Port debug scripts to new API
This commit is contained in:
parent
68e428ecc7
commit
86bcc094fa
2
.gitignore
vendored
2
.gitignore
vendored
@ -4,3 +4,5 @@
|
||||
/tools/ackermann.o
|
||||
/tools/venv
|
||||
/tools/*.pdf
|
||||
|
||||
__pycache__
|
||||
|
@ -1,6 +1,6 @@
|
||||
# synacor.py
|
||||
|
||||
My sort-of-OOP, ~~poorly-documented~~concise response to the Synacor challenge
|
||||
My OOP, ~~poorly-documented~~ ~~concise~~ working response to the Synacor challenge
|
||||
|
||||
## Debug commands
|
||||
|
||||
@ -12,15 +12,15 @@ This will execute the file `<cmd>.py` with `dbg_args[0]` set to `<cmd>` and `<ar
|
||||
|
||||
For example, the self-test and decryption at the beginning of the program takes a comparatively long time. To save the state to the `dumps/init` file, enter:
|
||||
|
||||
.dbg_dump dumps/init
|
||||
.dbg/dump dumps/init
|
||||
|
||||
Similarly, debug commands may be passed as command-line arguments to `synacor.py` in the form:
|
||||
|
||||
./synacor.py <cmd> <args>
|
||||
./synacor.py <file> <cmd> <args>
|
||||
|
||||
For example, to load the `dumps/init` state to skip the self-test and decryption, run:
|
||||
|
||||
./synacor.py dbg_load dumps/init
|
||||
./synacor.py challenge.bin dbg/load dumps/init
|
||||
|
||||
Dump files are stored in Python [pickle](https://docs.python.org/3/library/pickle.html) format, so if you want to inspect the memory in a hex editor, for example, it will be necessary to extract a raw memory dump:
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
# synacor.py - An implementation of the Synacor Challenge
|
||||
# Copyright © 2016 RunasSudo
|
||||
# Copyright © 2016–2017 RunasSudo
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
@ -20,10 +20,10 @@ if len(dbg_args) < 2:
|
||||
print('Usage: .{} <file>'.format(dbg_args[0]))
|
||||
else:
|
||||
model = {
|
||||
'SYN_PTR': SYN_PTR,
|
||||
'SYN_MEM': SYN_MEM,
|
||||
'SYN_REG': SYN_REG,
|
||||
'SYN_STK': SYN_STK
|
||||
'SYN_PTR': cpu.SYN_PTR,
|
||||
'SYN_MEM': cpu.SYN_MEM,
|
||||
'SYN_REG': cpu.SYN_REG,
|
||||
'SYN_STK': cpu.SYN_STK
|
||||
}
|
||||
|
||||
with open(dbg_args[1], 'wb') as f:
|
@ -14,4 +14,12 @@
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
DBG_FLAG = True
|
||||
# Emulate 06bb
|
||||
for R1 in range(0x17b4, 0x7562):
|
||||
R0 = cpu.SYN_MEM[R1]
|
||||
R0 ^= pow(R1, 2, 32768)
|
||||
R0 ^= 0x4154
|
||||
cpu.SYN_MEM[R1] = R0
|
||||
|
||||
# Jump past self-test
|
||||
cpu.SYN_PTR = 0x0377
|
@ -1,5 +1,5 @@
|
||||
# synacor.py - An implementation of the Synacor Challenge
|
||||
# Copyright © 2016 RunasSudo
|
||||
# Copyright © 2016–2017 RunasSudo
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
@ -22,7 +22,7 @@ else:
|
||||
with open(dbg_args[1], 'rb') as f:
|
||||
model = pickle.load(f)
|
||||
|
||||
SYN_PTR = model['SYN_PTR']
|
||||
SYN_MEM = model['SYN_MEM']
|
||||
SYN_REG = model['SYN_REG']
|
||||
SYN_STK = model['SYN_STK']
|
||||
cpu.SYN_PTR = model['SYN_PTR']
|
||||
cpu.SYN_MEM = model['SYN_MEM']
|
||||
cpu.SYN_REG = model['SYN_REG']
|
||||
cpu.SYN_STK = model['SYN_STK']
|
@ -97,16 +97,5 @@ take mirror
|
||||
use mirror
|
||||
"""
|
||||
|
||||
# Read code into memory
|
||||
SYN_PTR = 0
|
||||
with open('challenge.bin', 'rb') as data:
|
||||
while True:
|
||||
byteData = data.read(2)
|
||||
if len(byteData) < 2:
|
||||
break
|
||||
SYN_MEM[SYN_PTR] = struct.unpack('<H', byteData)[0]
|
||||
SYN_PTR += 1
|
||||
SYN_PTR = 0
|
||||
|
||||
# We cannot directly set SYN_STDIN_BUF since debug commands are processed only at stdin read
|
||||
sys.stdin = io.StringIO(transcript)
|
@ -1,5 +1,5 @@
|
||||
# synacor.py - An implementation of the Synacor Challenge
|
||||
# Copyright © 2016 RunasSudo
|
||||
# Copyright © 2016–2017 RunasSudo
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
@ -15,9 +15,9 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Set R7 to 6486
|
||||
SYN_REG[7] = 0x6486
|
||||
cpu.SYN_REG[7] = 0x6486
|
||||
|
||||
# Patch instructions 1571 to 1579 inclusive with nop's
|
||||
SYN_MEM[0x1571:0x157a] = [21] * 9
|
||||
cpu.SYN_MEM[0x1571:0x157a] = [21] * 9
|
||||
|
||||
print('Patched. Ready to run "use teleporter".')
|
@ -1,39 +0,0 @@
|
||||
# synacor.py - An implementation of the Synacor Challenge
|
||||
# Copyright © 2017 RunasSudo
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import pickle
|
||||
|
||||
# Read code into memory
|
||||
SYN_MEM = [0] * 32768
|
||||
|
||||
with open('challenge.bin', 'rb') as data:
|
||||
i = 0
|
||||
while True:
|
||||
byteData = data.read(2)
|
||||
if len(byteData) < 2:
|
||||
break
|
||||
SYN_MEM[i] = struct.unpack('<H', byteData)[0]
|
||||
i += 1
|
||||
|
||||
# Emulate 06bb
|
||||
for R1 in range(0x17b4, 0x7562):
|
||||
R0 = SYN_MEM[R1]
|
||||
R0 ^= pow(R1, 2, 32768)
|
||||
R0 ^= 0x4154
|
||||
SYN_MEM[R1] = R0
|
||||
|
||||
# Jump past self-test
|
||||
SYN_PTR = 0x0377
|
@ -196,6 +196,12 @@ class InstructionIn(Instruction):
|
||||
|
||||
while len(cpu.SYN_STDIN_BUF) == 0:
|
||||
line = sys.stdin.readline()
|
||||
if line.startswith('.'):
|
||||
# Debug command
|
||||
dbg_args = line[1:].split()
|
||||
with open(dbg_args[0] + '.py', 'r') as f:
|
||||
exec(f.read(), globals(), locals())
|
||||
else:
|
||||
cpu.SYN_STDIN_BUF = list(line)
|
||||
|
||||
self.args[0].set(cpu, ord(cpu.SYN_STDIN_BUF.pop(0)))
|
||||
|
6
notes.md
6
notes.md
@ -88,7 +88,7 @@ Proceed to the `north` door and `use` the `teleporter` to obtain the code:
|
||||
## The true-believers-only codes
|
||||
At this point, you will almost certainly need to delve into the code of the challenge, if you haven't already. The code in `challenge.bin` past the self-test is encrypted, so disassembling and analysing the code is most easily done based off a memory dump from a running copy:
|
||||
|
||||
.dbg_dump dumps/init (From inside the game)
|
||||
.dbg/dump dumps/init (From inside the game)
|
||||
./tools/dump_to_raw.py dumps/init dumps/init.raw
|
||||
./tools/disasm.py dumps/init.raw > dumps/init.asm
|
||||
|
||||
@ -232,7 +232,7 @@ Running the algorithm, the correct value is revealed to be `0x6486`. Now we simp
|
||||
|
||||
I've implemented this as a debug function to prepare the teleporter:
|
||||
|
||||
> .dbg_teleporter
|
||||
> .dbg/teleporter
|
||||
Patched. Ready to run "use teleporter".
|
||||
> use teleporter
|
||||
|
||||
@ -284,4 +284,4 @@ Given that you've made it this far (You didn't cheat, did you? I did warn you at
|
||||
|
||||
Now that we've solved the puzzle, the only thing left is to write a [tool-assisted speed-run](https://github.com/RunasSudo/synacor.py/blob/master/dbg_speedrun.py) to completely break any given instance of the challenge in 5 seconds.
|
||||
|
||||
time python -u synacor.py dbg_speedrun | head -n 849
|
||||
time python -u synacor.py challenge.bin dbg/speedrun | head -n 849
|
||||
|
@ -23,5 +23,10 @@ cpu = CPU()
|
||||
with open(sys.argv[1], 'rb') as data:
|
||||
cpu.SYN_MEM = memory_from_file(data)
|
||||
|
||||
if len(sys.argv) > 2:
|
||||
dbg_args = sys.argv[2:]
|
||||
with open(dbg_args[0] + '.py', 'r') as f:
|
||||
exec(f.read(), globals(), locals())
|
||||
|
||||
while True:
|
||||
cpu.step()
|
||||
|
Reference in New Issue
Block a user