Skip to content

Instantly share code, notes, and snippets.

@sudhackar
Last active February 6, 2023 06:22
Embed
What would you like to do?
csaw 2021 final control source by hgarrereyn modified for bbctf 2023 more control
target
ext.bin
main.bin
main
import argparse
from dataclasses import dataclass
import struct
defs = '''
#define REG_r0_R_DATA (1 << 0)
#define REG_r0_W_DATA (1 << 1)
#define REG_r0_W_ADDR (1 << 2)
#define REG_r1_R_DATA (1 << 3)
#define REG_r1_W_DATA (1 << 4)
#define REG_r1_W_ADDR (1 << 5)
#define REG_r2_R_DATA (1 << 6)
#define REG_r2_W_DATA (1 << 7)
#define REG_r2_W_ADDR (1 << 8)
#define REG_r3_R_DATA (1 << 9)
#define REG_r3_W_DATA (1 << 10)
#define REG_r3_W_ADDR (1 << 11)
#define REG_sp_R_DATA (1 << 12)
#define REG_sp_W_DATA (1 << 13)
#define REG_sp_W_ADDR (1 << 14)
#define ALU_R_X (1 << 15)
#define ALU_R_Y (1 << 16)
#define ALU_ADD (1 << 18)
#define ALU_MUL (1 << 19)
#define ALU_SHF (1 << 17)
#define ALU_XOR (1 << 20)
#define ALU_EQ (1 << 21)
#define RAM_R (1 << 22)
#define RAM_W (1 << 23)
#define OUT_R (1 << 24)
#define IN_W (1 << 25)
#define ROM_W_IP (1 << 26)
#define ROM_W_ADDR (1 << 27)
#define IP_ADD_1 (1 << 28)
#define IP_ADD_2 (1 << 29)
#define IP_R_DATA (1 << 30)
#define HLT (1 << 31)
'''
defs = defs.strip().split('\n')
defs = [x for x in defs if x != '']
defs = [x[8:] for x in defs]
for d in defs:
s = d.split(' ')
v = s[0]
t = eval(' '.join(s[1:]))
globals()[v] = t
label_map = {}
label_warn = False
@dataclass
class Label(object):
name: str
def lookup(lbl):
if lbl in label_map:
return label_map[lbl]
else:
if label_warn:
print('Label error: ', lbl)
return 0
def hlt():
return [(HLT)]
def mov(dst, src):
return eval(f'''[
(REG_{src}_W_DATA | REG_{dst}_R_DATA | IP_ADD_1)
]''')
def li(dst, val):
return eval(f'''[
(REG_{dst}_R_DATA | ROM_W_IP | IP_ADD_2),
({val})
]''')
def la(dst, lbl):
addr = lookup(lbl)
return eval(f'''[
(REG_{dst}_R_DATA | ROM_W_IP | IP_ADD_2),
({addr})
]''')
def addi(dst, val):
return eval(f'''[
(REG_{dst}_W_DATA | ALU_R_X | IP_ADD_1),
(ROM_W_IP | ALU_R_Y | IP_ADD_2),
({val}),
(ALU_ADD | REG_{dst}_R_DATA | IP_ADD_1)
]''')
def add(dst, dst2):
return eval(f'''[
(REG_{dst}_W_DATA | ALU_R_X | IP_ADD_1),
(REG_{dst2}_W_DATA | ALU_R_Y | IP_ADD_1),
(ALU_ADD | REG_{dst}_R_DATA | IP_ADD_1)
]''')
def xor(dst, dst2):
return eval(f'''[
(REG_{dst}_W_DATA | ALU_R_X | IP_ADD_1),
(REG_{dst2}_W_DATA | ALU_R_Y | IP_ADD_1),
(ALU_XOR | REG_{dst}_R_DATA | IP_ADD_1)
]''')
def xori(dst, val):
return eval(f'''[
(REG_{dst}_W_DATA | ALU_R_X | IP_ADD_1),
(ROM_W_IP | ALU_R_Y | IP_ADD_2),
({val}),
(ALU_XOR | REG_{dst}_R_DATA | IP_ADD_1)
]''')
def mul(dst, dst2):
return eval(f'''[
(REG_{dst}_W_DATA | ALU_R_X | IP_ADD_1),
(REG_{dst2}_W_DATA | ALU_R_Y | IP_ADD_1),
(ALU_MUL | REG_{dst}_R_DATA | IP_ADD_1)
]''')
def shifti(dst, val):
return eval(f'''[
(REG_{dst}_W_DATA | ALU_R_X | IP_ADD_1),
(ROM_W_IP | ALU_R_Y | IP_ADD_2),
({val}),
(ALU_SHF | REG_{dst}_R_DATA | IP_ADD_1)
]''')
def push(reg):
return eval(f'''[
(REG_{reg}_W_DATA | RAM_R | REG_sp_W_ADDR | IP_ADD_1),
*addi('sp', -1)
]''')
def pushi(val):
return eval(f'''[
(ROM_W_IP | RAM_R | REG_sp_W_ADDR | IP_ADD_2),
({val}),
*addi('sp', -1)
]''')
def pop(reg):
return eval(f'''[
*addi('sp', 1),
(REG_{reg}_R_DATA | RAM_W | REG_sp_W_ADDR | IP_ADD_1)
]''')
def out(reg):
return eval(f'''[
(REG_{reg}_W_DATA | OUT_R | IP_ADD_1)
]''')
def inr(reg):
return eval(f'''[
(REG_{reg}_R_DATA | IN_W | IP_ADD_1)
]''')
def eqi(reg, val, ltrue, lfalse):
addr_true = lookup(ltrue)
addr_false = lookup(lfalse)
return eval(f'''[
(REG_{reg}_W_DATA | ALU_R_X | IP_ADD_1),
(ROM_W_IP | ALU_R_Y | IP_ADD_2),
({val}),
(ALU_R_X | ALU_EQ | IP_ADD_1),
(ROM_W_IP | ALU_R_Y | IP_ADD_2),
({(addr_true - addr_false) & 0xffffffff}),
(ALU_R_X | ALU_MUL | IP_ADD_1),
(ROM_W_IP | ALU_R_Y | IP_ADD_2),
({addr_false}),
(ALU_ADD | IP_R_DATA),
]''')
def eq(reg, reg2, ltrue, lfalse):
addr_true = lookup(ltrue)
addr_false = lookup(lfalse)
return eval(f'''[
(REG_{reg}_W_DATA | ALU_R_X | IP_ADD_1),
(REG_{reg2}_W_DATA | ALU_R_Y | IP_ADD_1),
(ALU_R_X | ALU_EQ | IP_ADD_1),
(ROM_W_IP | ALU_R_Y | IP_ADD_2),
({(addr_true - addr_false) & 0xffffffff}),
(ALU_R_X | ALU_MUL | IP_ADD_1),
(ROM_W_IP | ALU_R_Y | IP_ADD_2),
({addr_false}),
(ALU_ADD | IP_R_DATA),
]''')
def jmp(lbl):
addr = lookup(lbl)
return eval(f'''[
(ROM_W_IP | IP_R_DATA),
({addr})
]''')
def ldm(reg, off):
return eval(f'''[
(REG_{off}_W_ADDR | ROM_W_ADDR | REG_{reg}_R_DATA | IP_ADD_1)
]''')
def load(reg, off):
return eval(f'''[
(REG_{off}_W_ADDR | RAM_W | REG_{reg}_R_DATA | IP_ADD_1)
]''')
def store(reg, off):
return eval(f'''[
(REG_{off}_W_ADDR | RAM_R | REG_{reg}_W_DATA | IP_ADD_1)
]''')
def call(lbl, ret_lbl):
addr_r = lookup(ret_lbl)
return eval(f'''[
*pushi({addr_r}),
*jmp("{lbl}")
]''')
def ret():
return eval(f'''[
*addi('sp', 1),
(RAM_W | REG_sp_W_ADDR | IP_R_DATA)
]''')
def dbs(val):
# raw string
bs = eval(val)
return list(bs)
@dataclass
class Instruction(object):
op: str
def enc(self):
p = self.op.split(' ')[0]
a = ' '.join(self.op.split(' ')[1:]).split(',')
a = [x.strip() for x in a]
a = [x for x in a if x != '']
if p == 'dbs':
a = [' '.join(self.op.split(' ')[1:])]
return globals()[p](*a)
def preprocess(asm):
out = []
ret_idx = 0
for a in asm:
if type(a) is Instruction and a.op.startswith('call'):
ret_lbl = f'_ret_{ret_idx}'
out.append(Instruction(f'{a.op}, {ret_lbl}'))
out.append(Label(ret_lbl))
ret_idx += 1
else:
out.append(a)
return out
def assemble(asm):
global label_map
global label_warn
label_map = {}
asm = asm.strip().split('\n')
asm = [x.strip() for x in asm if x.strip() != '' and not x.strip()[0] == ';']
asm = [x.split(";")[0] for x in asm]
asm = [Label(x[:-1]) if x.endswith(':') else Instruction(x) for x in asm]
asm = preprocess(asm)
# Generate bytecode.
label_warn = False
code = []
for line in asm:
if type(line) is Label:
label_map[line.name] = len(code)
else:
code += line.enc()
# Second pass, with full labels.
label_warn = True
code = []
for line in asm:
if type(line) is Label:
label_map[line.name] = len(code)
else:
code += line.enc()
enc = b''
for c in code:
enc += struct.pack('<I', c & 0xffffffff)
return enc
def main(args):
asm = open(args.input, 'r').read()
enc = assemble(asm)
open(args.output, 'wb').write(enc)
if __name__=='__main__':
parser = argparse.ArgumentParser()
parser.add_argument('input', help='Input assembly.')
parser.add_argument('output', help='Output path.')
args = parser.parse_args()
main(args)
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "control-rs"
version = "0.1.0"
dependencies = [
"byteorder",
]
[package]
name = "control-rs"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
byteorder = "1.4.3"
[[bin]]
name = "main"
path = "main.rs"
_start:
li sp, 0xffff
jmp main
; Spinloop sleep
; r0 : how long to sleep for
sleep:
_sleep_loop:
addi r0, -1
eqi r0, 0, _sleep_done, _sleep_loop
_sleep_done:
ret
; Print a string slowly
; r0 : pointer to string
slowputs:
push r1
ldm r1, r0
_slowputs_loop:
push r0
li r0, 0x80000
call sleep
pop r0
out r1
addi r0, 1
ldm r1, r0
eqi r1, 0, _slowputs_done, _slowputs_loop
_slowputs_done:
pop r1
ret
; Check if a string equals a fixed template string
; r0 : pointer to string (RAM)
; r1 : pointer to string (ROM)
strcmp:
_strcmp_loop:
load r2, r0
ldm r3, r1
addi r0, 1
addi r1, 1
eqi r3, 0, _strcmp_yes, _strcmp_cont
_strcmp_cont:
eq r2, r3, _strcmp_loop, _strcmp_no
_strcmp_yes:
li r0, 1
ret
_strcmp_no:
li r0, 0
ret
; String length.
; r0 : string in ram
strlen:
li r1, 0
_strlen_loop:
load r2, r0
eqi r2, 0, _strlen_done, _strlen_cont
_strlen_cont:
addi r1, 1
addi r0, 1
jmp _strlen_loop
_strlen_done:
mov r0, r1
ret
printline:
push r0
li r0, 10
out r0
pop r0
ret
printcolon:
push r0
li r0, 58
out r0
pop r0
ret
; r0 : nibble
printnibble:
la r1, hextable
add r1, r0
ldm r0, r1
out r0
ret
; r0 : digit
printhex:
push r0
shifti r0, 4
call printnibble
pop r0
shifti r0, -28
shifti r0, 28
call printnibble
ret
; r0 : addr
setup_mod8:
push r1
push r2
push r3
mov r1, r0
li r2, 0
setup_mod8_i_j_loop:
eqi r2, 0x20, setup_mod8_i_loop_end, setup_mod8_i_loop_cont
setup_mod8_i_loop_cont:
li r3, 0
setup_mod8_j_loop:
eqi r3, 0x8, setup_mod8_j_loop_end, setup_mod8_j_loop_cont
setup_mod8_j_loop_cont:
store r3, r1
addi r1, 1
addi r3, 1
jmp setup_mod8_j_loop
setup_mod8_j_loop_end:
addi r2, 1
jmp setup_mod8_i_j_loop
setup_mod8_i_loop_end:
pop r3
pop r2
pop r1
ret
; r0 : addr
setup_mod256:
push r1
push r2
push r3
mov r1, r0
li r2, 0
setup_mod256_i_j_loop:
eqi r2, 0x2, setup_mod256_i_loop_end, setup_mod256_i_loop_cont
setup_mod256_i_loop_cont:
li r3, 0
setup_mod256_j_loop:
eqi r3, 0x100, setup_mod256_j_loop_end, setup_mod256_j_loop_cont
setup_mod256_j_loop_cont:
store r3, r1
addi r1, 1
addi r3, 1
jmp setup_mod256_j_loop
setup_mod256_j_loop_end:
addi r2, 1
jmp setup_mod256_i_j_loop
setup_mod256_i_loop_end:
pop r3
pop r2
pop r1
ret
; x % 8
; r0 : x
mod8:
push r1
li r1, 0x400
add r1, r0
load r0, r1
pop r1
ret
; x % 256
; r0 : x
mod256:
push r1
li r1, 0x500
add r1, r0
load r0, r1
; call printhex
pop r1
ret
; r0 : seed
srand:
; rand val
push r1
li r1, 0x60
store r0, r1
pop r1
ret
rand:
push r1
push r2
li r1, 0x60
load r0, r1
li r2, 1103515245
mul r0, r2
li r2, 12345
add r0, r2
; truncate to 31 bits
shifti r0, -1
shifti r0, 1
store r0, r1
shifti r0, -26
shifti r0, 26
pop r2
pop r1
ret
; r0/r1 (ram) : pointers
swap:
push r2
push r3
; push r1
; push r0
; call printhex
; call printcolon
; pop r1
; pop r0
; call printhex
; call printline
load r2, r0
load r3, r1
; push r0
; mov r0, r2
; call printhex
; call printcolon
; mov r0, r3
; call printhex
; call printline
; pop r0
store r3, r0
store r2, r1
pop r3
pop r2
ret
; int KSA(char *key, unsigned char *S) {
; int len = strlen(key);
; int j = 0;
; for(int i = 0; i < N; i++)
; S[i] = i;
; for(int i = 0; i < N; i++) {
; j = (j + S[i] + key[i % len]) % N;
; swap(&S[i], &S[j]);
; }
; return 0;
; }
; key schedule
; r0 : key
; r1 : buf
ksa:
push r3
push r2
push r0
push r1
li r2, 0
_i_j_loop:
eqi r2, 0x1, _i_loop_end, _i_loop_cont
_i_loop_cont:
li r3, 0
pop r1
push r1
_j_loop:
eqi r3, 0x100, _j_loop_end, _j_loop_cont
_j_loop_cont:
store r3, r1
addi r1, 1
addi r3, 1
jmp _j_loop
_j_loop_end:
addi r2, 1
jmp _i_j_loop
_i_loop_end:
li r3, 0 ; j
li r2, 0 ; i
_swap_loop:
eqi r2, 0x100, _swap_loop_end, _swap_loop_cont ; i < 0x100
_swap_loop_cont:
pop r1 ; buf
push r1
add r1, r2 ; buf + i
load r0, r1 ; [buf + i]
add r0, r3 ; j + [buf + i]
call mod256 ; j + [buf + i] % 256
mov r3, r0
pop r1
pop r0
push r0
push r1
mov r1, r0 ; key
mov r0, r2
call mod8 ; i % 8
add r1, r0
ldm r0, r1 ; [key + (i % 8)]
add r0, r3
call mod256
mov r3, r0
pop r1
pop r0
push r0
push r1
mov r0, r1
add r0, r2
add r1, r3
call swap
addi r2, 1
jmp _swap_loop
_swap_loop_end:
pop r1
pop r0
pop r2
pop r3
ret
; int PRGA(unsigned char *S, char *plaintext, unsigned char *ciphertext) {
; int i = 0;
; int j = 0;
; for(size_t n = 0, len = strlen(plaintext); n < len; n++) {
; i = (i + 1) % N;
; j = (j + S[i]) % N;
; swap(&S[i], &S[j]);
; int rnd = S[(S[i] + S[j]) % N];
; ciphertext[n] = rnd ^ plaintext[n];
; }
; }
; r0 : S
; r1 : pt
; r2 : ct
prga:
push r3
push r2
push r1
push r0
li r2, 0 ; i
li r0, 0x886
store r2, r0
li r3, 0 ; j
li r0, 0x887
store r3, r0
li r1, 0 ; n
li r0, 0x888
store r1, r0
_main_loop:
li r0, 0x888; n
load r1, r0
eqi r1, 54, _main_loop_end, _main_loop_cont ; i < 0x100
_main_loop_cont:
li r0, 0x886
load r2, r0
addi r2, 1 ; i = i + 1
mov r0, r2
call mod256
mov r2, r0 ; i %= 256
li r0, 0x886
store r2, r0
pop r0
push r0 ; r0 = S
add r0, r2 ; r0 = S + i
load r0, r0; r0 = S[i]
li r2, 0x887
load r3, r2 ; r3 = j
add r0, r3 ; r0 = j + S[i]
call mod256
mov r3, r0 ; r3 = j + S[i] % 256
li r0, 0x887
store r3, r0
pop r0 ; r0 = S
push r0
add r3, r0 ; r3 = S + j
li r1, 0x886
load r2, r1; r2 = i
add r2, r0 ; r2 = S + i
mov r0, r3
mov r1, r2
call swap
load r0, r3; r3 = S + j,
load r1, r2; r2 = S + i,
add r0, r1; r0 = S[i] + S[j]
call mod256; r0 = (S[i] + S[j]) % 256
li r2, 0x888
load r1, r2
pop r2
push r2 ; r2 = S
add r0, r2
load r0, r0; S[(S[i] + S[j]) % 256]
pop r2 ; r2 = S
pop r3 ; r3 = pt
push r3
push r2
li r1, 0x888; n
load r2, r1
add r3, r2 ; r3 = pt + n
load r2, r3 ; r2 = pt[n]
xor r2, r0 ; r2 = pt[n] ^ rnd
pop r0
pop r1
pop r3 ; ct
push r3
push r1
push r0
li r0, 0x888; n
load r1, r0
add r3, r1; ct + n
store r2, r3
li r0, 0x888; n
load r1, r0
addi r1, 1
store r1, r0
jmp _main_loop
_main_loop_end:
pop r0
pop r1
pop r2
pop r3
ret
; Read up to N chars into a buffer.
; r0 : pointer to buffer
; r1 : max chars
readline:
push r2
_readline_loop:
inr r2
eqi r2, 0xa, _readline_done, _readline_ok
_readline_ok:
store r2, r0
addi r1, -1
addi r0, 1
eqi r1, 0, _readline_done, _readline_loop
_readline_done:
pop r2
ret
; r0 (rom)
; r1 (ram)
; r2 (len)
memcpy_oa:
push r3
_memcpy_oa_loop:
eqi r2, 0, _memcpy_oa_done, _memcpy_oa_cont
_memcpy_oa_cont:
ldm r3, r0
store r3, r1
addi r0, 1
addi r1, 1
addi r2, -1
jmp _memcpy_oa_loop
_memcpy_oa_done:
pop r3
ret
; Check flag format.
; r0 : pointer to flag in RAM
check_format:
push r0
; Check flag start
la r1, flag_pre
call strcmp
eqi r0, 1, _format_k1, _format_bad
_format_k1:
; Check length
la r0, msg6
call slowputs
pop r0
push r0
call strlen
eqi r0, 54, _format_k2, _format_bad
_format_k2:
; Check ending
la r0, msg6
call slowputs
pop r0
push r0
mov r1, r0
addi r1, 53
load r2, r1
eqi r2, 125, _format_good, _format_bad
_format_good:
pop r0
li r0, 1
ret
_format_bad:
pop r0
li r0, 0
ret
; r0 (ram)
; r1 (ram)
; r2 (len)
memcmp:
push r3
_memcmp_loop:
eqi r2, 0, _memcmp_good, _memcmp_cont
_memcmp_cont:
addi r2, -1
push r2
load r2, r0
load r3, r1
addi r0, 1
addi r1, 1
eq r2, r3, _memcmp_cont_2, _memcmp_bad
_memcmp_cont_2:
pop r2
jmp _memcmp_loop
_memcmp_good:
li r0, 1
pop r3
ret
_memcmp_bad:
pop r2
li r0, 0
pop r3
ret
; r0 : buf
shuf:
push r0
li r0, 0x1337
call srand
li r3, 0x0
_shuf_start:
eqi r3, 0x1337, _shuf_cont, _shuf_end
_shuf_cont:
pop r1
push r1
mov r2, r1
call rand
add r1, r0
call rand
add r2, r0
mov r0, r2
call swap
addi r3, 1
jmp _shuf_start
_shuf_end:
pop r0
ret
main:
; li r0, 0x1
; call srand
; call rand
; hlt
la r0, msg5
call slowputs
li r0, 0x400
call setup_mod8
; li r0, 15
; call mod8
li r0, 0x500
call setup_mod256
la r0, msg5
li r1, 0x100
call ksa
li r0, 0x0
li r1, 54
call readline
li r0, 0x0
call check_format
eqi r0, 1, _main_good_format, _main_bad_flag
_main_good_format:
la r0, msg6
call slowputs
li r0, 0x100
li r1, 0x0
li r2, 0x80
call prga
li r0, 0
call shuf
la r0, enc
li r1, 0x900
li r2, 54
call memcpy_oa
li r0, 0x900
call shuf
li r0, 0x80 ; prga(input)
li r1, 0x900 ; memcpy(enc)
li r2, 64
call memcmp
eqi r0, 1, _main_good_flag, _main_bad_flag
_main_good_flag:
la r0, s_correct
la r1, ansi_green
jmp _main_print_result
_main_bad_flag:
la r0, s_wrong
la r1, ansi_red
_main_print_result:
push r0
mov r0, r1
call slowputs
pop r0
call slowputs
la r0, ansi_reset
call slowputs
_main_exit:
hlt
hlt
enc:
dbs b'\x32\xfb\x19\xd5\xa1\xdf\x06\x83\xf2\xe6\xf9\xf8\x21\x69\x32\xb3\x33\xa4\x42\x3d\x45\x01\xe0\x40\xe1\x05\x7e\x14\xf3\x80\xe1\x27\x00\xbc\x92\x45\x1e\x87\x1f\xbe\xb9\xea\x65\xa3\x19\x5d\xfa\x95\x8c\xb3\x6c\xd6\xa9\x79'
ansi_red:
dbs b'\033[31m\x00'
ansi_green:
dbs b'\033[32m\x00'
ansi_reset:
dbs b'\033[0m\x00'
msg5:
dbs b'Give flag: \x00'
msg6:
dbs b'makes sense\n\x00'
hextable:
dbs b'0123456789abcdef'
flag_pre:
dbs b'flag{\x00'
s_correct:
dbs b'correct\x00'
s_wrong:
dbs b'wrong\x00'
flag{th1s_was__a_usele55__rewrite_of_c0ntr0l__to_rust}
_start:
li sp, 0xffff
jmp main
; Print a null terminated string
; r0 : pointer to string
puts:
push r1
ldm r1, r0
_puts_loop:
out r1
addi r0, 1
ldm r1, r0
eqi r1, 0, _puts_done, _puts_loop
_puts_done:
pop r1
ret
; Read up to N chars into a buffer.
; r0 : pointer to buffer
; r1 : max chars
readline:
push r2
_readline_loop:
inr r2
eqi r2, 0xa, _readline_done, _readline_ok
_readline_ok:
store r2, r0
addi r1, -1
addi r0, 1
eqi r1, 0, _readline_done, _readline_loop
_readline_done:
pop r2
ret
; Print a string slowly
; r0 : pointer to string
slowputs:
push r1
ldm r1, r0
_slowputs_loop:
push r0
li r0, 0x80000
call sleep
pop r0
out r1
addi r0, 1
ldm r1, r0
eqi r1, 0, _slowputs_done, _slowputs_loop
_slowputs_done:
pop r1
ret
; Check if a string equals a fixed template string
; r0 : pointer to string (RAM)
; r1 : pointer to string (ROM)
strcmp:
_strcmp_loop:
load r2, r0
ldm r3, r1
addi r0, 1
addi r1, 1
eqi r3, 0, _strcmp_yes, _strcmp_cont
_strcmp_cont:
eq r2, r3, _strcmp_loop, _strcmp_no
_strcmp_yes:
li r0, 1
ret
_strcmp_no:
li r0, 0
ret
; r0 : nibble
printnibble:
la r1, hextable
add r1, r0
ldm r0, r1
out r0
ret
printhex:
push r0
shifti r0, 4
call printnibble
pop r0
shifti r0, -28
shifti r0, 28
call printnibble
ret
fake_crash:
la r0, fake_crash_pre
call puts
li r1, 3
load r0, r1
call printhex
li r1, 2
load r0, r1
call printhex
li r1, 1
load r0, r1
call printhex
li r1, 0
load r0, r1
call printhex
la r0, fake_crash_post
call puts
li r0, 0x1000000
call sleep
la r0, omg_what
call slowputs
ret
; Spinloop sleep
; r0 : how long to sleep for
sleep:
_sleep_loop:
addi r0, -1
eqi r0, 0, _sleep_done, _sleep_loop
_sleep_done:
ret
; String length.
; r0 : string in ram
strlen:
li r1, 0
_strlen_loop:
load r2, r0
eqi r2, 0, _strlen_done, _strlen_cont
_strlen_cont:
addi r1, 1
addi r0, 1
jmp _strlen_loop
_strlen_done:
mov r0, r1
ret
; Check flag format.
; r0 : pointer to flag in RAM
check_format:
push r0
; Check flag start
la r1, flag_pre
call strcmp
eqi r0, 1, _format_k1, _format_bad
_format_k1:
; Check length
pop r0
push r0
call strlen
eqi r0, 46, _format_k2, _format_bad
_format_k2:
; Check ending
pop r0
push r0
mov r1, r0
addi r1, 45
load r2, r1
eqi r2, 125, _format_good, _format_bad
_format_good:
pop r0
li r0, 1
ret
_format_bad:
pop r0
li r0, 0
ret
; r0 : seed
srand:
; rand val
push r1
li r1, 0x60
store r0, r1
pop r1
ret
rand:
push r1
push r2
li r1, 0x60
load r0, r1
li r2, 1103515245
mul r0, r2
li r2, 12345
add r0, r2
; truncate to 31 bits
shifti r0, -1
shifti r0, 1
store r0, r1
pop r2
pop r1
ret
; r0 : char value
; r1 : bit buffer
char_to_bits:
push r2
li r2, 0
_char_to_bits_loop:
eqi r2, 8, _char_to_bits_done, _char_to_bits_cont
_char_to_bits_cont:
mov r3, r0
shifti r3, -31
shifti r3, 31
store r3, r1
shifti r0, 1
addi r1, 1
addi r2, 1
jmp _char_to_bits_loop
_char_to_bits_done:
pop r2
ret
; Chars to bit buffer.
; r0 (ram): pointer to 8 chars
; r1 (ram): pointer to bit buffer
chars_to_bits:
li r2, 0
_chars_to_bits_loop:
eqi r2, 8, _chars_to_bits_done, _chars_to_bits_cont
_chars_to_bits_cont:
load r3, r0
push r0
push r1
push r2
mov r0, r3
; r1 = bit buffer
call char_to_bits
pop r2
pop r1
pop r0
addi r0, 1
addi r1, 8
addi r2, 1
jmp _chars_to_bits_loop
_chars_to_bits_done:
ret
; r0 (rom)
; r1 (ram)
; r2 (len)
memcpy_oa:
push r3
_memcpy_oa_loop:
eqi r2, 0, _memcpy_oa_done, _memcpy_oa_cont
_memcpy_oa_cont:
ldm r3, r0
store r3, r1
addi r0, 1
addi r1, 1
addi r2, -1
jmp _memcpy_oa_loop
_memcpy_oa_done:
pop r3
ret
; r0 (ram)
; r1 (ram)
; r2 (len)
memcmp:
push r3
_memcmp_loop:
eqi r2, 0, _memcmp_good, _memcmp_cont
_memcmp_cont:
addi r2, -1
push r2
load r2, r0
load r3, r1
addi r0, 1
addi r1, 1
eq r2, r3, _memcmp_cont_2, _memcmp_bad
_memcmp_cont_2:
pop r2
jmp _memcmp_loop
_memcmp_good:
li r0, 1
pop r3
ret
_memcmp_bad:
pop r2
li r0, 0
pop r3
ret
; r0/r1 (ram) : pointers
swap:
push r2
push r3
load r2, r0
load r3, r1
store r3, r0
store r2, r1
pop r3
pop r2
ret
; r0 (ram): bit buffer
; r1 : seed
mutate:
push r2
push r3
mov r3, r0
; set srand seed
mov r0, r1
call srand
li r2, 0
_mutate_loop_1:
eqi r2, 0x1337, _mutate_done_1, _mutate_cont_1
_mutate_cont_1:
addi r2, 1
push r2
call rand
shifti r0, -26
shifti r0, 26
mov r1, r3
add r1, r0
call rand
shifti r0, -26
shifti r0, 26
mov r2, r3
add r2, r0
mov r0, r1
mov r1, r2
call swap
pop r2
jmp _mutate_loop_1
_mutate_done_1:
li r2, 0
_mutate_loop_2:
eqi r2, 0x1337, _mutate_done, _mutate_cont_2
_mutate_cont_2:
addi r2, 1
push r2
call rand
shifti r0, -26
shifti r0, 26
mov r1, r3
add r1, r0
load r2, r1
xori r2, 1
store r2, r1
pop r2
jmp _mutate_loop_2
_mutate_done:
pop r3
pop r2
ret
; Check chunk.
; r0 : flag chunk
; r1 : enc chunk
; r2 : seed
check_flag_chunk:
; start of inner part
push r1
push r2
li r1, 0x100
call chars_to_bits
li r0, 0x100
pop r1
call mutate
pop r0
li r1, 0x200
li r2, 8
call memcpy_oa
li r0, 0x200
li r1, 0x208
call chars_to_bits
li r0, 0x100
li r1, 0x208
li r2, 64
call memcmp
ret
; Check whole flag
; r0 : flag base
; r1 : enc base
check_flag:
; start of flag
addi r0, 5
li r2, 0
_check_flag_loop:
eqi r2, 5, _check_flag_good, _check_flag_cont
_check_flag_cont:
push r0
push r1
push r2
call check_flag_chunk
mov r3, r0
pop r2
pop r1
pop r0
eqi r3, 0, _check_flag_bad, _check_flag_cont2
_check_flag_cont2:
addi r0, 8
addi r1, 8
addi r2, 1
jmp _check_flag_loop
_check_flag_bad:
li r0, 0
ret
_check_flag_good:
li r0, 1
ret
main:
la r0, msg1
call slowputs
la r0, ansi_red
call puts
la r0, control
call puts
la r0, ansi_reset
call puts
la r0, msg2
call puts
inr r0
inr r1
eqi r0, 121, _main_has_control, _main_no_control
_main_no_control:
la r0, msg3
call slowputs
hlt
_main_has_control:
la r0, msg4
call slowputs
la r0, ansi_green
call puts
la r0, a_flag
call puts
la r0, ansi_reset
call puts
la r0, msg2
call puts
inr r0
inr r1
eqi r0, 121, _main_has_flag, _main_no_flag
_main_no_flag:
la r0, msg3
call slowputs
hlt
_main_has_flag:
la r0, msg5
call puts
li r0, 0x0
li r1, 0x30
call readline
li r0, 0x0
call check_format
eqi r0, 1, _main_no_crash, _main_fake_crash
_main_fake_crash:
call fake_crash
jmp _main_exit
_main_no_crash:
la r0, checking
call slowputs
li r0, 0
la r1, target_enc
call check_flag
eqi r0, 1, _main_good_flag, _main_bad_flag
_main_good_flag:
la r0, s_correct
la r1, ansi_green
jmp _main_print_result
_main_bad_flag:
la r0, s_wrong
la r1, ansi_red
_main_print_result:
push r0
mov r0, r1
call puts
pop r0
call puts
la r0, ansi_reset
call puts
_main_exit:
hlt
; Data section
msg1:
dbs b'Hello...\nDo you have: \n\x00'
control:
dbs ' ██████╗ ██████╗ ███╗ ██╗████████╗██████╗ ██████╗ ██╗ ██████╗ \n██╔════╝██╔═══██╗████╗ ██║╚══██╔══╝██╔══██╗██╔═══██╗██║ ╚════██╗\n██║ ██║ ██║██╔██╗ ██║ ██║ ██████╔╝██║ ██║██║ ▄███╔╝\n██║ ██║ ██║██║╚██╗██║ ██║ ██╔══██╗██║ ██║██║ ▀▀══╝ \n╚██████╗╚██████╔╝██║ ╚████║ ██║ ██║ ██║╚██████╔╝███████╗██╗ \n ╚═════╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ \n\x00'.encode('utf8')
ansi_red:
dbs b'\033[31m\x00'
ansi_green:
dbs b'\033[32m\x00'
ansi_reset:
dbs b'\033[0m\x00'
msg2:
dbs b'(y/N): \x00'
msg3:
dbs b'Hmm...\nWell bye then...\n\x00'
msg4:
dbs b'Nice!\nAnd do you have: \n\x00'
a_flag:
dbs ' █████╗ ███████╗██╗ █████╗ ██████╗██████╗ \n██╔══██╗ ██╔════╝██║ ██╔══██╗██╔════╝╚════██╗\n███████║ █████╗ ██║ ███████║██║ ███╗ ▄███╔╝\n██╔══██║ ██╔══╝ ██║ ██╔══██║██║ ██║ ▀▀══╝ \n██║ ██║ ██║ ███████╗██║ ██║╚██████╔╝ ██╗ \n╚═╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ \n\x00'.encode('utf8')
msg5:
dbs b'Give flag: \x00'
fake_crash_pre:
dbs b'Program received signal SIGSEGV, Segmentation fault.\n0x\x00'
fake_crash_post:
dbs b' in ?? ()\n\x00'
checking:
dbs b'Checking flag...\n\x00'
omg_what:
dbs b'... omg how could you do this to me???\nI thought we were friends!\n\x00'
flag_pre:
dbs b'flag{\x00'
hextable:
dbs b'0123456789abcdef'
s_correct:
dbs ' ██████╗ ██████╗ ██████╗ ██████╗ ███████╗ ██████╗████████╗██╗\n██╔════╝██╔═══██╗██╔══██╗██╔══██╗██╔════╝██╔════╝╚══██╔══╝██║\n██║ ██║ ██║██████╔╝██████╔╝█████╗ ██║ ██║ ██║\n██║ ██║ ██║██╔══██╗██╔══██╗██╔══╝ ██║ ██║ ╚═╝\n╚██████╗╚██████╔╝██║ ██║██║ ██║███████╗╚██████╗ ██║ ██╗\n ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝\n\x00'.encode('utf8')
s_wrong:
dbs '██╗ ██╗██████╗ ██████╗ ███╗ ██╗ ██████╗ ██╗\n██║ ██║██╔══██╗██╔═══██╗████╗ ██║██╔════╝ ██║\n██║ █╗ ██║██████╔╝██║ ██║██╔██╗ ██║██║ ███╗██║\n██║███╗██║██╔══██╗██║ ██║██║╚██╗██║██║ ██║╚═╝\n╚███╔███╔╝██║ ██║╚██████╔╝██║ ╚████║╚██████╔╝██╗\n ╚══╝╚══╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═╝\n\x00'.encode('utf8')
target_enc:
dbs b'\x85\xf5\xdd\xa8\x01\xc8\x08\xba\xaa\xf8\xb8\xc1\x95J[\nL\xb1\x88\xc5\xf7\x990\x02\x92\xe8\x93\x9f\xdb\x0cZ\x81\x97\xfc\xf1\xae\xed1\x91\x9a'
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>
#define DEBUG 0
// Control flags.
#define REG_r0_R_DATA (1 << 0)
#define REG_r0_W_DATA (1 << 1)
#define REG_r0_W_ADDR (1 << 2)
#define REG_r1_R_DATA (1 << 3)
#define REG_r1_W_DATA (1 << 4)
#define REG_r1_W_ADDR (1 << 5)
#define REG_r2_R_DATA (1 << 6)
#define REG_r2_W_DATA (1 << 7)
#define REG_r2_W_ADDR (1 << 8)
#define REG_r3_R_DATA (1 << 9)
#define REG_r3_W_DATA (1 << 10)
#define REG_r3_W_ADDR (1 << 11)
#define REG_sp_R_DATA (1 << 12)
#define REG_sp_W_DATA (1 << 13)
#define REG_sp_W_ADDR (1 << 14)
#define ALU_R_X (1 << 15)
#define ALU_R_Y (1 << 16)
#define ALU_SHF (1 << 17)
#define ALU_ADD (1 << 18)
#define ALU_MUL (1 << 19)
#define ALU_XOR (1 << 20)
#define ALU_EQ (1 << 21)
#define RAM_R (1 << 22)
#define RAM_W (1 << 23)
#define OUT_R (1 << 24)
#define IN_W (1 << 25)
#define ROM_W_IP (1 << 26)
#define ROM_W_ADDR (1 << 27)
#define IP_ADD_1 (1 << 28)
#define IP_ADD_2 (1 << 29)
#define IP_R_DATA (1 << 30)
#define HLT (1 << 31)
static uint32_t r0 = 0;
static uint32_t r1 = 0;
static uint32_t r2 = 0;
static uint32_t r3 = 0;
static uint32_t sp = 0;
static uint32_t alu_x = 0;
static uint32_t alu_y = 0;
static uint32_t ip = 0;
static uint32_t val = 0;
static uint32_t data_bus = 0;
static uint32_t addr_bus = 0;
uint32_t *rom;
uint32_t ram[0x10000];
int main(int argc, char **argv) {
setbuf(stdout, NULL);
setbuf(stdin, NULL);
if (argc != 2) {
printf("Usage: %s main.bin\n", argv[0]);
exit(0);
}
FILE *fd = fopen(argv[1], "rb");
fseek(fd, 0, SEEK_END);
size_t size = ftell(fd);
fseek(fd, 0, SEEK_SET);
rom = malloc(size);
fread(rom, 1, size, fd);
while (!(val & HLT)) {
// Load instruction.a
val = rom[ip];
#if DEBUG == 1
printf("[%04x] 0x%08x :: 0x%08x ;; \tr0=0x%08x\tr1=0x%08x\tr2=0x%08x\tr3=0x%08x\tsp=0x%08x\tax=0x%08x\tay=0x%08x\t\n", ip, val, rom[ip+1], r0, r1, r2, r3, sp, alu_x, alu_y);
printf("Mem: ");
for (int i = 0; i < 0x10; ++i) {
printf("0x%08x ", ram[i]);
}
printf("\n");
#endif
// Alu op.
if (val & ALU_ADD) data_bus = alu_x + alu_y;
if (val & ALU_MUL) data_bus = alu_x * alu_y;
if (val & ALU_SHF) data_bus = (((int32_t)alu_y)) > 0 ? alu_x >> alu_y : alu_x << (-((int32_t)alu_y));
if (val & ALU_XOR) data_bus = alu_x ^ alu_y;
if (val & ALU_EQ) data_bus = (alu_x == alu_y ? 1 : 0);
// Address writes.
if (val & REG_r0_W_ADDR) addr_bus = r0;
if (val & REG_r1_W_ADDR) addr_bus = r1;
if (val & REG_r2_W_ADDR) addr_bus = r2;
if (val & REG_r3_W_ADDR) addr_bus = r3;
if (val & REG_sp_W_ADDR) addr_bus = sp;
// Data writes.
if (val & REG_r0_W_DATA) data_bus = r0;
if (val & REG_r1_W_DATA) data_bus = r1;
if (val & REG_r2_W_DATA) data_bus = r2;
if (val & REG_r3_W_DATA) data_bus = r3;
if (val & REG_sp_W_DATA) data_bus = sp;
if (val & RAM_W) data_bus = ram[addr_bus];
if (val & ROM_W_IP) data_bus = rom[ip + 1];
if (val & ROM_W_ADDR) data_bus = rom[addr_bus];
if (val & IN_W) data_bus = getchar();
// Data reads.
if (val & REG_r0_R_DATA) r0 = data_bus;
if (val & REG_r1_R_DATA) r1 = data_bus;
if (val & REG_r2_R_DATA) r2 = data_bus;
if (val & REG_r3_R_DATA) r3 = data_bus;
if (val & REG_sp_R_DATA) sp = data_bus;
if (val & ALU_R_X) alu_x = data_bus;
if (val & ALU_R_Y) alu_y = data_bus;
if (val & RAM_R) ram[addr_bus] = data_bus;
if (val & OUT_R) putchar(data_bus);
// IP increment.
if (val & IP_ADD_1) ip += 1;
if (val & IP_ADD_2) ip += 2;
if (val & IP_R_DATA) ip = data_bus;
}
}
const REG_R0_R_DATA: u32 = 1 << 0;
const REG_R0_W_DATA: u32 = 1 << 1;
const REG_R0_W_ADDR: u32 = 1 << 2;
const REG_R1_R_DATA: u32 = 1 << 3;
const REG_R1_W_DATA: u32 = 1 << 4;
const REG_R1_W_ADDR: u32 = 1 << 5;
const REG_R2_R_DATA: u32 = 1 << 6;
const REG_R2_W_DATA: u32 = 1 << 7;
const REG_R2_W_ADDR: u32 = 1 << 8;
const REG_R3_R_DATA: u32 = 1 << 9;
const REG_R3_W_DATA: u32 = 1 << 10;
const REG_R3_W_ADDR: u32 = 1 << 11;
const REG_SP_R_DATA: u32 = 1 << 12;
const REG_SP_W_DATA: u32 = 1 << 13;
const REG_SP_W_ADDR: u32 = 1 << 14;
const ALU_R_X: u32 = 1 << 15;
const ALU_R_Y: u32 = 1 << 16;
const ALU_SHF: u32 = 1 << 17;
const ALU_ADD: u32 = 1 << 18;
const ALU_MUL: u32 = 1 << 19;
const ALU_XOR: u32 = 1 << 20;
const ALU_EQ: u32 = 1 << 21;
const RAM_R: u32 = 1 << 22;
const RAM_W: u32 = 1 << 23;
const OUT_R: u32 = 1 << 24;
const IN_W: u32 = 1 << 25;
const ROM_W_IP: u32 = 1 << 26;
const ROM_W_ADDR: u32 = 1 << 27;
const IP_ADD_1: u32 = 1 << 28;
const IP_ADD_2: u32 = 1 << 29;
const IP_R_DATA: u32 = 1 << 30;
const HLT: u32 = 1 << 31;
extern crate byteorder;
use byteorder::{NativeEndian, ReadBytesExt};
use std::{env, io::Read};
use std::io::{stdin, stdout, Write};
fn getchar() -> u32 {
let mut c : [u8; 1] = [0];
match stdin().read(&mut c) {
Ok(_) => {
c[0] as u32
}
Err(_) => {
0
}
}
}
fn putchar(c: u32) {
let c : [u8; 1] = [c as u8];
let _ = stdout().write(&c);
stdout().flush().unwrap();
}
fn main() {
// println!("flag{{wh0_n33ds_opc0des_wh3n_you_h4ve_CONTROL?}}");// flag{wh0_n33ds_opc0des_wh3n_you_h4ve_CONTROL.}
let mut r0: u32 = 0;
let mut r1: u32 = 0;
let mut r2: u32 = 0;
let mut r3: u32 = 0;
let mut sp: u32 = 0;
let mut alu_x: u32 = 0;
let mut alu_y: u32 = 0;
let mut ip: u32 = 0;
let mut val: u32 = 0;
let mut data_bus: u32 = 0;
let mut addr_bus: u32 = 0;
let mut ram: [u32; 0x10000] = [0; 0x10000];
let args: Vec<_> = env::args().collect();
if args.len() < 2 {
println!("./{} <bin>", args[0]);
return;
}
let filename = &args[1];
let mut file = std::fs::File::open(filename).expect("file not found");
let flen = file.metadata().unwrap().len() as usize;
let mut rom = vec![0u32; flen / 4];
let _ = file.read_u32_into::<NativeEndian>(&mut rom);
while val & HLT == 0 {
// Load instruction.a
val = rom[ip as usize];
// #if DEBUG == 1
// println!("[{:#04x}] {:#08x} :: {:#08x} ;; r0={:#08x}\tr1={:#08x}\tr2={:#08x}\tr3={:#08x}", ip, val, rom[(ip+1) as usize], r0, r1, r2, r3);
// Alu op.
if (val & ALU_ADD) != 0 {
data_bus = alu_x + alu_y;
}
if (val & ALU_MUL) != 0 {
data_bus = alu_x * alu_y;
}
if (val & ALU_SHF) != 0 {
data_bus = if (alu_y as i32) > 0 {
alu_x >> alu_y
} else {
alu_x << (-(alu_y as i32))
};
}
if (val & ALU_XOR) != 0 {
data_bus = alu_x ^ alu_y;
}
if (val & ALU_EQ) != 0 {
data_bus = if alu_x == alu_y { 1 } else { 0 };
}
// Address writes.
if (val & REG_R0_W_ADDR) != 0 {
addr_bus = r0;
}
if (val & REG_R1_W_ADDR) != 0 {
addr_bus = r1;
}
if (val & REG_R2_W_ADDR) != 0 {
addr_bus = r2;
}
if (val & REG_R3_W_ADDR) != 0 {
addr_bus = r3;
}
if (val & REG_SP_W_ADDR) != 0 {
addr_bus = sp;
}
// Data writes.
if (val & REG_R0_W_DATA) != 0 {
data_bus = r0;
}
if (val & REG_R1_W_DATA) != 0 {
data_bus = r1;
}
if (val & REG_R2_W_DATA) != 0 {
data_bus = r2;
}
if (val & REG_R3_W_DATA) != 0 {
data_bus = r3;
}
if (val & REG_SP_W_DATA) != 0 {
data_bus = sp;
}
if (val & RAM_W) != 0 {
data_bus = ram[addr_bus as usize];
// println!("read ram [{:#08x}] -> {:#08x}", addr_bus, data_bus);
}
if (val & ROM_W_IP) != 0 {
data_bus = rom[(ip + 1) as usize];
}
if (val & ROM_W_ADDR) != 0 {
data_bus = rom[addr_bus as usize];
// println!("read rom [{:#08x}] -> {:#08x}", addr_bus, data_bus);
}
if (val & IN_W) != 0 {
data_bus = getchar();
}
// Data reads.
if (val & REG_R0_R_DATA) != 0 {
r0 = data_bus;
}
if (val & REG_R1_R_DATA) != 0 {
r1 = data_bus;
}
if (val & REG_R2_R_DATA) != 0 {
r2 = data_bus;
}
if (val & REG_R3_R_DATA) != 0 {
r3 = data_bus;
}
if (val & REG_SP_R_DATA) != 0 {
sp = data_bus;
}
if (val & ALU_R_X) != 0 {
alu_x = data_bus;
}
if (val & ALU_R_Y) != 0 {
alu_y = data_bus;
}
if (val & RAM_R) != 0 {
// println!("write {:#08x} <- {:#08x}", addr_bus, data_bus);
ram[addr_bus as usize] = data_bus;
}
if (val & OUT_R) != 0 {
putchar(data_bus);
}
// IP increment.
if (val & IP_ADD_1) != 0 {
ip += 1;
}
if (val & IP_ADD_2) != 0 {
ip += 2;
}
if (val & IP_R_DATA) != 0 {
ip = data_bus;
}
}
// println!("[{:#04x}] {:#08x} :: {:#08x} ;; r0={:#08x}\tr1={:#08x}\tr2={:#08x}\tr3={:#08x}", ip, val, rom[(ip+1) as usize], r0, r1, r2, r3);
// (0x100..=0x200).for_each(|idx|print!("{:#02x}:", ram[idx]));
// println!("");
// (0x400..=0x500).for_each(|idx|print!("{:#02x}:", ram[idx]));
// println!("");
// (0x500..=0x700).for_each(|idx|print!("{:#02x}:", ram[idx]));
// println!("");
// (0x80..=0x100).for_each(|idx|print!("{:#02x}:", ram[idx]));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment