def _resolve_location_name(self, name, is_write=False): # Delayed load so SimMemory does not rely on SimEngines from ..engines.vex.ccall import _get_flags if self.category == 'reg': if self.state.arch.name in ('X86', 'AMD64'): if name in stn_map: return (((stn_map[name] + self.load('ftop')) & 7) << 3) + self.state.arch.registers['fpu_regs'][0], 8 elif name in tag_map: return ((tag_map[name] + self.load('ftop')) & 7) + self.state.arch.registers['fpu_tags'][0], 1 elif name in ('flags', 'eflags', 'rflags'): # we tweak the state to convert the vex condition registers into the flags register if not is_write: # this work doesn't need to be done if we're just gonna overwrite it self.store('cc_dep1', _get_flags(self.state)[0]) # TODO: can constraints be added by this? self.store('cc_op', 0) # OP_COPY return self.state.arch.registers['cc_dep1'][0], self.state.arch.bytes if is_arm_arch(self.state.arch): if name == 'flags': if not is_write: self.store('cc_dep1', _get_flags(self.state)[0]) self.store('cc_op', 0) return self.state.arch.registers['cc_dep1'][0], self.state.arch.bytes return self.state.arch.registers[name] elif name[0] == '*': return self.state.registers.load(name[1:]), None else: raise SimMemoryError("Trying to address memory with a register name.")
def _resolve_location_name(self, name, is_write=False): # Delayed load so SimMemory does not rely on SimEngines from angr.engines.vex.claripy.ccall import _get_flags if self.category == 'reg': if self.state.arch.name in ('X86', 'AMD64'): if name in stn_map: return (((stn_map[name] + self.load('ftop')) & 7) << 3) + self.state.arch.registers['fpu_regs'][0], 8 elif name in tag_map: return ((tag_map[name] + self.load('ftop')) & 7) + self.state.arch.registers['fpu_tags'][0], 1 elif name in ('flags', 'eflags', 'rflags'): # we tweak the state to convert the vex condition registers into the flags register if not is_write: # this work doesn't need to be done if we're just gonna overwrite it self.store('cc_dep1', _get_flags(self.state)) self.store('cc_op', 0) # OP_COPY return self.state.arch.registers['cc_dep1'][0], self.state.arch.bytes if is_arm_arch(self.state.arch): if name == 'flags': if not is_write: self.store('cc_dep1', _get_flags(self.state)) self.store('cc_op', 0) return self.state.arch.registers['cc_dep1'][0], self.state.arch.bytes return self.state.arch.registers[name] elif name[0] == '*': return self.state.registers.load(name[1:]), None else: raise SimMemoryError("Trying to address memory with a register name.")
def __init__(self, kb): self._kb = kb self._labels = {} self._reverse_labels = {} is_arm = is_arm_arch(kb._project.arch) for obj in kb._project.loader.all_objects: for v in obj.symbols: if is_arm and v.name in {"$d", "$t", "$a"}: continue if v.name and not v.is_import and v.type not in { cle.SymbolType.TYPE_OTHER, }: self._labels[v.rebased_addr] = v.name self._reverse_labels[v.name] = v.rebased_addr try: for v, k in obj.plt.items(): self._labels[k] = v except AttributeError: pass # Artificial labels for the entry point entry = kb._project.loader.main_object.entry if entry not in self._labels: lbl = "_start" self._labels[entry] = self.get_unique_label(lbl)
def __getitem__(self, ident) -> CFGModel: if ident not in self.cfgs: if self._kb is not None and self._kb._project is not None: is_arm = is_arm_arch(self._kb._project.arch) else: is_arm = False self.cfgs[ident] = CFGModel(ident, cfg_manager=self, is_arm=is_arm) return self.cfgs[ident]
def __dir__(self): if self.state.arch.name in ('X86', 'AMD64'): return list(self.state.arch.registers.keys()) + [ 'st%d' % n for n in range(8) ] + ['tag%d' % n for n in range(8)] + ['flags', 'eflags', 'rflags'] elif is_arm_arch(self.state.arch): return list(self.state.arch.registers.keys()) + ['flags'] return self.state.arch.registers.keys()
def decode_instruction(arch, instr): # this is clearly architecture specific arch_name = arch.name if arch_name == 'MIPS32' and once('mips-instruction-groups'): l.warning( 'Your version of capstone does not support MIPS instruction groups.' ) insn_info = None info = INS_GROUP_INFO.get(arch_name, None) if info is not None: for group in instr.insn.insn.groups: insn_info = info.get(group, None) if insn_info is not None: break if insn_info is None: info = INS_INFO.get(arch_name, None) if info is not None: insn_info = info.get(instr.insn.insn.id, None) if insn_info is None: return instr.type = insn_info if instr.type in ('call', 'branch'): # determine if this is a direct or indirect call/branch if arch_name in ('X86', 'AMD64'): last_operand = instr.insn.operands[-1] if last_operand.type == cs.x86.X86_OP_IMM: instr.branch_type = 'direct' else: instr.branch_type = 'indirect' instr.branch_target_operand = len(instr.insn.operands) - 1 elif is_arm_arch(arch): last_operand = instr.insn.operands[-1] if last_operand.type == cs.arm.ARM_OP_IMM: instr.branch_type = 'direct' else: instr.branch_type = 'indirect' instr.branch_target_operand = len(instr.insn.operands) - 1 elif arch_name == 'MIPS32': # check the last operand last_operand = instr.insn.operands[-1] if last_operand.type == cs.mips.MIPS_OP_REG: instr.branch_type = 'indirect' else: instr.branch_type = 'direct' instr.branch_target_operand = len(instr.insn.operands) - 1
def _is_sane_register_variable(self, variable: SimRegisterVariable) -> bool: """ Filters all registers that are surly not members of function arguments. This can be seen as a workaround, since VariableRecoveryFast sometimes gives input variables of cc_ndep (which is a VEX-specific register) :-( :param variable: The variable to test. :return: True if it is an acceptable function argument, False otherwise. :rtype: bool """ arch = self.project.arch if arch.name == 'AARCH64': return 16 <= variable.reg < 80 # x0-x7 elif arch.name == 'AMD64': return (24 <= variable.reg < 40 or # rcx, rdx 64 <= variable.reg < 104 # rsi, rdi, r8, r9, r10 ) # 224 <= variable.reg < 480) # xmm0-xmm7 elif is_arm_arch(arch): return 8 <= variable.reg < 24 # r0-r3 elif arch.name == 'MIPS32': return 24 <= variable.reg < 40 # a0-a3 elif arch.name == 'MIPS64': return 48 <= variable.reg < 80 or 112 <= variable.reg < 208 # a0-a3 or t4-t7 elif arch.name == 'PPC32': return 28 <= variable.reg < 60 # r3-r10 elif arch.name == 'X86': return (8 <= variable.reg < 24 or # eax, ebx, ecx, edx 160 <= variable.reg < 288) # xmm0-xmm7 else: l.critical('Unsupported architecture %s.', arch.name) return True
def _handle_Get(self, expr): reg_offset = expr.offset reg_size = expr.result_size(self.tyenv) // 8 # because of how VEX implements MOVCC and MOVCS instructions in ARM THUMB mode, we need to skip the register # read if the immediate next instruction is an WrTmp(ITE). # # MOVCC R3, #0 # # 46 | ------ IMark(0xfeca2, 2, 1) ------ # 47 | t299 = CmpLT32U(t8,0x00010000) # 48 | t143 = GET:I32(r3) <- this read does not exist # 49 | t300 = ITE(t299,0x00000000,t143) # 50 | PUT(r3) = t300 # 51 | PUT(pc) = 0x000feca5 if is_arm_arch(self.arch) and (self.ins_addr & 1) == 1: if self.stmt_idx < len(self.block.vex.statements) - 1: next_stmt = self.block.vex.statements[self.stmt_idx + 1] if isinstance(next_stmt, pyvex.IRStmt.WrTmp) and isinstance( next_stmt.data, pyvex.IRExpr.ITE): return RichR(self.state.top(reg_size * 8)) return self._read_from_register(reg_offset, reg_size, expr=expr)
def _is_sane_register_variable(self, variable): """ Filters all registers that are surly not members of function arguments. This can be seen as a workaround, since VariableRecoveryFast sometimes gives input variables of cc_ndep (which is a VEX-specific register) :-( :param SimRegisterVariable variable: The variable to test. :return: True if it is an acceptable function argument, False otherwise. :rtype: bool """ arch = self.project.arch if arch.name == 'AARCH64': return 16 <= variable.reg < 80 # x0-x7 elif arch.name == 'AMD64': return (24 <= variable.reg < 40 or # rcx, rdx 64 <= variable.reg < 104 or # rsi, rdi, r8, r9, r10 224 <= variable.reg < 480) # xmm0-xmm7 elif is_arm_arch(arch): return 8 <= variable.reg < 24 # r0-r3 elif arch.name == 'MIPS32': return 24 <= variable.reg < 40 # a0-a3 elif arch.name == 'PPC32': return 28 <= variable.reg < 60 # r3-r10 elif arch.name == 'X86': return (8 <= variable.reg < 24 or # eax, ebx, ecx, edx 160 <= variable.reg < 288) # xmm0-xmm7 else: l.critical('Unsupported architecture %s.', arch.name) return True
def __dir__(self): if self.state.arch.name in ('X86', 'AMD64'): return list(self.state.arch.registers.keys()) + ['st%d' % n for n in range(8)] + ['tag%d' % n for n in range(8)] + ['flags', 'eflags', 'rflags'] elif is_arm_arch(self.state.arch): return self.state.arch.registers.keys() + ['flags'] return self.state.arch.registers.keys()
def __init__(self, sig: Optional[Union[FlirtSignature, str]] = None): self._is_arm = is_arm_arch(self.project.arch) self._all_suggestions: Dict[str, Dict[str, Dict[int, str]]] = {} self._suggestions: Dict[int, str] = {} self.matched_suggestions: Dict[str, Tuple[FlirtSignature, Dict[int, str]]] = {} self._temporary_sig = False if sig: if isinstance(sig, str): # this is a file path sig = FlirtSignature(self.project.arch.name.lower(), self.project.simos.name.lower(), "Temporary", sig, None) self.signatures = [sig] self._temporary_sig = True else: if not FLIRT_SIGNATURES_BY_ARCH: raise RuntimeError( "No FLIRT signatures exist. Please load FLIRT signatures by calling " "load_signatures() before running FlirtAnalysis.") # determine all signatures to match against strings in mapped memory regions mem_regions = [ self.project.loader.memory.load(seg.vaddr, seg.memsize) for seg in self.project.loader.main_object.segments if seg.filesize > 0 and seg.memsize > 0 ] self.signatures = list(self._find_hits_by_strings(mem_regions)) _l.debug("Identified %d signatures to apply.", len(self.signatures)) path_to_sig: Dict[str, FlirtSignature] = {} for sig_ in self.signatures: self._match_all_against_one_signature(sig_) if sig_.sig_name not in self._all_suggestions: self._all_suggestions[sig_.sig_name] = {} path_to_sig[sig_.sig_path] = sig_ self._all_suggestions[sig_.sig_name][ sig_.sig_path] = self._suggestions self._suggestions = {} for lib, sig_to_suggestions in self._all_suggestions.items(): max_suggestions = None max_suggestion_sig_path = None for sig_, suggestion in sig_to_suggestions.items(): _l.debug("Signature %s has %d function name suggestions.", sig_, len(suggestion)) if max_suggestions is None or len( suggestion) > max_suggestions: max_suggestion_sig_path = sig_ max_suggestions = len(suggestion) if max_suggestion_sig_path is not None: sig_ = path_to_sig.get(max_suggestion_sig_path, None) _l.info("Applying FLIRT signature %s for library %s.", sig_, lib) self._apply_changes( sig_.sig_name if not self._temporary_sig else None, sig_to_suggestions[max_suggestion_sig_path]) self.matched_suggestions[lib] = ( sig_, sig_to_suggestions[max_suggestion_sig_path])