def analyze(bytecode: str, contract_name, result_printer: Printer, verbose=False) -> ContractReport: result_printer.info("***************************************************") result_printer.info("Analyzing contract: {0}".format(contract_name)) result = ContractReport() c_printer = CPrinter() instructions = ByteCode.disasm(bytecode, c_printer) result_printer.info("Symbolically executing") analyzer = Analyzer(instructions, result_printer, verbose) # analyze construction code result_printer.info("Checking construction assemble code") cfg_r = analyze_cfg(analyzer.construct_cfg, result_printer) result.add(cfg_r) result_printer.info("Checking construction assemble code...done") result_printer.info("- - - - - - - - - - - - - - - - - - - - - - - - - -") # analyze body code result_printer.info("Checking runtime assemble code") cfg_r = analyze_cfg(analyzer.body_cfg, result_printer, verbose) result.add(cfg_r) result_printer.info("Checking runtime assemble code...done") result_printer.info("***************************************************") return result
def process(args): c_printer = CPrinter() result = {} if args.result is not None: if not os.path.exists(args.result): c_printer.error( "Result output directory '{0}' does not exist".format( args.result)) sys.exit(-1) if not os.path.isdir(args.result): c_printer.error("'{0}' is not a directory".format(args.result)) sys.exit(-1) if args.file: if args.source and args.extension is None: args.extension = 'sol' elif args.bytecode and args.extension is None: args.extension = 'hex' c_printer.info("processing files with extension '{0}'".format( args.extension)) for s in args.input: f_r = FileReport() if os.path.splitext(s)[-1][1:] != args.extension: c_printer.warn("file '{0}' extension mismatch".format(s)) c_printer.warn("skipping '{0}'".format(s)) continue if not os.path.exists(s): c_printer.error("file '{0}' does not exist".format(s)) c_printer.warn("skipping '{0}'".format(s)) elif not os.path.isfile(s): c_printer.error("'{0}' is not a file".format(s)) c_printer.warn("skipping '{0}'".format(s)) else: with open(s) as file: c_printer.info("start analyzing {0}".format(s)) try: if args.source: bytecodes = utils.compile_sol(s, args.t_runtime) else: bytecodes = ''.join(file.readlines()) for contract_name, bytecode in bytecodes: if args.result is not None: filename = os.path.splitext(s)[0] + ".txt" f_printer = FPrinter(filename=os.path.join( args.result, filename)) c_r = analyze(bytecode, contract_name, f_printer) else: c_r = analyze(bytecode, contract_name, c_printer) f_r.add(c_r) except AttributeError as e: c_printer.error(str(e)) c_printer.warn("fail to analyze {0}".format(s)) except AnalyzerException as e: c_printer.warn("Unsupported feature: {}".format(e)) c_printer.warn("fail to analyze {0}".format(s)) except TimeoutException: c_printer.warn("Analyze timeout") c_printer.warn("fail to analyze {0}".format(s)) except Exception as e: c_printer.error("SmSymer internal Error: {}".format(e)) c_printer.warn("fail to analyze {0}".format(s)) else: c_printer.info("finish analyzing {0}".format(s)) result[s] = f_r elif args.dir: if args.source and args.extension is None: args.extension = 'sol' elif args.bytecode and args.extension is None: args.extension = 'hex' c_printer.info("processing files with extension '{0}'".format( args.extension)) for s in args.input: if not os.path.exists(s): c_printer.error("directory '{0}' does not exist") c_printer.warn("skipping '{0}'") elif not os.path.isdir(s): c_printer.error("'{0}' is not a directory") c_printer.warn("skipping '{0}'") else: f_r = process_dir(s, args) result.update(f_r) else: for i, s in enumerate(args.input): bytecode = s c_printer.info("start analyzing {0}".format(s)) f_r = FileReport() try: if args.result is not None: filename = str(i) + ".txt" f_printer = FPrinter( filename=os.path.join(args.result, filename)) c_r = analyze(bytecode, '', f_printer) else: c_r = analyze(bytecode, '', c_printer) f_r.add(c_r) except AttributeError as e: c_printer.error(str(e)) c_printer.warn("fail to analyze {0}".format(s)) except AnalyzerException as e: c_printer.warn("Unsupported feature: {}".format(e)) c_printer.warn("fail to analyze {0}".format(s)) except TimeoutException: c_printer.warn("Analyze timeout") c_printer.warn("fail to analyze {0}".format(s)) except Exception as e: c_printer.error("SmSymer internal Error: {}".format(e)) c_printer.warn("fail to analyze {0}".format(s)) else: c_printer.info("finish analyzing {0}".format(s)) result[i] = f_r # t_result_file = "/home/troublor/Desktop/result/t_contracts" # t_r_printer = FPrinter(t_result_file) # u_result_file = "/home/troublor/Desktop/result/u_contracts" # u_r_printer = FPrinter(u_result_file) # r_result_file = "/home/troublor/Desktop/result/r_contracts" # r_r_printer = FPrinter(r_result_file) c_printer.info("***********************************") f_total = 0 f_success = 0 c_total = 0 c_success = 0 n_td = 0 n_td_f = 0 n_uc = 0 n_r = 0 for filename, f_r in result.items(): f_total += 1 if f_r.success: f_success += 1 has_timestamp = False for c_r in f_r.c_reports: c_total += 1 if c_r.success: c_success += 1 for cfg_r in c_r.cfg_reports: if cfg_r.n_timestamp_dependency > 0: n_td += 1 has_timestamp = True # t_r_printer.print(filename) break for cfg_r in c_r.cfg_reports: if cfg_r.n_unchecked_call > 0: n_uc += 1 # u_r_printer.print(filename) break for cfg_r in c_r.cfg_reports: if cfg_r.n_reentrancy > 0: n_r += 1 # r_r_printer.print(filename) break if has_timestamp: n_td_f += 1 c_printer.info("SmSymer analyzed {0} files".format(f_total)) c_printer.info("{0} success files, containing {1} contracts".format( f_success, c_total)) c_printer.info("{0} success analyzed contracts".format(c_success)) c_printer.info( "{0} contracts contains Timestamp Dependency Vulnerability".format( n_td)) c_printer.info( "{0} contracts contains Unchecked Call Vulnerability".format(n_uc)) c_printer.info( "{0} contracts contains Reentrancy Vulnerability".format(n_r)) c_printer.info( "{0} files contains Timestamp Dependency Vulnerability".format(n_td_f))
def process_dir(directory: str, args) -> Dict[str, FileReport]: result = {} c_printer = CPrinter() for item in os.listdir(directory): f_r: FileReport = FileReport() if os.path.isdir(item): if args.recursively: process_dir(item, args) else: c_printer.warn( "not specify -R option, skipping subdirectory '{}'".format( item)) else: if os.path.splitext(item)[-1][1:] != args.extension: c_printer.warn("file '{0}' extension mismatch".format(item)) c_printer.warn("skipping '{0}'".format(item)) continue with open(os.path.join(directory, item)) as file: c_printer.info("start analyzing {0}".format( os.path.join(directory, item))) try: if args.source: bytecodes = utils.compile_sol( os.path.join(directory, item), args.t_runtime) else: bytecodes = ''.join(file.readlines()) for contract_name, bytecode in bytecodes: if args.result is not None: filename = os.path.join( args.result, os.path.split(directory)[0], item + ".txt") f_printer = FPrinter(filename=filename) c_r = analyze(bytecode, contract_name, f_printer) f_r.add(c_r) else: c_r = analyze(bytecode, contract_name, c_printer) f_r.add(c_r) except AttributeError as e: c_printer.error(str(e)) traceback.print_exc() c_printer.warn("fail to analyze {0}".format( os.path.join(directory, item))) except AnalyzerException as e: c_printer.warn("Unsupported feature: {}".format(e)) c_printer.warn("fail to analyze {0}".format( os.path.join(directory, item))) except TimeoutException: c_printer.warn("Analyze timeout") c_printer.warn("fail to analyze {0}".format( os.path.join(directory, item))) except Exception as e: c_printer.error("SmSymer internal Error: {}".format(e)) traceback.print_exc() c_printer.warn("fail to analyze {0}".format( os.path.join(directory, item))) else: c_printer.info("finish analyzing {0}".format( os.path.join(directory, item))) result[os.path.join(directory, item)] = f_r return result
def process_dir(directory: str, args): c_printer = CPrinter() for item in os.listdir(directory): if os.path.isdir(item): if args.recursively: process_dir(item, args) else: c_printer.warn( "not specify -R option, skipping subdirectory '{}'".format( item)) else: if os.path.splitext(item)[-1][1:] != args.extension: c_printer.warn("file '{0}' extension mismatch".format(item)) c_printer.warn("skipping '{0}'".format(item)) continue with open(os.path.join(directory, item)) as file: c_printer.info("start disassembling {0}".format( os.path.join(directory, item))) try: if args.source: _, bytecode = utils.compile_sol( os.path.join(directory, item))[0] else: bytecode = ''.join(file.readlines()) if args.result is not None: filename = os.path.join(args.result, os.path.split(directory)[0], item + ".asm") f_printer = FPrinter(filename=filename) f_printer.print(disasm(bytecode)) else: c_printer.print(disasm(bytecode)) except AttributeError as e: c_printer.error(str(e)) c_printer.info("fail to disassemble {0}".format( os.path.join(directory, item))) else: c_printer.info("finish disassembling {0}".format( os.path.join(directory, item)))
def disasm(bytecode: str) -> List[str]: c_printer = CPrinter() instructions = ByteCode.disasm(bytecode, c_printer) return list(map(lambda ins: str(ins), instructions))
def process(args): c_printer = CPrinter() if args.result is not None: if not os.path.exists(args.result): c_printer.error( "Result output directory '{0}' does not exist".format( args.result)) sys.exit(-1) if not os.path.isdir(args.result): c_printer.error("'{0}' is not a directory".format(args.result)) sys.exit(-1) if args.file: if args.source and args.extension is None: args.extension = 'sol' elif args.bytecode and args.extension is None: args.extension = 'hex' c_printer.info("processing files with extension '{0}'".format( args.extension)) for s in args.input: if os.path.splitext(s)[-1][1:] != args.extension: c_printer.warn("file '{0}' extension mismatch".format(s)) c_printer.warn("skipping '{0}'".format(s)) continue if not os.path.exists(s): c_printer.error("file '{0}' does not exist".format(s)) c_printer.warn("skipping '{0}'".format(s)) elif not os.path.isfile(s): c_printer.error("'{0}' is not a file".format(s)) c_printer.warn("skipping '{0}'".format(s)) else: with open(s) as file: c_printer.info("start disassembling {0}".format(s)) try: if args.source: _, bytecode = utils.compile_sol(s)[0] else: bytecode = ''.join(file.readlines()) if args.result is not None: filename = os.path.splitext(s)[0] + ".asm" f_printer = FPrinter( filename=os.path.join(args.result, filename)) f_printer.print(disasm(bytecode)) else: c_printer.print(disasm(bytecode)) except AttributeError as e: c_printer.error(str(e)) c_printer.info("fail to disassemble {0}".format(s)) else: c_printer.info("finish disassembling {0}".format(s)) elif args.dir: if args.source and args.extension is None: args.extension = 'sol' elif args.bytecode and args.extension is None: args.extension = 'hex' c_printer.info("processing files with extension '{0}'".format( args.extension)) for s in args.input: if not os.path.exists(s): c_printer.error("directory '{0}' does not exist") c_printer.warn("skipping '{0}'") elif not os.path.isdir(s): c_printer.error("'{0}' is not a directory") c_printer.warn("skipping '{0}'") else: process_dir(s, args) else: for i, s in enumerate(args.input): bytecode = s c_printer.info("start disassembling {0}".format(s)) try: if args.result is not None: filename = str(i) + ".asm" f_printer = FPrinter( filename=os.path.join(args.result, filename)) f_printer.print(disasm(bytecode)) else: c_printer.print(disasm(bytecode)) except AttributeError as e: c_printer.error(str(e)) c_printer.info("fail to disassemble {0}".format(s)) else: c_printer.info("finish disassembling {0}".format(s))
def process(args): c_printer = CPrinter() if args.file: s = args.input if not os.path.exists(s): c_printer.error("file '{0}' does not exist".format(s)) elif not os.path.isfile(s): c_printer.error("'{0}' is not a file".format(s)) else: with open(s) as file: c_printer.info("start debugging {0}".format(s)) try: bytecode = ''.join(file.readlines()) instructions = ByteCode.disasm(bytecode, c_printer) debugger = Debugger(instructions, c_printer) debugger.start() except AttributeError as e: c_printer.error(str(e)) c_printer.info("fail to debug {0}".format(s)) else: c_printer.info("finish debugging {0}".format(s)) else: bytecode = args.input c_printer.info("start debugging") try: instructions = ByteCode.disasm(bytecode, c_printer) debugger = Debugger(instructions, c_printer) debugger.start() except AttributeError as e: c_printer.error(str(e)) c_printer.info("fail to debug") else: c_printer.info("finish debugging")