Skip to content

Instantly share code, notes, and snippets.

@zommiommy
Last active September 26, 2022 21:27
Show Gist options
  • Save zommiommy/dba6292be04d96777bd9b26e95bb89f9 to your computer and use it in GitHub Desktop.
Save zommiommy/dba6292be04d96777bd9b26e95bb89f9 to your computer and use it in GitHub Desktop.
iki1vm-crackmeeva aka armando che mi fa' perdere tempo https://github.com/TeamItaly/TeamItalyCTF-2022/tree/master/CrackmeEVA
import struct
def u32(data):
return struct.unpack("i", data)[0]
def p32(data):
return struct.pack("i", data)
class Regs:
IP = 0
FLAG = 0
DATA_PTR = 0
RO_DATA_PTR = 0
R1 = 0
R2 = 0
R3 = 0
R4 = 0
R5 = 0
def reg_str(self, reg_num):
if reg_num == 0x81:
return "R2"
if reg_num == 0x82:
return "R4"
if reg_num == 0x83:
return "R1"
if reg_num == 0x84:
return "R5"
if reg_num == 0x85:
return "R3"
raise ValueError("reg_num %s"%reg_num)
def __getitem__(self, reg_num):
if reg_num == 0x81:
return self.R2
if reg_num == 0x82:
return self.R4
if reg_num == 0x83:
return self.R1
if reg_num == 0x84:
return self.R5
if reg_num == 0x85:
return self.R3
raise ValueError("reg_num %s"%reg_num)
def __setitem__(self, reg_num, value):
if isinstance(value, str):
value = ord(value)
if reg_num == 0x81:
self.R2 = value
return
if reg_num == 0x82:
self.R4 = value
return
if reg_num == 0x83:
self.R1 = value
return
if reg_num == 0x84:
self.R5 = value
return
if reg_num == 0x85:
self.R3 = value
return
raise ValueError("reg_num %s"%reg_num)
def dbg(self):
print(f"IP: {self.IP},FLAG: {self.FLAG}, DATA_PTR: {self.DATA_PTR}, RO_DATA_PTR: {self.RO_DATA_PTR}")
print(f"r1: {self.R1}, r2: {self.R2}, r3: {self.R3}, r4: {self.R4}, r5: {self.R5}")
with open("trace.log", "w") as f:
pass
def debug(fmt):
ip = int(fmt[:4])
if ip < 48:
return
with open("trace.log", "a") as f:
f.write(fmt)
f.write("\n")
with open("./crackme_eva.ik1vm", "rb") as f:
raw_bytes = f.read()
regs = Regs()
code_len = u32(raw_bytes[:4])
ro_data_len = u32(raw_bytes[4:8])
data_len = u32(raw_bytes[8:12])
code = raw_bytes[12:12 + code_len]
ro_data = raw_bytes[12 + code_len:12 + code_len + ro_data_len]
data = [0 for _ in range(data_len)]
stack = []
stdout = ""
stdin = "flag{" + "A" * 32 + "}"
instructions = 0
while True:
#regs.dbg()
start_ip = regs.IP
opcode = code[regs.IP]
if start_ip == 48:
print(bytes(data))
# div
if opcode == ord('R'):
regs.IP += 1
r1 = code[regs.IP]
regs.IP += 1
r2 = code[regs.IP]
debug(f"{start_ip:04} {opcode:02X} {repr(chr(opcode)):>6} {regs.reg_str(r1)} = {regs.reg_str(r1)}:{regs[r1]} / {regs.reg_str(r2)}:{regs[r2]}")
if regs[r2] == 0:
#raise ValueError("Division by zero")
regs[r1] = 0
else:
regs[r1] = regs[r1] / regs[r2]
# signed add
elif opcode == ord('W'):
regs.IP += 1
r1 = code[regs.IP]
regs.IP += 1
imm2 = code[regs.IP]
imm2 = struct.unpack("b", bytes([imm2]))[0] # read as signed
debug(f"{start_ip:04} {opcode:02X} {repr(chr(opcode)):>6} {regs.reg_str(r1)} = {regs.reg_str(r1)}:{regs[r1]} + {imm2}")
regs[r1] = (regs[r1] + imm2) & 0xff
# print imm
elif opcode == ord("X"):
regs.IP += 1
imm1 = code[regs.IP]
debug(f"{start_ip:04} {opcode:02X} {repr(chr(opcode)):>6} putchar imm {repr(chr(imm1))}")
stdout += chr(imm1)
# signed sub
elif opcode == ord("Y"):
regs.IP += 1
r1 = code[regs.IP]
regs.IP += 1
imm2 = code[regs.IP]
imm2 = struct.unpack("b", bytes([imm2]))[0] # read as signed
debug(f"{start_ip:04} {opcode:02X} {repr(chr(opcode)):>6} {regs.reg_str(r1)} = {regs.reg_str(r1)}:{regs[r1]} - {imm2}")
regs[r1] = (regs[r1] - imm2) & 0xff
# ret
elif opcode == ord("i"):
regs.IP = stack.pop()
debug(f"{start_ip:04} {opcode:02X} {repr(chr(opcode)):>6} ret {regs.IP + 1:04}")
# <
elif opcode == ord("q"):
regs.IP += 1
r1 = code[regs.IP]
regs.IP += 1
r2 = code[regs.IP]
if regs[r1] < regs[r2]:
regs.FLAG = 1
else:
regs.FLAG = 0
debug(f"{start_ip:04} {opcode:02X} {repr(chr(opcode)):>6} FLAG:{regs.FLAG} = {regs.reg_str(r1)}:{regs[r1]} < {regs.reg_str(r2)}:{regs[r2]}")
# call
elif opcode == ord("s"):
arg1 = code[regs.IP + 1]
arg2 = code[regs.IP + 2]
stack.append(regs.IP + 3)
if arg1 == 0:
offset = arg2
else:
offset = -arg2
regs.IP += 3 + offset - 1
debug(f"{start_ip:04} {opcode:02X} {repr(chr(opcode)):>6} call arg1:{arg1} arg2:{arg2} offset:{offset} IP:{regs.IP}\n")
# check FLAGs reg
elif opcode == ord("t"):
debug(f"{start_ip:04} {opcode:02X} {repr(chr(opcode)):>6} FLAG:{int(regs.FLAG == 0)} = FLAG:{regs.FLAG} == 0")
if regs.FLAG == 0:
regs.FLAG = 1
else:
regs.FLAG = 0
# store
elif opcode == ord("u"):
regs.IP += 1
r1 = code[regs.IP]
debug(f"{start_ip:04} {opcode:02X} {repr(chr(opcode)):>6} store DATA_PTR:{regs.DATA_PTR} = {regs.reg_str(r1)}:{regs[r1]}")
data[regs.DATA_PTR] = regs[r1]
# eq ==
elif opcode == ord("v"):
regs.IP += 1
r1 = code[regs.IP]
regs.IP += 1
r2 = code[regs.IP]
if regs[r1] == regs[r2]:
regs.FLAG = 1
else:
regs.FLAG = 0
debug(f"{start_ip:04} {opcode:02X} {repr(chr(opcode)):>6} FLAG:{regs.FLAG} = {regs.reg_str(r1)}:{regs[r1]} == {regs.reg_str(r2)}:{regs[r2]}")
# load ?
elif opcode == ord("x"):
imm1 = code[regs.IP + 1]
regs.IP += 2
r2 = code[regs.IP]
if imm1 == 0:
regs[r2] = data[regs.DATA_PTR]
debug(f"{start_ip:04} {opcode:02X} {repr(chr(opcode)):>6} {regs.reg_str(r2)} = DATA_PTR:{regs.DATA_PTR}:{data[regs.DATA_PTR]}")
else:
regs[r2] = ro_data[regs.RO_DATA_PTR]
debug(f"{start_ip:04} {opcode:02X} {repr(chr(opcode)):>6} {regs.reg_str(r2)} = RO_DATA_PTR:{regs.RO_DATA_PTR}:{ro_data[regs.RO_DATA_PTR]}")
# jump something flag check
elif opcode == 0x86:
if start_ip == 79:
regs.IP = 82
regs.FLAG = 0
continue
imm1 = code[regs.IP + 1]
imm2 = code[regs.IP + 2]
if regs.FLAG == 0:
regs.IP += 2
debug(f"{start_ip:04} {opcode:02X} {repr(chr(opcode)):>6} jz {regs.IP + 1:04} = {start_ip:04} + 2\n")
elif imm1 == 0:
regs.IP += imm2 - 1
regs.FLAG = 0
debug(f"{start_ip:04} {opcode:02X} {repr(chr(opcode)):>6} jnz {regs.IP + 1:04} = {start_ip:04} + {imm2}\n")
else:
regs.IP += ~imm2
regs.FLAG = 0
debug(f"{start_ip:04} {opcode:02X} {repr(chr(opcode)):>6} jnz {regs.IP + 1:04} = {start_ip:04} + {~imm2 + 1}\n")
# dec data ptr
elif opcode == 0x89:
regs.IP += 1
imm1 = code[regs.IP]
if imm1 == 0:
debug(f"{start_ip:04} {opcode:02X} {repr(chr(opcode)):>6} DATA_PTR:{regs.DATA_PTR} -= 1")
regs.DATA_PTR -= 1
else:
debug(f"{start_ip:04} {opcode:02X} {repr(chr(opcode)):>6} RO_DATA_PTR:{regs.RO_DATA_PTR} -= 1")
regs.RO_DATA_PTR -= 1
# inc data ptr
elif opcode == 0x90:
regs.IP += 1
imm1 = code[regs.IP]
if imm1 == 0:
debug(f"{start_ip:04} {opcode:02X} {repr(chr(opcode)):>6} DATA_PTR:{regs.DATA_PTR} += 1")
regs.DATA_PTR += 1
else:
debug(f"{start_ip:04} {opcode:02X} {repr(chr(opcode)):>6} RO_DATA_PTR:{regs.RO_DATA_PTR} += 1")
regs.RO_DATA_PTR += 1
# add
elif opcode == 0x91:
regs.IP += 1
r1 = code[regs.IP]
regs.IP += 1
r2 = code[regs.IP]
debug(f"{start_ip:04} {opcode:02X} {repr(chr(opcode)):>6} {regs.reg_str(r1)} = {regs.reg_str(r1)}:{regs[r1]} + {regs.reg_str(r2)}:{regs[r2]}")
regs[r1] = (regs[r1] + regs[r2]) & 0xff
# sub
elif opcode == 0x93:
regs.IP += 1
r1 = code[regs.IP]
regs.IP += 1
r2 = code[regs.IP]
debug(f"{start_ip:04} {opcode:02X} {repr(chr(opcode)):>6} {regs.reg_str(r1)} = {regs.reg_str(r1)}:{regs[r1]} - {regs.reg_str(r2)}:{regs[r2]}")
regs[r1] = (regs[r1] - regs[r2]) & 0xff
# mov
elif opcode == 0x96:
regs.IP += 1
r1 = code[regs.IP]
regs.IP += 1
r2 = code[regs.IP]
debug(f"{start_ip:04} {opcode:02X} {repr(chr(opcode)):>6} {regs.reg_str(r1)} = {regs.reg_str(r2)}:{regs[r2]}")
regs[r1] = regs[r2] & 0xff
# getchar
elif opcode == 0x97:
debug(f"{start_ip:04} {opcode:02X} {repr(chr(opcode)):>6} data[{regs.DATA_PTR}] getchar = {stdin[0]}")
data[regs.DATA_PTR] = stdin[0]
stdin = stdin[1:]
# putchar
elif opcode == 0x98:
regs.IP += 1
imm1 = code[regs.IP]
if imm1 == 0:
stdout += chr(data[regs.DATA_PTR])
debug(f"{start_ip:04} {opcode:02X} {repr(chr(opcode)):>6} putchar_data: {regs.DATA_PTR}:{repr(chr(data[regs.DATA_PTR]))}")
else:
stdout += chr(ro_data[regs.RO_DATA_PTR])
debug(f"{start_ip:04} {opcode:02X} {repr(chr(opcode)):>6} putchar_rodata: {regs.RO_DATA_PTR}:{repr(chr(ro_data[regs.RO_DATA_PTR]))}")
elif opcode == 0x99:
debug(f"{start_ip:04} EXIT {regs.R1}")
break
else:
pass
regs.IP += 1
instructions += 1
print(raw_bytes)
import struct
class Regs:
IP = 0
FLAG = 0
DATA_PTR = 0
RO_DATA_PTR = 0
R1 = 0
R2 = 0
R3 = 0
R4 = 0
R5 = 0
def reg_str(self, reg_num):
if reg_num == 0x81:
return "R2"
if reg_num == 0x82:
return "R4"
if reg_num == 0x83:
return "R1"
if reg_num == 0x84:
return "R5"
if reg_num == 0x85:
return "R3"
raise ValueError("reg_num %s"%reg_num)
def __getitem__(self, reg_num):
if reg_num == 0x81:
return self.R2
if reg_num == 0x82:
return self.R4
if reg_num == 0x83:
return self.R1
if reg_num == 0x84:
return self.R5
if reg_num == 0x85:
return self.R3
raise ValueError("reg_num %s"%reg_num)
def __setitem__(self, reg_num, value):
if isinstance(value, str):
value = ord(value)
if reg_num == 0x81:
self.R2 = value
return
if reg_num == 0x82:
self.R4 = value
return
if reg_num == 0x83:
self.R1 = value
return
if reg_num == 0x84:
self.R5 = value
return
if reg_num == 0x85:
self.R3 = value
return
raise ValueError("reg_num %s"%reg_num)
def dbg(self):
print(f"IP: {self.IP},FLAG: {self.FLAG}, DATA_PTR: {self.DATA_PTR}, RO_DATA_PTR: {self.RO_DATA_PTR}")
print(f"r1: {self.R1}, r2: {self.R2}, r3: {self.R3}, r4: {self.R4}, r5: {self.R5}")
def diassemble(code, f):
regs = Regs()
IP = 0
opcode = code[0]
# div
if opcode == ord('R'):
IP += 1
r1 = code[IP]
IP += 1
r2 = code[IP]
f.write(f"{regs.reg_str(r1)} = {regs.reg_str(r1)} / {regs.reg_str(r2)}\n")
# signed add
elif opcode == ord('W'):
IP += 1
r1 = code[IP]
IP += 1
imm2 = code[IP]
f.write(f"{regs.reg_str(r1)} = {regs.reg_str(r1)} + {imm2}\n")
# print imm
elif opcode == ord("X"):
IP += 1
imm1 = code[IP]
f.write(f"putchar imm {repr(chr(imm1))}\n")
# signed sub
elif opcode == ord("Y"):
IP += 1
r1 = code[IP]
IP += 1
imm2 = code[IP]
f.write(f"{regs.reg_str(r1)} = {regs.reg_str(r1)} - {imm2}\n")
# ret
elif opcode == ord("i"):
IP = stack.pop()
f.write(f"ret {IP + 1:04}\n")
# <
elif opcode == ord("q"):
IP += 1
r1 = code[IP]
IP += 1
r2 = code[IP]
f.write(f"FLAG = {regs.reg_str(r1)} < {regs.reg_str(r2)}\n")
# call
elif opcode == ord("s"):
arg1 = code[IP + 1]
arg2 = code[IP + 2]
stack.append(IP + 3)
new_addr = IP + 3 + offset - 1
f.write(f"call arg1:{arg1} arg2:if R1 == 0 {{ {arg2} }} else {{ -{arg2} }} offset:{offset} IP:{new_addr}\n\n\n")
# check FLAGs reg
elif opcode == ord("t"):
f.write(f"FLAG = FLAG == 0\n")
# store
elif opcode == ord("u"):
IP += 1
r1 = code[IP]
f.write(f"store data[{regs.DATA_PTR}] = {regs.reg_str(r1)}\n")
# eq ==
elif opcode == ord("v"):
IP += 1
r1 = code[IP]
IP += 1
r2 = code[IP]
f.write(f"FLAG = {regs.reg_str(r1)} == {regs.reg_str(r2)}\n")
# load ?
elif opcode == ord("x"):
imm1 = code[IP + 1]
IP += 2
r2 = code[IP]
if imm1 == 0:
f.write(f"{regs.reg_str(r2)} = data[DATA_PTR]\n")
else:
f.write(f"{regs.reg_str(r2)} = ro_data[RO_DATA_PTR]\n")
# jump something flag check
elif opcode == 0x86:
imm1 = code[IP + 1]
imm2 = code[IP + 2]
# jmp case
if imm1 == 0:
offset = imm2
else:
offset = (~imm2) + 1
f.write(f"jnz {offset}\n\n\n")
# dec data ptr
elif opcode == 0x89:
IP += 1
imm1 = code[IP]
if imm1 == 0:
f.write(f"DATA_PTR -= 1\n")
regs.DATA_PTR -= 1
else:
f.write(f"RO_DATA_PTR -= 1\n")
regs.RO_DATA_PTR -= 1
# inc data ptr
elif opcode == 0x90:
IP += 1
imm1 = code[IP]
if imm1 == 0:
f.write(f"DATA_PTR += 1\n")
regs.DATA_PTR += 1
else:
f.write(f"RO_DATA_PTR += 1\n")
regs.RO_DATA_PTR += 1
# add
elif opcode == 0x91:
IP += 1
r1 = code[IP]
IP += 1
r2 = code[IP]
f.write(f"{regs.reg_str(r1)} = {regs.reg_str(r1)} + {regs.reg_str(r2)}\n")
# sub
elif opcode == 0x93:
IP += 1
r1 = code[IP]
IP += 1
r2 = code[IP]
f.write(f"{regs.reg_str(r1)} = {regs.reg_str(r1)} - {regs.reg_str(r2)}\n")
# mov
elif opcode == 0x96:
IP += 1
r1 = code[IP]
IP += 1
r2 = code[IP]
f.write(f"{regs.reg_str(r1)} = {regs.reg_str(r2)}\n")
# getchar
elif opcode == 0x97:
f.write(f"data[DATA_PTR] = getchar()\n")
# putchar
elif opcode == 0x98:
IP += 1
imm1 = code[IP]
if imm1 == 0:
f.write(f"putchar(data[DATA_PTR])\n")
else:
f.write(f"putchar(ro_data[RO_DATA_PTR])\n")
elif opcode == 0x99:
f.write(f"EXIT {regs.R1}\n\n\n")
gdb.execute("b *0x004014fb")
gdb.execute("b getchar")
gdb.execute("r ./crackme_eva.ik1vm")
stdin = iter("flag{" + "A" * 32 + "}")
base_address = int(gdb.parse_and_eval("vm.code"))
with open("trace_gdb.log", "w") as f:
pass
with open("trace_gdb.log", "a") as f:
while True:
rip = int(gdb.parse_and_eval("$rip"))
if rip == 0x004014fb:
r1 = int(gdb.parse_and_eval("vm.reg.reg1" ))
r2 = int(gdb.parse_and_eval("vm.reg.reg2" ))
r3 = int(gdb.parse_and_eval("vm.reg.reg3" ))
r4 = int(gdb.parse_and_eval("vm.reg.reg4" ))
r5 = int(gdb.parse_and_eval("vm.reg.reg5" ))
flag = int(gdb.parse_and_eval("vm.reg.flag" ))
data_ptr = int(gdb.parse_and_eval("vm.reg.data_ptr" ))
ro_data_ptr = int(gdb.parse_and_eval("vm.reg.ro_data_ptr"))
ip = int(gdb.parse_and_eval("vm.reg.IP")) - base_address
code = struct.pack("l", int(gdb.parse_and_eval("*(long *)vm.reg.IP")))
f.write("ip: {:04} opcode: {} flag: {} data_ptr: {}, ro_data_ptr: {}\n".format(ip, code[0], flag, data_ptr, ro_data_ptr))
f.write("r1: {} r2: {} r3: {} r4: {} r5: {}\n".format(r1, r2, r3, r4, r5))
f.write("code: {}\n".format(code))
diassemble(code, f)
else:
gdb.execute("return {}".format(ord(next(stdin))))
gdb.execute("c")
import struct
def u32(data):
return struct.unpack("i", data)[0]
def p32(data):
return struct.pack("i", data)
class Regs:
IP = 0
FLAG = 0
DATA_PTR = 0
RO_DATA_PTR = 0
R1 = 0
R2 = 0
R3 = 0
R4 = 0
R5 = 0
def reg_str(self, reg_num):
if reg_num == 0x81:
return "R2"
if reg_num == 0x82:
return "R4"
if reg_num == 0x83:
return "R1"
if reg_num == 0x84:
return "R5"
if reg_num == 0x85:
return "R3"
raise ValueError("reg_num %s"%reg_num)
with open("./crackme_eva.ik1vm", "rb") as f:
raw_bytes = f.read()
code_len = u32(raw_bytes[:4])
ro_data_len = u32(raw_bytes[4:8])
data_len = u32(raw_bytes[8:12])
code = raw_bytes[12:12 + code_len]
ro_data = raw_bytes[12 + code_len:12 + code_len + ro_data_len]
data = [0 for _ in range(data_len)]
regs = Regs()
stack = []
stdout = ""
bb = []
with open("dis_lin.log", "w") as f:
while regs.IP < len(code):
start_ip = regs.IP
opcode = code[regs.IP]
# div
if opcode == ord('R'):
regs.IP += 1
r1 = code[regs.IP]
regs.IP += 1
r2 = code[regs.IP]
f.write(f"{start_ip:04} {regs.reg_str(r1)} = {regs.reg_str(r1)} / {regs.reg_str(r2)}\n")
# signed add
elif opcode == ord('W'):
regs.IP += 1
r1 = code[regs.IP]
regs.IP += 1
imm2 = code[regs.IP]
f.write(f"{start_ip:04} {regs.reg_str(r1)} = {regs.reg_str(r1)} + {imm2}\n")
# print imm
elif opcode == ord("X"):
regs.IP += 1
imm1 = code[regs.IP]
f.write(f"{start_ip:04} putchar imm {repr(chr(imm1))}\n")
# signed sub
elif opcode == ord("Y"):
regs.IP += 1
r1 = code[regs.IP]
regs.IP += 1
imm2 = code[regs.IP]
f.write(f"{start_ip:04} {regs.reg_str(r1)} = {regs.reg_str(r1)} - {imm2}\n")
# ret
elif opcode == ord("i"):
regs.IP = stack.pop()
f.write(f"{start_ip:04} ret {regs.IP + 1:04}\n")
# <
elif opcode == ord("q"):
regs.IP += 1
r1 = code[regs.IP]
regs.IP += 1
r2 = code[regs.IP]
f.write(f"{start_ip:04} FLAG = {regs.reg_str(r1)} < {regs.reg_str(r2)}\n")
# call
elif opcode == ord("s"):
arg1 = code[regs.IP + 1]
arg2 = code[regs.IP + 2]
stack.append(regs.IP + 3)
new_addr = regs.IP + 3 + offset - 1
f.write(f"{start_ip:04} call arg1:{arg1} arg2:if R1 == 0 {{ {arg2} }} else {{ -{arg2} }} offset:{offset} IP:{new_addr}\n")
# check FLAGs reg
elif opcode == ord("t"):
f.write(f"{start_ip:04} FLAG = FLAG == 0\n")
# store
elif opcode == ord("u"):
regs.IP += 1
r1 = code[regs.IP]
f.write(f"{start_ip:04} store data[{regs.DATA_PTR}] = {regs.reg_str(r1)}\n")
# eq ==
elif opcode == ord("v"):
regs.IP += 1
r1 = code[regs.IP]
regs.IP += 1
r2 = code[regs.IP]
f.write(f"{start_ip:04} FLAG = {regs.reg_str(r1)} == {regs.reg_str(r2)}\n")
# load ?
elif opcode == ord("x"):
imm1 = code[regs.IP + 1]
regs.IP += 2
r2 = code[regs.IP]
if imm1 == 0:
f.write(f"{start_ip:04} {regs.reg_str(r2)} = data[DATA_PTR]\n")
else:
f.write(f"{start_ip:04} {regs.reg_str(r2)} = ro_data[RO_DATA_PTR]\n")
# jump something flag check
elif opcode == 0x86:
imm1 = code[regs.IP + 1]
imm2 = code[regs.IP + 2]
# Fall case
regs.IP = start_ip + 2
# jmp case
if imm1 == 0:
offset = imm2
else:
offset = (~imm2) + 1
f.write(f"{start_ip:04} jnz {start_ip:04} + {offset} = {start_ip + offset:04}\n")
# dec data ptr
elif opcode == 0x89:
regs.IP += 1
imm1 = code[regs.IP]
if imm1 == 0:
f.write(f"{start_ip:04} DATA_PTR -= 1\n")
regs.DATA_PTR -= 1
else:
f.write(f"{start_ip:04} RO_DATA_PTR -= 1\n")
regs.RO_DATA_PTR -= 1
# inc data ptr
elif opcode == 0x90:
regs.IP += 1
imm1 = code[regs.IP]
if imm1 == 0:
f.write(f"{start_ip:04} DATA_PTR += 1\n")
regs.DATA_PTR += 1
else:
f.write(f"{start_ip:04} RO_DATA_PTR += 1\n")
regs.RO_DATA_PTR += 1
# add
elif opcode == 0x91:
regs.IP += 1
r1 = code[regs.IP]
regs.IP += 1
r2 = code[regs.IP]
f.write(f"{start_ip:04} {regs.reg_str(r1)} = {regs.reg_str(r1)} + {regs.reg_str(r2)}\n")
# sub
elif opcode == 0x93:
regs.IP += 1
r1 = code[regs.IP]
regs.IP += 1
r2 = code[regs.IP]
f.write(f"{start_ip:04} {regs.reg_str(r1)} = {regs.reg_str(r1)} - {regs.reg_str(r2)}\n")
# mov
elif opcode == 0x96:
regs.IP += 1
r1 = code[regs.IP]
regs.IP += 1
r2 = code[regs.IP]
f.write(f"{start_ip:04} {regs.reg_str(r1)} = {regs.reg_str(r2)}\n")
# getchar
elif opcode == 0x97:
f.write(f"{start_ip:04} data[DATA_PTR] = getchar()\n")
# putchar
elif opcode == 0x98:
regs.IP += 1
imm1 = code[regs.IP]
if imm1 == 0:
f.write(f"{start_ip:04} putchar(data[DATA_PTR])\n")
else:
f.write(f"{start_ip:04} putchar(ro_data[RO_DATA_PTR])\n")
elif opcode == 0x99:
f.write(f"EXIT {regs.R1}\n")
raise ValueError(1)
else:
raise ValueError("Unknown opcode %s"%opcode)
regs.IP += 1
import re
import struct
def u32(data):
return struct.unpack("i", data)[0]
def p32(data):
return struct.pack("i", data)
class Regs:
IP = 0
FLAG = 0
DATA_PTR = 0
RO_DATA_PTR = 0
R1 = 0
R2 = 0
R3 = 0
R4 = 0
R5 = 0
def reg_str(self, reg_num):
if reg_num == 0x81:
return "R2"
if reg_num == 0x82:
return "R4"
if reg_num == 0x83:
return "R1"
if reg_num == 0x84:
return "R5"
if reg_num == 0x85:
return "R3"
raise ValueError("reg_num %s"%reg_num)
with open("./crackme_eva.ik1vm", "rb") as f:
raw_bytes = f.read()
regs = Regs()
code_len = u32(raw_bytes[:4])
ro_data_len = u32(raw_bytes[4:8])
data_len = u32(raw_bytes[8:12])
code = raw_bytes[12:12 + code_len]
ro_data = raw_bytes[12 + code_len:12 + code_len + ro_data_len]
data = [0 for _ in range(data_len)]
stack = []
cfg = {}
edges = []
stdout = ""
instructions = 0
to_explore = [0]
while to_explore:
bb = []
entry_ip = to_explore.pop()
regs.IP = entry_ip
print(f"Exploring {entry_ip}")
while regs.IP < len(code):
start_ip = regs.IP
opcode = code[regs.IP]
# div
if opcode == ord('R'):
regs.IP += 1
r1 = code[regs.IP]
regs.IP += 1
r2 = code[regs.IP]
bb.append((start_ip, f"{regs.reg_str(r1)} = {regs.reg_str(r1)} / {regs.reg_str(r2)}"))
# signed add
elif opcode == ord('W'):
regs.IP += 1
r1 = code[regs.IP]
regs.IP += 1
imm2 = code[regs.IP]
bb.append((start_ip, f"{regs.reg_str(r1)} = {regs.reg_str(r1)} + {imm2}"))
# print imm
elif opcode == ord("X"):
regs.IP += 1
imm1 = code[regs.IP]
second_char = repr(repr(chr(imm1)))[2:-2]
if len(bb) > 0 and "putchar imm" in bb[-1]:
first_char = re.findall("putchar imm '(.+)'", bb[-1][1])[0]
bb[-1] = (bb[-1][0], f"puts '{first_char}{second_char}'")
elif len(bb) > 0 and "puts" in bb[-1]:
new_str = re.findall("puts '(.+)'", bb[-1][1])[0]
bb[-1] = (bb[-1][0], f"puts '{new_str}{second_char}'")
else:
bb.append((start_ip, f"putchar imm {repr(repr(chr(imm1)))[1:-1]}"))
# signed sub
elif opcode == ord("Y"):
regs.IP += 1
r1 = code[regs.IP]
regs.IP += 1
imm2 = code[regs.IP]
bb.append((start_ip, f"{regs.reg_str(r1)} = {regs.reg_str(r1)} - {imm2}"))
# ret
elif opcode == ord("i"):
bb.append((start_ip, f"ret"))
print(bb[-1])
break
# <
elif opcode == ord("q"):
regs.IP += 1
r1 = code[regs.IP]
regs.IP += 1
r2 = code[regs.IP]
bb.append((start_ip, f"FLAG = {regs.reg_str(r1)} < {regs.reg_str(r2)}"))
# call
elif opcode == ord("s"):
arg1 = code[regs.IP + 1]
arg2 = code[regs.IP + 2]
if arg1 == 0:
offset = arg2
else:
offset = -arg2
new_addr = regs.IP + 3 + offset
bb.append((start_ip, f"call offset:{offset} IP:{new_addr}"))
edges.append((entry_ip, new_addr, True))
if new_addr not in cfg:
to_explore.append(new_addr)
cfg.setdefault(new_addr, True)
new_addr = regs.IP + 3
edges.append((entry_ip, new_addr, False))
if new_addr not in cfg:
to_explore.append(new_addr)
cfg.setdefault(new_addr, False)
print(bb[-1])
break
# check FLAGs reg
elif opcode == ord("t"):
bb.append((start_ip, f"FLAG = FLAG == 0"))
# store
elif opcode == ord("u"):
regs.IP += 1
r1 = code[regs.IP]
bb.append((start_ip, f"store data[{regs.DATA_PTR}] = {regs.reg_str(r1)}"))
# eq ==
elif opcode == ord("v"):
regs.IP += 1
r1 = code[regs.IP]
regs.IP += 1
r2 = code[regs.IP]
bb.append((start_ip, f"FLAG = {regs.reg_str(r1)} == {regs.reg_str(r2)}"))
# load ?
elif opcode == ord("x"):
imm1 = code[regs.IP + 1]
regs.IP += 2
r2 = code[regs.IP]
if imm1 == 0:
bb.append((start_ip, f"{regs.reg_str(r2)} = data[DATA_PTR]"))
else:
bb.append((start_ip, f"{regs.reg_str(r2)} = ro_data[RO_DATA_PTR]"))
# jump something flag check
elif opcode == 0x86:
imm1 = code[regs.IP + 1]
imm2 = code[regs.IP + 2]
# Fall case
fall_addr = start_ip + 2 + 1
edges.append((entry_ip, fall_addr, False))
if fall_addr not in cfg:
to_explore.append(fall_addr)
cfg.setdefault(fall_addr, None)
# jmp case
if imm1 == 0:
offset = imm2
else:
offset = (~imm2) + 1
new_addr = start_ip + offset
edges.append((entry_ip, new_addr, True))
if new_addr not in cfg:
to_explore.append(new_addr)
cfg.setdefault(new_addr, None)
bb.append((start_ip, f"jnz {new_addr:04} = {start_ip:04} + {offset} else {fall_addr:04}\n"))
print(bb[-1])
break
# dec data ptr
elif opcode == 0x89:
regs.IP += 1
imm1 = code[regs.IP]
if imm1 == 0:
bb.append((start_ip, f"DATA_PTR -= 1"))
else:
bb.append((start_ip, f"RO_DATA_PTR -= 1"))
# inc data ptr
elif opcode == 0x90:
regs.IP += 1
imm1 = code[regs.IP]
if imm1 == 0:
bb.append((start_ip, f"DATA_PTR += 1"))
else:
bb.append((start_ip, f"RO_DATA_PTR += 1"))
# add
elif opcode == 0x91:
regs.IP += 1
r1 = code[regs.IP]
regs.IP += 1
r2 = code[regs.IP]
bb.append((start_ip, f"{regs.reg_str(r1)} = {regs.reg_str(r1)} + {regs.reg_str(r2)}"))
# sub
elif opcode == 0x93:
regs.IP += 1
r1 = code[regs.IP]
regs.IP += 1
r2 = code[regs.IP]
bb.append((start_ip, f"{regs.reg_str(r1)} = {regs.reg_str(r1)} - {regs.reg_str(r2)}"))
# mov
elif opcode == 0x96:
regs.IP += 1
r1 = code[regs.IP]
regs.IP += 1
r2 = code[regs.IP]
bb.append((start_ip, f"{regs.reg_str(r1)} = {regs.reg_str(r2)}"))
# getchar
elif opcode == 0x97:
bb.append((start_ip, f"data[DATA_PTR] = getchar()"))
# putchar
elif opcode == 0x98:
regs.IP += 1
imm1 = code[regs.IP]
if imm1 == 0:
bb.append((start_ip, f"putchar(data[DATA_PTR])"))
else:
bb.append((start_ip, f"putchar(ro_data[RO_DATA_PTR])"))
elif opcode == 0x99:
bb.append((start_ip, "EXIT R1}"))
print(bb[-1])
break
else:
bb.append((start_ip, f" Unknown opcode {opcode:02x} at {entry_ip:04}"))
break
regs.IP += 1
print(bb[-1])
cfg[entry_ip] = bb
import graphviz
dot = graphviz.Digraph()
comments = {
3: ["# while(*c++) putchar(c);"],
30: ["# data[:23] = ro_data[1587:1587 + 23 = 1611];"],
57: ["# data[23:23+38] = FLAG;"]
}
for addr, vals in cfg.items():
label = "".join(f"{x[0]:04} {x[1].strip()}\\l" for x in vals)
if addr in comments:
label = "".join(x.strip() + "\\l" for x in comments[addr]) + "\\l" + label
dot.node(str(addr), label, shape="box", labeljust="l")
for src, dst, color in sorted(list(set(edges))):
if color is None:
c = ""
elif color:
c = "red"
else:
c = "green"
dot.edge(str(src), str(dst), color=c)
with open("g.g", "w") as f:
f.write(dot.source)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment