def is_byte_swap(self): try: self.model_variable() except ModelIsConstrained: return False # Figure out if this might be a byte swap byte_values_len = len(self.byte_values) #print self.byte_values if 1 < byte_values_len <= self.var.src.var.type.width: var = create_BitVec(self.var.src, self.var.src.var.type.width) ordering = list(reversed([ self.byte_values[x] for x in sorted(self.byte_values.keys()) ])) reverse_var = Concat( *reversed([ Extract(i-1, i-8, var) for i in range(len(ordering) * 8, 0, -8) ]) ) if len(ordering) < 4: reverse_var = Concat( Extract( 31, len(ordering)*8, var ), reverse_var ) reversed_ordering = reversed(ordering) reversed_ordering = Concat(*reversed_ordering) # The idea here is that if we add the negation of this, if it's # not satisfiable, then that means there is no value such that # the equivalence does not hold. If that is the case, then this # should be a byte-swapped value. self.solver.add( Not( And( var == ZeroExt( var.size() - len(ordering)*8, Concat(*ordering) ), reverse_var == ZeroExt( reverse_var.size() - reversed_ordering.size(), reversed_ordering ) ) ) ) if self.solver.check() == unsat: return True return False
def visit_MLIL_LSL(self, expr): left, right = self.visit_both_sides(expr) if right.size() != left.size(): right = ZeroExt(left.size() - right.size(), right) return left << right
def evaluate_MLIL_MULU_DP(self, state): # TODO: CONFIRM THIS IS CORRECT # FIXME: Possibly broken on 64 bit; Might also be SET_VAR_SPLIT_SSA. operand_1, operand_2 = self.instructions_to_operands( self.instruction.operands, state, self.instruction.size) result_size = self.instruction.size * 8 * 2 result = ZeroExt(result_size // 2, operand_1) * ZeroExt( result_size // 2, operand_2) return [result]
def visit_MLIL_SET_VAR_SSA_FIELD(self, expr): # expr.size will be the width of the field, so we need the dest's real # width dest = create_BitVec(expr.dest, expr.dest.var.type.width) prev = create_BitVec(expr.prev, expr.prev.var.type.width) mask = (1 << (expr.size * 8) - 1) << (expr.offset * 8) mask = ~mask & ((1 << (expr.dest.var.type.width * 8)) - 1) src = self.visit(expr.src) self.visited.add(expr.dest) if expr.instr_index in self.to_visit: self.to_visit.remove(expr.instr_index) if src is not None: self.solver.add( dest == ( (prev & mask) | ZeroExt( ( expr.dest.var.type.width - (expr.size + expr.offset) ) * 8, (src << (expr.offset * 8)) ) ) )
def instructions_to_operands(self, instructions: List[MediumLevelILInstruction], state, size: int): """ Get operands from instruction list, increasing their size if needed. :instructions: List of instructions to convert to operands :state: Current active state :size: Minimum size in bytes of the operands """ operands = [] largest_size = size * 8 for instruction in instructions: ops = MLILInstructionExecutor(self.bv, instruction).execute(state) # TODO: Is this needed: for op in ops: if op.size() > largest_size: largest_size = op.size() operands.append(op) for i, op in enumerate(operands): if op.size() < largest_size: operands[i] = ZeroExt(largest_size - op.size(), op) return operands
def visit_MLIL_ZX(self, expr): src = self.visit(expr.src) if src is not None: return ZeroExt( (expr.size - expr.src.size) * 8, src )
def add_account(self, bytecode: str, addr: BitVecRef = None) -> BitVecRef: # アカウント番号とAccount address生成 new_num = len(self.accounts) new_addr = ZeroExt(96, BitVec('address{}'.format(new_num), 160)) if addr is None else addr # Account生成 account = Account(bytecode, new_num) # アドレスとAccountインスタンスの対応をaccountsに保存 self.accounts[str(new_addr)] = account return new_addr
def add_account(self, bytecode: Bytecode, addr: BitVecRef = None) -> BitVecRef: # generate account number and account address new_num = len(self.accounts) new_addr = ZeroExt(96, BitVec('address{}'.format(new_num), 160)) if addr is None else addr # generate Account object account = Account(bytecode, new_num) # アドレスとAccountインスタンスの対応をaccountsに保存 self.accounts[str(new_addr)] = account return new_addr
def execute(self, state): """ Execute instruction that this class was initialized with. :state: Current active state """ operation = self.instruction.operation.name log.log_debug("Evaluating {}: {} @ {}".format( operation, self.instruction, hex(self.instruction.address))) try: if self.instruction.value.is_constant: size = self.instruction.size * 8 return [BitVecVal(self.instruction.value.value, size)] except AttributeError: pass executor = getattr(self, "evaluate_" + operation, None) if executor is not None: result = executor(state) else: raise NotImplementedError(repr(operation)) for i in range(len(result)): width = self.instruction.size * 8 if operation.endswith("_DP"): # Double precision width = width * 2 if width < result[i].size(): result[i] = Extract(width - 1, 0, result[i]) if width > result[i].size(): result[i] = ZeroExt(width - result[i].size(), result[i]) log.log_debug("Completed {}: {} @ {}".format( operation, self.instruction, hex(self.instruction.address))) return result
def visit_MLIL_CMP_NE(self, expr): left = self.visit(expr.left) right = self.visit(expr.right) if right.size() != left.size(): right = ZeroExt(left.size() - right.size(), right) return left != right
def evaluate_MLIL_ZX(self, state): # TODO: Confirm size [operand] = self.instructions_to_operands(self.instruction.operands, state, self.instruction.size) return [ZeroExt(32, operand)]
def ADDMOD(x, y, m): return If(m == 0, 0, Extract(x.size() - 1, 0, URem(ZeroExt(1, x) + ZeroExt(1, y), ZeroExt(1, m))))
def MULMOD(x, y, m): return If(m == 0, 0, Extract(x.size() - 1, 0, URem(ZeroExt(x.size(), x) * ZeroExt(x.size(), y), ZeroExt(m.size(), m))))
def to_smt(r): # type: (Rtl) -> Tuple[List[ExprRef], Z3VarMap] """ Encode a concrete primitive Rtl r sa z3 query. Returns a tuple (query, var_m) where: - query is a list of z3 expressions - var_m is a map from Vars v with non-BVType to their correspodning z3 bitvector variable. """ assert r.is_concrete() # Should contain only primitives primitives = set(PRIMITIVES.instructions) assert set(d.expr.inst for d in r.rtl).issubset(primitives) q = [] # type: List[ExprRef] m = {} # type: Z3VarMap # Build declarations for any bitvector Vars var_to_bv = {} # type: Z3VarMap for v in r.vars(): typ = v.get_typevar().singleton_type() if not isinstance(typ, BVType): continue var_to_bv[v] = BitVec(v.name, typ.bits) # Encode each instruction as a equality assertion for d in r.rtl: inst = d.expr.inst exp = None # type: ExprRef # For prim_to_bv/prim_from_bv just update var_m. No assertion needed if inst == prim_to_bv: assert isinstance(d.expr.args[0], Var) m[d.expr.args[0]] = var_to_bv[d.defs[0]] continue if inst == prim_from_bv: assert isinstance(d.expr.args[0], Var) m[d.defs[0]] = var_to_bv[d.expr.args[0]] continue if inst in [bvadd, bvult]: # Binary instructions assert len(d.expr.args) == 2 and len(d.defs) == 1 lhs = d.expr.args[0] rhs = d.expr.args[1] df = d.defs[0] assert isinstance(lhs, Var) and isinstance(rhs, Var) if inst == bvadd: # Normal binary - output type same as args exp = (var_to_bv[lhs] + var_to_bv[rhs]) else: assert inst == bvult exp = (var_to_bv[lhs] < var_to_bv[rhs]) # Comparison binary - need to convert bool to BitVec 1 exp = If(exp, BitVecVal(1, 1), BitVecVal(0, 1)) exp = mk_eq(var_to_bv[df], exp) elif inst == bvzeroext: arg = d.expr.args[0] df = d.defs[0] assert isinstance(arg, Var) fromW = arg.get_typevar().singleton_type().width() toW = df.get_typevar().singleton_type().width() exp = mk_eq(var_to_bv[df], ZeroExt(toW - fromW, var_to_bv[arg])) elif inst == bvsignext: arg = d.expr.args[0] df = d.defs[0] assert isinstance(arg, Var) fromW = arg.get_typevar().singleton_type().width() toW = df.get_typevar().singleton_type().width() exp = mk_eq(var_to_bv[df], SignExt(toW - fromW, var_to_bv[arg])) elif inst == bvsplit: arg = d.expr.args[0] assert isinstance(arg, Var) arg_typ = arg.get_typevar().singleton_type() width = arg_typ.width() assert (width % 2 == 0) lo = d.defs[0] hi = d.defs[1] exp = And( mk_eq(var_to_bv[lo], Extract(width // 2 - 1, 0, var_to_bv[arg])), mk_eq(var_to_bv[hi], Extract(width - 1, width // 2, var_to_bv[arg]))) elif inst == bvconcat: assert isinstance(d.expr.args[0], Var) and \ isinstance(d.expr.args[1], Var) lo = d.expr.args[0] hi = d.expr.args[1] df = d.defs[0] # Z3 Concat expects hi bits first, then lo bits exp = mk_eq(var_to_bv[df], Concat(var_to_bv[hi], var_to_bv[lo])) else: assert False, "Unknown primitive instruction {}".format(inst) q.append(exp) return (q, m)