Пример #1
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_opcode_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)
Пример #2
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)
Пример #3
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
Пример #4
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