Created
October 4, 2023 08:56
-
-
Save M4GNV5/5d72cb1301797b6efe488eb8c59b5aae to your computer and use it in GitHub Desktop.
TeamItaly CTF 2023 disassembler for challenge secure comparator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
syscall_table = { | |
128: "getc", | |
127: "putc", | |
42: "sleepOrHalt", | |
} | |
# from checker.bin call table | |
call_table = { | |
0: 0x90, | |
1: 0x400, | |
2: 0x420, | |
3: 0xf4, | |
4: 0x44c, | |
5: 0x474, | |
} | |
# the following two are manually labeled | |
func_names = { | |
0x400: "puts", | |
0x420: "gets", | |
} | |
comments = { | |
0x0018: "SECure COMParator v0.2", | |
0x0024: ">>>", | |
0x0078: "Skill issue", | |
0x0088: "Looks like a flag!", | |
} | |
def get_func_name(x): | |
x = call_table[x] | |
return func_names.get(x, f"func{x:04x}") | |
def decode_instruction(encoded): | |
op = encoded & 0xff | |
reg1 = (encoded >> 8) & 0x7 | |
reg2 = (encoded >> 11) & 0x7 | |
dest = (encoded >> 14) & 0x7 | |
imm14 = (encoded >> 17) & 0x3fff | |
imm8 = (encoded >> 17) & 0xff | |
match op: | |
case 0: | |
return f"r{dest} = r{reg1}" | |
case 1: | |
return f"r{dest} = #{hex(imm8)}" | |
case 2: | |
return f"r{dest} = r{reg1} + r{reg2}" | |
case 3: | |
return f"r{dest} = r{reg1} - r{reg2}" | |
case 4: | |
return f"r{dest} = r{reg1} * r{reg2}" | |
case 5: | |
return f"r{dest} = r{reg1} / r{reg2}" | |
case 6: | |
return f"r{dest} = r{reg1} & r{reg2}" | |
case 7: | |
return f"r{dest} = r{reg1} | r{reg2}" | |
case 8: | |
return f"r{dest} = r{reg1} ^ r{reg2}" | |
case 9: | |
return f"r{dest} = [disp]" | |
case 10: | |
return f"[disp] = r{reg1}" | |
case 11: | |
return f"r{dest} = syscall:{syscall_table[imm8]}()" | |
case 12: | |
return f"syscall:{syscall_table[imm8]}(r{reg1})" | |
case 13: | |
return f"jmp r{reg1}:r{reg2}" | |
case 14: | |
return f"jmp {imm14:04x}" | |
case 15: | |
return f"if(r{reg1} == r{reg2}) goto {imm14:04x}" | |
case 16: | |
return f"if(r{reg1} != r{reg2}) goto {imm14:04x}" | |
case 17: | |
return f"if(r{reg1} > r{reg2}) goto {imm14:04x}" | |
case 18: | |
return f"if(r{reg1} >= r{reg2}) goto {imm14:04x}" | |
case 19: | |
return f"disp = r{reg1}:r{reg2}" | |
case 20: | |
return f"disp += 1" | |
case 21: | |
return f"stack = r{reg1}:r{reg2}" | |
case 22: | |
return f"stack += 1" | |
case 23: | |
return f"stack -= 1" | |
case 24: | |
return f"call {get_func_name(imm8)}" | |
case 25: | |
return f"return" | |
case _: | |
return f"<unknown {op} r{dest} = r{reg1} ? r{reg2} ? {imm8} ? {imm14}" | |
# Open the binary file | |
file_path = 'checker.bin' # Replace with your file path | |
with open(file_path, 'rb') as file: | |
# Read the first 0x4000 bytes from the file | |
buffer_size = 0x4000 | |
data = file.read(buffer_size).rstrip(b'\x00') | |
# Iterate over the data in 4-byte chunks and call the parse function | |
last = None | |
printedStar = False | |
for i in range(0, len(data), 4): | |
if i in call_table.values(): | |
print(func_names.get(i, f"func{i:04x}") + ":") | |
if i in comments: | |
print("// " + comments[i]) | |
chunk = data[i:i + 4] | |
x = decode_instruction(int.from_bytes(chunk, byteorder='little')) | |
if x == last: | |
if not printedStar: | |
print("*") | |
printedStar = True | |
else: | |
print(f" {i:04x} : {x}") | |
last = x |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment