added online lookup for signature hashes via 4bytes.directory

pull/308/head
tintinweb 7 years ago
parent fb77530574
commit 83c5eca66b
  1. 26
      mythril/disassembler/disassembly.py
  2. 67
      mythril/support/signatures.py

@ -1,6 +1,5 @@
from mythril.ether import asm,util
import os
import json
from mythril.support.signatures import Signatures
import logging
@ -13,21 +12,11 @@ class Disassembly:
self.addr_to_func = {}
self.bytecode = code
signatures = Signatures(enable_online_lookkup=True) # control if you want to have online sighash lookups
try:
mythril_dir = os.environ['MYTHRIL_DIR']
except KeyError:
mythril_dir = os.path.join(os.path.expanduser('~'), ".mythril")
# Load function signatures
signatures_file = os.path.join(mythril_dir, 'signatures.json')
if not os.path.exists(signatures_file):
logging.info("Missing function signature file. Resolving of function names disabled.")
signatures = {}
else:
with open(signatures_file) as f:
signatures = json.load(f)
signatures.open() # open from default locations
except FileNotFoundError:
logging.info("Missing function signature file. Resolving of function names from disabled.")
# Parse jump table & resolve function names
@ -36,7 +25,7 @@ class Disassembly:
for i in jmptable_indices:
func_hash = self.instruction_list[i]['argument']
try:
func_name = signatures[func_hash]
func_name = signatures.get(func_hash) # tries local cache, file and optional online lookup
except KeyError:
func_name = "_function_" + func_hash
@ -49,8 +38,5 @@ class Disassembly:
except:
continue
def get_easm(self):
return asm.instruction_list_to_easm(self.instruction_list)

@ -1,7 +1,17 @@
import re
import os
import logging
import json
from ethereum import utils
try:
# load if available but do not fail
import ethereum_input_decoder
except ImportError:
ethereum_input_decoder = None
# TODO: tintinweb: move this and signature functionality from mythril.py to class Signatures to have one single interface.
def add_signatures_from_file(file, sigs={}):
funcs = []
@ -42,3 +52,60 @@ def add_signatures_from_file(file, sigs={}):
signature = re.sub(r'\s', '', signature)
sigs["0x" + utils.sha3(signature)[:4].hex()] = signature
class Signatures(object):
def __init__(self, enable_online_lookkup=True):
self.signatures = {} # signatures in-mem cache
self.enable_online_lookup =enable_online_lookkup # enable online funcsig resolving
def open(self, path=None):
if not path:
# try default locations
try:
mythril_dir = os.environ['MYTHRIL_DIR']
except KeyError:
mythril_dir = os.path.join(os.path.expanduser('~'), ".mythril")
path = os.path.join(mythril_dir, 'signatures.json')
if not os.path.exists(path):
raise FileNotFoundError("Missing function signature file. Resolving of function names disabled.")
with open(path) as f:
sigs = json.load(f)
# normalize it to {sighash:list(signatures,...)}
for sighash,funcsig in sigs.items():
self.signatures.setdefault(sighash, [])
self.signatures[sighash].append(funcsig)
return self
def get(self, sighash):
"""
get a function signature for a sighash
1) try local cache
2) try online lookup
:param sighash:
:return: list of function signatures
"""
if not self.signatures.get(sighash) and self.enable_online_lookup:
self.signatures[sighash] = Signatures.lookup_online(sighash) # might return multiple sigs
return self.signatures.get(sighash)
@staticmethod
def lookup_online(sighash):
"""
Lookup function signatures from 4bytes.directory.
//tintinweb: the smart-contract-sanctuary project dumps contracts from etherscan.io and feeds them into
4bytes.directory.
https://github.com/tintinweb/smart-contract-sanctuary
:param s: function signature as hexstr
:return: a list of possible function signatures for this hash
"""
if not ethereum_input_decoder:
return None
return list(ethereum_input_decoder.decoder.FourByteDirectory.lookup_signatures(sighash))

Loading…
Cancel
Save