Load contracts into list

pull/22/head
Bernhard Mueller 7 years ago
parent ee4df81821
commit cf62c49ff5
  1. 63
      myth
  2. 6
      mythril/ether/ethcontract.py
  3. 11
      mythril/ether/util.py
  4. 2
      tests/ethcontract_test.py

63
myth

@ -4,7 +4,7 @@
http://www.github.com/b-mueller/mythril http://www.github.com/b-mueller/mythril
""" """
from mythril.ether import evm from mythril.ether import evm, util
from mythril.disassembler.disassembly import Disassembly from mythril.disassembler.disassembly import Disassembly
from mythril.disassembler.callgraph import generate_callgraph from mythril.disassembler.callgraph import generate_callgraph
from mythril.ether.contractstorage import get_persistent_storage from mythril.ether.contractstorage import get_persistent_storage
@ -48,8 +48,7 @@ commands.add_argument('--init-db', action='store_true', help='initialize the con
inputs = parser.add_argument_group('input arguments') inputs = parser.add_argument_group('input arguments')
inputs.add_argument('-c', '--code', help='hex-encoded bytecode string ("6060604052...")', metavar='BYTECODE') inputs.add_argument('-c', '--code', help='hex-encoded bytecode string ("6060604052...")', metavar='BYTECODE')
inputs.add_argument('-i', '--infile', help='solidity input file', metavar='INPUT_FILE') inputs.add_argument('-i', '--infiles', help='comma-separated list of solidity files', metavar='INPUT_FILES')
inputs.add_argument('-l', '--libs', help='comma-separated list of solidity library files', metavar='LIBRARY_FILES')
inputs.add_argument('-a', '--address', help='pull contract from the mainnet', metavar='CONTRACT_ADDRESS') inputs.add_argument('-a', '--address', help='pull contract from the mainnet', metavar='CONTRACT_ADDRESS')
inputs.add_argument('--data', help='message call input data for tracing') inputs.add_argument('--data', help='message call input data for tracing')
@ -108,7 +107,7 @@ if args.search or args.init_db:
# Establish RPC/IPC connection if necessary # Establish RPC/IPC connection if necessary
if (args.address or args.infile): if (args.address or args.infiles):
if args.ipc: if args.ipc:
try: try:
eth = EthIpc() eth = EthIpc()
@ -122,48 +121,36 @@ if (args.address or args.infile):
except Exception as e: except Exception as e:
exitWithError("Error establishing RPC connection: " + str(e)) exitWithError("Error establishing RPC connection: " + str(e))
# Handle libs # Load code
libraries = {} contracts = []
if (args.libs): if (args.code):
files = args.libs.split(",") contracts.append(ETHContract(args.code))
elif (args.address):
contracts.append(ETHContract(eth.eth_getCode(args.address)))
c = 0 elif (args.infiles):
files = args.infiles.split(",")
for file in files: for file in files:
address = binascii.b2a_hex(os.urandom(20)).decode('UTF-8') name, bytecode = compile_solidity(solc_binary, file)
bytecode = compile_solidity(solc_binary, args.infile)
libraries[address] = bytecode contract = ETHContract(bytecode, name=name)
print(libraries) contracts.append(contract)
# Get encoded bytecode for main module
if (args.code):
encoded_bytecode = args.code
elif (args.address):
encoded_bytecode = eth.eth_getCode(args.address)
elif (args.infile):
encoded_bytecode = compile_solidity(solc_binary, args.infile)
print(encoded_bytecode)
else: else:
exitWithError("No input bytecode. Please provide EVM code via -c BYTECODE, -a ADDRESS, or -i SOLIDITY_FILE") exitWithError("No input bytecode. Please provide EVM code via -c BYTECODE, -a ADDRESS, or -i SOLIDITY_FILES")
logging.debug("Input bytecode: " + encoded_bytecode)
try: logging.info("Loaded " + str(len(contracts)) + " contracts")
disassembly = Disassembly(encoded_bytecode)
except binascii.Error:
exitWithError("Disassembler: Invalid code string.")
# Process commands # Process commands
if (args.disassemble): if (args.disassemble):
easm_text = disassembly.get_easm() easm_text = contracts[0].get_easm()
sys.stdout.write(easm_text) sys.stdout.write(easm_text)
elif (args.graph): elif (args.graph):
@ -171,7 +158,7 @@ elif (args.graph):
if args.enable_physics is not None: if args.enable_physics is not None:
physics = True physics = True
html = generate_callgraph(disassembly, args.enable_physics) html = generate_callgraph(contracts[0].get_disassembly(), args.enable_physics)
try: try:
with open(args.graph, "w") as f: with open(args.graph, "w") as f:
@ -182,36 +169,36 @@ elif (args.graph):
elif (args.xrefs): elif (args.xrefs):
contract = ETHContract(encoded_bytecode) contract = ETHContract(bytecode)
print("\n".join(contract.get_xrefs())) print("\n".join(contract.get_xrefs()))
elif (args.fire_lasers): elif (args.fire_lasers):
laserfree.fire(disassembly) laserfree.fire(contracts[0].get_disassembly())
elif (args.trace): elif (args.trace):
if (args.code): if (args.code):
encoded_bytecode = args.code bytecode = args.code
elif (args.address): elif (args.address):
if args.ipc: if args.ipc:
eth = EthIpc() eth = EthIpc()
encoded_bytecode = eth.eth_getCode(args.address) bytecode = eth.eth_getCode(args.address)
else: else:
eth = EthJsonRpc(args.rpchost, args.rpcport, args.rpctls) eth = EthJsonRpc(args.rpchost, args.rpcport, args.rpctls)
encoded_bytecode = eth.eth_getCode(args.address) bytecode = eth.eth_getCode(args.address)
else: else:
exitWithError("Disassembler: Provide the input bytecode via -c BYTECODE or --id ID") exitWithError("Disassembler: Provide the input bytecode via -c BYTECODE or --id ID")
if (args.data): if (args.data):
trace = evm.trace(encoded_bytecode, args.data) trace = evm.trace(bytecode, args.data)
else: else:
trace = evm.trace(encoded_bytecode) trace = evm.trace(bytecode)
for i in trace: for i in trace:
if (re.match(r'^PUSH.*', i['op'])): if (re.match(r'^PUSH.*', i['op'])):

@ -6,11 +6,11 @@ from ethereum import utils
class ETHContract(persistent.Persistent): class ETHContract(persistent.Persistent):
def __init__(self, code, creation_code = ""): def __init__(self, code, creation_code = "", name = ""):
self.code = code self.code = code
self.creation_code = creation_code self.creation_code = creation_code
self.name = name
def get_xrefs(self): def get_xrefs(self):
@ -30,7 +30,7 @@ class ETHContract(persistent.Persistent):
return xrefs return xrefs
def get_instruction_list(self): def get_disassembly(self):
return asm.disassemble(util.safe_decode(self.code)) return asm.disassemble(util.safe_decode(self.code))

@ -2,6 +2,8 @@ from ethereum.abi import encode_abi, encode_int
from ethereum.utils import zpad from ethereum.utils import zpad
from ethereum.abi import method_id from ethereum.abi import method_id
import subprocess import subprocess
import binascii
import os
import re import re
@ -14,9 +16,8 @@ def safe_decode(hex_encoded_string):
def compile_solidity(solc_binary, file): def compile_solidity(solc_binary, file):
output = subprocess.check_output(["solc", "--bin-runtime", file], stderr=subprocess.DEVNULL) output = subprocess.check_output(["solc", "--bin-runtime", file], stderr=subprocess.DEVNULL)
m = re.search(r":(.*?) =======\\nBinary of the runtime part: \\n([0-9a-f]+)\\n", str(output))
m = re.search(r"runtime part: \\n([0-9a-f]+)\\n", str(output)) return [m.group(1), m.group(2)]
return m.group(1)
def encode_calldata(func_name, arg_types, args): def encode_calldata(func_name, arg_types, args):
@ -24,3 +25,7 @@ def encode_calldata(func_name, arg_types, args):
function_selector = zpad(encode_int(mid), 4) function_selector = zpad(encode_int(mid), 4)
args = encode_abi(arg_types, args) args = encode_abi(arg_types, args)
return "0x" + function_selector.hex() + args.hex() return "0x" + function_selector.hex() + args.hex()
def get_random_address():
return binascii.b2a_hex(os.urandom(20)).decode('UTF-8')

@ -14,7 +14,7 @@ class Getinstruction_listTestCase(ETHContractTestCase):
contract = ETHContract(self.code, self.creation_code) contract = ETHContract(self.code, self.creation_code)
instruction_list = contract.get_instruction_list() instruction_list = contract.get_disassembly()
self.assertEqual(len(instruction_list), 71, 'Error disassembling code using ETHContract.get_instruction_list()') self.assertEqual(len(instruction_list), 71, 'Error disassembling code using ETHContract.get_instruction_list()')

Loading…
Cancel
Save