{ "info": { "author": "QuoScient", "author_email": "", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Intended Audience :: Science/Research", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Software Development :: Disassemblers" ], "description": "# Octopus\n\n

\n\t\n

\n\n[![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg)](https://www.python.org/)\n[![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/quoscient/octopus/graphs/commit-activity)\n[![MIT license](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n\n**Octopus is a security analysis framework for WebAssembly module and Blockchain Smart Contract.**\n\nThe purpose of Octopus is to provide an easy way to analyze smart contract security and understand better what is really stored on the blockchain.\n\n\n## Features\n\n- **Explorer**: Octopus JSON-RPC client implementation to communicate with blockchain platforms\n- **Disassembler**: Octopus can translate bytecode into assembly representation\n- **Control Flow Analysis**: Octopus can generate a Control Flow Graph (CFG) \n- **Call Flow Analysis**: Octopus can generate a Call Flow Graph (function level) \n- **IR conversion (SSA)**: Octopus can simplify assembly into Static Single Assignment (SSA) representation\n- **Symbolic Execution**: Octopus use symbolic execution to find new paths into a program\n\n## Platforms / Architectures\n\nOctopus support the following types of programs/smart contracts:\n* WebAssembly module (WASM)\n* Bitcoin script (BTC script)\n* Ethereum smart contracts (EVM bytecode)\n* Ethereum smart contracts (WASM)\n* EOS smart contracts (WASM)\n* NEO smart contracts (AVM bytecode)\n\n\n|| BTC | ETH (EVM) | ETH (WASM) | EOS | NEO || WASM |\n|:--------------------:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|\n| **Explorer** | :heavy_check_mark: | :heavy_check_mark:| :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | :o: |\n|**Disassembler** | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | :heavy_check_mark: |\n|**Control Flow Analysis** | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | :heavy_check_mark: |\n|**Call Flow Analysis** | :heavy_multiplication_x: | :heavy_plus_sign: | :heavy_check_mark: | :heavy_check_mark: | :heavy_plus_sign: | | :heavy_check_mark: |\n|**IR conversion (SSA)** | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_plus_sign: | :heavy_plus_sign: | :heavy_multiplication_x: | | :heavy_check_mark: |\n|**Symbolic Execution** | :heavy_multiplication_x: | :heavy_plus_sign: | :heavy_plus_sign: | :heavy_plus_sign: | :heavy_multiplication_x: | | :heavy_plus_sign: |\n\n\n* PyPI package :heavy_check_mark:\n* IDA plugin :heavy_multiplication_x:\n* Binary ninja plugin :heavy_multiplication_x:\n\n:heavy_check_mark: **DONE** / :heavy_plus_sign: **WIP** / :heavy_multiplication_x: **TODO** / :o: **N/A**\n\n\n## Requirements\n\nOctopus is supported on Linux (ideally Ubuntu 16.04) and requires Python >=3.5 (ideally 3.6).\n\nDependencies:\n* Graph generation: [graphviz](https://graphviz.gitlab.io/download/)\n* Explorer: [requests](http://docs.python-requests.org/en/master/#)\n* Symbolic Execution: [z3-solver](https://pypi.org/project/z3-solver/)\n* Wasm: [wasm](https://github.com/athre0z/wasm)\n\n## Quick Start\n\n- Install system dependencies\n```\n# Install system dependencies\nsudo apt-get update && sudo apt-get install python-pip graphviz -y\n```\n\n- Install Octopus:\n```\n# Download Octopus\ngit clone https://github.com/quoscient/octopus\ncd octopus\n\n# Install Octopus library/CLI and its dependencies\npython3 setup.py install\n```\nor\n```\n# but prefer the first way to install if possible\npip3 install octopus\n```\n\n- Run tests\n```\n# Run tests for all platforms (disassembly, CFG, ...)\n./run_tests.sh\n# Run tests that require internet access (explorer tests)\n./run_explorer_tests.sh\n\n# Run tests for only one platforms\n# {btc, eth, eos, neo, wasm}_run_tests.sh\ncd octopus/tests/\n./wasm_run_tests.sh\n```\n\n## Command-line tools\n\n* WebAssembly: [octopus_wasm.py](octopus_wasm.py)\n* Ethereum (EVM): [octopus_eth_evm.py](octopus_eth_evm.py)\n\n\n## In-depth Examples using APIs\n\n
WebAssembly\n

\n\n#### Disassembler\n\nDisassembly of a Wasm module:\n```python\nfrom octopus.arch.wasm.disassembler import WasmDisassembler\n\nFILE = \"examples/wasm/samples/helloworld.wasm\"\n\nwith open(FILE, 'rb') as f:\n module_bytecode = f.read()\n\ndisasm = WasmDisassembler()\n# return list of functions instructions (list)\nprint(disasm.disassemble_module(module_bytecode))\n#[[,,]]\n\nprint()\n# return text of functions code\nprint(disasm.disassemble_module(module_bytecode, r_format='text'))\n# func 0\n# i32.const 0\n# call 0\n# end\n```\n\nDisassembly of wasm bytecode:\n```python\nfrom octopus.arch.wasm.disassembler import WasmDisassembler\n\n# bytecode in WebAssembly is the function code (i.e. function body)\nbytecode = b'\\x02\\x7fA\\x18\\x10\\x1cA\\x00\\x0f\\x0b'\n# create a WasmDisassembler object\ndisasm = WasmDisassembler(bytecode)\n\n# disassemble bytecode into a list of WasmInstruction\n# attributes r_format='list' by default\nprint(disasm.disassemble())\n\n#[, , , , , ]\nprint()\nprint(disasm.disassemble(r_format='reverse'))\n\n#{0: , 1: , 2: , 3: , 4: , 5: }\nprint()\nprint(disasm.disassemble(r_format='text'))\n# block -1\n# i32.const 24\n# call 28\n# i32.const 0\n# return\n# end\n```\n\n#### ModuleAnalyzer\n\n```python\nfrom octopus.arch.wasm.analyzer import WasmModuleAnalyzer\n\nFILE = \"examples/wasm/samples/hello_wasm_studio.wasm\"\n\nwith open(FILE, 'rb') as f:\n module_bytecode = f.read()\n\n# return list of functions instructions (list)\n# attributes analysis=True by default\nanalyzer = WasmModuleAnalyzer(module_bytecode)\n\n# show analyzer attributes\nprint(analyzer.func_prototypes)\n# [('putc_js', 'i32', ''),\n# ('__syscall0', 'i32', 'i32'),\n# ('__syscall3', 'i32 i32 i32 i32', 'i32'),\n# ('__syscall1', 'i32 i32', 'i32'),\n# ('__syscall5', 'i32 i32 i32 i32 i32 i32', 'i32'),\n# ('__syscall4', 'i32 i32 i32 i32 i32', 'i32'),\n# ('$func6', '', ''),\n# ('main', '', 'i32'),\n# ('writev_c', 'i32 i32 i32', 'i32'),\n# ('$func9', '', 'i32'),\n# ('$func10', 'i32', 'i32'),\n# ('$func11', 'i32', 'i32'),\n# ('$func12', 'i32', ''),\n# ('$func13', 'i32', 'i32'),\n# ('$func14', 'i32 i32 i32 i32', 'i32'),\n# ('$func15', 'i32 i32', 'i32'),\n# ('$func16', 'i32 i32', 'i32'),\n# ('$func17', 'i32', 'i32'),\n# ('$func18', 'i32', 'i32'),\n# ('$func19', 'i32', 'i32'),\n# ('$func20', 'i32 i32 i32', 'i32'),\n# ('$func21', 'i32 i32 i32', 'i32'),\n# ('$func22', 'i32 i64 i32', 'i64'),\n# ('$func23', 'i32 i32 i32', 'i32'),\n# ('$func24', 'i32', 'i32'),\n# ('$func25', 'i32 i32 i32 i32', '')]\nprint()\nprint(analyzer.contains_emscripten_syscalls())\n#[('__syscall0', 'restart_syscall'),\n# ('__syscall3', 'read'),\n# ('__syscall1', 'exit'),\n# ('__syscall5', 'open'),\n# ('__syscall4', 'write')]\n```\n\n#### Control Flow Analysis\n\n```python\nfrom octopus.arch.wasm.cfg import WasmCFG\n\n# complete wasm module\nfile_name = \"examples/wasm/samples/fib.wasm\"\n\n# read file\nwith open(file_name, 'rb') as f:\n raw = f.read()\n\n# create the cfg\ncfg = WasmCFG(raw)\n\n# visualize CFGGraph \n# generate graph.dot and graph.pdf file\ncfg.visualize()\n```\n\n

\n \n

\n\n\n#### Functions' instructions analytics\n\n```python\nfrom octopus.arch.wasm.cfg import WasmCFG\n\n# complete wasm module\nfile_name = \"examples/wasm/samples/hello_wasm_studio.wasm\"\n\n# read file\nwith open(file_name, 'rb') as f:\n raw = f.read()\n\n# create the cfg\ncfg = WasmCFG(raw)\n\n# visualization\ncfg.visualize_instrs_per_funcs()\n```\n\n

\n \n

\n\n#### Call Flow Analysis\n\n```python\nfrom octopus.arch.wasm.cfg import WasmCFG\n\n# fibonacci wasm module\nfile_name = \"examples/wasm/samples/hello_wasm_studio.wasm\"\n\n# read file\nwith open(file_name, 'rb') as f:\n raw = f.read()\n\n# create the cfg\ncfg = WasmCFG(raw)\n\n# visualize Call Flow Graph\n# generate call_graph.dot and call_graph.pdf file\n# \n# color similar to https://webassembly.studio/\n# imported func == turquoise / exported func == grey\n# edge label = number of different calls to the function\ncfg.visualize_call_flow()\n```\n\n

\n \n

\n\nLegend: \n\n

\n \n

\n\n#### IR conversion (SSA)\n\n```python\nfrom octopus.arch.wasm.emulator import WasmSSAEmulatorEngine\n\n# complete wasm module\nfile_name = \"examples/wasm/samples/fib.wasm\"\n\n# read file\nwith open(file_name, 'rb') as f:\n raw = f.read()\n\n\n# run the emulator for SSA\nemul = WasmSSAEmulatorEngine(raw)\nemul.emulate_one_function('fib')\n# or emul.emulate_functions(['fib'])\n# or emul.emulate_functions() # emulate all the function\n\n# visualization of the cfg with SSA\nemul.cfg.visualize(ssa=True)\n```\n\n

\n \n

\n\n\n

\n
\n\n
Ethereum (ETH) - EVM\n

\n\n#### Explorer\n\n```python\nfrom octopus.platforms.ETH.explorer import EthereumInfuraExplorer\nfrom octopus.platforms.ETH.explorer import INFURA_ROPSTEN\n\nKEY_API = \"bHuaQhX91nkQBac8Wtgj\"\n# connection to ROPSTEN network (testnet)\nexplorer = EthereumInfuraExplorer(KEY_API, network=INFURA_ROPSTEN)\n\n# connection to MAINNET network (mainnet)\n# explorer = EthereumInfuraExplorer(KEY_API)\n\n# Test ROPSTEN network current block number\nblock_number = explorer.eth_blockNumber()\nprint(block_number)\n# 3675552\n\n# Retrieve code of this smart contract\naddr = \"0x3c6B10a5239B1a8A27398583F49771485382818F\"\ncode = explorer.eth_getCode(addr)\nprint(code)\n# 0x6060604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c14606e575b600080fd5b3415605857600080fd5b606c60048080359060200190919050506094565b005b3415607857600080fd5b607e609e565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a72305820e1f98c821c12eea52047d7324b034ddccc41eaa7365d369b34580ab73c71a8940029\n```\n\n#### Disassembler\n\n```python\nfrom octopus.platforms.ETH.disassembler import EthereumDisassembler\n\n# smart contract bytecode\nbytecode_hex = \"60606040526000357c0100000000000000000000000000000000000000000000000000000000900480635fd8c7101461004f578063c0e317fb1461005e578063f8b2cb4f1461006d5761004d565b005b61005c6004805050610099565b005b61006b600480505061013e565b005b610083600480803590602001909190505061017d565b6040518082815260200191505060405180910390f35b3373ffffffffffffffffffffffffffffffffffffffff16611111600060005060003373ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060005054604051809050600060405180830381858888f19350505050151561010657610002565b6000600060005060003373ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050819055505b565b34600060005060003373ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828282505401925050819055505b565b6000600060005060008373ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000505490506101b6565b91905056\"\n\ndisasm = EthereumDisassembler()\ndisasm.disassemble(bytecode_hex)\n\n# disassemble bytecode into a list of EthereumInstruction\n# attributes r_format='list' by default\nprint(disasm.disassemble(bytecode_hex))\n\n#[, , ]\n\nprint()\nprint(disasm.disassemble(bytecode_hex, r_format='reverse'))\n\n# {0: , ..., 229: , 230: }\n\nprint()\nprint(disasm.disassemble(bytecode_hex,r_format='text'))\n# PUSH1 0x60\n# PUSH1 0x40\n# MSTORE\n# PUSH1 0x0\n# CALLDATALOAD\n# PUSH29 0x100000000000000000000000000000000000000000000000000000000\n# SWAP1\n# DIV\n# DUP1\n# PUSH4 0x5fd8c710\n# EQ\n# PUSH2 0x4f\n# JUMPI\n# ...\n# SWAP2\n# SWAP1\n# POP\n# JUMP\n```\n\n#### Control Flow Analysis\n\n```python\nfrom octopus.analysis.graph import CFGGraph\nfrom octopus.platforms.ETH.cfg import EthereumCFG\n\n# ethernaut0 bytecode\nfile_name = \"examples/ETH/evm_bytecode/Zeppelin_Hello_ethernaut0.bytecode\"\n\n# read file\nwith open(file_name) as f:\n bytecode_hex = f.read()\n\n# create the CFG\ncfg = EthereumCFG(bytecode_hex)\n\n\n# generic visualization api\n# generate graph.dot and graph.pdf file\ngraph = CFGGraph(cfg)\ngraph.view()\n# or directly using the cfg binding\n# cfg.visualize()\n# and you can get a simplify cfg representation using\n# cfg.visualize(simplify=True) or graph.view(simplify=True)\n```\n\n

\n \n

\n\n#### IR conversion (SSA)\n\n```python\n# The conversion to SSA is already done by the SSAEmulator\n# when the CFG is reconstruct\n# by default you have just to visualize it\nfrom octopus.platforms.ETH.cfg import EthereumCFG\n\n# ethernaut0 bytecode\nfile_name = \"examples/ETH/evm_bytecode/Zeppelin_Hello_ethernaut0.bytecode\"\n\n# read file\nwith open(file_name) as f:\n bytecode_hex = f.read()\n\n# create the CFG\ncfg = EthereumCFG(bytecode_hex)\n\n# SSA visualization\ncfg.visualize(ssa=True)\n```\n\n

\n \n

\n\n\n

\n
\n\n
Ethereum (WASM)\n

\n\n#### Explorer\n\n```python\nfrom octopus.platforms.ETH.explorer import EthereumInfuraExplorer\nfrom octopus.platforms.ETH.explorer import INFURA_KOVAN\n\n# connection to ROPSTEN network (testnet)\nexplorer = EthereumInfuraExplorer(\"bHuaQhX91nkQBac8Wtgj\",\n network=INFURA_KOVAN)\n# connection to MAINNET network (mainnet)\n# explorer = EthereumInfuraExplorer(\"bHuaQhX91nkQBac8Wtgj\")\n\n# test infura access\nblock_number = explorer.eth_blockNumber()\nprint('blockNumber = %d' % block_number)\n\n# retrieve code of this smart contract\naddr = \"0x1120e596b173d953ba52ce262f73ce3734b0e40e\"\ncode = explorer.eth_getCode(addr)\nprint()\nprint(code)\n# blockNumber = 8803487\n# \n# 0x0061736d0100000001090260000060027f7f00021a0203656e7603726574000103656e76066d656d6f7279020102100303020000040501700101010501000601000708010463616c6c00010a120205001002000b0a00418008410b1000000b0b1201004180080b0b48656c6c6f20776f726c64000b076c696e6b696e6703010b0066046e616d65015f060003726574010570616e6963020463616c6c032f5f5a4e3134707761736d5f657468657265756d3365787433726574313768363034643830393864313638366338304504066465706c6f790511727573745f626567696e5f756e77696e64\n```\n\n#### Disassembler\n\nDisassembly of a Wasm module:\n```python\nfrom octopus.platforms.ETH.disassembler import EthereumDisassembler\n\nFILE = \"examples/ETH/wasm/helloworld_kovan.bytecode\"\n\nwith open(FILE, 'r') as f:\n module_bytecode = f.read()\n\ndisasm = EthereumDisassembler(arch='wasm')\n# return list of functions instructions (list)\nprint(disasm.disassemble_module(module_bytecode))\n#[[], [, , , , ]]\n\nprint()\n# return text of functions code\nprint(disasm.disassemble_module(module_bytecode, r_format='text'))\n# func 0\n# end\n# \n# func 1\n# call 1\n# i32.const 1036\n# i32.const 232\n# call 0\n# end\n\n```\n\nDisassembly of wasm bytecode:\n```python\nfrom octopus.platforms.ETH.disassembler import EthereumDisassembler\n\n# bytecode in WebAssembly is the function code (i.e. function body)\nbytecode = b'\\x02\\x7fA\\x18\\x10\\x1cA\\x00\\x0f\\x0b'\n# create a WasmDisassembler object\ndisasm = EthereumDisassembler(bytecode, arch='wasm')\n\n# disassemble bytecode into a list of WasmInstruction\n# attributes r_format='list' by default\nprint(disasm.disassemble())\n\n#[, , , , , ]\nprint()\nprint(disasm.disassemble(r_format='reverse'))\n\n#{0: , 1: , 2: , 3: , 4: , 5: }\nprint()\nprint(disasm.disassemble(r_format='text'))\n# block -1\n# i32.const 24\n# call 28\n# i32.const 0\n# return\n# end\n```\n\n#### ModuleAnalyzer\n\n```python\nfrom octopus.arch.wasm.analyzer import WasmModuleAnalyzer\n\nFILE = \"examples/ETH/wasm/helloworld_kovan.bytecode\"\n\nwith open(FILE, 'r') as f:\n module_bytecode = f.read()\n\n# return list of functions instructions (list)\n# attributes analysis=True by default\nanalyzer = WasmModuleAnalyzer(module_bytecode)\n\n# show analyzer attributes\nprint(analyzer.func_prototypes)\n# [('ret', 'i32 i32', '', 'import'), ('$func1', '', '', 'local'), ('call', '', '', 'export')]\nprint()\nprint(analyzer.exports)\n# [{'field_str': 'call', 'kind': 0, 'index': 2}]\nprint()\nprint(analyzer.imports_func)\n# [('env', 'ret', 1)]\nprint()\nprint(analyzer.datas)\n# [{'data': b'Hello world', 'index': 0, 'offset': None, 'size': 11},\n# {'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',\n# 'index': 0,\n# 'offset': None,\n# 'size': 232}]\n\n```\n\n#### Control Flow Analysis\n\n```python\nfrom octopus.platforms.ETH.cfg import EthereumCFG\n\n# HelloWorld on Kovan Parity Network\nfile_name = \"examples/ETH/wasm/helloworld_kovan.bytecode\"\n\n# read file\nwith open(file_name) as f:\n bytecode_hex = f.read()\n\n# create the CFG\ncfg = EthereumCFG(bytecode_hex, arch='wasm')\ncfg.visualize()\n```\n\n

\n \n

\n\n#### Functions' instructions analytics\n\n```python\nfrom octopus.platforms.ETH.cfg import EthereumCFG\n\n# HelloWorld on Kovan Parity Network\nfile_name = \"examples/ETH/wasm/helloworld_kovan.bytecode\"\n\n# read file\nwith open(file_name) as f:\n bytecode_hex = f.read()\n\n# create the CFG\ncfg = EthereumCFG(bytecode_hex, arch='wasm')\n\n# visualization\ncfg.visualize_instrs_per_funcs()\n```\n\n

\n \n

\n\n#### Call Flow Analysis\n\n```python\nfrom octopus.platforms.ETH.cfg import EthereumCFG\n\n# HelloWorld on Kovan Parity Network\nfile_name = \"examples/ETH/wasm/helloworld_kovan.bytecode\"\n\n# read file\nwith open(file_name) as f:\n bytecode_hex = f.read()\n\n# create the CFG\ncfg = EthereumCFG(bytecode_hex, arch='wasm')\n\n# visualization\ncfg.visualize_call_flow()\n```\n\n

\n \n

\n\nLegend: \n\n

\n \n

\n\n\n#### IR conversion (SSA)\n\n```python\n# TODO\n```\n\n\n

\n
\n\n
NEO\n

\n\n#### Explorer\n\n```python\nfrom octopus.platforms.NEO.explorer import NeoExplorerRPC\n\n# get list nodes here: http://monitor.cityofzion.io/\nexplorer = NeoExplorerRPC(host='seed2.neo.org')\n\n# get current number of block on the blockchain\nprint(explorer.getblockcount())\n# 2534868\n\n# get information on a contract\n# lock smart contract address: d3cce84d0800172d09c88ccad61130611bd047a4\ncontract = explorer.getcontractstate(\"d3cce84d0800172d09c88ccad61130611bd047a4\")\nprint(contract)\n# {'author': 'Erik Zhang',\n# 'code_version': '2.0',\n# 'description': 'Lock 2.0',\n# 'email': 'erik@neo.org',\n# 'hash': '0xd3cce84d0800172d09c88ccad61130611bd047a4',\n# 'name': 'Lock',\n# 'parameters': ['Integer', 'PublicKey', 'Signature'],\n# 'properties': {'dynamic_invoke': False, 'storage': False},\n# 'returntype': 'Boolean',\n# 'script': '56c56b6c766b00527ac46c766b51527ac46c766b52527ac4616168184e656f2e426c6f636b636861696e2e4765744865696768746168184e656f2e426c6f636b636861696e2e4765744865616465726c766b53527ac46c766b00c36c766b53c36168174e656f2e4865616465722e47657454696d657374616d70a06c766b54527ac46c766b54c3640e00006c766b55527ac4621a006c766b51c36c766b52c3617cac6c766b55527ac46203006c766b55c3616c7566',\n# 'version': 0}\n\n# smart contract code in contract['script']\nprint(contract['script'])\n```\n\n#### Disassembler\n\n```python\nfrom octopus.platforms.NEO.disassembler import NeoDisassembler\n\n# lock contract\nfile_name = \"examples/NEO/samples/Lock.bytecode\"\n\n# read file\nwith open(file_name) as f:\n bytecode = f.read()\n\ndisasm = NeoDisassembler()\n\nprint(disasm.disassemble(bytecode, r_format='text'))\n# PUSH6\n# NEWARRAY\n# TOALTSTACK\n# FROMALTSTACK\n# DUP\n# TOALTSTACK\n# PUSH0\n# PUSH2\n# ROLL\n# SETITEM\n# FROMALTSTACK\n# ....\n# PICKITEM\n# NOP\n# FROMALTSTACK\n# DROP\n# RET\n```\n\n#### Control Flow Analysis\n\n```python\nfrom octopus.analysis.graph import CFGGraph\nfrom octopus.platforms.NEO.cfg import NeoCFG\n\n# lock contract\nfile_name = \"examples/NEO/samples/Lock.bytecode\"\n\n# read file\nwith open(file_name) as f:\n raw = f.read()\n\n# create neo cfg - automatic static analysis\ncfg = NeoCFG(raw)\n\n# graph visualization\ngraph = CFGGraph(cfg, filename=\"Lock_cfg\")\ngraph.view_functions()\n```\n\n

\n \n

\n\n\n

\n
\n\n
EOS\n

\n\n#### Explorer\n\n```python\nfrom octopus.platforms.EOS.explorer import EosExplorer\n\nhost = \"api.cypherglass.com\"\n\n# by defaul the port is 8888\nexplo = EosExplorer(host=host)\n\n# get info about the node\nexplo.get_info()\n\n'''\n{'block_cpu_limit': 180289,\n 'block_net_limit': 1045680,\n 'chain_id': 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906',\n 'head_block_id': '018d6e2bcf6295126cd74cf694b5cca3529eefc42b334b394ef87c3a43876739',\n 'head_block_num': 26045995,\n 'head_block_producer': 'eosswedenorg',\n 'head_block_time': '2018-11-09T14:11:29.500',\n 'last_irreversible_block_id': '018d6cdcff78bbd9f25c605b02fb67c47a337ece78ddcf73089cee4bf6a410ee',\n 'last_irreversible_block_num': 26045660,\n 'server_version': 'c71d2245',\n 'server_version_string': 'mainnet-1.3.0',\n 'virtual_block_cpu_limit': 38092879,\n 'virtual_block_net_limit': 1048576000}\n'''\nexplo.get_block(1337)\n\n'''\n{'action_mroot': 'bcb9763baa3bbf98ed36379b4be0ecb2d9cd21c75df01729c63b2b021001c10c',\n 'block_extensions': [],\n 'block_num': 1337,\n 'confirmed': 0,\n 'header_extensions': [],\n 'id': '00000539d17a03af7126e073be4c4d99a72b7f58793cf2c87b9bfd41b6c711fb',\n 'new_producers': None,\n 'previous': '00000538b374c1cbfaeed7253ad3075ddc72a28f0a0515301fc1bbed675f2316',\n 'producer': 'eosio',\n 'producer_signature': 'SIG_K1_K5jWf36t6j454Hb2fGuV37YTwMTvuQ51ZPBtpru8Ud2axtMTEauWyvtpJuTpnvqzReUndDgEDXvoeEP4jdj2bpnYKBt6g2',\n 'ref_block_prefix': 1944069745,\n 'schedule_version': 0,\n 'timestamp': '2018-06-09T12:09:21.500',\n 'transaction_mroot': '0000000000000000000000000000000000000000000000000000000000000000',\n 'transactions': []}\n'''\n```\n\n#### Disassembler\n\n```python\nfrom octopus.platforms.EOS.disassembler import EosDisassembler\n\n# complete wasm module\nfile_name = \"examples/EOS/samples/eos_ping.wasm\"\n\n# read file\nwith open(file_name, 'rb') as f:\n raw = f.read()\n\n# just disassembly\ndisasm = EosDisassembler()\n\n# because we provide full module bytecode\n# we need to use disassemble_module()\n# otherwise just disassemble() is enough\ntext = disasm.disassemble_module(raw, r_format=\"text\")\nprint(text)\n# func 0\n# get_local 0\n# get_local 1\n# i32.const 32\n# call 12\n# i32.eqz\n# end\n# \n# func 1\n# get_local 0\n# i64.load 3, 0\n# get_local 0\n# i64.load 3, 8\n# call 6\n# end\n# \n# func 2\n# ...\n# end\n# \n# ...\n```\n\n#### ModuleAnalyzer\n\n```python\n\nfrom octopus.platforms.EOS.analyzer import EosAnalyzer\n\n# complete wasm module\nfile_name = \"examples/EOS/samples/eos_ping.wasm\"\n\nwith open(file_name, 'rb') as f:\n module_bytecode = f.read()\n\n# return list of functions instructions (list)\n# attributes analysis=True by default\nanalyzer = EosAnalyzer(module_bytecode)\n\n# show analyzer attributes\nprint(analyzer.func_prototypes)\n#[('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')]\nprint()\nprint(analyzer.exports)\n# [{'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}]\nprint()\nprint(analyzer.imports_func)\n# [('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)]\n```\n\n#### Control Flow Analysis\n\n```python\nfrom octopus.platforms.EOS.cfg import EosCFG\nfrom octopus.analysis.graph import CFGGraph\n\n# complete wasm module\nfile_name = \"examples/EOS/samples/eos_ping.wasm\"\n\n# read file\nwith open(file_name, 'rb') as f:\n raw = f.read()\n\n# create the cfg\ncfg = EosCFG(raw)\n\n# visualize\ngraph = CFGGraph(cfg)\ngraph.view_functions()\n```\n\n\n

\n \n

\n\n#### Call Flow Analysis\n\n```python\nfrom octopus.platforms.EOS.cfg import EosCFG\n\n# complete wasm module\nfile_name = \"examples/EOS/samples/eos_ping.wasm\"\n\n# read file\nwith open(file_name, 'rb') as f:\n raw = f.read()\n\n# create the cfg\ncfg = EosCFG(raw)\n\n# visualize\ncfg.visualize_call_flow()\n```\n\n

\n \n

\n\n#### Functions' instructions analytics\n\n```python\nfrom octopus.platforms.EOS.cfg import EosCFG\n\n# complete wasm module\nfile_name = \"examples/EOS/samples/eos_ping.wasm\"\n\n# read file\nwith open(file_name, 'rb') as f:\n raw = f.read()\n\n# create the cfg\ncfg = EosCFG(raw)\n\n# visualize\ncfg.visualize_instrs_per_funcs()\n```\n\n

\n \n

\n\n

\n
\n\n
Bitcoin\n

\n\n#### Explorer\n\n```python\nfrom octopus.platforms.BTC.explorer import BitcoinExplorerRPC\n\nRPC_USER = 'test'\nRPC_PASSWORD = 'test'\nRPC_HOST = 'localhost'\n\nhost = '%s:%s@%s' % (RPC_USER, RPC_PASSWORD, RPC_HOST)\n\nexplorer = BitcoinExplorerRPC(host)\n\nexplorer.getbestblockhash()\n# '00000000000000000012085cfe8c79bcdacf81fbd82f6ab52c3cb3a454d4987c'\n\nexplorer.getblockcount()\n#550859\n```\n\n#### Disassembler\n\n```python\nfrom octopus.platforms.BTC.disassembler import BitcoinDisassembler\n\n# Witness Script\nfile_name = \"examples/BTC/witness_script.hex\"\n\n# read file\nwith open(file_name) as f:\n bytecode = f.read()\n\ndisasm = BitcoinDisassembler()\n\nprint(disasm.disassemble(bytecode, r_format='text'))\n# 0\n# OP_ROT\n# OP_ROT\n# 2\n# 0203f4d01d0b35588638631ebb7d46d8387fd1aeb3dbecfdd3faf7c056b023c833\n# 03aa6677e3ce1bd634f4f2e1cd60a60af002e1b30484d4d1611b183b16d391ee96\n# 03bf164811abb8c91ed39e58d4e307f86cb4e487c83f727a2c482bc71a0f96f1db\n# 3\n# OP_CHECKMULTISIG\n```\n\n

\n
\n\n\nPlease find examples in [examples](examples) folder.\n\n## Publications and Videos\n\n* BLACKALPS 2018 [Reversing and Vulnerability research of Ethereum Smart Contracts](https://www.blackalps.ch/ba-18/talks.php#111)\n* Devcon iv. [Reversing Ethereum Smart Contracts to find out what's behind EVM bytecode](https://guidebook.com/guide/117233/event/21956134/)\n* hack.lu 2018 [Reversing and Vulnerability research of Ethereum Smart Contracts](https://2018.hack.lu/talks/#Reversing+and+Vulnerability+research+of+Ethereum+Smart+Contracts)\n* ToorCon XX - 2018 [Reversing Ethereum Smart Contracts (Introduction)](https://frab.toorcon.net/en/toorcon20/public/events/97)\n* ToorCon XX - 2018 [Dissection of WebAssembly module](https://frab.toorcon.net/en/toorcon20/public/events/92)\n* REcon Montreal 2018: [Reverse Engineering Of Blockchain Smart Contracts](https://recon.cx/2018/montreal/schedule/system/event_attachments/attachments/000/000/053/original/RECON-MTL-2018-Reversing_blockchains_smart_contracts.pdf)\n\n## Authors\n\n**Patrick Ventuzelo** - *Creator* - [@Pat_Ventuzelo](https://twitter.com/pat_ventuzelo)\n\nSee also the list of [contributors](https://github.com/quoscient/octopus/contributors) who participated in this project.\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details\n\n## Acknowledgments\n\nInspired by:\n* [Manticore](https://github.com/trailofbits/manticore)\n* [Mythril](https://github.com/ConsenSys/mythril)\n* [Rattle](https://github.com/trailofbits/rattle)\n* [ethersplay](https://github.com/trailofbits/ethersplay)\n* ...\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/quoscient/octopus", "keywords": "disassembler security webassembly ethereum eos neo", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "octopus", "package_url": "https://pypi.org/project/octopus/", "platform": "", "project_url": "https://pypi.org/project/octopus/", "project_urls": { "Homepage": "https://github.com/quoscient/octopus" }, "release_url": "https://pypi.org/project/octopus/0.3.4/", "requires_dist": [ "z3-solver (>=4.5)", "requests (>=2.18.4)", "graphviz (>=0.8.3)", "wasm (>=1.1)" ], "requires_python": ">=3.5", "summary": "Security analysis framework for WebAssembly module (wasm) and Blockchain Smart Contract (BTC/ETH/EOS/NEO).", "version": "0.3.4" }, "last_serial": 4574840, "releases": { "0.1.1": [ { "comment_text": "", "digests": { "md5": "2afddfd2dd7d0ef396bd34f7865b8a13", "sha256": "cc89713279c6074b06c078ef9a4ef295a89cee56b42be8b26fbdee786550078c" }, "downloads": -1, "filename": "octopus-0.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "2afddfd2dd7d0ef396bd34f7865b8a13", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 126105, "upload_time": "2018-07-24T10:32:13", "url": "https://files.pythonhosted.org/packages/83/29/535406724590f3e8e644e263de0475ad38a028d1c5addaca50dfabf2d3fc/octopus-0.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "975cf617e377505b92757dafc1c17a70", "sha256": "eded95a844ac7735147280d0e8e99c376be98dae49071f0906730a120d844ab6" }, "downloads": -1, "filename": "octopus-0.1.1.tar.gz", "has_sig": false, "md5_digest": "975cf617e377505b92757dafc1c17a70", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 105620, "upload_time": "2018-07-24T10:32:15", "url": "https://files.pythonhosted.org/packages/e9/c7/6d54404f29cc25dc769b7c00021a9362bfd3d725b1159252cfdf0f3e9200/octopus-0.1.1.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "0e66ebf1448253803b8867beb263bdd7", "sha256": "762e0280b99ca5bb50b9647c865cd00242106870f6896ced0fe79df83a512f92" }, "downloads": -1, "filename": "octopus-0.1.2-py3-none-any.whl", "has_sig": false, "md5_digest": "0e66ebf1448253803b8867beb263bdd7", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 126439, "upload_time": "2018-07-24T21:24:32", "url": "https://files.pythonhosted.org/packages/9b/83/d031c3392c6e5b78d771cd287cedd8f64586dfb3f74c6a867b1b1266c7bd/octopus-0.1.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "3468c6c7c18ea3471ec76ccc4d73e358", "sha256": "2c629acf107865c4c0a438ea5f254df97475a9a8104b24ccc22bfde6388c704c" }, "downloads": -1, "filename": "octopus-0.1.2.tar.gz", "has_sig": false, "md5_digest": "3468c6c7c18ea3471ec76ccc4d73e358", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 106004, "upload_time": "2018-07-24T21:24:34", "url": "https://files.pythonhosted.org/packages/0a/47/4679d161a5282f1a8051e8492abeab1423ce9a1ed6ddac9148ab52cedf55/octopus-0.1.2.tar.gz" } ], "0.1.3": [ { "comment_text": "", "digests": { "md5": "54bbdb23744582297d788b156891aed1", "sha256": "ebf49d4835779b0a841db09376124ba356b019904789ebe4d7e6c819b99776c3" }, "downloads": -1, "filename": "octopus-0.1.3-py3-none-any.whl", "has_sig": false, "md5_digest": "54bbdb23744582297d788b156891aed1", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 126419, "upload_time": "2018-07-26T10:08:56", "url": "https://files.pythonhosted.org/packages/0f/35/88b1914b95351029e095341308b53e993404c5f64fab2996f75bdd074afd/octopus-0.1.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "db4d0d5169ddafc7422abdc0d18cd17c", "sha256": "0b847e0af1699755c979b098c4d2effb9c685905cd087ac8772b1730742db7cb" }, "downloads": -1, "filename": "octopus-0.1.3.tar.gz", "has_sig": false, "md5_digest": "db4d0d5169ddafc7422abdc0d18cd17c", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 106004, "upload_time": "2018-07-26T10:08:58", "url": "https://files.pythonhosted.org/packages/8e/b9/b34b96f489e9021aadc82ca268313fc9bdef02d07f2bb09ff9f029e9b8ed/octopus-0.1.3.tar.gz" } ], "0.1.4": [ { "comment_text": "", "digests": { "md5": "82287c2985e5548b07c00960307316bf", "sha256": "0e4f113b1c1700a0d1ab70cedf4f2b1e7d5e2318847b456e86ea1574de1dd97d" }, "downloads": -1, "filename": "octopus-0.1.4-py3-none-any.whl", "has_sig": false, "md5_digest": "82287c2985e5548b07c00960307316bf", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 126419, "upload_time": "2018-07-26T11:51:27", "url": "https://files.pythonhosted.org/packages/f4/7a/add68220e893902697726be280cf5892917436856d1a5e9fea86d8ee5542/octopus-0.1.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "51c75d77636f276fdeb52117df8afeff", "sha256": "a8c79ae69cc1a2d35d7474782e1c7def4a2b30ea981e86af711c78cacd2a17c5" }, "downloads": -1, "filename": "octopus-0.1.4.tar.gz", "has_sig": false, "md5_digest": "51c75d77636f276fdeb52117df8afeff", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 106005, "upload_time": "2018-07-26T11:51:29", "url": "https://files.pythonhosted.org/packages/ef/a8/f3d7bb6334bd430214cd13fc508a763527bbd52ec284915627544d4dc073/octopus-0.1.4.tar.gz" } ], "0.1.5": [ { "comment_text": "", "digests": { "md5": "d7c6a7579761717a9acf5f789359095f", "sha256": "60dc979938d673df7b10e02985f096eecf559d08c7102a018bbf1d52243bcd5a" }, "downloads": -1, "filename": "octopus-0.1.5-py3-none-any.whl", "has_sig": false, "md5_digest": "d7c6a7579761717a9acf5f789359095f", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 128948, "upload_time": "2018-09-06T07:22:52", "url": "https://files.pythonhosted.org/packages/39/09/086952d552853f46e1e77f2b1f57b4220c30273d8e17d462d65d439c790d/octopus-0.1.5-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7d934b2d2a8445dff4f2c6fe8692a1ef", "sha256": "0f1ec063805649f3d5fe9a37c70c99313b346a1592f62076e87ed2fc66d7bd17" }, "downloads": -1, "filename": "octopus-0.1.5.tar.gz", "has_sig": false, "md5_digest": "7d934b2d2a8445dff4f2c6fe8692a1ef", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 108873, "upload_time": "2018-09-06T07:22:54", "url": "https://files.pythonhosted.org/packages/ee/94/29b1d7b738c10bc15de7d32c434460a90f9939790c2769db062da76baaee/octopus-0.1.5.tar.gz" } ], "0.1.6": [ { "comment_text": "", "digests": { "md5": "2ddd4fe97ab1a5df5262e8dccf6f98e6", "sha256": "ab6e61531e2689f8c1533e1d0701e7039421a9e1bf754210fad66e7ce7e06249" }, "downloads": -1, "filename": "octopus-0.1.6-py3-none-any.whl", "has_sig": false, "md5_digest": "2ddd4fe97ab1a5df5262e8dccf6f98e6", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 130684, "upload_time": "2018-09-13T16:31:22", "url": "https://files.pythonhosted.org/packages/7d/7c/950dc0e3cbd3a4b00394242e29589c7d2348508dc254af372e36545b3767/octopus-0.1.6-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "00de6c99d4103765fa2f5e4eb6a32a75", "sha256": "3beacbcb6d8f148f5d8bd56e5d2192d627ecb8e04503475559e91a93d744c95b" }, "downloads": -1, "filename": "octopus-0.1.6.tar.gz", "has_sig": false, "md5_digest": "00de6c99d4103765fa2f5e4eb6a32a75", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 110783, "upload_time": "2018-09-13T16:31:25", "url": "https://files.pythonhosted.org/packages/7e/f4/c64e467844537a0090d56ef897b401f6b876dfab266a7b8c23eeede0a620/octopus-0.1.6.tar.gz" } ], "0.1.7": [ { "comment_text": "", "digests": { "md5": "30ee78f6f4a70dc9cd396fff9e1a611e", "sha256": "e4f06af85bff04ee640ff1071527e71b9c6617adbacea0160c53c561ea8bda48" }, "downloads": -1, "filename": "octopus-0.1.7-py3-none-any.whl", "has_sig": false, "md5_digest": "30ee78f6f4a70dc9cd396fff9e1a611e", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 137240, "upload_time": "2018-10-11T12:06:13", "url": "https://files.pythonhosted.org/packages/9e/7a/c24456d400c929db83e8a4a262f7362b13b3e8454111b3b528aab8a489b2/octopus-0.1.7-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "eb30a857aea05501ef327c3ddc90b5b8", "sha256": "ecf776d01c386c492c2565f625a7c853b2962c77d542729429a30086e36454a6" }, "downloads": -1, "filename": "octopus-0.1.7.tar.gz", "has_sig": false, "md5_digest": "eb30a857aea05501ef327c3ddc90b5b8", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 121186, "upload_time": "2018-10-11T12:06:15", "url": "https://files.pythonhosted.org/packages/fa/49/b70e41134c4d290218fcfa9307884358ed5ed561dc116d7ae3466e1a254f/octopus-0.1.7.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "acef589adad655b28d096997e6b01f29", "sha256": "7bfe85d67d02c7900ae418bea866fb27522d2321407d34a79641e05edae294f1" }, "downloads": -1, "filename": "octopus-0.2.1-py3-none-any.whl", "has_sig": false, "md5_digest": "acef589adad655b28d096997e6b01f29", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 141796, "upload_time": "2018-10-12T13:20:07", "url": "https://files.pythonhosted.org/packages/f7/bb/78287358c02ac861dd7aed66ed0eed0ae3593e842ad0e2a501fc8a7a5489/octopus-0.2.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "38eef54def5daf9f8512b1973f8f7a5d", "sha256": "7009076728f42645b7dc0b30bfabab671fb6ee0d918d800faca9870098a67a4f" }, "downloads": -1, "filename": "octopus-0.2.1.tar.gz", "has_sig": false, "md5_digest": "38eef54def5daf9f8512b1973f8f7a5d", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 123547, "upload_time": "2018-10-12T13:20:09", "url": "https://files.pythonhosted.org/packages/d9/eb/98cf3c8ef5084b7560bd983fc4e911992432d905675a958616c5ba4125cd/octopus-0.2.1.tar.gz" } ], "0.2.2": [ { "comment_text": "", "digests": { "md5": "e82c6106adcfd78a948c08e6d33d6b26", "sha256": "e2743a0ffc71c4a29382d00e69c74e9d7d7115843029618949d25caeee27fc93" }, "downloads": -1, "filename": "octopus-0.2.2-py3-none-any.whl", "has_sig": false, "md5_digest": "e82c6106adcfd78a948c08e6d33d6b26", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 139968, "upload_time": "2018-10-12T13:27:42", "url": "https://files.pythonhosted.org/packages/50/a9/608005a74f33034bc53ebbfc8455951a4a5d26d9b626f0f743e2cdbeb082/octopus-0.2.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "af50362d6ab4916b2b01282c0d9f9126", "sha256": "9f423174ef224334a97009a2081ad4bf735b9ebf9d1f80d1c34784da0c57e826" }, "downloads": -1, "filename": "octopus-0.2.2.tar.gz", "has_sig": false, "md5_digest": "af50362d6ab4916b2b01282c0d9f9126", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 125449, "upload_time": "2018-10-12T13:27:44", "url": "https://files.pythonhosted.org/packages/e7/5b/ce8c56556ad0e8b204498be8ea0da4e8279dcab2c06ba78f7db5da9eb088/octopus-0.2.2.tar.gz" } ], "0.2.4": [ { "comment_text": "", "digests": { "md5": "62fda6604ef7141106d014b4485f0cf9", "sha256": "2149a549d019d47859e5f80a7e9646fdedc907fe1cd332e95157ffad29133cdc" }, "downloads": -1, "filename": "octopus-0.2.4-py3-none-any.whl", "has_sig": false, "md5_digest": "62fda6604ef7141106d014b4485f0cf9", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 142029, "upload_time": "2018-10-12T14:17:59", "url": "https://files.pythonhosted.org/packages/dd/ea/904d2abdf1fe2500555635503e54bdb3c1b7d9df5872b90a4d4c55470bca/octopus-0.2.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "d5c9b2f98121f1e8113d4848b66f95af", "sha256": "9473d36886d631b905f9a2e5d95063ca9d48af73e0b3fb93f4a416e825a14d09" }, "downloads": -1, "filename": "octopus-0.2.4.tar.gz", "has_sig": false, "md5_digest": "d5c9b2f98121f1e8113d4848b66f95af", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 123658, "upload_time": "2018-10-12T14:18:00", "url": "https://files.pythonhosted.org/packages/fe/3e/7f76325002787fd15a6a0a0f0fa9f9c2c73439b89ba1c878ffdc6bc38384/octopus-0.2.4.tar.gz" } ], "0.2.5": [ { "comment_text": "", "digests": { "md5": "05c9fd7d3f405f097b1bd816772c793b", "sha256": "6e9a4d63cb11f94d41db3fca53437522bb4a5327401b8141b3928a0adca11c26" }, "downloads": -1, "filename": "octopus-0.2.5-py3-none-any.whl", "has_sig": false, "md5_digest": "05c9fd7d3f405f097b1bd816772c793b", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 1819100, "upload_time": "2018-10-12T14:38:09", "url": "https://files.pythonhosted.org/packages/00/a4/e499145b7d2b01357bb166dbcbef5aa8948de7744d9543bafa25f27d0729/octopus-0.2.5-py3-none-any.whl" } ], "0.2.6": [ { "comment_text": "", "digests": { "md5": "8ef399afd0749d04183b57167cc955cd", "sha256": "cf3eb60b9314fa2e869bb22ec0f8fecf2631e8a511b98078cb4987784814c1df" }, "downloads": -1, "filename": "octopus-0.2.6-py3-none-any.whl", "has_sig": false, "md5_digest": "8ef399afd0749d04183b57167cc955cd", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 1819094, "upload_time": "2018-10-12T15:25:00", "url": "https://files.pythonhosted.org/packages/0c/6d/476169569f53aa5a0cc97f033fc8082a7212a1ecbc307aacb8b0addc4366/octopus-0.2.6-py3-none-any.whl" } ], "0.2.7": [ { "comment_text": "", "digests": { "md5": "608188f69d8066fa39c55566db0b245b", "sha256": "eecccba5b5c7c2d507c7b95053196610d20a76bddf13a812103e960b600d28f3" }, "downloads": -1, "filename": "octopus-0.2.7-py3-none-any.whl", "has_sig": false, "md5_digest": "608188f69d8066fa39c55566db0b245b", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 1819095, "upload_time": "2018-10-12T15:25:43", "url": "https://files.pythonhosted.org/packages/bc/b9/178002d198b9c6355824d35798ffa366307058f4a83ab0d0573fe1f81631/octopus-0.2.7-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a7a8089e35a4d159e3e6e65dbda8224f", "sha256": "aad588f733656eabe75a5321b6388b249e97a2714d32f59a8600f918cfa691c4" }, "downloads": -1, "filename": "octopus-0.2.7.tar.gz", "has_sig": false, "md5_digest": "a7a8089e35a4d159e3e6e65dbda8224f", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 1780206, "upload_time": "2018-10-12T15:25:48", "url": "https://files.pythonhosted.org/packages/ec/75/4d76e1db2f11a4c33c2c215b5ad323ca29227ebb30e71de456062fd7c31b/octopus-0.2.7.tar.gz" } ], "0.2.8": [ { "comment_text": "", "digests": { "md5": "7e2971296c9329f80f5d55dca03abec1", "sha256": "381efef9bda76bdee9eb7343fcf38f790a4c2736d9b09e1a38159b4d10e41fbc" }, "downloads": -1, "filename": "octopus-0.2.8-py3-none-any.whl", "has_sig": false, "md5_digest": "7e2971296c9329f80f5d55dca03abec1", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 1819092, "upload_time": "2018-10-12T15:32:05", "url": "https://files.pythonhosted.org/packages/09/64/eb9270dee67d5fbea81398196783e895e92199e3e0d5083f1fa3757bfd55/octopus-0.2.8-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "1a1f967cb2ef68e7cd4155cc1c899cfb", "sha256": "0d3f4eafcccfdfb01ef44181e190b4dbe0dc50b9c6a50cdb22601c9056482bbe" }, "downloads": -1, "filename": "octopus-0.2.8.tar.gz", "has_sig": false, "md5_digest": "1a1f967cb2ef68e7cd4155cc1c899cfb", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 1780196, "upload_time": "2018-10-12T15:32:10", "url": "https://files.pythonhosted.org/packages/30/03/f521de556e1a1ac455c841e54f04650180f5a6ffd619737127707f2f3f24/octopus-0.2.8.tar.gz" } ], "0.2.9": [ { "comment_text": "", "digests": { "md5": "e7c20e85e0eb6c80593a882580b89793", "sha256": "2c3dd45811b142d36db85a86aec1d7cbc0fc2cff36d9c64d15c15d460d6ca07b" }, "downloads": -1, "filename": "octopus-0.2.9-py3-none-any.whl", "has_sig": false, "md5_digest": "e7c20e85e0eb6c80593a882580b89793", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 1814939, "upload_time": "2018-10-12T15:41:36", "url": "https://files.pythonhosted.org/packages/56/2a/dc7d1b691af532141d829af1900c792738cd0cb13e9ef8bdd7a0a446cce0/octopus-0.2.9-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "e866e5810c7543ecd3f5177ab7ce4cc6", "sha256": "c534e5c72cbff6e66ac1bf1e47254be4d56cf124e9f24ef03ad7d551502917b0" }, "downloads": -1, "filename": "octopus-0.2.9.tar.gz", "has_sig": false, "md5_digest": "e866e5810c7543ecd3f5177ab7ce4cc6", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 1780199, "upload_time": "2018-10-12T15:41:42", "url": "https://files.pythonhosted.org/packages/e0/d0/7aa9ee15280cbc613b02bd82ba4b8e23608c19b13cbfdb7c53df63e29196/octopus-0.2.9.tar.gz" } ], "0.3.0": [ { "comment_text": "", "digests": { "md5": "d9302465ab4e65b0aacb37227c4c9435", "sha256": "34d291c53abe0e4f8b8645e1b3a4f421165f70d6a9ff5ef7b8137fe922097ee5" }, "downloads": -1, "filename": "octopus-0.3.0-py3-none-any.whl", "has_sig": false, "md5_digest": "d9302465ab4e65b0aacb37227c4c9435", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 1814944, "upload_time": "2018-10-12T15:56:01", "url": "https://files.pythonhosted.org/packages/73/80/2c87d47f72cfb2407954ea4add8acf626dd88f017412abb89039cae265f2/octopus-0.3.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "1d0f671c80199d557942cc31560e38cc", "sha256": "9ffeb5feeb132b61345f3cd2e5dc84e4e68f3398f5ec355f41acb9a0b99ff873" }, "downloads": -1, "filename": "octopus-0.3.0.tar.gz", "has_sig": false, "md5_digest": "1d0f671c80199d557942cc31560e38cc", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 1780204, "upload_time": "2018-10-12T15:56:06", "url": "https://files.pythonhosted.org/packages/c7/32/311251eea480f86ed7b0c8fe643a67940a420834bd5e62482a6749901d5c/octopus-0.3.0.tar.gz" } ], "0.3.1": [ { "comment_text": "", "digests": { "md5": "113f762d2287ed2eaa473f34f00da2b9", "sha256": "2dc9e6f409c746ea5e88f5c671417d029d5f30ec0a365aad1ae2c9b248c62d2d" }, "downloads": -1, "filename": "octopus-0.3.1-py3-none-any.whl", "has_sig": false, "md5_digest": "113f762d2287ed2eaa473f34f00da2b9", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 1815047, "upload_time": "2018-10-12T20:33:50", "url": "https://files.pythonhosted.org/packages/bc/1d/36013b05416f11052b82b1d1e369838acfd2b9e278e21fae0bf725f890aa/octopus-0.3.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7341bd6d2b038fe6053ba657553c80bf", "sha256": "0eb9ed17e5ee74a158b85eea5553acc9db4a53f93c79329249b5c49c4d908243" }, "downloads": -1, "filename": "octopus-0.3.1.tar.gz", "has_sig": false, "md5_digest": "7341bd6d2b038fe6053ba657553c80bf", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 1780341, "upload_time": "2018-10-12T20:33:55", "url": "https://files.pythonhosted.org/packages/8e/ed/b016917fa596b60cd5235369df412ed8c74690932a001c86550b71fd0d0b/octopus-0.3.1.tar.gz" } ], "0.3.2": [ { "comment_text": "", "digests": { "md5": "7de864dcf000030333932637d2c3cc29", "sha256": "1c9e4d554707379e30634c20b9e71934a68049ca9858639caf122dc49ed0401a" }, "downloads": -1, "filename": "octopus-0.3.2-py3-none-any.whl", "has_sig": false, "md5_digest": "7de864dcf000030333932637d2c3cc29", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 1815047, "upload_time": "2018-10-12T20:35:03", "url": "https://files.pythonhosted.org/packages/e4/29/d40194ed475d64231927b5715f9c47ebf1e8b6a5ce41a67d80a2e46f9f9f/octopus-0.3.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "37a62cce17e7d70af22a83cca06b0831", "sha256": "10efc6cd599e374684d849c038f32a2cb8cc65170f8efe33da7599fcec23a639" }, "downloads": -1, "filename": "octopus-0.3.2.tar.gz", "has_sig": false, "md5_digest": "37a62cce17e7d70af22a83cca06b0831", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 1780355, "upload_time": "2018-10-12T20:35:09", "url": "https://files.pythonhosted.org/packages/55/5a/999937abcc93d7a8ffb6db3c9a664f032b86658bdb74900b6e7dd0de6d2e/octopus-0.3.2.tar.gz" } ], "0.3.3": [ { "comment_text": "", "digests": { "md5": "d0ede9c5eaa990710ca2d7c1c7e597b1", "sha256": "f98fad75a97001f27cbe13735be10babe46425f54c293a06f1e2ecc6959ef5cc" }, "downloads": -1, "filename": "octopus-0.3.3-py3-none-any.whl", "has_sig": false, "md5_digest": "d0ede9c5eaa990710ca2d7c1c7e597b1", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 1816642, "upload_time": "2018-11-19T08:39:23", "url": "https://files.pythonhosted.org/packages/f2/b4/ecc3c2c721cd6e678046bf8a2ccc44e2b2db50703fea908c2e7de84cf73e/octopus-0.3.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "e2281ef32b56db21182f48d3700211b0", "sha256": "3c77eacfd39f67eddd37de22b5a6bbd473f6abd8e7a0e69eb3447858a0f485eb" }, "downloads": -1, "filename": "octopus-0.3.3.tar.gz", "has_sig": false, "md5_digest": "e2281ef32b56db21182f48d3700211b0", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 1787288, "upload_time": "2018-11-19T08:39:28", "url": "https://files.pythonhosted.org/packages/cb/13/4cc91da3152af85d2d6c9f72d5f6db2461c874c21c052557e7079e5c7b73/octopus-0.3.3.tar.gz" } ], "0.3.4": [ { "comment_text": "", "digests": { "md5": "0046127c70ecbcb5a9806d85077a5f80", "sha256": "f25cda86160fa3198cb136312bef939367f5f74af842bcea31673d56acc4d516" }, "downloads": -1, "filename": "octopus-0.3.4-py3-none-any.whl", "has_sig": false, "md5_digest": "0046127c70ecbcb5a9806d85077a5f80", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 1818120, "upload_time": "2018-12-08T09:31:14", "url": "https://files.pythonhosted.org/packages/db/14/e58e19dbe4e2a14a65e6b682e34a7e1d4c105eb9fdd40b4c7c07517b9a2e/octopus-0.3.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "3c32675d10d6357c1efa793652387a21", "sha256": "ee5ec7db118fd8963dd929de48fb84b0b0263767e887db8d9d5e263d7b2ad3e1" }, "downloads": -1, "filename": "octopus-0.3.4.tar.gz", "has_sig": false, "md5_digest": "3c32675d10d6357c1efa793652387a21", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 1789686, "upload_time": "2018-12-08T09:31:20", "url": "https://files.pythonhosted.org/packages/93/81/b7e82d4b92b53b127dbef4971c7f3690d7703afeaa0f832e2ac7601c650e/octopus-0.3.4.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "0046127c70ecbcb5a9806d85077a5f80", "sha256": "f25cda86160fa3198cb136312bef939367f5f74af842bcea31673d56acc4d516" }, "downloads": -1, "filename": "octopus-0.3.4-py3-none-any.whl", "has_sig": false, "md5_digest": "0046127c70ecbcb5a9806d85077a5f80", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 1818120, "upload_time": "2018-12-08T09:31:14", "url": "https://files.pythonhosted.org/packages/db/14/e58e19dbe4e2a14a65e6b682e34a7e1d4c105eb9fdd40b4c7c07517b9a2e/octopus-0.3.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "3c32675d10d6357c1efa793652387a21", "sha256": "ee5ec7db118fd8963dd929de48fb84b0b0263767e887db8d9d5e263d7b2ad3e1" }, "downloads": -1, "filename": "octopus-0.3.4.tar.gz", "has_sig": false, "md5_digest": "3c32675d10d6357c1efa793652387a21", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 1789686, "upload_time": "2018-12-08T09:31:20", "url": "https://files.pythonhosted.org/packages/93/81/b7e82d4b92b53b127dbef4971c7f3690d7703afeaa0f832e2ac7601c650e/octopus-0.3.4.tar.gz" } ] }