Add the runtime bytecode to source list

pull/1002/head
Nikhil Parasaram 6 years ago
parent 8254bf1f5c
commit 7af06fe6f9
  1. 9
      mythril/analysis/symbolic.py
  2. 8
      mythril/disassembler/disassembly.py
  3. 21
      mythril/laser/ethereum/state/account.py
  4. 16
      mythril/laser/ethereum/state/world_state.py
  5. 2
      mythril/laser/ethereum/transaction/symbolic.py
  6. 2
      mythril/laser/ethereum/transaction/transaction_models.py
  7. 7
      mythril/support/source_support.py

@ -2,6 +2,7 @@
purposes.""" purposes."""
import copy import copy
from ethereum.utils import mk_contract_address
from mythril.analysis.security import get_detection_module_hooks, get_detection_modules from mythril.analysis.security import get_detection_module_hooks, get_detection_modules
from mythril.laser.ethereum import svm from mythril.laser.ethereum import svm
from mythril.laser.ethereum.state.account import Account from mythril.laser.ethereum.state.account import Account
@ -11,11 +12,12 @@ from mythril.laser.ethereum.strategy.basic import (
ReturnRandomNaivelyStrategy, ReturnRandomNaivelyStrategy,
ReturnWeightedRandomStrategy, ReturnWeightedRandomStrategy,
) )
from mythril.laser.ethereum.transaction.symbolic import CREATOR_ADDRESS
from mythril.laser.ethereum.plugins.plugin_factory import PluginFactory from mythril.laser.ethereum.plugins.plugin_factory import PluginFactory
from mythril.laser.ethereum.plugins.plugin_loader import LaserPluginLoader from mythril.laser.ethereum.plugins.plugin_loader import LaserPluginLoader
from mythril.solidity.soliditycontract import EVMContract, SolidityContract from mythril.solidity.soliditycontract import EVMContract, SolidityContract
from .ops import Call, SStore, VarType, get_variable from .ops import Call, SStore, VarType, get_variable
@ -110,6 +112,11 @@ class SymExecWrapper:
) )
else: else:
self.laser.sym_exec(address) self.laser.sym_exec(address)
created_address = "0x" + str(mk_contract_address(CREATOR_ADDRESS, 0).hex())
for key, value in self.laser.world_state.accounts.items():
if created_address == value.address:
contract.code = value.code.bytecode
break
if not requires_statespace: if not requires_statespace:
return return

@ -28,11 +28,15 @@ class Disassembly(object):
self.func_hashes = [] # type: List[str] self.func_hashes = [] # type: List[str]
self.function_name_to_address = {} # type: Dict[str, int] self.function_name_to_address = {} # type: Dict[str, int]
self.address_to_function_name = {} # type: Dict[int, str] self.address_to_function_name = {} # type: Dict[int, str]
self.enable_online_lookup = enable_online_lookup
self.assign_bytecode(bytecode=code)
def assign_bytecode(self, bytecode):
self.bytecode = bytecode
# open from default locations # open from default locations
# control if you want to have online signature hash lookups # control if you want to have online signature hash lookups
signatures = SignatureDB(enable_online_lookup=enable_online_lookup) signatures = SignatureDB(enable_online_lookup=self.enable_online_lookup)
self.instruction_list = asm.disassemble(util.safe_decode(bytecode))
# Need to take from PUSH1 to PUSH4 because solc seems to remove excess 0s at the beginning for optimizing # Need to take from PUSH1 to PUSH4 because solc seems to remove excess 0s at the beginning for optimizing
jump_table_indices = asm.find_op_code_sequence( jump_table_indices = asm.find_op_code_sequence(
[("PUSH1", "PUSH2", "PUSH3", "PUSH4"), ("EQ",)], self.instruction_list [("PUSH1", "PUSH2", "PUSH3", "PUSH4"), ("EQ",)], self.instruction_list

@ -2,7 +2,7 @@
This includes classes representing accounts and their storage. This includes classes representing accounts and their storage.
""" """
from copy import deepcopy, copy
from typing import Any, Dict, KeysView, Union from typing import Any, Dict, KeysView, Union
from z3 import ExprRef from z3 import ExprRef
@ -61,6 +61,13 @@ class Storage:
""" """
return self._storage.keys() return self._storage.keys()
def __deepcopy__(self, memodict={}):
storage = Storage(
concrete=self.concrete, address=self.address, dynamic_loader=self.dynld
)
storage._storage = copy(self._storage)
return storage
class Account: class Account:
"""Account class representing ethereum accounts.""" """Account class representing ethereum accounts."""
@ -92,7 +99,6 @@ class Account:
self.storage = Storage( self.storage = Storage(
concrete_storage, address=address, dynamic_loader=dynamic_loader concrete_storage, address=address, dynamic_loader=dynamic_loader
) )
# Metadata # Metadata
self.address = address self.address = address
self.contract_name = contract_name self.contract_name = contract_name
@ -128,3 +134,14 @@ class Account:
"balance": self.balance, "balance": self.balance,
"storage": self.storage, "storage": self.storage,
} }
def __deepcopy__(self, memodict={}):
new_account = Account(
address=self.address,
code=self.code,
balance=self.balance,
contract_name=self.contract_name,
)
new_account.storage = deepcopy(self.storage)
new_account.code = self.code
return new_account

@ -2,7 +2,7 @@
from copy import copy from copy import copy
from random import randint from random import randint
from typing import Dict, List, Iterator, Optional, TYPE_CHECKING from typing import Dict, List, Iterator, Optional, TYPE_CHECKING
from ethereum.utils import mk_contract_address
from mythril.laser.ethereum.state.account import Account from mythril.laser.ethereum.state.account import Account
from mythril.laser.ethereum.state.annotation import StateAnnotation from mythril.laser.ethereum.state.annotation import StateAnnotation
@ -50,7 +50,12 @@ class WorldState:
return new_world_state return new_world_state
def create_account( def create_account(
self, balance=0, address=None, concrete_storage=False, dynamic_loader=None self,
balance=0,
address=None,
concrete_storage=False,
dynamic_loader=None,
creator=None,
) -> Account: ) -> Account:
"""Create non-contract account. """Create non-contract account.
@ -60,7 +65,7 @@ class WorldState:
:param dynamic_loader: used for dynamically loading storage from the block chain :param dynamic_loader: used for dynamically loading storage from the block chain
:return: The new account :return: The new account
""" """
address = address if address else self._generate_new_address() address = address if address else self._generate_new_address(creator)
new_account = Account( new_account = Account(
address, address,
balance=balance, balance=balance,
@ -111,11 +116,14 @@ class WorldState:
""" """
return filter(lambda x: isinstance(x, annotation_type), self.annotations) return filter(lambda x: isinstance(x, annotation_type), self.annotations)
def _generate_new_address(self) -> str: def _generate_new_address(self, creator=None) -> str:
"""Generates a new address for the global state. """Generates a new address for the global state.
:return: :return:
""" """
if creator:
# TODO: Use nounce
return "0x" + str(mk_contract_address(creator, 0).hex())
while True: while True:
address = "0x" + "".join([str(hex(randint(0, 16)))[-1] for _ in range(40)]) address = "0x" + "".join([str(hex(randint(0, 16)))[-1] for _ in range(40)])
if address not in self.accounts.keys(): if address not in self.accounts.keys():

@ -73,7 +73,7 @@ def execute_contract_creation(
del laser_evm.open_states[:] del laser_evm.open_states[:]
new_account = laser_evm.world_state.create_account( new_account = laser_evm.world_state.create_account(
0, concrete_storage=True, dynamic_loader=None 0, concrete_storage=True, dynamic_loader=None, creator=CREATOR_ADDRESS
) )
if contract_name: if contract_name:
new_account.contract_name = contract_name new_account.contract_name = contract_name

@ -188,7 +188,7 @@ class ContractCreationTransaction(BaseTransaction):
contract_code = bytes.hex(array.array("B", return_data).tostring()) contract_code = bytes.hex(array.array("B", return_data).tostring())
global_state.environment.active_account.code = Disassembly(contract_code) global_state.environment.active_account.code.assign_bytecode(contract_code)
self.return_data = global_state.environment.active_account.address self.return_data = global_state.environment.active_account.address
assert global_state.environment.active_account.code.instruction_list != [] assert global_state.environment.active_account.code.instruction_list != []

@ -55,4 +55,9 @@ class Source:
:param bytecode_hash: The contract hash :param bytecode_hash: The contract hash
:return: The index of the contract in the _source_hash list :return: The index of the contract in the _source_hash list
""" """
return self._source_hash.index(bytecode_hash) # TODO: Add this part to exception logs
try:
return self._source_hash.index(bytecode_hash)
except ValueError:
self._source_hash.append(bytecode_hash)
return len(self._source_hash) - 1

Loading…
Cancel
Save