|
|
@ -77,6 +77,8 @@ try: |
|
|
|
except KeyError: |
|
|
|
except KeyError: |
|
|
|
solc_binary = 'solc' |
|
|
|
solc_binary = 'solc' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Parse cmdline args |
|
|
|
|
|
|
|
|
|
|
|
args = parser.parse_args() |
|
|
|
args = parser.parse_args() |
|
|
|
|
|
|
|
|
|
|
|
if not (args.search or args.init_db or args.hash or args.disassemble or args.graph or args.xrefs or args.fire_lasers or args.trace): |
|
|
|
if not (args.search or args.init_db or args.hash or args.disassemble or args.graph or args.xrefs or args.fire_lasers or args.trace): |
|
|
@ -134,26 +136,26 @@ if (args.address or len(args.solidity_file)): |
|
|
|
except Exception as e: |
|
|
|
except Exception as e: |
|
|
|
exitWithError("Error establishing RPC connection: " + str(e)) |
|
|
|
exitWithError("Error establishing RPC connection: " + str(e)) |
|
|
|
|
|
|
|
|
|
|
|
# Load input contracts |
|
|
|
# Load / compile input contracts |
|
|
|
|
|
|
|
|
|
|
|
contracts = [] |
|
|
|
contracts = [] |
|
|
|
|
|
|
|
|
|
|
|
if (args.code): |
|
|
|
if (args.code): |
|
|
|
contracts.append(ETHContract(args.code, address = util.get_random_address())) |
|
|
|
contracts.append(ETHContract(args.code, address = util.get_indexed_address(0))) |
|
|
|
elif (args.address): |
|
|
|
elif (args.address): |
|
|
|
contracts.append(ETHContract(eth.eth_getCode(args.address), address = args.address)) |
|
|
|
contracts.append(ETHContract(eth.eth_getCode(args.address), address = args.address)) |
|
|
|
elif (len(args.solidity_file)): |
|
|
|
elif (len(args.solidity_file)): |
|
|
|
counter = 0 |
|
|
|
index = 0 |
|
|
|
|
|
|
|
|
|
|
|
for file in args.solidity_file: |
|
|
|
for file in args.solidity_file: |
|
|
|
|
|
|
|
|
|
|
|
file = file.replace("~", str(Path.home())) # Expand user path |
|
|
|
file = file.replace("~", str(Path.home())) # Expand user path |
|
|
|
name, bytecode = compile_solidity(solc_binary, file) |
|
|
|
name, bytecode = compile_solidity(solc_binary, file) |
|
|
|
|
|
|
|
|
|
|
|
# Max. 16 contracts supported |
|
|
|
# Max. 16 contracts supported! |
|
|
|
|
|
|
|
|
|
|
|
contract = ETHContract(bytecode, name = name, address = "0x" + hex(counter)[2:] * 40) |
|
|
|
contract = ETHContract(bytecode, name = name, address = util.get_indexed_address(index)) |
|
|
|
counter += 1 |
|
|
|
index += 1 |
|
|
|
|
|
|
|
|
|
|
|
contracts.append(contract) |
|
|
|
contracts.append(contract) |
|
|
|
logging.info(contract.name + " at " + contract.address) |
|
|
|
logging.info(contract.name + " at " + contract.address) |
|
|
@ -161,6 +163,7 @@ elif (len(args.solidity_file)): |
|
|
|
else: |
|
|
|
else: |
|
|
|
exitWithError("No input bytecode. Please provide EVM code via -c BYTECODE, -a ADDRESS, or -i SOLIDITY_FILES") |
|
|
|
exitWithError("No input bytecode. Please provide EVM code via -c BYTECODE, -a ADDRESS, or -i SOLIDITY_FILES") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Commands |
|
|
|
# Commands |
|
|
|
|
|
|
|
|
|
|
|
if (args.disassemble): |
|
|
|
if (args.disassemble): |
|
|
@ -168,79 +171,50 @@ if (args.disassemble): |
|
|
|
easm_text = contracts[0].get_easm() |
|
|
|
easm_text = contracts[0].get_easm() |
|
|
|
sys.stdout.write(easm_text) |
|
|
|
sys.stdout.write(easm_text) |
|
|
|
|
|
|
|
|
|
|
|
elif (args.graph): |
|
|
|
elif (args.trace): |
|
|
|
|
|
|
|
|
|
|
|
if args.enable_physics is not None: |
|
|
|
|
|
|
|
physics = True |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
modules = [] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for contract in contracts: |
|
|
|
|
|
|
|
modules.append(contract.as_dict()) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
html = generate_callgraph(modules, args.enable_physics) |
|
|
|
if (args.data): |
|
|
|
|
|
|
|
trace = evm.trace(contracts[0].code, args.data) |
|
|
|
|
|
|
|
|
|
|
|
try: |
|
|
|
else: |
|
|
|
with open(args.graph, "w") as f: |
|
|
|
trace = evm.trace(contracts[0].code) |
|
|
|
f.write(html) |
|
|
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print("Error saving graph: " + str(e)) |
|
|
|
for i in trace: |
|
|
|
|
|
|
|
if (re.match(r'^PUSH.*', i['op'])): |
|
|
|
|
|
|
|
print(str(i['pc']) + " " + i['op'] + " " + i['pushvalue'] + ";\tSTACK: " + i['stack']) |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
print(str(i['pc']) + " " + i['op'] + ";\tSTACK: " + i['stack']) |
|
|
|
|
|
|
|
|
|
|
|
elif (args.xrefs): |
|
|
|
elif (args.xrefs): |
|
|
|
|
|
|
|
|
|
|
|
contract = ETHContract(bytecode) |
|
|
|
print("\n".join(contracts[0].get_xrefs())) |
|
|
|
|
|
|
|
|
|
|
|
print("\n".join(contract.get_xrefs())) |
|
|
|
elif (args.graph) or (args.fire_lasers): |
|
|
|
|
|
|
|
|
|
|
|
elif (args.fire_lasers): |
|
|
|
# Convert to LASER SVM format |
|
|
|
|
|
|
|
|
|
|
|
modules = [] |
|
|
|
modules = {} |
|
|
|
|
|
|
|
|
|
|
|
for contract in contracts: |
|
|
|
for contract in contracts: |
|
|
|
modules.append(contract.as_dict()) |
|
|
|
modules[contract.address] = contract.as_dict() |
|
|
|
|
|
|
|
|
|
|
|
laserfree.fire(modules) |
|
|
|
if (args.graph): |
|
|
|
|
|
|
|
|
|
|
|
elif (args.trace): |
|
|
|
if args.enable_physics is not None: |
|
|
|
|
|
|
|
physics = True |
|
|
|
if (args.code): |
|
|
|
|
|
|
|
bytecode = args.code |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
elif (args.address): |
|
|
|
html = generate_callgraph(modules, args.enable_physics) |
|
|
|
if args.ipc: |
|
|
|
|
|
|
|
eth = EthIpc() |
|
|
|
|
|
|
|
bytecode = eth.eth_getCode(args.address) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
else: |
|
|
|
try: |
|
|
|
if args.infura_mainnet: |
|
|
|
with open(args.graph, "w") as f: |
|
|
|
eth = EthJsonRpc('mainnet.infura.io', 443, True) |
|
|
|
f.write(html) |
|
|
|
elif args.infura_rinkeby: |
|
|
|
except Exception as e: |
|
|
|
eth = EthJsonRpc('rinkeby.infura.io', 443, True) |
|
|
|
|
|
|
|
elif args.infura_kovan: |
|
|
|
|
|
|
|
eth = EthJsonRpc('kovan.infura.io', 443, True) |
|
|
|
|
|
|
|
elif args.infura_ropsten: |
|
|
|
|
|
|
|
eth = EthJsonRpc('ropsten.infura.io', 443, True) |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
eth = EthJsonRpc(args.rpchost, args.rpcport, args.rpctls) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bytecode = eth.eth_getCode(args.address) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
exitWithError("Disassembler: Provide the input bytecode via -c BYTECODE or --id ID") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (args.data): |
|
|
|
print("Error saving graph: " + str(e)) |
|
|
|
trace = evm.trace(bytecode, args.data) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
else: |
|
|
|
else: |
|
|
|
trace = evm.trace(bytecode) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for i in trace: |
|
|
|
|
|
|
|
if (re.match(r'^PUSH.*', i['op'])): |
|
|
|
|
|
|
|
print(str(i['pc']) + " " + i['op'] + " " + i['pushvalue'] + ";\tSTACK: " + i['stack']) |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
print(str(i['pc']) + " " + i['op'] + ";\tSTACK: " + i['stack']) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
laserfree.fire(modules) |
|
|
|
|
|
|
|
|
|
|
|
else: |
|
|
|
else: |
|
|
|
parser.print_help() |
|
|
|
parser.print_help() |
|
|
|