
最近在 GitHub 上翻到一个叫 unikeyfarmer 的项目名字起得很直白uni 是通用key 是密钥farmer 是农夫连起来就是“批量生产钱包密钥的工具”。这类 Web3 批量注册脚本在空投圈、开发者社区里传得很广很多新手拿到手的第一反应是安装依赖、跑起来但我建议你先冷静一下。这个项目能做的事简单说就是批量生成钱包地址、助记词、私钥再配合一些自动交互逻辑去各个链上应用完成“注册—交互—领空投”的动作。听起来确实很香尤其是测试环境、需要大量地址做压力测试的场景。但你有没有想过一个能接触到私钥的脚本如果里面藏了一段“额外逻辑”你的资产会变成什么样这篇文章就以我审核 unikeyfarmer 源码的过程为例讲讲代码审计到底看哪些地方以及为什么不建议在没有充分评估的情况下直接运行一个 Web3 批量注册脚本。适合刚接触 Web3 的开发者、想用自动化工具做测试的工程师以及任何一个准备在 GitHub 上跑开源项目的朋友。1. 批量注册脚本为什么泛滥GitHub 上到底藏着什么1.1 Web3 里的“批量注册”到底在解决什么问题Web3 世界里很多应用会通过空投来吸引早期用户“一个地址领一份”的逻辑催生了一种玩法准备尽量多的地址去和合约、dApp 交互提高获得空投的概率。还有一类场景是开发者做压力测试、做数据分析需要成百上千个测试地址。另外一些项目方要做市场冷启动也会注册大量账号用来做社区氛围测试。不管哪种场景只要数量上去了手工操作就不现实。于是“批量注册脚本”有了稳定的需求。这类脚本通常负责三件事生成合法格式的钱包助记词、私钥、地址、维护地址列表、连接 RPC 节点查询链上状态甚至自动执行转账和合约调用。又因为很多人希望“用完即走”脚本往往被包装成一键式命令行工具装上 Node.js 就能跑。1.2 unikeyfarmer 这类项目的典型画像在 GitHub 上搜一圈你会发现叫 farmer、bot、auto 的项目数不胜数它们有几个非常相似的画像名字起得很有识别度方便搜索比如 unikeyfarmer 这种组合词。README 写得很吸引人配几张空投收益截图甚至有“收益计算器”让你觉得跑一下就能躺赚。依赖很简单基本就是 ethers.js、web3.js、axios、commander 这几个常见库。star 数可能不低但 issue 区经常是空的或者只有“作者你运行成功了吗”这种无效问题。版本更新集中在一小段时间之后戛然而止作者再没出现过。这些特征本身不算罪但它们叠加在一起就是一个“快餐项目”的画像作者用最短时间写出来发布到 GitHub目的往往不是长期维护而是把下载量变成别的东西——引流、赚打赏甚至就是投毒。你没法从表面判断它是哪一种所以审计这一步不能省。1.3 为什么这类项目特别容易成为投毒目标Web3 脚本和普通脚本最大的区别在于它手里握着私钥。私钥是资金的唯一凭证整个流程里私钥一旦出网钱包就相当于透明。另一个原因是脚本的执行环境通常不可控很多人会带着本地浏览器、云服务器、API Key 一起跑脚本作者对这些敏感信息动手比想象中容易得多。再加上 Web3 圈子本身崇尚“匿名”和“开放”传播链又短一个项目可能只在几个群里转一圈就获得了第一批用户完全没有经历安全社区的眼球洗礼。这给了一些恶意项目“发布—收割—跑路”的窗口期。所以每当我看到有人把这类项目直接放在主力机器上跑我都会替他的钱包捏一把汗。2. 源码审计到底审什么以 unikeyfarmer 为例拆解2.1 审计前先做环境隔离审计代码的第一步不是打开源码而是准备好一个“扔了也不心疼”的环境。我习惯用 Docker 容器来做这件事原因很简单容器可以限制文件系统、网络和资源跑完以后一键销毁不留残余。我的标准动作是这样的拉一个 Ubuntu LTS 官方镜像起一个临时容器不映射宿主端口。在容器里装 Node.js 运行时和基础工具但不用 root 账号建一个低权限用户。把 unikeyfarmer 的源码复制进去注意不要直接挂载宿主目录避免脚本反向读取宿主文件。记录容器启动时间先拍一个进程快照方便后面对照。在容器里准备一个假的 RPC 服务把脚本要连的节点指向本机端口。这里提醒一句动态审计一定要在外面先起一个假的 RPC 服务。脚本要连链上节点我们故意给它一个假服务它发的任何 HTTP 请求都会跑到我们能监控到的地方这个信息非常值钱。2.2 静态代码审计的 6 个关键检查点静态审计的核心思路是“跟着数据和执行流走”。我会按下面这个清单逐项排查package.json。先看依赖列表有没有可疑的包再检查依赖是否锁定版本最后看有没有 postinstall、preinstall 这类安装后执行的脚本。很多投毒就藏在这里表面装一个正常库实际下载恶意二进制。入口执行流。main.js、index.js 这些入口文件里是在 require 阶段就执行函数还是只导出函数如果加载模块的瞬间就发生了网络请求那基本可以断定有鬼。私钥和助记词的去向。全局搜索 mnemonic、privateKey、wallet、eth.getAccounts 这些关键字然后沿着每个变量的赋值路径看它流向哪里。只要发现私钥被拼进一个 HTTP 请求里不管对方是谁直接判死刑。远程代码加载。搜索 eval、exec、child_process、spawn、curl、wget、base64、atob 这些关键字。正常的 Web3 脚本几乎不需要在运行时拉取远程代码如果出现大量这种调用就要重点分析。网络请求目的地。把代码里所有硬编码的 URL 列出来逐个看域名归属。如果出现一个看起来很正规的域名但注册时间是最近三个月那就要高度警惕。README 和代码不一致的地方。README 说“生成过程完全本地不上传任何数据”但代码里有一段明显向某个服务器发数据的逻辑这就是有意隐瞒。2.3 unikeyfarmer 里的高危动作示例我在审计笔记里会给高危动作打标记。这里列几种我在同类项目里反复看到、你也可能在 unikeyfarmer 里找到的模式私钥收集型生成助记词后用 fetch 把前 100 个地址和一个自定义的 user-agent 发到某个对象存储服务然后假装返回“已跳过”。代码里可能只多了一两行不仔细看完全发现不了。混淆配置型把真实 RPC 地址通过 base64 写死在代码里解码后发现是一个私有服务器而不是 Infura、Alchemy 这类公开服务。这种设计毫无合理性私链节点只对自己有意义。后门依赖型主代码很干净但安装依赖时从某个 GitHub Release 下载一个二进制文件并给它可执行权限后续通过定时器调用。挖矿型正常执行你想要的逻辑但后台用 CPU 跑随机运算把结果提交到一个奖励池。需要说明的是这些手法都是我在安全分析里见过的通用套路不代表 unikeyfarmer 一定全部命中。写出来是想让你知道代码里藏东西的方式可以非常隐蔽普通用户根本看不出问题这也是“不要直接运行”的根本原因。2.4 动态运行让脚本在沙箱里露出马脚静态分析之后要在沙箱里动态跑一遍。我常用的命令大致是这样# 启动一个网络受限的容器只允许访问本地 RPC docker run --rm -it --network none -v $PWD/code:/app/code:ro my-audit-image # 在另一个容器里启动假 RPC 服务和抓包工具 docker run --rm -it --network bridge -p 3000:3000 my-audit-image # 在 Python 里起一个最简陋的 HTTP Server 当作假 RPC python3 -m http.server 3000跑起来之后观察这几个现象脚本是不是在启动阶段就发了一堆请求而不是等到你指定任务之后才发错误处理是否正常如果 RPC 返回 404它应该报错停止。如果它无视错误继续发请求说明它不太关心链上返回更像在回传数据。私钥文件是不是只在本地生成还是有额外写盘操作有没有突然出现的子进程我见过最离谱的例子是脚本只在启动时向一个陌生域名发送了一串编码后的字符串然后看起来很努力地执行注册流程实际上核心动作全部是烟雾弹。这些东西不跑起来根本看不到。3. 为什么不建议直接运行这 4 类风险必须看清3.1 私钥泄露攻击者不是不偷而是等以后偷这个风险最直接。脚本把私钥上传后攻击者通常不会立刻转走余额而是会把你的地址放到一个监控列表里。等你的地址通过空投筛选、里面有了代币他再一次性转走。你以为是项目方还没发币其实是你的钱包已经被别人接管了。这种“延迟收割”比直接盗取更阴险。因为你很难判断到底是项目本身不行还是自己的钱包已经出了问题。等你发现异常时交易记录早就被彻底清理过了。3.2 批量账号成片被封女巫检测在等着你即使不考虑恶意代码用脚本批量注册本身就是平台严厉打击的行为。现在很多链上应用和服务商都有女巫检测系统会通过 IP、浏览器指纹、钱包行为模式、资金流向关系网来识别“同一人控制的集群”。这里我不展开讲怎么绕过因为那本身是违规方向。我想说的是脚本生成的地址如果共享同一套网络出口或浏览器特征轻则账号冻结重则整批地址进黑名单。你辛苦跑出来的量可能一夜之间全部作废这才是纯粹的“白干一场”。3.3 供应链投毒你信任的不只是脚本本身一个开源项目的风险不只来自主代码依赖树里的任何一层都可能是突破口。unikeyfarmer 用了很多常见的 Web3 库如果作者没有锁定依赖版本或者某个依赖包本身被攻击者接管那么即使主代码是干净的安装依赖的时候也等于引狼入室。这类事件已经发生过很多次npm 和 PyPI 上都出现过伪装成热门工具包的恶意版本功能完全正常副作用是收集环境变量里的密钥。供应链攻击最可怕的地方在于你可能一直都没发现因为主程序看起来一点问题都没有。3.4 法律与服务条款风险批量注册未必只是“玩一下”批量注册空投账号、刷交互量在很多项目条款里都已经明确写成违规行为。平台有权冻结账户、没收奖励甚至追究法律责任。如果你的脚本里还包含对服务系统的自动化请求涉及的技术手段可能非常敏感。我一直觉得学习脚本技术、做安全测试都是合理需求但在没有授权的情况下用脚本去大规模注册账号、薅平台资源性质就变了。审计后发现问题可以写文章披露但为了测试别人的防御机制去跑这类脚本无论如何都是越界。4. 如果真的要用怎么把风险降到最低4.1 一份可以直接抄的源码审查清单我把审计时的核心检查项做成了表格你可以直接保存下来拿到任何开源项目都能用检查项关注点处理方式安装脚本package.json 的 postinstall/preinstall逐行读异常就拒绝安装入口执行流模块加载时是否立即执行副作用改成“导出函数”再手动调用私钥处理是否有日志、网络请求、写盘动作跟踪每个变量流向远程加载eval、exec、curl 管道还原代码确认目的网络目的地硬编码 URL 归属与端口对比 Whois 和注册时间依赖完整性lock 文件是否提交缺失 lock 文件要小心权限要求是否请求读取用户目录、环境变量拒绝不合理的权限这张表看起来简单但每一条背后都有人踩过坑。比如 lock 文件缺失这件事很多项目为了“省事”不提交 package-lock.json结果你安装到的依赖版本可能跟作者开发时的完全不一样安全风险完全不可控。4.2 Docker 沙箱运行 5 步法如果你评估后还是想跑那请务必按沙箱流程来。我自己用的方案是 5 步用官方 Node 镜像起容器别用宿主环境。把脚本和配置挂载成只读目录里只放必要的文件。设置出站防火墙默认拒绝外联只放行你指定的一些公开 RPC 地址。不要挂载用户目录、浏览器数据、登录凭据一个都不要。跑完以后销毁容器检查快照对比有没有额外的文件或进程留下来。这套流程的核心思路是把脚本当成一个“不可信的外部程序”对待而不是你写的代码。它可以访问它自己的小世界但碰不到你的真实资产。4.3 网络流量监控的必看指标运行过程中一定要开流量监控。重点看这几个指标DNS 请求解析到的 IP 列表有没有非知名云厂商的地址。有没有非标准端口比如 8080、8443、9999上的 TLS 连接。TLS 握手中的 SNI 字段连的是哪个域名。重试逻辑和回传频率。正常查询 RPC 失败后会重试几次就停恶意回传往往每隔几秒就发一次非常规律。我看过一个真实案例脚本主流程完全正常但会每隔 90 秒向一个隐藏域名发送一次“心跳包”里面的内容是当前时间戳和地址数量。这种流量不抓包根本发现不了而且由于频率很低也不容易被防火墙标记。所以你如果真要跑时刻开着流量监控是底线。5. 常见问题与排查技巧实录5.1 为什么钱包被转空了这是最常被问的问题。绝大多数情况都是私钥已经在某个环节泄露了泄露渠道可能是脚本后门、依赖投毒也可能是不小心把私钥文件传到了公开仓库。排查思路是先查 DNS 历史记录和网络流量日志看脚本运行时有没有向陌生地址发过请求再查依赖树的完整性看有没有可疑的二进制文件最后检查一下私钥文件的权限和修改时间比如文件是否在脚本运行之后被读取过。如果这些都查不到那就想想你是不是在某个教程网站提交过助记词。5.2 为什么批量注册的账号全被封大概率不是脚本的问题而是女巫检测在发挥作用。同一个 IP 段、同一个浏览器指纹、同一套行为模式在平台看来就是一批机器人。遇到这种情况别想着怎么换网络绕过去先停下来。如果你只是做技术研究换个思路控制样本量模拟真实用户行为而不是无脑批量注册。如果你是为了刷空投那我只能说你被平台封掉一点都不冤因为平台规则本来就禁止这种行为。5.3 为什么脚本报错却查不到原因有一种情况是代码被故意混淆了报错信息只是烟雾弹真正的逻辑可能根本不依赖报错信息来判断。比如它在 try-catch 里自行吞掉异常然后走另一条完全无关的路径。这时候我的建议是别在报错信息上死磕直接回到静态审计用反混淆工具还原代码然后再看执行流。宁可多花几个小时把代码看明白也不要在不明不白的报错里稀里糊涂地继续跑。5.4 怎么判断一个 GitHub 项目能不能信我一般看五个维度维护者的历史。看他之前发布过什么项目、参与过什么社区是不是一个长期活跃的开发者。最近提交记录。关键看有没有“隐形提交”也就是作者把已经存在很久的文件偷偷改掉提交信息却很模糊。Issue 和 PR 的质量。如果有真实的用户反馈、维护者认真回复可信度会高很多。Release 是否规范。有没有签名校验、是否只从官方仓库发布产物。外部安全扫描。一些平台能看到项目的依赖扫描结果如果一打开就是一堆高危漏洞那还是算了。Star 数量不能说明问题因为刷星太容易了。拿着 5000 星的项目也可能是投毒项目而且因为星多受害者更多。判断一个项目靠不靠谱还是要回到代码本身。6. 一点个人体会这几年我审计过不少所谓的“Web3 批量注册神器”坦率地说真正干净的项目不到三成。有些是作者能力有限写得很烂有些是能力很强但目的不纯。你很难一眼看出差别唯一的办法就是养成“先审计再运行”的习惯。对我来说GitHub 是一个绝佳的学习平台开源代码是极好的教材但“能下载”和“能直接跑”是两回事。尤其是在涉及私钥、账户、自动化请求这些敏感操作时多一分谨慎真的能帮你避开很多坑。最后再分享一个小技巧如果你只是需要批量生成测试地址其实完全不用去跑别人的脚本。自己用 ethers.js 写一个简单的生成器二三十行代码就能搞定从一开始就能保证私钥不出本机。自己写的代码也许功能简陋了一点但它不会在某个深夜把你的钱包悄悄交给一个你完全不认识的域名。