From 2ce971cf317188865c7eed18e95681f1b3b94f9d Mon Sep 17 00:00:00 2001 From: Bernhard Mueller Date: Tue, 13 Aug 2019 20:03:30 +0200 Subject: [PATCH] Exempt constructor and fallback function --- mythril/analysis/symbolic.py | 9 ++++++ mythril/interfaces/cli.py | 28 ++++++++++++++++++- .../implementations/function_selector.py | 14 +++++----- mythril/mythril/mythril_analyzer.py | 10 +++++++ 4 files changed, 53 insertions(+), 8 deletions(-) diff --git a/mythril/analysis/symbolic.py b/mythril/analysis/symbolic.py index 02b5c8ca..358287ec 100644 --- a/mythril/analysis/symbolic.py +++ b/mythril/analysis/symbolic.py @@ -56,6 +56,8 @@ class SymExecWrapper: disable_dependency_pruning=False, run_analysis_modules=True, enable_coverage_strategy=False, + func_whitelist=[], + func_blacklist=[], custom_modules_directory="", ): """ @@ -130,6 +132,13 @@ class SymExecWrapper: if not disable_dependency_pruning: plugin_loader.load(PluginFactory.build_dependency_pruner_plugin()) + if len(func_whitelist) or len(func_blacklist): + plugin_loader.load( + PluginFactory.build_function_selector_plugin( + func_whitelist, func_blacklist + ) + ) + world_state = WorldState() for account in self.accounts.values(): world_state.put_account(account) diff --git a/mythril/interfaces/cli.py b/mythril/interfaces/cli.py index 2cbf3f4c..579a179d 100644 --- a/mythril/interfaces/cli.py +++ b/mythril/interfaces/cli.py @@ -368,7 +368,20 @@ def create_analyzer_parser(analyzer_parser: ArgumentParser): action="store_true", help="turns off getting the data from onchain contracts (both loading storage and contract code)", ) - + options.add_argument( + "-w", + "--func-whitelist", + type=str, + help="Execute only functions with these signatures (comma-separated list)", + metavar="FUNCTION_SIGS", + ) + options.add_argument( + "-n", + "--func-blacklist", + type=str, + help="Don't execute functions with these signatures (comma-separated list)", + metavar="FUNCTION_SIGS", + ) options.add_argument( "--phrack", action="store_true", help="Phrack-style call graph" ) @@ -556,6 +569,17 @@ def execute_command( print("Disassembly: \n" + disassembler.contracts[0].get_creation_easm()) elif args.command in ANALYZE_LIST: + + if args.func_whitelist: + _whitelist = args.func_whitelist.split(",") + else: + _whitelist = [] + + if args.func_blacklist: + _blacklist = args.func_blacklist.split(",") + else: + _blacklist = [] + analyzer = MythrilAnalyzer( strategy=args.strategy, disassembler=disassembler, @@ -573,6 +597,8 @@ def execute_command( custom_modules_directory=args.custom_modules_directory if args.custom_modules_directory else "", + func_whitelist=_whitelist, + func_blacklist=_blacklist, ) if not disassembler.contracts: diff --git a/mythril/laser/ethereum/plugins/implementations/function_selector.py b/mythril/laser/ethereum/plugins/implementations/function_selector.py index dae48ed0..a6a7d0d2 100644 --- a/mythril/laser/ethereum/plugins/implementations/function_selector.py +++ b/mythril/laser/ethereum/plugins/implementations/function_selector.py @@ -32,13 +32,13 @@ class FunctionSelector(LaserPlugin): :return: """ - @symbolic_vm.laser_hook("execute_state") - def world_state_filter_hook(global_state: GlobalState): - if ( - len(self.whitelist) - and global_state.node.function_name not in self.whitelist - ): + @symbolic_vm.post_hook("JUMPI") + def jumpi_hook(state: GlobalState): + if state.node.function_name in ["constructor", "fallback"]: + return + + if len(self.whitelist) and state.node.function_name not in self.whitelist: raise PluginSkipState - if global_state.node.function_name in self.blacklist: + if state.node.function_name in self.blacklist: raise PluginSkipState diff --git a/mythril/mythril/mythril_analyzer.py b/mythril/mythril/mythril_analyzer.py index d5e87369..5fb87844 100644 --- a/mythril/mythril/mythril_analyzer.py +++ b/mythril/mythril/mythril_analyzer.py @@ -41,6 +41,8 @@ class MythrilAnalyzer: enable_iprof: bool = False, disable_dependency_pruning: bool = False, solver_timeout: Optional[int] = None, + func_whitelist: Optional[List] = [], + func_blacklist: Optional[List] = [], enable_coverage_strategy: bool = False, custom_modules_directory: str = "", ): @@ -65,6 +67,8 @@ class MythrilAnalyzer: self.disable_dependency_pruning = disable_dependency_pruning self.enable_coverage_strategy = enable_coverage_strategy self.custom_modules_directory = custom_modules_directory + self.func_whitelist = func_whitelist + self.func_blacklist = func_blacklist analysis_args.set_loop_bound(loop_bound) analysis_args.set_solver_timeout(solver_timeout) @@ -92,6 +96,8 @@ class MythrilAnalyzer: run_analysis_modules=False, enable_coverage_strategy=self.enable_coverage_strategy, custom_modules_directory=self.custom_modules_directory, + func_whitelist=self.func_whitelist, + func_blacklist=self.func_blacklist, ) return get_serializable_statespace(sym) @@ -129,6 +135,8 @@ class MythrilAnalyzer: run_analysis_modules=False, enable_coverage_strategy=self.enable_coverage_strategy, custom_modules_directory=self.custom_modules_directory, + func_whitelist=self.func_whitelist, + func_blacklist=self.func_blacklist, ) return generate_graph(sym, physics=enable_physics, phrackify=phrackify) @@ -168,6 +176,8 @@ class MythrilAnalyzer: disable_dependency_pruning=self.disable_dependency_pruning, enable_coverage_strategy=self.enable_coverage_strategy, custom_modules_directory=self.custom_modules_directory, + func_whitelist=self.func_whitelist, + func_blacklist=self.func_blacklist, ) issues = fire_lasers(sym, modules, self.custom_modules_directory) except KeyboardInterrupt: