def output(self, filename): """ Output the inheritance relation _filename is not used Args: _filename(string) """ info = 'Inheritance\n' if not self.contracts: return info += blue('Child_Contract -> ') + green('Base_Contracts') for child in self.contracts: info += blue(f'\n+ {child.name}') if child.inheritance: info += ' -> ' + green(", ".join(map(str, child.inheritance))) info += green('\n\nBase_Contract -> ') + blue('Child_Contracts') for base in self.contracts: info += green(f'\n+ {base.name}') children = list(self._get_child_contracts(base)) if children: info += ' -> ' + blue(", ".join(map(str, children))) self.info(info)
def output(self, filename): """ Output the inheritance relation _filename is not used Args: _filename(string) """ info = "Inheritance\n" info += blue("Child_Contract -> ") + green("Immediate_Base_Contracts") info += green(" [Not_Immediate_Base_Contracts]") result = {"child_to_base": {}} for child in self.contracts: if child.is_top_level: continue info += blue(f"\n+ {child.name}\n") result["child_to_base"][child.name] = {"immediate": [], "not_immediate": []} if child.inheritance: immediate = child.immediate_inheritance not_immediate = [i for i in child.inheritance if i not in immediate] info += " -> " + green(", ".join(map(str, immediate))) + "\n" result["child_to_base"][child.name]["immediate"] = list(map(str, immediate)) if not_immediate: info += ", [" + green(", ".join(map(str, not_immediate))) + "]\n" result["child_to_base"][child.name]["not_immediate"] = list( map(str, not_immediate) ) info += green("\n\nBase_Contract -> ") + blue("Immediate_Child_Contracts") + "\n" info += blue(" [Not_Immediate_Child_Contracts]") + "\n" result["base_to_child"] = {} for base in self.contracts: if base.is_top_level: continue info += green(f"\n+ {base.name}") + "\n" children = list(self._get_child_contracts(base)) result["base_to_child"][base.name] = {"immediate": [], "not_immediate": []} if children: immediate = [child for child in children if base in child.immediate_inheritance] not_immediate = [child for child in children if not child in immediate] info += " -> " + blue(", ".join(map(str, immediate))) + "\n" result["base_to_child"][base.name]["immediate"] = list(map(str, immediate)) if not_immediate: info += ", [" + blue(", ".join(map(str, not_immediate))) + "]" + "\n" result["base_to_child"][base.name]["not_immediate"] = list(map(str, immediate)) self.info(info) res = self.generate_output(info, additional_fields=result) return res
def run(filename, mod_name): """Executes script""" # Init Slither slither = Slither(filename) if not len(slither.contracts): print(f"Error: Slither could not find any contracts") exit(-1) print(f"== Functions with {yellow(mod_name)} modifier ==") txt = "" for c in slither.contracts: txt += blue(f"\n+ Contract {c.name}\n") collect = collections.defaultdict(list) for f in filter_by_modifier(c.functions, mod_name): collect[f.contract.name].append((f.full_name, f.visibility)) for contract, function_visi_pairs in collect.items(): txt += blue(f" - From {contract}\n") function_visi_pairs = sorted(function_visi_pairs) for function, visi in function_visi_pairs: if visi in ['external', 'public']: txt += green(f" - {function} ({visi})\n") for function, visi in function_visi_pairs: if visi in ['internal', 'private']: txt += magenta(f" - {function} ({visi})\n") for function, visi in function_visi_pairs: if visi not in ['external', 'public', 'internal', 'private']: txt += f" - {function} ({visi})\n" print(txt)
def output(self, _filename): """ _filename is not used Args: _filename(string) """ txt = "" for c in self.contracts: (name, _inheritance, _var, func_summaries, _modif_summaries) = c.get_summary() txt += blue("\n+ Contract %s\n" % name) # (c_name, f_name, visi, _, _, _, _, _) in func_summaries public = [(elem[0], (elem[1], elem[2])) for elem in func_summaries] collect = collections.defaultdict(list) for a, b in public: collect[a].append(b) public = list(collect.items()) for contract, functions in public: txt += blue(" - From {}\n".format(contract)) functions = sorted(functions) for (function, visi) in functions: if visi in ['external', 'public']: txt += green(" - {} ({})\n".format(function, visi)) for (function, visi) in functions: if visi in ['internal', 'private']: txt += magenta(" - {} ({})\n".format( function, visi)) for (function, visi) in functions: if visi not in [ 'external', 'public', 'internal', 'private' ]: txt += " - {} ({})\n".format(function, visi) self.info(txt)
def run(filename): """Executes script""" # Init Slither slither = Slither(filename) if not len(slither.contracts): print(f"Error: Slither could not find any contracts") exit(-1) text = "" for c in slither.contracts: text += blue(f"\n+ Contract {c.name}\n") collect = collections.defaultdict(list) collect[c.name].append(c.modifiers) text += "\n" + '\n'.join([m.name for m in c.modifiers]) + "\n" print(text)
def output(self, _filename): """ _filename is not used Args: _filename(string) """ txt = "" for c in self.contracts: (name, _inheritance, _var, func_summaries, _modif_summaries) = c.get_summary() txt += blue("\n+ Contract %s\n"%name) for (f_name, visi, _, _, _, _, _) in func_summaries: txt += " - " if visi in ['external', 'public']: txt += green("%s (%s)\n"%(f_name, visi)) elif visi in ['internal', 'private']: txt += magenta("%s (%s)\n"%(f_name, visi)) else: txt += "%s (%s)\n"%(f_name, visi) self.info(txt)
def output(self, filename): """ Output the inheritance relation _filename is not used Args: _filename(string) """ info = 'Inheritance\n' if not self.contracts: return info += blue('Child_Contract -> ') + green('Immediate_Base_Contracts') info += green(' [Not_Immediate_Base_Contracts]') for child in self.contracts: info += blue(f'\n+ {child.name}') if child.inheritance: immediate = child.immediate_inheritance not_immediate = [ i for i in child.inheritance if i not in immediate ] info += ' -> ' + green(", ".join(map(str, immediate))) if not_immediate: info += ", [" + green(", ".join(map(str, not_immediate))) + "]" info += green('\n\nBase_Contract -> ') + blue( 'Immediate_Child_Contracts') info += blue(' [Not_Immediate_Child_Contracts]') for base in self.contracts: info += green(f'\n+ {base.name}') children = list(self._get_child_contracts(base)) if children: immediate = [ child for child in children if base in child.immediate_inheritance ] not_immediate = [ child for child in children if not child in immediate ] info += ' -> ' + blue(", ".join(map(str, immediate))) if not_immediate: info += ', [' + blue(", ".join(map(str, not_immediate))) + ']' self.info(info)
def main_impl(all_detector_classes, all_printer_classes): """ :param all_detector_classes: A list of all detectors that can be included/excluded. :param all_printer_classes: A list of all printers that can be included. """ # Set logger of Slither to info, to catch warnings related to the arg parsing logger.setLevel(logging.INFO) args = parse_args(all_detector_classes, all_printer_classes) # Set colorization option set_colorization_enabled(not args.disable_color) # Define some variables for potential JSON output json_results = {} output_error = None outputting_json = args.json is not None outputting_json_stdout = args.json == '-' outputting_zip = args.zip is not None if args.zip_type not in ZIP_TYPES_ACCEPTED.keys(): logger.error(f'Zip type not accepted, it must be one of {",".join(ZIP_TYPES_ACCEPTED.keys())}') # If we are outputting JSON, capture all standard output. If we are outputting to stdout, we block typical stdout # output. if outputting_json: StandardOutputCapture.enable(outputting_json_stdout) printer_classes = choose_printers(args, all_printer_classes) detector_classes = choose_detectors(args, all_detector_classes) default_log = logging.INFO if not args.debug else logging.DEBUG for (l_name, l_level) in [('Slither', default_log), ('Contract', default_log), ('Function', default_log), ('Node', default_log), ('Parsing', default_log), ('Detectors', default_log), ('FunctionSolc', default_log), ('ExpressionParsing', default_log), ('TypeParsing', default_log), ('SSA_Conversion', default_log), ('Printers', default_log), # ('CryticCompile', default_log) ]: l = logging.getLogger(l_name) l.setLevel(l_level) console_handler = logging.StreamHandler() console_handler.setLevel(logging.INFO) console_handler.setFormatter(FormatterCryticCompile()) crytic_compile_error = logging.getLogger(('CryticCompile')) crytic_compile_error.addHandler(console_handler) crytic_compile_error.propagate = False crytic_compile_error.setLevel(logging.INFO) results_detectors = [] results_printers = [] try: filename = args.filename # Determine if we are handling ast from solc if args.solc_ast or (filename.endswith('.json') and not is_supported(filename)): globbed_filenames = glob.glob(filename, recursive=True) filenames = glob.glob(os.path.join(filename, "*.json")) if not filenames: filenames = globbed_filenames number_contracts = 0 slither_instances = [] if args.splitted: (slither_instance, results_detectors, results_printers, number_contracts) = process_from_asts(filenames, args, detector_classes, printer_classes) slither_instances.append(slither_instance) else: for filename in filenames: (slither_instance, results_detectors_tmp, results_printers_tmp, number_contracts_tmp) = process_single(filename, args, detector_classes, printer_classes) number_contracts += number_contracts_tmp results_detectors += results_detectors_tmp results_printers += results_printers_tmp slither_instances.append(slither_instance) # Rely on CryticCompile to discern the underlying type of compilations. else: (slither_instances, results_detectors, results_printers, number_contracts) = process_all(filename, args, detector_classes, printer_classes) # Determine if we are outputting JSON if outputting_json or outputting_zip: # Add our compilation information to JSON if 'compilations' in args.json_types: compilation_results = [] for slither_instance in slither_instances: compilation_results.append(generate_standard_export(slither_instance.crytic_compile)) json_results['compilations'] = compilation_results # Add our detector results to JSON if desired. if results_detectors and 'detectors' in args.json_types: json_results['detectors'] = results_detectors # Add our printer results to JSON if desired. if results_printers and 'printers' in args.json_types: json_results['printers'] = results_printers # Add our detector types to JSON if 'list-detectors' in args.json_types: detectors, _ = get_detectors_and_printers() json_results['list-detectors'] = output_detectors_json(detectors) # Add our detector types to JSON if 'list-printers' in args.json_types: _, printers = get_detectors_and_printers() json_results['list-printers'] = output_printers_json(printers) # Output our results to markdown if we wish to compile a checklist. if args.checklist: output_results_to_markdown(results_detectors) # Dont print the number of result for printers if number_contracts == 0: logger.warning(red('No contract was analyzed')) if printer_classes: logger.info('%s analyzed (%d contracts)', filename, number_contracts) else: logger.info('%s analyzed (%d contracts with %d detectors), %d result(s) found', filename, number_contracts, len(detector_classes), len(results_detectors)) logger.info(blue('Use https://crytic.io/ to get access to additional detectors and Github integration')) if args.ignore_return_value: return except SlitherException as se: output_error = str(se) traceback.print_exc() logging.error(red('Error:')) logging.error(red(output_error)) logging.error('Please report an issue to https://github.com/crytic/slither/issues') except Exception: output_error = traceback.format_exc() logging.error(traceback.print_exc()) logging.error('Error in %s' % args.filename) logging.error(output_error) # If we are outputting JSON, capture the redirected output and disable the redirect to output the final JSON. if outputting_json: if 'console' in args.json_types: json_results['console'] = { 'stdout': StandardOutputCapture.get_stdout_output(), 'stderr': StandardOutputCapture.get_stderr_output() } StandardOutputCapture.disable() output_to_json(None if outputting_json_stdout else args.json, output_error, json_results) if outputting_zip: output_to_zip(args.zip, output_error, json_results, args.zip_type) # Exit with the appropriate status code if output_error: sys.exit(-1) else: exit(results_detectors)
def output(self, _filename): """ _filename is not used Args: _filename(string) """ txt = "" all_contracts = [] for c in self.contracts: if c.is_top_level: continue is_upgradeable_proxy = c.is_upgradeable_proxy is_upgradeable = c.is_upgradeable additional_txt_info = '' if is_upgradeable_proxy: additional_txt_info += ' (Upgradeable Proxy)' if is_upgradeable: additional_txt_info += ' (Upgradeable)' if c in self.slither.contracts_derived: additional_txt_info += ' (Most derived contract)' txt += blue(f"\n+ Contract {c.name}{additional_txt_info}\n") additional_fields = output.Output( '', additional_fields={ 'is_upgradeable_proxy': is_upgradeable_proxy, 'is_upgradeable': is_upgradeable, 'is_most_derived': c in self.slither.contracts_derived }) # Order the function with # contract_declarer -> list_functions public = [(f.contract_declarer.name, f) for f in c.functions if (not f.is_shadowed and not f.is_constructor_variables) ] collect = collections.defaultdict(list) for a, b in public: collect[a].append(b) public = list(collect.items()) for contract, functions in public: txt += blue(" - From {}\n".format(contract)) functions = sorted(functions, key=lambda f: f.full_name) for function in functions: if function.visibility in ['external', 'public']: txt += green(" - {} ({})\n".format( function.full_name, function.visibility)) if function.visibility in ['internal', 'private']: txt += magenta(" - {} ({})\n".format( function.full_name, function.visibility)) if function.visibility not in [ 'external', 'public', 'internal', 'private' ]: txt += " - {} ({})\n".format( function.full_name, function.visibility) additional_fields.add( function, additional_fields={"visibility": function.visibility}) all_contracts.append((c, additional_fields.data)) self.info(txt) res = self.generate_output(txt) for contract, additional_fields in all_contracts: res.add(contract, additional_fields=additional_fields) return res
def output(self, _filename): # pylint: disable=too-many-locals """ _filename is not used Args: _filename(string) """ txt = "" all_contracts = [] for c in self.contracts: if c.is_top_level: continue is_upgradeable_proxy = c.is_upgradeable_proxy is_upgradeable = c.is_upgradeable additional_txt_info = "" if is_upgradeable_proxy: additional_txt_info += " (Upgradeable Proxy)" if is_upgradeable: additional_txt_info += " (Upgradeable)" if c in self.slither.contracts_derived: additional_txt_info += " (Most derived contract)" txt += blue(f"\n+ Contract {c.name}{additional_txt_info}\n") additional_fields = output.Output( "", additional_fields={ "is_upgradeable_proxy": is_upgradeable_proxy, "is_upgradeable": is_upgradeable, "is_most_derived": c in self.slither.contracts_derived, }, ) # Order the function with # contract_declarer -> list_functions public = [ (f.contract_declarer.name, f) for f in c.functions if (not f.is_shadowed and not f.is_constructor_variables) ] collect = collections.defaultdict(list) for a, b in public: collect[a].append(b) public = list(collect.items()) for contract, functions in public: txt += blue(f" - From {contract}\n") functions = sorted(functions, key=lambda f: f.full_name) for function in functions: if function.visibility in ["external", "public"]: txt += green(f" - {function.full_name} ({function.visibility})\n") if function.visibility in ["internal", "private"]: txt += magenta(f" - {function.full_name} ({function.visibility})\n") if function.visibility not in [ "external", "public", "internal", "private", ]: txt += f" - {function.full_name} ({function.visibility})\n" additional_fields.add( function, additional_fields={"visibility": function.visibility} ) all_contracts.append((c, additional_fields.data)) self.info(txt) res = self.generate_output(txt) for contract, additional_fields in all_contracts: res.add(contract, additional_fields=additional_fields) return res
def output(self, _filename): """ _filename is not used Args: _filename(string) """ txt = "" if not self.slither.crytic_compile: txt = "The EVM printer requires to compile with crytic-compile" self.info(red(txt)) res = self.generate_output(txt) return res evm_info = _extract_evm_info(self.slither) for contract in self.slither.contracts_derived: txt += blue("Contract {}\n".format(contract.name)) contract_file = self.slither.source_code[ contract.source_mapping["filename_absolute"] ].encode("utf-8") contract_file_lines = open( contract.source_mapping["filename_absolute"], "r" ).readlines() contract_pcs = {} contract_cfg = {} for function in contract.functions: txt += blue(f"\tFunction {function.canonical_name}\n") # CFG and source mapping depend on function being constructor or not if function.is_constructor: contract_cfg = evm_info["cfg_init", contract.name] contract_pcs = evm_info["mapping_init", contract.name] else: contract_cfg = evm_info["cfg", contract.name] contract_pcs = evm_info["mapping", contract.name] for node in function.nodes: txt += green("\t\tNode: " + str(node) + "\n") node_source_line = ( contract_file[0 : node.source_mapping["start"]].count("\n".encode("utf-8")) + 1 ) txt += green( "\t\tSource line {}: {}\n".format( node_source_line, contract_file_lines[node_source_line - 1].rstrip(), ) ) txt += magenta("\t\tEVM Instructions:\n") node_pcs = contract_pcs.get(node_source_line, []) for pc in node_pcs: txt += magenta( "\t\t\t0x{:x}: {}\n".format( int(pc), contract_cfg.get_instruction_at(pc) ) ) for modifier in contract.modifiers: txt += blue(f"\tModifier {modifier.canonical_name}\n") for node in modifier.nodes: txt += green("\t\tNode: " + str(node) + "\n") node_source_line = ( contract_file[0 : node.source_mapping["start"]].count("\n".encode("utf-8")) + 1 ) txt += green( "\t\tSource line {}: {}\n".format( node_source_line, contract_file_lines[node_source_line - 1].rstrip(), ) ) txt += magenta("\t\tEVM Instructions:\n") node_pcs = contract_pcs.get(node_source_line, []) for pc in node_pcs: txt += magenta( "\t\t\t0x{:x}: {}\n".format( int(pc), contract_cfg.get_instruction_at(pc) ) ) self.info(txt) res = self.generate_output(txt) return res
def output(self, filename): """ Output the inheritance relation _filename is not used Args: _filename(string) """ info = 'Inheritance\n' if not self.contracts: return info += blue('Child_Contract -> ') + green('Immediate_Base_Contracts') info += green(' [Not_Immediate_Base_Contracts]') result = {'child_to_base': {}} for child in self.contracts: if child.is_top_level: continue info += blue(f'\n+ {child.name}\n') result['child_to_base'][child.name] = { 'immediate': [], 'not_immediate': [] } if child.inheritance: immediate = child.immediate_inheritance not_immediate = [ i for i in child.inheritance if i not in immediate ] info += ' -> ' + green(", ".join(map(str, immediate))) + '\n' result['child_to_base'][child.name]['immediate'] = list( map(str, immediate)) if not_immediate: info += ", [" + green(", ".join(map( str, not_immediate))) + "]\n" result['child_to_base'][ child.name]['not_immediate'] = list( map(str, not_immediate)) info += green('\n\nBase_Contract -> ') + blue( 'Immediate_Child_Contracts') + '\n' info += blue(' [Not_Immediate_Child_Contracts]') + '\n' result['base_to_child'] = {} for base in self.contracts: if base.is_top_level: continue info += green(f'\n+ {base.name}') + '\n' children = list(self._get_child_contracts(base)) result['base_to_child'][base.name] = { 'immediate': [], 'not_immediate': [] } if children: immediate = [ child for child in children if base in child.immediate_inheritance ] not_immediate = [ child for child in children if not child in immediate ] info += ' -> ' + blue(", ".join(map(str, immediate))) + '\n' result['base_to_child'][base.name]['immediate'] = list( map(str, immediate)) if not_immediate: info += ', [' + blue(", ".join(map( str, not_immediate))) + ']' + '\n' result['base_to_child'][base.name]['not_immediate'] = list( map(str, immediate)) self.info(info) res = self.generate_output(info, additional_fields=result) return res