本帖最后由 图钉鱼 于 2026-6-30 09:20 编辑
4. XWorm RAT 功能方法清单
从 stage-3 反编译代码中识别的功能方法:
│ 方法名 │ 功能描述
│ BeginConnect │ 初始化 C2 连接 │
│ ConnectServer│ 连接到 C2 服务器 │
│ BeginReceive │ 开始接收 C2 命令 │
│ BeginRead │ 读取 C2 数据 │
│ Read │ 读取数据 │
│ Send │ 发送数据到 C2 │
│ EndSend │ 结束发送 │
│ SendMSG │ 发送消息 │
│ SendError │ 发送错误信息 │
│ Ping 发送 Ping │
│ Pong │ 响应 Ping │
│ isDisconnected│ 检测断开连接 │
│ Info 收集系统信息 │
│ INDATE │ 心跳/保持连接 │
│ GPU │ GPU 信息收集 │
│ CPU │ CPU 信息收集 │
│ RAM │ RAM 信息收集 │
│ Monitoring │ 监控功能 │
│ Spread │ USB 传播 (枚举 DriveInfo, 复制 USB.exe)│
│ UAC │ 管理员权限检测 (WindowsPrincipal.IsInRole) │
│ Antivirus │ 杀软查询 (WMI SecurityCenter2) │
│ OpenUrl │ 打开 URL (可见/隐藏) │
│ Cam │ 摄像头访问 │
│ UNS │ 自卸载/自更新 (批处理自删除) │
│ Plugin │ 插件系统 (Assembly.Load + 反射 Invoke)│
│ TD │ DDoS 攻击线程入口 │
│ XLogger.callk│ 键盘记录 (WH_KEYBOARD_LL = 13) │
└──────────────┴─────────────────────────────────────┘
注: 本次反编译未见 CMSTP UAC Bypass 实现,UAC() 方法仅检测当前进程是否
以 Administrator 身份运行 (WindowsBuiltInRole.Administrator),向 C2
回报。
4A. RAT 内部机制深度分析 (Internal Mechanics)
以下分析基于 uuu 版本反编译代码 (stage3_decompiled.cs, 317,239 字节),
huu 版本结构相似 。
4A.1 启动流程 (Main 函数)
位置: Stub.Main.Main() (行 3352)
启动序列:
1. Thread.Sleep(Settings.Sleep * 1000) // 延迟启动, Sleep=1 → 1秒
2. AES 解密所有 Settings 字段 (Hosts/Port/KEY/SPL/Groub/USBNM)
3. Ⴜ.Ⴍ() // 创建全局 Mutex (Settings.Mutex)
// 失败则 Environment.Exit(0) — 防止多实例
4. Ⴜ.Ⴃ() // 安装持久化 (注册表写入 + 文件释放)
5. new Thread(XLogger.callk).Start() // 启动键盘记录线程
6. new Thread(Ⴜ.Ⴐ).Start() // 启动辅助线程 (USB 传播等)
7. 主线程进入 C2 连接循环:
while (true) {
if (!isConnected) {
isDisconnected();
BeginConnect(); // 异步连接 C2
}
allDone.WaitOne(); // 等待连接完成
Sleep(random(3000, 10000)); // 随机延迟, 反检测
}
4A.2 C2 通信协议 (ClientSocket 类)
位置: ClientSocket 类 (行 3513)
协议类型: 自定义 TCP 异步协议 (长度前缀 + 数据块)
连接参数:
Socket: AddressFamily.InterNetwork, Stream, Tcp
SendBufferSize = ReceiveBufferSize = 51200 字节
远程: Settings.Host : int.Parse(Settings.Port)
多 C2 容错: Settings.Hosts 用逗号分隔, 随机选择一个
握手流程:
1. ConnectServer(host) 建立连接
2. Send(Info()) // 发送上线信息包 (见 4A.3)
3. 启动心跳 Timer (10000-15000ms 随机间隔)
4. BeginReceive 异步接收循环
消息格式 (上行/下行相同):
┌────────┬──────────────────────────────────────────┐
│ 字节 0 │ 含义: 消息长度高位字节 (or 标记字节) │
├────────┼──────────────────────────────────────────┤
│ 字节 1 │ 消息总长度 (计算自 Ⴐ = f(MemoryStream)) │
├────────┼──────────────────────────────────────────┤
│ 字节 2+│ 消息体 (SPL 分隔的字符串数组) │
└────────┴──────────────────────────────────────────┘
接收状态机 (BeginReceive, 行 4409):
阶段 1: 接收 1 字节, 若 != 0 → 计算预期长度 Ⴄ
阶段 2: 分配 byte[Ⴄ-1] 缓冲区, 继续接收
阶段 3: 检查 MemoryStream.Length == Ⴄ → 完整消息
阶段 4: 启动新线程调用 BeginRead(byte[]) 处理
阶段 5: 重置 MemoryStream, 继续下一次接收
────────────────────────────────────────────────────────────────────────────────
4A.3 上线信息包 (Info 函数)
────────────────────────────────────────────────────────────────────────────────
位置: Info() (行 ~3780-3874)
构造 27 字段数组, 用 Settings.SPL ("<Xwormmm>") 拼接:
┌──────┬──────────────────────────────────────────────┐
│ 索引 │ 字段内容 │
├──────┼──────────────────────────────────────────────┤
│ 0 │ 命令标识 (上线) │
│ 2 │ 计算机名/用户名 (My.Computer.Name) │
│ 4 │ 当前日期时间字符串 │
│ 6 │ 操作系统信息 (ComputerInfo.OSFullName) │
│ 8 │ .NET CLR 版本 │
│ 10 │ Settings.Groub = "XWorm V7.1" (组名) │
│ 12 │ INDATE() — 安装日期 │
│ 14 │ Spread() — USB 传播状态 │
│ 16 │ UAC() — 管理员权限状态 ("True"/"False") │
│ 18 │ Cam() — 摄像头可用性 │
│ 20 │ CPU() — CPU 型号 (Win32_Processor) │
│ 22 │ GPU() — 显卡型号 (Win32_VideoController) │
│ 24 │ RAM() — 物理内存容量 │
│ 26 │ Antivirus() — 杀软名称 (SecurityCenter2) │
└──────┴──────────────────────────────────────────────┘
────────────────────────────────────────────────────────────────────────────────
4A.4 命令分发列表 (Read 函数)
────────────────────────────────────────────────────────────────────────────────
位置: Read(byte[] b) (行 5015)
收到 C2 数据后用 Settings.SPL 分隔, array[0] 为命令名,
通过 AlgorithmAES._isr(cmd, "<命令字符串>", false, ...) 进行 Babel
混淆的字符串比较, 路由到对应处理逻辑:
┌──────────────┬──────────────────────────────────────────────────────┐
│ 命令字符串 │ 行为 │
├──────────────┼──────────────────────────────────────────────────────┤
│ pong │ 重置 ActivatePong=false, Interval=0 (心跳响应) │
│ rec │ 调用 Ⴜ.Ⴃ.Ⴓ() (录制/恢复) │
│ CLOSE │ Socket.Shutdown(Both) + Close, 断开 C2 │
│ uninstall │ UNS(IsUpdate:false, null, null) — 自卸载 │
│ update │ UNS(IsUpdate:true, url, hash) — 下载更新并替换 │
│ DW │ 下载 URL 到本地路径并执行 (WebClient.DownloadFile) │
│ Urlopen │ OpenUrl(url, Hidden:false) — 可见打开 URL │
│ Urlhide │ OpenUrl(url, Hidden:true) — 隐藏打开 URL │
│ RunShell │ My.MyComputer.ႠႭ(cmd, AppWinStyle.Hide) — 隐藏执行 │
│ StartDDos │ DDos = new Thread(TD) — 启动 DDoS 攻击线程 │
│ StopDDos │ DDos.Abort() — 停止 DDoS │
│ StartReport │ ReportWindow = new Thread(Monitoring) — 启动监控 │
│ StopReport │ ReportWindow.Abort() — 停止监控 │
│ plugin │ Plugin(base64decode(array[1])) — 加载 .NET 插件 │
│ sendPlugin │ Plugin(byte[]) — 加载字节数组插件 │
│ savePlugin │ 保存插件到磁盘 │
│ RemovePlugins│ 卸载所有插件 │
│ $Cap / #CAP │ 屏幕截图: 256x156 JPEG, Base64 编码, 通过 C2 回传 │
│ Xchat │ 聊天消息转发 │
│ Hosts │ 主机列表/远程执行 │
│ OfflineGet │ 离线命令获取 │
│ XLogger │ 触发键盘记录器 │
│ PCShutdown │ 关机 │
│ PCRestart │ 重启 │
│ PCLogoff │ 注销 │
│ LN │ 登录相关 │
└──────────────┴──────────────────────────────────────────────────────┘
屏幕截图实现 (行 5443-5540):
Screen.PrimaryScreen.Bounds 获取屏幕尺寸
new Bitmap(w, h, Format16bppRgb555)
Graphics.CopyFromScreen 捕获屏幕
缩放到 256x156 (大幅降低传输量)
JPEG 编码 → Base64 → 通过 C2 回传
含 Graphics/Bitmap/MemoryStream 资源释放
────────────────────────────────────────────────────────────────────────────────
4A.5 心跳机制 (Ping 函数)
────────────────────────────────────────────────────────────────────────────────
位置: Ping() (行 4853)
定时器: System.Threading.Timer, 10000-15000ms 随机间隔
- 随机化避免固定周期被检测
心跳消息格式:
array[0] = "PING!" (Babel 解密)
array[1] = Settings.SPL
array[2] = Ⴜ.Ⴃ.Ⴙ() // 哈希值/会话标识
array[3] = Settings.SPL
array[4] = Ⴜ.Ⴃ.Ⴍ // 计数器
状态机:
发送 PING 后: ActivatePong = true
收到 C2 "pong" 命令: ActivatePong = false, Interval = 0
若长时间未收到 pong: 连接视为失效, 触发重连
────────────────────────────────────────────────────────────────────────────────
4A.6 持久化机制
────────────────────────────────────────────────────────────────────────────────
位置: Ⴜ.Ⴃ() 安装函数 + Ⴓ(string, byte[]) 注册表写入 (行 12212)
注册表写入 (HKCU):
路径: HKEY_CURRENT_USER\<Ⴍ.Ⴃ.Ⴈ> (子键路径由 Babel 解密变量持有)
操作: Registry.CurrentUser.CreateSubKey(path, ReadWriteSubTree)
RegistryKey.SetValue(name, value, RegistryValueKind.Binary)
类型: REG_BINARY (字节数组, 而非经典 Run 键的 REG_SZ)
注册表读取 (行 12288):
Ⴀ(string P_0) — 从 HKCU\<subkey> 读取名为 P_0 的 REG_BINARY 值
返回 byte[] — 可能为 PE 字节流或配置数据
注: 经典 XWorm 通常写入 HKCU\Software\<随机>\<Name> 持久化键,
本样本因 Babel 名称混淆, 注册表子键具体名称需运行时动态解密获取,
静态分析无法直接还原。建议狩猎时扫描 HKCU 下所有 REG_BINARY 值
与已知 Mutex/路径关联分析。
辅助持久化 (stage-2 loader, 见 Stage 6):
计划任务 1: YOL9BiN6Qx (msBuild.exe 路径)
计划任务 2: Z5rQ0GqDlI (huu.hta 路径)
使用 Microsoft.Win32.TaskScheduler v2.12.2.0
────────────────────────────────────────────────────────────────────────────────
4A.7 键盘记录器 (XLogger.callk)
────────────────────────────────────────────────────────────────────────────────
位置: XLogger 类 (行 9541-10031)
钩子安装:
SetWindowsHookEx(13, callback, hModule, 0)
// WH_KEYBOARD_LL = 13, 全局低级键盘钩子
GetModuleHandle(null) 获取当前模块句柄
回调类型 ႳႳ: delegate IntPtr(int nCode, IntPtr wParam, IntPtr lParam)
按键解码链:
1. GetForegroundWindow() — 获取活动窗口
2. GetWindowThreadProcessId(hwnd, out pid) — 获取进程 ID
3. Process.GetProcessById(pid).MainWindowTitle — 获取窗口标题
4. GetKeyState(vk) / GetKeyboardState(byte[256]) — 获取键状态
5. GetKeyboardLayout(threadId) — 获取键盘布局
6. MapVirtualKey(vk, 0) — 虚拟键 → 扫描码
7. ToUnicodeEx(vk, scancode, keystate, StringBuilder, 8, 0, hkl)
— 虚拟键 → Unicode 字符
日志写入:
文件: Settings.LoggerPath = "temp\Log.tmp"
模式: StreamWriter(path, append:true) — 追加
格式: 窗口切换时写入 "\r\n\r\n<窗口标题>\r\n"
按键直接写入字符 (特殊键映射为 [ENTER]/[SPACE]/[CTRL] 等)
已解密特殊键名映射 (Babel 解密):
[SPACE] [ENTER] [ESC] [CTRL] [Shift] [Back] [WIN] [Tab]
[CAPSLOCK: ON] / [CAPSLOCK: OFF]
────────────────────────────────────────────────────────────────────────────────
4A.8 插件系统 (Plugin 函数)
────────────────────────────────────────────────────────────────────────────────
位置: Plugin(byte[] B) (行 5716)
加载流程:
1. Assembly.Load(B) — 加载 .NET 程序集字节数组
2. 遍历 assembly.GetTypes():
- 查找含特定方法名的 Type
- 已知方法名 (Babel 解密): "Run" / "Main" / 其他重载
3. 对每个 Type, MethodInfo[] = Type.GetMethods()
4. 匹配方法名后, 反射 Invoke:
args[0] = null
args[1] = new object[] {
Settings.Host, // C2 主机
Settings.Port, // C2 端口
Settings.SPL, // 分隔符
Settings.KEY, // 通信密钥
Ⴜ.Ⴃ.Ⴀ() // HWID/会话标识
}
MethodInfo.Invoke(null, args)
5. 插件可调用宿主函数 (SendMSG/SendError/ClientSocket.Send)
安全含义:
攻击者可动态推送任意 .NET 程序集到受感染主机
插件继承宿主上下文, 直接复用 C2 通道
经典 XWorm 插件示例: 密码窃取、浏览器 Cookie 抓取、Telegram 窃取
────────────────────────────────────────────────────────────────────────────────
4A.9 自卸载/自更新 (UNS 函数)
────────────────────────────────────────────────────────────────────────────────
位置: UNS(bool IsUpdate, string Str, byte[] B) (行 7658)
IsUpdate=true (自更新):
1. 下载新版本到 Path.Combine(Path.GetTempPath(), Str)
2. 写入批处理脚本到临时文件, 内容 (Babel 解密):
@echo off
timeout 3 > NUL
DEL "<当前可执行文件>" /f /q
DEL "<批处理自身>"
3. Process.Start(新版本路径) — 启动更新
4. Process.Start(批处理) — 隐藏窗口执行删除
ProcessWindowStyle.Hidden, CreateNoWindow=true, UseShellExecute=false
5. Environment.Exit(0) — 退出当前进程
IsUpdate=false (自卸载):
1. 仅写入批处理脚本 (含 DEL 当前文件)
2. Process.Start(批处理) 隐藏执行
3. Environment.Exit(0)
批处理自删除技术: 经典反取证手段, 利用 timeout 延迟等待主进程退出,
然后强制删除主 PE 文件, 最后自删除批处理。
|