Code Structure
oyente.py
这是程序的主要入口点。Oyente能够通过以下输入分析智能契约:
- solidity program
- evm bytecode
- remote contracts
然后使用evm disasm ...
命令将合约分解为操作码
。
然后,使用已分解的文件调用symexec模块
,该文件对各种漏洞(TOD、时间戳依赖、处理不当的异常)的契约进行分析。
symExec.py
分析从build_cfg_and_analyze函数
开始。我们使用本机tokenize python模块将disasm文件分解为tokens。(We break up the disasm file created by oyente.py into tokens using the native tokenize python module
.)
collect_vertices和construct_bb函数
标识程序中的基本块,并将它们存储为顶点。基本块通过使用诸如JUMPDEST、STOP、RETURN、SUICIDE、JUMP和JUMPI
等操作码作为分隔符
来识别。每个基本块都由BasicBlock .py
中定义的BasicBlock类的实例支持。
创建基本块之后,我们开始使用full_sym_exec函数
象征性地执行每个基本块。我们获取存储在每个基本块中的指令,并通过sym_exec_ins函数
象征性地执行它们。在这个函数中,我们将每个操作码尽可能地与ethereum黄色论文中描述的行为紧密地建模。
Vulnerabilities
Callstack attack
检查callstack攻击
是由check_callstack_attack函数
完成的。如果一个CALL
或一个CALLCODE
指令在没有SWAP4、POP、POP、POP、POP、ISZERO
(或者SWAP3
后面跟着3POP
,等等)的情况下被发现,我们将它标记为容易受到callstack攻击
。这个操作码序列是solc生成的,与下面推荐的代码模式相对应,以防止攻击。
if (owner.send(amount)) {..}
Timestamp dependence attack
我们找出path_conditions
变量是否包含与块时间戳
对应的符号变量。如果是这样,程序可以在程序中使用块时间戳的路径,使其容易受到时间戳依赖攻击。
Reentrancy bug
在analysis.py
中的check_reentrancy_bug
函数中分析了这个bug的存在。在遇到的每个CALL
中,我们都会在CALL
执行之前获得执行的路径条件。然后,我们用更新的变量(例如,存储值)检查这种条件是否仍然成立(如果调用可以再次执行)。如果是这样,我们认为这是一个漏洞,因为被调用方有可能在完成调用之前重新执行调用。我们还考虑了用户使用send
和transfer
而不是CALL
函数的情况。由于在send
和transfer
过程中gas
的限制,使用send
和transfer
是安全的。为了检查合约是否安全,基于gas
作为这些功能的一部分,我们设置了一个2300的阈值,这是send
和transfer
提供的gas
数量。然后用阈值比较随这些函数发送的gas
。如果gas
大于阈值,我们将合约标记为易受重入攻击。否则,我们将其标记为安全。