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
[![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"/>
@ -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.
## 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
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
"""
from json.decoder import JSONDecodeError
import logging
import json
import sys
@ -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()
@ -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."
}
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()

@ -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 hashlib
import persistent
import persistent.list
import transaction
from BTrees.OOBTree import BTree
@ -9,7 +8,8 @@ from ZODB import FileStorage
from multiprocessing import Pool
import logging
from mythril.ether.ethcontract import ETHContract, InstanceList
from mythril import ether
import time
BLOCKS_PER_THREAD = 256
NUM_THREADS = 8
@ -127,7 +127,9 @@ class ContractStorage(persistent.Persistent):
processed += NUM_THREADS * BLOCKS_PER_THREAD
self.last_block = blockNum
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
self.last_block = 0

@ -3,6 +3,7 @@ import socket
import logging
from mythril.rpc.base_client import BaseClient
from .utils import (get_default_ipc_path, to_text, to_bytes)
import threading
try:
from json import JSONDecodeError
@ -18,42 +19,55 @@ This code is mostly adapted from:
- 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):
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:
ipc_path = get_default_ipc_path(testnet)
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):
_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
_socket.connect(self.ipc_path)
# Tell the socket not to block on reads.
_socket.settimeout(self.socket_timeout)
_socket.settimeout(2)
return _socket
def send(self, request):
_socket = None
try:
_socket = self.get_socket()
_socket.sendall(request)
response_raw = ""
@staticmethod
def send_request(request):
THREAD_LOCAL.socket.sendall(request)
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:
response_raw += to_text(_socket.recv(4096))
except socket.timeout:
break
if response_raw == "":
return None
else:
return response_raw
finally:
if _socket:
_socket.close()
return json.loads(trimmed)
except JSONDecodeError:
continue
def _call(self, method, params=None, _id=1):
params = params or []
@ -66,16 +80,18 @@ class EthIpc(BaseClient):
logging.debug("ipc send: %s" % json.dumps(data))
request = to_bytes(json.dumps(data))
self.connect_if_not_yet()
for _ in range(3):
response_raw = self.send(request)
if response_raw is not None:
try:
self.send_request(request)
response = self.read_response()
break
except socket.timeout or OSError:
self.reconnect()
else:
raise ValueError("No JSON returned by socket")
logging.debug("ipc response: %s" % response_raw)
response = json.loads(response_raw)
if "error" in response:
raise ValueError(response["error"]["message"])

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

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