示例#1
0
def trace(code, calldata=""):

    logHandlers = [
        'eth.vm.op', 'eth.vm.op.stack', 'eth.vm.op.memory', 'eth.vm.op.storage'
    ]

    output = StringIO()
    streamHandler = StreamHandler(output)

    for handler in logHandlers:
        log_vm_op = get_logger(handler)
        log_vm_op.setLevel("TRACE")
        log_vm_op.addHandler(streamHandler)

    addr = codecs.decode('0123456789ABCDEF0123456789ABCDEF01234567',
                         'hex_codec')

    state = State()

    ext = messages.VMExt(state,
                         transactions.Transaction(0, 0, 21000, addr, 0, addr))

    message = vm.Message(addr, addr, 0, 21000, calldata)

    res, gas, dat = vm.vm_execute(ext, message, util.safe_decode(code))

    streamHandler.flush()

    ret = output.getvalue()

    return ret
示例#2
0
文件: evm.py 项目: norhh/mythril
def trace(code, calldata=""):
    log_handlers = [
        "eth.vm.op",
        "eth.vm.op.stack",
        "eth.vm.op.memory",
        "eth.vm.op.storage",
    ]
    output = StringIO()
    stream_handler = StreamHandler(output)

    for handler in log_handlers:
        log_vm_op = get_logger(handler)
        log_vm_op.setLevel("TRACE")
        log_vm_op.addHandler(stream_handler)

    addr = bytes.fromhex("0123456789ABCDEF0123456789ABCDEF01234567")
    state = State()

    ext = messages.VMExt(state,
                         transactions.Transaction(0, 0, 21000, addr, 0, addr))
    message = vm.Message(addr, addr, 0, 21000, calldata)
    vm.vm_execute(ext, message, util.safe_decode(code))
    stream_handler.flush()
    ret = output.getvalue()
    lines = ret.split("\n")

    state_trace = []
    for line in lines:
        m = re.search(r"pc=b\'(\d+)\'.*op=([A-Z0-9]+)", line)
        if m:
            pc = m.group(1)
            op = m.group(2)
            m = re.match(r".*stack=(\[.*?\])", line)

            if m:
                stackitems = re.findall(r"b\'(\d+)\'", m.group(1))
                stack = "["

                if len(stackitems):
                    for i in range(0, len(stackitems) - 1):
                        stack += hex(int(stackitems[i])) + ", "
                    stack += hex(int(stackitems[-1]))

                stack += "]"
            else:
                stack = "[]"

            if re.match(r"^PUSH.*", op):
                val = re.search(r"pushvalue=(\d+)", line).group(1)
                pushvalue = hex(int(val))
                state_trace.append({
                    "pc": pc,
                    "op": op,
                    "stack": stack,
                    "pushvalue": pushvalue
                })
            else:
                state_trace.append({"pc": pc, "op": op, "stack": stack})

    return state_trace
示例#3
0
    def __init__(self, code: str, enable_online_lookup: bool = False):
        self.bytecode = code
        self.instruction_list = asm.disassemble(util.safe_decode(code))

        self.func_hashes = []
        self.function_name_to_address = {}
        self.address_to_function_name = {}

        signatures = SignatureDb(
            enable_online_lookup=enable_online_lookup
        )  # control if you want to have online signature hash lookups
        try:
            signatures.open()  # open from default locations
        except FileNotFoundError:
            logging.info(
                "Missing function signature file. Resolving of function names from signature file disabled."
            )

        # Need to take from PUSH1 to PUSH4 because solc seems to remove excess 0s at the beginning for optimizing
        jump_table_indices = asm.find_op_code_sequence(
            [("PUSH1", "PUSH2", "PUSH3", "PUSH4"),
             ("EQ", )], self.instruction_list)

        for index in jump_table_indices:
            function_hash, jump_target, function_name = get_function_info(
                index, self.instruction_list, signatures)
            self.func_hashes.append(function_hash)

            if jump_target is not None and function_name is not None:
                self.function_name_to_address[function_name] = jump_target
                self.address_to_function_name[jump_target] = function_name

        signatures.write(
        )  # store resolved signatures (potentially resolved online)
示例#4
0
    def __init__(self, code, enable_online_lookup=True):
        self.instruction_list = asm.disassemble(util.safe_decode(code))
        self.func_hashes = []
        self.func_to_addr = {}
        self.addr_to_func = {}
        self.bytecode = code

        signatures = SignatureDb(
            enable_online_lookup=enable_online_lookup
        )  # control if you want to have online sighash lookups
        try:
            signatures.open()  # open from default locations
        except FileNotFoundError:
            logging.info(
                "Missing function signature file. Resolving of function names from signature file disabled."
            )

        # Parse jump table & resolve function names

        # Need to take from PUSH1 to PUSH4 because solc seems to remove excess 0s at the beginning for optimizing
        jmptable_indices = asm.find_opcode_sequence(
            [("PUSH1", "PUSH2", "PUSH3", "PUSH4"),
             ("EQ", )], self.instruction_list)

        for i in jmptable_indices:
            func_hash = self.instruction_list[i]['argument']

            # Append with missing 0s at the beginning
            func_hash = "0x" + func_hash[2:].rjust(8, "0")

            self.func_hashes.append(func_hash)
            try:
                # tries local cache, file and optional online lookup
                # may return more than one function signature. since we cannot probe for the correct one we'll use the first
                func_names = signatures.get(func_hash)
                if len(func_names) > 1:
                    # ambigious result
                    func_name = "**ambiguous** %s" % func_names[
                        0]  # return first hit but note that result was ambiguous
                else:
                    # only one item
                    func_name = func_names[0]
            except KeyError:
                func_name = "_function_" + func_hash

            try:
                offset = self.instruction_list[i + 2]['argument']
                jump_target = int(offset, 16)

                self.func_to_addr[func_name] = jump_target
                self.addr_to_func[jump_target] = func_name
            except:
                continue

        signatures.write(
        )  # store resolved signatures (potentially resolved online)
示例#5
0
    def get_xrefs(self):

        disassembly = asm.disassemble(util.safe_decode(self.code))

        xrefs = []

        for instruction in disassembly:
            if instruction['opcode'] == "PUSH20":
                if instruction['argument']:
                    addr = instruction['argument'].decode("utf-8")

                    if (re.match(r'^[a-zA-Z0-9]{40}$', addr) and addr != "ffffffffffffffffffffffffffffffffffffffff"):
                        if addr not in xrefs:
                            xrefs.append(addr)

        return xrefs
示例#6
0
    def __init__(self, code):
        self.instruction_list = asm.disassemble(util.safe_decode(code))
        self.xrefs = []
        self.func_to_addr = {}
        self.addr_to_func = {}
        self.bytecode = code

        try:
            mythril_dir = os.environ['MYTHRIL_DIR']
        except KeyError:
            mythril_dir = os.path.join(os.path.expanduser('~'), ".mythril")

        # Load function signatures

        signatures_file = os.path.join(mythril_dir, 'signatures.json')

        if not os.path.exists(signatures_file):
            logging.info(
                "Missing function signature file. Resolving of function names disabled."
            )
            signatures = {}
        else:
            with open(signatures_file) as f:
                signatures = json.load(f)

        # Parse jump table & resolve function names

        jmptable_indices = asm.find_opcode_sequence(["PUSH4", "EQ"],
                                                    self.instruction_list)

        for i in jmptable_indices:
            func_hash = self.instruction_list[i]['argument']
            try:
                func_name = signatures[func_hash]
            except KeyError:
                func_name = "_function_" + func_hash

            try:
                offset = self.instruction_list[i + 2]['argument']
                jump_target = int(offset, 16)

                self.func_to_addr[func_name] = jump_target
                self.addr_to_func[jump_target] = func_name
            except:
                continue
示例#7
0
文件: asm.py 项目: nbanmp/mythril
def assemble(instruction_list):

    bytecode = b""

    for instruction in instruction_list:

        try:
            opcode = get_opcode_from_name(instruction["opcode"])
        except RuntimeError:
            opcode = 0xBB

        bytecode += opcode.to_bytes(1, byteorder="big")

        if "argument" in instruction:

            bytecode += util.safe_decode(instruction["argument"])

    return bytecode
示例#8
0
文件: asm.py 项目: maxme/mythril
def assemble(instruction_list):

    bytecode = b""

    for instruction in instruction_list:

        try:
            opcode = get_opcode_from_name(instruction['opcode'])
        except RuntimeError:
            opcode = 0xbb

        bytecode += opcode.to_bytes(1, byteorder='big')

        if 'argument' in instruction:

            bytecode += util.safe_decode(instruction['argument'])

    return bytecode
示例#9
0
文件: evm.py 项目: zzzxxxbbb/mythril
def trace(code, calldata=""):

    logHandlers = [
        'eth.vm.op', 'eth.vm.op.stack', 'eth.vm.op.memory', 'eth.vm.op.storage'
    ]

    output = StringIO()
    streamHandler = StreamHandler(output)

    for handler in logHandlers:
        log_vm_op = get_logger(handler)
        log_vm_op.setLevel("TRACE")
        log_vm_op.addHandler(streamHandler)

    addr = bytes.fromhex('0123456789ABCDEF0123456789ABCDEF01234567')

    state = State()

    ext = messages.VMExt(state,
                         transactions.Transaction(0, 0, 21000, addr, 0, addr))

    message = vm.Message(addr, addr, 0, 21000, calldata)

    res, gas, dat = vm.vm_execute(ext, message, util.safe_decode(code))

    streamHandler.flush()

    ret = output.getvalue()

    lines = ret.split("\n")

    trace = []

    for line in lines:

        m = re.search(r'pc=b\'(\d+)\'.*op=([A-Z0-9]+)', line)

        if m:
            pc = m.group(1)
            op = m.group(2)

            m = re.match(r'.*stack=(\[.*?\])', line)

            if (m):

                stackitems = re.findall(r'b\'(\d+)\'', m.group(1))

                stack = "["

                if (len(stackitems)):

                    for i in range(0, len(stackitems) - 1):
                        stack += hex(int(stackitems[i])) + ", "

                    stack += hex(int(stackitems[-1]))

                stack += "]"

            else:
                stack = "[]"

            if (re.match(r'^PUSH.*', op)):
                val = re.search(r'pushvalue=(\d+)', line).group(1)
                pushvalue = hex(int(val))
                trace.append({
                    'pc': pc,
                    'op': op,
                    'stack': stack,
                    'pushvalue': pushvalue
                })
            else:
                trace.append({'pc': pc, 'op': op, 'stack': stack})

    return trace
示例#10
0
    def __init__(self, code):
        self.instruction_list = asm.disassemble(util.safe_decode(code))
        self.blocks = []
        self.xrefs = []
        self.func_to_addr = {}
        self.addr_to_func = {}

        # Parse jump table & resolve function names

        script_dir = os.path.dirname(os.path.realpath(__file__))
        signature_file = os.path.join(script_dir, 'signatures.json')

        with open(signature_file) as f:
            signatures = json.load(f)

        jmptable_indices = asm.find_opcode_sequence(["PUSH4", "EQ"], self.instruction_list)

        for i in jmptable_indices:
            func_hash = self.instruction_list[i]['argument']
            try:
                func_name = signatures[func_hash]
            except KeyError:
                func_name = "UNK_" + func_hash

            try:
                offset = self.instruction_list[i+2]['argument']
                jump_target = int(offset, 16)

                self.func_to_addr[func_name] = jump_target
                self.addr_to_func[jump_target] = func_name
            except:
                continue

        # Parse instructions into basic blocks

        current_block = Block(0, 0, "PROLOGUE")

        index = 0
        blocklen = 0
        blocknumber = 1

        for instruction in self.instruction_list:

            if (instruction['opcode'] == "JUMPDEST"):

                try:
                    func_name = "- FUNCTION " + self.addr_to_func[instruction['address']] + " -"
                except KeyError:
                    func_name = "- JUMPDEST_UNK -"
                
                current_block.update_length(blocklen)
                self.blocks.append(current_block)
                current_block = Block(blocknumber, index, func_name)
                blocklen = 0
                blocknumber += 1
                
            current_block.instruction_list.append(instruction)
            blocklen += 1

            index += 1
        
        # Add the last block

        current_block.update_length(blocklen)
        self.blocks.append(current_block)

        # Resolve cross-references

        for block in self.blocks:

            jmp_indices = asm.find_opcode_sequence(["JUMP"], block.instruction_list)
            jmp_indices += asm.find_opcode_sequence(["JUMPI"], block.instruction_list)

            for i in jmp_indices:
                try:
                    dest_hex = block.instruction_list[i - 1]['argument']
                    dest = int(dest_hex[2:], 16)
                except:
                    continue

                j = 0

                try:
                    while(self.blocks[j].end_addr < dest):
                        j += 1
                except IndexError:
                    continue


                if not (block.id, self.blocks[j].id) in self.xrefs:
                    self.xrefs.append((block.id, self.blocks[j].id))

            # if the last instruction isn't an unconditional jump or halt, also add a reference to the following block

            try:
                if (block.id < len(self.blocks)) and (block.instruction_list[block.length - 1]['opcode'] not in ['JUMP', 'STOP', 'THROW', 'REVERT', 'INVALID']):
                    if not (block.id, self.blocks[j].id) in self.xrefs:
                        self.xrefs.append((block.id, block.id + 1))
            except UnboundLocalError:
                # quickfix
                continue
示例#11
0
    def get_easm(self):

        return asm.disassembly_to_easm(asm.disassemble(util.safe_decode(self.code)))
示例#12
0
    def get_disassembly(self):

        return asm.disassemble(util.safe_decode(self.code))