乐于分享
好东西不私藏

VoidLink Rootkit 源码泄露:一个 AI 写出的内核级隐身框架长什么样

VoidLink Rootkit 源码泄露:一个 AI 写出的内核级隐身框架长什么样

2026 年 3 月 26 日,Elastic Security Labs 发布了一篇重磅技术分析,披露了 VoidLink 恶意框架的内核 rootkit 子系统源码。这批源码来自一次数据泄露,包含完整的开发历史、编译产物和部署脚本,让外界第一次看到了这个「云原生」Linux 恶意框架的内核隐身模块到底是怎么造出来的。

VoidLink 并不是新面孔。2026 年 1 月,Check Point Research 首次曝光了这个框架——用 Zig 语言编写、针对 Linux 云环境设计、拥有 30 多个插件模块的完整 C2 平台。一周后,Check Point 又扔出第二颗炸弹:VoidLink 几乎完全由 AI 辅助开发,一个人用字节跳动旗下的 TRAE IDE,不到一周就把 88000 行代码从概念推进到可用状态。

Elastic 这次拿到的源码,相当于把 Check Point 描述的「黑盒」拆开了。里面不是一个成品,而是四代 rootkit 的完整迭代记录——从最早针对 CentOS 7 的粗糙原型,到最终命名为「Ultimate Stealth v5」的生产版本。

核心架构:LKM + eBPF 的混合设计

VoidLink rootkit 最值得注意的地方,是它同时使用了两种内核级技术来实现隐藏。

多数 Linux rootkit 只会选一种方式下手:要么用 LKM(可加载内核模块)劫持系统调用,要么用 eBPF 挂钩追踪点,要么通过 LD_PRELOAD 在用户态做手脚。VoidLink 把 LKM 和 eBPF 各取所长,拼成了一个混合体。Elastic 的研究人员明确表示,这种双组件架构在野外极为罕见。

具体分工是这样的:

组件
负责的隐藏任务
技术手段
LKM(vl_stealth
进程隐藏、文件/模块痕迹清除、netstat 连接隐藏、ICMP 隐蔽通信
ftrace 劫持系统调用、kretprobe、Netfilter 钩子
eBPF 程序
从 ss 工具隐藏网络连接
kprobe 挂钩 __sys_recvmsg,篡改用户态 Netlink 缓冲区

为什么要分成两块?说白了,netstat 和 ss 这两个网络诊断工具走的是完全不同的数据路径。netstat 读的是 /proc/net/tcp,用 kretprobe 回滚 seq_file 计数器就能骗过它。但 ss 用的是 Netlink 套接字直接查询内核的 socket 诊断接口,传统的 kretprobe 对它完全无效。

开发者最初尝试用 kretprobe 劫持 inet_sk_diag_fill 来对付 ss,但这个方法会导致内核不稳定。源码注释里留了一句话(从中文翻译过来):「ss 命令隐藏由 eBPF 模块实现(更稳定)」。

最终的 eBPF 方案相当精巧。它在 __sys_recvmsg 的入口和返回处各挂一个钩子。入口处记下用户态接收缓冲区的地址;返回时遍历缓冲区里的 Netlink 消息链。当发现需要隐藏的端口时,它不是删除这条消息(那会破坏整个消息链),而是把前一条消息的长度字段「撑大」,让目标消息被「吞掉」。ss 的解析器在遍历消息链时会把被吞掉的条目当作前一条消息的填充数据直接跳过。

这个「吞噬」技巧通过 bpf_probe_write_user 这个 BPF 辅助函数实现——这个函数本来是给调试用的,被 VoidLink 拿来做了创造性的滥用。Elastic 的报告指出,这种 Netlink 缓冲区操纵手法在公开文献中极少被记录。

四代进化:从粗暴到精密

泄露的源码揭示了至少四代 rootkit 的迭代轨迹,每一代都在适应更新的内核防御机制。

第一代(CentOS 7 / kernel 3.10) 是最原始的版本,1148 行代码,直接修改系统调用表。在 3.10 内核上,kallsyms_lookup_name() 还是公开导出的符号,定位系统调用表很容易。修改时需要临时关闭 CPU 的写保护位(CR0 寄存器),这是一个在 rootkit 开发圈子里有悠久历史的经典手法。这一代还有个有意思的细节:它会暴力枚举 GCC 编译器优化后的符号名后缀(.isra.0.constprop.5 等),每种后缀尝试 20 个变体,说明开发者在实际部署中遇到过符号被重命名的问题。

第二代(kernel 5.x) 被迫改变策略。从 kernel 5.7 开始,kallsyms_lookup_name() 不再导出,系统调用表也加了更强的写保护。第二代用了 rootkit 圈子里流行的「kprobe 把戏」——注册一个指向 kallsyms_lookup_name 的 kprobe,内核在注册过程中会自动解析地址并存在 kp.addr 字段里,读出来后立刻注销。系统调用劫持也从直接改表换成了 ftrace 钩子。

第三代(生产版) 加入了模块参数,操作者可以在加载时直接指定要隐藏的进程 ID 和端口,不用再等 ICMP 命令通道建立。它还在两条 Netfilter 链上同时注册钩子,确保在各种网络配置和 iptables 规则下都能可靠接收命令。最关键的变化是正式把 ss 隐藏任务交给了 eBPF 组件。

第四代(「Ultimate Stealth v5」) 是最成熟的版本,引入了几项高级规避技术:

  • 延迟初始化:模块加载时只做最基本的符号解析就返回「成功」,三秒后才通过 delayed_work 安装所有钩子。这样,任何在模块加载事件触发时扫描的安全工具都会认为这是个干净模块。
  • 反调试定时器:每五秒扫描一次全部进程列表,检测 stracegdbbpftoolrkhunter 等 13 种调试和取证工具。
  • 进程保护:通过 ftrace 劫持 do_send_sig_info,拦截发送给受保护进程的 SIGKILLSIGTERM 等致命信号,返回成功但实际不投递——管理员以为 kill 成功了,进程却还在运行。
  • 模块伪装:模块元数据伪装成 AMD 的内存加密驱动 amd_mem_encrypt,在云实例和虚拟机上很难引起怀疑。模块名还用 XOR 加密存储,防止简单的字符串扫描发现伪装名。

ICMP 隐蔽通道

VoidLink 所有版本都内置了 ICMP 隐蔽指挥通道。操作者发送特制的 ICMP Echo Request 包,rootkit 的 Netfilter 钩子在内核正常处理之前就拦截这些包,执行命令后直接丢弃,不发回 ICMP Reply。

识别机制靠 ICMP 头部 echo.id 字段的魔数(默认 0xC0DE),命令数据用单字节 XOR 加密(默认密钥 0x42)。生产版支持 10 种命令,包括隐藏进程/端口、提权(直接把目标进程的 UID/GID 设为 0)和自毁。

有意思的是运行时密钥轮换功能:操作者可以在运行中更换魔数和加密密钥,之后所有命令必须使用新值。即使防御者发现了初始的 0xC0DE 签名,攻击者换个值就能继续操作。控制脚本 icmp_ctl.py 的 v2 版本甚至有个「探测模式」,会遍历常用魔数列表(0xC0DE0xDEAD0xBEEF0xCAFE0xFACE)来重新找回密钥被轮换过的 rootkit。

不过这个通道有个固有弱点:所有命令包都被静默丢弃(NF_DROP),正常的 ICMP Echo Request 会收到回复,而 rootkit 命令不会。研判:一个能关联 ICMP 请求和响应的网络监控系统,应该能发现这种「有去无回」的异常 ping 模式。

AI 辅助开发的微观证据

Check Point 从宏观层面证实了 VoidLink 用 AI 开发——恢复了冲刺规划文档、TRAE IDE 工件和规范驱动的开发流程。Elastic 的源码分析则从微观层面补充了这个发现。

最有说服力的证据是 CentOS 7 版本中的分阶段重构标注。文件头有一个结构化变更日志,读起来就像一系列 LLM 对话轮次:「修复安全问题」(Phase 1)、「改进隐身」(Phase 2)、「添加兼容性」(Phase 3)、「提升稳定性」(Phase 4)、「添加防御机制」(Phase 5)。代码中每个修改都标有 [1.1][2.3][5.2] 这样的标签,对应特定阶段的特定修复编号。

注释风格也很说明问题。一个三行的 XOR 解密循环上面标着「XOR 解密」——有经验的内核开发者不会给这么显而易见的代码写注释。每个源文件都用相同的 Unicode 盒线字符(═══)分隔章节,这种装饰性格式是 LLM 生成代码的典型特征。

ebpf_test/ 目录是最生动的证据。从 hide_ss.bpf.c 到 hide_ss_v9.bpf.c,10 个版本逐步迭代,多个版本里留着注释掉的「方法尝试」标注,读起来像思维链推理的痕迹。

但 VoidLink 不是纯 AI 创作。控制脚本里有真实的阿里云 IP 地址(8.149.128[.]10 和 116.62.172[.]147),说明在真实目标上使用过。编译好的 .ko 文件针对特定内核版本,启动脚本 load_lkm.sh 的 memfd 扫描逻辑表明它是更大攻击工具链的一部分。研判:最可能的开发模式是人-AI 协作——人定义需求并在真实系统上测试,AI 生成初始实现并根据错误报告迭代修复。

据 Check Point 和 Sysdig 的分析,开发者使用了字节跳动的 TRAE IDE(一个基于 VS Code 分支的 AI 编程工具,免费提供 Claude 和 GPT-4o 访问)。整个项目从 2025 年 11 月 27 日启动到 12 月 4 日达到功能可用状态,不到一周。一个原本需要三个团队 30 周的开发计划,被一个人配合 AI 压缩到了几天。

Sysdig 发现的额外能力

Elastic 的分析聚焦于 rootkit 源码,而 Sysdig 威胁研究团队在 1 月的独立分析中发现了一个此前从未被记录的技术——服务端 Rootkit 编译(Serverside Rootkit Compilation, SRC)。

LKM rootkit 有一个老大难问题:内核模块必须针对特定内核版本编译,跨版本部署很困难。VoidLink 的解决方案是让 C2 服务器按需编译。植入体把目标机器的内核信息发送到 C2,C2 返回一个针对该内核版本量身定制的模块。这意味着植入体本身可以保持小巧,rootkit 代码可以在服务端更新,不需要在目标机器上安装编译工具。

框架还会根据内核版本自动选择部署方式:kernel 6.x 用远程编译的 eBPF,kernel 5.x 用 eBPF + LKM 混合模式,更老的内核用远程编译的 LKM。

威胁态势评估

VoidLink 放在更大的背景下看,标志着 eBPF rootkit 正在成为一个不可忽视的威胁类别。2025 年 10 月,Synacktiv 披露了 LinkPro rootkit,同样利用 eBPF 隐藏进程和通过「魔术包」激活后门。FortiGuard Labs 在 2025 年底报告了 BPFDoor 的 151 个新样本和 Symbiote 的新变种,都在升级 eBPF 过滤能力。

研判:VoidLink 的出现与这些趋势共同说明,eBPF 这把双刃剑正在被越来越多地武器化。它本是 Linux 内核的可观测性利器(Cilium、Tetragon 等工具都依赖它),但同样的能力也让 rootkit 可以在内核中近乎隐形地运行。更令人担忧的是 AI 辅助开发降低了门槛——以前写内核级 rootkit 需要多年内核编程经验,现在一个懂概念但缺乏实现能力的操作者,配合 LLM 迭代就能产出功能完善的多代 rootkit。

检测与防御要点

尽管 VoidLink 层层伪装,Elastic 指出了几个可行的检测切入点:

  • 模块完整性:rootkit 会从内核模块链表中删除自己(lsmod 看不到),但 /sys/module/ 下的 sysfs 条目可能还在。比较 lsmod 和 ls /sys/module/ 的差异能暴露隐藏模块。在没有 AMD 硬件的系统上出现 amd_mem_encrypt 模块是强异常信号。
  • ftrace 钩子:检查 /sys/kernel/debug/tracing/enabled_functions,对 __x64_sys_getdents64vfs_read 等函数的异常 ftrace 钩子高度可疑。但注意 VoidLink 的 vfs_read 钩子会过滤这个文件,需要从可信内核检查。
  • eBPF 程序bpftool prog list 可以枚举所有加载的 BPF 程序。附着在 __sys_recvmsg 上的 kprobe/kretprobe 在生产环境中不寻常。监控 bpf_probe_write_user 辅助函数的使用也是一个检测点。
  • 行为交叉验证:比较 ps aux 与 /proc/ 目录条目、netstat 与 ss 与 /proc/net/tcp 的输出。如果 eBPF 组件未加载或隐藏列表不同步,不同视角之间的不一致就是 rootkit 活动的标志。
  • ICMP 异常:关联 ICMP Echo Request 与 Reply,没有回复的 ping 包值得调查。

防御层面,Elastic 建议启用 Secure Boot 和内核模块签名、Linux 5.4+ 的 kernel lockdown 模式、通过 Auditd 监控 init_module/finit_module 系统调用,以及用 seccomp 或 LSM 策略限制 bpf() 系统调用。