Package: octopus
OctopusHuge thanks toQuoScientfor having sponsored this project.Octopus is a security analysis framework for WebAssembly module and Blockchain Smart Contract.The purpose of Octopus is to provide an easy way to analyze closed-source WebAssembly module and smart contracts bytecode to understand deeper their internal behaviours.FeaturesExplorer: Octopus JSON-RPC client implementation to communicate with blockchain platformsDisassembler: Octopus can translate bytecode into assembly representationControl Flow Analysis: Octopus can generate a Control Flow Graph (CFG)Call Flow Analysis: Octopus can generate a Call Flow Graph (function level)IR conversion (SSA): Octopus can simplify assembly into Static Single Assignment (SSA) representationSymbolic Execution: Octopus use symbolic execution to find new paths into a programPlatforms / ArchitecturesOctopus support the following types of programs/smart contracts:WebAssembly module (WASM)Bitcoin script (BTC script)Ethereum smart contracts (EVM bytecode & Ewasm)EOS smart contracts (WASM)NEO smart contracts (AVM bytecode)BTCETH (EVM)ETH (WASM)EOSNEOWASMExplorer:heavy_check_mark::heavy_check_mark::heavy_check_mark::heavy_check_mark::heavy_check_mark::o:Disassembler:heavy_check_mark::heavy_check_mark::heavy_check_mark::heavy_check_mark::heavy_check_mark::heavy_check_mark:Control Flow Analysis:heavy_multiplication_x::heavy_check_mark::heavy_check_mark::heavy_check_mark::heavy_check_mark::heavy_check_mark:Call Flow Analysis:heavy_multiplication_x::heavy_plus_sign::heavy_check_mark::heavy_check_mark::heavy_plus_sign::heavy_check_mark:IR conversion (SSA):heavy_multiplication_x::heavy_check_mark::heavy_plus_sign::heavy_plus_sign::heavy_multiplication_x::heavy_check_mark:Symbolic Execution:heavy_multiplication_x::heavy_plus_sign::heavy_plus_sign::heavy_plus_sign::heavy_multiplication_x::heavy_plus_sign:PyPI package :heavy_check_mark:Docker :heavy_check_mark::heavy_check_mark:DONE/ :heavy_plus_sign:WIP/ :heavy_multiplication_x:TODO/ :o:N/ARequirementsOctopus is supported on Linux (ideally Ubuntu 16.04) and requires Python >=3.5 (ideally 3.6).Dependencies:Graph generation:graphvizExplorer:requestsSymbolic Execution:z3-solverWasm:wasmQuick StartInstall system dependencies# Install system dependencies
sudo apt-get update && sudo apt-get install python-pip graphviz xdg-utils -yInstall Octopus:# Download Octopus
git clone https://github.com/quoscient/octopus
cd octopus

# Install Octopus library/CLI and its dependencies
python3 setup.py installor# but prefer the first way to install if possible
pip3 install octopusRun tests# Run tests for all platforms (disassembly, CFG, ...)
./run_tests.sh
# Run tests that require internet access (explorer tests)
./run_explorer_tests.sh

# Run tests for only one platforms
# {btc, eth, eos, neo, wasm}_run_tests.sh
cd octopus/tests/
./wasm_run_tests.shDocker containerA docker container providing the toolset is available atdocker hub.
In a terminal, run the following commands:docker pull smartbugs/octopus
docker run -it smartbugs/octopus
cd octopus
python3 octopus_eth_evm.py -s -f examples/ETH/evm_bytecode/61EDCDf5bb737ADffE5043706e7C5bb1f1a56eEA.bytecodeCommand-line toolsWebAssembly:octopus_wasm.pyEthereum (EVM):octopus_eth_evm.pyIn-depth Examples using APIsWebAssemblyDisassemblerDisassembly of a Wasm module:fromoctopus.arch.wasm.disassemblerimportWasmDisassemblerFILE="examples/wasm/samples/helloworld.wasm"withopen(FILE,'rb')asf:module_bytecode=f.read()disasm=WasmDisassembler()# return list of functions instructions (list)print(disasm.disassemble_module(module_bytecode))#[[<octopus.arch.wasm.instruction.WasmInstruction at 0x7f85e4904278>,<octopus.arch.wasm.instruction.WasmInstruction at 0x7f85e4904f60>,<octopus.arch.wasm.instruction.WasmInstruction at 0x7f85e4904ef0>]]print()# return text of functions codeprint(disasm.disassemble_module(module_bytecode,r_format='text'))# func 0# i32.const 0# call 0# endDisassembly of wasm bytecode:fromoctopus.arch.wasm.disassemblerimportWasmDisassembler# bytecode in WebAssembly is the function code (i.e. function body)bytecode=b'\x02\x7fA\x18\x10\x1cA\x00\x0f\x0b'# create a WasmDisassembler objectdisasm=WasmDisassembler(bytecode)# disassemble bytecode into a list of WasmInstruction# attributes r_format='list' by defaultprint(disasm.disassemble())#[<octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904eb8>, <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904278>, <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904390>, <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904ef0>, <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904f60>, <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4901048>]print()print(disasm.disassemble(r_format='reverse'))#{0: <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4901048>, 1: <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904240>, 2: <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904f60>, 3: <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904ef0>, 4: <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904278>, 5: <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904390>}print()print(disasm.disassemble(r_format='text'))# block -1# i32.const 24# call 28# i32.const 0# return# endModuleAnalyzerfromoctopus.arch.wasm.analyzerimportWasmModuleAnalyzerFILE="examples/wasm/samples/hello_wasm_studio.wasm"withopen(FILE,'rb')asf:module_bytecode=f.read()# return list of functions instructions (list)# attributes analysis=True by defaultanalyzer=WasmModuleAnalyzer(module_bytecode)# show analyzer attributesprint(analyzer.func_prototypes)# [('putc_js', 'i32', ''),#  ('__syscall0', 'i32', 'i32'),#  ('__syscall3', 'i32 i32 i32 i32', 'i32'),#  ('__syscall1', 'i32 i32', 'i32'),#  ('__syscall5', 'i32 i32 i32 i32 i32 i32', 'i32'),#  ('__syscall4', 'i32 i32 i32 i32 i32', 'i32'),#  ('$func6', '', ''),#  ('main', '', 'i32'),#  ('writev_c', 'i32 i32 i32', 'i32'),#  ('$func9', '', 'i32'),#  ('$func10', 'i32', 'i32'),#  ('$func11', 'i32', 'i32'),#  ('$func12', 'i32', ''),#  ('$func13', 'i32', 'i32'),#  ('$func14', 'i32 i32 i32 i32', 'i32'),#  ('$func15', 'i32 i32', 'i32'),#  ('$func16', 'i32 i32', 'i32'),#  ('$func17', 'i32', 'i32'),#  ('$func18', 'i32', 'i32'),#  ('$func19', 'i32', 'i32'),#  ('$func20', 'i32 i32 i32', 'i32'),#  ('$func21', 'i32 i32 i32', 'i32'),#  ('$func22', 'i32 i64 i32', 'i64'),#  ('$func23', 'i32 i32 i32', 'i32'),#  ('$func24', 'i32', 'i32'),#  ('$func25', 'i32 i32 i32 i32', '')]print()print(analyzer.contains_emscripten_syscalls())#[('__syscall0', 'restart_syscall'),# ('__syscall3', 'read'),# ('__syscall1', 'exit'),# ('__syscall5', 'open'),# ('__syscall4', 'write')]Control Flow Analysisfromoctopus.arch.wasm.cfgimportWasmCFG# complete wasm modulefile_name="examples/wasm/samples/fib.wasm"# read filewithopen(file_name,'rb')asf:raw=f.read()# create the cfgcfg=WasmCFG(raw)# visualize CFGGraph# generate graph.dot and graph.pdf filecfg.visualize()Functions' instructions analyticsfromoctopus.arch.wasm.cfgimportWasmCFG# complete wasm modulefile_name="examples/wasm/samples/hello_wasm_studio.wasm"# read filewithopen(file_name,'rb')asf:raw=f.read()# create the cfgcfg=WasmCFG(raw)# visualizationcfg.visualize_instrs_per_funcs()Call Flow Analysisfromoctopus.arch.wasm.cfgimportWasmCFG# fibonacci wasm modulefile_name="examples/wasm/samples/hello_wasm_studio.wasm"# read filewithopen(file_name,'rb')asf:raw=f.read()# create the cfgcfg=WasmCFG(raw)# visualize Call Flow Graph# generate call_graph.dot and call_graph.pdf file## color similar to https://webassembly.studio/# imported func == turquoise / exported func == grey# edge label = number of different calls to the functioncfg.visualize_call_flow()Legend:IR conversion (SSA)fromoctopus.arch.wasm.emulatorimportWasmSSAEmulatorEngine# complete wasm modulefile_name="examples/wasm/samples/fib.wasm"# read filewithopen(file_name,'rb')asf:raw=f.read()# run the emulator for SSAemul=WasmSSAEmulatorEngine(raw)emul.emulate_one_function('fib')# or emul.emulate_functions(['fib'])# or emul.emulate_functions() # emulate all the function# visualization of the cfg with SSAemul.cfg.visualize(ssa=True)Ethereum (ETH) - EVMExplorerfromoctopus.platforms.ETH.explorerimportEthereumInfuraExplorerfromoctopus.platforms.ETH.explorerimportINFURA_ROPSTENKEY_API="bHuaQhX91nkQBac8Wtgj"# connection to ROPSTEN network (testnet)explorer=EthereumInfuraExplorer(KEY_API,network=INFURA_ROPSTEN)# connection to MAINNET network (mainnet)# explorer = EthereumInfuraExplorer(KEY_API)# Test ROPSTEN network current block numberblock_number=explorer.eth_blockNumber()print(block_number)# 3675552# Retrieve code of this smart contractaddr="0x3c6B10a5239B1a8A27398583F49771485382818F"code=explorer.eth_getCode(addr)print(code)# 0x6060604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c14606e575b600080fd5b3415605857600080fd5b606c60048080359060200190919050506094565b005b3415607857600080fd5b607e609e565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a72305820e1f98c821c12eea52047d7324b034ddccc41eaa7365d369b34580ab73c71a8940029Disassemblerfromoctopus.platforms.ETH.disassemblerimportEthereumDisassembler# smart contract bytecodebytecode_hex="60606040526000357c0100000000000000000000000000000000000000000000000000000000900480635fd8c7101461004f578063c0e317fb1461005e578063f8b2cb4f1461006d5761004d565b005b61005c6004805050610099565b005b61006b600480505061013e565b005b610083600480803590602001909190505061017d565b6040518082815260200191505060405180910390f35b3373ffffffffffffffffffffffffffffffffffffffff16611111600060005060003373ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060005054604051809050600060405180830381858888f19350505050151561010657610002565b6000600060005060003373ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050819055505b565b34600060005060003373ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828282505401925050819055505b565b6000600060005060008373ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000505490506101b6565b91905056"disasm=EthereumDisassembler()disasm.disassemble(bytecode_hex)# disassemble bytecode into a list of EthereumInstruction# attributes r_format='list' by defaultprint(disasm.disassemble(bytecode_hex))#[<octopus.platforms.ETH.instruction.EthereumInstruction object at 0x7f85d4add5c0>, <octopus.platforms.ETH.instruction.EthereumInstruction object at 0x7f85d4ad8588>, <octopus.platforms.ETH.instruction.EthereumInstruction object at 0x7f85d4ad8c50>]print()print(disasm.disassemble(bytecode_hex,r_format='reverse'))# {0: <octopus.platforms.ETH.instruction.EthereumInstruction object at 0x7f85d4ad8160>, ..., 229: <octopus.platforms.ETH.instruction.EthereumInstruction object at 0x7f85d4ad8630>, 230: <octopus.platforms.ETH.instruction.EthereumInstruction object at 0x7f85d4ad87b8>}print()print(disasm.disassemble(bytecode_hex,r_format='text'))# PUSH1 0x60# PUSH1 0x40# MSTORE# PUSH1 0x0# CALLDATALOAD# PUSH29 0x100000000000000000000000000000000000000000000000000000000# SWAP1# DIV# DUP1# PUSH4 0x5fd8c710# EQ# PUSH2 0x4f# JUMPI# ...# SWAP2# SWAP1# POP# JUMPControl Flow Analysisfromoctopus.analysis.graphimportCFGGraphfromoctopus.platforms.ETH.cfgimportEthereumCFG# ethernaut0 bytecodefile_name="examples/ETH/evm_bytecode/Zeppelin_Hello_ethernaut0.bytecode"# read filewithopen(file_name)asf:bytecode_hex=f.read()# create the CFGcfg=EthereumCFG(bytecode_hex)# generic visualization api# generate graph.dot and graph.pdf filegraph=CFGGraph(cfg)graph.view()# or directly using the cfg binding# cfg.visualize()# and you can get a simplify cfg representation using# cfg.visualize(simplify=True) or graph.view(simplify=True)IR conversion (SSA)# The conversion to SSA is already done by the SSAEmulator# when the CFG is reconstruct# by default you have just to visualize itfromoctopus.platforms.ETH.cfgimportEthereumCFG# ethernaut0 bytecodefile_name="examples/ETH/evm_bytecode/Zeppelin_Hello_ethernaut0.bytecode"# read filewithopen(file_name)asf:bytecode_hex=f.read()# create the CFGcfg=EthereumCFG(bytecode_hex)# SSA visualizationcfg.visualize(ssa=True)Ethereum (WASM)Explorerfromoctopus.platforms.ETH.explorerimportEthereumInfuraExplorerfromoctopus.platforms.ETH.explorerimportINFURA_KOVAN# connection to ROPSTEN network (testnet)explorer=EthereumInfuraExplorer("bHuaQhX91nkQBac8Wtgj",network=INFURA_KOVAN)# connection to MAINNET network (mainnet)# explorer = EthereumInfuraExplorer("bHuaQhX91nkQBac8Wtgj")# test infura accessblock_number=explorer.eth_blockNumber()print('blockNumber =%d'%block_number)# retrieve code of this smart contractaddr="0x1120e596b173d953ba52ce262f73ce3734b0e40e"code=explorer.eth_getCode(addr)print()print(code)# blockNumber = 8803487## 0x0061736d0100000001090260000060027f7f00021a0203656e7603726574000103656e76066d656d6f7279020102100303020000040501700101010501000601000708010463616c6c00010a120205001002000b0a00418008410b1000000b0b1201004180080b0b48656c6c6f20776f726c64000b076c696e6b696e6703010b0066046e616d65015f060003726574010570616e6963020463616c6c032f5f5a4e3134707761736d5f657468657265756d3365787433726574313768363034643830393864313638366338304504066465706c6f790511727573745f626567696e5f756e77696e64DisassemblerDisassembly of a Wasm module:fromoctopus.platforms.ETH.disassemblerimportEthereumDisassemblerFILE="examples/ETH/wasm/helloworld_kovan.bytecode"withopen(FILE,'r')asf:module_bytecode=f.read()disasm=EthereumDisassembler(arch='wasm')# return list of functions instructions (list)print(disasm.disassemble_module(module_bytecode))#[[<octopus.arch.wasm.instruction.WasmInstruction object at 0x7efc0ceaa898>], [<octopus.arch.wasm.instruction.WasmInstruction object at 0x7efc0ceaa7b8>, <octopus.arch.wasm.instruction.WasmInstruction object at 0x7efc0ceaa780>, <octopus.arch.wasm.instruction.WasmInstruction object at 0x7efc0ceaa748>, <octopus.arch.wasm.instruction.WasmInstruction object at 0x7efc0ceaa6d8>, <octopus.arch.wasm.instruction.WasmInstruction object at 0x7efc0ceaa710>]]print()# return text of functions codeprint(disasm.disassemble_module(module_bytecode,r_format='text'))# func 0# end## func 1# call 1# i32.const 1036# i32.const 232# call 0# endDisassembly of wasm bytecode:fromoctopus.platforms.ETH.disassemblerimportEthereumDisassembler# bytecode in WebAssembly is the function code (i.e. function body)bytecode=b'\x02\x7fA\x18\x10\x1cA\x00\x0f\x0b'# create a WasmDisassembler objectdisasm=EthereumDisassembler(bytecode,arch='wasm')# disassemble bytecode into a list of WasmInstruction# attributes r_format='list' by defaultprint(disasm.disassemble())#[<octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904eb8>, <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904278>, <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904390>, <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904ef0>, <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904f60>, <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4901048>]print()print(disasm.disassemble(r_format='reverse'))#{0: <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4901048>, 1: <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904240>, 2: <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904f60>, 3: <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904ef0>, 4: <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904278>, 5: <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904390>}print()print(disasm.disassemble(r_format='text'))# block -1# i32.const 24# call 28# i32.const 0# return# endModuleAnalyzerfromoctopus.arch.wasm.analyzerimportWasmModuleAnalyzerFILE="examples/ETH/wasm/helloworld_kovan.bytecode"withopen(FILE,'r')asf:module_bytecode=f.read()# return list of functions instructions (list)# attributes analysis=True by defaultanalyzer=WasmModuleAnalyzer(module_bytecode)# show analyzer attributesprint(analyzer.func_prototypes)# [('ret', 'i32 i32', '', 'import'), ('$func1', '', '', 'local'), ('call', '', '', 'export')]print()print(analyzer.exports)# [{'field_str': 'call', 'kind': 0, 'index': 2}]print()print(analyzer.imports_func)# [('env', 'ret', 1)]print()print(analyzer.datas)# [{'data': b'Hello world', 'index': 0, 'offset': None, 'size': 11},# {'data': b'\x00asm\x01\x00\x00\x00\x01\t\x02`\x00\x00`\x02\x7f\x7f\x00\x02\x1a\x02\x03env\x03ret\x00\x01\x03env\x06memory\x02\x01\x02\x10\x03\x03\x02\x00\x00\x04\x05\x01p\x01\x01\x01\x05\x01\x00\x06\x01\x00\x07\x08\x01\x04call\x00\x01\n\x12\x02\x05\x00\x10\x02\x00\x0b\n\x00A\x80\x08A\x0b\x10\x00\x00\x0b\x0b\x12\x01\x00A\x80\x08\x0b\x0bHello world\x00\x0b\x07linking\x03\x01\x0b\x00f\x04name\x01_\x06\x00\x03ret\x01\x05panic\x02\x04call\x03/_ZN14pwasm_ethereum3ext3ret17h604d8098d1686c80E\x04\x06deploy\x05\x11rust_begin_unwind',# 'index': 0,# 'offset': None,# 'size': 232}]Control Flow Analysisfromoctopus.platforms.ETH.cfgimportEthereumCFG# HelloWorld on Kovan Parity Networkfile_name="examples/ETH/wasm/helloworld_kovan.bytecode"# read filewithopen(file_name)asf:bytecode_hex=f.read()# create the CFGcfg=EthereumCFG(bytecode_hex,arch='wasm')cfg.visualize()Functions' instructions analyticsfromoctopus.platforms.ETH.cfgimportEthereumCFG# HelloWorld on Kovan Parity Networkfile_name="examples/ETH/wasm/helloworld_kovan.bytecode"# read filewithopen(file_name)asf:bytecode_hex=f.read()# create the CFGcfg=EthereumCFG(bytecode_hex,arch='wasm')# visualizationcfg.visualize_instrs_per_funcs()Call Flow Analysisfromoctopus.platforms.ETH.cfgimportEthereumCFG# HelloWorld on Kovan Parity Networkfile_name="examples/ETH/wasm/helloworld_kovan.bytecode"# read filewithopen(file_name)asf:bytecode_hex=f.read()# create the CFGcfg=EthereumCFG(bytecode_hex,arch='wasm')# visualizationcfg.visualize_call_flow()Legend:IR conversion (SSA)# TODONEOExplorerfromoctopus.platforms.NEO.explorerimportNeoExplorerRPC# get list nodes here: http://monitor.cityofzion.io/explorer=NeoExplorerRPC(host='seed2.neo.org')# get current number of block on the blockchainprint(explorer.getblockcount())# 2534868# get information on a contract# lock smart contract address: d3cce84d0800172d09c88ccad61130611bd047a4contract=explorer.getcontractstate("d3cce84d0800172d09c88ccad61130611bd047a4")print(contract)# {'author': 'Erik Zhang',# 'code_version': '2.0',# 'description': 'Lock 2.0',# 'email': 'erik@neo.org',# 'hash': '0xd3cce84d0800172d09c88ccad61130611bd047a4',# 'name': 'Lock',# 'parameters': ['Integer', 'PublicKey', 'Signature'],# 'properties': {'dynamic_invoke': False, 'storage': False},# 'returntype': 'Boolean',# 'script': '56c56b6c766b00527ac46c766b51527ac46c766b52527ac4616168184e656f2e426c6f636b636861696e2e4765744865696768746168184e656f2e426c6f636b636861696e2e4765744865616465726c766b53527ac46c766b00c36c766b53c36168174e656f2e4865616465722e47657454696d657374616d70a06c766b54527ac46c766b54c3640e00006c766b55527ac4621a006c766b51c36c766b52c3617cac6c766b55527ac46203006c766b55c3616c7566',# 'version': 0}# smart contract code in contract['script']print(contract['script'])Disassemblerfromoctopus.platforms.NEO.disassemblerimportNeoDisassembler# lock contractfile_name="examples/NEO/samples/Lock.bytecode"# read filewithopen(file_name)asf:bytecode=f.read()disasm=NeoDisassembler()print(disasm.disassemble(bytecode,r_format='text'))# PUSH6# NEWARRAY# TOALTSTACK# FROMALTSTACK# DUP# TOALTSTACK# PUSH0# PUSH2# ROLL# SETITEM# FROMALTSTACK# ....# PICKITEM# NOP# FROMALTSTACK# DROP# RETControl Flow Analysisfromoctopus.analysis.graphimportCFGGraphfromoctopus.platforms.NEO.cfgimportNeoCFG# lock contractfile_name="examples/NEO/samples/Lock.bytecode"# read filewithopen(file_name)asf:raw=f.read()# create neo cfg - automatic static analysiscfg=NeoCFG(raw)# graph visualizationgraph=CFGGraph(cfg,filename="Lock_cfg")graph.view_functions()EOSExplorerfromoctopus.platforms.EOS.explorerimportEosExplorerhost="api.cypherglass.com"# by defaul the port is 8888explo=EosExplorer(host=host)# get info about the nodeexplo.get_info()'''{'block_cpu_limit': 180289,'block_net_limit': 1045680,'chain_id': 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906','head_block_id': '018d6e2bcf6295126cd74cf694b5cca3529eefc42b334b394ef87c3a43876739','head_block_num': 26045995,'head_block_producer': 'eosswedenorg','head_block_time': '2018-11-09T14:11:29.500','last_irreversible_block_id': '018d6cdcff78bbd9f25c605b02fb67c47a337ece78ddcf73089cee4bf6a410ee','last_irreversible_block_num': 26045660,'server_version': 'c71d2245','server_version_string': 'mainnet-1.3.0','virtual_block_cpu_limit': 38092879,'virtual_block_net_limit': 1048576000}'''explo.get_block(1337)'''{'action_mroot': 'bcb9763baa3bbf98ed36379b4be0ecb2d9cd21c75df01729c63b2b021001c10c','block_extensions': [],'block_num': 1337,'confirmed': 0,'header_extensions': [],'id': '00000539d17a03af7126e073be4c4d99a72b7f58793cf2c87b9bfd41b6c711fb','new_producers': None,'previous': '00000538b374c1cbfaeed7253ad3075ddc72a28f0a0515301fc1bbed675f2316','producer': 'eosio','producer_signature': 'SIG_K1_K5jWf36t6j454Hb2fGuV37YTwMTvuQ51ZPBtpru8Ud2axtMTEauWyvtpJuTpnvqzReUndDgEDXvoeEP4jdj2bpnYKBt6g2','ref_block_prefix': 1944069745,'schedule_version': 0,'timestamp': '2018-06-09T12:09:21.500','transaction_mroot': '0000000000000000000000000000000000000000000000000000000000000000','transactions': []}'''Disassemblerfromoctopus.platforms.EOS.disassemblerimportEosDisassembler# complete wasm modulefile_name="examples/EOS/samples/eos_ping.wasm"# read filewithopen(file_name,'rb')asf:raw=f.read()# just disassemblydisasm=EosDisassembler()# because we provide full module bytecode# we need to use disassemble_module()# otherwise just disassemble() is enoughtext=disasm.disassemble_module(raw,r_format="text")print(text)# func 0# get_local 0# get_local 1# i32.const 32# call 12# i32.eqz# end## func 1# get_local 0# i64.load 3, 0# get_local 0# i64.load 3, 8# call 6# end## func 2# ...# end## ...ModuleAnalyzerfromoctopus.platforms.EOS.analyzerimportEosAnalyzer# complete wasm modulefile_name="examples/EOS/samples/eos_ping.wasm"withopen(file_name,'rb')asf:module_bytecode=f.read()# return list of functions instructions (list)# attributes analysis=True by defaultanalyzer=EosAnalyzer(module_bytecode)# show analyzer attributesprint(analyzer.func_prototypes)#[('action_data_size', '', 'i32', 'import'), ('eosio_assert', 'i32 i32', '', 'import'), ('eosio_exit', 'i32', '', 'import'), ('memcpy', 'i32 i32 i32', 'i32', 'import'), ('prints', 'i32', '', 'import'), ('read_action_data', 'i32 i32', 'i32', 'import'), ('require_auth2', 'i64 i64', '', 'import'), ('_ZeqRK11checksum256S1_', 'i32 i32', 'i32', 'export'), ('_ZN5eosio12require_authERKNS_16permission_levelE', 'i32', '', 'export'), ('apply', 'i64 i64 i64', '', 'export'), ('$func10', 'i32 i64', '', 'local'), ('$func11', 'i32 i32', 'i32', 'local'), ('memcmp', 'i32 i32 i32', 'i32', 'export'), ('malloc', 'i32', 'i32', 'export'), ('$func14', 'i32 i32', 'i32', 'local'), ('$func15', 'i32', 'i32', 'local'), ('free', 'i32', '', 'export'), ('$func17', '', '', 'local')]print()print(analyzer.exports)# [{'field_str': 'memory', 'kind': 2, 'index': 0}, {'field_str': '_ZeqRK11checksum256S1_', 'kind': 0, 'index': 7}, {'field_str': '_ZN5eosio12require_authERKNS_16permission_levelE', 'kind': 0, 'index': 8}, {'field_str': 'apply', 'kind': 0, 'index': 9}, {'field_str': 'memcmp', 'kind': 0, 'index': 12}, {'field_str': 'malloc', 'kind': 0, 'index': 13}, {'field_str': 'free', 'kind': 0, 'index': 16}]print()print(analyzer.imports_func)# [('env', 'action_data_size', 3), ('env', 'eosio_assert', 5), ('env', 'eosio_exit', 2), ('env', 'memcpy', 6), ('env', 'prints', 2), ('env', 'read_action_data', 4), ('env', 'require_auth2', 1)]Control Flow Analysisfromoctopus.platforms.EOS.cfgimportEosCFGfromoctopus.analysis.graphimportCFGGraph# complete wasm modulefile_name="examples/EOS/samples/eos_ping.wasm"# read filewithopen(file_name,'rb')asf:raw=f.read()# create the cfgcfg=EosCFG(raw)# visualizegraph=CFGGraph(cfg)graph.view_functions()Call Flow Analysisfromoctopus.platforms.EOS.cfgimportEosCFG# complete wasm modulefile_name="examples/EOS/samples/eos_ping.wasm"# read filewithopen(file_name,'rb')asf:raw=f.read()# create the cfgcfg=EosCFG(raw)# visualizecfg.visualize_call_flow()Functions' instructions analyticsfromoctopus.platforms.EOS.cfgimportEosCFG# complete wasm modulefile_name="examples/EOS/samples/eos_ping.wasm"# read filewithopen(file_name,'rb')asf:raw=f.read()# create the cfgcfg=EosCFG(raw)# visualizecfg.visualize_instrs_per_funcs()BitcoinExplorerfromoctopus.platforms.BTC.explorerimportBitcoinExplorerRPCRPC_USER='test'RPC_PASSWORD='test'RPC_HOST='localhost'host='%s:%s@%s'%(RPC_USER,RPC_PASSWORD,RPC_HOST)explorer=BitcoinExplorerRPC(host)explorer.getbestblockhash()# '00000000000000000012085cfe8c79bcdacf81fbd82f6ab52c3cb3a454d4987c'explorer.getblockcount()#550859Disassemblerfromoctopus.platforms.BTC.disassemblerimportBitcoinDisassembler# Witness Scriptfile_name="examples/BTC/witness_script.hex"# read filewithopen(file_name)asf:bytecode=f.read()disasm=BitcoinDisassembler()print(disasm.disassemble(bytecode,r_format='text'))# 0# OP_ROT# OP_ROT# 2# 0203f4d01d0b35588638631ebb7d46d8387fd1aeb3dbecfdd3faf7c056b023c833# 03aa6677e3ce1bd634f4f2e1cd60a60af002e1b30484d4d1611b183b16d391ee96# 03bf164811abb8c91ed39e58d4e307f86cb4e487c83f727a2c482bc71a0f96f1db# 3# OP_CHECKMULTISIGPlease find examples inexamplesfolder.Publications and VideosBLACKALPS 2018Reversing and Vulnerability research of Ethereum Smart ContractsDevcon iv.Reversing Ethereum Smart Contracts to find out what's behind EVM bytecodehack.lu 2018Reversing and Vulnerability research of Ethereum Smart ContractsToorCon XX - 2018Reversing Ethereum Smart Contracts (Introduction)ToorCon XX - 2018Dissection of WebAssembly moduleREcon Montreal 2018:Reverse Engineering Of Blockchain Smart ContractsAuthorsPatrick Ventuzelo-Creator-@Pat_VentuzeloSee also the list ofcontributorswho participated in this project.LicenseThis project is licensed under the MIT License - see theLICENSEfile for detailsAcknowledgmentsSponsor:QuoScientInspired by:ManticoreMythrilRattleethersplay...Trainings & ContactPatrick Ventuzelo -@pat_ventuzelo- Independent Security Researcher / Trainer.Consulting & trainings:4-daysWebAssembly securitytraining:here2-daysRust securitytraining:here