|
|
@ -1,5 +1,5 @@ |
|
|
|
#!/usr/bin/env python |
|
|
|
#!/usr/bin/env python |
|
|
|
"""mythril.py: Smart contract bug hunting on the Ethereum blockchain |
|
|
|
"""mythril.py: Bug hunting on the Ethereum blockchain |
|
|
|
|
|
|
|
|
|
|
|
http://www.github.com/b-mueller/mythril |
|
|
|
http://www.github.com/b-mueller/mythril |
|
|
|
""" |
|
|
|
""" |
|
|
@ -7,8 +7,8 @@ |
|
|
|
from ether import asm,evm,util |
|
|
|
from ether import asm,evm,util |
|
|
|
from contractstorage import ContractStorage |
|
|
|
from contractstorage import ContractStorage |
|
|
|
import sys |
|
|
|
import sys |
|
|
|
import codecs |
|
|
|
|
|
|
|
import argparse |
|
|
|
import argparse |
|
|
|
|
|
|
|
from rpc.client import EthJsonRpc |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def exitWithError(message): |
|
|
|
def exitWithError(message): |
|
|
@ -16,15 +16,16 @@ def exitWithError(message): |
|
|
|
sys.exit() |
|
|
|
sys.exit() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
parser = argparse.ArgumentParser(description='Smart contract bug hunting on the Ethereum blockchain') |
|
|
|
parser = argparse.ArgumentParser(description='Bug hunting on the Ethereum blockchain') |
|
|
|
|
|
|
|
|
|
|
|
parser.add_argument('-d', '--disassemble', action='store_true', help='disassemble, use with -c or --id') |
|
|
|
parser.add_argument('-d', '--disassemble', action='store_true', help='disassemble, use with -c or -a') |
|
|
|
parser.add_argument('-t', '--trace', action='store_true', help='trace bytecode provided via the -c argument') |
|
|
|
parser.add_argument('-t', '--trace', action='store_true', help='trace, use with -c or -a and --data (optional)') |
|
|
|
parser.add_argument('-c', '--code', help='hex-encoded bytecode string ("6060604052...")', metavar='BYTECODE') |
|
|
|
parser.add_argument('-c', '--code', help='hex-encoded bytecode string ("6060604052...")', metavar='BYTECODE') |
|
|
|
|
|
|
|
parser.add_argument('-a', '--address', default='0x0123456789ABCDEF0123456789ABCDEF01234567', help='contract address') |
|
|
|
parser.add_argument('-o', '--outfile') |
|
|
|
parser.add_argument('-o', '--outfile') |
|
|
|
parser.add_argument('--id', help='contract id') |
|
|
|
parser.add_argument('--data', help='message call input data for tracing') |
|
|
|
|
|
|
|
parser.add_argument('--search', help='search the contract database') |
|
|
|
parser.add_argument('--init-db', action='store_true', help='Initialize the contract database') |
|
|
|
parser.add_argument('--init-db', action='store_true', help='Initialize the contract database') |
|
|
|
parser.add_argument('--search', help='search contract database') |
|
|
|
|
|
|
|
parser.add_argument('--rpchost', default='127.0.0.1', help='RPC host') |
|
|
|
parser.add_argument('--rpchost', default='127.0.0.1', help='RPC host') |
|
|
|
parser.add_argument('--rpcport', type=int, default=8545, help='RPC port') |
|
|
|
parser.add_argument('--rpcport', type=int, default=8545, help='RPC port') |
|
|
|
|
|
|
|
|
|
|
@ -38,10 +39,14 @@ if (args.disassemble): |
|
|
|
|
|
|
|
|
|
|
|
if (args.code): |
|
|
|
if (args.code): |
|
|
|
encoded_bytecode = args.code |
|
|
|
encoded_bytecode = args.code |
|
|
|
elif (args.id): |
|
|
|
elif (args.address): |
|
|
|
|
|
|
|
|
|
|
|
try: |
|
|
|
try: |
|
|
|
encoded_bytecode = storage.get_contract_code_by_address(args.id) |
|
|
|
# encoded_bytecode = storage.get_contract_code_by_address(args.id) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
eth = EthJsonRpc(args.rpchost, args.rpcport) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
encoded_bytecode = eth.eth_getCode(args.address) |
|
|
|
|
|
|
|
|
|
|
|
except Exception as e: |
|
|
|
except Exception as e: |
|
|
|
exitWithError("Exception loading bytecode via RPC: " + str(e)) |
|
|
|
exitWithError("Exception loading bytecode via RPC: " + str(e)) |
|
|
@ -68,14 +73,24 @@ if (args.disassemble): |
|
|
|
|
|
|
|
|
|
|
|
elif (args.trace): |
|
|
|
elif (args.trace): |
|
|
|
|
|
|
|
|
|
|
|
if args.code: |
|
|
|
if (args.code): |
|
|
|
|
|
|
|
encoded_bytecode = args.code |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
elif (args.address): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
eth = EthJsonRpc(args.rpchost, args.rpcport) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
encoded_bytecode = eth.eth_getCode(args.address) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
exitWithError("Disassembler: Provide the input bytecode via -c BYTECODE or --id ID") |
|
|
|
|
|
|
|
|
|
|
|
bytecode = util.safe_decode(args.code) |
|
|
|
if (args.data): |
|
|
|
|
|
|
|
evm.trace(util.safe_decode(encoded_bytecode), args.address, args.data) |
|
|
|
|
|
|
|
|
|
|
|
else: |
|
|
|
else: |
|
|
|
exitWithError("Trace: Provide the input bytecode using -c BYTECODE or -f INPUT_FILE") |
|
|
|
evm.trace(util.safe_decode(encoded_bytecode), args.address) |
|
|
|
|
|
|
|
|
|
|
|
evm.trace(bytecode) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
elif (args.search): |
|
|
|
elif (args.search): |
|
|
|
|
|
|
|
|
|
|
|