diff --git a/myth b/myth index 0bec6238..ce42bdb8 100755 --- a/myth +++ b/myth @@ -11,8 +11,9 @@ from mythril.ether.ethcontract import ETHContract from mythril.ether.util import compile_solidity from mythril.rpc.client import EthJsonRpc from mythril.ipc.client import EthIpc +from mythril.support.loader import DynLoader from ethereum import utils -from laser.ethereum import laserfree +from laser.ethereum import svm, laserfree from pathlib import Path import logging import sys @@ -50,6 +51,7 @@ commands.add_argument('--init-db', action='store_true', help='initialize the con inputs = parser.add_argument_group('input arguments') inputs.add_argument('-c', '--code', help='hex-encoded bytecode string ("6060604052...")', metavar='BYTECODE') inputs.add_argument('-a', '--address', help='pull contract from the blockchain', metavar='CONTRACT_ADDRESS') +inputs.add_argument('-l', '--dynld', action='store_true', help='auto-load dependencies (experimental)') inputs.add_argument('--data', help='message call input data for tracing') options = parser.add_argument_group('options') @@ -163,7 +165,6 @@ elif (len(args.solidity_file)): else: exitWithError("No input bytecode. Please provide EVM code via -c BYTECODE, -a ADDRESS, or -i SOLIDITY_FILES") - # Commands if (args.disassemble): @@ -198,12 +199,18 @@ elif (args.graph) or (args.fire_lasers): for contract in contracts: modules[contract.address] = contract.as_dict() + if (args.dynld): + loader = DynLoader(eth) + _svm = svm.SVM(modules, loader) + else: + _svm = svm.SVM(modules) + if (args.graph): if args.enable_physics is not None: physics = True - html = generate_callgraph(modules, contracts[0].address, args.enable_physics) + html = generate_callgraph(_svm, contracts[0].address, args.enable_physics) try: with open(args.graph, "w") as f: @@ -214,7 +221,7 @@ elif (args.graph) or (args.fire_lasers): else: - laserfree.fire(modules) + laserfree.fire(_svm) else: parser.print_help() diff --git a/mythril/disassembler/callgraph.py b/mythril/disassembler/callgraph.py index cf360d36..d166223a 100644 --- a/mythril/disassembler/callgraph.py +++ b/mythril/disassembler/callgraph.py @@ -1,4 +1,3 @@ -from laser.ethereum import svm from z3 import Z3Exception, simplify import re @@ -130,21 +129,19 @@ def serialize(_svm, color_map): -def generate_callgraph(modules, main_address, physics): +def generate_callgraph(svm, main_address, physics): - _svm = svm.SVM(modules) - - _svm.sym_exec(main_address) + svm.sym_exec(main_address) i = 0 color_map = {} - for k in modules: - color_map[modules[k]['name']] = colors[i] + for k in svm.modules: + color_map[svm.modules[k]['name']] = colors[i] i += 1 - html = graph_html.replace("[JS]", serialize(_svm, color_map)) + html = graph_html.replace("[JS]", serialize(svm, color_map)) html = html.replace("[ENABLE_PHYSICS]", str(physics).lower()) return html diff --git a/mythril/support/loader.py b/mythril/support/loader.py new file mode 100644 index 00000000..e8074987 --- /dev/null +++ b/mythril/support/loader.py @@ -0,0 +1,11 @@ +from mythril.ether.ethcontract import ETHContract + +class DynLoader: + + def __init__(self, eth): + self.eth = eth + + def dynld(self, address): + + contract = ETHContract(self.eth.eth_getCode(address), name=address, address=address) + return contract.as_dict() \ No newline at end of file diff --git a/tests/svm_test.py b/tests/svm_test.py index ecaf943f..acf41400 100644 --- a/tests/svm_test.py +++ b/tests/svm_test.py @@ -1,6 +1,7 @@ import unittest from mythril.disassembler.callgraph import generate_callgraph from mythril.disassembler.disassembly import Disassembly +from laser.ethereum import svm class SVMTestCase(unittest.TestCase): @@ -11,6 +12,8 @@ class SVMTestCase(unittest.TestCase): modules['0x0000000000000000000000000000000000000000'] = {'name': 'metaCoin', 'address': '0x0000000000000000000000000000000000000000', 'creation_code': '', 'code': '60606040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806327e235e314610051578063412664ae1461009e575b600080fd5b341561005c57600080fd5b610088600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506100f8565b6040518082815260200191505060405180910390f35b34156100a957600080fd5b6100de600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610110565b604051808215151515815260200191505060405180910390f35b60006020528060005260406000206000915090505481565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101561016157600090506101fe565b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550600090505b929150505600a165627a7a72305820fd4fa106da498514e90965a45ffecc1da53a0cd8bb7a7135910f8612245a46370029'} modules['0x0000000000000000000000000000000000000000']['disassembly'] = Disassembly(modules['0x0000000000000000000000000000000000000000']['code']) - html = generate_callgraph(modules, '0x0000000000000000000000000000000000000000', False) + _svm = svm.SVM(modules) + + html = generate_callgraph(_svm, '0x0000000000000000000000000000000000000000', False) self.assertTrue("var nodes = [\n{id: \'metaCoin:" in html)