def get_inputs(self, targetContracts=None): inputs = [] if self.input_type == InputHelper.BYTECODE: with open(self.source, 'r') as f: bytecode = f.read() self._prepare_disasm_file(self.source, bytecode) disasm_file = self._get_temporary_files(self.source)['disasm'] inputs.append({'disasm_file': disasm_file}) else: contracts = self._get_compiled_contracts() self._prepare_disasm_files_for_analysis(contracts) for contract, _ in contracts: c_source, cname = contract.split(':') if targetContracts is not None and cname not in targetContracts: continue c_source = re.sub(self.root_path, "", c_source) if self.input_type == InputHelper.SOLIDITY: source_map = SourceMap(contract, self.source, 'solidity', self.root_path, self.remap, self.allow_paths) else: source_map = SourceMap(contract, self.source, 'standard json', self.root_path) disasm_file = self._get_temporary_files(contract)['disasm'] inputs.append({ 'contract': contract, 'source_map': source_map, 'source': self.source, 'c_source': c_source, 'c_name': cname, 'disasm_file': disasm_file }) if targetContracts is not None and not inputs: raise ValueError("Targeted contracts weren't found in the source code!") return inputs
def get_inputs(self): inputs = [] if self.input_type == InputHelper.BYTECODE: with open(self.source, 'r') as f: bytecode = f.read() self._prepare_disasm_file(self.source, bytecode) disasm_file = self._get_temporary_files(self.source)['disasm'] inputs.append({'disasm_file': disasm_file}) else: contracts = self._get_compiled_contracts() self._prepare_disasm_files_for_analysis(contracts) for contract, _ in contracts: c_source, cname = contract.split(':') c_source = re.sub(self.root_path, "", c_source) if self.input_type == InputHelper.SOLIDITY: source_map = SourceMap(contract, self.source, 'solidity', self.root_path, self.remap, self.allow_paths) else: source_map = SourceMap(contract, self.source, 'standard json', self.root_path) disasm_file = self._get_temporary_files(contract)['disasm'] inputs.append({ 'contract': contract, 'source_map': source_map, 'source': self.source, 'c_source': c_source, 'c_name': cname, 'disasm_file': disasm_file }) return inputs
def run_standard_json_analysis(contracts): global args results = {} exit_code = 0 for contract, _ in contracts: source, cname = contract.split(":") source = re.sub(args.root_path, "", source) logging.info("Contract %s:", contract) source_map = SourceMap(contract, args.source, "standard json") result, return_code = run_source_code_analysis(contract, source_map) try: results[source][cname] = result except: results[source] = {cname: result} if return_code == 1: exit_code = 1 return results, exit_code
def main(): # TODO: Implement -o switch. global args parser = argparse.ArgumentParser() group = parser.add_mutually_exclusive_group(required=True) group.add_argument( "-s", "--source", type=str, help= "local source file name. Solidity by default. Use -b to process evm instead. Use stdin to read from stdin." ) group.add_argument( "-ru", "--remoteURL", type=str, help= "Get contract from remote URL. Solidity by default. Use -b to process evm instead.", dest="remote_URL") parser.add_argument("--version", action="version", version="oyente version 0.2.7 - Commonwealth") parser.add_argument("-t", "--timeout", help="Timeout for Z3 in ms.", action="store", type=int) parser.add_argument("-gl", "--gaslimit", help="Limit Gas", action="store", dest="gas_limit", type=int) parser.add_argument("-rp", "--root-path", help="Root directory path used for the online version", action="store", dest="root_path", type=str) parser.add_argument("-ll", "--looplimit", help="Limit number of loops", action="store", dest="loop_limit", type=int) parser.add_argument("-dl", "--depthlimit", help="Limit DFS depth", action="store", dest="depth_limit", type=int) parser.add_argument("-ap", "--allow-paths", help="Allow a given path for imports", action="store", dest="allow_paths", type=str) parser.add_argument("-glt", "--global-timeout", help="Timeout for symbolic execution", action="store", dest="global_timeout", type=int) parser.add_argument("-e", "--evm", help="Do not remove the .evm file.", action="store_true") parser.add_argument("-w", "--web", help="Run Oyente for web service", action="store_true") parser.add_argument("-j", "--json", help="Redirect results to a json file.", action="store_true") parser.add_argument( "-err", "--error", help="Enable exceptions and print output. Monsters here.", action="store_true") parser.add_argument("-p", "--paths", help="Print path condition information.", action="store_true") parser.add_argument("-db", "--debug", help="Display debug information", action="store_true") parser.add_argument("-st", "--state", help="Get input state from state.json", action="store_true") parser.add_argument("-r", "--report", help="Create .report file.", action="store_true") parser.add_argument("-v", "--verbose", help="Verbose output, print everything.", action="store_true") parser.add_argument( "-b", "--bytecode", help="read bytecode in source instead of solidity file.", action="store_true") parser.add_argument("-a", "--assertion", help="Check assertion failures.", action="store_true") parser.add_argument("-sj", "--standard-json", help="Support Standard JSON input", action="store_true") parser.add_argument("-gb", "--globalblockchain", help="Integrate with the global ethereum blockchain", action="store_true") parser.add_argument( "-gtc", "--generate-test-cases", help="Generate test cases each branch of symbolic execution tree", action="store_true") args = parser.parse_args() if args.root_path: if args.root_path[-1] != '/': args.root_path += '/' else: args.root_path = "" if args.timeout: global_params.TIMEOUT = args.timeout if args.verbose: logging.basicConfig(level=logging.DEBUG) else: logging.basicConfig(level=logging.INFO) global_params.PRINT_PATHS = 1 if args.paths else 0 global_params.REPORT_MODE = 1 if args.report else 0 global_params.IGNORE_EXCEPTIONS = 1 if args.error else 0 global_params.USE_GLOBAL_BLOCKCHAIN = 1 if args.globalblockchain else 0 global_params.INPUT_STATE = 1 if args.state else 0 global_params.WEB = 1 if args.web else 0 global_params.STORE_RESULT = 1 if args.json else 0 global_params.CHECK_ASSERTIONS = 1 if args.assertion else 0 global_params.DEBUG_MODE = 1 if args.debug else 0 global_params.GENERATE_TEST_CASES = 1 if args.generate_test_cases else 0 if args.depth_limit: global_params.DEPTH_LIMIT = args.depth_limit if args.gas_limit: global_params.GAS_LIMIT = args.gas_limit if args.loop_limit: global_params.LOOP_LIMIT = args.loop_limit if global_params.WEB: if args.global_timeout and args.global_timeout < global_params.GLOBAL_TIMEOUT: global_params.GLOBAL_TIMEOUT = args.global_timeout else: if args.global_timeout: global_params.GLOBAL_TIMEOUT = args.global_timeout if not has_dependencies_installed(): return if args.remote_URL: r = requests.get(args.remote_URL) code = r.text filename = "remote_contract.evm" if args.bytecode else "remote_contract.sol" args.source = filename with open(filename, 'w') as f: f.write(code) if args.bytecode: processed_evm_file = args.source + '.1' disasm_file = args.source + '.disasm' with open(args.source) as f: evm = f.read() with open(processed_evm_file, 'w') as f: f.write(removeSwarmHash(evm)) result = analyze(processed_evm_file, disasm_file) bug_found = result[1] if global_params.WEB: print json.dumps(result[0]) remove_temporary_file(disasm_file) remove_temporary_file(processed_evm_file) if global_params.UNIT_TEST == 2 or global_params.UNIT_TEST == 3: exit_code = os.WEXITSTATUS(cmd) if exit_code != 0: exit(exit_code) else: if bug_found: exit(1) elif args.standard_json: FNULL = open(os.devnull, 'w') cmd = "cat %s" % args.source p1 = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, stderr=FNULL) cmd = "solc --allow-paths %s --standard-json" % args.allow_paths p2 = subprocess.Popen(shlex.split(cmd), stdin=p1.stdout, stdout=subprocess.PIPE, stderr=FNULL) p1.stdout.close() out = p2.communicate()[0] with open('standard_json_output', 'w') as f: f.write(out) # should handle the case without allow-paths option j = json.loads(out) contracts = [] for source in j["sources"]: for contract in j["contracts"][source]: cname = source + ":" + contract evm = j["contracts"][source][contract]["evm"][ "deployedBytecode"]["object"] contracts.append((cname, evm)) bug_found = False for cname, bin_str in contracts: logging.info("Contract %s:", cname) processed_evm_file = cname + '.evm' disasm_file = cname + '.evm.disasm' with open(processed_evm_file, 'w') as of: of.write(removeSwarmHash(bin_str)) result = analyze(processed_evm_file, disasm_file, SourceMap(cname, args.source, "standard json")) if not bug_found: bug_found = result[1] try: results[source][contract] = result[0] except: results[source] = {contract: result[0]} if args.evm: with open(processed_evm_file, 'w') as of: of.write(bin_str) remove_temporary_file(processed_evm_file) remove_temporary_file(disasm_file) remove_temporary_file(disasm_file + '.log') if bug_found: exit(1) else: contracts = compileContracts(args.source) results = {} bug_found = False for cname, bin_str in contracts: source, contract = cname.split(":") source = re.sub(args.root_path, "", source) logging.info("Contract %s:", cname) processed_evm_file = cname + '.evm' disasm_file = cname + '.evm.disasm' with open(processed_evm_file, 'w') as of: of.write(removeSwarmHash(bin_str)) result = analyze( processed_evm_file, disasm_file, SourceMap(args.root_path, cname, args.source, "solidity")) if not bug_found: bug_found = result[1] try: results[source][contract] = result[0] except: results[source] = {contract: result[0]} if args.evm: with open(processed_evm_file, 'w') as of: of.write(bin_str) remove_temporary_file(processed_evm_file) remove_temporary_file(disasm_file) remove_temporary_file(disasm_file + '.log') if global_params.WEB: print json.dumps(results) if bug_found: exit(1)
def main(): # TODO: Implement -o switch. global args parser = argparse.ArgumentParser() group = parser.add_mutually_exclusive_group(required=True) group.add_argument( "-s", "--source", type=str, help= "local source file name. Solidity by default. Use -b to process evm instead. Use stdin to read from stdin." ) group.add_argument( "-ru", "--remoteURL", type=str, help= "Get contract from remote URL. Solidity by default. Use -b to process evm instead.", dest="remote_URL") parser.add_argument("--version", action="version", version="oyente version 0.2.5-Buona Vista") parser.add_argument( "-b", "--bytecode", help="read bytecode in source instead of solidity file.", action="store_true") parser.add_argument("-j", "--json", help="Redirect results to a json file.", action="store_true") parser.add_argument("-e", "--evm", help="Do not remove the .evm file.", action="store_true") parser.add_argument("-p", "--paths", help="Print path condition information.", action="store_true") parser.add_argument( "--error", help="Enable exceptions and print output. Monsters here.", action="store_true") parser.add_argument("-t", "--timeout", type=int, help="Timeout for Z3 in ms.") parser.add_argument("-v", "--verbose", help="Verbose output, print everything.", action="store_true") parser.add_argument("-r", "--report", help="Create .report file.", action="store_true") parser.add_argument("-gb", "--globalblockchain", help="Integrate with the global ethereum blockchain", action="store_true") parser.add_argument("-dl", "--depthlimit", help="Limit DFS depth", action="store", dest="depth_limit", type=int) parser.add_argument("-gl", "--gaslimit", help="Limit Gas", action="store", dest="gas_limit", type=int) parser.add_argument("-st", "--state", help="Get input state from state.json", action="store_true") parser.add_argument("-ll", "--looplimit", help="Limit number of loops", action="store", dest="loop_limit", type=int) parser.add_argument("-w", "--web", help="Run Oyente for web service", action="store_true") parser.add_argument("-glt", "--global-timeout", help="Timeout for symbolic execution", action="store", dest="global_timeout", type=int) parser.add_argument("-a", "--assertion", help="Check assertion failures.", action="store_true") parser.add_argument("--debug", help="Display debug information", action="store_true") args = parser.parse_args() if args.timeout: global_params.TIMEOUT = args.timeout if args.verbose: logging.basicConfig(level=logging.DEBUG) else: logging.basicConfig(level=logging.INFO) global_params.PRINT_PATHS = 1 if args.paths else 0 global_params.REPORT_MODE = 1 if args.report else 0 global_params.IGNORE_EXCEPTIONS = 1 if args.error else 0 global_params.USE_GLOBAL_BLOCKCHAIN = 1 if args.globalblockchain else 0 global_params.INPUT_STATE = 1 if args.state else 0 global_params.WEB = 1 if args.web else 0 global_params.STORE_RESULT = 1 if args.json else 0 global_params.CHECK_ASSERTIONS = 1 if args.assertion else 0 global_params.DEBUG_MODE = 1 if args.debug else 0 if args.depth_limit: global_params.DEPTH_LIMIT = args.depth_limit if args.gas_limit: global_params.GAS_LIMIT = args.gas_limit if args.loop_limit: global_params.LOOP_LIMIT = args.loop_limit if args.global_timeout and args.global_timeout < global_params.GLOBAL_TIMEOUT: global_params.GLOBAL_TIMEOUT = args.global_timeout if not has_dependencies_installed(): return if args.remote_URL: r = requests.get(args.remote_URL) code = r.text filename = "remote_contract.evm" if args.bytecode else "remote_contract.sol" args.source = filename with open(filename, 'w') as f: f.write(code) if args.bytecode: processed_evm_file = args.source + '.1' disasm_file = args.source + '.disasm' with open(args.source) as f: evm = f.read() with open(processed_evm_file, 'w') as f: f.write(removeSwarmHash(evm)) analyze(processed_evm_file, disasm_file) remove_temporary_file(disasm_file) remove_temporary_file(processed_evm_file) if global_params.UNIT_TEST == 2 or global_params.UNIT_TEST == 3: exit_code = os.WEXITSTATUS(cmd) if exit_code != 0: exit(exit_code) else: contracts = compileContracts(args.source) for cname, bin_str in contracts: logging.info("Contract %s:", cname) processed_evm_file = cname + '.evm' disasm_file = cname + '.evm.disasm' with open(processed_evm_file, 'w') as of: of.write(removeSwarmHash(bin_str)) analyze(processed_evm_file, disasm_file, SourceMap(cname, args.source)) if args.evm: with open(processed_evm_file, 'w') as of: of.write(bin_str) remove_temporary_file(processed_evm_file) remove_temporary_file(disasm_file) remove_temporary_file(disasm_file + '.log')
def main(): global args print("") print(" .oooooo. o8o o8o ") print(" d8P' `Y8b `\"' `\"' ") print("888 888 .oooo.o oooo oooo d8b oooo .oooo.o") print("888 888 d88( \"8 `888 `888\"\"8P `888 d88( \"8") print("888 888 `\"Y88b. 888 888 888 `\"Y88b. ") print("`88b d88' o. )88b 888 888 888 o. )88b") print(" `Y8bood8P' 8\"\"888P' o888o d888b o888o 8\"\"888P'") print("") parser = argparse.ArgumentParser() group = parser.add_mutually_exclusive_group(required=True) group.add_argument( "-s", "--source", type=str, help= "local source file name. Solidity by default. Use -b to process evm instead. Use stdin to read from stdin." ) group.add_argument( "-ru", "--remoteURL", type=str, help= "Get contract from remote URL. Solidity by default. Use -b to process evm instead.", dest="remote_URL") parser.add_argument( "--version", action="version", version= "Osiris version 0.0.1 - 'Memphis' (Oyente version 0.2.7 - Commonwealth)" ) parser.add_argument( "-b", "--bytecode", help="read bytecode in source instead of solidity file.", action="store_true") parser.add_argument("-j", "--json", help="Redirect results to a json file.", action="store_true") parser.add_argument("-e", "--evm", help="Do not remove the .evm file.", action="store_true") parser.add_argument("-p", "--paths", help="Print path condition information.", action="store_true") parser.add_argument( "--error", help="Enable exceptions and print output. Monsters here.", action="store_true") parser.add_argument("-t", "--timeout", type=int, help="Timeout for Z3 in ms (default " + str(global_params.TIMEOUT) + " ms).") parser.add_argument("-v", "--verbose", help="Verbose output, print everything.", action="store_true") parser.add_argument("-r", "--report", help="Create .report file.", action="store_true") parser.add_argument("-gb", "--globalblockchain", help="Integrate with the global ethereum blockchain", action="store_true") parser.add_argument("-dl", "--depthlimit", help="Limit DFS depth (default " + str(global_params.DEPTH_LIMIT) + ").", action="store", dest="depth_limit", type=int) parser.add_argument("-gl", "--gaslimit", help="Limit Gas (default " + str(global_params.GAS_LIMIT) + ").", action="store", dest="gas_limit", type=int) parser.add_argument("-st", "--state", help="Get input state from state.json", action="store_true") parser.add_argument("-ll", "--looplimit", help="Limit number of loops (default " + str(global_params.LOOP_LIMIT) + ").", action="store", dest="loop_limit", type=int) parser.add_argument("-w", "--web", help="Run Osiris for web service", action="store_true") parser.add_argument( "-glt", "--global-timeout", help="Timeout for symbolic execution in sec (default " + str(global_params.GLOBAL_TIMEOUT) + " sec).", action="store", dest="global_timeout", type=int) parser.add_argument("-a", "--assertion", help="Check assertion failures.", action="store_true") parser.add_argument("--debug", help="Display debug information", action="store_true") parser.add_argument( "--generate-test-cases", help="Generate test cases each branch of symbolic execution tree", action="store_true") parser.add_argument( "-c", "--cfg", help="Create control flow graph and store as .dot file.", action="store_true") parser.add_argument("-m", "--model", help="Output models generated by the solver.", action="store_true") args = parser.parse_args() # Set global arguments for symbolic execution if args.timeout: global_params.TIMEOUT = args.timeout if args.verbose: logging.basicConfig(level=logging.DEBUG) else: logging.basicConfig(level=logging.INFO) global_params.PRINT_PATHS = 1 if args.paths else 0 global_params.REPORT_MODE = 1 if args.report else 0 global_params.IGNORE_EXCEPTIONS = 1 if args.error else 0 global_params.USE_GLOBAL_BLOCKCHAIN = 1 if args.globalblockchain else 0 global_params.INPUT_STATE = 1 if args.state else 0 global_params.WEB = 1 if args.web else 0 global_params.STORE_RESULT = 1 if args.json else 0 global_params.CHECK_ASSERTIONS = 1 if args.assertion else 0 global_params.DEBUG_MODE = 1 if args.debug else 0 global_params.GENERATE_TEST_CASES = 1 if args.generate_test_cases else 0 global_params.CFG = 1 if args.cfg else 0 global_params.MODEL_INPUT = 1 if args.model else 0 if args.depth_limit: global_params.DEPTH_LIMIT = args.depth_limit if args.gas_limit: global_params.GAS_LIMIT = args.gas_limit if args.loop_limit: global_params.LOOP_LIMIT = args.loop_limit if global_params.WEB: if args.global_timeout and args.global_timeout < global_params.GLOBAL_TIMEOUT: global_params.GLOBAL_TIMEOUT = args.global_timeout else: if args.global_timeout: global_params.GLOBAL_TIMEOUT = args.global_timeout # Check that our system has everything we need (evm, Z3) if not has_dependencies_installed(): return # Retrieve contract from remote URL, if necessary if args.remote_URL: r = requests.get(args.remote_URL) code = r.text filename = "remote_contract.evm" if args.bytecode else "remote_contract.sol" if "etherscan.io" in args.remote_URL and not args.bytecode: try: filename = re.compile( '<td>Contract<span class="hidden-su-xs"> Name</span>:</td><td>(.+?)</td>' ).findall(code.replace('\n', '').replace('\t', ''))[0].replace(' ', '') filename += ".sol" except: pass code = re.compile( "<pre class='js-sourcecopyarea' id='editor' style='.+?'>([\s\S]+?)</pre>", re.MULTILINE).findall(code)[0] code = HTMLParser().unescape(code) args.source = filename with open(filename, 'w') as f: f.write(code) # If we are given bytecode, disassemble first, as we need to operate on EVM ASM. if args.bytecode: processed_evm_file = args.source + '.evm' disasm_file = args.source + '.evm.disasm' with open(args.source) as f: evm = f.read() with open(processed_evm_file, 'w') as f: f.write(removeSwarmHash(evm)) analyze(processed_evm_file, disasm_file) remove_temporary_file(disasm_file) remove_temporary_file(processed_evm_file) remove_temporary_file(disasm_file + '.log') if global_params.UNIT_TEST == 2 or global_params.UNIT_TEST == 3: exit_code = os.WEXITSTATUS(cmd) if exit_code != 0: exit(exit_code) else: # Compile contracts using solc contracts = compileContracts(args.source) # Analyze each contract for cname, bin_str in contracts: print("") logging.info("Contract %s:", cname) processed_evm_file = cname + '.evm' disasm_file = cname + '.evm.disasm' with open(processed_evm_file, 'w') as of: of.write(removeSwarmHash(bin_str)) analyze(processed_evm_file, disasm_file, SourceMap(cname, args.source)) remove_temporary_file(processed_evm_file) remove_temporary_file(disasm_file) remove_temporary_file(disasm_file + '.log') if args.evm: with open(processed_evm_file, 'w') as of: of.write(bin_str) if global_params.STORE_RESULT: if ':' in cname: result_file = os.path.join( global_params.RESULTS_DIR, cname.split(':')[0].replace('.sol', '.json').split('/')[-1]) with open(result_file, 'a') as of: of.write("}")
def main(remoteAddress = None): global args print("") print(art.LOGO) print(art.NAME) print("") parser = argparse.ArgumentParser() group = parser.add_mutually_exclusive_group(required=False) group.add_argument("-s", "--source", type=str, help="local source file name. Solidity by default. Use -b to process evm instead. Use stdin to read from stdin.") group.add_argument("-ru", "--remoteURL", type=str, help="Get contract from remote URL. Solidity by default. Use -b to process evm instead.", dest="remote_URL") parser.add_argument("--version", action="version", version="Cryptoprobe version 0.1.0 (Honeybadger version 0.0.1, Oyente version 0.2.7 - Commonwealth)") parser.add_argument( "-b", "--bytecode", help="read bytecode in source instead of solidity file.", action="store_true") parser.add_argument( "-j", "--json", help="Redirect results to a json file.", action="store_true") parser.add_argument("-t", "--timeout", type=int, help="Timeout for Z3 in ms (default "+str(global_params.TIMEOUT)+" ms).") parser.add_argument("-gb", "--globalblockchain", help="Integrate with the global ethereum blockchain", action="store_true") parser.add_argument("-dl", "--depthlimit", help="Limit DFS depth (default "+str(global_params.DEPTH_LIMIT)+").", action="store", dest="depth_limit", type=int) parser.add_argument("-gl", "--gaslimit", help="Limit Gas (default "+str(global_params.GAS_LIMIT)+").", action="store", dest="gas_limit", type=int) parser.add_argument( "-st", "--state", help="Get input state from state.json", action="store_true") parser.add_argument("-ll", "--looplimit", help="Limit number of loops (default "+str(global_params.LOOP_LIMIT)+").", action="store", dest="loop_limit", type=int) parser.add_argument("-glt", "--global-timeout", help="Timeout for symbolic execution in sec (default "+str(global_params.GLOBAL_TIMEOUT)+" sec).", action="store", dest="global_timeout", type=int) parser.add_argument( "--debug", help="Display debug information.", action="store_true") parser.add_argument( "-c", "--cfg", help="Create control flow graph and store as .dot file.", action="store_true") args = parser.parse_args() # Set global arguments for symbolic execution global_params.USE_GLOBAL_BLOCKCHAIN = 1 if args.globalblockchain else 0 global_params.INPUT_STATE = 1 if args.state else 0 global_params.STORE_RESULT = 1 if args.json else 0 global_params.DEBUG_MODE = 1 if args.debug else 0 global_params.CFG = 1 if args.cfg else 0 global_params.BYTECODE = 1 if args.bytecode else 0 if args.timeout: global_params.TIMEOUT = args.timeout if args.depth_limit: global_params.DEPTH_LIMIT = args.depth_limit if args.gas_limit: global_params.GAS_LIMIT = args.gas_limit if args.loop_limit: global_params.LOOP_LIMIT = args.loop_limit if args.global_timeout: global_params.GLOBAL_TIMEOUT = args.global_timeout logging.basicConfig(level=logging.INFO) # Check that our system has everything we need (evm, Z3) if not has_dependencies_installed(): return if not args.remote_URL and not args.source and not remoteAddress: print("Specify atleast one of -ru or -s or functional args") return # Retrieve contract from remote URL, if necessary if args.remote_URL or remoteAddress: contractAddress = remoteAddress if remoteAddress else args.remote_URL dataSource = EthereumData() code = dataSource.getSourceCode(contractAddress) filename = "remote_contract.evm" if args.bytecode else "remote_contract.sol" args.source = filename with open(filename, 'w') as f: f.write(code) # If we are given bytecode, disassemble first, as we need to operate on EVM ASM. if args.bytecode: processed_evm_file = args.source + '.evm' disasm_file = args.source + '.evm.disasm' with open(args.source) as f: evm = f.read() with open(processed_evm_file, 'w') as f: f.write(removeSwarmHash(evm)) analyze(processed_evm_file, disasm_file) remove_temporary_file(disasm_file) remove_temporary_file(processed_evm_file) remove_temporary_file(disasm_file + '.log') else: # Compile contracts using solc contracts = compileContracts(args.source) # Analyze each contract for cname, bin_str in contracts: print("") logging.info("Contract %s:", cname) processed_evm_file = cname + '.evm' disasm_file = cname + '.evm.disasm' with open(processed_evm_file, 'w') as of: of.write(removeSwarmHash(bin_str)) analyze(processed_evm_file, disasm_file, SourceMap(cname, args.source)) remove_temporary_file(processed_evm_file) remove_temporary_file(disasm_file) remove_temporary_file(disasm_file + '.log') if global_params.STORE_RESULT: if ':' in cname: result_file = os.path.join(global_params.RESULTS_DIR, cname.split(':')[0].replace('.sol', '.json').split('/')[-1]) with open(result_file, 'a') as of: of.write("}") return global_params.finalReturnResults
def main(): global args print("") print(" ___,,___ ") print(" _,-='=- =- -`''--.__,,.._ ") print(" ,-;// / - - - -= - '=. ") print(" ,'/// - - - = - ==-=\`. ") print(" |/// / = `. - = == - =.=_,,._ `=/| ") print(" /// - - \ - - = ,ndDMHHMM/\b \\ ") print(" ,' - / / / /\ = - /MM(,,._`YQMML `| ") print(" <_,=^Kkm / / / / ///H|wnWWdMKKK#''-;. `'0\ | ") print(" `''QkmmmmmnWMMM\''WHMKKMM\ `--. \> \ ") print(" `''' `->>> ``WHMb,. `-_<@) ") print(" `'QMM`. ") print(" `>>> ") print(" _ _ ____ _ ") print(" | | | | | _ \ | | ") print(" | |__| | ___ _ __ ___ _ _| |_) | __ _ __| | __ _ ___ _ __ ") print(" | __ |/ _ \| '_ \ / _ \ | | | _ < / _` |/ _` |/ _` |/ _ \ '__|") print(" | | | | (_) | | | | __/ |_| | |_) | (_| | (_| | (_| | __/ | ") print(" |_| |_|\___/|_| |_|\___|\__, |____/ \__,_|\__,_|\__, |\___|_| ") print(" __/ | __/ | ") print(" |___/ |___/ ") print("") parser = argparse.ArgumentParser() group = parser.add_mutually_exclusive_group(required=True) group.add_argument( "-s", "--source", type=str, help= "local source file name. Solidity by default. Use -b to process evm instead. Use stdin to read from stdin." ) group.add_argument( "-ru", "--remoteURL", type=str, help= "Get contract from remote URL. Solidity by default. Use -b to process evm instead.", dest="remote_URL") parser.add_argument( "--version", action="version", version= "HoneyBadger version 0.0.1 (Oyente version 0.2.7 - Commonwealth)") parser.add_argument( "-b", "--bytecode", help="read bytecode in source instead of solidity file.", action="store_true") parser.add_argument("-j", "--json", help="Redirect results to a json file.", action="store_true") parser.add_argument("-t", "--timeout", type=int, help="Timeout for Z3 in ms (default " + str(global_params.TIMEOUT) + " ms).") parser.add_argument("-gb", "--globalblockchain", help="Integrate with the global ethereum blockchain", action="store_true") parser.add_argument("-dl", "--depthlimit", help="Limit DFS depth (default " + str(global_params.DEPTH_LIMIT) + ").", action="store", dest="depth_limit", type=int) parser.add_argument("-gl", "--gaslimit", help="Limit Gas (default " + str(global_params.GAS_LIMIT) + ").", action="store", dest="gas_limit", type=int) parser.add_argument("-st", "--state", help="Get input state from state.json", action="store_true") parser.add_argument("-ll", "--looplimit", help="Limit number of loops (default " + str(global_params.LOOP_LIMIT) + ").", action="store", dest="loop_limit", type=int) parser.add_argument( "-glt", "--global-timeout", help="Timeout for symbolic execution in sec (default " + str(global_params.GLOBAL_TIMEOUT) + " sec).", action="store", dest="global_timeout", type=int) parser.add_argument("--debug", help="Display debug information.", action="store_true") parser.add_argument( "-c", "--cfg", help="Create control flow graph and store as .dot file.", action="store_true") args = parser.parse_args() # Set global arguments for symbolic execution global_params.USE_GLOBAL_BLOCKCHAIN = 1 if args.globalblockchain else 0 global_params.INPUT_STATE = 1 if args.state else 0 global_params.STORE_RESULT = 1 if args.json else 0 global_params.DEBUG_MODE = 1 if args.debug else 0 global_params.CFG = 1 if args.cfg else 0 global_params.BYTECODE = 1 if args.bytecode else 0 if args.timeout: global_params.TIMEOUT = args.timeout if args.depth_limit: global_params.DEPTH_LIMIT = args.depth_limit if args.gas_limit: global_params.GAS_LIMIT = args.gas_limit if args.loop_limit: global_params.LOOP_LIMIT = args.loop_limit if args.global_timeout: global_params.GLOBAL_TIMEOUT = args.global_timeout logging.basicConfig(level=logging.INFO) # Check that our system has everything we need (evm, Z3) if not has_dependencies_installed(): return # Retrieve contract from remote URL, if necessary if args.remote_URL: r = requests.get(args.remote_URL) code = r.text filename = "remote_contract.evm" if args.bytecode else "remote_contract.sol" if "etherscan.io" in args.remote_URL and not args.bytecode: try: filename = re.compile( '<td>Contract<span class="hidden-su-xs"> Name</span>:</td><td>(.+?)</td>' ).findall(code.replace('\n', '').replace('\t', ''))[0].replace(' ', '') filename += ".sol" except: pass code = re.compile( "<pre class='js-sourcecopyarea' id='editor' style='.+?'>([\s\S]+?)</pre>", re.MULTILINE).findall(code)[0] code = HTMLParser().unescape(code) args.source = filename with open(filename, 'w') as f: f.write(code) # If we are given bytecode, disassemble first, as we need to operate on EVM ASM. if args.bytecode: processed_evm_file = args.source + '.evm' disasm_file = args.source + '.evm.disasm' with open(args.source) as f: evm = f.read() with open(processed_evm_file, 'w') as f: f.write(removeSwarmHash(evm)) analyze(processed_evm_file, disasm_file) remove_temporary_file(disasm_file) remove_temporary_file(processed_evm_file) remove_temporary_file(disasm_file + '.log') else: # Compile contracts using solc contracts = compileContracts(args.source) # Analyze each contract for cname, bin_str in contracts: print("") logging.info("Contract %s:", cname) processed_evm_file = cname + '.evm' disasm_file = cname + '.evm.disasm' with open(processed_evm_file, 'w') as of: of.write(removeSwarmHash(bin_str)) analyze(processed_evm_file, disasm_file, SourceMap(cname, args.source)) remove_temporary_file(processed_evm_file) remove_temporary_file(disasm_file) remove_temporary_file(disasm_file + '.log') if global_params.STORE_RESULT: if ':' in cname: result_file = os.path.join( global_params.RESULTS_DIR, cname.split(':')[0].replace('.sol', '.json').split('/')[-1]) with open(result_file, 'a') as of: of.write("}")