diff --git a/Makefile.new b/Makefile.new new file mode 100644 index 0000000..e62254f --- /dev/null +++ b/Makefile.new @@ -0,0 +1,56 @@ +# TODO: enforce c99 +# eventually add -Wextra + +# Personal makefile notes: +# '$@' gets replaced with the target name +# '$^' gets replaced with the target's dependencies (to right of target name) +# For more, check out https://youtu.be/G5dNorAoeCM + +# Note: I understand this makefile is not as optimal as it could/should be + +CC = gcc +CFLAGS ?= -Wall -Wpedantic -Wextra -std=c99 +DEBUG = -g -ggdb +ROM = roms/rom.bin +TRACE_SUFFIX = +TARGET = hard + +all: $(TARGET) + +debug: CFLAGS += $(DEBUG) +debug: $(TARGET) + +trace: CFLAGS += $(DEBUG) -DTRACE -lreadline +trace: TRACE_SUFFIX = -trace +trace: $(TARGET) + + +disass: CFLAGS += -DTRACE -lreadline +disass: bin/disass.o bin/vm.o bin/emcalls.o + $(CC) $(CFLAGS) -o bin/$@ $^ + +bin/%.o: src/%.c + $(CC) $(CFLAGS) -o $@ -c $^ + +bin/emcalls.o: +bin/vm.o: +bin/main.o: +bin/disass.o: + +# needs to be run separately +rom: $(ROM) + xxd -i src/$^ > src/$@.h + +rom.bin: src/rom.asm src/zeropage.incbin + ./ass.sh src/rom.asm src/zeropage.incbin + +$(TARGET): bin/main.o bin/vm.o bin/emcalls.o + $(CC) $(CFLAGS) -o bin/$@$(TRACE_SUFFIX) $^ + +clean: + rm -f bin/* +cleano: + rm -f bin/*.o + +.PHONY: all debug trace clean cleano + diff --git a/README.md b/README.md index 14f6857..09516cb 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Build "normal" competition/prod image (default): Build trace image (integrates debugger into the build): `$ make trace` -* Note: in-between making the normal and trace images, one should run `make cleano` to remove previous object files, since they'll differ between normal and trace builds +* Note: in-between making the normal and trace images, one should run `make cleano` to remove previous object files since they'll differ between normal and trace builds Build disassembler: `$ make disass` diff --git a/ctf-challenge-src/main.c b/ctf-challenge-src/main.c new file mode 100644 index 0000000..3202dd7 --- /dev/null +++ b/ctf-challenge-src/main.c @@ -0,0 +1,52 @@ +/* x1phosura 2021 */ + +#include +#include +#include +#include +#include +#include + +#include "vm.h" + +#include "rom.h" // automatically generated from rom.bin by `make` + +char *embedded_msg = "Strings won't save you here...\n"; + + +int main() +{ + char flag_input[21]; + uint8_t *memory = NULL; + struct CPU cpu; + + // believe me, I _really_ tried to put the below calloc() in vm_init() + memory = calloc(RAM_SIZE, sizeof(uint8_t)); + if (memory == NULL) + perror("Failed to allocate memory. Aborting..."); + + // src_rom_bin* comes from "rom.h", generated by make from rom.bin + vm_init(&cpu, memory, src_rom_bin, src_rom_bin_len); + printf("Fill in the rest of the flag: RS{"); + fgets(flag_input, 20, stdin); + flag_input[strcspn(flag_input, "\n")] = 0; // trim trailing newline + + printf("The inputted flag was RS{%s}\n\n", flag_input); + for (uint8_t i = 0; i < strlen(flag_input); ++i) + memory[128+i] = (uint8_t)flag_input[i]; + + #ifdef TRACE + printf("[DEBUG MODE]: Running VM in debugger...\n"); + #endif + vm_run(&cpu, memory); + + uint8_t win = memory[0x30]; // memory test to see if + if (win == 7) // flag was correct + printf("YAY, you got the flag!\n"); + else + printf("Sorry, that's not the flag. Try again!\n"); + + free(memory); + return EXIT_SUCCESS; +} + diff --git a/ctf-challenge-src/rom.asm b/ctf-challenge-src/rom.asm new file mode 100644 index 0000000..0888d40 --- /dev/null +++ b/ctf-challenge-src/rom.asm @@ -0,0 +1,453 @@ +# rom.asm + +# Flag for this challenge: +# B4bys_1st_VMPr0tect + +# Note: as you go deeper in the file, it just gets worse and worse. You can +# see my mental endurance draining to the point of not wanting to think despite +# being forced to because I'm writing really tedious, hardcoded assembly. +# MAJOR lesson learned: if I ever have to write another assembler, I WILL +# add support for labels, as hardcoding EVERY address for every jump/reference +# ended up being even worse than I originally thought. + +# This was the result of 50-60+ hours of hard work (mostly Wednesday-Saturday), +# two all-nighters, and a complete and total rejection of my schoolwork. +# On the schoolwork: let the record show that I learned FAR more writing this +# in a week than I have so far learned in all of my "technical" degree-related +# classes this semester, which I unfortunately suspect will not have changed by +# the time I graduate. + +# program start: 0x0100 +jmp 0x8d01 # jump to main-like function + +##################################################################### +# This subroutine implements the world's sketchiest string reversal +# (using my favorite: self-modifying code!) + +# 0x0103: +push 0x8000 # do push instruction (to be modified) +push 0x0401 # push 1st operand of previous instruction to stack +pushi 0x0100 # push 0x01 to stack +add # add items to stack +dup # duplicate sum +pop 0x0401 # pop one of the sums to overwrite 1st operand of first 'push' +pushi 0x9400 # push 0x94 to top of stack (Note: because of self-modifying + # code, this 94 actually also determines the size of the buffer + # to be copied) +beq 0x2401 # jump ahead to 'pushed' if stack vals are equal +pop 0xffff # dispose at high memory +pop 0xffff # dispose at high memory +jmp 0x0301 # jump back + + +# pushed: (0x0124) +pop 0xffff # dispose at high memory +pop 0xffff # dispose at high memory + + +# current position: 0x012a +pop 0xa010 # do pop instruction (to be modified) +push 0x2b01 # push 1st operand of previous instruction to stack +pushi 0x0100 # push 0x01 to stack +add # add items to stack +dup # duplicate sum +pop 0x2b01 # pop one of the sums to overwrite 1st operand of first 'push' +pushi 0xb400 # push 0xb4 to top of stack (Note: because of self-modifying + # code, this b4 actually also determines the size of the buffer + # to be copied) +# 0x013f +beq 0x4b01 # jump ahead to 'pushed' if stack vals are equal +pop 0xffff # dispose at high memory +pop 0xffff # dispose at high memory +# 0x0148 +jmp 0x2a01 # jump back + +# popped: (0x014b) +pop 0xffff # dispose at high memory +pop 0xffff # dispose at high memory +ret +##################################################################### + + +##################################################################### +# This subroutine simply subtracts 27 from each of the bytes in the +# previously reversed string + +# 0x0154 +push 0xa010 +pushi 0x1b00 # 0x1b = 27dec +sub +pop 0xa010 # pop subtracted value back into zero page +push 0x5501 # push 1st operand of instruction at 0x154 to stack +pushi 0x0100 +add +dup +dup +pop 0x5501 # pop incremented 1st operand back to code +pop 0x5e01 # pop incremented 1st operand back to code +pushi 0xb400 # push 'pointer' (0xb4) to byte after last byte in string +beq 0x8401 # +pop 0xffff +pop 0xffff +jmp 0x5401 +pop 0xffff +pop 0xffff +ret + +# By this point, the reversed, subtracted flag looks like the following: +# e5 59 48 4a 59 15 57 35 32 3b 44 59 58 16 44 58 5e 47 19 27 +# ... and it is located at address 0x10a0 + +##################################################################### + + +##################################################################### +##################################################################### +# main-ish: this pretty calls everything else +0x41 0x41 0x41 +0x42 0x42 0x42 +0x43 0x43 0x43 +0x44 0x44 0x44 +0x45 0x45 0x45 +0x46 0x46 0x46 +0x47 0x47 0x47 +0x48 0x48 0x48 +0x49 0x49 0x49 +# 0x01a8 +nop +# 0x01ab +call 0x0301 +# 0x01ae +call 0x5401 +# 0x01b1 +call 0xba01 +0x61 0x62 0x63 # TODO: replace with call to flag_cmp +halt +# end main-ish +##################################################################### +##################################################################### + + +##################################################################### +# block_setup: +# +# Note: a "block" is a 4-byte section of the overall 20-byte flag (so +# there are 5 blocks in total) +# blocks get placed at 0x08d0, 0x09d0, 0x0ad0, 0x0bd0 + +# 0x01ba +stlr 0x1000 # store link-register at address 0x10 (16) +# 0x01bd +pushi 0x0800 +pushi 0xd000 # stack has 0x08d0 (->buffer) in little-endian (idk) +# 0x01c3 +pop 0x3c02 # write next block address to scramble_block scratchpad +pop 0x3b02 # write next block address to scramble_block scratchpad +push 0xa010 # push block[0] (character) +push 0xa110 # push block[1] (character) +push 0xa210 # push block[2] (character) +push 0xa310 # push block[3] (character) +# 0x01d5 +call 0x3802 # scramble_block: Note: <- need discard 4 pushed vals off stack + +# 0x01d8 +push 0xca01 # modify 1st push instruction +pushi 0x0400 +add +pop 0xca01 + +# 0x01e4 +push 0xcd01 # modify 2nd push instruction +pushi 0x0400 +add +pop 0xcd01 + +# 0x01f0 +push 0xd001 # modify 3rd push instruction +pushi 0x0400 +add +pop 0xd001 + +# 0x01fc +push 0xd301 # modify 4th push instruction +pushi 0x0400 +add +pop 0xd301 + +# 0x0208 +push 0xca01 # get 1st operand of 1st push instruction +pushi 0xb400 # push value to compare it to (1st operand + 20) +beq 0x2602 # if value matches limit, branch, else +pop 0xffff # discard stack byte +pop 0xffff # discard stack byte + +# 0x0217 +push 0xbe01 # get old pointer to flag buffer block +pushi 0x0100 # add new offset +add +pop 0xbe01 # update pointer to flag buffer block (self-modifying code) +jmp 0xba01 # loop back to scramble next block + +# 0x0226 +pop 0xffff # discard stack byte +pop 0xffff # discard stack byte + +# 0x022c +0x69 0x69 0x69 +0x69 0x69 0x69 +ldlr 0x1000 # restore link-register from address 0x10 + # (literally fails, and I'm too lazy to debug it rn) +jmp 0xc802 +##################################################################### + + + +##################################################################### +# scramble_block: takes a 4-byte block on the stack, write it to scratchpad, +# scrambles it somewhat, write scratchpad to place in memory, erase scratchpad +# return +# + +# 0x0238 +jmp 0x4402 # skip ahead (past function scratchpad) + +# 0x023b # scratchpad: +42 42 42 # first two bytes set to pointer to block location in mem +# 0x023e +43 43 43 # first 3 bytes of block +# 0x0241 +44 44 44 # 4th byte of block is first here + +# 0x0244 (I think) +pushi 0x4500 # push 69dec to stack (Nice) +xor +# 0x024a +pop 0x3e02 # written to by block_setup, points to block location in mem +0x77 0x77 0x77 # junk + +# 0x0250 +pop 0x4002 # write "2nd" byte to 3rd block position +pop 0x3f02 # write "3rd" byte to 2nd block position +push 0x3e02 # read 69-XORed value to stack +add +pop 0x4102 # add 69-XORed value to 4th value, write to block + +# 0x025f +jmp 0x7102 # GOTO set_lsb + +# 0x0262: write_block_to_mem +pop 0x0000 # write 1st byte of block +pop 0x0100 # write 2nd byte of block +pop 0x0200 # write 3rd byte of block +pop 0x0300 # write 4th byte of block +# 0x026e +jmp 0xc502 # GOTO END (ret) + +# 0x0271: set_lsb: +0x2f 0x2f 0x2f # junk instruction +# 0x0274 +push 0x3b02 # push MSB of pointer to block location in memory +seti 0x6402 # write MSB to code block that will eventually write to it +seti 0x6702 # write MSB to code block that will eventually write to it +seti 0x6a02 # write MSB to code block that will eventually write to it +seti 0x6d02 # write MSB to code block that will eventually write to it + +# 0x0283 +pop 0xffff + +# 0x0286 +push 0x6302 +push 0x3c02 +add +pop 0x6302 # add offset to block pointer LSB to make new LSB +# 0x0292 +push 0x6602 +push 0x3c02 +add +pop 0x6602 # add offset to block pointer LSB to make new LSB +# 0x029e +push 0x6902 +push 0x3c02 +add +pop 0x6902 # add offset to block pointer LSB to make new LSB +# 0x02aa +push 0x6c02 +push 0x3c02 +add +pop 0x6c02 # add offset to block pointer LSB to make new LSB + +# 0x02b6 +push 0x4102 # push 4th block value to stack +push 0x4002 # push 3rd block value to stack +push 0x3f02 # push 2nd block value to stack +push 0x3e02 # push 1st block value to stack + +# 0x02c2 +jmp 0x6202 # GOTO write_block_to_mem + +# 0x02c5: END +jmp 0xd801 + + + # Oh, the joy of working 80+ hours on writing a difficult CTF + # challenge and staring at bad assembly and tons of hex for + # a third of that time. At this point, it is just "getting it + # to werk!" + +# 0x02c8 +jmp 0xda02 +# 0x02cb +pushi 0x0700 # IMPORTANT!!! +seti 0x3000 # set address 0x30 to the number 7 to indicate correct flag. +# 0x02d1 +0x30 0x30 0x30 # junk NOP +0xee 0x07 0x30 # junk NOP +halt + +push 0xa009 # check second block +pushi 0x7000 +push 0xa109 +pushi 0x1500 +0x30 0x30 0x30 # junk NOP +push 0xa209 +pushi 0x5700 +push 0xa309 +pushi 0xc900 +0x30 0x30 0x30 # junk NOP + +# +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +0x30 0x30 0x30 # junk NOP +0xee 0x07 0x30 # junk NOP +pop 0xffff +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff + +0xee 0x07 0x30 # junk NOP +push 0x700a # check third block +pushi 0x1c00 +push 0x710a +pushi 0x3b00 +push 0x720a +pushi 0x4400 +push 0x730a +pushi 0x4e00 + +# +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +0x30 0x30 0x30 # junk NOP +0xee 0x07 0x30 # junk NOP +pop 0xffff +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff + +push 0xd008 # check first block +pushi 0x0f00 +0xee 0x07 0x30 # junk NOP +push 0xd108 +0x30 0x30 0x30 # junk NOP +pushi 0x5900 +push 0xd208 +pushi 0x4800 +push 0xd308 +pushi 0xf400 + +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff +0xee 0x07 0x30 # junk NOP +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff +0x30 0x30 0x30 # junk NOP +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff +0x30 0x30 0x30 # junk NOP +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff + + + +push 0x100c # check fifth block +pushi 0x6200 +push 0x110c +pushi 0x4700 +0xee 0x07 0x30 # junk NOP +push 0x120c +pushi 0x1900 +0x30 0x30 0x30 # junk NOP +push 0x130c +pushi 0xc000 + +# +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff +bnq 0xd102 # Fail if any two bytes ever not equal +0x30 0x30 0x30 # junk NOP +0x30 0x30 0x30 # junk NOP +0x30 0x30 0x30 # junk NOP +pop 0xffff +pop 0xffff +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +0xee 0x07 0x30 # junk NOP +pop 0xffff +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff + +push 0x400b # check fourth block +pushi 0x1d00 +push 0x410b +pushi 0x1600 +emc 0x0122 +0x30 0x30 0x30 # junk NOP +push 0x420b +pushi 0x4400 +push 0x430b +pushi 0x7500 + +# +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff +0xee 0x07 0x30 # junk NOP +emc 0x3344 +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +0xee 0x07 0x30 # junk NOP +pop 0xffff +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff +0xee 0x07 0x30 # junk NOP +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +0x30 0x30 0x30 # junk NOP +pop 0xffff + +jmp 0xcb02 +push 0xcb02 +0x40 0x77 0x12 # junk NOP +halt +0x30 0x30 0x30 # junk NOP + diff --git a/ctf-challenge-src/rom.h b/ctf-challenge-src/rom.h new file mode 100644 index 0000000..3257723 --- /dev/null +++ b/ctf-challenge-src/rom.h @@ -0,0 +1,97 @@ +unsigned char src_rom_bin[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0x8d, 0x01, 0x01, 0x80, 0x00, 0x01, 0x04, + 0x01, 0x03, 0x01, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, 0x00, 0x02, 0x04, + 0x01, 0x03, 0x94, 0x00, 0x0e, 0x24, 0x01, 0x02, 0xff, 0xff, 0x02, 0xff, + 0xff, 0x0d, 0x03, 0x01, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0x02, 0xa0, + 0x10, 0x01, 0x2b, 0x01, 0x03, 0x01, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x02, 0x2b, 0x01, 0x03, 0xb4, 0x00, 0x0e, 0x4b, 0x01, 0x02, 0xff, + 0xff, 0x02, 0xff, 0xff, 0x0d, 0x2a, 0x01, 0x02, 0xff, 0xff, 0x02, 0xff, + 0xff, 0x0c, 0x00, 0x00, 0x01, 0xa0, 0x10, 0x03, 0x1b, 0x00, 0x09, 0x00, + 0x00, 0x02, 0xa0, 0x10, 0x01, 0x55, 0x01, 0x03, 0x01, 0x00, 0x08, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x07, 0x00, 0x00, 0x02, 0x55, 0x01, 0x02, 0x5e, + 0x01, 0x03, 0xb4, 0x00, 0x0e, 0x84, 0x01, 0x02, 0xff, 0xff, 0x02, 0xff, + 0xff, 0x0d, 0x54, 0x01, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0x0c, 0x00, + 0x00, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x44, 0x44, + 0x44, 0x45, 0x45, 0x45, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x48, 0x48, + 0x48, 0x49, 0x49, 0x49, 0xff, 0x00, 0x00, 0x0b, 0x03, 0x01, 0x0b, 0x54, + 0x01, 0x0b, 0xba, 0x01, 0x61, 0x62, 0x63, 0x00, 0x00, 0x00, 0x05, 0x10, + 0x00, 0x03, 0x08, 0x00, 0x03, 0xd0, 0x00, 0x02, 0x3c, 0x02, 0x02, 0x3b, + 0x02, 0x01, 0xa0, 0x10, 0x01, 0xa1, 0x10, 0x01, 0xa2, 0x10, 0x01, 0xa3, + 0x10, 0x0b, 0x38, 0x02, 0x01, 0xca, 0x01, 0x03, 0x04, 0x00, 0x08, 0x00, + 0x00, 0x02, 0xca, 0x01, 0x01, 0xcd, 0x01, 0x03, 0x04, 0x00, 0x08, 0x00, + 0x00, 0x02, 0xcd, 0x01, 0x01, 0xd0, 0x01, 0x03, 0x04, 0x00, 0x08, 0x00, + 0x00, 0x02, 0xd0, 0x01, 0x01, 0xd3, 0x01, 0x03, 0x04, 0x00, 0x08, 0x00, + 0x00, 0x02, 0xd3, 0x01, 0x01, 0xca, 0x01, 0x03, 0xb4, 0x00, 0x0e, 0x26, + 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0x01, 0xbe, 0x01, 0x03, 0x01, + 0x00, 0x08, 0x00, 0x00, 0x02, 0xbe, 0x01, 0x0d, 0xba, 0x01, 0x02, 0xff, + 0xff, 0x02, 0xff, 0xff, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x04, 0x10, + 0x00, 0x0d, 0xc8, 0x02, 0x0d, 0x44, 0x02, 0x42, 0x42, 0x42, 0x43, 0x43, + 0x43, 0x44, 0x44, 0x44, 0x03, 0x45, 0x00, 0x0a, 0x00, 0x00, 0x02, 0x3e, + 0x02, 0x77, 0x77, 0x77, 0x02, 0x40, 0x02, 0x02, 0x3f, 0x02, 0x01, 0x3e, + 0x02, 0x08, 0x00, 0x00, 0x02, 0x41, 0x02, 0x0d, 0x71, 0x02, 0x02, 0x00, + 0x00, 0x02, 0x01, 0x00, 0x02, 0x02, 0x00, 0x02, 0x03, 0x00, 0x0d, 0xc5, + 0x02, 0x2f, 0x2f, 0x2f, 0x01, 0x3b, 0x02, 0x06, 0x64, 0x02, 0x06, 0x67, + 0x02, 0x06, 0x6a, 0x02, 0x06, 0x6d, 0x02, 0x02, 0xff, 0xff, 0x01, 0x63, + 0x02, 0x01, 0x3c, 0x02, 0x08, 0x00, 0x00, 0x02, 0x63, 0x02, 0x01, 0x66, + 0x02, 0x01, 0x3c, 0x02, 0x08, 0x00, 0x00, 0x02, 0x66, 0x02, 0x01, 0x69, + 0x02, 0x01, 0x3c, 0x02, 0x08, 0x00, 0x00, 0x02, 0x69, 0x02, 0x01, 0x6c, + 0x02, 0x01, 0x3c, 0x02, 0x08, 0x00, 0x00, 0x02, 0x6c, 0x02, 0x01, 0x41, + 0x02, 0x01, 0x40, 0x02, 0x01, 0x3f, 0x02, 0x01, 0x3e, 0x02, 0x0d, 0x62, + 0x02, 0x0d, 0xd8, 0x01, 0x0d, 0xda, 0x02, 0x03, 0x07, 0x00, 0x06, 0x30, + 0x00, 0x30, 0x30, 0x30, 0xee, 0x07, 0x30, 0x00, 0x00, 0x00, 0x01, 0xa0, + 0x09, 0x03, 0x70, 0x00, 0x01, 0xa1, 0x09, 0x03, 0x15, 0x00, 0x30, 0x30, + 0x30, 0x01, 0xa2, 0x09, 0x03, 0x57, 0x00, 0x01, 0xa3, 0x09, 0x03, 0xc9, + 0x00, 0x30, 0x30, 0x30, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, + 0xff, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x30, 0x30, 0x30, 0xee, 0x07, + 0x30, 0x02, 0xff, 0xff, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, + 0xff, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0xee, 0x07, + 0x30, 0x01, 0x70, 0x0a, 0x03, 0x1c, 0x00, 0x01, 0x71, 0x0a, 0x03, 0x3b, + 0x00, 0x01, 0x72, 0x0a, 0x03, 0x44, 0x00, 0x01, 0x73, 0x0a, 0x03, 0x4e, + 0x00, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x30, 0x30, 0x30, 0xee, 0x07, + 0x30, 0x02, 0xff, 0xff, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, + 0xff, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0x0f, 0xd1, + 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0x01, 0xd0, 0x08, 0x03, 0x0f, + 0x00, 0xee, 0x07, 0x30, 0x01, 0xd1, 0x08, 0x30, 0x30, 0x30, 0x03, 0x59, + 0x00, 0x01, 0xd2, 0x08, 0x03, 0x48, 0x00, 0x01, 0xd3, 0x08, 0x03, 0xf4, + 0x00, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0xee, 0x07, + 0x30, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0x30, 0x30, + 0x30, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0x30, 0x30, + 0x30, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0x01, 0x10, + 0x0c, 0x03, 0x62, 0x00, 0x01, 0x11, 0x0c, 0x03, 0x47, 0x00, 0xee, 0x07, + 0x30, 0x01, 0x12, 0x0c, 0x03, 0x19, 0x00, 0x30, 0x30, 0x30, 0x01, 0x13, + 0x0c, 0x03, 0xc0, 0x00, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, + 0xff, 0x0f, 0xd1, 0x02, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0x0f, 0xd1, 0x02, 0x02, 0xff, + 0xff, 0xee, 0x07, 0x30, 0x02, 0xff, 0xff, 0x0f, 0xd1, 0x02, 0x02, 0xff, + 0xff, 0x02, 0xff, 0xff, 0x01, 0x40, 0x0b, 0x03, 0x1d, 0x00, 0x01, 0x41, + 0x0b, 0x03, 0x16, 0x00, 0x10, 0x01, 0x22, 0x30, 0x30, 0x30, 0x01, 0x42, + 0x0b, 0x03, 0x44, 0x00, 0x01, 0x43, 0x0b, 0x03, 0x75, 0x00, 0x0f, 0xd1, + 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0xee, 0x07, 0x30, 0x10, 0x33, + 0x44, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0xee, 0x07, 0x30, 0x02, 0xff, + 0xff, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0xee, 0x07, + 0x30, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x30, 0x30, 0x30, 0x02, 0xff, + 0xff, 0x0d, 0xcb, 0x02, 0x01, 0xcb, 0x02, 0x40, 0x77, 0x12, 0x00, 0x00, + 0x00, 0x30, 0x30, 0x30 +}; +unsigned int src_rom_bin_len = 1120; diff --git a/ctf-challenge-src/zeropage.incbin b/ctf-challenge-src/zeropage.incbin new file mode 100644 index 0000000..b8d9031 --- /dev/null +++ b/ctf-challenge-src/zeropage.incbin @@ -0,0 +1,16 @@ +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 diff --git a/src/emcalls.c b/src/emcalls.c index d97fe5a..80b3bcf 100644 --- a/src/emcalls.c +++ b/src/emcalls.c @@ -3,8 +3,8 @@ analogous to system calls, except since there's no real OS, they're handled directly by the emulator. The basic usage should revolve around adding cases to the emcall switch-case, where each case is a special emcall that calls a function to handle it. This is perhaps the easiest way to plug fancy features -into the emulator itself; basically treat the EMC instruction is like the ioctl -syscall (_now_ I see why ioctl is such a tempting serpent of a syscall to have) +into the emulator itself; basically the EMC instruction is like ioctl (_now_ I +see why ioctl is such a tempting serpent of a syscall to have) x1phosura 2021 */ @@ -19,16 +19,21 @@ void do_emcall(uint8_t emc_args[2]) switch(emc_args[0]) { case 0x00: printf("I'm a zero emcall!\n"); // replace with emcall handler + //char in_byte = getchar(); + // TODO: push inputted byte to system stack + // Note: this will require access to the CPU struct in vm.h break; - case 0x01: - printf("I'm a one emcall!\n"); // replace with emcall handler + case 0x01: // basically 'putchar()' emcall + //printf("I'm a one emcall!\n"); // DEBUG + putchar(emc_args[1]); // write emcall arg to STDOUT + /* Fun idea: implement puts() in my own assembly! */ break; case 0x02: printf("I'm a two emcall!\n"); // replace with emcall handler break; default: + // print attempted emcall (for debugging) printf("EMC: 1st arg: 0x%02x, 2nd arg: 0x%02x\n", emc_args[0], emc_args[1]); } - printf("[DEBUG] TODO: finish (stubbed)\n"); } diff --git a/src/main.c b/src/main.c index 3202dd7..0b8806d 100644 --- a/src/main.c +++ b/src/main.c @@ -11,12 +11,10 @@ #include "rom.h" // automatically generated from rom.bin by `make` -char *embedded_msg = "Strings won't save you here...\n"; - int main() { - char flag_input[21]; + char user_input[64]; uint8_t *memory = NULL; struct CPU cpu; @@ -27,24 +25,21 @@ int main() // src_rom_bin* comes from "rom.h", generated by make from rom.bin vm_init(&cpu, memory, src_rom_bin, src_rom_bin_len); - printf("Fill in the rest of the flag: RS{"); - fgets(flag_input, 20, stdin); - flag_input[strcspn(flag_input, "\n")] = 0; // trim trailing newline + printf("Type in any user input here: "); + fgets(user_input, 63, stdin); + user_input[strcspn(user_input, "\n")] = 0; // trim trailing newline - printf("The inputted flag was RS{%s}\n\n", flag_input); - for (uint8_t i = 0; i < strlen(flag_input); ++i) - memory[128+i] = (uint8_t)flag_input[i]; + //printf("User input: %s\n\n", user_input); + for (uint8_t i = 0; i < strlen(user_input); ++i) + memory[128+i] = (uint8_t)user_input[i]; #ifdef TRACE printf("[DEBUG MODE]: Running VM in debugger...\n"); #endif vm_run(&cpu, memory); - uint8_t win = memory[0x30]; // memory test to see if - if (win == 7) // flag was correct - printf("YAY, you got the flag!\n"); - else - printf("Sorry, that's not the flag. Try again!\n"); + // Note: once the emulator's finished, you can check results by reading + // memory[], which is the emulator's "RAM" free(memory); return EXIT_SUCCESS; diff --git a/src/rom.asm b/src/rom.asm index 0888d40..3f1048f 100644 --- a/src/rom.asm +++ b/src/rom.asm @@ -415,11 +415,13 @@ bnq 0xd102 # Fail if any two bytes ever not equal pop 0xffff pop 0xffff +emc 0x0000 push 0x400b # check fourth block pushi 0x1d00 push 0x410b pushi 0x1600 -emc 0x0122 +emc 0x0141 +emc 0x010a 0x30 0x30 0x30 # junk NOP push 0x420b pushi 0x4400 diff --git a/src/rom.h b/src/rom.h index 3257723..da8f036 100644 --- a/src/rom.h +++ b/src/rom.h @@ -84,14 +84,14 @@ unsigned char src_rom_bin[] = { 0xff, 0x0f, 0xd1, 0x02, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0xee, 0x07, 0x30, 0x02, 0xff, 0xff, 0x0f, 0xd1, 0x02, 0x02, 0xff, - 0xff, 0x02, 0xff, 0xff, 0x01, 0x40, 0x0b, 0x03, 0x1d, 0x00, 0x01, 0x41, - 0x0b, 0x03, 0x16, 0x00, 0x10, 0x01, 0x22, 0x30, 0x30, 0x30, 0x01, 0x42, - 0x0b, 0x03, 0x44, 0x00, 0x01, 0x43, 0x0b, 0x03, 0x75, 0x00, 0x0f, 0xd1, - 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0xee, 0x07, 0x30, 0x10, 0x33, - 0x44, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0xee, 0x07, 0x30, 0x02, 0xff, - 0xff, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0xee, 0x07, - 0x30, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x30, 0x30, 0x30, 0x02, 0xff, - 0xff, 0x0d, 0xcb, 0x02, 0x01, 0xcb, 0x02, 0x40, 0x77, 0x12, 0x00, 0x00, - 0x00, 0x30, 0x30, 0x30 + 0xff, 0x02, 0xff, 0xff, 0x10, 0x00, 0x00, 0x01, 0x40, 0x0b, 0x03, 0x1d, + 0x00, 0x01, 0x41, 0x0b, 0x03, 0x16, 0x00, 0x10, 0x01, 0x41, 0x10, 0x01, + 0x0a, 0x30, 0x30, 0x30, 0x01, 0x42, 0x0b, 0x03, 0x44, 0x00, 0x01, 0x43, + 0x0b, 0x03, 0x75, 0x00, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, + 0xff, 0xee, 0x07, 0x30, 0x10, 0x33, 0x44, 0x0f, 0xd1, 0x02, 0x02, 0xff, + 0xff, 0xee, 0x07, 0x30, 0x02, 0xff, 0xff, 0x0f, 0xd1, 0x02, 0x02, 0xff, + 0xff, 0x02, 0xff, 0xff, 0xee, 0x07, 0x30, 0x0f, 0xd1, 0x02, 0x02, 0xff, + 0xff, 0x30, 0x30, 0x30, 0x02, 0xff, 0xff, 0x0d, 0xcb, 0x02, 0x01, 0xcb, + 0x02, 0x40, 0x77, 0x12, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30 }; -unsigned int src_rom_bin_len = 1120; +unsigned int src_rom_bin_len = 1126; diff --git a/src/roms/rom.asm b/src/roms/rom.asm new file mode 100644 index 0000000..0888d40 --- /dev/null +++ b/src/roms/rom.asm @@ -0,0 +1,453 @@ +# rom.asm + +# Flag for this challenge: +# B4bys_1st_VMPr0tect + +# Note: as you go deeper in the file, it just gets worse and worse. You can +# see my mental endurance draining to the point of not wanting to think despite +# being forced to because I'm writing really tedious, hardcoded assembly. +# MAJOR lesson learned: if I ever have to write another assembler, I WILL +# add support for labels, as hardcoding EVERY address for every jump/reference +# ended up being even worse than I originally thought. + +# This was the result of 50-60+ hours of hard work (mostly Wednesday-Saturday), +# two all-nighters, and a complete and total rejection of my schoolwork. +# On the schoolwork: let the record show that I learned FAR more writing this +# in a week than I have so far learned in all of my "technical" degree-related +# classes this semester, which I unfortunately suspect will not have changed by +# the time I graduate. + +# program start: 0x0100 +jmp 0x8d01 # jump to main-like function + +##################################################################### +# This subroutine implements the world's sketchiest string reversal +# (using my favorite: self-modifying code!) + +# 0x0103: +push 0x8000 # do push instruction (to be modified) +push 0x0401 # push 1st operand of previous instruction to stack +pushi 0x0100 # push 0x01 to stack +add # add items to stack +dup # duplicate sum +pop 0x0401 # pop one of the sums to overwrite 1st operand of first 'push' +pushi 0x9400 # push 0x94 to top of stack (Note: because of self-modifying + # code, this 94 actually also determines the size of the buffer + # to be copied) +beq 0x2401 # jump ahead to 'pushed' if stack vals are equal +pop 0xffff # dispose at high memory +pop 0xffff # dispose at high memory +jmp 0x0301 # jump back + + +# pushed: (0x0124) +pop 0xffff # dispose at high memory +pop 0xffff # dispose at high memory + + +# current position: 0x012a +pop 0xa010 # do pop instruction (to be modified) +push 0x2b01 # push 1st operand of previous instruction to stack +pushi 0x0100 # push 0x01 to stack +add # add items to stack +dup # duplicate sum +pop 0x2b01 # pop one of the sums to overwrite 1st operand of first 'push' +pushi 0xb400 # push 0xb4 to top of stack (Note: because of self-modifying + # code, this b4 actually also determines the size of the buffer + # to be copied) +# 0x013f +beq 0x4b01 # jump ahead to 'pushed' if stack vals are equal +pop 0xffff # dispose at high memory +pop 0xffff # dispose at high memory +# 0x0148 +jmp 0x2a01 # jump back + +# popped: (0x014b) +pop 0xffff # dispose at high memory +pop 0xffff # dispose at high memory +ret +##################################################################### + + +##################################################################### +# This subroutine simply subtracts 27 from each of the bytes in the +# previously reversed string + +# 0x0154 +push 0xa010 +pushi 0x1b00 # 0x1b = 27dec +sub +pop 0xa010 # pop subtracted value back into zero page +push 0x5501 # push 1st operand of instruction at 0x154 to stack +pushi 0x0100 +add +dup +dup +pop 0x5501 # pop incremented 1st operand back to code +pop 0x5e01 # pop incremented 1st operand back to code +pushi 0xb400 # push 'pointer' (0xb4) to byte after last byte in string +beq 0x8401 # +pop 0xffff +pop 0xffff +jmp 0x5401 +pop 0xffff +pop 0xffff +ret + +# By this point, the reversed, subtracted flag looks like the following: +# e5 59 48 4a 59 15 57 35 32 3b 44 59 58 16 44 58 5e 47 19 27 +# ... and it is located at address 0x10a0 + +##################################################################### + + +##################################################################### +##################################################################### +# main-ish: this pretty calls everything else +0x41 0x41 0x41 +0x42 0x42 0x42 +0x43 0x43 0x43 +0x44 0x44 0x44 +0x45 0x45 0x45 +0x46 0x46 0x46 +0x47 0x47 0x47 +0x48 0x48 0x48 +0x49 0x49 0x49 +# 0x01a8 +nop +# 0x01ab +call 0x0301 +# 0x01ae +call 0x5401 +# 0x01b1 +call 0xba01 +0x61 0x62 0x63 # TODO: replace with call to flag_cmp +halt +# end main-ish +##################################################################### +##################################################################### + + +##################################################################### +# block_setup: +# +# Note: a "block" is a 4-byte section of the overall 20-byte flag (so +# there are 5 blocks in total) +# blocks get placed at 0x08d0, 0x09d0, 0x0ad0, 0x0bd0 + +# 0x01ba +stlr 0x1000 # store link-register at address 0x10 (16) +# 0x01bd +pushi 0x0800 +pushi 0xd000 # stack has 0x08d0 (->buffer) in little-endian (idk) +# 0x01c3 +pop 0x3c02 # write next block address to scramble_block scratchpad +pop 0x3b02 # write next block address to scramble_block scratchpad +push 0xa010 # push block[0] (character) +push 0xa110 # push block[1] (character) +push 0xa210 # push block[2] (character) +push 0xa310 # push block[3] (character) +# 0x01d5 +call 0x3802 # scramble_block: Note: <- need discard 4 pushed vals off stack + +# 0x01d8 +push 0xca01 # modify 1st push instruction +pushi 0x0400 +add +pop 0xca01 + +# 0x01e4 +push 0xcd01 # modify 2nd push instruction +pushi 0x0400 +add +pop 0xcd01 + +# 0x01f0 +push 0xd001 # modify 3rd push instruction +pushi 0x0400 +add +pop 0xd001 + +# 0x01fc +push 0xd301 # modify 4th push instruction +pushi 0x0400 +add +pop 0xd301 + +# 0x0208 +push 0xca01 # get 1st operand of 1st push instruction +pushi 0xb400 # push value to compare it to (1st operand + 20) +beq 0x2602 # if value matches limit, branch, else +pop 0xffff # discard stack byte +pop 0xffff # discard stack byte + +# 0x0217 +push 0xbe01 # get old pointer to flag buffer block +pushi 0x0100 # add new offset +add +pop 0xbe01 # update pointer to flag buffer block (self-modifying code) +jmp 0xba01 # loop back to scramble next block + +# 0x0226 +pop 0xffff # discard stack byte +pop 0xffff # discard stack byte + +# 0x022c +0x69 0x69 0x69 +0x69 0x69 0x69 +ldlr 0x1000 # restore link-register from address 0x10 + # (literally fails, and I'm too lazy to debug it rn) +jmp 0xc802 +##################################################################### + + + +##################################################################### +# scramble_block: takes a 4-byte block on the stack, write it to scratchpad, +# scrambles it somewhat, write scratchpad to place in memory, erase scratchpad +# return +# + +# 0x0238 +jmp 0x4402 # skip ahead (past function scratchpad) + +# 0x023b # scratchpad: +42 42 42 # first two bytes set to pointer to block location in mem +# 0x023e +43 43 43 # first 3 bytes of block +# 0x0241 +44 44 44 # 4th byte of block is first here + +# 0x0244 (I think) +pushi 0x4500 # push 69dec to stack (Nice) +xor +# 0x024a +pop 0x3e02 # written to by block_setup, points to block location in mem +0x77 0x77 0x77 # junk + +# 0x0250 +pop 0x4002 # write "2nd" byte to 3rd block position +pop 0x3f02 # write "3rd" byte to 2nd block position +push 0x3e02 # read 69-XORed value to stack +add +pop 0x4102 # add 69-XORed value to 4th value, write to block + +# 0x025f +jmp 0x7102 # GOTO set_lsb + +# 0x0262: write_block_to_mem +pop 0x0000 # write 1st byte of block +pop 0x0100 # write 2nd byte of block +pop 0x0200 # write 3rd byte of block +pop 0x0300 # write 4th byte of block +# 0x026e +jmp 0xc502 # GOTO END (ret) + +# 0x0271: set_lsb: +0x2f 0x2f 0x2f # junk instruction +# 0x0274 +push 0x3b02 # push MSB of pointer to block location in memory +seti 0x6402 # write MSB to code block that will eventually write to it +seti 0x6702 # write MSB to code block that will eventually write to it +seti 0x6a02 # write MSB to code block that will eventually write to it +seti 0x6d02 # write MSB to code block that will eventually write to it + +# 0x0283 +pop 0xffff + +# 0x0286 +push 0x6302 +push 0x3c02 +add +pop 0x6302 # add offset to block pointer LSB to make new LSB +# 0x0292 +push 0x6602 +push 0x3c02 +add +pop 0x6602 # add offset to block pointer LSB to make new LSB +# 0x029e +push 0x6902 +push 0x3c02 +add +pop 0x6902 # add offset to block pointer LSB to make new LSB +# 0x02aa +push 0x6c02 +push 0x3c02 +add +pop 0x6c02 # add offset to block pointer LSB to make new LSB + +# 0x02b6 +push 0x4102 # push 4th block value to stack +push 0x4002 # push 3rd block value to stack +push 0x3f02 # push 2nd block value to stack +push 0x3e02 # push 1st block value to stack + +# 0x02c2 +jmp 0x6202 # GOTO write_block_to_mem + +# 0x02c5: END +jmp 0xd801 + + + # Oh, the joy of working 80+ hours on writing a difficult CTF + # challenge and staring at bad assembly and tons of hex for + # a third of that time. At this point, it is just "getting it + # to werk!" + +# 0x02c8 +jmp 0xda02 +# 0x02cb +pushi 0x0700 # IMPORTANT!!! +seti 0x3000 # set address 0x30 to the number 7 to indicate correct flag. +# 0x02d1 +0x30 0x30 0x30 # junk NOP +0xee 0x07 0x30 # junk NOP +halt + +push 0xa009 # check second block +pushi 0x7000 +push 0xa109 +pushi 0x1500 +0x30 0x30 0x30 # junk NOP +push 0xa209 +pushi 0x5700 +push 0xa309 +pushi 0xc900 +0x30 0x30 0x30 # junk NOP + +# +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +0x30 0x30 0x30 # junk NOP +0xee 0x07 0x30 # junk NOP +pop 0xffff +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff + +0xee 0x07 0x30 # junk NOP +push 0x700a # check third block +pushi 0x1c00 +push 0x710a +pushi 0x3b00 +push 0x720a +pushi 0x4400 +push 0x730a +pushi 0x4e00 + +# +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +0x30 0x30 0x30 # junk NOP +0xee 0x07 0x30 # junk NOP +pop 0xffff +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff + +push 0xd008 # check first block +pushi 0x0f00 +0xee 0x07 0x30 # junk NOP +push 0xd108 +0x30 0x30 0x30 # junk NOP +pushi 0x5900 +push 0xd208 +pushi 0x4800 +push 0xd308 +pushi 0xf400 + +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff +0xee 0x07 0x30 # junk NOP +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff +0x30 0x30 0x30 # junk NOP +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff +0x30 0x30 0x30 # junk NOP +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff + + + +push 0x100c # check fifth block +pushi 0x6200 +push 0x110c +pushi 0x4700 +0xee 0x07 0x30 # junk NOP +push 0x120c +pushi 0x1900 +0x30 0x30 0x30 # junk NOP +push 0x130c +pushi 0xc000 + +# +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff +bnq 0xd102 # Fail if any two bytes ever not equal +0x30 0x30 0x30 # junk NOP +0x30 0x30 0x30 # junk NOP +0x30 0x30 0x30 # junk NOP +pop 0xffff +pop 0xffff +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +0xee 0x07 0x30 # junk NOP +pop 0xffff +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff + +push 0x400b # check fourth block +pushi 0x1d00 +push 0x410b +pushi 0x1600 +emc 0x0122 +0x30 0x30 0x30 # junk NOP +push 0x420b +pushi 0x4400 +push 0x430b +pushi 0x7500 + +# +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff +0xee 0x07 0x30 # junk NOP +emc 0x3344 +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +0xee 0x07 0x30 # junk NOP +pop 0xffff +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +pop 0xffff +0xee 0x07 0x30 # junk NOP +bnq 0xd102 # Fail if any two bytes ever not equal +pop 0xffff +0x30 0x30 0x30 # junk NOP +pop 0xffff + +jmp 0xcb02 +push 0xcb02 +0x40 0x77 0x12 # junk NOP +halt +0x30 0x30 0x30 # junk NOP + diff --git a/src/roms/rom.h b/src/roms/rom.h new file mode 100644 index 0000000..3257723 --- /dev/null +++ b/src/roms/rom.h @@ -0,0 +1,97 @@ +unsigned char src_rom_bin[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0x8d, 0x01, 0x01, 0x80, 0x00, 0x01, 0x04, + 0x01, 0x03, 0x01, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, 0x00, 0x02, 0x04, + 0x01, 0x03, 0x94, 0x00, 0x0e, 0x24, 0x01, 0x02, 0xff, 0xff, 0x02, 0xff, + 0xff, 0x0d, 0x03, 0x01, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0x02, 0xa0, + 0x10, 0x01, 0x2b, 0x01, 0x03, 0x01, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x02, 0x2b, 0x01, 0x03, 0xb4, 0x00, 0x0e, 0x4b, 0x01, 0x02, 0xff, + 0xff, 0x02, 0xff, 0xff, 0x0d, 0x2a, 0x01, 0x02, 0xff, 0xff, 0x02, 0xff, + 0xff, 0x0c, 0x00, 0x00, 0x01, 0xa0, 0x10, 0x03, 0x1b, 0x00, 0x09, 0x00, + 0x00, 0x02, 0xa0, 0x10, 0x01, 0x55, 0x01, 0x03, 0x01, 0x00, 0x08, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x07, 0x00, 0x00, 0x02, 0x55, 0x01, 0x02, 0x5e, + 0x01, 0x03, 0xb4, 0x00, 0x0e, 0x84, 0x01, 0x02, 0xff, 0xff, 0x02, 0xff, + 0xff, 0x0d, 0x54, 0x01, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0x0c, 0x00, + 0x00, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x44, 0x44, + 0x44, 0x45, 0x45, 0x45, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x48, 0x48, + 0x48, 0x49, 0x49, 0x49, 0xff, 0x00, 0x00, 0x0b, 0x03, 0x01, 0x0b, 0x54, + 0x01, 0x0b, 0xba, 0x01, 0x61, 0x62, 0x63, 0x00, 0x00, 0x00, 0x05, 0x10, + 0x00, 0x03, 0x08, 0x00, 0x03, 0xd0, 0x00, 0x02, 0x3c, 0x02, 0x02, 0x3b, + 0x02, 0x01, 0xa0, 0x10, 0x01, 0xa1, 0x10, 0x01, 0xa2, 0x10, 0x01, 0xa3, + 0x10, 0x0b, 0x38, 0x02, 0x01, 0xca, 0x01, 0x03, 0x04, 0x00, 0x08, 0x00, + 0x00, 0x02, 0xca, 0x01, 0x01, 0xcd, 0x01, 0x03, 0x04, 0x00, 0x08, 0x00, + 0x00, 0x02, 0xcd, 0x01, 0x01, 0xd0, 0x01, 0x03, 0x04, 0x00, 0x08, 0x00, + 0x00, 0x02, 0xd0, 0x01, 0x01, 0xd3, 0x01, 0x03, 0x04, 0x00, 0x08, 0x00, + 0x00, 0x02, 0xd3, 0x01, 0x01, 0xca, 0x01, 0x03, 0xb4, 0x00, 0x0e, 0x26, + 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0x01, 0xbe, 0x01, 0x03, 0x01, + 0x00, 0x08, 0x00, 0x00, 0x02, 0xbe, 0x01, 0x0d, 0xba, 0x01, 0x02, 0xff, + 0xff, 0x02, 0xff, 0xff, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x04, 0x10, + 0x00, 0x0d, 0xc8, 0x02, 0x0d, 0x44, 0x02, 0x42, 0x42, 0x42, 0x43, 0x43, + 0x43, 0x44, 0x44, 0x44, 0x03, 0x45, 0x00, 0x0a, 0x00, 0x00, 0x02, 0x3e, + 0x02, 0x77, 0x77, 0x77, 0x02, 0x40, 0x02, 0x02, 0x3f, 0x02, 0x01, 0x3e, + 0x02, 0x08, 0x00, 0x00, 0x02, 0x41, 0x02, 0x0d, 0x71, 0x02, 0x02, 0x00, + 0x00, 0x02, 0x01, 0x00, 0x02, 0x02, 0x00, 0x02, 0x03, 0x00, 0x0d, 0xc5, + 0x02, 0x2f, 0x2f, 0x2f, 0x01, 0x3b, 0x02, 0x06, 0x64, 0x02, 0x06, 0x67, + 0x02, 0x06, 0x6a, 0x02, 0x06, 0x6d, 0x02, 0x02, 0xff, 0xff, 0x01, 0x63, + 0x02, 0x01, 0x3c, 0x02, 0x08, 0x00, 0x00, 0x02, 0x63, 0x02, 0x01, 0x66, + 0x02, 0x01, 0x3c, 0x02, 0x08, 0x00, 0x00, 0x02, 0x66, 0x02, 0x01, 0x69, + 0x02, 0x01, 0x3c, 0x02, 0x08, 0x00, 0x00, 0x02, 0x69, 0x02, 0x01, 0x6c, + 0x02, 0x01, 0x3c, 0x02, 0x08, 0x00, 0x00, 0x02, 0x6c, 0x02, 0x01, 0x41, + 0x02, 0x01, 0x40, 0x02, 0x01, 0x3f, 0x02, 0x01, 0x3e, 0x02, 0x0d, 0x62, + 0x02, 0x0d, 0xd8, 0x01, 0x0d, 0xda, 0x02, 0x03, 0x07, 0x00, 0x06, 0x30, + 0x00, 0x30, 0x30, 0x30, 0xee, 0x07, 0x30, 0x00, 0x00, 0x00, 0x01, 0xa0, + 0x09, 0x03, 0x70, 0x00, 0x01, 0xa1, 0x09, 0x03, 0x15, 0x00, 0x30, 0x30, + 0x30, 0x01, 0xa2, 0x09, 0x03, 0x57, 0x00, 0x01, 0xa3, 0x09, 0x03, 0xc9, + 0x00, 0x30, 0x30, 0x30, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, + 0xff, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x30, 0x30, 0x30, 0xee, 0x07, + 0x30, 0x02, 0xff, 0xff, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, + 0xff, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0xee, 0x07, + 0x30, 0x01, 0x70, 0x0a, 0x03, 0x1c, 0x00, 0x01, 0x71, 0x0a, 0x03, 0x3b, + 0x00, 0x01, 0x72, 0x0a, 0x03, 0x44, 0x00, 0x01, 0x73, 0x0a, 0x03, 0x4e, + 0x00, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x30, 0x30, 0x30, 0xee, 0x07, + 0x30, 0x02, 0xff, 0xff, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, + 0xff, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0x0f, 0xd1, + 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0x01, 0xd0, 0x08, 0x03, 0x0f, + 0x00, 0xee, 0x07, 0x30, 0x01, 0xd1, 0x08, 0x30, 0x30, 0x30, 0x03, 0x59, + 0x00, 0x01, 0xd2, 0x08, 0x03, 0x48, 0x00, 0x01, 0xd3, 0x08, 0x03, 0xf4, + 0x00, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0xee, 0x07, + 0x30, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0x30, 0x30, + 0x30, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0x30, 0x30, + 0x30, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0x01, 0x10, + 0x0c, 0x03, 0x62, 0x00, 0x01, 0x11, 0x0c, 0x03, 0x47, 0x00, 0xee, 0x07, + 0x30, 0x01, 0x12, 0x0c, 0x03, 0x19, 0x00, 0x30, 0x30, 0x30, 0x01, 0x13, + 0x0c, 0x03, 0xc0, 0x00, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, + 0xff, 0x0f, 0xd1, 0x02, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0x0f, 0xd1, 0x02, 0x02, 0xff, + 0xff, 0xee, 0x07, 0x30, 0x02, 0xff, 0xff, 0x0f, 0xd1, 0x02, 0x02, 0xff, + 0xff, 0x02, 0xff, 0xff, 0x01, 0x40, 0x0b, 0x03, 0x1d, 0x00, 0x01, 0x41, + 0x0b, 0x03, 0x16, 0x00, 0x10, 0x01, 0x22, 0x30, 0x30, 0x30, 0x01, 0x42, + 0x0b, 0x03, 0x44, 0x00, 0x01, 0x43, 0x0b, 0x03, 0x75, 0x00, 0x0f, 0xd1, + 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0xee, 0x07, 0x30, 0x10, 0x33, + 0x44, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0xee, 0x07, 0x30, 0x02, 0xff, + 0xff, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0xee, 0x07, + 0x30, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x30, 0x30, 0x30, 0x02, 0xff, + 0xff, 0x0d, 0xcb, 0x02, 0x01, 0xcb, 0x02, 0x40, 0x77, 0x12, 0x00, 0x00, + 0x00, 0x30, 0x30, 0x30 +}; +unsigned int src_rom_bin_len = 1120; diff --git a/src/vm.c b/src/vm.c index dd8e3b5..9f33559 100644 --- a/src/vm.c +++ b/src/vm.c @@ -77,6 +77,8 @@ uint16_t vm_do_instruction(struct CPU *cpu, uint8_t *mem, uint8_t instr[3]) uint16_t operand = ((uint16_t)instr[2] * 256) + instr[1]; #ifdef TRACE + /* IDEA: have instruction printing behavior controllable from + debugger (would require a refactor...) */ printf("0x%04x: ", pc); print_op_decoded(instr, true); #endif @@ -271,6 +273,7 @@ void vm_trace(struct CPU *cpu, uint8_t *mem, struct TRACE_T *tstate) } while(tstate->mode == STEP) { + /* TODO: detect OS, change readline to fgets if Windows */ if ((command = readline("trace> ")) == NULL) { printf("Error: readline returned NULL. Aborting...\n"); exit(0);