def fetch_sequence(self, address): base_addr, index = split_address(address) if base_addr not in self.__container: raise ReilContainerInvalidAddressError() return self.__container[base_addr]
def __execute(self, asm_instr): # Process one assembler instruction. Translate it to REIL instruction and # process each one. instr_container = self.__translate(asm_instr) ip = to_reil_address(asm_instr.address) next_addr = None while ip: # Fetch instruction. try: reil_instr = instr_container.fetch(ip) except ReilContainerInvalidAddressError: next_addr, _ = split_address(ip) break if reil_instr.mnemonic == ReilMnemonic.UNKN: raise InstructionNotImplemented(asm_instr) # Execute instruction. next_ip = self.ir_emulator.single_step(reil_instr) # Update instruction pointer. ip = next_ip if next_ip else instr_container.get_next_address(ip) del instr_container # delete temporal registers regs = self.ir_emulator.registers.keys() for r in regs: if r.startswith("t"): del self.ir_emulator.registers[r] return next_addr if next_addr else asm_instr.address + asm_instr.size
def fetch(self, address): base_addr, index = split_address(address) if base_addr not in self.__container: self.__resolve_address(base_addr) return self.__container[base_addr].get(index)
def fetch(self, address): base_addr, index = split_address(address) if base_addr != to_asm_address(self.address): raise ReilSequenceInvalidAddressError() return self.get(index)
def add(self, sequence): base_addr, _ = split_address(sequence.address) if base_addr in self.__container.keys(): raise Exception("Invalid sequence") else: self.__container[base_addr] = sequence
def fetch_sequence(self, address): base_addr, index = split_address(address) if base_addr not in self.__container.keys(): raise ReilContainerInvalidAddressError() return self.__container[base_addr]
def fetch(self, address): base_addr, index = split_address(address) if base_addr not in self.__container.keys(): self.__resolve_address(base_addr) return self.__container[base_addr].get(index)
def fetch(self, address): base_addr, index = split_address(address) if base_addr not in self.__container: raise ReilContainerInvalidAddressError() return self.__container[base_addr].get(index)
def get_next_address(self, address): base_addr, index = split_address(address) if base_addr != to_asm_address(self.address): raise ReilSequenceInvalidAddressError() addr = address if index < len(self.__sequence) - 1: addr += 1 else: raise ReilSequenceInvalidAddressError() return addr
def get_next_address(self, address): base_addr, index = split_address(address) if base_addr not in self.__container.keys(): raise Exception("Invalid address.") addr = address if index < len(self.__container[base_addr]) - 1: addr += 1 else: addr = self.__container[base_addr].next_sequence_address return addr
def get_next_address(self, address): base_addr, index = split_address(address) if base_addr not in self.__container: raise Exception("Invalid address.") addr = address if index < len(self.__container[base_addr]) - 1: addr += 1 else: addr = self.__container[base_addr].next_sequence_address return addr
def __fa_process_sequence(self, sequence, avoid, initial_state, execution_state, trace_current, next_addr): """Process a REIL sequence. Args: sequence (ReilSequence): A REIL sequence to process. avoid (list): List of address to avoid. initial_state: Initial state. execution_state: Execution state queue. trace_current (list): Current trace. next_addr: Address of the next instruction following the current one. Returns: Returns the next instruction to execute in case there is one, otherwise returns None. """ # TODO: Process execution intra states. ip = sequence.address next_ip = None while ip: # Fetch next instruction in the sequence. try: instr = sequence.fetch(ip) except ReilSequenceInvalidAddressError: # At this point, ip should be a native instruction address, therefore # the index should be zero. assert split_address(ip)[1] == 0x0 next_ip = ip break try: target_addr = sequence.get_next_address(ip) except ReilSequenceInvalidAddressError: # We reached the end of the sequence. Execution continues on the next native instruction # (it's a REIL address). target_addr = next_addr next_ip = self.__process_instr(instr, avoid, target_addr, initial_state, execution_state, trace_current) # Update instruction pointer. try: ip = next_ip if next_ip else sequence.get_next_address(ip) except ReilSequenceInvalidAddressError: break return next_ip
def __process_instr(self, instr, avoid, next_addr, initial_state, execution_state, trace_current): """Process a REIL instruction. Args: instr (ReilInstruction): Instruction to process. avoid (list): List of addresses to avoid while executing the code. next_addr (int): Address of the following instruction. initial_state (State): Initial execution state. execution_state (Queue): Queue of execution states. trace_current (list): Current trace. Returns: int: Returns the next address to execute. """ # Process branch (JCC oprnd0, empty, oprnd2). if instr.mnemonic == ReilMnemonic.JCC: not_taken_addr = next_addr address, index = split_address(instr.address) logger.debug("[+] Processing branch: {:#08x}:{:02x} : {:s}".format( address, index, instr)) # Process conditional branch (oprnd0 is a REGISTER). if isinstance(instr.operands[0], ReilRegisterOperand): next_ip = self.__process_branch_cond(instr, avoid, initial_state, execution_state, trace_current, not_taken_addr) # Process unconditional branch (oprnd0 is an INTEGER). else: next_ip = self.__process_branch_uncond(instr, trace_current, not_taken_addr) # Process the rest of the instructions. else: trace_current += [(instr, None)] self.__cpu.execute(instr) next_ip = next_addr return next_ip
def __execute(self, asm_instr): # Process one assembler instruction. Translate it to REIL instruction and # process each one. instr_container = self.__translate(asm_instr) ip = to_reil_address(asm_instr.address) next_addr = None while ip: # Fetch instruction. try: reil_instr = instr_container.fetch(ip) except ReilContainerInvalidAddressError: next_addr, _ = split_address(ip) break if reil_instr.mnemonic == ReilMnemonic.UNKN: raise InstructionNotImplemented(asm_instr) # Execute instruction. next_ip = self.ir_emulator.single_step(reil_instr) # Update instruction pointer. ip = next_ip if next_ip else instr_container.get_next_address(ip) del instr_container # Execute post instruction handlers handler_fn_post, handler_param_post = self.__instr_handler_post handler_fn_post(self, asm_instr, handler_param_post) # delete temporal registers regs = self.ir_emulator.registers.keys() for r in regs: if r.startswith("t"): del self.ir_emulator.registers[r] return next_addr if next_addr else asm_instr.address + asm_instr.size
def __process_instr(self, instr, avoid, next_addr, initial_state, execution_state, trace_current): """Process a REIL instruction. Args: instr (ReilInstruction): Instruction to process. avoid (list): List of addresses to avoid while executing the code. next_addr (int): Address of the following instruction. initial_state (State): Initial execution state. execution_state (Queue): Queue of execution states. trace_current (list): Current trace. Returns: int: Returns the next address to execute. """ # Process branch (JCC oprnd0, empty, oprnd2). if instr.mnemonic == ReilMnemonic.JCC: not_taken_addr = next_addr address, index = split_address(instr.address) logger.debug("[+] Processing branch: {:#08x}:{:02x} : {}".format(address, index, instr)) # Process conditional branch (oprnd0 is a REGISTER). if isinstance(instr.operands[0], ReilRegisterOperand): next_ip = self.__process_branch_cond(instr, avoid, initial_state, execution_state, trace_current, not_taken_addr) # Process unconditional branch (oprnd0 is an INTEGER). else: next_ip = self.__process_branch_uncond(instr, trace_current, not_taken_addr) # Process the rest of the instructions. else: trace_current += [(instr, None)] self.__cpu.execute(instr) next_ip = next_addr return next_ip
def dump(self): for instr in self.__sequence: base_addr, index = split_address(instr.address) print("{:08x}:{:02x}\t{}".format(base_addr, index, instr))
def __fa_process_container(self, container, find, start, end, avoid, initial_state, execution_state, trace_current, trace_final): """Process a REIL container. Args: avoid (list): List of addresses to avoid while executing the code. container (ReilContainer): REIL container to execute. end (int): End address. execution_state (Queue): Queue of execution states. find (int): Address to find. initial_state (State): Initial state. start (int): Start address. trace_current: trace_final: """ ip = start while ip: # NOTE *ip* and *next_addr* variables can be, independently, either intra # or inter addresses. # Fetch next instruction. try: instr = container.fetch(ip) except ReilContainerInvalidAddressError: logger.debug("Exception @ {:#08x}".format(ip)) raise ReilContainerInvalidAddressError # Compute the address of the following instruction to the fetched one. try: next_addr = container.get_next_address(ip) except Exception: logger.debug("Exception @ {:#08x}".format(ip)) # TODO Should this be considered an error? raise ReilContainerInvalidAddressError # Process the instruction. next_ip = self.__process_instr(instr, avoid, next_addr, initial_state, execution_state, trace_current) # # ====================================================================================================== # # # NOTE This is an attempt to separate intra and inter instruction # # addresses processing. Here, *ip* and *next_addr* are always inter # # instruction addresses. # # assert split_address(ip)[1] == 0x0 # # # Compute the address of the following instruction to the fetched one. # try: # seq = container.fetch_sequence(ip) # except ReilContainerInvalidAddressError: # logger.debug("Exception @ {:#08x}".format(ip)) # # raise ReilContainerInvalidAddressError # # # Fetch next instruction address. # try: # next_addr = container.get_next_address(ip + len(seq)) # except Exception: # logger.debug("Exception @ {:#08x}".format(ip)) # # # TODO Should this be considered an error? # # raise ReilContainerInvalidAddressError # # next_ip = self.__process_sequence(seq, avoid, initial_state, execution_state, trace_current, next_addr) # # if next_ip: # assert split_address(next_ip)[1] == 0x0 # # # ====================================================================================================== # # Check termination conditions. if find and next_ip and next_ip == find: logger.debug("[+] Find address found!") trace_final.append(list(trace_current)) next_ip = None if end and next_ip and next_ip == end: logger.debug("[+] End address found!") next_ip = None # Update instruction pointer. ip = next_ip if next_ip else None while not ip: if not execution_state.empty(): # Pop next execution state. ip, trace_current, registers, memory = execution_state.get() if split_address(ip)[1] == 0x0: logger.debug("[+] Popping execution state @ {:#x} (INTER)".format(ip)) else: logger.debug("[+] Popping execution state @ {:#x} (INTRA)".format(ip)) # Setup cpu and memory. self.__cpu.registers = registers self.__cpu.memory = memory logger.debug("[+] Next address: {:#08x}:{:02x}".format(ip >> 8, ip & 0xff)) else: logger.debug("[+] No more paths to explore! Exiting...") break # Check termination conditions (AGAIN...). if find and ip == find: logger.debug("[+] Find address found!") trace_final.append(list(trace_current)) ip = None if end and ip == end: logger.debug("[+] End address found!") ip = None
def __fs_process_container(self, container, final_state, start, end, avoid, initial_state, execution_state, trace_current, trace_final): ip = start while ip: # Fetch next instruction. try: instr = container.fetch(ip) except ReilContainerInvalidAddressError: logger.debug("Exception @ {:#08x}".format(ip)) raise ReilContainerInvalidAddressError # Compute the address of the following instruction to the fetched one. try: next_addr = container.get_next_address(ip) except Exception: logger.debug("Exception @ {:#08x}".format(ip)) # TODO Should this be considered an error? raise ReilContainerInvalidAddressError # Process instruction next_ip = self.__process_instr(instr, avoid, next_addr, initial_state, execution_state, trace_current) # Check is final state holds. if instr.mnemonic == ReilMnemonic.JCC and isinstance(instr.operands[0], ReilRegisterOperand): # TODO Check only when it is necessary. self.__reset_solver() self.__set_initial_state(initial_state) self.__add_trace_to_solver(trace_current) self.__set_final_state(final_state) is_sat = self.__code_analyzer.check() if is_sat == "sat": logger.debug("[+] Final state found!") trace_final.append(list(trace_current)) next_ip = None # Check termination conditions. if end and next_ip and next_ip == end: logger.debug("[+] End address found!") next_ip = None # Update instruction pointer. ip = next_ip if next_ip else None while not ip: if not execution_state.empty(): # Pop next execution state. ip, trace_current, registers, memory = execution_state.get() if split_address(ip)[1] == 0x0: logger.debug("[+] Popping execution state @ {:#x} (INTER)".format(ip)) else: logger.debug("[+] Popping execution state @ {:#x} (INTRA)".format(ip)) # Setup cpu and memory. self.__cpu.registers = registers self.__cpu.memory = memory logger.debug("[+] Next address: {:#08x}:{:02x}".format(ip >> 8, ip & 0xff)) else: logger.debug("[+] No more paths to explore! Exiting...") break # Check termination conditions (AGAIN...). if end and ip == end: logger.debug("[+] End address found!") ip = None