Ejemplo n.º 1
0
 def SHL(self):
     op0 = self._stack_pop()
     op1 = self._stack_pop()
     if not utils.is_symbol(op0) and not utils.is_symbol(op1):
         self._stack_push(op1 << op0)
     else:
         self._stack_push(Int("(" + op1 + " << " + op0 + ")"))
Ejemplo n.º 2
0
 def SDIV(self):
     op0 = self._stack_pop()
     op1 = self._stack_pop()
     if not utils.is_symbol(op0) and not utils.is_symbol(op1):
         self._stack_push(int(op0 // op1))  # TODO 浮点运算丢失精度
     else:
         self._stack_push(Int("(" + str(op0) + "//" + str(op1) + ")"))
Ejemplo n.º 3
0
 def XOR(self):
     op0 = self._stack_pop()
     op1 = self._stack_pop()
     if utils.is_symbol(op0) or utils.is_symbol(op1):
         self._stack_push(Int(str(op0) + "^" + str(op1)))
     else:
         self._stack_push(op0 ^ op1)
Ejemplo n.º 4
0
 def BYTE(self):
     op0 = self._stack_pop()
     op1 = self._stack_pop()
     if utils.is_symbol(op1) or utils.is_symbol(op0):
         self._stack_push(Int("byte_{0}".format(self._pc)))
     else:
         b = utils.int2bytes(op1, l_word=l_word, type_=int)
         self._stack_push(b[op0])
Ejemplo n.º 5
0
 def SGT(self):
     op0 = self._stack_pop()
     op1 = self._stack_pop()
     if utils.is_symbol(op0) or utils.is_symbol(op1):
         # raise EvmExecutionException("SLT does not support symbolic execution")
         self._stack_push(Int("sgt_{0}".format(self._pc)))
     else:
         self._stack_push(Word(op0).sgt(Word(op1)))
Ejemplo n.º 6
0
 def SMOD(self):
     op0 = self._stack_pop()
     op1 = self._stack_pop()
     if not utils.is_symbol(op0) and not utils.is_symbol(op1):
         self._stack_push(Word(op0).smod(Word(op1)))
     else:
         # raise EvmExecutionException("SMOD not support symbolic execution")
         self._stack_push(Int("smod_{0}".format(self._pc)))
Ejemplo n.º 7
0
 def DIV(self):
     op0 = self._stack_pop()
     op1 = self._stack_pop()
     if not utils.is_symbol(op0) and not utils.is_symbol(op1):
         decimal.getcontext().prec = 65
         self._stack_push(int(decimal.Decimal(op0) / decimal.Decimal(op1)))
     else:
         self._stack_push(op0 / op1)
Ejemplo n.º 8
0
 def conflicts_with(self, other):
     # if self will modify the content of other
     if utils.is_symbol(self.start) or utils.is_symbol(
             self.length) or utils.is_symbol(
                 other.start) or utils.is_symbol(other.length):
         return False
     if self.start <= other.start < self.start + self.length or other.start <= self.start < other.start + other.length:
         return True
     else:
         return False
Ejemplo n.º 9
0
 def AND(self):
     op0 = self._stack_pop()
     op1 = self._stack_pop()
     if utils.is_symbol(op0) or utils.is_symbol(op1):
         address_mask = 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff
         if not utils.is_symbol(op0) and op0 == address_mask:
             self._stack_push(op1)
         elif not utils.is_symbol(op1) and op1 == address_mask:
             self._stack_push(op0)
         else:
             self._stack_push(Int(str(op0) + "&" + str(op1)))
         # self._stack_push(Int(str(op0) + "&" + str(op1)))
     else:
         self._stack_push(op0 & op1)
Ejemplo n.º 10
0
 def NOT(self):
     # TODO bug fix
     op0 = self._stack_pop()
     if utils.is_symbol(op0):
         self._stack_push(Int("~" + str(op0)))
     else:
         self._stack_push(~op0)
Ejemplo n.º 11
0
 def SIGNEXTEND(self):
     op0 = self._stack_pop()
     op1 = self._stack_pop()
     t = l_word * 8 - 8 * (op0 + 1)
     if utils.is_symbol(op1):
         # raise EvmExecutionException("SIGNEXTEND does not support symbolic execution")
         self._stack_push(Int("signextend_{0}".format(self._pc)))
     else:
         self._stack_push(Word(op1).sign_extend(t))
Ejemplo n.º 12
0
 def op(self, instruction: Instruction, stack: Stack,
        immutable_storage_references: List[ImmutableStorageTracker]):
     # cases that the timestamp is used in conditional jump
     if instruction.opcode == "JUMPI":
         # 检查是否是时间戳与一个固定值进行比较
         if utils.is_symbol(stack[-2]):
             for z3_ref in utils.extract_z3_ref(stack[-2]):
                 if utils.is_z3_constant(z3_ref):
                     # 是一个z3表达式中的常量
                     continue
                 elif z3.eq(z3_ref, z3.Int("IHs")):
                     # 是时间戳
                     continue
                 else:
                     for ref in immutable_storage_references:
                         if ref.contains(
                                 len(stack) - 2) and utils.is_symbol(
                                     ref.storage_value) and utils.in_list(
                                         utils.extract_z3_ref(
                                             ref.storage_value), z3_ref):
                             break
                     else:
                         # 不是一个不可变Storage变量
                         break
                     # 是某一个不可变Storage变量
                     continue
             else:
                 # 参与比较的所有变量都是常量(除了时间戳本身)
                 self.pop(instruction.input_amount, len(stack))
                 return
         not_used_before = not self.used
         self.use(instruction, len(stack))
         if not_used_before and self.used:
             self.dependency_addr = instruction.addr
     else:
         self.pop(instruction.input_amount, len(stack))
Ejemplo n.º 13
0
    def op(self, instruction: Instruction, stack: Stack,
           immutable_storage_references):
        # cases that storage variables are used in the path condition of a CALL operation
        if instruction.opcode == "JUMPI":
            # make sure that the condition is the direct condition of CALL, WRONG, but may have false positives...
            # self.used = False
            # check if current condition contains Storage variable
            self.use(instruction, len(stack))
            if self.used is True:
                self.after_used_in_condition = True
        elif instruction.opcode in [
                "CALL", "STATICCALL", "DELEGATECALL", "CALLCODE"
        ]:
            self.checked_calls.append(instruction.addr)
            # check the gas forwarded
            self.pop(instruction.input_amount, len(stack))
            self.new(len(stack) - instruction.input_amount)
            gas = stack[-1]
            value = stack[-3]
            # 检测目的地址是否和是一个不确定的值(mutable)
            for ref in immutable_storage_references:
                if ref.contains(len(stack) - 2):
                    # 如果目的地址是一个确定的值,说明接收人是可信的
                    return

            if not utils.is_symbol(gas) and (int(gas) == 0
                                             or int(gas) == 2300):
                self.gas_guarded = True
                return
            if '2300' in str(gas):
                self.gas_guarded = True
                return
            if value == 0:
                self.value0 = True
                return
                # There is no reentrancy bug only when some storage values used in path conditions
                # are changed after the condition and before the call operation
            if not self.changed_after_condition or not self.changed_before_call:
                self.buggy = True
                self.vulnerable_calls.append(instruction.addr)
                # clear detection history, be prepare for the next reentrancy
                self.after_call = False
                self.changed_before_call = False
                return
            self.after_call = True
        else:
            self.pop(instruction.input_amount, len(stack))
Ejemplo n.º 14
0
    def get_status(self):
        resp = {
            "storage": [],
            "memory": [],
            "stack": [],
        }

        for key, value in self._evm.get_storage().items():
            resp["storage"].append((hex(key), str(value)))
        for value in self._evm.get_memory().values():
            resp["memory"].append(
                (hex(value.start), hex(value.length), str(value.content)))
        for item in reversed(self._evm.get_stack()):
            if utils.is_symbol(item):
                resp["stack"].append(str(item))
            else:
                resp["stack"].append(hex(int(item))[2:].rjust(64, '0'))
        return resp
Ejemplo n.º 15
0
 def _show_status(self):
     if len(self._evm.get_storage()) > 0:
         self._c_printer.print("Storage: ")
         for key, value in self._evm.get_storage().items():
             self._c_printer.print("\t{0} => {1}".format(key, value))
         self._c_printer.print()
     if len(self._evm.get_memory()) > 0:
         self._c_printer.print("Memory: ")
         for value in self._evm.get_memory().values():
             self._c_printer.print(
                 "\t{0}...{1} => {2}".format(value.start, value.start + value.length, value.content))
         self._c_printer.print()
     self._c_printer.print("Stack: ")
     for item in reversed(self._evm.get_stack()):
         if utils.is_symbol(item):
             self._c_printer.print("\t" + str(item))
         else:
             self._c_printer.print("\t" + hex(int(item))[2:].rjust(64, '0'))
     self._c_printer.print()
Ejemplo n.º 16
0
 def SHA3(self):
     op0 = self._stack_pop()
     op1 = self._stack_pop()
     # m_slice = self._memory[int(op0):int(op0) + int(op1)]
     value = self._memory.load(op0, op1)
     global sha3_map
     if value in sha3_map.keys():
         self._stack_push(sha3_map[value])
     else:
         if utils.is_symbol(value):
             sha3_value = Int("SHA3_{0}".format(self._pc))
             self._stack_push(sha3_value)
             sha3_map[value] = sha3_value
             return
         else:
             value1 = bytes(utils.int2bytes(value, type_=int))
             keccak_hash = keccak.new(digest_bits=8 * l_word)
             keccak_hash.update(value1)
             hash_value = keccak_hash.hexdigest()
             self._stack_push(Word(hash_value))
             sha3_map[value] = Word(hash_value)
             return
Ejemplo n.º 17
0
 def _get_block_index(self, addr: int) -> int:
     if utils.is_symbol(addr):
         raise AnalyzerException("Do not support symbolic JUMP destination")
     for index, block in enumerate(self.blocks):
         if block.address == addr:
             return index
Ejemplo n.º 18
0
    def _update_all_ref_tracker(self, instruction: Instruction):
        # update all the references
        for ref in self.call_result_references + self.timestamp_references + self.reentrancy_references:
            ref.update(instruction, self._stack,
                       self.immutable_storage_references)
        # check if there are new references
        if instruction.opcode in [
                'CALL', "STATICCALL", "DELEGATECALL", "CALLCODE"
        ]:
            h = len(self._stack) - instruction.input_amount
            if len(self.reentrancy_references) == 0:
                # 如果之前没有任何Storage被读取,也就是为创建任何ReentrancyTracker,那么当前的这个Call就是有reentrancy bug的
                tmp = ReentrancyTracker(instruction.addr, h, -1)
                tmp.buggy = True
                self.reentrancy_references.append(tmp)
            # 判断Call的目的地址是否是可变的(mutable)
            for ref in self.immutable_storage_references:
                if ref.contains(len(self._stack) - 2):
                    break
            else:
                # 当前的目的地址包含在某一个mutable storage reference中
                # 只有当目的地址不是一个确定值,也就是说不可靠的时候
                # new call result reference is generated
                call_ref = CallResultTracker(instruction.addr, h)
                self.call_result_references.append(call_ref)
        elif instruction.opcode == "TIMESTAMP":
            # new timestamp reference is generated here
            ref = TimestampDepTracker(instruction.addr, len(self._stack))
            self.timestamp_references.append(ref)
        elif instruction.opcode == "SLOAD":
            storage_addr = self._stack[-1]
            h = len(self._stack) - instruction.input_amount
            # 检查是否需要新建MutableStorageTracker
            if not utils.in_list(self.mutable_storage_addresses, storage_addr):
                # 是不可变的(immutable)
                for ref in self.immutable_storage_references:
                    if utils.eq(ref.storage_addr, storage_addr):
                        ref.new(h)
                        ref.new_born = True
                        break
                else:
                    ref = ImmutableStorageTracker(instruction.addr, h,
                                                  storage_addr,
                                                  self._storage[storage_addr])
                    self.immutable_storage_references.append(ref)
            # 检查是否需要新建ReentrancyTracker
            for r in self.reentrancy_references:
                # check if there already exists the same reference
                try:
                    if utils.is_symbol(storage_addr) and utils.is_symbol(
                            r.storage_addr) and eq(
                                simplify(r.storage_addr),
                                simplify(storage_addr)) or not utils.is_symbol(
                                    storage_addr) and not utils.is_symbol(
                                        r.storage_addr
                                    ) and r.storage_addr == storage_addr:
                        r.new(h)
                        break
                except Exception as e:
                    print(e)
            else:
                ref = ReentrancyTracker(instruction.addr, h, storage_addr)
                self.reentrancy_references.append(ref)

        # 更新mutable storage reference
        for ref in self.immutable_storage_references:
            if ref.new_born:
                ref.new_born = False
            else:
                ref.update(instruction, self._stack, None)
Ejemplo n.º 19
0
 def exe_with_path_condition(self,
                             instruction: Instruction,
                             path_condition: list = []) -> PcPointer:
     self._update_all_ref_tracker(instruction)
     if instruction.opcode == "SSTORE":
         # save the value of every referred storage variable before SSTORE
         bak = {}
         for ref in self.reentrancy_references:
             bak[ref] = self._storage[ref.storage_addr]
     if instruction.opcode == "SSTORE" and self.pre_process:
         op0 = self._stack[-1]
         # 在可信条件下进行修改的Storage变量仍然是可信的(immutable)
         caller = z3.Int("Is")
         solver = z3.Solver()
         solver.add(path_condition)
         if "sat" == str(solver.check()):
             for storage_addr, storage_value in self._storage.get_storage(
             ).items():
                 if not utils.in_list(self.mutable_storage_addresses,
                                      storage_addr):
                     # solver.add(caller & 0xffffffffffffffffffff != storage_value & 0xffffffffffffffffffff)
                     mask = 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff
                     if utils.is_symbol(storage_value):
                         # solver.add(z3.Int(str("Is") + "&" + str(mask)) != z3.Int(str(storage_value) + "&" + str(mask)))
                         # solver.add(z3.Int(str(mask) + "&" + str("Is")) != z3.Int(str(storage_value) + "&" + str(mask)))
                         # solver.add(z3.Int(str("Is") + "&" + str(mask)) != z3.Int(str(mask) + "&" + str(storage_value)))
                         # solver.add(z3.Int(str(mask) + "&" + str("Is")) != z3.Int(str(mask) + "&" + str(storage_value)))
                         # solver.add(z3.Int(str("Is")) != z3.Int(str(storage_value)))
                         solver.add(
                             z3.Int(str("Is")) != z3.Int(str(storage_value))
                         )
                     else:
                         # solver.add(z3.Int(str("Is") + "&" + str(mask)) != storage_value & mask)
                         # solver.add(z3.Int(str(mask) + "&" + str("Is")) != storage_value & mask)
                         solver.add(
                             z3.Int(str("Is")) != storage_value & mask)
             if "sat" == str(solver.check()):
                 # caller不为任意一个可信storage变量的时候仍然可能进行SSTORE,则说明被修改的storage变量是不可靠的
                 if not utils.in_list(self.mutable_storage_addresses, op0):
                     self.mutable_storage_addresses.append(op0)
     pc_pointer = super().exe(instruction)
     if instruction.opcode == "SSTORE":
         # check if any referred storage variable is changed after SSTORE
         # if len(bak) != len(self._storage):
         #     # 如果新增了Storage变量,那么一定是做修改了
         #     ref.storage_changed = True
         #     if ref.after_used_in_condition:
         #         ref.changed_after_condition = True
         #     if not ref.after_call:
         #         ref.changed_before_call = True
         # else:
         # 如果Storage变量的个数没变,那么就检查每一个变量的值有没有改变
         for ref, value in bak.items():
             if utils.is_symbol(value) is not utils.is_symbol(self._storage[ref.storage_addr]) or \
                     utils.is_symbol(value) and not eq(simplify(value),
                                                       simplify(self._storage[ref.storage_addr])) or \
                     not utils.is_symbol(value) and value != self._storage[ref.storage_addr]:
                 ref.storage_changed = True
                 if ref.after_used_in_condition:
                     ref.changed_after_condition = True
                 if not ref.after_call:
                     ref.changed_before_call = True
     return pc_pointer