Skip to content

Instantly share code, notes, and snippets.

@M4GNV5
Created October 4, 2023 08:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save M4GNV5/5d72cb1301797b6efe488eb8c59b5aae to your computer and use it in GitHub Desktop.
Save M4GNV5/5d72cb1301797b6efe488eb8c59b5aae to your computer and use it in GitHub Desktop.
TeamItaly CTF 2023 disassembler for challenge secure comparator
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