You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

872 lines
16 KiB

2 years ago
.include "instr.inc"
.text
mem_e000:
.2byte 0
mem_e002:
.fill 0x0efe
mem_ef00:
.fill 0xb0
mem_efb0:
.fill 0x30
mem_efe0:
.fill 0x20
.global _start
_start:
ld_sp stack
# Set up the entrypoint for the breakpoint instruction
ld_r0 entry
ld_r1 0x98 # 'call'
strb_r1_r0
inc_r0
ld_r1 main
str_r1_r0
# Explain the debugger
ld_r2 str_intro
call PrintStr
auth_user:
# Gather the username
ld_r2 str_prompt_user
call PrintStr
ld_r3 0x10
ld_r2 mem_input_user
call ReadStr
ld_r2 database
auth_user_loop:
# Check if we've reached the end of the database
ldrb_r0_r2
cp_r0 0
jp_eq error_incorrect_user
# Check if the username matches the current entry
ld_r3 mem_input_user
push_r2
call StrCmp
pop_r2
cp_r0 0
jp_eq auth_pass
# Next entry
add_r2 0x50
jp auth_user_loop
auth_pass:
# Grab the password field
add_r2 0x10
push_r2
call delay_input
# Gather the password
ld_r2 str_prompt_pass
call PrintStr
ld_r3 0x30
ld_r2 mem_input_pass
call ReadStr
call delay_input
# Load the ENCTABLE.BIN file
ld_r0 1
ld_r1 0xc000
copr_readblk
# r2 = encoded pass
# r3 = input pass
pop_r2
ld_r3 mem_input_pass
auth_pass_loop:
push_r3
# b = *(0xc000 + *input)
ld_r1 0xc000
ldrb_r0_r3
add_r1_r0
ld_r3 0
ldrb_r0_r1
add_r3_r0
# b += *(0xc100 + *input)
add_r1 0x100
ldrb_r0_r1
add_r3_r0
# b += *(0xc200 + *input)
add_r1 0x100
ldrb_r0_r1
add_r3_r0
# b += *(0xc300 + *input)
add_r1 0x100
ldrb_r0_r1
add_r3_r0
# b &= 0xff
ld_r0_r3
and_r0 0xff
ldrb_r1_r2
cp_r0_r1
jp_ne error_incorrect_pass
pop_r3
call rotate_enctable
inc_r2
inc_r3
ldrb_r0_r2
cp_r0 0
jp_eq auth_success
jp auth_pass_loop
auth_success:
ld_r2 str_login_success
call PrintStr
# Execute the breakpoint, jump to main
brk
# If breakpoint returns here, we've ran out of stack
ld_r2 str_dry_stack
call PrintStr
copr_halt
die:
jp die
error_incorrect_user:
call delay_input
ld_r2 str_incorrect_user
call PrintStr
jp auth_user
error_incorrect_pass:
ld_r2 str_incorrect_pass
call PrintStr
jp auth_user
rotate_enctable:
ldrb_r0 0xc000
strb_r0 rotate_enctable_temp + 0
ldrb_r0 0xc100
strb_r0 rotate_enctable_temp + 1
ldrb_r0 0xc200
strb_r0 rotate_enctable_temp + 2
ldrb_r0 0xc300
strb_r0 rotate_enctable_temp + 3
ld_r1 0xc000
rotate_enctable_loop:
inc_r1
ldrb_r0_r1
dec_r1
strb_r0_r1
inc_r1
cp_r1 0xc3ff
jp_ne rotate_enctable_loop
ldrb_r0 rotate_enctable_temp + 0
strb_r0 0xc0ff
ldrb_r0 rotate_enctable_temp + 1
strb_r0 0xc1ff
ldrb_r0 rotate_enctable_temp + 2
strb_r0 0xc2ff
ldrb_r0 rotate_enctable_temp + 3
strb_r0 0xc3ff
ret
rotate_enctable_temp:
.fill 4
delay_input:
push_r2
ld_r2 str_please_wait
call PrintStr
pop_r2
ld_r0 0x3fff
delay_input_loop:
nop
nop
nop
nop
nop
nop
nop
dec_r0
cp_r0 0
jp_ne delay_input_loop
ret
database:
.fill 0x00 - (. - database)
.ascii "ax.arwen\0"
.fill 0x10 - (. - database)
.byte 0xc6, 0x44, 0x99, 0xe3, 0xe9, 0x19, 0x0d, 0x07, 0x0d, 0x12, 0x79
.fill 0x50 - (. - database)
.ascii "sbw.shadow\0"
.fill 0x60 - (. - database)
.byte 0xe9, 0x22, 0xd8, 0x7c, 0x3c, 0x07, 0x54, 0x2d
.byte 0x5e, 0x53, 0x6a, 0xff, 0x80, 0x5e, 0xcd, 0xc8
.byte 0xcf, 0xff, 0x44, 0x74, 0xc8, 0xd8, 0x4b
.fill 0xbd - (. - database)
mem_input_user:
.ascii "________________\0"
mem_input_pass:
.ascii "________________________________________________________________\0"
str_prompt_user:
.ascii "Username: \0"
str_prompt_pass:
.ascii ">> Username OK. Password required\n"
.ascii "Password: \0"
str_please_wait:
.ascii ">> Please wait...\n\0"
str_incorrect_user:
.ascii ">> User not found in database.\n\0"
str_incorrect_pass:
.ascii ">> Password is incorrect.\n\0"
str_login_success:
.ascii ">> Login successful.\n"
.ascii "======================================================================\n"
.ascii "Running machine language monitor now.\n"
.ascii "======================================================================\n"
.ascii "\n\0"
main:
# Save all the registers
push_sp
str_r0 mem_save_r0
str_r1 mem_save_r1
str_r2 mem_save_r2
str_r3 mem_save_r3
# Store the stack pointer
pop_r0
str_r0 mem_info_sp
# Read the return address
ld_r0_sp
ldr_r0_r0
add_r0 -1
str_r0 mem_info_pc
# Read some more stack values
ld_r1 (6 * 2)
ld_r2 mem_info_stack
ldr_r3 mem_info_sp
call MemCpy
# Print the processor state
ld_r2 str_breakpoint
call PrintStr
main_cmd_loop:
ld_r0 0
strb_r0 mem_e002
ld_r2 str_ready
call PrintStr
# Read input
ld_r2 mem_e000
ld_r3 8
call ReadStr
cp_r3 0
jp_eq error_too_long
ld_r2 mem_e000
call StrTrim
# Make sure the input is at most 2 characters
ldrb_r0 mem_e002
cp_r0 0
jp_ne error_bad_command
# Parse all the commands
ldr_r0 mem_e000
cp_r0 ('h' + '\n' * 0x100)
jp_eq cmd_help
cp_r0 'h'
jp_eq cmd_help
cp_r0 'r'
jp_eq cmd_read
cp_r0 ('r' + '\n' * 0x100)
jp_eq cmd_read
cp_r0 'p'
jp_eq cmd_print
cp_r0 ('p' + '\n' * 0x100)
jp_eq cmd_print
cp_r0 'x'
jp_eq cmd_exec
cp_r0 ('x' + '\n' * 0x100)
jp_eq cmd_exec
cp_r0 'c'
jp_eq cmd_cont
cp_r0 ('c' + '\n' * 0x100)
jp_eq cmd_cont
cp_r0 ('U' + 'C' * 0x100)
jp_eq cmd_undoc
cp_r0 ('l' + 's' * 0x100)
jp_eq cmd_list
cp_r0 ('r' + 'f' * 0x100)
jp_eq cmd_readfile
cp_r0 'w'
jp_eq cmd_write
cp_r0 ('w' + '\n' * 0x100)
jp_eq cmd_write
error_bad_command:
ld_r2 str_error_bad_command
call PrintStr
jp main_cmd_loop
error_too_long:
ld_r2 str_error_too_long
call PrintStr
jp main_cmd_loop
cmd_help:
ld_r2 str_help
call PrintStr
jp main_cmd_loop
cmd_read:
# Get the address to read
ld_r2 str_prompt_address
call PrintStr
ld_r2 mem_e000
ld_r3 8
call ReadStr
ld_r2 mem_e000
call ConvertHex
cp_r0 -1
jp_eq cmd_read_invalid
push_r0
# Get the amount of lines to read
ld_r2 str_prompt_lines
call PrintStr
ld_r2 mem_e000
ld_r3 8
call ReadStr
ld_r2 mem_e000
call ConvertHex
cp_r0 -1
jp_eq cmd_read_invalid
cp_r0 0
jp_eq cmd_read_invalid
# r2 = address, r3 = lines
ld_r3_r0
pop_r2
cmd_read_loop:
# Read 8 bytes
push_r2
push_r3
ld_r1 8
ld_r3_r2
ld_r2 mem_data
call MemCpy
pop_r3
pop_r2
# Store the current read address
str_r2 mem_addr
# Write it out
push_r2
push_r3
ld_r2 str_hexdump
call PrintStr
pop_r3
pop_r2
# Check if we're done
add_r2 8
dec_r3
cp_r3 0
jp_ne cmd_read_loop
jp main_cmd_loop
cmd_read_invalid:
ld_r2 str_error_invalid_input
call PrintStr
jp main_cmd_loop
cmd_write:
# Get the address to write
ld_r2 str_prompt_address
call PrintStr
ld_r2 mem_e000
ld_r3 8
call ReadStr
ld_r2 mem_e000
call ConvertHex
cp_r0 -1
jp_eq cmd_write_invalid
str_r0 mem_addr
ld_r2 str_prompt_hex
call PrintStr
cmd_write_loop:
# Clear the buffer
ld_r3 mem_e000 + 2
ld_r0 0
strb_r0_r3
dec_r3
strb_r0_r3
dec_r3
cmd_write_loop_first:
# Get the first nybble
copr_getc
strb_r0_r3
ld_r2_r3
# Check if it's the end or invalid
cp_r0 '.'
jp_eq cmd_write_end
cp_r0 '\n'
jp_eq cmd_write_loop_first
# Try to convert the nybble
push_r3
call ConvertHex
pop_r3
cp_r0 -1
jp_eq cmd_write_loop_first
inc_r3
cmd_write_loop_second:
# Get the second nybble
copr_getc
strb_r0_r3
ld_r2_r3
# Check if it's the end or invalid
cp_r0 '.'
jp_eq cmd_write_end
cp_r0 '\n'
jp_eq cmd_write_loop_second
# Try to convert the nybble
push_r3
call ConvertHex
pop_r3
cp_r0 -1
jp_eq cmd_write_loop_second
# Convert and store the full byte
dec_r3
ld_r2_r3
call ConvertHex
ldr_r1 mem_addr
strb_r0_r1
inc_r1
str_r1 mem_addr
jp cmd_write_loop # 0xf1d0
cmd_write_end:
# Read until newline
copr_getc
cp_r0 '\n'
jp_ne cmd_write_end
ld_r2 str_loaded
call PrintStr
jp main_cmd_loop
cmd_write_invalid:
ld_r2 str_error_invalid_input
call PrintStr
jp main_cmd_loop
cmd_print:
# Get the string to print
ld_r2 str_prompt_address
call PrintStr
ld_r2 mem_e000
ld_r3 8
call ReadStr
ld_r2 mem_e000
call ConvertHex
ld_r2_r0
call PrintStr
jp main_cmd_loop
cmd_exec:
# Get the address to execute
ld_r2 str_prompt_address
call PrintStr
ld_r2 mem_e000
ld_r3 8
call ReadStr
ld_r2 mem_e000
call ConvertHex
# Prompt the user to execute the address
push_r0
str_r0 mem_addr
ld_r2 str_prompt_exec
call PrintStr
ld_r2 mem_e000
ld_r3 8
call ReadStr
ldrb_r0 mem_e000
cp_r0 'Y'
jp_eq cmd_exec_go
cp_r0 'y'
jp_eq cmd_exec_go
# Cancel the call
ld_r2 str_error_cancelled
call PrintStr
pop_r0
jp main_cmd_loop
cmd_exec_go:
# Call the function
pop_r3
call_r3
jp main_cmd_loop
cmd_cont:
ld_r2 str_continuing
call PrintStr
# Restore register state and unpause
ldr_r0 mem_save_r0
ldr_r1 mem_save_r1
ldr_r2 mem_save_r2
ldr_r3 mem_save_r3
ret
cmd_list:
ld_r2 str_file_list_header
call PrintStr
# Read directory
ld_r0 0
ld_r1 mem_e000
copr_readblk
ld_r3 mem_e000
cmd_list_loop:
ldrb_r0_r3
cp_r0 0
jp_eq cmd_list_next
# Store block
push_r3
strb_r0 mem_data
inc_r3
ldr_r0_r3
# Store size
push_r3
str_r0 mem_addr
# Print block and size
ld_r2 str_file_list_entry
call PrintStr
pop_r3
# Print filename
inc_r3
inc_r3
ld_r2_r3
call PrintStr
ld_r0 '\n'
copr_putc
pop_r3
cmd_list_next:
add_r3 0x10
cp_r3 mem_ef00
jp_ne cmd_list_loop
jp main_cmd_loop
cmd_undoc:
ld_r2 str_undoc
call PrintStr
jp main_cmd_loop
cmd_readfile:
ld_r2 str_prompt_filename
call PrintStr
# Read directory
ld_r0 0
ld_r1 mem_e000
copr_readblk
# Get filename to read
ld_r2 mem_efb0
ld_r3 0x10
call ReadStr
cp_r3 0
jp_eq cmd_readfile_error_too_long
ld_r2 mem_efb0
call StrTrim
ld_r3 mem_e000 + 3
cmd_readfile_loop:
# Check if the filename matches
ld_r2 mem_efb0
push_r3
call StrCmp
pop_r3
cp_r0 0
jp_eq cmd_readfile_match
add_r3 0x10
cp_r3 mem_ef00 + 3
jp_eq cmd_readfile_error_not_found
jp cmd_readfile_loop
cmd_readfile_match:
# Read file block
dec_r3
dec_r3
dec_r3
ldrb_r0_r3
# Read file size
inc_r3
ldr_r1_r3
# Read file into memory
push_r1
ld_r1 mem_e000
copr_readblk
# Prompt for address to write to
ld_r2 str_prompt_address
call PrintStr
ld_r2 mem_efe0
ld_r3 0x10
call ReadStr
ld_r2 mem_efe0
call ConvertHex
pop_r1
cp_r0 -1
jp_eq cmd_readfile_error_invalid_input
# Copy the data
ld_r2_r0
ld_r3 mem_e000
call MemCpy
ld_r2 str_loaded
call PrintStr
jp main_cmd_loop
cmd_readfile_error_not_found:
ld_r2 str_error_not_found
call PrintStr
jp main_cmd_loop
cmd_readfile_error_too_long:
ld_r2 str_error_too_long
call PrintStr
jp main_cmd_loop
cmd_readfile_error_invalid_input:
ld_r2 str_error_invalid_input
call PrintStr
jp main_cmd_loop
str_intro:
.ascii "======================================================================\r\n"
.ascii "Welcome to Glitch Research Laboratory Network: Test Server 2 (GRLTS02)\r\n"
.ascii "======================================================================\r\n"
.ascii "This machine requires authentication.\r\n\0"
str_error_too_long:
.ascii "! Input too long error.\n\0"
str_error_bad_command:
.ascii "! Bad command error (h for help).\n\0"
str_error_invalid_input:
.ascii "! Invalid input error.\n\0"
str_prompt_address:
.ascii "> Which address? \0"
str_prompt_lines:
.ascii "> How many lines? \0"
str_prompt_exec:
.ascii "> Really exec at "
text_ram_word mem_addr
.ascii "? Type Y if so: \0"
str_error_cancelled:
.ascii "! Cancelled action error.\n\0"
str_continuing:
.ascii "Continuing.\n\0"
str_loaded:
.ascii "Loaded.\n\0"
str_dry_stack:
.ascii "! Dry stack. Halting machine.\n\0"
str_prompt_filename:
.ascii "> Filename? \0"
str_error_not_found:
.ascii "! File not found error.\n\0"
str_prompt_hex:
.ascii "> Enter hex data. End with dot \".\" + newline:\n\0"
str_undoc:
.ascii "Wow, undocumented monitor command! FOOLS2023_{Secret"
text_ram_word 0xe000
.ascii "x"
text_ram_word 0xe001
.ascii "Command}\n\0"
str_help:
.ascii "Available commands:\n"
.ascii "r :: print memory as hex\n"
.ascii "p :: print memory as text\n"
.ascii "w :: write hex data to memory\n"
.ascii "x :: execute memory\n"
.ascii "rf :: load memory from file\n"
.ascii "ls :: print file index\n"
.ascii "h :: print this help message\n"
.ascii "c :: exit monitor and continue\n"
.ascii "Please enter hex numbers when prompted.\n"
.ascii "If necessary for debugging, you can break into monitor\n"
.ascii "with instruction BRK (0x00) and continue with 'c'\n"
.ascii "Note: memory region E000-FFFF is used by monitor\n\0"
str_file_list_header:
.ascii "BLK SIZE NAME\n"
.ascii "=======================\n\0"
str_file_list_entry:
text_ram_byte mem_data
.ascii " "
text_ram_word mem_addr
.ascii " \0" # 0xfa97
str_ready:
.ascii "Ready.\n"
.ascii "> \0"
str_breakpoint:
.ascii "*** BREAK INTO MONITOR AT $"
text_ram_word mem_info_pc
.ascii " ***\n"
.ascii "R0=$"
text_ram_word mem_save_r0
.ascii " R1=$"
text_ram_word mem_save_r1
.ascii " R2=$"
text_ram_word mem_save_r2
.ascii " R3=$"
text_ram_word mem_save_r3
.ascii "\n"
.ascii "SP=$"
text_ram_word mem_info_sp
.ascii " ["
text_ram_byte mem_info_stack + 0
text_ram_byte mem_info_stack + 1
text_ram_byte mem_info_stack + 2
text_ram_byte mem_info_stack + 3
text_ram_byte mem_info_stack + 4
text_ram_byte mem_info_stack + 5
text_ram_byte mem_info_stack + 6
text_ram_byte mem_info_stack + 7
text_ram_byte mem_info_stack + 8
text_ram_byte mem_info_stack + 9
text_ram_byte mem_info_stack + 10
text_ram_byte mem_info_stack + 11
.ascii "]\n\0"
str_hexdump:
text_ram_word mem_addr
.ascii " | "
text_ram_byte mem_data + 0
.ascii " "
text_ram_byte mem_data + 1
.ascii " "
text_ram_byte mem_data + 2
.ascii " "
text_ram_byte mem_data + 3
.ascii " "
text_ram_byte mem_data + 4
.ascii " "
text_ram_byte mem_data + 5
.ascii " "
text_ram_byte mem_data + 6
.ascii " "
text_ram_byte mem_data + 7
.ascii "\n\0"
mem_save_r0:
.2byte 0
mem_save_r1:
.2byte 0
mem_save_r2:
.2byte 0
mem_save_r3:
.2byte 0
mem_info_sp:
.2byte 0
mem_info_pc:
.2byte 0
mem_info_stack:
.fill 12
mem_data:
.fill 8
mem_addr:
.2byte 0
.fill 0xf00 - (. - _start)
stack:
.fill 0xf0
entry:
.fill 0x10