【免费下载链接】publications
Publications from Trail of Bits
本篇技术指南围绕 Trail of Bits 两位安全研究员在 CanSecWest 2018 上的演讲《Blackhat Ethereum》展开,完整还原其"从入门到攻击"的完整脉络:先建立 Ethereum 与 EVM 的底层认知,再从区块链上批量提取合约字节码,进而通过逆向分析定位漏洞并编写利用。读完本文,你将掌握 EVM 栈机的运行原理、ABI 函数分派机制、常见的智能合约漏洞类别,以及 Remix、Oyente、Mythril、Manticore、Ethersplay、Rattle 等工具在字节码与 Solidity 源码两个层面的实战用法。
演讲幻灯片原件位于 presentations/Blackhat Ethereum/Blackhat Ethereum.pdf,元数据说明见 presentations/Blackhat Ethereum/README.md。
演讲背景与核心议程
本演讲由 Trail of Bits 两位首席安全研究员主讲:
- Ryan Stortz(@withzombies):约 10 年安全行业经验,曾任职 Raytheon SI,参与过 VedaGodz、HatesIrony、Marauders 等 CTF 战队,并主办 GhostInTheShellcode、CSAW CTF 等赛事,此前有 Swift Reversing、Cyber Grand Challenge、Binary Ninja 等主题演讲。
- Jay Little(@computerality):约 10 年行业经验,CTF 经历覆盖 0x28 Thieves、Whitehatters、Samurai 等战队,同样主办过 GhostInTheShellcode,其最喜欢的 IDA 按键是
Y(重命名)和D(转换数据类型)。
演讲按照四个阶段递进展开,这也是本文的骨架:
- Ethereum 入门(Introduction to Ethereum)
- 从区块链中提取有用信息(Extract useful information from the blockchain)
- 审计合约中的漏洞(Audit contracts for vulnerabilities)
- 编写并投出利用(Write and throw an exploit)
演讲的核心观点是:几乎所有 Ethereum 代码都只能通过逆向工程来分析,而过去一年中,精明的攻击者正是利用智能合约的缺陷盗走了数百万美元。因此,掌握字节码逆向是智能合约安全研究的必修课。
Ethereum 基础:从转账到可编程合约
Ethereum 被视为"另一种"区块链实现,与比特币最大的区别在于它是面向智能合约(smart contract)的:比特币开创了无需信任的货币转账,而 Ethereum 更进一步,为智能合约提供了一台图灵完备的机器,支持富应用,并能追踪股票、抵押贷款、域名等资产。公众通常只听说 ICO(Initial Coin Offerings),但这远不是 Ethereum 能力的全部。
演讲中给出了一张通俗的术语对照表,将密码学概念映射到非加密世界的类比:
| 术语 | 含义 | 非加密类比 |
|---|---|---|
| Ether / ETH | 基础货币 | 货币 |
| Wei / Gwei | ETH 的 10⁻¹⁸ / 10⁻⁹ 单位 | 分 / 角 |
| Gas | 执行计算的计量单位 | 邮票上的邮资 |
| Block | 一笔交易的列表 | 账页 |
| Transaction | 在地址间发送 ETH(可选附带消息) | 转账单 |
| Address | 160 位数字,可以是账户或合约 | 银行路由号 + 账号 |
| Account | 持有 ETH、可收发款项的账户 | 银行账户 |
| Contract | 收到消息时自动运行代码的账户 | 自动柜员 |
| DApp | 合约 + 前端 Web UI | 应用 |
客户端实现:用哪个、不用哪个
Ethereum 协议由 Yellow Paper(黄皮书)描述,存在众多独立的客户端实现,它们共同维护共识,包括所有智能合约交易的状态。演讲给出的选型建议非常明确:
- 推荐使用:
geth和parity - 不要使用:
cpp-ethereum、pyethereum、EthereumJ
Solidity 与 EVM
Solidity 是一种受 JavaScript 启发的智能合约高级语言,编译为 EVM(Ethereum Virtual Machine)字节码——Ethereum 的原生机器码。演讲直言"Solidity 是 Ethereum 几乎所有问题的根源":它降低了编写链上程序的门槛,但语言特性和历史包袱也引入了大量易错模式(后文漏洞清单会详述)。
EVM 架构剖析:一台 256 位的栈机器
EVM 是一台栈机器(stack machine),其关键特征:
- 约 181 个操作码
- 原生数据宽度为 256 位 / 32 字节
- 大量指令是重复的族系:
PUSH1–PUSH32、DUP1–DUP16、SWAP1–SWAP16 - 每条指令都有 gas 成本(可通过 Trail of Bits 的 evm-opcodes 项目查阅完整指令表)
演讲用一段简单的字节码演示了栈机的执行过程。给定指令序列:
PUSH1 0x2 PUSH1 0x3 ADD PUSH1 0x8 MUL执行过程如下(Code 列展示剩余指令,Stack 列展示栈顶变化):
| 步骤 | 执行后 Code | 执行后 Stack |
|---|---|---|
| 1 | PUSH1 0x2 | 0x2 |
| 2 | PUSH1 0x3 | 0x3 0x2 |
| 3 | ADD | 0x5 |
| 4 | PUSH1 0x8 | 0x8 0x5 |
| 5 | MUL | 0x28 |
即(2 + 3) × 8 = 40 = 0x28。这段最小的例子揭示了理解 EVM 逆向的核心心法:一切运算都在栈上完成,操作码隐式消费栈顶元素并压回结果。
攻击面:一次成功的 Hack 长什么样
演讲对智能合约"被黑"给出了一个简洁而准确的定义:
Hack = 合约返还给你的 ETH 比你发给它的更多。
漏洞形态上,绝大多数是逻辑缺陷(logic flaws),但演讲特别提醒:内存破坏(memory corruption)在 EVM 上确实会发生(如对Array.length、Inline Assembly的误用),不能因为 EVM 是虚拟栈机就排除这类经典漏洞。
为什么只能靠逆向工程
演讲用一组当时(2018 年)的链上观测数据说明问题:
| 统计项 | 数量 |
|---|---|
| 合约总数 | 1,500,000 |
| 持有 ETH 的合约 | 26,300 |
| 唯一代码(unique code) | 5,643 |
| 带源码的合约 | 1,536 |
| 持有 >1 ETH 的合约 | 470 |
可见:上百万个合约中,公开源码的仅 1,536 个。绝大多数链上代码没有对应源码,这决定了"从字节码反推逻辑"是唯一的通用分析路径——这正是演讲标题"Blackhat Ethereum"的由来。
从区块链提取合约:工具与数据获取
工具全景
演讲给出了一张完整的工具清单,覆盖从链上取数到静态分析的全流程:
| 工具 | 作用 |
|---|---|
| geth / parity | Ethereum 客户端 / JSON RPC 提供方 |
| web3.js / web3.py | 面向客户端的 JSON / WebSocket 客户端库 |
| Etherscan.io | "最有用的网站" |
| Remix / Oyente | Solidity 源码编辑器与静态分析器 |
| Mythril | EVM、Solidity、区块链搜索 |
| Manticore | EVM 与区块链符号执行器 |
| Ethersplay | 反汇编器 |
获取合约的三种方式
Ethereum 客户端通常提供 JSON RPC 接口,获取合约数据有三种途径:
- 连接公共节点服务(如 infura.io、myetherapi.com)
- 手动在 Etherscan.io 上浏览
- 自己运行 geth 或 parity 全节点
geth 实战与踩坑
演讲者分享了自己运行 geth 的亲身经历,命令为:
geth.exe --syncmode "fast" --cache 4096(--syncmode "fast"使用快速同步模式跳过历史状态回放,--cache 4096将内存缓存设为 4 GB 以加速同步。)
首次体验以一连串 leveldb 数据库损坏错误告终:
ERROR[11-29|19:16:30] Failed to close database database=/eth/.ethereum/geth/chaindata err="leveldb/table: corruption on>for b in range(blockNumber('latest')): block = getBlockByNumber(b) for tx in block['transactions']: r = getTransactionReceipt(tx['hash']) the_code = getCode(r['address'])这段代码逐区块遍历所有交易,取回每笔交易的收据,再用收据中的合约地址调用getCode拉取字节码。实际执行中还有三个坑:
selfdestruct(自毁)过的合约拿不到代码,需另行处理- 合约创建代码(Creation Code)不直接存在收据里,而是存在交易的
input字段中,需要补抓 - 补跑脚本又花了 4 天,链目录体积膨胀了 5 倍
最终,约 150 万个合约的字节码被整齐地归档到本地目录,为批量逆向分析做好了准备。
目标分析:EVM ABI 与函数分派
逆向目标
演讲选择的演示目标是合约:
0xcd6d2cd79fd754c6b909585e46541d32ec491962通过 web3 提取到其字节码,且没有可用源码——这是链上合约的常态,也正好展示了纯逆向路径。
EVM 是 Harvard 架构
演讲强调:EVM 是哈佛架构(Harvard architecture),代码与数据分离,存在约 5 个独立地址空间:
- Code:字节码本体,不可写
- Stack:栈机的工作栈
- Call data:本次调用的输入参数区
- Storage:持久化存储(键值存储)
- Memory:临时内存(易失)
函数分派:前 4 字节哈希
EVM 中所有执行都从 PC 0x0 进入,合约通过检查调用数据(calldata)来分派到具体函数。分派机制是:
sha3(函数原型签名).digest()[:4].encode('hex')即取函数原型签名的 Keccak/SHA3 哈希的前 4 字节作为函数选择子(selector)。例如:
SetOwner(address) = 0x167d3e9c逆向分析的第一步,就是从入口分派代码(通常是一串PUSH4+EQ+JUMPI的比较链)中恢复出合约暴露的全部函数签名。另外注意:calldata 在前 4 字节之后按 32 字节对齐,参数解析必须遵循这一约定。
基于这些知识,逆向者可以从纯字节码中逐步重建合约的接口与状态变量布局,再结合后面的工具链将控制流与数据流还原成可读的逻辑。
常见智能合约漏洞类别:完整清单
演讲给出了一份实战导向的漏洞知识清单,按"合约自身缺陷"与"环境/随机性"分组:
合约自身缺陷(语言与逻辑层面):
- Integer overflow / underflow:整数溢出与下溢,历史上大量 DeFi 事件的主因
- Incomplete initialization:初始化不完整,状态变量未正确赋值
- Uninitialized variables:未初始化变量
- Callbacks / re-entrancy:回调 / 重入,经典的 DAO 攻击模式
- Variable name shadowing:变量名遮蔽
- Type inference(
var关键字):类型推断导致意外的窄/宽类型转换 - Array.length:对动态数组长度的误用
- Inline Assembly:内联汇编绕过 Solidity 安全检查
环境与随机性层面:
- Divide by zero:除零
- Race conditions / replay attacks:竞态条件 / 重放攻击
- Bad random number generation:糟糕的随机数生成
- Time sensitive:时间敏感逻辑(依赖区块时间戳)
- Using blockchain as random:用区块链(区块哈希等可预测数据)当随机源
这份清单至今仍是智能合约审计的检查底稿。Trail of Bits 后续在 papers/smart_contract_flaws_fc2020.pdf 中进一步系统化了这类缺陷的实证研究,并在 datasets/smart_contract_audit_findings/ 提供了审计发现的数据集供对照学习。
工具链详解:源码级与字节码级双轨审计
Etherscan.io
"最有用的网站":提供合约源码验证、字节码查看、交易追踪与函数调用浏览,是手工取证的第一站。
Remix 与 Oyente
- Remix:官方推荐的 Solidity 源码编辑器,支持编译、部署、调试一体化
- Oyente:经典的 Solidity 静态分析器,面向源码级别检测已知缺陷模式
两者配合适合"有源码"场景的快速扫描。
Mythril
面向EVM、Solidity 与区块链搜索的安全分析工具,可基于字节码直接展开符号化分析,适合无源码合约的自动漏洞发现。
MAIAN
MAIAN 是另一款链上合约漏洞检测工具,专注于在已部署的字节码上发现可利用的缺陷,常与 Mythril 一起作为批量扫描流水线的一环。
Manticore:EVM 与区块链符号执行
Manticore 是 Trail of Bits 出品的符号执行引擎,同时支持二进制与 EVM。演讲现场演示了对一个 Solidity 合约的符号执行:
$ manticore simple.sol [25981] m.main:INFO: Beginning analysis [25981] m.ethereum:INFO: Starting symbolic transaction: 1 [25981] m.ethereum:INFO: Generated testcase No. 0 - REVERT [25981] m.ethereum:INFO: Generated testcase No. 1 - REVERT [25981] m.ethereum:INFO: Finished symbolic transaction: 1 | Code Coverage: 100% | Terminated States: 3 | Alive States: 1 [32058] m.ethereum:INFO: Generated testcase No. 2 - STOP [25981] m.ethereum:INFO: Results in /examples/mcore_zua0Yl可以看到:Manticore 以符号化交易驱动合约执行,自动生成覆盖不同路径的测试用例(REVERT/STOP),并报告代码覆盖率(此处 100%)与终止/存活状态数。它能够自动探索"哪些输入序列能让合约进入异常状态",正是"Write and throw an exploit"之前的自动化侦察手段。更系统的符号执行方法论可参考 papers/manticore.pdf。
Ethersplay 与 IDA-EVM:反汇编与交互式逆向
- Ethersplay:EVM 反汇编器,将原始字节码转换为可读的指令流
- IDA-EVM:把 EVM 反汇编能力嵌入 IDA,让逆向工程师用熟悉的交互工具分析合约字节码
Rattle:从字节码重建高层语义
演讲最后介绍了 Trail of Bits 自家的 EVM 二进制分析框架Rattle,其能力包括:
- 恢复 EVM 控制流图(CFG)
- 将栈机转换为 SSA(静态单赋值)形式
- 优化并简化逻辑
- 恢复 storage 与 memory 变量,以及函数参数
Rattle 的价值在于:它把"栈机 + 手动跟踪"的逆向模式升级为"CFG + SSA + 变量恢复"的编译器式分析,大幅降低了纯字节码审计的心智负担。仓库中 presentations/Rattle - an Ethereum EVM binary analysis framework/README.md 将其定位为"针对已部署智能合约的 EVM 二进制静态分析框架",配套 RattleRecon.pdf 展示了实际分析效果。
Slither:源码级静态分析的现代主力
在源码可得时,Trail of Bits 的静态分析框架Slither是这套工具链的现代补充,其相关演讲见 presentations/Slither: A Static Analysis Framework for Smart Contracts/README.md。从源码结构看,它可与本演讲介绍的字节码工具(Ethersplay、Rattle)形成"源码 + 字节码"双轨覆盖,并为后续的 SlithIR 中间表示、模型上下文协议(MCP)集成等演进提供了基础(见 presentations/SlithIR, An Intermediate Representation of Solidity to enable High Precision Security Analysis/README.md)。
从"审计"到"测试":属性测试与 Echidna
本演讲聚焦审计与利用;而审计发现的缺陷如何被系统化复现,Trail of Bits 给出的答案是属性测试(property-based testing)。同仓库的 presentations/Property-based testing of smart contracts/README.md 总结了三个关键要点:
- 单元测试并不总是充分:它一次只测一个具体用例,且通常聚焦于已知场景与失败模式;属性测试通过描述通用代码不变量(invariant)来覆盖未知场景
- Echidna 是专用于智能合约的属性测试工具:速度极快,能自动发现违反合约属性的新交易序列
- 用这类工具做属性测试,几乎必然能命中用户在单测中遗漏的条件
Echidna 的相关学术成果也收录在本仓库中,如 papers/echidna_issta2020.pdf、papers/echidna-parade_issta21.pdf 与 papers/echidna_fc_poster.pdf。
学习资源清单
演讲在结尾给出了一份面向进阶者的资源清单(此处保留其完整结构,供继续深入):
| 资源 | 说明 |
|---|---|
| /r/ethdev | 以太坊开发社区 |
| Solidity Docs | Solidity 官方文档 |
| Beige Paper | 面向开发者的 EVM 规范("米色纸",黄皮书的友好版本) |
| Not So Smart Contracts | Trail of Bits 维护的"反面教材"合约示例集 |
| Ethersplay | EVM 反汇编器 |
| EVM-opcodes | EVM 操作码速查表 |
| Rattle | EVM 二进制分析框架(演讲时即将发布) |
| Echidna | 智能合约模糊/属性测试工具 |
| Manticore | EVM 与二进制符号执行引擎 |
| Mythril | EVM/Solidity 安全分析 |
| MAIAN | 链上合约漏洞检测 |
结语:一条可复制的链上审计流水线
综合整场演讲,可以提炼出一条从零开始、纯字节码驱动的智能合约审计流水线:
- 取数:运行 geth/parity 全节点(或使用公共 RPC),用 web3.py 按区块遍历交易,抓取合约字节码并归档(注意补抓
tx.input中的创建代码、剔除已 selfdestruct 的合约) - 初筛:用 Ethersplay 反汇编、用 Etherscan.io 交叉核对,识别函数选择子与入口分派
- 还原:用 Rattle 恢复 CFG、转换为 SSA、重建变量与函数参数
- 检测:对源码可得的合约跑 Slither/Oyente/Remix,对纯字节码合约跑 Mythril/MAIAN/Manticore
- 复现:用 Manticore 符号执行生成触发用例,必要时编写利用脚本"投出"验证
- 补强:用 Echidna 做属性测试,把已知缺陷固化为不变量,防止回归
这条流水线至今仍可在 Trail of Bits 的公开审计实践中找到印证——仓库 reviews/ 收录了自 2018 年以来针对 Aave、Uniswap、Scroll、Offchain Labs 等项目的数百份智能合约安全审查报告,是检验上述方法学在真实生产代码上效果的绝佳语料。
【免费下载链接】publications
Publications from Trail of Bits
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考