454 lines
12 KiB
NASM
454 lines
12 KiB
NASM
# 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
|
|
|