Use arguments from constructor in MythrilAnalyzer and fix typos

pull/906/head
Nikhil Parasaram 6 years ago
parent 231e3ae8fc
commit 636f7defaf
  1. 34
      mythril/interfaces/cli.py
  2. 95
      mythril/mythril/mythril_analyzer.py
  3. 20
      mythril/mythril/mythril_disassembler.py
  4. 8
      tests/graph_test.py
  5. 4
      tests/mythril/mythril_analyzer_test.py

@ -350,15 +350,15 @@ def parse_args(parser: argparse.ArgumentParser, args: argparse.Namespace) -> Non
) )
if args.search or args.contract_hash_to_address: if args.search or args.contract_hash_to_address:
leveldb_sercher = MythrilLevelDB(config.eth_db) leveldb_searcher = MythrilLevelDB(config.eth_db)
if args.search: if args.search:
# Database search ops # Database search ops
leveldb_sercher.search_db(args.search) leveldb_searcher.search_db(args.search)
else: else:
# search corresponding address # search corresponding address
try: try:
leveldb_sercher.contract_hash_to_address( leveldb_searcher.contract_hash_to_address(
args.contract_hash_to_address args.contract_hash_to_address
) )
except AddressNotFoundError: except AddressNotFoundError:
@ -413,7 +413,13 @@ def parse_args(parser: argparse.ArgumentParser, args: argparse.Namespace) -> Non
) )
analyzer = MythrilAnalyzer( analyzer = MythrilAnalyzer(
strategy=args.strategy,
disassembler=dissasembler, disassembler=dissasembler,
address=address,
max_depth=args.max_depth,
execution_timeout=args.execution_timeout,
create_timeout=args.create_timeout,
enable_iprof=args.enable_iprof,
onchain_storage_access=not args.no_onchain_storage_access, onchain_storage_access=not args.no_onchain_storage_access,
) )
# Commands # Commands
@ -447,15 +453,9 @@ def parse_args(parser: argparse.ArgumentParser, args: argparse.Namespace) -> Non
if args.graph: if args.graph:
html = analyzer.graph_html( html = analyzer.graph_html(
strategy=args.strategy,
contract=analyzer.contracts[0], contract=analyzer.contracts[0],
address=address,
enable_physics=args.enable_physics, enable_physics=args.enable_physics,
phrackify=args.phrack, phrackify=args.phrack,
max_depth=args.max_depth,
execution_timeout=args.execution_timeout,
create_timeout=args.create_timeout,
enable_iprof=args.enable_iprof,
) )
try: try:
@ -467,17 +467,11 @@ def parse_args(parser: argparse.ArgumentParser, args: argparse.Namespace) -> Non
else: else:
try: try:
report = analyzer.fire_lasers( report = analyzer.fire_lasers(
strategy=args.strategy,
address=address,
modules=[m.strip() for m in args.modules.strip().split(",")] modules=[m.strip() for m in args.modules.strip().split(",")]
if args.modules if args.modules
else [], else [],
verbose_report=args.verbose_report, verbose_report=args.verbose_report,
max_depth=args.max_depth,
execution_timeout=args.execution_timeout,
create_timeout=args.create_timeout,
transaction_count=args.transaction_count, transaction_count=args.transaction_count,
enable_iprof=args.enable_iprof,
) )
outputs = { outputs = {
"json": report.as_json(), "json": report.as_json(),
@ -498,15 +492,7 @@ def parse_args(parser: argparse.ArgumentParser, args: argparse.Namespace) -> Non
args.outform, "input files do not contain any valid contracts" args.outform, "input files do not contain any valid contracts"
) )
statespace = analyzer.dump_statespace( statespace = analyzer.dump_statespace(contract=analyzer.contracts[0])
strategy=args.strategy,
contract=analyzer.contracts[0],
address=address,
max_depth=args.max_depth,
execution_timeout=args.execution_timeout,
create_timeout=args.create_timeout,
enable_iprof=args.enable_iprof,
)
try: try:
with open(args.statespace_json, "w") as f: with open(args.statespace_json, "w") as f:

@ -29,6 +29,12 @@ class MythrilAnalyzer:
disassembler: MythrilDisassembler, disassembler: MythrilDisassembler,
requires_dynld: bool = False, requires_dynld: bool = False,
onchain_storage_access: bool = True, onchain_storage_access: bool = True,
strategy: str = "dfs",
address: Optional[str] = None,
max_depth: Optional[int] = None,
execution_timeout: Optional[int] = None,
create_timeout: Optional[int] = None,
enable_iprof: bool = False,
): ):
""" """
@ -41,134 +47,99 @@ class MythrilAnalyzer:
self.enable_online_lookup = disassembler.enable_online_lookup self.enable_online_lookup = disassembler.enable_online_lookup
self.dynld = requires_dynld self.dynld = requires_dynld
self.onchain_storage_access = onchain_storage_access self.onchain_storage_access = onchain_storage_access
self.strategy = strategy
def dump_statespace( self.address = address
self, self.max_depth = max_depth
strategy: str, self.execution_timeout = execution_timeout
contract: EVMContract = None, self.create_timeout = create_timeout
address: Optional[str] = None, self.enable_iprof = enable_iprof
max_depth: Optional[int] = None,
execution_timeout: Optional[int] = None, def dump_statespace(self, contract: EVMContract = None) -> str:
create_timeout: Optional[int] = None,
enable_iprof: bool = False,
) -> str:
""" """
Returns serializable statespace of the contract Returns serializable statespace of the contract
:param strategy: The search strategy to go through the CFG
:param contract: The Contract on which the analysis should be done :param contract: The Contract on which the analysis should be done
:param address: The Contract address
:param max_depth: The max depth till which the CFG should be constructed
:param execution_timeout: The total execution timeout of the contract
:param create_timeout: The total contract creation timeout
:param enable_iprof: Enables/disables instruction profiler
:return: The serialized state space :return: The serialized state space
""" """
sym = SymExecWrapper( sym = SymExecWrapper(
contract or self.contracts[0], contract or self.contracts[0],
address, self.address,
strategy, self.strategy,
dynloader=DynLoader( dynloader=DynLoader(
self.eth, self.eth,
storage_loading=self.onchain_storage_access, storage_loading=self.onchain_storage_access,
contract_loading=self.dynld, contract_loading=self.dynld,
), ),
max_depth=max_depth, max_depth=self.max_depth,
execution_timeout=execution_timeout, execution_timeout=self.execution_timeout,
create_timeout=create_timeout, create_timeout=self.create_timeout,
enable_iprof=enable_iprof, enable_iprof=self.enable_iprof,
) )
return get_serializable_statespace(sym) return get_serializable_statespace(sym)
def graph_html( def graph_html(
self, self,
strategy: str,
address: str,
contract: EVMContract = None, contract: EVMContract = None,
max_depth: Optional[int] = None,
enable_physics: bool = False, enable_physics: bool = False,
phrackify: bool = False, phrackify: bool = False,
execution_timeout: Optional[int] = None,
create_timeout: Optional[int] = None,
transaction_count: Optional[int] = None, transaction_count: Optional[int] = None,
enable_iprof: bool = False,
) -> str: ) -> str:
""" """
:param strategy: The search strategy to go through the CFG
:param contract: The Contract on which the analysis should be done :param contract: The Contract on which the analysis should be done
:param address: The Contract address
:param max_depth: The max depth till which the CFG should be constructed
:param enable_physics: If true then enables the graph physics simulation :param enable_physics: If true then enables the graph physics simulation
:param phrackify: If true generates Phrack-style call graph :param phrackify: If true generates Phrack-style call graph
:param execution_timeout: The total execution timeout of the contract
:param create_timeout: The total contract creation timeout
:param transaction_count: The amount of transactions to be executed :param transaction_count: The amount of transactions to be executed
:param enable_iprof: Enables/disables instruction profiler
:return: The generated graph in html format :return: The generated graph in html format
""" """
sym = SymExecWrapper( sym = SymExecWrapper(
contract or self.contracts[0], contract or self.contracts[0],
address, self.address,
strategy, self.strategy,
dynloader=DynLoader( dynloader=DynLoader(
self.eth, self.eth,
storage_loading=self.onchain_storage_access, storage_loading=self.onchain_storage_access,
contract_loading=self.dynld, contract_loading=self.dynld,
), ),
max_depth=max_depth, max_depth=self.max_depth,
execution_timeout=execution_timeout, execution_timeout=self.execution_timeout,
transaction_count=transaction_count, transaction_count=transaction_count,
create_timeout=create_timeout, create_timeout=self.create_timeout,
enable_iprof=enable_iprof, enable_iprof=self.enable_iprof,
) )
return generate_graph(sym, physics=enable_physics, phrackify=phrackify) return generate_graph(sym, physics=enable_physics, phrackify=phrackify)
def fire_lasers( def fire_lasers(
self, self,
strategy: str,
contracts: Optional[List[EVMContract]] = None,
address: Optional[str] = None,
modules: Optional[List[str]] = None, modules: Optional[List[str]] = None,
verbose_report: bool = False, verbose_report: bool = False,
max_depth: Optional[int] = None,
execution_timeout: Optional[int] = None,
create_timeout: Optional[int] = None,
transaction_count: Optional[int] = None, transaction_count: Optional[int] = None,
enable_iprof: bool = False,
) -> Report: ) -> Report:
""" """
:param strategy: The search strategy to go through the CFG
:param contracts: The Contracts list on which the analysis should be done
:param address: The Contract address
:param modules: The analysis modules which should be executed :param modules: The analysis modules which should be executed
:param verbose_report: Gives out the transaction sequence of the vulnerability :param verbose_report: Gives out the transaction sequence of the vulnerability
:param max_depth: The max depth till which the CFG should be constructed
:param execution_timeout: The total execution timeout of the contract
:param create_timeout: The total contract creation timeout
:param transaction_count: The amount of transactions to be executed :param transaction_count: The amount of transactions to be executed
:param enable_iprof: Enables/disables instruction profiler
:return: The Report class which contains the all the issues/vulnerabilities :return: The Report class which contains the all the issues/vulnerabilities
""" """
all_issues = [] # type: List[Issue] all_issues = [] # type: List[Issue]
for contract in contracts or self.contracts: for contract in self.contracts:
try: try:
sym = SymExecWrapper( sym = SymExecWrapper(
contract, contract,
address, self.address,
strategy, self.strategy,
dynloader=DynLoader( dynloader=DynLoader(
self.eth, self.eth,
storage_loading=self.onchain_storage_access, storage_loading=self.onchain_storage_access,
contract_loading=self.dynld, contract_loading=self.dynld,
), ),
max_depth=max_depth, max_depth=self.max_depth,
execution_timeout=execution_timeout, execution_timeout=self.execution_timeout,
create_timeout=create_timeout, create_timeout=self.create_timeout,
transaction_count=transaction_count, transaction_count=transaction_count,
modules=modules, modules=modules,
compulsory_statespace=False, compulsory_statespace=False,
enable_iprof=enable_iprof, enable_iprof=self.enable_iprof,
) )
issues = fire_lasers(sym, modules) issues = fire_lasers(sym, modules)
except KeyboardInterrupt: except KeyboardInterrupt:

@ -122,19 +122,17 @@ class MythrilDisassembler:
) )
except Exception as e: except Exception as e:
raise CriticalError("IPC / RPC error: " + str(e)) raise CriticalError("IPC / RPC error: " + str(e))
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."
)
else: else:
if code == "0x" or code == "0x0": self.contracts.append(
raise CriticalError( EVMContract(
"Received an empty response from eth_getCode. Check the contract address and verify that you are on the correct chain." code, name=address, enable_online_lookup=self.enable_online_lookup
)
else:
self.contracts.append(
EVMContract(
code,
name=address,
enable_online_lookup=self.enable_online_lookup,
)
) )
)
return address, self.contracts[-1] # return address and contract object return address, self.contracts[-1] # return address and contract object
def load_from_solidity( def load_from_solidity(

@ -24,15 +24,15 @@ class GraphTest(BaseTestCase):
contract = EVMContract(input_file.read_text()) contract = EVMContract(input_file.read_text())
disassembler = MythrilDisassembler() disassembler = MythrilDisassembler()
disassembler.contracts.append(contract) disassembler.contracts.append(contract)
analyzer = MythrilAnalyzer(disassembler) analyzer = MythrilAnalyzer(
disassembler=disassembler,
html = analyzer.graph_html(
strategy="dfs", strategy="dfs",
transaction_count=1,
execution_timeout=5, execution_timeout=5,
max_depth=30, max_depth=30,
address=(util.get_indexed_address(0)), address=(util.get_indexed_address(0)),
) )
html = analyzer.graph_html(transaction_count=1)
output_current.write_text(html) output_current.write_text(html)
lines_expected = re.findall( lines_expected = re.findall(

@ -21,9 +21,9 @@ def test_fire_lasers(mock_sym, mock_fire_lasers, mock_code_info):
) )
] ]
) )
analyzer = MythrilAnalyzer(disassembler) analyzer = MythrilAnalyzer(disassembler, strategy="dfs")
issues = analyzer.fire_lasers(strategy="dfs", modules=[]).sorted_issues() issues = analyzer.fire_lasers(modules=[]).sorted_issues()
mock_sym.assert_called() mock_sym.assert_called()
mock_fire_lasers.assert_called() mock_fire_lasers.assert_called()
mock_code_info.assert_called() mock_code_info.assert_called()

Loading…
Cancel
Save