コード例 #1
0
    def __getitem__(self, item: Union[int, slice, BitVec]) -> Any:
        """

        :param item:
        :return:
        """
        if isinstance(item, int) or isinstance(item, Expression):
            return self._load(item)

        if isinstance(item, slice):
            start = 0 if item.start is None else item.start
            step = 1 if item.step is None else item.step
            stop = self.size if item.stop is None else item.stop

            try:
                current_index = (
                    start
                    if isinstance(start, Expression)
                    else symbol_factory.BitVecVal(start, 256)
                )
                parts = []
                while simplify(current_index != stop):
                    element = self._load(current_index)
                    if not isinstance(element, Expression):
                        element = symbol_factory.BitVecVal(element, 8)

                    parts.append(element)
                    current_index = simplify(current_index + step)
            except Z3Exception:
                raise IndexError("Invalid Calldata Slice")

            return parts

        raise ValueError
コード例 #2
0
    def _load(self, item: Union[int, BitVec]) -> Any:
        """

        :param item:
        :return:
        """
        item = symbol_factory.BitVecVal(item, 256) if isinstance(item, int) else item
        return simplify(
            If(
                item < self._size,
                simplify(self._calldata[cast(BitVec, item)]),
                symbol_factory.BitVecVal(0, 8),
            )
        )
コード例 #3
0
    def __setitem__(
        self,
        key: Union[int, BitVec, slice],
        value: Union[BitVec, int, List[Union[int, BitVec]]],
    ):
        """

        :param key:
        :param value:
        """
        if isinstance(key, slice):
            start, step, stop = key.start, key.step, key.stop

            if start is None:
                start = 0
            if stop is None:
                raise IndexError("Invalid Memory Slice")
            if step is None:
                step = 1
            else:
                assert False, "Currently mentioning step size is not supported"
            assert type(value) == list
            bvstart, bvstop, bvstep = (
                convert_bv(start),
                convert_bv(stop),
                convert_bv(step),
            )
            symbolic_len = False
            itr = symbol_factory.BitVecVal(0, 256)
            if (bvstop - bvstart).symbolic:
                symbolic_len = True
            while simplify(bvstart + bvstep * itr != bvstop) and (
                not symbolic_len or itr <= APPROX_ITR
            ):
                self[bvstart + itr * bvstep] = cast(List[Union[int, BitVec]], value)[
                    itr.value
                ]
                itr += 1

        else:
            bv_key = simplify(convert_bv(key))
            if bv_key >= len(self):
                return
            if isinstance(value, int):
                assert 0 <= value <= 0xFF
            if isinstance(value, BitVec):
                assert value.size() == 8
            self._memory[bv_key] = cast(Union[int, BitVec], value)
コード例 #4
0
ファイル: memory.py プロジェクト: mygirl8893/mythril
    def get_word_at(self, index: int) -> Union[int, BitVec]:
        """Access a word from a specified memory index.

        :param index: integer representing the index to access
        :return: 32 byte word at the specified index
        """
        try:
            return symbol_factory.BitVecVal(
                util.concrete_int_from_bytes(
                    bytes([
                        util.get_concrete_int(b)
                        for b in self[index:index + 32]
                    ]),
                    0,
                ),
                256,
            )
        except TypeError:
            result = simplify(
                Concat([
                    b if isinstance(b, BitVec) else symbol_factory.BitVecVal(
                        b, 8)
                    for b in cast(List[Union[int,
                                             BitVec]], self[index:index + 32])
                ]))
            assert result.size() == 256
            return result
コード例 #5
0
ファイル: callgraph.py プロジェクト: cpstdhs/mythril-docker
def extract_edges(statespace):
    """

    :param statespace:
    :return:
    """
    edges = []
    for edge in statespace.edges:
        if edge.condition is None:
            label = ""
        else:
            try:
                label = str(simplify(edge.condition)).replace("\n", "")
            except Z3Exception:
                label = str(edge.condition).replace("\n", "")

        label = re.sub(
            r"([^_])([\d]{2}\d+)", lambda m: m.group(1) + hex(int(m.group(2))), label
        )

        edges.append(
            {
                "from": str(edge.as_dict["from"]),
                "to": str(edge.as_dict["to"]),
                "arrows": "to",
                "label": label,
                "smooth": {"type": "cubicBezier"},
            }
        )
    return edges
コード例 #6
0
    def __getitem__(self, item: BitVec) -> BitVec:
        storage, is_keccak_storage = self._get_corresponding_storage(item)
        if is_keccak_storage:
            item = self._sanitize(cast(BitVecFunc, item).input_)
        value = storage[item]
        if (value.value == 0 and self.address and item.symbolic is False
                and self.address.value != 0
                and (self.dynld and self.dynld.storage_loading)):
            try:
                storage[item] = symbol_factory.BitVecVal(
                    int(
                        self.dynld.read_storage(
                            contract_address=hex(self.address.value),
                            index=int(item.value),
                        ),
                        16,
                    ),
                    256,
                )
                self.printable_storage[item] = storage[item]
                return storage[item]
            except ValueError:
                pass

        return simplify(storage[item])
コード例 #7
0
    def __getitem__(self, item: BitVec) -> BitVec:
        storage, is_keccak_storage = self._get_corresponding_storage(item)
        if is_keccak_storage:
            sanitized_item = self._sanitize(cast(BitVecFunc, item).input_)
        else:
            sanitized_item = item
        if (
            self.address
            and self.address.value != 0
            and item.symbolic is False
            and int(item.value) not in self.storage_keys_loaded
            and (self.dynld and self.dynld.storage_loading)
        ):
            try:
                storage[sanitized_item] = symbol_factory.BitVecVal(
                    int(
                        self.dynld.read_storage(
                            contract_address="0x{:040X}".format(self.address.value),
                            index=int(item.value),
                        ),
                        16,
                    ),
                    256,
                )
                self.storage_keys_loaded.add(int(item.value))
                self.printable_storage[item] = storage[sanitized_item]
            except ValueError as e:
                log.debug("Couldn't read storage at %s: %s", item, e)

        return simplify(storage[sanitized_item])
コード例 #8
0
    def get_word_at(self, offset: int) -> Expression:
        """Gets word at offset.

        :param offset:
        :return:
        """
        parts = self[offset : offset + 32]
        return simplify(Concat(parts))
コード例 #9
0
    def _load(self, item: Union[int, BitVec]) -> BitVec:
        """

        :param item:
        :return:
        """
        item = symbol_factory.BitVecVal(item, 256) if isinstance(item, int) else item
        return simplify(self._calldata[item])
コード例 #10
0
 def get_map_index(key: BitVec) -> BitVec:
     if (
         not isinstance(key, BitVecFunc)
         or key.func_name != "keccak256"
         or key.input_ is None
     ):
         return None
     index = Extract(255, 0, key.input_)
     return simplify(index)
コード例 #11
0
ファイル: constraints.py プロジェクト: dotrungkien/mythril
    def append(self, constraint: Union[bool, Bool]) -> None:
        """

        :param constraint: The constraint to be appended
        """
        constraint = (simplify(constraint)
                      if isinstance(constraint, Bool) else Bool(constraint))
        super(Constraints, self).append(constraint)
        self._is_possible = None
コード例 #12
0
ファイル: call.py プロジェクト: yxliang01/mythril-classic
def get_callee_address(
    global_state: GlobalState,
    dynamic_loader: DynLoader,
    symbolic_to_address: Expression,
):
    """Gets the address of the callee.

    :param global_state: state to look in
    :param dynamic_loader:  dynamic loader to use
    :param symbolic_to_address: The (symbolic) callee address
    :return: Address of the callee
    """
    environment = global_state.environment

    try:
        callee_address = hex(util.get_concrete_int(symbolic_to_address))
    except TypeError:
        log.debug("Symbolic call encountered")

        match = re.search(r"storage_(\d+)", str(simplify(symbolic_to_address)))
        log.debug("CALL to: " + str(simplify(symbolic_to_address)))

        if match is None or dynamic_loader is None:
            raise ValueError()

        index = int(match.group(1))
        log.debug("Dynamic contract address at storage index {}".format(index))

        # attempt to read the contract address from instance storage
        try:
            callee_address = dynamic_loader.read_storage(
                environment.active_account.address, index
            )
        # TODO: verify whether this happens or not
        except:
            log.debug("Error accessing contract storage.")
            raise ValueError

        # testrpc simply returns the address, geth response is more elaborate.
        if not re.match(r"^0x[0-9a-f]{40}$", callee_address):
            callee_address = "0x" + callee_address[26:]

    return callee_address
コード例 #13
0
ファイル: util.py プロジェクト: xahiru/mythril
def concrete_int_to_bytes(val):
    """

    :param val:
    :return:
    """
    # logging.debug("concrete_int_to_bytes " + str(val))
    if type(val) == int:
        return val.to_bytes(32, byteorder="big")
    return simplify(val).value.to_bytes(32, byteorder="big")
コード例 #14
0
ファイル: ops.py プロジェクト: yxliang01/mythril-classic
def get_variable(i):
    """

    :param i:
    :return:
    """
    try:
        return Variable(util.get_concrete_int(i), VarType.CONCRETE)
    except TypeError:
        return Variable(simplify(i), VarType.SYMBOLIC)
コード例 #15
0
def test_concrete_shr(val1, val2, expected):
    state = get_state()
    state.mstate.stack = [BVV(int(val1, 16), 256), BVV(int(val2, 16), 256)]
    expected = BVV(int(expected, 16), 256)
    instruction = Instruction("shr", dynamic_loader=None)

    # Act
    new_state = instruction.evaluate(state)[0]

    # Assert
    assert simplify(new_state.mstate.stack[-1]) == expected
コード例 #16
0
ファイル: mstate_test.py プロジェクト: cpstdhs/mythril-docker
def test_memory_write():
    # Arrange
    mem = Memory()
    mem.extend(200 + 32)

    a = symbol_factory.BitVecSym("a", 256)
    b = symbol_factory.BitVecSym("b", 8)

    # Act
    mem[11] = 10
    mem[12] = b
    mem.write_word_at(200, 0x12345)
    mem.write_word_at(100, a)

    # Assert
    assert mem[0] == 0
    assert mem[11] == 10
    assert mem[200 + 31] == 0x45
    assert mem.get_word_at(200) == 0x12345
    assert simplify(a == mem.get_word_at(100))
    assert simplify(b == mem[12])
コード例 #17
0
def test_shr(inputs, output):
    # Arrange
    state = get_state()

    state.mstate.stack = inputs
    instruction = Instruction("shr", dynamic_loader=None)

    # Act
    new_state = instruction.evaluate(state)[0]

    # Assert
    assert simplify(new_state.mstate.stack[-1]) == output
コード例 #18
0
ファイル: call.py プロジェクト: xahiru/mythril
def get_call_data(
    global_state: GlobalState,
    memory_start: Union[int, BitVec],
    memory_size: Union[int, BitVec],
):
    """Gets call_data from the global_state.

    :param global_state: state to look in
    :param memory_start: Start index
    :param memory_size: Size
    :return: Tuple containing: call_data array from memory or empty array if symbolic, type found
    """
    state = global_state.mstate
    transaction_id = "{}_internalcall".format(global_state.current_transaction.id)

    memory_start = cast(
        BitVec,
        (
            symbol_factory.BitVecVal(memory_start, 256)
            if isinstance(memory_start, int)
            else memory_start
        ),
    )
    memory_size = cast(
        BitVec,
        (
            symbol_factory.BitVecVal(memory_size, 256)
            if isinstance(memory_size, int)
            else memory_size
        ),
    )

    uses_entire_calldata = simplify(
        memory_size == global_state.environment.calldata.calldatasize
    )

    if is_true(uses_entire_calldata):
        return global_state.environment.calldata

    try:
        calldata_from_mem = state.memory[
            util.get_concrete_int(memory_start) : util.get_concrete_int(
                memory_start + memory_size
            )
        ]
        return ConcreteCalldata(transaction_id, calldata_from_mem)
    except TypeError:
        log.debug(
            "Unsupported symbolic memory offset %s size %s", memory_start, memory_size
        )
        return SymbolicCalldata(transaction_id)
コード例 #19
0
    def __getitem__(
        self, item: Union[BitVec, slice]
    ) -> Union[BitVec, int, List[Union[int, BitVec]]]:
        """

        :param item:
        :return:
        """
        if isinstance(item, slice):
            start, step, stop = item.start, item.step, item.stop
            if start is None:
                start = 0
            if stop is None:  # 2**256 is just a bit too big
                raise IndexError("Invalid Memory Slice")
            if step is None:
                step = 1
            bvstart, bvstop, bvstep = (
                convert_bv(start),
                convert_bv(stop),
                convert_bv(step),
            )
            ret_lis = []
            symbolic_len = False
            itr = symbol_factory.BitVecVal(0, 256)
            if (bvstop - bvstart).symbolic:
                symbolic_len = True

            while simplify(bvstart + bvstep * itr != bvstop) and (
                not symbolic_len or itr <= APPROX_ITR
            ):
                ret_lis.append(self[bvstart + bvstep * itr])
                itr += 1

            return ret_lis

        item = simplify(convert_bv(item))
        return self._memory.get(item, 0)
コード例 #20
0
ファイル: calldata.py プロジェクト: xahiru/mythril
    def _load(self, item: Union[int, BitVec], clean=False) -> Any:
        expr_item = (symbol_factory.BitVecVal(item, 256) if isinstance(
            item, int) else item)  # type: BitVec

        symbolic_base_value = If(
            expr_item >= self._size,
            symbol_factory.BitVecVal(0, 8),
            BitVec(
                symbol_factory.BitVecSym(
                    "{}_calldata_{}".format(self.tx_id, str(item)), 8)),
        )
        return_value = symbolic_base_value
        for r_index, r_value in self._reads:
            return_value = If(r_index == expr_item, r_value, return_value)
        if not clean:
            self._reads.append((expr_item, symbolic_base_value))
        return simplify(return_value)
コード例 #21
0
ファイル: util.py プロジェクト: xahiru/mythril
def pop_bitvec(state: "MachineState") -> BitVec:
    """

    :param state:
    :return:
    """
    # pop one element from stack, converting boolean expressions and
    # concrete Python variables to BitVecVal

    item = state.stack.pop()

    if isinstance(item, Bool):
        return If(
            cast(Bool, item),
            symbol_factory.BitVecVal(1, 256),
            symbol_factory.BitVecVal(0, 256),
        )
    elif isinstance(item, int):
        return symbol_factory.BitVecVal(item, 256)
    else:
        item = cast(BitVec, item)
        return simplify(item)
コード例 #22
0
    def _sha3_preprocess(self, state: GlobalState):
        """
        Helper function that scans the memory for words that are concrete values, checks
        if their value exists in the cache, and in that case marks that value to be forwarded
        (later as an annotation) after the SHA3 operation gets executed.

        This is a hack for forwarding annotations of concrete values since once the Laser EVM stores
        a (concrete) value in memory, only the bytes get stored (not as BitVec instances), and all the
        annotations get lost.
        """
        word_len = 32
        lo = state.mstate.stack[-1].value
        hi = lo + state.mstate.stack[-2].value
        if hi - lo < word_len:
            return
        for i in range(lo, hi, word_len):
            data_list = [
                b if isinstance(b, BitVec) else symbol_factory.BitVecVal(b, 8)
                for b in state.mstate.memory[i:i + word_len]
            ]
            data = simplify(Concat(data_list))
            if data.symbolic is False and data.value in self.concrete_memory_cache:
                self.sha3_should_forward = True
                self.concrete_memory_cache.remove(data.value)
コード例 #23
0
def get_serializable_statespace(statespace):
    """

    :param statespace:
    :return:
    """
    nodes = []
    edges = []

    color_map = {}
    i = 0
    for k in statespace.accounts:
        color_map[statespace.accounts[k].contract_name] = colors[i]
        i += 1

    for node_key in statespace.nodes:

        node = statespace.nodes[node_key]

        code = node.get_cfg_dict()["code"]
        code = re.sub("([0-9a-f]{8})[0-9a-f]+", lambda m: m.group(1) + "(...)", code)

        if NodeFlags.FUNC_ENTRY in node.flags:
            code = re.sub("JUMPDEST", node.function_name, code)

        code_split = code.split("\\n")

        truncated_code = (
            code
            if (len(code_split) < 7)
            else "\\n".join(code_split[:6]) + "\\n(click to expand +)"
        )

        color = color_map[node.get_cfg_dict()["contract_name"]]

        def get_state_accounts(node_state):
            """

            :param node_state:
            :return:
            """
            state_accounts = []
            for key in node_state.accounts:
                account = node_state.accounts[key].as_dict
                account.pop("code", None)
                account["balance"] = str(account["balance"])

                storage = {}
                for storage_key in account["storage"].keys():
                    storage[str(storage_key)] = str(account["storage"][storage_key])

                state_accounts.append({"address": key, "storage": storage})
            return state_accounts

        states = [
            {"machine": x.mstate.as_dict, "accounts": get_state_accounts(x)}
            for x in node.states
        ]

        for state in states:
            state["machine"]["stack"] = [str(s) for s in state["machine"]["stack"]]
            state["machine"]["memory"] = [
                str(m)
                for m in state["machine"]["memory"][: len(state["machine"]["memory"])]
            ]

        truncated_code = truncated_code.replace("\\n", "\n")
        code = code.replace("\\n", "\n")

        s_node = {
            "id": str(node_key),
            "func": str(node.function_name),
            "label": truncated_code,
            "code": code,
            "truncated": truncated_code,
            "states": states,
            "color": color,
            "instructions": code.split("\n"),
        }

        nodes.append(s_node)

    for edge in statespace.edges:

        if edge.condition is None:
            label = ""
        else:

            try:
                label = str(simplify(edge.condition)).replace("\n", "")
            except Z3Exception:
                label = str(edge.condition).replace("\n", "")

        label = re.sub(
            "([^_])([\d]{2}\d+)", lambda m: m.group(1) + hex(int(m.group(2))), label
        )
        code = re.sub("([0-9a-f]{8})[0-9a-f]+", lambda m: m.group(1) + "(...)", code)

        s_edge = {
            "from": str(edge.as_dict["from"]),
            "to": str(edge.as_dict["to"]),
            "arrows": "to",
            "label": label,
            "smooth": {"type": "cubicBezier"},
        }

        edges.append(s_edge)

    return {"edges": edges, "nodes": nodes}