Last active
September 26, 2022 21:27
-
-
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
This file contains hidden or 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
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) |
This file contains hidden or 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
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") |
This file contains hidden or 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
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 |
This file contains hidden or 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
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