def annotation(self, xdata: InstrXData) -> str: args = ", ".join(str(x) for x in self.arguments(xdata)) if xdata.has_call_target(): return "call " + str(xdata.call_target( self.ixd)) + "(" + args + ")" else: return "call- " + str(self.target) + "(" + args + ")"
def annotation(self, xdata: InstrXData) -> str: """xdata format: a:x . xprs[0]: true condition xprs[1]: false condition xprs[2]: true condition (simplified) xprs[3]: false condition (simplified) xprs[4]: target address (absolute) or, if no conditions xprs[0]: target address (absolute) """ if self.is_call_instruction(xdata): tgt = xdata.call_target(self.ixd) args = ", ".join(str(x) for x in self.arguments(xdata)) return "call " + str(tgt) + "(" + args + ")" elif xdata.has_branch_conditions(): return "if " + str(xdata.xprs[0]) + " then goto " + str( xdata.xprs[2]) elif self.tags[1] in ["a", "unc"]: return "goto " + str(xdata.xprs[0]) else: return "if ? goto " + str(xdata.xprs[0])
def call_target(self, xdata: InstrXData) -> "CallTarget": if xdata.has_call_target(): return xdata.call_target(self.ixd) else: raise UF.CHBError( "Syscall instruction does not have a call target: " + str(self))
def annotation(self, xdata: InstrXData) -> str: """lhs, rhs, with optional instr condition and base update vars[0]: lhs vars[1]: memory location expressed as a variable xprs[0]: value in memory location xprs[1]: value in memory location (simplified) optional: vars[1]: lhs base register (if base update) xprs[.]: instruction condition (if has condition) xprs[.]: new address for base register """ lhs = str(xdata.vars[0]) rhs = str(xdata.xprs[1]) xctr = 2 if xdata.has_instruction_condition(): pcond = "if " + str(xdata.xprs[xctr]) + " then " xctr += 1 elif xdata.has_unknown_instruction_condition(): pcond = "if ? then " else: pcond = "" if xdata.has_base_update(): blhs = str(xdata.vars[1]) brhs = str(xdata.xprs[xctr]) pbupd = "; " + blhs + " := " + brhs else: pbupd = "" return pcond + lhs + " := " + rhs + pbupd
def arguments(self, xdata: InstrXData) -> List[XXpr]: if xdata.has_indirect_call_target_exprs(): return xdata.xprs[2:] elif xdata.has_call_target(): return xdata.xprs else: return []
def annotation(self, xdata: InstrXData) -> str: """data formats: call, jumptable, indirect jump call: [a:..., 'call'], <args> + <index of call-target in ixd> jumptable: [a:x, 'table'], [xpr, [< i, address index>]] indirect jump: [a:x], [ xpr ] """ if self.is_call(xdata) and xdata.has_call_target(): tgt = xdata.call_target(self.ixd) args = ", ".join(str(x) for x in self.arguments(xdata)) return "call " + str(tgt) + "(" + args + ")" elif self.is_jump_table(xdata): tgtd = get_jump_table_targets([str(i) for i in xdata.args[1:]]) tgtstr = ' (' for t in sorted(tgtd): tgtaddr = self.mipsd.app.bdictionary.address(int(t)) tgtstr += (str(tgtd[t]) + ':' + str(tgtaddr) + ',') tgtstr += ')' jtgts = tgtstr else: jtgts = '' tgtx = str(xdata.xprs[0]) return 'jmp* ' + tgtx + ' ' + jtgts + ' (' + str( self.src_operand) + ')'
def annotation(self, xdata: InstrXData) -> str: """xdata format: a:vxx . vars[0]: lhs xprs[0]: rhs xprs[1]: rhs (simplified) xprs[2]: condition (if TC is set) """ lhs = str(xdata.vars[0]) rhs = str(xdata.xprs[1]) if xdata.xprs[1].is_function_return_value: rhs = str(xdata.xprs[1].variable.denotation) assign = lhs + " := " + rhs xctr = 2 if xdata.has_instruction_condition(): pcond = "if " + str(xdata.xprs[xctr]) + " then " xctr += 1 elif xdata.has_unknown_instruction_condition(): pcond = "if ? then " else: pcond = "" return pcond + assign
def annotation(self, xdata: InstrXData) -> str: if self.is_call(xdata) and xdata.has_call_target(): tgt = xdata.call_target(self.ixd) args = ", ".join(str(x) for x in self.arguments(xdata)) return "call " + str(tgt) + "(" + args + ")" else: return 'goto ' + str(self.target)
def ast(self, astree: AbstractSyntaxTree, iaddr: str, bytestring: str, xdata: InstrXData) -> List[ASTInstruction]: tgtx = str(xdata.xprs[0]) if tgtx == "$ra_in": return [] elif self.is_call(xdata) and xdata.has_call_target(): calltarget = xdata.call_target(self.ixd) tgtname = calltarget.name tgtxpr = self.target_expr_ast(astree, xdata) (lhs, assigns) = self.lhs_ast(astree, iaddr, xdata) args = self.arguments(xdata) argxprs: List[ASTExpr] = [] for arg in args: if XU.is_struct_field_address(arg, astree): addr = XU.xxpr_to_struct_field_address_expr(arg, astree) elif arg.is_string_reference: xpr = XU.xxpr_to_ast_expr(arg, astree) cstr = arg.constant.string_reference() saddr = hex(arg.constant.value) argxprs.append(astree.mk_string_constant(xpr, cstr, saddr)) elif arg.is_argument_value: argindex = arg.argument_index() funarg = astree.function_argument(argindex) if funarg: astxpr = astree.mk_register_variable_expr( funarg.name, vtype=funarg.typ, parameter=argindex) argxprs.append(astxpr) else: astxpr = XU.xxpr_to_ast_expr(arg, astree) argxprs.append(astxpr) else: astxpr = XU.xxpr_to_ast_expr(arg, astree) argxprs.append(astxpr) if lhs.is_ignored: call: ASTInstruction = astree.mk_call(lhs, tgtxpr, argxprs) astree.add_instruction_span(call.id, iaddr, bytestring) return [call] else: call = cast(ASTInstruction, astree.mk_call(lhs, tgtxpr, argxprs)) astree.add_instruction_span(call.id, iaddr, bytestring) for assign in assigns: astree.add_instruction_span(assign.id, iaddr, bytestring) return [call] + assigns else: # TODO: accomodate indirect jumps return []
def ast(self, astree: AbstractSyntaxTree, iaddr: str, bytestring: str, xdata: InstrXData) -> List[ASTInstruction]: if self.is_call(xdata) and xdata.has_call_target(): calltarget = xdata.call_target(self.ixd) tgtname = calltarget.name tgtxpr = self.target_expr_ast(astree, xdata) (lhs, assigns) = self.lhs_ast(astree, iaddr, xdata) args = self.arguments(xdata) argregs = ["R0", "R1", "R2", "R3"] callargs = argregs[:len(args)] argxprs: List[ASTExpr] = [] for (reg, arg) in zip(callargs, args): if XU.is_struct_field_address(arg, astree): addr = XU.xxpr_to_struct_field_address_expr(arg, astree) argxprs.append(addr) elif arg.is_string_reference: regast = astree.mk_register_variable_expr(reg) cstr = arg.constant.string_reference() saddr = hex(arg.constant.value) argxprs.append(astree.mk_string_constant(regast, cstr, saddr)) elif arg.is_argument_value: argindex = arg.argument_index() funarg = astree.function_argument(argindex) if funarg: astxpr = astree.mk_register_variable_expr( funarg.name, vtype=funarg.typ, parameter=argindex) argxprs.append(astxpr) else: argxprs.append(astree.mk_register_variable_expr(reg)) else: argxprs.append(astree.mk_register_variable_expr(reg)) if len(args) > 4: for a in args[4:]: argxprs.append(XU.xxpr_to_ast_expr(a, astree)) if lhs.is_ignored: call: ASTInstruction = astree.mk_call(lhs, tgtxpr, argxprs) astree.add_instruction_span(call.id, iaddr, bytestring) return [call] else: call = cast(ASTInstruction, astree.mk_call(lhs, tgtxpr, argxprs)) astree.add_instruction_span(call.id, iaddr, bytestring) for assign in assigns: astree.add_instruction_span(assign.id, iaddr, bytestring) return [call] + assigns else: return self.assembly_ast(astree, iaddr, bytestring, xdata)
def annotation(self, xdata: InstrXData) -> str: """xdata format: a:x . xprs[0]: target operand """ if self.is_call(xdata) and xdata.has_call_target(): tgt = xdata.call_target(self.ixd) args = ", ".join(str(x) for x in self.arguments(xdata)) return "call " + str(tgt) + "(" + args + ")" else: ctgt = str(xdata.xprs[0]) args = ", ".join(str(xdata.xprs[i]) for i in [1, 2, 3, 4]) return "call " + ctgt + "(" + args + ")"
def lhs_ast(self, astree: AbstractSyntaxTree, iaddr: str, xdata: InstrXData) -> Tuple[ASTLval, List[ASTInstruction]]: def indirect_lhs( rtype: Optional[BCTyp] ) -> Tuple[ASTLval, List[ASTInstruction]]: tmplval = astree.mk_returnval_variable_lval(iaddr, rtype) tmprhs = astree.mk_lval_expr(tmplval) reglval = astree.mk_register_variable_lval("R0") return (tmplval, [astree.mk_assign(reglval, tmprhs)]) calltarget = xdata.call_target(self.ixd) tgtname = calltarget.name models = ModelsAccess() if astree.has_symbol(tgtname): fnsymbol = astree.symbol(tgtname) if fnsymbol.returns_void: return (astree.mk_ignored_lval(), []) else: return indirect_lhs(fnsymbol.vtype) elif models.has_so_function_summary(tgtname): summary = models.so_function_summary(tgtname) returntype = summary.signature.returntype if returntype.is_named_type: returntype = cast(MNamedType, returntype) typename = returntype.typename if typename == "void" or typename == "VOID": return (astree.mk_ignored_lval(), []) else: return indirect_lhs(None) else: return indirect_lhs(None) else: return indirect_lhs(None)
def annotation(self, xdata: InstrXData) -> str: if xdata.has_call_target(): args = ", ".join(str(x) for x in xdata.xprs) tgt = str(self.call_target(xdata)) return "call " + tgt + "(" + args + ")" else: tgtx = str(xdata.xprs[0]) return 'call* ' + tgtx
def annotation(self, xdata: InstrXData) -> str: """data formats: call, jumptable, indirect jump call: [a:..., 'call'], <args> + <index of call-target in ixd> or xdata format: a:x . xprs[0]: target operand """ if self.is_call(xdata) and xdata.has_call_target(): tgt = xdata.call_target(self.ixd) args = ", ".join(str(x) for x in self.arguments(xdata)) return "call " + str(tgt) + "(" + args + ")" ctgt = str(xdata.xprs[0]) return "call " + ctgt
def annotation(self, xdata: InstrXData) -> str: """xdata format: a:vxx . with optional condition, identified by tags[1]: "TC" vars[0]: lhs xprs[0]: rhs xprs[1]: condition (if flagged by tags[1]) """ lhs = str(xdata.vars[0]) rhs = str(xdata.xprs[1]) assignment = lhs + " := " + rhs if xdata.has_unknown_instruction_condition(): return "if ? then " + assignment elif xdata.has_instruction_condition(): c = str(xdata.xprs[1]) return "if " + c + " then " + assignment else: return assignment
def target_expr_ast(self, astree: AbstractSyntaxTree, xdata: InstrXData) -> ASTExpr: calltarget = xdata.call_target(self.ixd) tgtname = calltarget.name if calltarget.is_app_target: apptgt = cast("AppTarget", calltarget) return astree.mk_global_variable_expr(tgtname, globaladdress=int( str(apptgt.address), 16)) else: return astree.mk_global_variable_expr(tgtname)
def annotation(self, xdata: InstrXData) -> str: """data format: a:<v0><args><call-target-ix> , or a:<v0> xprs[0]: value of v0 xprs[1...]: arguments xprs[-1]: index of call target in interface dictionary """ if xdata.has_call_target(): pargs = "(" + ", ".join(str(a) for a in self.arguments(xdata)) + ")" return str(xdata.call_target(self.ixd)) + pargs else: rhs = str(xdata.xprs[0]) if rhs.startswith("0x"): syscallnumber = int(rhs, 16) syscallfunction = SC.get_mips_linux_syscall(syscallnumber) return "linux-systemcall:" + syscallfunction else: return "linux-systemcall(" + rhs + ")"
def assembly_ast_condition(self, astree: AbstractSyntaxTree, iaddr: str, bytestring: str, xdata: InstrXData) -> Optional[ASTExpr]: ftconds = self.ft_conditions(xdata) if len(ftconds) == 2: tcond = ftconds[1] astcond = XU.xxpr_to_ast_expr(tcond, astree) if xdata.has_condition_setter(): csetter = xdata.get_condition_setter() cbytestr = xdata.get_condition_setter_bytestring() if int(csetter, 16) + (len(cbytestr) // 2) == int(iaddr, 16): newaddr = hex(int(iaddr, 16) - (len(cbytestr) // 2)) astree.add_instruction_span(astcond.id, newaddr, cbytestr + bytestring) else: astree.add_instruction_span(astcond.id, iaddr, bytestring) else: astree.add_instruction_span(astcond.id, iaddr, bytestring) return astcond else: return None
def assembly_ast( self, astree: AbstractSyntaxTree, iaddr: str, bytestring: str, xdata: InstrXData) -> List[AST.ASTInstruction]: if xdata.instruction_is_subsumed(): return [] else: (lhs, _, _) = self.operands[0].ast_lvalue(astree) (rhs, _, _) = self.operands[1].ast_rvalue(astree) assign = astree.mk_assign(lhs, rhs) astree.add_instruction_span(assign.id, iaddr, bytestring) return [assign]
def annotation(self, xdata: InstrXData) -> str: """data format: a:xx... + c direct call / resolved indirect call: xprs[0..] arguments calltarget unresolved indirect call: xprs[0] target expression xprs[1] target expression (simplified) xprs[2...] arguments """ if xdata.has_indirect_call_target_exprs(): tgtx = xdata.xprs[1] callargs = xdata.xprs[2:] return str(tgtx) + "(" + ",".join([str(x) for x in callargs]) + ")" elif xdata.has_call_target(): ctgt = xdata.call_target(self.ixd) callargs = xdata.xprs return str(ctgt) + "(" + ",".join([str(x) for x in callargs]) + ")" else: return "call to " + str(self.tgtoperand)
def annotation(self, xdata: InstrXData) -> str: """xdata format: a:v...x... . vars[0..n-1]: lhs variables xprs[0..n-1]: rhs memory values xprs[n]: conditional expression if TC is set """ vars = xdata.vars xprs = xdata.xprs xctr = len(vars) pairs = zip(vars, xprs[:xctr]) assigns = "; ".join(str(v) + " := " + str(x) for (v, x) in pairs) if xdata.has_instruction_condition(): pcond = "if " + str(xprs[xctr]) + " then " xctr += 1 elif xdata.has_unknown_instruction_condition(): pcond = "if ? then " else: pcond = "" return pcond + assigns
def ast( self, astree: AbstractSyntaxTree, iaddr: str, bytestring: str, xdata: InstrXData) -> List[AST.ASTInstruction]: if xdata.instruction_is_subsumed(): return [] else: lhs = XU.xvariable_to_ast_lval(xdata.vars[0], astree) rhs = XU.xxpr_to_ast_expr(xdata.xprs[0], astree) # (lhs, _, _) = self.operands[0].ast_lvalue(astree) # (rhs, _, _) = self.operands[1].ast_rvalue(astree) assign = astree.mk_assign(lhs, rhs) astree.add_instruction_span(assign.id, iaddr, bytestring) return [assign]
def assembly_ast(self, astree: AbstractSyntaxTree, iaddr: str, bytestring: str, xdata: InstrXData) -> List[ASTInstruction]: if self.is_call_instruction(xdata) and xdata.has_call_target(): lhs = astree.mk_register_variable_lval("R0") tgt = self.operands[0] if tgt.is_absolute: tgtaddr = cast(ARMAbsoluteOp, tgt.opkind) if self.app.has_function_name(tgtaddr.address.get_hex()): faddr = tgtaddr.address.get_hex() fnsymbol = self.app.function_name(faddr) tgtxpr: ASTExpr = astree.mk_global_variable_expr( fnsymbol, globaladdress=tgtaddr.address.get_int()) else: (tgtxpr, _, _) = self.operands[0].ast_rvalue(astree) else: (tgtxpr, _, _) = self.operands[0].ast_rvalue(astree) call = astree.mk_call(lhs, tgtxpr, []) astree.add_instruction_span(call.id, iaddr, bytestring) return [call] else: return []
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 get_instrx(self, ix: int) -> InstrXData: return InstrXData(self, self.instrx_table.retrieve(ix))
def is_unresolved_call(self, xdata: InstrXData) -> bool: return xdata.has_indirect_call_target_exprs()
def call_target(self, xdata: InstrXData) -> CallTarget: return xdata.call_target(self.ixd)
def has_call_target(self, xdata: InstrXData) -> bool: """Returns true if this is a direct call or a resolved indirect call.""" return xdata.has_call_target()
def ft_conditions(self, xdata: InstrXData) -> Sequence[XXpr]: if xdata.has_branch_conditions(): return [xdata.xprs[1], xdata.xprs[0]] else: return []
def is_call_instruction(self, xdata: InstrXData) -> bool: return xdata.has_call_target()