def test(self): # Disassemble & assemble unit tests unit_tests = [("ADD R1, 2", "6108")] unit_tests += [("JMP 0xC3FA38", "d9c8c3fa")] unit_tests += [("SLT3 R0, R8, R10", "08a2")] unit_tests += [("SB R9, (R4)", "0948")] unit_tests += [("SSARB 3(GP)", "13ec")] unit_tests += [("SWCPI C13, (R2+)", "3d20")] unit_tests += [("ADD3 R2, SP, 0x1C", "421c")] unit_tests += [("SW R7, 0x50(SP)", "4752")] for mn_str, mn_hex in unit_tests: print("-" * 49) # Tests separation # Disassemble mn_bin = decode_hex(mn_hex) mn = mn_mep.dis(mn_bin, "b") print("dis: %s -> %s" % (mn_hex.rjust(20), str(mn).rjust(20))) assert (str(mn) == mn_str) # disassemble assertion # Assemble and return all possible candidates instr = mn_mep.fromstring(str(mn), "b") instr.mode = "b" asm_list = [encode_hex(i).decode() for i in mn_mep.asm(instr)] # Print the results print("asm: %s -> %s" % (mn_str.rjust(20), ", ".join(asm_list).rjust(20))) assert (mn_hex in asm_list) # assemble assertion
def _check_state(self): """Check the current state against the concrete one""" errors = [] # List of DriftInfo for symbol in self.symb.modified_expr: # Do not consider PC if symbol in [self.ir_arch.pc, self.ir_arch.IRDst]: continue # Consider only concrete values symb_value = self.eval_expr(symbol) if not symb_value.is_int(): continue symb_value = int(symb_value) # Check computed values against real ones if symbol.is_id(): if hasattr(self.jitter.cpu, symbol.name): value = getattr(self.jitter.cpu, symbol.name) if value != symb_value: errors.append(DriftInfo(symbol, symb_value, value)) elif symbol.is_mem() and symbol.ptr.is_int(): value_chr = self.jitter.vm.get_mem(int(symbol.ptr), symbol.size // 8) exp_value = int(encode_hex(value_chr[::-1]), 16) if exp_value != symb_value: errors.append(DriftInfo(symbol, symb_value, exp_value)) # Check for drift, and act accordingly if errors: raise DriftException(errors)
def read_memory(self, addr, size): except_flag_vm = self.dbg.myjit.vm.get_exception() try: return encode_hex(self.dbg.get_mem_raw(addr, size)) except RuntimeError: self.dbg.myjit.vm.set_exception(except_flag_vm) return b"00" * size
def test(self): # Disassemble & assemble unit tests unit_tests = [("ADD R1, 2", "6108")] unit_tests += [("JMP 0xC3FA38", "d9c8c3fa")] unit_tests += [("SLT3 R0, R8, R10", "08a2")] unit_tests += [("SB R9, (R4)", "0948")] unit_tests += [("SSARB 3(GP)", "13ec")] unit_tests += [("SWCPI C13, (R2+)", "3d20")] unit_tests += [("ADD3 R2, SP, 0x1C", "421c")] unit_tests += [("SW R7, 0x50(SP)", "4752")] for mn_str, mn_hex in unit_tests: print("-" * 49) # Tests separation # Dissassemble mn_bin = decode_hex(mn_hex) mn = mn_mep.dis(mn_bin, "b") print("dis: %s -> %s" % (mn_hex.rjust(20), str(mn).rjust(20))) assert(str(mn) == mn_str) # dissassemble assertion # Assemble and return all possible candidates instr = mn_mep.fromstring(str(mn), "b") instr.mode = "b" asm_list = [encode_hex(i).decode() for i in mn_mep.asm(instr)] # Print the results print("asm: %s -> %s" % ( mn_str.rjust(20), ", ".join(asm_list).rjust(20)) ) assert(mn_hex in asm_list) # assemble assertion
def _check_state(self): """Check the current state against the concrete one""" errors = [] # List of DriftInfo for symbol in self.symb.modified_expr: # Do not consider PC if symbol in [self.ir_arch.pc, self.ir_arch.IRDst]: continue # Consider only concrete values symb_value = self.eval_expr(symbol) if not symb_value.is_int(): continue symb_value = int(symb_value) # Check computed values against real ones if symbol.is_id(): if hasattr(self.jitter.cpu, symbol.name): value = getattr(self.jitter.cpu, symbol.name) if value != symb_value: errors.append(DriftInfo(symbol, symb_value, value)) elif symbol.is_mem() and symbol.ptr.is_int(): value_chr = self.jitter.vm.get_mem( int(symbol.ptr), symbol.size // 8 ) exp_value = int(encode_hex(value_chr[::-1]), 16) if exp_value != symb_value: errors.append(DriftInfo(symbol, symb_value, exp_value)) # Check for drift, and act accordingly if errors: raise DriftException(errors)
def mem_read(self, expr_mem): """Memory read wrapper for symbolic execution @expr_mem: ExprMem""" addr = expr_mem.ptr if not addr.is_int(): return super(EmulatedSymbExec, self).mem_read(expr_mem) addr = int(addr) size = expr_mem.size // 8 value = self.vm.get_mem(addr, size) if self.vm.is_little_endian(): value = value[::-1] self.vm.add_mem_read(addr, size) return m2_expr.ExprInt(int(encode_hex(value), 16), expr_mem.size)
def read_register(self, reg_num): reg_name = self.general_registers_order[reg_num] reg_value = self.read_register_by_name(reg_name) size = self.general_registers_size[reg_name] pack_token = "" if size == 1: pack_token = "<B" elif size == 2: pack_token = "<H" elif size == 4: pack_token = "<I" elif size == 8: pack_token = "<Q" else: raise NotImplementedError("Unknown size") return encode_hex(struct.pack(pack_token, reg_value))
def mem_read(self, expr_mem): """Memory read wrapper for symbolic execution @expr_mem: ExprMem""" addr = expr_mem.ptr if not addr.is_int(): return super(EmulatedSymbExec, self).mem_read(expr_mem) addr = int(addr) size = expr_mem.size // 8 value = self.cpu.get_mem(addr, size) if self.vm.is_little_endian(): value = value[::-1] self.vm.add_mem_read(addr, size) return m2_expr.ExprInt( int(encode_hex(value), 16), expr_mem.size )
("c8028406 FCMPGT FR4, FR2", "45f2"), ("c8019ca4 FDIV FR2, FR12", "23fc"), ("c800ce5e FLOAT FPUL, FR2", "2df2"), ("xxxxxxxx FMAC FR0, FR1, FR2", "1ef2"), ("c800b006 FMUL FR2, FR4", "22f4"), ("c805e412 FNEG FR14", "4dfe"), ("xxxxxxxx FSQRT FR14", "6dfe"), ("c8030400 FSUB FR4, FR2", "41f2"), ("c80303ba FTRC FR2, FPUL", "3df2"), ] for s, l in reg_tests_sh4: print("-" * 80) s = s[12:] b = h2i((l)) print(encode_hex(b)) mn = mn_sh4.dis(b, None) print([str(x) for x in mn.args]) print(s) print(mn) assert (str(mn) == s) l = mn_sh4.fromstring(s, loc_db, None) assert (str(l) == s) a = mn_sh4.asm(l) print([x for x in a]) print(repr(b)) assert (b in a) # speed test o = b"" for s, l, in reg_tests_sh4:
def compute_checksum(self, data): return encode_hex(int_to_byte(sum(map(ord, data)) % 256))
def check_instruction(mn_str, mn_hex, multi=None, offset=0): """Try to disassemble and assemble this instruction""" # Rename objdump registers names mn_str = re.sub("\$([0-9]+)", lambda m: "R"+m.group(1), mn_str) mn_str = mn_str.replace("$", "") # Disassemble mn = dis(mn_hex) mn.offset = offset if mn.dstflow(): # Remember ExprInt arguments sizes args_size = list() for i in range(len(mn.args)): if isinstance(mn.args[i], ExprInt): args_size.append(mn.args[i].size) else: args_size.append(None) # Adjust arguments values using the instruction offset loc_db = LocationDB() mn.dstflow2label(loc_db) # Convert ExprLoc to ExprInt for i in range(len(mn.args)): if args_size[i] is None: continue if isinstance(mn.args[i], ExprLoc): addr = loc_db.get_location_offset(mn.args[i].loc_key) mn.args[i] = ExprInt(addr, args_size[i]) print("dis: %s -> %s" % (mn_hex.rjust(20), str(mn).rjust(20))) assert(str(mn) == mn_str) # disassemble assertion # Assemble and return all possible candidates instr = mn_mep.fromstring(mn_str, "b") instr.offset = offset instr.mode = "b" if instr.offset: instr.fixDstOffset() asm_list = [encode_hex(i).decode() for i in mn_mep.asm(instr)] # Check instructions variants if multi: print("Instructions count:", len(asm_list)) assert(len(asm_list) == multi) # Ensure that variants correspond to the same disassembled instruction for mn_hex_tmp in asm_list: mn = dis(mn_hex_tmp) print("dis: %s -> %s" % (mn_hex_tmp.rjust(20), str(mn).rjust(20))) # Check the assembly result print( "asm: %s -> %s" % ( mn_str.rjust(20), ", ".join(asm_list).rjust(20) ) ) assert(mn_hex in asm_list) # assemble assertion
def send_string(self, s): self.send_queue.append(b"O" + encode_hex(s))
def process_messages(self): while self.recv_queue: msg = self.recv_queue.pop(0) buf = BytesIO(msg) msg_type = buf.read(1) self.send_queue.append(b"+") if msg_type == b"q": if msg.startswith(b"qSupported"): self.send_queue.append(b"PacketSize=3fff") elif msg.startswith(b"qC"): # Current thread self.send_queue.append(b"") elif msg.startswith(b"qAttached"): # Not supported self.send_queue.append(b"") elif msg.startswith(b"qTStatus"): # Not supported self.send_queue.append(b"") elif msg.startswith(b"qfThreadInfo"): # Not supported self.send_queue.append(b"") else: raise NotImplementedError() elif msg_type == b"H": # Set current thread self.send_queue.append(b"OK") elif msg_type == b"?": # Report why the target halted self.send_queue.append(self.status) # TRAP signal elif msg_type == b"g": # Report all general register values self.send_queue.append(self.report_general_register_values()) elif msg_type == b"p": # Read a specific register reg_num = int(buf.read(), 16) self.send_queue.append(self.read_register(reg_num)) elif msg_type == b"P": # Set a specific register reg_num, value = buf.read().split(b"=") reg_num = int(reg_num, 16) value = int(encode_hex(decode_hex(value)[::-1]), 16) self.set_register(reg_num, value) self.send_queue.append(b"OK") elif msg_type == b"m": # Read memory addr, size = (int(x, 16) for x in buf.read().split(b",", 1)) self.send_queue.append(self.read_memory(addr, size)) elif msg_type == b"k": # Kill self.sock.close() self.send_queue = [] self.sock = None elif msg_type == b"!": # Extending debugging will be used self.send_queue.append(b"OK") elif msg_type == b"v": if msg == b"vCont?": # Is vCont supported ? self.send_queue.append(b"") elif msg_type == b"s": # Step self.dbg.step() self.send_queue.append(b"S05") # TRAP signal elif msg_type == b"Z": # Add breakpoint or watchpoint bp_type = buf.read(1) if bp_type == b"0": # Exec breakpoint assert (buf.read(1) == b",") addr, size = (int(x, 16) for x in buf.read().split(b",", 1)) if size != 1: raise NotImplementedError("Bigger size") self.dbg.add_breakpoint(addr) self.send_queue.append(b"OK") elif bp_type == b"1": # Hardware BP assert (buf.read(1) == b",") addr, size = (int(x, 16) for x in buf.read().split(b",", 1)) self.dbg.add_memory_breakpoint(addr, size, read=True, write=True) self.send_queue.append(b"OK") elif bp_type in [b"2", b"3", b"4"]: # Memory breakpoint assert (buf.read(1) == b",") read = bp_type in [b"3", b"4"] write = bp_type in [b"2", b"4"] addr, size = (int(x, 16) for x in buf.read().split(b",", 1)) self.dbg.add_memory_breakpoint(addr, size, read=read, write=write) self.send_queue.append(b"OK") else: raise ValueError("Impossible value") elif msg_type == b"z": # Remove breakpoint or watchpoint bp_type = buf.read(1) if bp_type == b"0": # Exec breakpoint assert (buf.read(1) == b",") addr, size = (int(x, 16) for x in buf.read().split(b",", 1)) if size != 1: raise NotImplementedError("Bigger size") dbgsoft = self.dbg.get_breakpoint_by_addr(addr) assert (len(dbgsoft) == 1) self.dbg.remove_breakpoint(dbgsoft[0]) self.send_queue.append(b"OK") elif bp_type == b"1": # Hardware BP assert (buf.read(1) == b",") addr, size = (int(x, 16) for x in buf.read().split(b",", 1)) self.dbg.remove_memory_breakpoint_by_addr_access( addr, read=True, write=True) self.send_queue.append(b"OK") elif bp_type in [b"2", b"3", b"4"]: # Memory breakpoint assert (buf.read(1) == b",") read = bp_type in [b"3", b"4"] write = bp_type in [b"2", b"4"] addr, size = (int(x, 16) for x in buf.read().split(b",", 1)) self.dbg.remove_memory_breakpoint_by_addr_access( addr, read=read, write=write) self.send_queue.append(b"OK") else: raise ValueError("Impossible value") elif msg_type == b"c": # Continue self.status = b"" self.send_messages() ret = self.dbg.run() if isinstance(ret, debugging.DebugBreakpointSoft): self.status = b"S05" self.send_queue.append(b"S05") # TRAP signal elif isinstance(ret, ExceptionHandle): if ret == ExceptionHandle.memoryBreakpoint(): self.status = b"S05" self.send_queue.append(b"S05") else: raise NotImplementedError("Unknown Except") elif isinstance(ret, debugging.DebugBreakpointTerminate): # Connection should close, but keep it running as a TRAP # The connection will be close on instance destruction print(ret) self.status = b"S05" self.send_queue.append(b"S05") else: raise NotImplementedError() else: raise NotImplementedError("Not implemented: message type %r" % msg_type)
def process_messages(self): while self.recv_queue: msg = self.recv_queue.pop(0) buf = BytesIO(msg) msg_type = buf.read(1) self.send_queue.append(b"+") if msg_type == b"q": if msg.startswith(b"qSupported"): self.send_queue.append(b"PacketSize=3fff") elif msg.startswith(b"qC"): # Current thread self.send_queue.append(b"") elif msg.startswith(b"qAttached"): # Not supported self.send_queue.append(b"") elif msg.startswith(b"qTStatus"): # Not supported self.send_queue.append(b"") elif msg.startswith(b"qfThreadInfo"): # Not supported self.send_queue.append(b"") else: raise NotImplementedError() elif msg_type == b"H": # Set current thread self.send_queue.append(b"OK") elif msg_type == b"?": # Report why the target halted self.send_queue.append(self.status) # TRAP signal elif msg_type == b"g": # Report all general register values self.send_queue.append(self.report_general_register_values()) elif msg_type == b"p": # Read a specific register reg_num = int(buf.read(), 16) self.send_queue.append(self.read_register(reg_num)) elif msg_type == b"P": # Set a specific register reg_num, value = buf.read().split(b"=") reg_num = int(reg_num, 16) value = int(encode_hex(decode_hex(value)[::-1]), 16) self.set_register(reg_num, value) self.send_queue.append(b"OK") elif msg_type == b"m": # Read memory addr, size = (int(x, 16) for x in buf.read().split(b",", 1)) self.send_queue.append(self.read_memory(addr, size)) elif msg_type == b"k": # Kill self.sock.close() self.send_queue = [] self.sock = None elif msg_type == b"!": # Extending debugging will be used self.send_queue.append(b"OK") elif msg_type == b"v": if msg == b"vCont?": # Is vCont supported ? self.send_queue.append(b"") elif msg_type == b"s": # Step self.dbg.step() self.send_queue.append(b"S05") # TRAP signal elif msg_type == b"Z": # Add breakpoint or watchpoint bp_type = buf.read(1) if bp_type == b"0": # Exec breakpoint assert(buf.read(1) == b",") addr, size = (int(x, 16) for x in buf.read().split(b",", 1)) if size != 1: raise NotImplementedError("Bigger size") self.dbg.add_breakpoint(addr) self.send_queue.append(b"OK") elif bp_type == b"1": # Hardware BP assert(buf.read(1) == b",") addr, size = (int(x, 16) for x in buf.read().split(b",", 1)) self.dbg.add_memory_breakpoint( addr, size, read=True, write=True ) self.send_queue.append(b"OK") elif bp_type in [b"2", b"3", b"4"]: # Memory breakpoint assert(buf.read(1) == b",") read = bp_type in [b"3", b"4"] write = bp_type in [b"2", b"4"] addr, size = (int(x, 16) for x in buf.read().split(b",", 1)) self.dbg.add_memory_breakpoint( addr, size, read=read, write=write ) self.send_queue.append(b"OK") else: raise ValueError("Impossible value") elif msg_type == b"z": # Remove breakpoint or watchpoint bp_type = buf.read(1) if bp_type == b"0": # Exec breakpoint assert(buf.read(1) == b",") addr, size = (int(x, 16) for x in buf.read().split(b",", 1)) if size != 1: raise NotImplementedError("Bigger size") dbgsoft = self.dbg.get_breakpoint_by_addr(addr) assert(len(dbgsoft) == 1) self.dbg.remove_breakpoint(dbgsoft[0]) self.send_queue.append(b"OK") elif bp_type == b"1": # Hardware BP assert(buf.read(1) == b",") addr, size = (int(x, 16) for x in buf.read().split(b",", 1)) self.dbg.remove_memory_breakpoint_by_addr_access( addr, read=True, write=True ) self.send_queue.append(b"OK") elif bp_type in [b"2", b"3", b"4"]: # Memory breakpoint assert(buf.read(1) == b",") read = bp_type in [b"3", b"4"] write = bp_type in [b"2", b"4"] addr, size = (int(x, 16) for x in buf.read().split(b",", 1)) self.dbg.remove_memory_breakpoint_by_addr_access( addr, read=read, write=write ) self.send_queue.append(b"OK") else: raise ValueError("Impossible value") elif msg_type == b"c": # Continue self.status = b"" self.send_messages() ret = self.dbg.run() if isinstance(ret, debugging.DebugBreakpointSoft): self.status = b"S05" self.send_queue.append(b"S05") # TRAP signal elif isinstance(ret, ExceptionHandle): if ret == ExceptionHandle.memoryBreakpoint(): self.status = b"S05" self.send_queue.append(b"S05") else: raise NotImplementedError("Unknown Except") elif isinstance(ret, debugging.DebugBreakpointTerminate): # Connexion should close, but keep it running as a TRAP # The connexion will be close on instance destruction print(ret) self.status = b"S05" self.send_queue.append(b"S05") else: raise NotImplementedError() else: raise NotImplementedError( "Not implemented: message type %r" % msg_type )
("c805e412 FNEG FR14", "4dfe"), ("xxxxxxxx FSQRT FR14", "6dfe"), ("c8030400 FSUB FR4, FR2", "41f2"), ("c80303ba FTRC FR2, FPUL", "3df2"), ] for s, l in reg_tests_sh4: print("-" * 80) s = s[12:] b = h2i((l)) print(encode_hex(b)) mn = mn_sh4.dis(b, None) print([str(x) for x in mn.args]) print(s) print(mn) assert(str(mn) == s) l = mn_sh4.fromstring(s, loc_db, None) assert(str(l) == s) a = mn_sh4.asm(l) print([x for x in a]) print(repr(b)) assert(b in a) # speed test o = b""
('b', "XXXXXXXX SUBFIC R11, R31, 0x0", "217f0000"), ('b', "XXXXXXXX TW 0x5, R0, R3", "7ca01808"), ('b', "XXXXXXXX TWI 0x5, R0, 0x12", "0ca00012"), ('b', "XXXXXXXX XORI R9, R0, 0x62", "68090062"), ('b', "XXXXXXXX XORIS R10, R10, 0x8000", "6d4a8000"), ] ts = time.time() for mode, s, l, in reg_tests: print("-" * 80) s = s[12:] b = h2i(l) print("fromstring %r" % s) l = mn_ppc.fromstring(s, None, mode) for x in mn_ppc.asm(l): print('(%r, "XXXXXXXX %s", "%s"),' % (mode, l, encode_hex(x))) print("%s %r" % (mode, b)) mn = mn_ppc.dis(b, mode) print("dis args %s" % [(str(x), x.size) for x in mn.args]) print(s) print(mn) assert(str(mn).strip() == s) print('fromstring %r' % s) l = mn_ppc.fromstring(s, None, mode) print('str args %s' % [(str(x), x.size) for x in l.args]) assert(str(l).strip(' ') == s) a = mn_ppc.asm(l) print('asm result %s' % [x for x in a]) print(repr(b)) print(l.to_html())
jitter.run = False jitter.pc = 0 return True myjit.push_uint32_t(0x1337beef) myjit.add_breakpoint(0x1337beef, code_sentinelle) # Run myjit.init_run(run_addr) myjit.continue_run() # Check end assert myjit.run is False # Check resulting state / accessors assert myjit.cpu.EAX == 0 assert myjit.cpu.ECX == 4 # Check eval_expr eax = ExprId("RAX", 64)[:32] imm0, imm4, imm4_64 = ExprInt(0, 32), ExprInt(4, 32), ExprInt(4, 64) memdata = ExprMem(ExprInt(run_addr, 32), len(data) * 8) assert myjit.eval_expr(eax) == imm0 ## Due to ExprAssign construction, imm4 is "promoted" to imm4_64 assert myjit.eval_expr(ExprAssign(eax, imm4)) == imm4_64 assert myjit.eval_expr(eax) == imm4 ## Changes must be passed on myjit.cpu instance assert myjit.cpu.EAX == 4 ## Memory assert myjit.eval_expr(memdata).arg.arg == int(encode_hex(data[::-1]), 16)
jitter.pc = 0 return True myjit.push_uint32_t(0x1337beef) myjit.add_breakpoint(0x1337beef, code_sentinelle) # Run myjit.init_run(run_addr) myjit.continue_run() # Check end assert myjit.running is False # Check resulting state / accessors assert myjit.cpu.EAX == 0 assert myjit.cpu.ECX == 4 # Check eval_expr eax = ExprId("RAX", 64)[:32] imm0, imm4, imm4_64 = ExprInt(0, 32), ExprInt(4, 32), ExprInt(4, 64) memdata = ExprMem(ExprInt(run_addr, 32), len(data) * 8) assert myjit.eval_expr(eax) == imm0 ## Due to ExprAssign construction, imm4 is "promoted" to imm4_64 assert myjit.eval_expr(ExprAssign(eax, imm4)) == imm4_64 assert myjit.eval_expr(eax) == imm4 ## Changes must be passed on myjit.cpu instance assert myjit.cpu.EAX == 4 ## Memory assert int(myjit.eval_expr(memdata)) == int(encode_hex(data[::-1]), 16)