def get_functions_call_edges(self): nodes = list() edges = list() if not self.analyzer: self.analyzer = WasmModuleAnalyzer(self.module_bytecode) if not self.functions: self.functions = enum_func(self.module_bytecode) # create nodes for name, param_str, return_str in self.analyzer.func_prototypes: nodes.append(format_func_name(name, param_str, return_str)) log.info('nodes: %s', nodes) # create edges tmp_edges = enum_func_call_edges(self.functions, len(self.analyzer.imports_func)) # tmp_edges = [(node_from, node_to), (...), ...] for node_from, node_to in tmp_edges: # node_from name, param, ret = self.analyzer.func_prototypes[node_from] from_final = format_func_name(name, param, ret) # node_to name, param, ret = self.analyzer.func_prototypes[node_to] to_final = format_func_name(name, param, ret) edges.append(Edge(from_final, to_final, EDGE_CALL)) log.info('edges: %s', edges) return (nodes, edges)
def __init__(self, module_bytecode): self.module_bytecode = bytecode_to_bytes(module_bytecode) self.functions = list() self.basicblocks = list() self.edges = list() self.analyzer = WasmModuleAnalyzer(self.module_bytecode) self.run_static_analysis()
def __init__(self, module_bytecode, static_analysis=True): if isinstance(module_bytecode, str): self.module_bytecode = binascii.unhexlify(module_bytecode) else: self.module_bytecode = module_bytecode self.static_analysis = static_analysis self.analyzer = None self.functions = list() self.basicblocks = list() self.edges = list() if self.static_analysis: self.analyzer = WasmModuleAnalyzer(self.module_bytecode) self.run_static_analysis()
def enum_func(module_bytecode): ''' return a list of Function see:: octopus.core.function ''' functions = list() analyzer = WasmModuleAnalyzer(module_bytecode) protos = analyzer.func_prototypes import_len = len(analyzer.imports_func) for idx, code in enumerate(analyzer.codes): # get corresponding function prototype name, param_str, return_str, _ = protos[import_len + idx] name = format_func_name(name, param_str, return_str) instructions = WasmDisassembler().disassemble(code) cur_function = Function(0, instructions[0], name=name) cur_function.instructions = instructions functions.append(cur_function) return functions
def main() -> None: parser = argparse.ArgumentParser( description= 'Security Analysis tool for WebAssembly module and Blockchain Smart Contracts (BTC/ETH/NEO/EOS)' ) inputs = parser.add_argument_group('Input arguments') inputs.add_argument( '-r', '--raw', help='hex-encoded bytecode string ("ABcdeF09..." or "0xABcdeF09...")', metavar='BYTECODE') inputs.add_argument('-f', '--file', type=argparse.FileType('rb'), help='binary file (.wasm)', metavar='WASMMODULE') features = parser.add_argument_group('Features') features.add_argument('-d', '--disassemble', action='store_true', help='print text disassembly ') features.add_argument('-z', '--analyzer', action='store_true', help='print module information') features.add_argument('-y', '--analytic', action='store_true', help='print Functions instructions analytics') features.add_argument('-g', '--cfg', action='store_true', help='generate the control flow graph (CFG)') features.add_argument('-c', '--call', action='store_true', help='generate the call flow graph') features.add_argument('-s', '--ssa', action='store_true', help='generate the CFG with SSA representation') graph = parser.add_argument_group('Graph options') graph.add_argument('--simplify', action='store_true', help='generate a simplify CFG') graph.add_argument('--functions', action='store_true', help='create subgraph for each function') graph.add_argument( '--onlyfunc', type=str, nargs="*", default=[], help='only generate the CFG for this list of function name') #graph.add_argument('--visualize', # help='direcly open the CFG file') #graph.add_argument('--format', # choices=['pdf', 'png', 'dot'], # default='pdf', # help='direcly open the CFG file') args = parser.parse_args() octo_bytecode = None octo_analyzer = None octo_disasm = None octo_cfg = None # process input code if args.raw: octo_bytecode = args.raw elif args.file: octo_bytecode = args.file.read() # Disassembly if args.disassemble: from octopus.arch.wasm.disassembler import WasmDisassembler # TODO add other r_format support octo_disasm = WasmDisassembler() print(octo_disasm.disassemble_module(octo_bytecode, r_format='text')) if args.analyzer: from octopus.arch.wasm.analyzer import WasmModuleAnalyzer octo_analyzer = WasmModuleAnalyzer(octo_bytecode) print(octo_analyzer) # Control Flow Analysis & Call flow Analysis if args.cfg or args.call or args.analytic: from octopus.arch.wasm.cfg import WasmCFG from octopus.analysis.graph import CFGGraph octo_cfg = WasmCFG(octo_bytecode) if args.call: octo_cfg.visualize_call_flow() if args.analytic: octo_cfg.visualize_instrs_per_funcs() if args.cfg: octo_graph = CFGGraph(octo_cfg) if args.functions or args.onlyfunc: octo_graph.view_functions(only_func_name=args.onlyfunc, simplify=args.simplify, ssa=args.ssa) else: octo_graph.view(simplify=args.simplify, ssa=args.ssa) if args.ssa: from octopus.arch.wasm.emulator import WasmSSAEmulatorEngine emul = WasmSSAEmulatorEngine(octo_bytecode) # run the emulator for SSA if args.onlyfunc: emul.emulate_functions(args.onlyfunc) # try to emulate main by default else: emul.emulate_functions() # visualization of the cfg with SSA emul.cfg.visualize(ssa=True) if not args.disassemble and not args.ssa \ and not args.cfg and not args.call\ and not args.analyzer and not args.analytic: parser.print_help()
# # Title: WebAssembly module analysis # # Date: 20/08/18 # # Author: Patrick Ventuzelo - @Pat_Ventuzelo # from octopus.arch.wasm.analyzer import WasmModuleAnalyzer # complete wasm module file_name = "examples/wasm/samples/hello_wasm_studio.wasm" # read file with open(file_name, 'rb') as f: raw = f.read() # create the WasmModuleAnalyzer # analysis set to True by default an = WasmModuleAnalyzer(raw, analysis=True) print('list functions:') print(an.func_prototypes) print() # detect if wasm module contains emscripten syscalls print('contains emscripten syscalls ?') print(an.contains_emscripten_syscalls())
def __init__(self, module_bytecode, analysis=True): WasmModuleAnalyzer.__init__(self, module_bytecode=module_bytecode, analysis=analysis)