Beispiel #1
0
    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)
Beispiel #2
0
    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()
Beispiel #3
0
    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()
Beispiel #4
0
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
Beispiel #5
0
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()
Beispiel #6
0
#
# 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())
Beispiel #7
0
 def __init__(self, module_bytecode, analysis=True):
     WasmModuleAnalyzer.__init__(self,
                                 module_bytecode=module_bytecode,
                                 analysis=analysis)