def mk_instance( self, vd: "FnVarDictionary", ixval: IndexedTableValue, superclass: type) -> VdR: tag = ixval.tags[0] if (superclass, tag) not in self.register: raise UF.CHBError( "Unknown vardictionary type: " + tag + " with type " + str(superclass)) instance = self.register[(superclass, tag)](vd, ixval) return cast(VdR, instance)
def condition(self, src: str, tgt: str) -> Optional[XXpr]: """Returns the condition, if any, that leads from src to tgt.""" if len(self.edges[src]) > 1: brinstr = self.branch_instruction(src) ftconditions = brinstr.ft_conditions if len(ftconditions) == 2: for i, t in enumerate(self.edges[src]): if tgt == t: return ftconditions[i] else: raise UF.CHBError("Error in Cfg.condition") return None
def to_xml(self, node: ET.Element) -> None: xsuccessors = ET.Element(self.name) node.append(xsuccessors) for srec in self.successors: if "ia" in srec: iaddr = cast(str, srec["ia"]) if "sr" in srec: addrs: List[str] = [] srange = cast(List[str], srec["sr"]) sa = int(srange[0], 16) se = int(srange[1], 16) for a in range(sa, se, 4): addrs.append(hex(a)) xs = ET.Element("instr") xs.set("ia", iaddr) xs.set("ss", ",".join(addrs)) xsuccessors.append(xs) else: raise UF.CHBError("Successor range field missing " + "from successor specification: " + iaddr) else: raise UF.CHBError("Instruction address (ia) missing " + "from successor specification")
def get_strings(self, minlen: int = 3) -> Generator[ Tuple[int, List[int]], None, None]: """Yield sequences of printable characters of mimimum length minlen.""" def makestream(s: str) -> Generator[Tuple[int, int], None, None]: c = 0 for w in s.split(): for i in range(0, len(w), 2): yield((c*8) + i, int(w[i:i+2], 16)) c += 1 def is_printable(i: int) -> bool: return (i >= 32 and i < 127) result: List[int] = [] for b in self.hex_data.findall("ablock"): for a in b.findall("aline"): xva = a.get("va") if xva: va = int(xva, 16) xbytes = a.get("bytes") if xbytes: for (offset, i) in makestream(xbytes): if is_printable(i): result.append(i) else: if len(result) >= minlen: strva = (va + (offset // 2)) - len(result) strval = result[:] result = [] yield (strva, strval) else: result = [] else: raise UF.CHBError( "Raw section line without bytes") else: raise UF.CHBError("Raw section line without virtual address")
def to_xml(self, node: ET.Element) -> None: xswitchpoints = ET.Element(self.name) node.append(xswitchpoints) for p in self.switchpoints: if p.endswith(":A") or p.endswith(":T"): iaddr = p[:-2] tgt = p[-1] xs = ET.Element("switch") xs.set("ia", iaddr) xs.set("tgt", tgt) xswitchpoints.append(xs) else: raise UF.CHBError("Error in thumb switch point: " + "Expected format <addr>:A or <addr>:T . " + "Found: " + p)
def _read_summary(self, dll, fname): def isref(xnode): return (not (xnode.find('refer-to') is None)) xnode = self.get_summary_xnode(dll, fname) if xnode is None: raise UF.CHBError('Summary for ' + dll + ':' + fname + ' may be corrupted') if isref(xnode): refnode = xnode.find('refer-to') self.dllsummaries[(dll, fname)] = DllSummaryRef(self.models, refnode, dll, fname) else: self.dllsummaries[(dll, fname)] = DllSummary(self.models, xnode)
def get_call_facts(self): if not self.is_call_instruction(): raise UF.CHBError("Not a call instruction: " + str(self)) xdata = self.idictionary.read_xml_instrx(self.xnode) opcode = self.mipsdictionary.read_xml_mips_opcode(self.xnode) result = {} callargs = self.get_annotated_call_arguments() if callargs: result['args'] = callargs tgt = self.get_call_target() if tgt == 'call-target:u': result['t'] = '?' else: result['t'] = str(tgt) return result
def xxpr_to_ast_expr(xpr: X.XXpr, astree: AbstractSyntaxTree) -> AST.ASTExpr: """Convert an XXpr expression into an AST Expr node.""" if xpr.is_constant: return xconstant_to_ast_expr(cast(X.XprConstant, xpr), astree) elif xpr.is_var: return xprvariable_to_ast_expr(cast(X.XprVariable, xpr), astree) elif xpr.is_compound: return xcompound_to_ast_expr(cast(X.XprCompound, xpr), astree) else: raise UF.CHBError("AST conversion of xxpr " + str(xpr) + " not yet supported")
def reset_to_checkpoint(self) -> int: """Remove all entries added since the checkpoint was set.""" cp = self.checkpoint if cp is None: raise UF.CHBError("Cannot reset non-existent checkpoint") for i in range(cp, self.next): if i in self.reserved: continue self.indextable.pop(i) for k in self.keytable.keys(): if self.keytable[k] >= cp: self.keytable.pop(k) self.checkpoint = None self.reserved = [] self.next = cp return cp
def instructions(self) -> Mapping[str, ARMAssemblyInstruction]: if len(self._instructions) == 0: for b in self.xnode.findall("b"): for n in b.findall("i"): iaddr = n.get("ia") if iaddr is None: raise UF.CHBError("Instruction without address") opcode = self.app.armdictionary.read_xml_arm_opcode(n) stat = n.get("stat", "") self._instructions[iaddr] = ARMAssemblyInstruction( iaddr, opcode, stat) self.sorted_instructions = ( sorted(int(k, 16) for k in self._instructions.keys())) self.revsorted_instructions = sorted( self.sorted_instructions, reverse=True) return self._instructions
def roles(self) -> Sequence[ParameterRole]: if "roles" in self.xnode.attrib: xrolesattr = self.xnode.get("roles") if xrolesattr: if xrolesattr == "none": return [] else: raise UF.CHBError("Roles attribute not recognized: " + str(xrolesattr)) else: return [] xroles = self.xnode.find('roles') if xroles: return [ParameterRole(self, r) for r in xroles.findall("role")] else: return []
def invariants(self) -> Mapping[str, Sequence[InvariantFact]]: if len(self._invariants) == 0: xinvnode = UF.get_function_invs_xnode( self.path, self.filename, self.faddr) xfacts = xinvnode.find("locations") if xfacts is None: raise UF.CHBError("Location invariants element not found") for xloc in xfacts.findall("loc"): xaddr = xloc.get("a") xifacts = xloc.get("ifacts") if xaddr is not None and xifacts is not None: ifacts = [int(i) for i in xifacts.split(",")] self._invariants[xaddr] = [] for ix in ifacts: self._invariants[xaddr].append( self.invdictionary.invariant_fact(ix)) return self._invariants
def xtyped_expr_to_ast_expr(op: str, op1: AST.ASTExpr, op2: AST.ASTExpr, astree: AbstractSyntaxTree) -> AST.ASTExpr: """Determine if expression needs different representation based on type.""" if op1.ctype is None: raise UF.CHBError("Expression is not typed: " + str(op1)) if op1.ctype.is_pointer and op2.is_integer_constant: op2 = cast(AST.ASTIntegerConstant, op2) tgttype = cast("BCTypPtr", op1.ctype).tgttyp if tgttype.is_struct: compinfo = cast("BCTypComp", tgttype).compinfo fieldoffset = field_at_offset(compinfo, op2.cvalue, astree) lval = astree.mk_memref_lval(op1, fieldoffset) return astree.mk_address_of(lval) return astree.mk_binary_op(op, op1, op2)
def initialize(self, xnode: ET.Element) -> None: for t in self.tables: t.reset() xtable = xnode.find(t.name) if xtable is not None: t.read_xml(xtable, "n") else: if t.name.startswith("arm") and (not self.app.is_arm): pass else: raise UF.CHBError("Error reading table " + t.name) self.string_table.reset() xstable = xnode.find(self.string_table.name) if xstable is not None: self.string_table.read_xml(xstable) else: raise UF.CHError("Error reading stringtable " + self.string_table.name)
def to_xml(self, node: ET.Element) -> None: xjumps = ET.Element(self.name) node.append(xjumps) for r in self.jumps: if "fa" in r and "ia" in r and "targets" in r: fa = cast(str, r["fa"]) ia = cast(str, r["ia"]) tgts = cast(List[str], r["targets"]) xj = ET.Element("jumpinstr") xjumps.append(xj) xj.set("fa", fa) xj.set("ia", ia) for tgt in tgts: xtgt = ET.Element("tgt") xj.append(xtgt) xtgt.set("a", tgt) else: raise UF.CHBError("Invalid format for indirect jump: " + "expected to find fa, ia, and targets")
def mk_user_btype(d: Union[str, Dict[str, Any]]) -> T.UserBType: if isinstance(d, str) or "name" in d: name: str = d if isinstance(d, str) else d["name"] if name in opaque_types: return T.UserNamedBType(name) elif user_type_store.has_size_of(name): size = user_type_store.size_of(name) return T.UserNamedBType(name, size=size) else: raise UF.CHBError("Cannot determine size of named type " + name) elif "key" in d: if d["key"] == "ptr": if "tgt" in d: try: return T.UserPointerBType(mk_user_btype(d["tgt"])) except UF.CHBError as e: raise UF.CHBError("Error in pointer target type: " + str(e)) else: raise UF.CHBError("Expected tgt field for pointer type") elif d["key"] == "struct": if "fields" in d: return T.UserStructBType(mk_field_infos(d["fields"])) else: raise UF.CHBError("Expected fields field for struct type") elif d["key"] == "array": if "tgt" in d and "size" in d: try: return T.UserArrayBType(mk_user_btype(d["tgt"]), d["size"]) except UF.CHBError as e: raise UF.CHBError("Error in array target type: " + str(e)) else: raise UF.CHBError("Expected tgt and size for array type") else: raise UF.CHBError("Key " + d["key"] + " not recognized for btype") else: raise UF.CHBError("Expected name or key field in btype")
def get_zero_blocks(self, hexva: str, align: int = 32) -> List[Tuple[str, str]]: s = "" offsetalign = 2 * align z = "0" * offsetalign qalign = int(align / 4) qoffsetalign = int(offsetalign / 4) qz = "0" * qoffsetalign for b in self.hex_data.findall("block"): for a in b.findall("aline"): xbytes = a.get("bytes") if xbytes: s += xbytes.replace(" ", "") else: raise UF.CHBError("Raw section line without bytes") va = int(hexva, 16) offset = 0 slen = len(s) result = [] while (va % align) > 0: va += 1 offset += 2 while offset < slen - offsetalign: while s[offset:offset+offsetalign] != z: va += align offset += offsetalign if offset > slen - offsetalign: break if offset > slen - qoffsetalign: break dbstart = hex(va) while (s[offset:offset+qoffsetalign] == qz): va += qalign offset += qoffsetalign if offset > slen - qoffsetalign: break dbend = hex(va) result.append((dbstart, dbend)) return result
def subu(self, simval: SV.SimValue) -> SV.SimValue: """Unsigned subtraction. This may be either subtraction of another stackaddress, resulting in a scalar, or subtraction of a scalar, resulting in another stack address. """ if simval.is_literal and simval.is_defined: simval = cast(SV.SimLiteralValue, simval) return self.add_offset(-simval.value) elif simval.is_symbolic: simval = cast(SimSymbolicValue, simval) if simval.is_stack_address: simval = cast("SimStackAddress", simval) return SV.mk_simvalue(self.offsetvalue - simval.offsetvalue, size=4) else: raise UF.CHBError( "Illegal subtraction from stack address with: " + str(simval)) else: return SV.simUndefinedDW
def name(self) -> str: raise UF.CHBError( "Method name only applicable to named type, not to " + self.kind)
def faddr(self) -> str: xfaddr = self.xnode.get("fa") if xfaddr is not None: return xfaddr else: raise UF.CHBError("Function address missing from stack adjustment")
def unresolved_call_target_expr(self) -> XXpr: if self.has_global_value_unresolved_call_target(): opc = cast(X86Call, self.opcode) return opc.unresolved_call_target_expr(self.xdata) else: raise UF.CHBError("Instruction is not an unresolved call")
def call_arguments(self) -> List[XXpr]: if self.opcode.is_call: opc = cast(X86Call, self.opcode) return opc.arguments(self.xdata) else: raise UF.CHBError("Instruction is not a call instruction")
def call_target(self) -> CallTarget: if self.opcode.is_call: opc = cast(X86Call, self.opcode) return opc.call_target(self.xdata) else: raise UF.CHBError("Instruction is not a call instruction")
def addr(self) -> str: xaddr = self.xnode.get("a") if xaddr is not None: return xaddr else: raise UF.CHBError("Address missing from function name")
def jumptable_targets(self) -> List[str]: if self.is_indirect_jump(): opc = cast(X86IndirectJmp, self.opcode) return opc.targets(self.xdata) else: raise UF.CHBError("Instruction is not an indirect jump: " + str(self))
def branch_predicate(self) -> XXpr: if self.has_branch_predicate(): return self.opcode.predicate(self.xdata) else: raise UF.CHBError("Instruction does not have a branch predicate: " + str(self))
def call_target(self, xdata: InstrXData) -> "CallTarget": if self.is_call(xdata): return xdata.call_target(self.ixd) else: raise UF.CHBError("Instruction is not a call: " + str(self))
def selector_expr(self) -> XXpr: if self.is_indirect_jump(): return self.opcode.selector_expr(self.xdata) else: raise UF.CHBError("Instruction is not an indirect jump: " + str(self))
def name(self) -> str: xname = self.xnode.get("n") if xname is not None: return xname else: raise UF.CHBError("Name missing from function name")
def branch_condition(self) -> XXpr: if self.has_branch_condition(): return self.xdata.xprs[0] else: raise UF.CHBError('Instruction does not have a branch condition: ' + str(self))