Source code for mythril.laser.ethereum.util

"""This module contains various utility conversion functions and constants for
LASER."""
import re
from typing import Dict, List, Union, TYPE_CHECKING, cast

if TYPE_CHECKING:
    from mythril.laser.ethereum.state.machine_state import MachineState

from mythril.laser.smt import BitVec, Bool, Expression, If, simplify, symbol_factory

TT256 = 2**256
TT256M1 = 2**256 - 1
TT255 = 2**255


[docs]def safe_decode(hex_encoded_string: str) -> bytes: """ :param hex_encoded_string: :return: """ if hex_encoded_string.startswith("0x"): return bytes.fromhex(hex_encoded_string[2:]) else: return bytes.fromhex(hex_encoded_string)
[docs]def to_signed(i: int) -> int: """ :param i: :return: """ return i if i < TT255 else i - TT256
[docs]def get_instruction_index( instruction_list: List[Dict], address: int ) -> Union[int, None]: """ :param instruction_list: :param address: :return: """ index = 0 for instr in instruction_list: if instr["address"] >= address: return index index += 1 return None
[docs]def get_trace_line(instr: Dict, state: "MachineState") -> str: """ :param instr: :param state: :return: """ stack = str(state.stack[::-1]) # stack = re.sub("(\d+)", lambda m: hex(int(m.group(1))), stack) stack = re.sub("\n", "", stack) return str(instr["address"]) + " " + instr["opcode"] + "\tSTACK: " + stack
[docs]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)
[docs]def get_concrete_int(item: Union[int, Expression]) -> int: """ :param item: :return: """ if isinstance(item, int): return item elif isinstance(item, BitVec): if item.symbolic: raise TypeError("Got a symbolic BitVecRef") return item.value elif isinstance(item, Bool): value = item.value if value is None: raise TypeError("Symbolic boolref encountered") return value assert False, "Unhandled type {} encountered".format(str(type(item)))
[docs]def concrete_int_from_bytes( concrete_bytes: Union[List[Union[BitVec, int]], bytes], start_index: int ) -> int: """ :param concrete_bytes: :param start_index: :return: """ concrete_bytes = [ byte.value if isinstance(byte, BitVec) and not byte.symbolic else byte for byte in concrete_bytes ] integer_bytes = concrete_bytes[start_index : start_index + 32] # The below statement is expected to fail in some circumstances whose error is caught return int.from_bytes(integer_bytes, byteorder="big") # type: ignore
[docs]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")
[docs]def bytearray_to_int(arr): """ :param arr: :return: """ o = 0 for a in arr: o = (o << 8) + a return o
[docs]def extract_copy( data: bytearray, mem: bytearray, memstart: int, datastart: int, size: int ): for i in range(size): if datastart + i < len(data): mem[memstart + i] = data[datastart + i] else: mem[memstart + i] = 0
[docs]def extract32(data: bytearray, i: int) -> int: """ :param data: :param i: :return: """ if i >= len(data): return 0 o = data[i : min(i + 32, len(data))] o.extend(bytearray(32 - len(o))) return bytearray_to_int(o)