def _disassemble_bb(self, start, end, symbols): bb = BasicBlock() addr = start taken, not_taken, direct = None, None, None while addr < end: try: data_end = addr + self._arch_info.max_instruction_size data_chunk = self._memory[addr:min(data_end, end)] asm = self._disasm.disassemble(data_chunk, addr) except (DisassemblerError, InvalidAddressError, InvalidDisassemblerData): logger.warning( "Error while disassembling @ {:#x}".format(addr), exc_info=True) break asm.ir_instrs = self._translator.translate(asm) bb.instrs.append(asm) # If it is a RET or HALT instruction, break. if self._arch_info.instr_is_ret(asm) or \ self._arch_info.instr_is_halt(asm): bb.is_exit = True break # If it is a CALL instruction and the callee does not return, break. if self._arch_info.instr_is_call(asm): target = helper.extract_call_target(asm) if target and func_is_non_return(target, symbols): bb.is_exit = True break # If it is a BRANCH instruction, extract target and break. if self._arch_info.instr_is_branch(asm): target = helper.extract_branch_target(asm) if self._arch_info.instr_is_branch_cond(asm): taken = target not_taken = asm.address + asm.size else: direct = target # Jump to a function? if direct in symbols: bb.is_exit = True break # Update instruction pointer and iterate. addr += asm.size bb.taken_branch = taken bb.not_taken_branch = not_taken bb.direct_branch = direct return bb
def _disassemble_bb(self, start, end, symbols): bb = BasicBlock() addr = start taken, not_taken, direct = None, None, None while addr < end: try: data_end = addr + self._arch_info.max_instruction_size data_chunk = self._memory[addr:min(data_end, end)] asm = self._disasm.disassemble(data_chunk, addr) except (DisassemblerError, InvalidAddressError, InvalidDisassemblerData): logger.warn("Error while disassembling @ {:#x}".format(addr), exc_info=True) break ir = self._translator.translate(asm) bb.instrs.append(DualInstruction(addr, asm, ir)) # If it is a RET or HALT instruction, break. if self._arch_info.instr_is_ret(asm) or \ self._arch_info.instr_is_halt(asm): bb.is_exit = True break # If it is a CALL instruction and the callee does not return, break. if self._arch_info.instr_is_call(asm): target = helper.extract_call_target(asm) if target and func_is_non_return(target, symbols): bb.is_exit = True break # If it is a BRANCH instruction, extract target and break. if self._arch_info.instr_is_branch(asm): target = helper.extract_branch_target(asm) if self._arch_info.instr_is_branch_cond(asm): taken = target not_taken = asm.address + asm.size else: direct = target # Jump to a function? if direct in symbols: bb.is_exit = True break # Update instruction pointer and iterate. addr += asm.size bb.taken_branch = taken bb.not_taken_branch = not_taken bb.direct_branch = direct return bb
def _extract_call_targets(self, bbs): call_targets = [] for bb in bbs: for dinstr in bb: if self._arch_info.instr_is_call(dinstr.asm_instr): target = helper.extract_call_target(dinstr.asm_instr) if target: call_targets.append(target) return call_targets
def _extract_call_targets(self, bbs): call_targets = [] for bb in bbs: for dinstr in bb: if self._arch_info.instr_is_call(dinstr.asm_instr): target = helper.extract_call_target(dinstr.asm_instr) if target: call_targets.append(target) return call_targets