def begin_func(self, jitter): ''' Function called by miasm at the begin of every execution of the traced function ''' self.old_ret_addr = jitter.pop_uint64_t() jitter.push_uint64_t(0x1337beef) self.isTracing = True self.current_snapshot = Snapshot(self.abicls, self.machine) # Add the breakpoint to watch every memory read and write jitter.jit.symbexec.add_read_call(self.read_callback) jitter.jit.symbexec.add_write_call(self.write_callback) # Called before the execution of each basic bloc jitter.exec_cb = self.exec_callback for reg_name in self.reg_list: self.current_snapshot.add_input_register( reg_name, getattr(jitter.cpu, reg_name)) return True
def __parse_pin_output_file(self, traceFile): '''Parse the file created by the pintool in order to construct the trace''' trace = Trace() # Statefull elements started = False current_image_name = None # State machine for parsing for line in traceFile: infos = line.strip().split(' ') entry_type = infos[0] # Image loaded in memory # IMG <img_name> if entry_type == "IMG": img_name = infos[1] current_image_name = img_name continue # Symbol entry # S <symbol_addr> <symbol_name> elif entry_type == 'S': assert current_image_name is not None symbol_name = infos[2] symbol_addr = int(infos[1], 16) trace.add_symbol(current_image_name, symbol_name, symbol_addr) continue values = [int(v, 16) for v in infos[1:]] # Start of the learned function # Fields are registers value if entry_type == 'I': if not started: started = True current_snapshot = Snapshot(self.abicls, self.machine) for i, reg_name in enumerate(self.reg_list): current_snapshot.add_input_register(reg_name, values[i]) # Executed instructions address elif entry_type == '@': if started: current_snapshot.add_executed_instruction(values[0]) # Memory read access # Fields are read address, read size and read value elif entry_type == 'R': if started: current_snapshot.add_memory_read( values[0], values[1], values[2]) # Memory write access # Fields are writen address, writen size and writen value elif entry_type == 'W': if started: current_snapshot.add_memory_write( values[0], values[1], values[2]) # End of the learned function # Field are register value elif entry_type == 'O': if started: for i, reg_name in enumerate(self.reg_list): current_snapshot.add_output_register( reg_name, values[i]) # The learned function execution is over # Snapshot can be added to the trace started = False yield current_snapshot # Call to a function # CALL <caller_addr> <stack pointer> elif entry_type == "CALL": current_snapshot.add_call(values[0], values[1]) # Return from a function # RET <ret_addr> <stack pointer after> <ret value> elif entry_type == "RET": current_snapshot.add_ret(values[0], values[1], values[2])
def __parse_pin_output_file(self, traceFile): '''Parse the file created by the pintool in order to construct the trace''' # Read the begin of file until the first blank line # This correspond to the segment enumeration segments = [] for line in traceFile: if line == "\n": break # Each line begins with the bound of the segment, # separated by a '-' and followed by a white space segments += [ tuple( [int(addr, 16) for addr in line.split(' ')[0].split('-')]) ] trace = Trace() started = False for line in traceFile: infos = line.strip().split(' ') first_char = infos[0] values = [int(v, 16) for v in infos[1:]] # Start of the learned function # Fields are registers value if first_char == 'I': if not started: started = True current_snapshot = Snapshot(segments, self.abicls, self.machine) for i, reg_name in enumerate(self.reg_list): current_snapshot.add_input_register(reg_name, values[i]) # Executed instructions address elif first_char == '@': if started: current_snapshot.add_executed_instruction(values[0]) # Memory read access # Fields are read address, read size and read value elif first_char == 'R': if started: current_snapshot.add_memory_read(values[0], values[1], values[2]) # Memory write access # Fields are writen address, writen size and writen value elif first_char == 'W': if started: current_snapshot.add_memory_write(values[0], values[1], values[2]) # End of the learned function # Field are register value elif first_char == 'O': if started: for i, reg_name in enumerate(self.reg_list): current_snapshot.add_output_register( reg_name, values[i]) # The learned function execution is over # Snapshot can be added to the trace started = False trace.append(current_snapshot) return trace
class TracerMiasm(Tracer): '''Tracer that uses miasm''' def __init__(self, *args, **kwargs): super(TracerMiasm, self).__init__(*args, **kwargs) self.isTracing = False self.trace = None def read_callback(self, symb_exec, expr_mem): '''Read callback that add the read event to the snapshot''' addr = int(expr_mem.ptr) size = expr_mem.size / 8 value = int(symb_exec.cpu.get_mem(addr, size)[::-1].encode("hex"), 16) self.current_snapshot.add_memory_read(addr, size, value) def write_callback(self, symb_exec, dest, data): '''Write callback that add the read event to the snapshot''' addr = int(dest.ptr) size = data.size / 8 value = int(data.arg.arg) self.current_snapshot.add_memory_write(addr, size, value) def exec_callback(self, jitter): '''Callback called before each bloc execution''' self.current_snapshot.add_executed_instruction(jitter.pc) return True def begin_func(self, jitter): ''' Function called by miasm at the begin of every execution of the traced function ''' self.old_ret_addr = jitter.pop_uint64_t() jitter.push_uint64_t(0x1337beef) self.isTracing = True self.current_snapshot = Snapshot(self.abicls, self.machine) # Add the breakpoint to watch every memory read and write jitter.jit.symbexec.add_read_call(self.read_callback) jitter.jit.symbexec.add_write_call(self.write_callback) # Called before the execution of each basic bloc jitter.exec_cb = self.exec_callback for reg_name in self.reg_list: self.current_snapshot.add_input_register( reg_name, getattr(jitter.cpu, reg_name)) return True def end_func(self, jitter): ''' Function called by miasm at the end of every execution of the traced function ''' jitter.pc = self.old_ret_addr for reg_name in self.reg_list: self.current_snapshot.add_output_register( reg_name, getattr(jitter.cpu, reg_name)) jitter.exec_cb = None # Remove memory breakpoints jitter.jit.symbexec.remove_read_callback(self.read_callback) jitter.jit.symbexec.remove_write_callback(self.write_callback) self.trace.append(self.current_snapshot) self.isTracing = False return True def end_do_trace(self, jitter): ''' Function called by miasm at the end of the program's execution ''' jitter.run = False return False def do_trace(self): '''Run miasm and construct the trace''' self.trace = Trace() # Retrieve miasm tools machine = Machine(self.machine) jitter = machine.jitter("python") # Set the jitter to use our custom emulator jitter.jit.symbexec = CustomEmulatedSymbExec(jitter.cpu, jitter.vm, jitter.jit.ir_arch, {}) jitter.jit.symbexec.enable_emulated_simplifications() jitter.jit.symbexec.reset_regs() elf = vm_load_elf(jitter.vm, open(self.program, "rb").read()) # Init segment jitter.ir_arch.do_stk_segm = True jitter.ir_arch.do_ds_segm = True jitter.ir_arch.do_str_segm = True jitter.ir_arch.do_all_segm = True FS_0_ADDR = 0x7ff70000 jitter.cpu.FS = 0x4 jitter.cpu.set_segm_base(jitter.cpu.FS, FS_0_ADDR) jitter.vm.add_memory_page(FS_0_ADDR + 0x28, PAGE_READ, "\x42\x42\x42\x42\x42\x42\x42\x42") # Init stack and push main args jitter.init_stack() jitter.push_uint64_t(1) jitter.vm.add_memory_page(0x800000, PAGE_READ, self.program) jitter.push_uint64_t(0x800000) jitter.push_uint64_t(0xDEADDEAD) jitter.add_breakpoint(0xDEADDEAD, self.end_do_trace) jitter.add_breakpoint(0x1337beef, self.end_func) jitter.add_breakpoint(self.address, self.begin_func) # Run the execution if self.main_address is None: jitter.init_run(elf.Ehdr.entry) else: jitter.init_run(self.main_address) jitter.continue_run() assert jitter.run == False return self.trace
class TracerMiasm(Tracer): '''Tracer that uses miasm''' def __init__(self, *args, **kwargs): super(TracerMiasm, self).__init__(*args, **kwargs) self.isTracing = False self.trace = None def read_callback(self, symb_exec, expr_mem): '''Read callback that add the read event to the snapshot''' addr = int(expr_mem.ptr) size = expr_mem.size / 8 value = int(symb_exec.cpu.get_mem(addr, size)[::-1].encode("hex"), 16) self.current_snapshot.add_memory_read(addr, size, value) def write_callback(self, symb_exec, dest, data): '''Write callback that add the read event to the snapshot''' addr = int(dest.ptr) size = data.size / 8 value = int(data.arg.arg) self.current_snapshot.add_memory_write(addr, size, value) def exec_callback(self, jitter): '''Callback called before each bloc execution''' self.current_snapshot.add_executed_instruction(jitter.pc) return True def begin_func(self, jitter): ''' Function called by miasm at the begin of every execution of the traced function ''' self.old_ret_addr = jitter.pop_uint64_t() jitter.push_uint64_t(0x1337beef) self.isTracing = True self.current_snapshot = Snapshot(self.abicls, self.machine) # Add the breakpoint to watch every memory read and write jitter.jit.symbexec.add_read_call(self.read_callback) jitter.jit.symbexec.add_write_call(self.write_callback) # Called before the execution of each basic bloc jitter.exec_cb = self.exec_callback for reg_name in self.reg_list: self.current_snapshot.add_input_register( reg_name, getattr(jitter.cpu, reg_name)) return True def end_func(self, jitter): ''' Function called by miasm at the end of every execution of the traced function ''' jitter.pc = self.old_ret_addr for reg_name in self.reg_list: self.current_snapshot.add_output_register( reg_name, getattr(jitter.cpu, reg_name)) jitter.exec_cb = None # Remove memory breakpoints jitter.jit.symbexec.remove_read_callback(self.read_callback) jitter.jit.symbexec.remove_write_callback(self.write_callback) self.trace.append(self.current_snapshot) self.isTracing = False return True def end_do_trace(self, jitter): ''' Function called by miasm at the end of the program's execution ''' jitter.run = False return False def do_trace(self): '''Run miasm and construct the trace''' self.trace = Trace() # Retrieve miasm tools machine = Machine(self.machine) jitter = machine.jitter("python") # Set the jitter to use our custom emulator jitter.jit.symbexec = CustomEmulatedSymbExec( jitter.cpu, jitter.vm, jitter.jit.ir_arch, {}) jitter.jit.symbexec.enable_emulated_simplifications() jitter.jit.symbexec.reset_regs() elf = vm_load_elf(jitter.vm, open(self.program, "rb").read()) # Init segment jitter.ir_arch.do_stk_segm = True jitter.ir_arch.do_ds_segm = True jitter.ir_arch.do_str_segm = True jitter.ir_arch.do_all_segm = True FS_0_ADDR = 0x7ff70000 jitter.cpu.FS = 0x4 jitter.cpu.set_segm_base(jitter.cpu.FS, FS_0_ADDR) jitter.vm.add_memory_page( FS_0_ADDR + 0x28, PAGE_READ, "\x42\x42\x42\x42\x42\x42\x42\x42") # Init stack and push main args jitter.init_stack() jitter.push_uint64_t(1) jitter.vm.add_memory_page(0x800000, PAGE_READ, self.program) jitter.push_uint64_t(0x800000) jitter.push_uint64_t(0xDEADDEAD) jitter.add_breakpoint(0xDEADDEAD, self.end_do_trace) jitter.add_breakpoint(0x1337beef, self.end_func) jitter.add_breakpoint(self.address, self.begin_func) # Run the execution if self.main_address is None: jitter.init_run(elf.Ehdr.entry) else: jitter.init_run(self.main_address) jitter.continue_run() assert jitter.run == False return self.trace
def __parse_pin_output_file(self, traceFile): '''Parse the file created by the pintool in order to construct the trace''' trace = Trace() # Statefull elements started = False current_image_name = None # State machine for parsing for line in traceFile: infos = line.strip().split(' ') entry_type = infos[0] # Image loaded in memory # IMG <img_name> if entry_type == "IMG": img_name = infos[1] current_image_name = img_name continue # Symbol entry # S <symbol_addr> <symbol_name> elif entry_type == 'S': assert current_image_name is not None symbol_name = infos[2] symbol_addr = int(infos[1], 16) trace.add_symbol(current_image_name, symbol_name, symbol_addr) continue values = [int(v, 16) for v in infos[1:]] # Start of the learned function # Fields are registers value if entry_type == 'I': if not started: started = True current_snapshot = Snapshot(self.abicls, self.machine) for i, reg_name in enumerate(self.reg_list): current_snapshot.add_input_register(reg_name, values[i]) # Executed instructions address elif entry_type == '@': if started: current_snapshot.add_executed_instruction(values[0]) # Memory read access # Fields are read address, read size and read value elif entry_type == 'R': if started: current_snapshot.add_memory_read(values[0], values[1], values[2]) # Memory write access # Fields are writen address, writen size and writen value elif entry_type == 'W': if started: current_snapshot.add_memory_write(values[0], values[1], values[2]) # End of the learned function # Field are register value elif entry_type == 'O': if started: for i, reg_name in enumerate(self.reg_list): current_snapshot.add_output_register( reg_name, values[i]) # The learned function execution is over # Snapshot can be added to the trace started = False yield current_snapshot # Call to a function # CALL <caller_addr> <stack pointer> elif entry_type == "CALL": current_snapshot.add_call(values[0], values[1]) # Return from a function # RET <ret_addr> <stack pointer after> <ret value> elif entry_type == "RET": current_snapshot.add_ret(values[0], values[1], values[2])