3、静态分析工具Slither:Slither安装与配置、基础规则扫描、自定义规则编写
静态分析,说白了就是在代码还没跑起来之前,先拿放大镜把源码翻个底朝天。我最早接触智能合约安全时,总觉得部署上去跑一跑就能发现问题,后来被一个隐藏的整数溢出坑惨了——嗯,从那以后,Slither就成了我工具箱里的常客。
Slither是Trail of Bits团队开发的Solidity静态分析框架。它不执行合约,而是把代码解析成抽象语法树和控制流图,然后基于这些结构做模式匹配和数据流分析。你想想看,这相当于给合约做了一次全身CT扫描。
核心能力一览:
- 检测常见漏洞(重入、未检查的call、整数溢出等)
- 分析合约继承关系和函数调用图
- 支持自定义检测规则(Python编写)
- 输出JSON、SARIF等结构化报告
3.1 安装与配置
安装Slither其实很简单,但有几个坑我得提前跟你说。我个人习惯用pip安装,干净利落:
pip install slither-analyzer
不过光装Slither还不够,它依赖solc编译器。你想想看,没有编译器,它怎么解析Solidity源码?所以还得装solc-select来管理编译器版本:
pip install solc-select
solc-select install 0.8.19
solc-select use 0.8.19
我曾经踩过的坑:有一次我直接装了最新版solc,结果项目用的还是0.6.12的旧语法。Slither解析时直接报错,说语法不兼容。后来我学乖了,每次跑分析前先用solc-select切换到目标版本。
验证安装是否成功,跑个版本号看看:
slither --version
如果看到版本号输出,恭喜你,环境搭好了。如果报错说找不到solc,多半是环境变量没配好。检查一下~/.solc-select/artifacts目录下有没有对应的solc二进制文件。
3.2 基础规则扫描
安装完第一件事,当然是找个合约试试水。我建议你从最简单的ERC20合约开始:
slither my_token.sol
输出结果会分成几个部分:
- INFO:常规信息,比如合约名称、版本
- WARNING:潜在风险,需要人工确认
- ERROR:确定性的漏洞,必须修复
举个例子,Slither检测到未检查的call返回值时,会这样提示:
WARNING: Low-level call (my_token.sol#L42) is used without checking return value.
Consider using transfer() or checking the return value.
我个人习惯把结果输出成JSON,方便后续集成到CI/CD流水线:
slither my_token.sol --json report.json
JSON格式长这样:
{
"success": true,
"results": {
"detectors": [
{
"check": "unchecked-lowcall",
"impact": "Medium",
"confidence": "High",
"description": "Low-level call without return value check..."
}
]
}
}
小技巧:如果你只想看某个特定类型的漏洞,可以用--detect参数过滤。比如只看重入漏洞:slither . --detect reentrancy。我经常在审计大项目时这么干,先扫一遍所有规则,再针对高风险项单独排查。
Slither内置了90多条检测规则,覆盖了SWC(Smart Contract Weakness Classification)中的大部分类别。常用的有:
| 规则ID | 检测内容 | 严重程度 |
|---|---|---|
| reentrancy | 重入漏洞 | High |
| unchecked-lowcall | 未检查的底层调用 | Medium |
| timestamp | 依赖区块时间戳 | Low |
| tx-origin | 使用tx.origin做身份验证 | Medium |
| pragma | 浮点编译指示版本 | Informational |
3.3 自定义规则编写
内置规则虽然多,但总有覆盖不到的场景。比如你想检测合约中所有使用block.number的地方,或者想检查某个特定命名模式的函数。这时候就得自己写规则了。
Slither的自定义规则用Python写,核心是继承AbstractDetector类。我带你写一个最简单的例子——检测合约中是否使用了selfdestruct:
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
class SelfdestructDetector(AbstractDetector):
ARGUMENT = "selfdestruct-check"
HELP = "检测合约中是否包含selfdestruct"
IMPACT = DetectorClassification.HIGH
CONFIDENCE = DetectorClassification.HIGH
def detect(self):
results = []
for contract in self.slither.contracts_derived:
for function in contract.functions:
for node in function.nodes:
for ir in node.irs:
if ir.name == "SELFDESTRUCT":
info = f"合约 {contract.name} 中的 {function.name} 函数调用了 selfdestruct\n"
json = self.generate_result(info)
results.append(json)
return results
写完之后,保存成selfdestruct_detector.py,然后通过--detect参数加载:
slither my_token.sol --detect selfdestruct-check --detectors-path ./
关键点解析:
ARGUMENT:命令行中使用的规则名称IMPACT和CONFIDENCE:影响程度和置信度,分为HIGH/MEDIUM/LOW/INFORMATIONALdetect()方法:核心逻辑,返回检测结果列表self.slither.contracts_derived:获取所有合约对象function.nodes:函数的控制流图节点node.irs:节点中的中间表示(Intermediate Representation)
你可能会问,怎么知道有哪些IR类型?Slither提供了完整的API文档。我个人常用的IR包括:
CALL:外部调用DELEGATECALL:委托调用SLOAD/SSTORE:状态变量读写BALANCE:余额查询TRANSFER/SEND:转账操作
注意:自定义规则写完后,一定要先在测试合约上跑一遍。我曾经写过一个检测未初始化变量的规则,结果因为没处理好继承关系,误报率高达80%。后来加上了contract.is_interface过滤,才把误报压下去。
如果你想把自定义规则做成永久性的,可以把它放到Slither的插件目录下:
~/.slither/plugins/
这样每次运行Slither时,它会自动加载所有插件。我个人习惯把常用的审计规则打包成一个插件集合,团队里其他人也能直接用。
进阶技巧:Slither还支持数据流分析。比如你想追踪某个变量是否被用户输入污染,可以用slither.data_dependency模块。我曾在审计一个DeFi项目时,用这个功能找到了一个通过闪电贷操纵预言机的漏洞——那是我用自定义规则抓到的最值钱的一个bug。
好了,Slither的基本用法就这些。从安装到基础扫描,再到自定义规则,这套流程我用了两年多,审计了上百个合约。说白了,静态分析工具就是你的第二双眼睛,它能帮你看到人眼容易漏掉的东西。但记住,工具只是辅助,最终的判断还得靠你自己。
公众号:蓝海资料掘金营,微信deep3321