衷心感谢 QuoScient 对本项目的赞助。
Octopus 是一个用于 WebAssembly 模块和区块链智能合约的安全分析框架。
Octopus 旨在提供一种简单的方式来分析闭源的 WebAssembly 模块和智能合约字节码,从而更深入地理解其内部行为。
Octopus 支持以下类型的程序/智能合约:
| BTC | ETH (EVM) | ETH (WASM) | EOS | NEO | WASM | ||
|---|---|---|---|---|---|---|---|
| 浏览器 (Explorer) | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ⭕ | |
| 反汇编器 (Disassembler) | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | |
| 控制流分析 | ✖️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | |
| 调用流分析 | ✖️ | ➕ | ✔️ | ✔️ | ➕ | ✔️ | |
| IR 转换 (SSA) | ✖️ | ✔️ | ➕ | ➕ | ✖️ | ✔️ | |
| 符号执行 | ✖️ | ➕ | ➕ | ➕ | ✖️ | ➕ |
✔️ 已完成 / ➕ 进行中 / ✖️ 待办 / ⭕ 不适用
Octopus 支持在 Linux(理想为 Ubuntu 16.04)上运行,并要求 Python >=3.5(理想为 3.6)。
依赖项:
sudo apt-get update && sudo apt-get install python-pip graphviz xdg-utils -y
- 安装 Octopus:```
# Download Octopus
git clone https://github.com/pventuzelo/octopus
cd octopus
# Install Octopus library/CLI and its dependencies
python3 setup.py install
或```
pip3 install octopus
- 运行测试```
# 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.sh
提供工具集的 Docker 容器可在 docker hub 获取。 在终端中,运行以下命令:
docker pull smartbugs/octopus
docker build -t smartbugs/octopus .
docker run -it smartbugs/octopus
docker pull smartbugs/octopus docker run -it smartbugs/octopus cd octopus python3 octopus_eth_evm.py -s -f examples/ETH/evm_bytecode/61EDCDf5bb737ADffE5043706e7C5bb1f1a56eEA.bytecode
## 命令行工具
* WebAssembly: [octopus_wasm.py](https://github.com/fuzzinglabs/octopus/blob/master/octopus_wasm.py)
* Ethereum (EVM): [octopus_eth_evm.py](https://github.com/fuzzinglabs/octopus/blob/master/octopus_eth_evm.py)
## 使用API的深入示例
<details><summary>WebAssembly</summary>
<p>
#### 反汇编器
Wasm模块的反汇编:```python
from octopus.arch.wasm.disassembler import WasmDisassembler
FILE = "examples/wasm/samples/helloworld.wasm"
with open(FILE, 'rb') as f:
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 code
print(disasm.disassemble_module(module_bytecode, r_format='text'))
# func 0
# i32.const 0
# call 0
# end
Wasm字节码的反汇编:```python from octopus.arch.wasm.disassembler import WasmDisassembler
bytecode = b'\x02\x7fA\x18\x10\x1cA\x00\x0f\x0b'
disasm = WasmDisassembler(bytecode)
print(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'))
#### ModuleAnalyzer```python
from octopus.arch.wasm.analyzer import WasmModuleAnalyzer
FILE = "examples/wasm/samples/hello_wasm_studio.wasm"
with open(FILE, 'rb') as f:
module_bytecode = f.read()
# return list of functions instructions (list)
# attributes analysis=True by default
analyzer = WasmModuleAnalyzer(module_bytecode)
# show analyzer attributes
print(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')]
from octopus.arch.wasm.cfg import WasmCFG
file_name = "examples/wasm/samples/fib.wasm"
with open(file_name, 'rb') as f: raw = f.read()
cfg = WasmCFG(raw)
cfg.visualize()
<p align="center">
<img src="https://assets.kitploit.com/production/public/readmes/6916/a317892fc1e0ce1939535b5f1e0fd00188634ec14f21e7f5eee950e4c2f92206.png" height="400px"/>
</p>