Пример #1
0
 def load_from_bytecode(
         self,
         code: str,
         bin_runtime: bool = False,
         address: Optional[str] = None) -> Tuple[str, EVMContract]:
     """
     Returns the address and the contract class for the given bytecode
     :param code: Bytecode
     :param bin_runtime: Whether the code is runtime code or creation code
     :param address: address of contract
     :return: tuple(address, Contract class)
     """
     if address is None:
         address = util.get_indexed_address(0)
     if bin_runtime:
         self.contracts.append(
             EVMContract(
                 code=code,
                 name="MAIN",
                 enable_online_lookup=self.enable_online_lookup,
             ))
     else:
         self.contracts.append(
             EVMContract(
                 creation_code=code,
                 name="MAIN",
                 enable_online_lookup=self.enable_online_lookup,
             ))
     return address, self.contracts[
         -1]  # return address and contract object
Пример #2
0
    def load_from_bytecode(self, code, bin_runtime=False, address=None):
        """

        :param code:
        :param bin_runtime:
        :param address:
        :return:
        """
        if address is None:
            address = util.get_indexed_address(0)
        if bin_runtime:
            self.contracts.append(
                EVMContract(
                    code=code,
                    name="MAIN",
                    enable_online_lookup=self.enable_online_lookup,
                ))
        else:
            self.contracts.append(
                EVMContract(
                    creation_code=code,
                    name="MAIN",
                    enable_online_lookup=self.enable_online_lookup,
                ))
        return address, self.contracts[
            -1]  # return address and contract object
Пример #3
0
    def runTest(self):
        contract = EVMContract(self.code)

        instruction_list = contract.get_easm()

        self.assertTrue(
            "PUSH1 0x60" in instruction_list,
            "Error obtaining EASM code through EVMContract.get_easm()",
        )
Пример #4
0
    def runTest(self):
        contract = EVMContract(self.code)

        self.assertTrue(
            contract.matches_expression("code#PUSH1# or code#PUSH1#"),
            "Unexpected result in expression matching",
        )
        self.assertFalse(
            contract.matches_expression("func#abcdef#"),
            "Unexpected result in expression matching",
        )
Пример #5
0
    def load_from_address(self, address: str) -> Tuple[str, EVMContract]:
        """
        Returns the contract given it's on chain address
        :param address: The on chain address of a contract
        :return: tuple(address, contract)
        """
        if not re.match(r"0x[a-fA-F0-9]{40}", address):
            raise CriticalError(
                "Invalid contract address. Expected format is '0x...'.")

        try:
            code = self.eth.eth_getCode(address)
        except FileNotFoundError as e:
            raise CriticalError("IPC error: " + str(e))
        except ConnectionError:
            raise CriticalError(
                "Could not connect to RPC server. Make sure that your node is running and that RPC parameters are set correctly."
            )
        except Exception as e:
            raise CriticalError("IPC / RPC error: " + str(e))

        if code == "0x" or code == "0x0":
            raise CriticalError(
                "Received an empty response from eth_getCode. Check the contract address and verify that you are on the correct chain."
            )
        else:
            self.contracts.append(
                EVMContract(code,
                            name=address,
                            enable_online_lookup=self.enable_online_lookup))
        return address, self.contracts[
            -1]  # return address and contract object
Пример #6
0
def AnalyseSherlockJson(fileAddress):

    startTime = time.time()  # pour calculer temps exécution

    accounts = {}
    contractAddress = ""
    contractName = ""
    firstContract = True

    with open(fileAddress) as json_file:
        data = json.load(json_file)
        #print (data)
        for p in data['contract']:
            contract = EVMContract(code=p['contractBytecode'],
                                   name=p['contractName'])
            address = p['contractAddress']
            account = svm.Account(address, contract.disassembly)
            accounts[address] = account
            if firstContract == True:
                contractAddress = p['contractAddress']
                contractName = p['contractName']
                firstContract = False
            print('contract name: ' + p['contractName'])
            print('contract address: ' + p['contractAddress'])
            #print('contract bytecote: ' + p['contractBytecode'])
            print('')

    laser = svm.LaserEVM(accounts,
                         max_depth=maxDept,
                         execution_timeout=executionTimeOut,
                         create_timeout=createTimeOut,
                         transaction_count=transactionCount)
    ExecutionSymbolique(laser, contractAddress, contractName, startTime)
Пример #7
0
def symbolic_execute(code, address):
    contract = EVMContract(code)
    sym = SymExecWrapper(contract=contract, address=address, strategy="dfs")

    # populate graph object
    graph = MythrilSymExecGraph()
    for n in sym.nodes.values():
        # g.add all nodes - just in case one is not connected which should not happen
        graph.add_node(n)

    for e in sym.edges:
        graph.add_edge(sym.nodes[e.node_from], sym.nodes[e.node_to], e)

    """
    print(graph.iterate_graph())
    print(sorted([x.uid for x in graph.nodes]))
    print(graph._first_added.uid)
    print(next(graph.get_basicblocks_by_address(0)))
    print(graph.get_basicblock_by_uid(0))
    print(list(n.uid for n in graph.iterate_graph(graph.get_basicblock_by_uid(0))))

    print(graph.find_all_paths(graph.get_basicblock_by_uid(0), graph.get_basicblock_by_uid(37)))
    print(graph.find_all_paths(graph.get_basicblock_by_uid(0),None))
    print("streams")
    for stream in graph.get_streams(graph.get_basicblock_by_uid(0)):
        print([s.uid for s in stream])
    
    print(list(s.get_current_instruction() for b,s in graph.get_block_and_state_by_instruction_name("PUSH",prn_cmp=lambda x,y:x.startswith(y))))

    print(graph.get_stream_by_block(block=graph.get_block_by_uid(2)))
    """
    # only work on the graph from now
    return graph
Пример #8
0
 def contract(self) -> EVMContract:
     try:
         with open(self._file_path) as contract_bin:
             bytecode = contract_bin.read()
     except IOError as e:
         log.error('Failed to open contract binary file: %s', e)
         raise IOError('Failed to open contract binary file')
     return EVMContract(creation_code=bytecode)
Пример #9
0
    def get_contracts(self):
        """Iterate through all contracts."""
        for account in self.reader._get_head_state().get_all_accounts():
            if account.code is not None:
                code = _encode_hex(account.code)
                contract = EVMContract(code, enable_online_lookup=False)

                yield contract, account.address, account.balance
Пример #10
0
    def runTest(self):
        contract = EVMContract(self.code, self.creation_code)

        disassembly = contract.disassembly

        self.assertEqual(
            len(disassembly.instruction_list),
            53,
            "Error disassembling code using EVMContract.get_instruction_list()",
        )
Пример #11
0
    def runTest(self):

        code = "0x60606040525b603c5b60006010603e565b9050593681016040523660008237602060003683856040603f5a0204f41560545760206000f35bfe5b50565b005b73c3b2ae46792547a96b9f84405e36d0e07edcd05c5b905600a165627a7a7230582062a884f947232ada573f95940cce9c8bfb7e4e14e21df5af4e884941afb55e590029"

        contract = EVMContract(code)
        sym = SymExecWrapper(contract,
                             "0xd0a6E6C543bC68Db5db3A191B171A77407Ff7ccf")

        html = generate_graph(sym)

        self.assertTrue(
            "0 PUSH1 0x60\\n2 PUSH1 0x40\\n4 MSTORE\\n5 JUMPDEST" in html)
Пример #12
0
def analyze_truffle_project(sigs, args):
    """

    :param sigs:
    :param args:
    """
    project_root = os.getcwd()

    build_dir = os.path.join(project_root, "build", "contracts")

    files = os.listdir(build_dir)

    for filename in files:

        if re.match(r".*\.json$", filename) and filename != "Migrations.json":

            with open(os.path.join(build_dir, filename)) as cf:
                contractdata = json.load(cf)

            try:
                name = contractdata["contractName"]
                bytecode = contractdata["deployedBytecode"]
                filename = PurePath(contractdata["sourcePath"]).name
            except KeyError:
                print(
                    "Unable to parse contract data. Please use Truffle 4 to compile your project."
                )
                sys.exit()
            if len(bytecode) < 4:
                continue
            get_sigs_from_truffle(sigs, contractdata)

            ethcontract = EVMContract(bytecode, name=name)

            address = util.get_indexed_address(0)
            sym = SymExecWrapper(
                ethcontract,
                address,
                args.strategy,
                max_depth=args.max_depth,
                create_timeout=args.create_timeout,
                execution_timeout=args.execution_timeout,
                transaction_count=args.transaction_count,
                modules=args.modules or [],
                compulsory_statespace=False,
            )
            issues = fire_lasers(sym)

            if not len(issues):
                if args.outform == "text" or args.outform == "markdown":
                    print("# Analysis result for " + name +
                          "\n\nNo issues found.")
                else:
                    result = {
                        "contract": name,
                        "result": {
                            "success": True,
                            "error": None,
                            "issues": []
                        },
                    }
                    print(json.dumps(result))
            else:

                report = Report()
                # augment with source code

                deployed_disassembly = ethcontract.disassembly
                constructor_disassembly = ethcontract.creation_disassembly

                source = contractdata["source"]

                deployed_source_map = contractdata["deployedSourceMap"].split(
                    ";")
                source_map = contractdata["sourceMap"].split(";")

                deployed_mappings = get_mappings(source, deployed_source_map)
                constructor_mappings = get_mappings(source, source_map)

                for issue in issues:
                    if issue.function == "constructor":
                        mappings = constructor_mappings
                        disassembly = constructor_disassembly
                    else:
                        mappings = deployed_mappings
                        disassembly = deployed_disassembly

                    index = get_instruction_index(disassembly.instruction_list,
                                                  issue.address)

                    if index:
                        try:
                            offset = mappings[index].offset
                            length = mappings[index].length

                            issue.filename = filename
                            issue.code = source.encode("utf-8")[offset:offset +
                                                                length].decode(
                                                                    "utf-8")
                            issue.lineno = mappings[index].lineno
                        except IndexError:
                            log.debug("No code mapping at index %d", index)

                    report.append_issue(issue)

                if args.outform == "json":

                    result = {
                        "contract": name,
                        "result": {
                            "success": True,
                            "error": None,
                            "issues": list(map(lambda x: x.as_dict, issues)),
                        },
                    }
                    print(json.dumps(result))

                else:
                    if args.outform == "text":
                        print("# Analysis result for " + name + ":\n\n" +
                              report.as_text())
                    elif args.outform == "markdown":
                        print(report.as_markdown())