Merge branch 'master' into topcoder

pull/99/head
freewind 7 years ago
commit 1ac4087802
  1. 10
      README.md
  2. 21
      myth
  3. 185
      mythril-repo-changes.diff
  4. 109
      mythril/analysis/traceexplore.py
  5. 3
      mythril/ether/__init__.py
  6. 8
      mythril/ether/contractstorage.py
  7. 68
      mythril/ipc/client.py
  8. 2
      requirements.txt
  9. 4
      setup.py
  10. 161
      static/assertions.html

@ -1,6 +1,6 @@
# Mythril # Mythril
[![PyPI](https://badge.fury.io/py/mythril.svg)](https://pypi.python.org/pypi/mythril) [![Join the chat at https://gitter.im/ConsenSys/mythril](https://badges.gitter.im/ConsenSys/mythril.svg)](https://gitter.im/ConsenSys/mythril?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![PyPI](https://badge.fury.io/py/mythril.svg)](https://pypi.python.org/pypi/mythril)
<img height="120px" align="right" src="/static/mythril.png"/> <img height="120px" align="right" src="/static/mythril.png"/>
@ -183,6 +183,14 @@ $ myth -ig ./graph.html -a 0x5c436ff914c458983414019195e0f4ecbef9e6dd --max-dept
~~The "bounce" effect, while awesome (and thus enabled by default), sometimes messes up the graph layout.~~ Try adding the `--enable-physics` flag for a very entertaining "bounce" effect that unfortunately completely destroys usability. ~~The "bounce" effect, while awesome (and thus enabled by default), sometimes messes up the graph layout.~~ Try adding the `--enable-physics` flag for a very entertaining "bounce" effect that unfortunately completely destroys usability.
## Statespace JSON for Traceview Explorer
The `-j FILENAME` option dumps the statespace to json in the format that is required by the [Symbolic Trace Explorer GUI](https://github.com/ConsenSys/mythril-trace-explorer).
```bash
$ ./myth -ij ./statespace.json -a 0x5c436ff914c458983414019195e0f4ecbef9e6dd --max-depth 8
```
## Blockchain exploration ## Blockchain exploration
If you are planning to do batch operations or use the contract search features, running a [go-ethereum](https://github.com/ethereum/go-ethereum) node is recommended. Start your local node as follows: If you are planning to do batch operations or use the contract search features, running a [go-ethereum](https://github.com/ethereum/go-ethereum) node is recommended. Start your local node as follows:

21
myth

@ -4,7 +4,7 @@
http://www.github.com/b-mueller/mythril http://www.github.com/b-mueller/mythril
""" """
from json.decoder import JSONDecodeError
import logging import logging
import json import json
import sys import sys
@ -29,6 +29,7 @@ from mythril.support.loader import DynLoader
from mythril.exceptions import CompilerError, NoContractFoundError from mythril.exceptions import CompilerError, NoContractFoundError
from mythril.analysis.symbolic import SymExecWrapper from mythril.analysis.symbolic import SymExecWrapper
from mythril.analysis.callgraph import generate_graph from mythril.analysis.callgraph import generate_graph
from mythril.analysis.traceexplore import get_serializable_statespace
from mythril.analysis.security import fire_lasers from mythril.analysis.security import fire_lasers
from mythril.analysis.report import Report from mythril.analysis.report import Report
@ -57,6 +58,7 @@ commands.add_argument('-g', '--graph', help='generate a control flow graph', met
commands.add_argument('-x', '--fire-lasers', action='store_true', help='detect vulnerabilities, use with -c, -a or solidity file(s)') commands.add_argument('-x', '--fire-lasers', action='store_true', help='detect vulnerabilities, use with -c, -a or solidity file(s)')
commands.add_argument('-t', '--truffle', action='store_true', help='analyze a truffle project (run from project dir)') commands.add_argument('-t', '--truffle', action='store_true', help='analyze a truffle project (run from project dir)')
commands.add_argument('-d', '--disassemble', action='store_true', help='print disassembly') commands.add_argument('-d', '--disassemble', action='store_true', help='print disassembly')
commands.add_argument('-j', '--statespace-json', help='dumps the statespace json', metavar='OUTPUT_FILE')
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')
@ -129,7 +131,7 @@ with open(signatures_file) as f:
# Parse cmdline args # Parse cmdline args
if not (args.search or args.init_db or args.hash or args.disassemble or args.graph or args.fire_lasers or args.storage or args.truffle): if not (args.search or args.init_db or args.hash or args.disassemble or args.graph or args.fire_lasers or args.storage or args.truffle or args.statespace_json):
parser.print_help() parser.print_help()
sys.exit() sys.exit()
@ -398,6 +400,21 @@ elif args.graph or args.fire_lasers:
'markdown': report.as_markdown() or "The analysis was completed successfully. No issues were detected." 'markdown': report.as_markdown() or "The analysis was completed successfully. No issues were detected."
} }
print(outputs[args.outform]) print(outputs[args.outform])
elif args.statespace_json:
if not contracts:
exitWithError(args.outform, "input files do not contain any valid contracts")
if args.dynld:
sym = SymExecWrapper(contracts[0], address, dynloader=DynLoader(eth), max_depth=args.max_depth)
else:
sym = SymExecWrapper(contracts[0], address, max_depth=args.max_depth)
try:
with open(args.statespace_json, "w") as f:
json.dump(get_serializable_statespace(sym), f)
except Exception as e:
exitWithError(args.outform, "Error saving json: " + str(e))
else: else:
parser.print_help() parser.print_help()

@ -0,0 +1,185 @@
diff --git a/README.md b/README.md
index ab3d9fd..357a612 100644
--- a/README.md
+++ b/README.md
@@ -144,6 +144,14 @@ $ myth -ig ./graph.html -a 0x5c436ff914c458983414019195e0f4ecbef9e6dd --max-dept
~~The "bounce" effect, while awesome (and thus enabled by default), sometimes messes up the graph layout.~~ Try adding the `--enable-physics` flag for a very entertaining "bounce" effect that unfortunately completely destroys usability.
+## Statespace JSON for Traceview Explorer
+
+The `-j FILENAME` option dumps the statespace to json in the format that is required by the TraceView Explorer GUI
+
+```bash
+$ ./myth -ij ./statespace.json -a 0x5c436ff914c458983414019195e0f4ecbef9e6dd --max-depth 8
+```
+
## Blockchain exploration
If you are planning to do batch operations or use the contract search features, running a [go-ethereum](https://github.com/ethereum/go-ethereum) node is recommended. Start your local node as follows:
diff --git a/myth b/myth
index b3289bc..08e44d9 100755
--- a/myth
+++ b/myth
@@ -29,6 +29,7 @@ from mythril.support.loader import DynLoader
from mythril.exceptions import CompilerError, NoContractFoundError
from mythril.analysis.symbolic import SymExecWrapper
from mythril.analysis.callgraph import generate_graph
+from mythril.analysis.traceexplore import get_serializable_statespace
from mythril.analysis.security import fire_lasers
from mythril.analysis.report import Report
@@ -57,6 +58,7 @@ commands.add_argument('-g', '--graph', help='generate a control flow graph', met
commands.add_argument('-x', '--fire-lasers', action='store_true', help='detect vulnerabilities, use with -c, -a or solidity file(s)')
commands.add_argument('-t', '--truffle', action='store_true', help='analyze a truffle project (run from project dir)')
commands.add_argument('-d', '--disassemble', action='store_true', help='print disassembly')
+commands.add_argument('-j', '--statespace-json', help='dumps the statespace json', metavar='OUTPUT_FILE')
inputs = parser.add_argument_group('input arguments')
inputs.add_argument('-c', '--code', help='hex-encoded bytecode string ("6060604052...")', metavar='BYTECODE')
@@ -129,7 +131,7 @@ with open(signatures_file) as f:
# Parse cmdline args
-if not (args.search or args.init_db or args.hash or args.disassemble or args.graph or args.fire_lasers or args.storage or args.truffle):
+if not (args.search or args.init_db or args.hash or args.disassemble or args.graph or args.fire_lasers or args.storage or args.truffle or args.statespace_json):
parser.print_help()
sys.exit()
@@ -402,6 +404,21 @@ elif args.graph or args.fire_lasers:
'markdown': report.as_markdown() or "The analysis was completed successfully. No issues were detected."
}
print(outputs[args.outform])
+
+elif args.statespace_json:
+ if not contracts:
+ exitWithError(args.outform, "input files do not contain any valid contracts")
+
+ if args.dynld:
+ sym = SymExecWrapper(contracts[0], address, dynloader=DynLoader(eth), max_depth=args.max_depth)
+ else:
+ sym = SymExecWrapper(contracts[0], address, max_depth=args.max_depth)
+
+ try:
+ with open(args.statespace_json, "w") as f:
+ json.dump(get_serializable_statespace(sym), f)
+ except Exception as e:
+ exitWithError(args.outform, "Error saving json: " + str(e))
else:
parser.print_help()
diff --git a/mythril/analysis/traceexplore.py b/mythril/analysis/traceexplore.py
new file mode 100644
index 0000000..cbe0391
--- /dev/null
+++ b/mythril/analysis/traceexplore.py
@@ -0,0 +1,109 @@
+from z3 import Z3Exception, simplify
+from laser.ethereum.svm import NodeFlags
+import re
+
+colors = [
+ {'border': '#26996f', 'background': '#2f7e5b', 'highlight': {'border': '#fff', 'background': '#28a16f'}},
+ {'border': '#9e42b3', 'background': '#842899', 'highlight': {'border': '#fff', 'background': '#933da6'}},
+ {'border': '#b82323', 'background': '#991d1d', 'highlight': {'border': '#fff', 'background': '#a61f1f'}},
+ {'border': '#4753bf', 'background': '#3b46a1', 'highlight': {'border': '#fff', 'background': '#424db3'}},
+ {'border': '#26996f', 'background': '#2f7e5b', 'highlight': {'border': '#fff', 'background': '#28a16f'}},
+ {'border': '#9e42b3', 'background': '#842899', 'highlight': {'border': '#fff', 'background': '#933da6'}},
+ {'border': '#b82323', 'background': '#991d1d', 'highlight': {'border': '#fff', 'background': '#a61f1f'}},
+ {'border': '#4753bf', 'background': '#3b46a1', 'highlight': {'border': '#fff', 'background': '#424db3'}},
+]
+
+def get_serializable_statespace(statespace):
+
+ nodes = []
+ edges = []
+
+ color_map = {}
+ i = 0
+ for k in statespace.accounts:
+ color_map[statespace.accounts[k].contract_name] = colors[i]
+ i += 1
+
+ for node_key in statespace.nodes:
+
+ node = statespace.nodes[node_key]
+
+ code = node.get_cfg_dict()['code']
+ code = re.sub("([0-9a-f]{8})[0-9a-f]+", lambda m: m.group(1) + "(...)", code)
+
+ if NodeFlags.FUNC_ENTRY in node.flags:
+ code = re.sub("JUMPDEST", node.function_name, code)
+
+ code_split = code.split("\\n")
+
+ truncated_code = code if (len(code_split) < 7) else "\\n".join(code_split[:6]) + "\\n(click to expand +)"
+
+ color = color_map[node.get_cfg_dict()['contract_name']]
+
+ def get_state_accounts(state):
+ state_accounts = []
+ for key in state.accounts:
+ account = state.accounts[key].as_dict()
+ account.pop('code', None)
+ account['balance'] = str(account['balance'])
+
+ storage = {}
+ for storage_key in account['storage']:
+ storage[str(storage_key)] = str(account['storage'][storage_key])
+
+ state_accounts.append({
+ 'address': key,
+ 'storage': storage
+ })
+ return state_accounts
+
+ states = [{'machine': x.mstate.as_dict(), 'accounts': get_state_accounts(x)} for x in node.states]
+
+ for state in states:
+ state['machine']['stack'] = [str(s) for s in state['machine']['stack']]
+ state['machine']['memory'] = [str(m) for m in state['machine']['memory']]
+
+ truncated_code = truncated_code.replace('\\n', '\n')
+ code = code.replace('\\n', '\n')
+
+ s_node = {
+ 'id': str(node_key),
+ 'func': str(node.function_name),
+ 'label': truncated_code,
+ 'code': code,
+ 'truncated': truncated_code,
+ 'states': states,
+ 'color': color,
+ 'instructions': code.split('\n')
+ }
+
+ nodes.append(s_node)
+
+ for edge in statespace.edges:
+
+ if (edge.condition is None):
+ label = ""
+ else:
+
+ try:
+ label = str(simplify(edge.condition)).replace("\n", "")
+ except Z3Exception:
+ label = str(edge.condition).replace("\n", "")
+
+ label = re.sub("([^_])([\d]{2}\d+)", lambda m: m.group(1) + hex(int(m.group(2))), label)
+ code = re.sub("([0-9a-f]{8})[0-9a-f]+", lambda m: m.group(1) + "(...)", code)
+
+ s_edge = {
+ 'from': str(edge.as_dict()['from']),
+ 'to': str(edge.as_dict()['to']),
+ 'arrows': 'to',
+ 'label': label,
+ 'smooth': { 'type': "cubicBezier" }
+ }
+
+ edges.append(s_edge)
+
+ return {
+ 'edges': edges,
+ 'nodes': nodes
+ }

@ -0,0 +1,109 @@
from z3 import Z3Exception, simplify
from laser.ethereum.svm import NodeFlags
import re
colors = [
{'border': '#26996f', 'background': '#2f7e5b', 'highlight': {'border': '#fff', 'background': '#28a16f'}},
{'border': '#9e42b3', 'background': '#842899', 'highlight': {'border': '#fff', 'background': '#933da6'}},
{'border': '#b82323', 'background': '#991d1d', 'highlight': {'border': '#fff', 'background': '#a61f1f'}},
{'border': '#4753bf', 'background': '#3b46a1', 'highlight': {'border': '#fff', 'background': '#424db3'}},
{'border': '#26996f', 'background': '#2f7e5b', 'highlight': {'border': '#fff', 'background': '#28a16f'}},
{'border': '#9e42b3', 'background': '#842899', 'highlight': {'border': '#fff', 'background': '#933da6'}},
{'border': '#b82323', 'background': '#991d1d', 'highlight': {'border': '#fff', 'background': '#a61f1f'}},
{'border': '#4753bf', 'background': '#3b46a1', 'highlight': {'border': '#fff', 'background': '#424db3'}},
]
def get_serializable_statespace(statespace):
nodes = []
edges = []
color_map = {}
i = 0
for k in statespace.accounts:
color_map[statespace.accounts[k].contract_name] = colors[i]
i += 1
for node_key in statespace.nodes:
node = statespace.nodes[node_key]
code = node.get_cfg_dict()['code']
code = re.sub("([0-9a-f]{8})[0-9a-f]+", lambda m: m.group(1) + "(...)", code)
if NodeFlags.FUNC_ENTRY in node.flags:
code = re.sub("JUMPDEST", node.function_name, code)
code_split = code.split("\\n")
truncated_code = code if (len(code_split) < 7) else "\\n".join(code_split[:6]) + "\\n(click to expand +)"
color = color_map[node.get_cfg_dict()['contract_name']]
def get_state_accounts(state):
state_accounts = []
for key in state.accounts:
account = state.accounts[key].as_dict()
account.pop('code', None)
account['balance'] = str(account['balance'])
storage = {}
for storage_key in account['storage']:
storage[str(storage_key)] = str(account['storage'][storage_key])
state_accounts.append({
'address': key,
'storage': storage
})
return state_accounts
states = [{'machine': x.mstate.as_dict(), 'accounts': get_state_accounts(x)} for x in node.states]
for state in states:
state['machine']['stack'] = [str(s) for s in state['machine']['stack']]
state['machine']['memory'] = [str(m) for m in state['machine']['memory']]
truncated_code = truncated_code.replace('\\n', '\n')
code = code.replace('\\n', '\n')
s_node = {
'id': str(node_key),
'func': str(node.function_name),
'label': truncated_code,
'code': code,
'truncated': truncated_code,
'states': states,
'color': color,
'instructions': code.split('\n')
}
nodes.append(s_node)
for edge in statespace.edges:
if (edge.condition is None):
label = ""
else:
try:
label = str(simplify(edge.condition)).replace("\n", "")
except Z3Exception:
label = str(edge.condition).replace("\n", "")
label = re.sub("([^_])([\d]{2}\d+)", lambda m: m.group(1) + hex(int(m.group(2))), label)
code = re.sub("([0-9a-f]{8})[0-9a-f]+", lambda m: m.group(1) + "(...)", code)
s_edge = {
'from': str(edge.as_dict()['from']),
'to': str(edge.as_dict()['to']),
'arrows': 'to',
'label': label,
'smooth': { 'type': "cubicBezier" }
}
edges.append(s_edge)
return {
'edges': edges,
'nodes': nodes
}

@ -0,0 +1,3 @@
import time
start_time = time.time()

@ -1,6 +1,5 @@
import os import os
import hashlib import hashlib
import persistent
import persistent.list import persistent.list
import transaction import transaction
from BTrees.OOBTree import BTree from BTrees.OOBTree import BTree
@ -9,7 +8,8 @@ from ZODB import FileStorage
from multiprocessing import Pool from multiprocessing import Pool
import logging import logging
from mythril.ether.ethcontract import ETHContract, InstanceList from mythril.ether.ethcontract import ETHContract, InstanceList
from mythril import ether
import time
BLOCKS_PER_THREAD = 256 BLOCKS_PER_THREAD = 256
NUM_THREADS = 8 NUM_THREADS = 8
@ -127,7 +127,9 @@ class ContractStorage(persistent.Persistent):
processed += NUM_THREADS * BLOCKS_PER_THREAD processed += NUM_THREADS * BLOCKS_PER_THREAD
self.last_block = blockNum self.last_block = blockNum
transaction.commit() transaction.commit()
print("%d blocks processed, %d unique contracts in database, next block: %d" % (processed, len(self.contracts), blockNum))
cost_time = time.time() - ether.start_time
print("%d blocks processed (in %d seconds), %d unique contracts in database, next block: %d" % (processed, cost_time, len(self.contracts), blockNum))
# If we've finished initializing the database, start over from the end of the chain if we want to initialize again # If we've finished initializing the database, start over from the end of the chain if we want to initialize again
self.last_block = 0 self.last_block = 0

@ -3,6 +3,7 @@ import socket
import logging import logging
from mythril.rpc.base_client import BaseClient from mythril.rpc.base_client import BaseClient
from .utils import (get_default_ipc_path, to_text, to_bytes) from .utils import (get_default_ipc_path, to_text, to_bytes)
import threading
try: try:
from json import JSONDecodeError from json import JSONDecodeError
@ -18,42 +19,55 @@ This code is mostly adapted from:
- https://github.com/ethereum/web3.py - https://github.com/ethereum/web3.py
''' '''
# use thread local to store socket which will be reused just in owner thread
THREAD_LOCAL = threading.local()
class EthIpc(BaseClient): class EthIpc(BaseClient):
def __init__(self, ipc_path=IPC_PATH, testnet=False, socket_timeout=0.2): def __init__(self, ipc_path=IPC_PATH, testnet=False):
if ipc_path is None: if ipc_path is None:
ipc_path = get_default_ipc_path(testnet) ipc_path = get_default_ipc_path(testnet)
self.ipc_path = ipc_path self.ipc_path = ipc_path
self.socket_timeout = socket_timeout
def connect_if_not_yet(self):
if not hasattr(THREAD_LOCAL, "socket"):
THREAD_LOCAL.socket = self.get_socket()
def reconnect(self):
self.close()
THREAD_LOCAL.socket = self.get_socket()
@staticmethod
def close():
if THREAD_LOCAL.socket is not None:
try:
THREAD_LOCAL.socket.close()
except socket.error:
pass
def get_socket(self): def get_socket(self):
_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) _socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
_socket.connect(self.ipc_path) _socket.connect(self.ipc_path)
# Tell the socket not to block on reads. # Tell the socket not to block on reads.
_socket.settimeout(self.socket_timeout) _socket.settimeout(2)
return _socket return _socket
def send(self, request): @staticmethod
_socket = None def send_request(request):
try: THREAD_LOCAL.socket.sendall(request)
_socket = self.get_socket()
_socket.sendall(request)
response_raw = ""
while True: @staticmethod
def read_response():
response_raw = ""
while True:
response_raw += to_text(THREAD_LOCAL.socket.recv(4096))
trimmed = response_raw.strip()
if trimmed and trimmed[-1] == '}':
logging.debug("ipc response: %s" % response_raw)
try: try:
response_raw += to_text(_socket.recv(4096)) return json.loads(trimmed)
except socket.timeout: except JSONDecodeError:
break continue
if response_raw == "":
return None
else:
return response_raw
finally:
if _socket:
_socket.close()
def _call(self, method, params=None, _id=1): def _call(self, method, params=None, _id=1):
params = params or [] params = params or []
@ -66,16 +80,18 @@ class EthIpc(BaseClient):
logging.debug("ipc send: %s" % json.dumps(data)) logging.debug("ipc send: %s" % json.dumps(data))
request = to_bytes(json.dumps(data)) request = to_bytes(json.dumps(data))
self.connect_if_not_yet()
for _ in range(3): for _ in range(3):
response_raw = self.send(request) try:
if response_raw is not None: self.send_request(request)
response = self.read_response()
break break
except socket.timeout or OSError:
self.reconnect()
else: else:
raise ValueError("No JSON returned by socket") raise ValueError("No JSON returned by socket")
logging.debug("ipc response: %s" % response_raw)
response = json.loads(response_raw)
if "error" in response: if "error" in response:
raise ValueError(response["error"]["message"]) raise ValueError(response["error"]["message"])

@ -1,7 +1,7 @@
ethereum>=2.3.0 ethereum>=2.3.0
ZODB>=5.3.0 ZODB>=5.3.0
z3-solver>=4.5 z3-solver>=4.5
laser-ethereum==0.5.18 laser-ethereum==0.5.19
requests requests
BTrees BTrees
py-solc py-solc

@ -254,7 +254,7 @@ Credit
setup( setup(
name='mythril', name='mythril',
version='0.15.5', version='0.15.7',
description='Security analysis tool for Ethereum smart contracts', description='Security analysis tool for Ethereum smart contracts',
long_description=long_description, long_description=long_description,
@ -290,7 +290,7 @@ setup(
'ethereum>=2.3.0', 'ethereum>=2.3.0',
'ZODB>=5.3.0', 'ZODB>=5.3.0',
'z3-solver>=4.5', 'z3-solver>=4.5',
'laser-ethereum==0.5.18', 'laser-ethereum==0.5.19',
'requests', 'requests',
'BTrees', 'BTrees',
'py-solc', 'py-solc',

@ -0,0 +1,161 @@
<html>
<head>
<style type="text/css">
#mynetwork {
background-color: #ffffff;
}
body {
background-color: #ffffff;
color: #000000;
font-size: 10px;
font-family: "courier new";
}
</style>
<link href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.css" rel="stylesheet" type="text/css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.js"></script>
<script>
var options = {
autoResize: true,
height: '100%',
width: '100%',
manipulation: false,
height: '90%',
layout: {
randomSeed: undefined,
improvedLayout:true,
hierarchical: {
enabled:true,
levelSeparation: 450,
nodeSpacing: 200,
treeSpacing: 100,
blockShifting: true,
edgeMinimization: true,
parentCentralization: false,
direction: 'LR', // UD, DU, LR, RL
sortMethod: 'directed' // hubsize, directed
}
},
nodes:{
color: '#000000',
borderWidth: 1,
borderWidthSelected: 1,
shapeProperties: {
borderDashes: false, // only for borders
borderRadius: 0, // only for box shape
},
chosen: true,
shape: 'box',
font: {
face: 'courier new',
align: 'left',
color: '#000000',
},
},
edges:{
font: {
color: '#000000',
face: 'courier new',
background: 'none',
strokeWidth: 0, // px
strokeColor: '#ffffff',
align: 'horizontal',
multi: false,
vadjust: 0,
}
},
physics:{
enabled: false,
}
}
var nodes = [
{id: '0', color: {border: '#000000', background: '#ffffff', highlight: {border: '#000000', background: '#ffffff'}}, size: 150, 'label': '0 PUSH1 0x60\n2 PUSH1 0x40\n4 MSTORE\n5 PUSH1 0x04\n7 CALLDATASIZE\n8 LT\n(click to expand +)', 'fullLabel': '0 PUSH1 0x60\n2 PUSH1 0x40\n4 MSTORE\n5 PUSH1 0x04\n7 CALLDATASIZE\n8 LT\n9 PUSH1 0x49\n11 JUMPI\n', 'truncLabel': '0 PUSH1 0x60\n2 PUSH1 0x40\n4 MSTORE\n5 PUSH1 0x04\n7 CALLDATASIZE\n8 LT\n(click to expand +)', 'isExpanded': false},
{id: '1', color: {border: '#000000', background: '#ffffff', highlight: {border: '#000000', background: '#ffffff'}}, size: 150, 'label': '73 JUMPDEST\n74 PUSH1 0x00\n76 DUP1\n77 REVERT\n', 'fullLabel': '73 JUMPDEST\n74 PUSH1 0x00\n76 DUP1\n77 REVERT\n', 'truncLabel': '73 JUMPDEST\n74 PUSH1 0x00\n76 DUP1\n77 REVERT\n', 'isExpanded': false},
{id: '2', color: {border: '#000000', background: '#ffffff', highlight: {border: '#000000', background: '#ffffff'}}, size: 150, 'label': '12 PUSH1 0x00\n14 CALLDATALOAD\n15 PUSH29 0x01000000(...)\n45 SWAP1\n46 DIV\n47 PUSH4 0xffffffff\n(click to expand +)', 'fullLabel': '12 PUSH1 0x00\n14 CALLDATALOAD\n15 PUSH29 0x01000000(...)\n45 SWAP1\n46 DIV\n47 PUSH4 0xffffffff\n52 AND\n53 DUP1\n54 PUSH4 0x59ce2f44\n59 EQ\n60 PUSH1 0x4e\n62 JUMPI\n', 'truncLabel': '12 PUSH1 0x00\n14 CALLDATALOAD\n15 PUSH29 0x01000000(...)\n45 SWAP1\n46 DIV\n47 PUSH4 0xffffffff\n(click to expand +)', 'isExpanded': false},
{id: '3', color: {border: '#000000', background: '#ffffff', highlight: {border: '#000000', background: '#ffffff'}}, size: 150, 'label': '78 assertion2(uint256)\n79 CALLVALUE\n80 ISZERO\n81 PUSH1 0x58\n83 JUMPI\n', 'fullLabel': '78 assertion2(uint256)\n79 CALLVALUE\n80 ISZERO\n81 PUSH1 0x58\n83 JUMPI\n', 'truncLabel': '78 assertion2(uint256)\n79 CALLVALUE\n80 ISZERO\n81 PUSH1 0x58\n83 JUMPI\n', 'isExpanded': false},
{id: '4', color: {border: '#000000', background: '#ffffff', highlight: {border: '#000000', background: '#ffffff'}}, size: 150, 'label': '88 JUMPDEST\n89 PUSH1 0x6c\n91 PUSH1 0x04\n93 DUP1\n94 DUP1\n95 CALLDATALOAD\n(click to expand +)', 'fullLabel': '88 JUMPDEST\n89 PUSH1 0x6c\n91 PUSH1 0x04\n93 DUP1\n94 DUP1\n95 CALLDATALOAD\n96 SWAP1\n97 PUSH1 0x20\n99 ADD\n100 SWAP1\n101 SWAP2\n102 SWAP1\n103 POP\n104 POP\n105 PUSH1 0x8e\n107 JUMP\n', 'truncLabel': '88 JUMPDEST\n89 PUSH1 0x6c\n91 PUSH1 0x04\n93 DUP1\n94 DUP1\n95 CALLDATALOAD\n(click to expand +)', 'isExpanded': false},
{id: '5', color: {border: '#000000', background: '#ffffff', highlight: {border: '#000000', background: '#ffffff'}}, size: 150, 'label': '142 JUMPDEST\n143 PUSH2 0x0100\n146 DUP2\n147 GT\n148 ISZERO\n149 PUSH1 0x9c\n(click to expand +)', 'fullLabel': '142 JUMPDEST\n143 PUSH2 0x0100\n146 DUP2\n147 GT\n148 ISZERO\n149 PUSH1 0x9c\n151 JUMPI\n', 'truncLabel': '142 JUMPDEST\n143 PUSH2 0x0100\n146 DUP2\n147 GT\n148 ISZERO\n149 PUSH1 0x9c\n(click to expand +)', 'isExpanded': false},
{id: '6', color: {border: '#000000', background: '#ffffff', highlight: {border: '#000000', background: '#ffffff'}}, size: 150, 'label': '156 JUMPDEST\n157 PUSH2 0x0400\n160 PUSH1 0x04\n162 DUP3\n163 MUL\n164 GT\n(click to expand +)', 'fullLabel': '156 JUMPDEST\n157 PUSH2 0x0400\n160 PUSH1 0x04\n162 DUP3\n163 MUL\n164 GT\n165 ISZERO\n166 ISZERO\n167 ISZERO\n168 PUSH1 0xac\n170 JUMPI\n', 'truncLabel': '156 JUMPDEST\n157 PUSH2 0x0400\n160 PUSH1 0x04\n162 DUP3\n163 MUL\n164 GT\n(click to expand +)', 'isExpanded': false},
{id: '7', color: {border: '#000000', background: '#ffffff', highlight: {border: '#000000', background: '#ffffff'}}, size: 150, 'label': '172 JUMPDEST\n173 POP\n174 JUMP\n', 'fullLabel': '172 JUMPDEST\n173 POP\n174 JUMP\n', 'truncLabel': '172 JUMPDEST\n173 POP\n174 JUMP\n', 'isExpanded': false},
{id: '8', color: {border: '#000000', background: '#ffffff', highlight: {border: '#000000', background: '#ffffff'}}, size: 150, 'label': '108 JUMPDEST\n109 STOP\n', 'fullLabel': '108 JUMPDEST\n109 STOP\n', 'truncLabel': '108 JUMPDEST\n109 STOP\n', 'isExpanded': false},
{id: '9', color: {border: '#000000', background: '#ffffff', highlight: {border: '#000000', background: '#ffffff'}}, size: 150, 'label': '171 ASSERT_FAIL\n', 'fullLabel': '171 ASSERT_FAIL\n', 'truncLabel': '171 ASSERT_FAIL\n', 'isExpanded': false},
{id: '10', color: {border: '#000000', background: '#ffffff', highlight: {border: '#000000', background: '#ffffff'}}, size: 150, 'label': '152 PUSH1 0x00\n154 DUP1\n155 REVERT\n', 'fullLabel': '152 PUSH1 0x00\n154 DUP1\n155 REVERT\n', 'truncLabel': '152 PUSH1 0x00\n154 DUP1\n155 REVERT\n', 'isExpanded': false},
{id: '11', color: {border: '#000000', background: '#ffffff', highlight: {border: '#000000', background: '#ffffff'}}, size: 150, 'label': '84 PUSH1 0x00\n86 DUP1\n87 REVERT\n', 'fullLabel': '84 PUSH1 0x00\n86 DUP1\n87 REVERT\n', 'truncLabel': '84 PUSH1 0x00\n86 DUP1\n87 REVERT\n', 'isExpanded': false},
{id: '12', color: {border: '#000000', background: '#ffffff', highlight: {border: '#000000', background: '#ffffff'}}, size: 150, 'label': '63 DUP1\n64 PUSH4 0xe166a663\n69 EQ\n70 PUSH1 0x6e\n72 JUMPI\n', 'fullLabel': '63 DUP1\n64 PUSH4 0xe166a663\n69 EQ\n70 PUSH1 0x6e\n72 JUMPI\n', 'truncLabel': '63 DUP1\n64 PUSH4 0xe166a663\n69 EQ\n70 PUSH1 0x6e\n72 JUMPI\n', 'isExpanded': false},
{id: '13', color: {border: '#000000', background: '#ffffff', highlight: {border: '#000000', background: '#ffffff'}}, size: 150, 'label': '110 assertion1(uint256)\n111 CALLVALUE\n112 ISZERO\n113 PUSH1 0x78\n115 JUMPI\n', 'fullLabel': '110 assertion1(uint256)\n111 CALLVALUE\n112 ISZERO\n113 PUSH1 0x78\n115 JUMPI\n', 'truncLabel': '110 assertion1(uint256)\n111 CALLVALUE\n112 ISZERO\n113 PUSH1 0x78\n115 JUMPI\n', 'isExpanded': false},
{id: '14', color: {border: '#000000', background: '#ffffff', highlight: {border: '#000000', background: '#ffffff'}}, size: 150, 'label': '120 JUMPDEST\n121 PUSH1 0x8c\n123 PUSH1 0x04\n125 DUP1\n126 DUP1\n127 CALLDATALOAD\n(click to expand +)', 'fullLabel': '120 JUMPDEST\n121 PUSH1 0x8c\n123 PUSH1 0x04\n125 DUP1\n126 DUP1\n127 CALLDATALOAD\n128 SWAP1\n129 PUSH1 0x20\n131 ADD\n132 SWAP1\n133 SWAP2\n134 SWAP1\n135 POP\n136 POP\n137 PUSH1 0xaf\n139 JUMP\n', 'truncLabel': '120 JUMPDEST\n121 PUSH1 0x8c\n123 PUSH1 0x04\n125 DUP1\n126 DUP1\n127 CALLDATALOAD\n(click to expand +)', 'isExpanded': false},
{id: '15', color: {border: '#000000', background: '#ffffff', highlight: {border: '#000000', background: '#ffffff'}}, size: 150, 'label': '175 JUMPDEST\n176 PUSH2 0x0400\n179 PUSH1 0x04\n181 DUP3\n182 MUL\n183 LT\n(click to expand +)', 'fullLabel': '175 JUMPDEST\n176 PUSH2 0x0400\n179 PUSH1 0x04\n181 DUP3\n182 MUL\n183 LT\n184 ISZERO\n185 ISZERO\n186 PUSH1 0xbe\n188 JUMPI\n', 'truncLabel': '175 JUMPDEST\n176 PUSH2 0x0400\n179 PUSH1 0x04\n181 DUP3\n182 MUL\n183 LT\n(click to expand +)', 'isExpanded': false},
{id: '16', color: {border: '#000000', background: '#ffffff', highlight: {border: '#000000', background: '#ffffff'}}, size: 150, 'label': '190 JUMPDEST\n191 POP\n192 JUMP\n', 'fullLabel': '190 JUMPDEST\n191 POP\n192 JUMP\n', 'truncLabel': '190 JUMPDEST\n191 POP\n192 JUMP\n', 'isExpanded': false},
{id: '17', color: {border: '#000000', background: '#ffffff', highlight: {border: '#000000', background: '#ffffff'}}, size: 150, 'label': '140 JUMPDEST\n141 STOP\n', 'fullLabel': '140 JUMPDEST\n141 STOP\n', 'truncLabel': '140 JUMPDEST\n141 STOP\n', 'isExpanded': false},
{id: '18', color: {border: '#000000', background: '#ffffff', highlight: {border: '#000000', background: '#ffffff'}}, size: 150, 'label': '189 ASSERT_FAIL\n', 'fullLabel': '189 ASSERT_FAIL\n', 'truncLabel': '189 ASSERT_FAIL\n', 'isExpanded': false},
{id: '19', color: {border: '#000000', background: '#ffffff', highlight: {border: '#000000', background: '#ffffff'}}, size: 150, 'label': '116 PUSH1 0x00\n118 DUP1\n119 REVERT\n', 'fullLabel': '116 PUSH1 0x00\n118 DUP1\n119 REVERT\n', 'truncLabel': '116 PUSH1 0x00\n118 DUP1\n119 REVERT\n', 'isExpanded': false},
{id: '20', color: {border: '#000000', background: '#ffffff', highlight: {border: '#000000', background: '#ffffff'}}, size: 150, 'label': '73 JUMPDEST\n74 PUSH1 0x00\n76 DUP1\n77 REVERT\n', 'fullLabel': '73 JUMPDEST\n74 PUSH1 0x00\n76 DUP1\n77 REVERT\n', 'truncLabel': '73 JUMPDEST\n74 PUSH1 0x00\n76 DUP1\n77 REVERT\n', 'isExpanded': false}
];
var edges = [
{from: '0', to: '1', 'arrows': 'to', 'label': 'Not(ULE(4, calldatasize_Assertions))', 'smooth': {'type': 'cubicBezier'}},
{from: '7', to: '8', 'arrows': 'to', 'label': '', 'smooth': {'type': 'cubicBezier'}},
{from: '6', to: '7', 'arrows': 'to', 'label': 'And(Extract(0xff, 11, 4*calldata_Assertions_4) == 0, ULE(4*Extract(10, 0, calldata_Assertions_4), 0x400))', 'smooth': {'type': 'cubicBezier'}},
{from: '6', to: '9', 'arrows': 'to', 'label': 'Not(And(Extract(0xff, 11, 4*calldata_Assertions_4) == 0, ULE(4*Extract(10, 0, calldata_Assertions_4), 0x400)))', 'smooth': {'type': 'cubicBezier'}},
{from: '5', to: '6', 'arrows': 'to', 'label': 'And(Extract(0xff, 9, calldata_Assertions_4) == 0, ULE(Extract(8, 0, calldata_Assertions_4), 0x100))', 'smooth': {'type': 'cubicBezier'}},
{from: '5', to: '10', 'arrows': 'to', 'label': 'Not(And(Extract(0xff, 9, calldata_Assertions_4) == 0, ULE(Extract(8, 0, calldata_Assertions_4), 0x100)))', 'smooth': {'type': 'cubicBezier'}},
{from: '4', to: '5', 'arrows': 'to', 'label': '', 'smooth': {'type': 'cubicBezier'}},
{from: '3', to: '4', 'arrows': 'to', 'label': 'callvalue == 0', 'smooth': {'type': 'cubicBezier'}},
{from: '3', to: '11', 'arrows': 'to', 'label': 'Not(callvalue == 0)', 'smooth': {'type': 'cubicBezier'}},
{from: '2', to: '3', 'arrows': 'to', 'label': 'Extract(0xff, 0xe0, calldata_Assertions_0) == 0x59ce2f44', 'smooth': {'type': 'cubicBezier'}},
{from: '16', to: '17', 'arrows': 'to', 'label': '', 'smooth': {'type': 'cubicBezier'}},
{from: '15', to: '16', 'arrows': 'to', 'label': 'Not(ULE(0x400, 4*calldata_Assertions_4))', 'smooth': {'type': 'cubicBezier'}},
{from: '15', to: '18', 'arrows': 'to', 'label': 'ULE(0x400, 4*calldata_Assertions_4)', 'smooth': {'type': 'cubicBezier'}},
{from: '14', to: '15', 'arrows': 'to', 'label': '', 'smooth': {'type': 'cubicBezier'}},
{from: '13', to: '14', 'arrows': 'to', 'label': 'callvalue == 0', 'smooth': {'type': 'cubicBezier'}},
{from: '13', to: '19', 'arrows': 'to', 'label': 'Not(callvalue == 0)', 'smooth': {'type': 'cubicBezier'}},
{from: '12', to: '13', 'arrows': 'to', 'label': 'Extract(0xff, 0xe0, calldata_Assertions_0) == 0xe166a663', 'smooth': {'type': 'cubicBezier'}},
{from: '12', to: '20', 'arrows': 'to', 'label': 'Not(Extract(0xff, 0xe0, calldata_Assertions_0) == 0xe166a663)', 'smooth': {'type': 'cubicBezier'}},
{from: '2', to: '12', 'arrows': 'to', 'label': 'Not(Extract(0xff, 0xe0, calldata_Assertions_0) == 0x59ce2f44)', 'smooth': {'type': 'cubicBezier'}},
{from: '0', to: '2', 'arrows': 'to', 'label': 'ULE(4, calldatasize_Assertions)', 'smooth': {'type': 'cubicBezier'}}
];
</script>
</head>
<body>
<p>Mythril / LASER Symbolic VM</p>
<p><div id="mynetwork"></div><br/></p>
<script type="text/javascript">
var container = document.getElementById('mynetwork');
var nodesSet = new vis.DataSet(nodes);
var edgesSet = new vis.DataSet(edges);
var data = {'nodes': nodesSet, 'edges': edgesSet}
var gph = new vis.Network(container, data, options);
gph.on("click", function (params) {
// parse node id
var nodeID = params['nodes']['0'];
if (nodeID) {
var clickedNode = nodesSet.get(nodeID);
if(clickedNode.isExpanded) {
clickedNode.label = clickedNode.truncLabel;
}
else {
clickedNode.label = clickedNode.fullLabel;
}
clickedNode.isExpanded = !clickedNode.isExpanded;
nodesSet.update(clickedNode);
}
});
</script>
</body>
</html>
Loading…
Cancel
Save