From 217e9c01ea89e9fa140fdd81dba659fc3d1d8cb8 Mon Sep 17 00:00:00 2001 From: Dominik Muhs Date: Tue, 9 Oct 2018 21:19:21 +0200 Subject: [PATCH 01/16] Remove unused variable --- mythril/laser/ethereum/call.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mythril/laser/ethereum/call.py b/mythril/laser/ethereum/call.py index 31e6990e..4afdf49d 100644 --- a/mythril/laser/ethereum/call.py +++ b/mythril/laser/ethereum/call.py @@ -98,7 +98,7 @@ def get_callee_account(global_state, callee_address, dynamic_loader): try: code = dynamic_loader.dynld(environment.active_account.address, callee_address) - except Exception as e: + except Exception: logging.info("Unable to execute dynamic loader.") raise ValueError() if code is None: From 6e86c183b2741cf3b481d37ae19881eb6aa2ef03 Mon Sep 17 00:00:00 2001 From: Dominik Muhs Date: Tue, 9 Oct 2018 21:19:31 +0200 Subject: [PATCH 02/16] Reformat evm from tabs to spaces --- mythril/ether/evm.py | 81 ++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/mythril/ether/evm.py b/mythril/ether/evm.py index 449fcdcf..4cf03752 100644 --- a/mythril/ether/evm.py +++ b/mythril/ether/evm.py @@ -7,69 +7,68 @@ from io import StringIO import re -def trace(code, calldata = ""): +def trace(code, calldata=""): + log_handlers = ['eth.vm.op', 'eth.vm.op.stack', 'eth.vm.op.memory', 'eth.vm.op.storage'] - log_handlers = ['eth.vm.op', 'eth.vm.op.stack', 'eth.vm.op.memory', 'eth.vm.op.storage'] + output = StringIO() + stream_handler = StreamHandler(output) - output = StringIO() - stream_handler = StreamHandler(output) + for handler in log_handlers: + log_vm_op = get_logger(handler) + log_vm_op.setLevel("TRACE") + log_vm_op.addHandler(stream_handler) - for handler in log_handlers: - log_vm_op = get_logger(handler) - log_vm_op.setLevel("TRACE") - log_vm_op.addHandler(stream_handler) + addr = bytes.fromhex('0123456789ABCDEF0123456789ABCDEF01234567') - addr = bytes.fromhex('0123456789ABCDEF0123456789ABCDEF01234567') + state = State() - state = State() + ext = messages.VMExt(state, transactions.Transaction(0, 0, 21000, addr, 0, addr)) - ext = messages.VMExt(state, transactions.Transaction(0, 0, 21000, addr, 0, addr)) + message = vm.Message(addr, addr, 0, 21000, calldata) - message = vm.Message(addr, addr, 0, 21000, calldata) + res, gas, dat = vm.vm_execute(ext, message, util.safe_decode(code)) - res, gas, dat = vm.vm_execute(ext, message, util.safe_decode(code)) + stream_handler.flush() - stream_handler.flush() + ret = output.getvalue() - ret = output.getvalue() + lines = ret.split("\n") - lines = ret.split("\n") + trace = [] - trace = [] + for line in lines: - for line in lines: + m = re.search(r'pc=b\'(\d+)\'.*op=([A-Z0-9]+)', line) - m = re.search(r'pc=b\'(\d+)\'.*op=([A-Z0-9]+)', line) + if m: + pc = m.group(1) + op = m.group(2) - if m: - pc = m.group(1) - op = m.group(2) + m = re.match(r'.*stack=(\[.*?\])', line) - m = re.match(r'.*stack=(\[.*?\])', line) - - if (m): + if (m): - stackitems = re.findall(r'b\'(\d+)\'', m.group(1)) + stackitems = re.findall(r'b\'(\d+)\'', m.group(1)) - stack = "["; + stack = "["; - if (len(stackitems)): + if (len(stackitems)): - for i in range(0, len(stackitems) - 1): - stack += hex(int(stackitems[i])) + ", " + for i in range(0, len(stackitems) - 1): + stack += hex(int(stackitems[i])) + ", " - stack += hex(int(stackitems[-1])) + stack += hex(int(stackitems[-1])) - stack += "]" + stack += "]" - else: - stack = "[]" + else: + stack = "[]" - if (re.match(r'^PUSH.*', op)): - val = re.search(r'pushvalue=(\d+)', line).group(1) - pushvalue = hex(int(val)) - trace.append({'pc': pc, 'op': op, 'stack': stack, 'pushvalue': pushvalue}) - else: - trace.append({'pc': pc, 'op': op, 'stack': stack}) + if (re.match(r'^PUSH.*', op)): + val = re.search(r'pushvalue=(\d+)', line).group(1) + pushvalue = hex(int(val)) + trace.append({'pc': pc, 'op': op, 'stack': stack, 'pushvalue': pushvalue}) + else: + trace.append({'pc': pc, 'op': op, 'stack': stack}) - return trace + return trace From 527dd0b1d8221245f74d5c826b69938efca531c9 Mon Sep 17 00:00:00 2001 From: Dominik Muhs Date: Tue, 9 Oct 2018 21:20:00 +0200 Subject: [PATCH 03/16] Remove evm unused variables --- mythril/ether/evm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mythril/ether/evm.py b/mythril/ether/evm.py index 4cf03752..4a099a1f 100644 --- a/mythril/ether/evm.py +++ b/mythril/ether/evm.py @@ -26,7 +26,7 @@ def trace(code, calldata=""): message = vm.Message(addr, addr, 0, 21000, calldata) - res, gas, dat = vm.vm_execute(ext, message, util.safe_decode(code)) + vm.vm_execute(ext, message, util.safe_decode(code)) stream_handler.flush() From 12f8460628f7e1c1ed05df0b21d858082737d0c0 Mon Sep 17 00:00:00 2001 From: Dominik Muhs Date: Tue, 9 Oct 2018 21:21:02 +0200 Subject: [PATCH 04/16] Remove evm redundant parentheses --- mythril/ether/evm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mythril/ether/evm.py b/mythril/ether/evm.py index 4a099a1f..2cc40e97 100644 --- a/mythril/ether/evm.py +++ b/mythril/ether/evm.py @@ -52,7 +52,7 @@ def trace(code, calldata=""): stack = "["; - if (len(stackitems)): + if len(stackitems): for i in range(0, len(stackitems) - 1): stack += hex(int(stackitems[i])) + ", " @@ -64,7 +64,7 @@ def trace(code, calldata=""): else: stack = "[]" - if (re.match(r'^PUSH.*', op)): + if re.match(r'^PUSH.*', op): val = re.search(r'pushvalue=(\d+)', line).group(1) pushvalue = hex(int(val)) trace.append({'pc': pc, 'op': op, 'stack': stack, 'pushvalue': pushvalue}) From 355d5edd87a5f03cc282f63d15315d2ae26aa35d Mon Sep 17 00:00:00 2001 From: Dominik Muhs Date: Tue, 9 Oct 2018 21:22:14 +0200 Subject: [PATCH 05/16] Fix line spacing in evm --- mythril/ether/evm.py | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/mythril/ether/evm.py b/mythril/ether/evm.py index 2cc40e97..576223d5 100644 --- a/mythril/ether/evm.py +++ b/mythril/ether/evm.py @@ -9,7 +9,6 @@ import re def trace(code, calldata=""): log_handlers = ['eth.vm.op', 'eth.vm.op.stack', 'eth.vm.op.memory', 'eth.vm.op.storage'] - output = StringIO() stream_handler = StreamHandler(output) @@ -19,48 +18,33 @@ def trace(code, calldata=""): log_vm_op.addHandler(stream_handler) addr = bytes.fromhex('0123456789ABCDEF0123456789ABCDEF01234567') - state = State() ext = messages.VMExt(state, transactions.Transaction(0, 0, 21000, addr, 0, addr)) - message = vm.Message(addr, addr, 0, 21000, calldata) - vm.vm_execute(ext, message, util.safe_decode(code)) - stream_handler.flush() - ret = output.getvalue() - lines = ret.split("\n") trace = [] - for line in lines: - m = re.search(r'pc=b\'(\d+)\'.*op=([A-Z0-9]+)', line) - if m: pc = m.group(1) op = m.group(2) - m = re.match(r'.*stack=(\[.*?\])', line) - if (m): - + if m: stackitems = re.findall(r'b\'(\d+)\'', m.group(1)) - stack = "["; if len(stackitems): - for i in range(0, len(stackitems) - 1): stack += hex(int(stackitems[i])) + ", " - stack += hex(int(stackitems[-1])) stack += "]" - else: stack = "[]" From 3d4484811a570bbdac0803de9c98b068c72c353f Mon Sep 17 00:00:00 2001 From: Dominik Muhs Date: Tue, 9 Oct 2018 21:26:03 +0200 Subject: [PATCH 06/16] Remove unused variables in instructions --- mythril/laser/ethereum/instructions.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mythril/laser/ethereum/instructions.py b/mythril/laser/ethereum/instructions.py index a7c19959..ff253f3f 100644 --- a/mythril/laser/ethereum/instructions.py +++ b/mythril/laser/ethereum/instructions.py @@ -503,7 +503,6 @@ class Instruction: global keccak_function_manager state = global_state.mstate - environment = global_state.environment op0, op1 = state.stack.pop(), state.stack.pop() try: @@ -711,7 +710,6 @@ class Instruction: _bytes = util.concrete_int_to_bytes(value) i = 0 - for b in _bytes: state.memory[mstart + i] = _bytes[i] i += 1 @@ -956,7 +954,7 @@ class Instruction: state = global_state.mstate dpth = int(self.op_code[3:]) state.stack.pop(), state.stack.pop() - [state.stack.pop() for x in range(dpth)] + [state.stack.pop() for _ in range(dpth)] # Not supported return [global_state] From 4dfff5fb2b917ba6a5d85061d2625340a9e980df Mon Sep 17 00:00:00 2001 From: Dominik Muhs Date: Tue, 9 Oct 2018 21:26:58 +0200 Subject: [PATCH 07/16] Refactor loop to use enumerate --- mythril/laser/ethereum/instructions.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mythril/laser/ethereum/instructions.py b/mythril/laser/ethereum/instructions.py index ff253f3f..34cd76c7 100644 --- a/mythril/laser/ethereum/instructions.py +++ b/mythril/laser/ethereum/instructions.py @@ -709,10 +709,8 @@ class Instruction: # Attempt to concretize value _bytes = util.concrete_int_to_bytes(value) - i = 0 - for b in _bytes: - state.memory[mstart + i] = _bytes[i] - i += 1 + for i, b in enumerate(_bytes): + state.memory[mstart + i] = b except: try: state.memory[mstart] = value From 9a90a92297540a2b7240c666fb84408ebf0821e5 Mon Sep 17 00:00:00 2001 From: Dominik Muhs Date: Tue, 9 Oct 2018 21:28:46 +0200 Subject: [PATCH 08/16] Remove unused variables from tests --- tests/analysis/test_delegatecall.py | 2 +- tests/laser/state/mstack_test.py | 2 +- tests/laser/transaction/symbolic_test.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/analysis/test_delegatecall.py b/tests/analysis/test_delegatecall.py index 3fb02020..9e88c1fd 100644 --- a/tests/analysis/test_delegatecall.py +++ b/tests/analysis/test_delegatecall.py @@ -189,7 +189,7 @@ def test_delegate_call(sym_mock, concrete_mock, curr_instruction): statespace.calls = [call] # act - issues = execute(statespace) + execute(statespace) # assert assert concrete_mock.call_count == 1 diff --git a/tests/laser/state/mstack_test.py b/tests/laser/state/mstack_test.py index 7ccd51c1..6dba7031 100644 --- a/tests/laser/state/mstack_test.py +++ b/tests/laser/state/mstack_test.py @@ -45,7 +45,7 @@ class MachineStackTest(BaseTestCase): mstack = MachineStack([0, 1]) with pytest.raises(NotImplementedError): - mstack = mstack + [2] + mstack + [2] @staticmethod def test_mstack_no_support_iadd(): diff --git a/tests/laser/transaction/symbolic_test.py b/tests/laser/transaction/symbolic_test.py index 6c27b327..91ee00f5 100644 --- a/tests/laser/transaction/symbolic_test.py +++ b/tests/laser/transaction/symbolic_test.py @@ -49,7 +49,7 @@ def test_execute_contract_creation(mocked_setup: MagicMock): mocked_setup.side_effect = _is_contract_creation # Act - new_account = execute_contract_creation(laser_evm, "606000") + execute_contract_creation(laser_evm, "606000") # Assert # mocked_setup.assert_called() From a85918a6f700970642447303aec9a41d26a80ca2 Mon Sep 17 00:00:00 2001 From: Dominik Muhs Date: Tue, 9 Oct 2018 21:35:11 +0200 Subject: [PATCH 09/16] Remove unused variables from mythril --- mythril/mythril.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/mythril/mythril.py b/mythril/mythril.py index 080493fd..221d136d 100644 --- a/mythril/mythril.py +++ b/mythril/mythril.py @@ -87,7 +87,7 @@ class Mythril(object): self.sigs = signatures.SignatureDb() try: self.sigs.open() # tries mythril_dir/signatures.json by default (provide path= arg to make this configurable) - except FileNotFoundError as fnfe: + except FileNotFoundError: logging.info( "No signature database found. Creating database if sigs are loaded in: " + self.sigs.signatures_file + "\n" + "Consider replacing it with the pre-initialized database at https://raw.githubusercontent.com/ConsenSys/mythril/master/signatures.json") @@ -259,8 +259,7 @@ class Mythril(object): def search_db(self, search): - def search_callback(contract, address, balance): - + def search_callback(_, address, balance): print("Address: " + address + ", balance: " + str(balance)) try: @@ -288,10 +287,10 @@ class Mythril(object): code = self.eth.eth_getCode(address) except FileNotFoundError as e: raise CriticalError("IPC error: " + str(e)) - except ConnectionError as e: + except ConnectionError: raise CriticalError("Could not connect to RPC server. Make sure that your node is running and that RPC parameters are set correctly.") except Exception as e: - raise CriticalError("IPC / RPC error: " + str(e)) + raise CriticalError("IPC / RPC error: " + str(e)) else: if code == "0x" or code == "0x0": raise CriticalError("Received an empty response from eth_getCode. Check the contract address and verify that you are on the correct chain.") @@ -431,7 +430,7 @@ class Mythril(object): outtxt.append("{}: {}".format(hex(i), self.eth.eth_getStorageAt(address, i))) except FileNotFoundError as e: raise CriticalError("IPC error: " + str(e)) - except ConnectionError as e: + except ConnectionError: raise CriticalError("Could not connect to RPC server. Make sure that your node is running and that RPC parameters are set correctly.") return '\n'.join(outtxt) From 1428343a3d91af7694d2ebe0e1cd84047a573b69 Mon Sep 17 00:00:00 2001 From: Dominik Muhs Date: Tue, 9 Oct 2018 21:37:22 +0200 Subject: [PATCH 10/16] Remove even more unused variables --- mythril/analysis/symbolic.py | 1 - mythril/laser/ethereum/state.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/mythril/analysis/symbolic.py b/mythril/analysis/symbolic.py index 09447a67..bc2373a7 100644 --- a/mythril/analysis/symbolic.py +++ b/mythril/analysis/symbolic.py @@ -16,7 +16,6 @@ class SymExecWrapper: def __init__(self, contract, address, strategy, dynloader=None, max_depth=22, execution_timeout=None, create_timeout=None): - s_strategy = None if strategy == 'dfs': s_strategy = DepthFirstSearchStrategy elif strategy == 'bfs': diff --git a/mythril/laser/ethereum/state.py b/mythril/laser/ethereum/state.py index 16c01c3a..fd35c86c 100644 --- a/mythril/laser/ethereum/state.py +++ b/mythril/laser/ethereum/state.py @@ -278,10 +278,10 @@ class GlobalState: def new_bitvec(self, name, size=256): transaction_id = self.current_transaction.id - node_id = self.node.uid return BitVec("{}_{}".format(transaction_id, name), size) + class WorldState: """ The WorldState class represents the world state as described in the yellow paper From 2547f43f8ab3bab211bf2515ae8be578f3a04539 Mon Sep 17 00:00:00 2001 From: Dominik Muhs Date: Tue, 9 Oct 2018 21:39:11 +0200 Subject: [PATCH 11/16] Remove unreachable code --- mythril/leveldb/accountindexing.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mythril/leveldb/accountindexing.py b/mythril/leveldb/accountindexing.py index 26a4ab9a..5eca5547 100644 --- a/mythril/leveldb/accountindexing.py +++ b/mythril/leveldb/accountindexing.py @@ -71,8 +71,6 @@ class AccountIndexer(object): else: raise AddressNotFoundError - return self.db.reader._get_address_by_hash(contract_hash) - def _process(self, startblock): ''' Processesing method @@ -154,4 +152,4 @@ class AccountIndexer(object): self.db.writer._set_last_indexed_number(self.lastProcessedBlock) print("Finished indexing") - self.lastBlock = self.lastProcessedBlock \ No newline at end of file + self.lastBlock = self.lastProcessedBlock From 2e56cef99a8bcfb78b1a915b63be03266ff3c0ad Mon Sep 17 00:00:00 2001 From: Dominik Muhs Date: Tue, 9 Oct 2018 21:52:18 +0200 Subject: [PATCH 12/16] Fix outer scope variable shadowing --- .../modules/dependence_on_predictable_vars.py | 4 +-- mythril/analysis/modules/ether_send.py | 4 +-- mythril/analysis/modules/multiple_sends.py | 2 +- mythril/analysis/traceexplore.py | 10 +++---- mythril/ether/evm.py | 8 +++--- mythril/leveldb/accountindexing.py | 8 +++--- mythril/leveldb/state.py | 28 +++++++++---------- tests/taint_runner_test.py | 21 +++++++------- 8 files changed, 42 insertions(+), 43 deletions(-) diff --git a/mythril/analysis/modules/dependence_on_predictable_vars.py b/mythril/analysis/modules/dependence_on_predictable_vars.py index 56cc3156..1e1085ab 100644 --- a/mythril/analysis/modules/dependence_on_predictable_vars.py +++ b/mythril/analysis/modules/dependence_on_predictable_vars.py @@ -120,8 +120,8 @@ def solve(call): model = solver.get_model(call.node.constraints) logging.debug("[DEPENDENCE_ON_PREDICTABLE_VARS] MODEL: " + str(model)) - for d in model.decls(): - logging.debug("[DEPENDENCE_ON_PREDICTABLE_VARS] main model: %s = 0x%x" % (d.name(), model[d].as_long())) + for decl in model.decls(): + logging.debug("[DEPENDENCE_ON_PREDICTABLE_VARS] main model: %s = 0x%x" % (decl.name(), model[decl].as_long())) return True except UnsatError: diff --git a/mythril/analysis/modules/ether_send.py b/mythril/analysis/modules/ether_send.py index bfb0d057..00aac6a5 100644 --- a/mythril/analysis/modules/ether_send.py +++ b/mythril/analysis/modules/ether_send.py @@ -111,8 +111,8 @@ def execute(statespace): try: model = solver.get_model(node.constraints) - for d in model.decls(): - logging.debug("[ETHER_SEND] main model: %s = 0x%x" % (d.name(), model[d].as_long())) + for decl in model.decls(): + logging.debug("[ETHER_SEND] main model: %s = 0x%x" % (decl.name(), model[decl].as_long())) debug = "SOLVER OUTPUT:\n" + solver.pretty_print_model(model) diff --git a/mythril/analysis/modules/multiple_sends.py b/mythril/analysis/modules/multiple_sends.py index 0df17575..5b36f86d 100644 --- a/mythril/analysis/modules/multiple_sends.py +++ b/mythril/analysis/modules/multiple_sends.py @@ -38,7 +38,7 @@ def execute(statespace): def _explore_nodes(call, statespace): children = _child_nodes(statespace, call.node) - sending_children = list(filter(lambda call: call.node in children, statespace.calls)) + sending_children = list(filter(lambda c: c.node in children, statespace.calls)) return sending_children diff --git a/mythril/analysis/traceexplore.py b/mythril/analysis/traceexplore.py index dc7af177..d70fdcbd 100644 --- a/mythril/analysis/traceexplore.py +++ b/mythril/analysis/traceexplore.py @@ -13,8 +13,8 @@ colors = [ {'border': '#4753bf', 'background': '#3b46a1', 'highlight': {'border': '#fff', 'background': '#424db3'}}, ] + def get_serializable_statespace(statespace): - nodes = [] edges = [] @@ -40,10 +40,10 @@ def get_serializable_statespace(statespace): color = color_map[node.get_cfg_dict()['contract_name']] - def get_state_accounts(state): + def get_state_accounts(node_state): state_accounts = [] - for key in state.accounts: - account = state.accounts[key].as_dict + for key in node_state.accounts: + account = node_state.accounts[key].as_dict account.pop('code', None) account['balance'] = str(account['balance']) @@ -81,7 +81,7 @@ def get_serializable_statespace(statespace): for edge in statespace.edges: - if (edge.condition is None): + if edge.condition is None: label = "" else: diff --git a/mythril/ether/evm.py b/mythril/ether/evm.py index 576223d5..545e30ff 100644 --- a/mythril/ether/evm.py +++ b/mythril/ether/evm.py @@ -27,7 +27,7 @@ def trace(code, calldata=""): ret = output.getvalue() lines = ret.split("\n") - trace = [] + state_trace = [] for line in lines: m = re.search(r'pc=b\'(\d+)\'.*op=([A-Z0-9]+)', line) if m: @@ -51,8 +51,8 @@ def trace(code, calldata=""): if re.match(r'^PUSH.*', op): val = re.search(r'pushvalue=(\d+)', line).group(1) pushvalue = hex(int(val)) - trace.append({'pc': pc, 'op': op, 'stack': stack, 'pushvalue': pushvalue}) + state_trace.append({'pc': pc, 'op': op, 'stack': stack, 'pushvalue': pushvalue}) else: - trace.append({'pc': pc, 'op': op, 'stack': stack}) + state_trace.append({'pc': pc, 'op': op, 'stack': stack}) - return trace + return state_trace diff --git a/mythril/leveldb/accountindexing.py b/mythril/leveldb/accountindexing.py index 5eca5547..dacc2f0a 100644 --- a/mythril/leveldb/accountindexing.py +++ b/mythril/leveldb/accountindexing.py @@ -63,11 +63,11 @@ class AccountIndexer(object): def get_contract_by_hash(self, contract_hash): ''' - get mapped address by its hash, if not found try indexing + get mapped contract_address by its hash, if not found try indexing ''' - address = self.db.reader._get_address_by_hash(contract_hash) - if address is not None: - return address + contract_address = self.db.reader._get_address_by_hash(contract_hash) + if contract_address is not None: + return contract_address else: raise AddressNotFoundError diff --git a/mythril/leveldb/state.py b/mythril/leveldb/state.py index 96360300..c6a24119 100644 --- a/mythril/leveldb/state.py +++ b/mythril/leveldb/state.py @@ -43,9 +43,9 @@ class Account(rlp.Serializable): ('code_hash', hash32) ] - def __init__(self, nonce, balance, storage, code_hash, db, address): + def __init__(self, nonce, balance, storage, code_hash, db, addr): self.db = db - self.address = address + self.address = addr super(Account, self).__init__(nonce, balance, storage, code_hash) self.storage_cache = {} self.storage_trie = SecureTrie(Trie(self.db)) @@ -73,12 +73,12 @@ class Account(rlp.Serializable): return self.storage_cache[key] @classmethod - def blank_account(cls, db, address, initial_nonce=0): + def blank_account(cls, db, addr, initial_nonce=0): ''' creates a blank account ''' db.put(BLANK_HASH, b'') - o = cls(initial_nonce, 0, trie.BLANK_ROOT, BLANK_HASH, db, address) + o = cls(initial_nonce, 0, trie.BLANK_ROOT, BLANK_HASH, db, addr) o.existent_at_start = False return o @@ -100,21 +100,21 @@ class State(): self.journal = [] self.cache = {} - def get_and_cache_account(self, address): + def get_and_cache_account(self, addr): ''' gets and caches an account for an addres, creates blank if not found ''' - if address in self.cache: - return self.cache[address] - rlpdata = self.secure_trie.get(address) - if rlpdata == trie.BLANK_NODE and len(address) == 32: # support for hashed addresses - rlpdata = self.trie.get(address) + if addr in self.cache: + return self.cache[addr] + rlpdata = self.secure_trie.get(addr) + if rlpdata == trie.BLANK_NODE and len(addr) == 32: # support for hashed addresses + rlpdata = self.trie.get(addr) if rlpdata != trie.BLANK_NODE: - o = rlp.decode(rlpdata, Account, db=self.db, address=address) + o = rlp.decode(rlpdata, Account, db=self.db, address=addr) else: o = Account.blank_account( - self.db, address, 0) - self.cache[address] = o + self.db, addr, 0) + self.cache[addr] = o o._mutable = True o._cached_rlp = None return o @@ -125,4 +125,4 @@ class State(): ''' for address_hash, rlpdata in self.secure_trie.trie.iter_branch(): if rlpdata != trie.BLANK_NODE: - yield rlp.decode(rlpdata, Account, db=self.db, address=address_hash) \ No newline at end of file + yield rlp.decode(rlpdata, Account, db=self.db, address=address_hash) diff --git a/tests/taint_runner_test.py b/tests/taint_runner_test.py index 17ef00eb..9b533f3b 100644 --- a/tests/taint_runner_test.py +++ b/tests/taint_runner_test.py @@ -6,13 +6,14 @@ from mythril.laser.ethereum.cfg import Node, Edge from mythril.laser.ethereum.state import MachineState, Account, Environment, GlobalState from mythril.laser.ethereum.svm import LaserEVM -def test_execute_state(mocker): + +def test_execute_state(state_mocker): record = TaintRecord() record.stack = [True, False, True] state = GlobalState(None, None, None) state.mstate.stack = [1, 2, 3] - mocker.patch.object(state, 'get_current_instruction') + state_mocker.patch.object(state, 'get_current_instruction') state.get_current_instruction.return_value = {"opcode": "ADD"} # Act @@ -23,19 +24,19 @@ def test_execute_state(mocker): assert record.stack == [True, False, True] -def test_execute_node(mocker): +def test_execute_node(node_mocker): record = TaintRecord() record.stack = [True, True, False, False] state_1 = GlobalState(None, None, None) state_1.mstate.stack = [1, 2, 3, 1] state_1.mstate.pc = 1 - mocker.patch.object(state_1, 'get_current_instruction') + node_mocker.patch.object(state_1, 'get_current_instruction') state_1.get_current_instruction.return_value = {"opcode": "SWAP1"} state_2 = GlobalState(None, 1, None) state_2.mstate.stack = [1, 2, 4, 1] - mocker.patch.object(state_2, 'get_current_instruction') + node_mocker.patch.object(state_2, 'get_current_instruction') state_2.get_current_instruction.return_value = {"opcode": "ADD"} node = Node("Test contract") @@ -54,19 +55,17 @@ def test_execute_node(mocker): assert state_1 in record.states - - -def test_execute(mocker): +def test_execute(state_mocker): active_account = Account('0x00') environment = Environment(active_account, None, None, None, None, None) state_1 = GlobalState(None, environment, None, MachineState(gas=10000000)) state_1.mstate.stack = [1, 2] - mocker.patch.object(state_1, 'get_current_instruction') + state_mocker.patch.object(state_1, 'get_current_instruction') state_1.get_current_instruction.return_value = {"opcode": "PUSH"} state_2 = GlobalState(None, environment, None, MachineState(gas=10000000)) state_2.mstate.stack = [1, 2, 3] - mocker.patch.object(state_2, 'get_current_instruction') + state_mocker.patch.object(state_2, 'get_current_instruction') state_2.get_current_instruction.return_value = {"opcode": "ADD"} node_1 = Node("Test contract") @@ -74,7 +73,7 @@ def test_execute(mocker): state_3 = GlobalState(None, environment, None, MachineState(gas=10000000)) state_3.mstate.stack = [1, 2] - mocker.patch.object(state_3, 'get_current_instruction') + state_mocker.patch.object(state_3, 'get_current_instruction') state_3.get_current_instruction.return_value = {"opcode": "ADD"} node_2 = Node("Test contract") From 0142e6e41b2c9abe6b4ea2d1a6528c00669e129e Mon Sep 17 00:00:00 2001 From: Dominik Muhs Date: Tue, 9 Oct 2018 22:11:41 +0200 Subject: [PATCH 13/16] Fix builtin name shadowing --- mythril/interfaces/cli.py | 4 ++-- mythril/leveldb/accountindexing.py | 6 ++--- mythril/leveldb/client.py | 38 +++++++++++++++--------------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/mythril/interfaces/cli.py b/mythril/interfaces/cli.py index be6cec59..e10b4e98 100644 --- a/mythril/interfaces/cli.py +++ b/mythril/interfaces/cli.py @@ -17,8 +17,8 @@ from mythril.mythril import Mythril from mythril.version import VERSION -def exit_with_error(format, message): - if format == 'text' or format == 'markdown': +def exit_with_error(fmt, message): + if fmt == 'text' or fmt == 'markdown': print(message) else: result = {'success': False, 'error': str(message), 'issues': []} diff --git a/mythril/leveldb/accountindexing.py b/mythril/leveldb/accountindexing.py index dacc2f0a..f61ebe80 100644 --- a/mythril/leveldb/accountindexing.py +++ b/mythril/leveldb/accountindexing.py @@ -80,9 +80,9 @@ class AccountIndexer(object): addresses = [] for blockNum in range(startblock, startblock + BATCH_SIZE): - hash = self.db.reader._get_block_hash(blockNum) - if hash is not None: - receipts = self.db.reader._get_block_receipts(hash, blockNum) + block_hash = self.db.reader._get_block_hash(blockNum) + if block_hash is not None: + receipts = self.db.reader._get_block_receipts(block_hash, blockNum) for receipt in receipts: if receipt.contractAddress is not None and not all(b == 0 for b in receipt.contractAddress): diff --git a/mythril/leveldb/client.py b/mythril/leveldb/client.py index b192b004..7d0bb0df 100644 --- a/mythril/leveldb/client.py +++ b/mythril/leveldb/client.py @@ -79,38 +79,38 @@ class LevelDBReader(object): gets head block header ''' if not self.head_block_header: - hash = self.db.get(head_header_key) - num = self._get_block_number(hash) - self.head_block_header = self._get_block_header(hash, num) + block_hash = self.db.get(head_header_key) + num = self._get_block_number(block_hash) + self.head_block_header = self._get_block_header(block_hash, num) # find header with valid state while not self.db.get(self.head_block_header.state_root) and self.head_block_header.prevhash is not None: - hash = self.head_block_header.prevhash - num = self._get_block_number(hash) - self.head_block_header = self._get_block_header(hash, num) + block_hash = self.head_block_header.prevhash + num = self._get_block_number(block_hash) + self.head_block_header = self._get_block_header(block_hash, num) return self.head_block_header - def _get_block_number(self, hash): + def _get_block_number(self, block_hash): ''' - gets block number by hash + gets block number by its hash ''' - number_key = block_hash_prefix + hash + number_key = block_hash_prefix + block_hash return self.db.get(number_key) - def _get_block_header(self, hash, num): + def _get_block_header(self, block_hash, num): ''' get block header by block header hash & number ''' - header_key = header_prefix + num + hash + header_key = header_prefix + num + block_hash block_header_data = self.db.get(header_key) header = rlp.decode(block_header_data, sedes=BlockHeader) return header - def _get_address_by_hash(self, hash): + def _get_address_by_hash(self, block_hash): ''' get mapped address by its hash ''' - address_key = address_prefix + hash + address_key = address_prefix + block_hash return self.db.get(address_key) def _get_last_indexed_number(self): @@ -119,12 +119,12 @@ class LevelDBReader(object): ''' return self.db.get(address_mapping_head_key) - def _get_block_receipts(self, hash, num): + def _get_block_receipts(self, block_hash, num): ''' get block transaction receipts by block header hash & number ''' number = _format_block_number(num) - receipts_key = block_receipts_prefix + number + hash + receipts_key = block_receipts_prefix + number + block_hash receipts_data = self.db.get(receipts_key) receipts = rlp.decode(receipts_data, sedes=CountableList(ReceiptForStorage)) return receipts @@ -216,12 +216,12 @@ class EthLevelDB(object): if not cnt % 1000: logging.info("Searched %d contracts" % cnt) - def contract_hash_to_address(self, hash): + def contract_hash_to_address(self, contract_hash): ''' tries to find corresponding account address ''' - address_hash = binascii.a2b_hex(utils.remove_0x_head(hash)) + address_hash = binascii.a2b_hex(utils.remove_0x_head(contract_hash)) indexer = AccountIndexer(self) return _encode_hex(indexer.get_contract_by_hash(address_hash)) @@ -230,9 +230,9 @@ class EthLevelDB(object): ''' gets block header by block number ''' - hash = self.reader._get_block_hash(number) + block_hash = self.reader._get_block_hash(number) block_number = _format_block_number(number) - return self.reader._get_block_header(hash, block_number) + return self.reader._get_block_header(block_hash, block_number) def eth_getBlockByNumber(self, number): ''' From 128a6f76e2bd51b1868dad7dd4ca283f03de14e0 Mon Sep 17 00:00:00 2001 From: Dominik Muhs Date: Tue, 9 Oct 2018 22:26:48 +0200 Subject: [PATCH 14/16] Revert taint test refactoring to fix pytest fixtures --- tests/taint_runner_test.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/taint_runner_test.py b/tests/taint_runner_test.py index 9b533f3b..e8dd3078 100644 --- a/tests/taint_runner_test.py +++ b/tests/taint_runner_test.py @@ -7,13 +7,13 @@ from mythril.laser.ethereum.state import MachineState, Account, Environment, Glo from mythril.laser.ethereum.svm import LaserEVM -def test_execute_state(state_mocker): +def test_execute_state(mocker): record = TaintRecord() record.stack = [True, False, True] state = GlobalState(None, None, None) state.mstate.stack = [1, 2, 3] - state_mocker.patch.object(state, 'get_current_instruction') + mocker.patch.object(state, 'get_current_instruction') state.get_current_instruction.return_value = {"opcode": "ADD"} # Act @@ -24,19 +24,19 @@ def test_execute_state(state_mocker): assert record.stack == [True, False, True] -def test_execute_node(node_mocker): +def test_execute_node(mocker): record = TaintRecord() record.stack = [True, True, False, False] state_1 = GlobalState(None, None, None) state_1.mstate.stack = [1, 2, 3, 1] state_1.mstate.pc = 1 - node_mocker.patch.object(state_1, 'get_current_instruction') + mocker.patch.object(state_1, 'get_current_instruction') state_1.get_current_instruction.return_value = {"opcode": "SWAP1"} state_2 = GlobalState(None, 1, None) state_2.mstate.stack = [1, 2, 4, 1] - node_mocker.patch.object(state_2, 'get_current_instruction') + mocker.patch.object(state_2, 'get_current_instruction') state_2.get_current_instruction.return_value = {"opcode": "ADD"} node = Node("Test contract") @@ -55,17 +55,17 @@ def test_execute_node(node_mocker): assert state_1 in record.states -def test_execute(state_mocker): +def test_execute(mocker): active_account = Account('0x00') environment = Environment(active_account, None, None, None, None, None) state_1 = GlobalState(None, environment, None, MachineState(gas=10000000)) state_1.mstate.stack = [1, 2] - state_mocker.patch.object(state_1, 'get_current_instruction') + mocker.patch.object(state_1, 'get_current_instruction') state_1.get_current_instruction.return_value = {"opcode": "PUSH"} state_2 = GlobalState(None, environment, None, MachineState(gas=10000000)) state_2.mstate.stack = [1, 2, 3] - state_mocker.patch.object(state_2, 'get_current_instruction') + mocker.patch.object(state_2, 'get_current_instruction') state_2.get_current_instruction.return_value = {"opcode": "ADD"} node_1 = Node("Test contract") @@ -73,7 +73,7 @@ def test_execute(state_mocker): state_3 = GlobalState(None, environment, None, MachineState(gas=10000000)) state_3.mstate.stack = [1, 2] - state_mocker.patch.object(state_3, 'get_current_instruction') + mocker.patch.object(state_3, 'get_current_instruction') state_3.get_current_instruction.return_value = {"opcode": "ADD"} node_2 = Node("Test contract") From b53ac587c57e07273e8078e934831fa2080b631f Mon Sep 17 00:00:00 2001 From: Dominik Muhs Date: Thu, 11 Oct 2018 19:27:18 +0200 Subject: [PATCH 15/16] Rename fmt to format_type in cli interface --- mythril/interfaces/cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mythril/interfaces/cli.py b/mythril/interfaces/cli.py index e10b4e98..9bab540a 100644 --- a/mythril/interfaces/cli.py +++ b/mythril/interfaces/cli.py @@ -17,8 +17,8 @@ from mythril.mythril import Mythril from mythril.version import VERSION -def exit_with_error(fmt, message): - if fmt == 'text' or fmt == 'markdown': +def exit_with_error(format_type, message): + if format_type == 'text' or format_type == 'markdown': print(message) else: result = {'success': False, 'error': str(message), 'issues': []} From 8f8bf3e7c11bd9dd579778163a49004f3d6bc619 Mon Sep 17 00:00:00 2001 From: Dominik Muhs Date: Thu, 11 Oct 2018 21:27:43 +0200 Subject: [PATCH 16/16] Rename format var and refactor mstore memory loop --- mythril/interfaces/cli.py | 4 ++-- mythril/laser/ethereum/instructions.py | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/mythril/interfaces/cli.py b/mythril/interfaces/cli.py index 9bab540a..061044fd 100644 --- a/mythril/interfaces/cli.py +++ b/mythril/interfaces/cli.py @@ -17,8 +17,8 @@ from mythril.mythril import Mythril from mythril.version import VERSION -def exit_with_error(format_type, message): - if format_type == 'text' or format_type == 'markdown': +def exit_with_error(format_, message): + if format_ == 'text' or format_ == 'markdown': print(message) else: result = {'success': False, 'error': str(message), 'issues': []} diff --git a/mythril/laser/ethereum/instructions.py b/mythril/laser/ethereum/instructions.py index 34cd76c7..a1dbbe60 100644 --- a/mythril/laser/ethereum/instructions.py +++ b/mythril/laser/ethereum/instructions.py @@ -707,10 +707,8 @@ class Instruction: try: # Attempt to concretize value - _bytes = util.concrete_int_to_bytes(value) - - for i, b in enumerate(_bytes): - state.memory[mstart + i] = b + bytes_ = util.concrete_int_to_bytes(value) + state.memory[mstart: mstart + len(bytes_)] = bytes_ except: try: state.memory[mstart] = value