跳转到帖子

Windows 远控木马逆向分析实战:从持久化、配置提取到日志闭环

精选回复

发布于

背景与场景

本文记录一次授权内网排查中的 Windows 远控木马分析流程。终端告警显示某台办公主机周期性连接外部地址 192.0.2.45,进程来源为用户目录下的 updatehelper.exe。该地址属于文档示例网段,文中的文件名、域名和特征均已脱敏。

分析目标不是直接运行样本“观察一下”,而是回答四个具体问题:样本如何启动、远控配置存放在哪里、是否存在进程注入或凭据访问、哪些日志可以用于横向排查。

样本必须放在断网或 Host-Only 网络的隔离虚拟机中分析,并保留原始文件副本、哈希、采集时间和来源路径。不要在生产终端上直接双击验证。

一、证据固定与初步定位

先对文件做只读复制并记录基本属性。除 SHA256 外,还应检查数字签名、备用数据流和原始路径。Zone.Identifier 能帮助判断文件是否经浏览器、邮件或压缩包落地。

$sample = 'D:\case\updatehelper.exe'

Get-FileHash $sample -Algorithm SHA256
Get-AuthenticodeSignature $sample | Format-List Status,StatusMessage,SignerCertificate
Get-Item $sample -Stream *
Get-Content $sample -Stream Zone.Identifier -ErrorAction SilentlyContinue

sigcheck64.exe -accepteula -nobanner -h -i -m $sample
diec.exe $sample
capa.exe $sample

需要重点记录以下异常:

  • 签名缺失、签名无效,或签名主体与文件描述明显不一致。
  • 编译时间早于 PE 格式版本、晚于文件落地时间,或者时间戳为 0。
  • 导入表极少,但包含 VirtualAlloc、VirtualProtect、LoadLibrary、GetProcAddress 等动态解析相关 API。
  • 节区名称异常、可写可执行节区同时存在,或某个节区熵值接近 8,提示加壳或加密数据。
  • capa 命中 HTTP 通信、注册表持久化、屏幕捕获、键盘输入监控或进程注入能力。

加壳判断不能只依赖熵值。正常安装程序、压缩资源和 .NET 单文件程序同样可能具有高熵节区,应结合入口点、节区权限、导入数量和运行时行为确认。

二、静态逆向:定位启动逻辑与远控配置

将样本导入 Ghidra、IDA 或 Binary Ninja 后,先确认它是原生 PE 还是 .NET 程序。.NET 样本可优先使用 dnSpyEx 或 ILSpy;原生样本则从入口点向下追踪 CRT 初始化,直到进入实际业务函数。

本例在字符串和交叉引用中发现以下线索:

  • 互斥体前缀 Global\UpdateHelper-,用于避免重复运行。
  • 注册表路径 Software\Microsoft\Windows\CurrentVersion\Run。
  • URI /api/v2/checkin,以及固定的 User-Agent。
  • WinHttpOpen、WinHttpConnect、WinHttpSendRequest、WinHttpReceiveResponse 调用链。
  • 配置标记 CFG0,后接四字节长度、单字节密钥和加密内容。

追踪 CFG0 的交叉引用后,可以看到解码循环对每个字节执行异或操作,随后将结果交给 JSON 解析函数。以下脚本用于离线提取这种样本特定格式,不执行 PE 文件本身:

from pathlib import Path
import json
import struct

path = Path('updatehelper.exe')
data = path.read_bytes()
marker = b'CFG0'
off = data.find(marker)

if off < 0:
    raise SystemExit('CFG0 marker not found')

# 布局:CFG0 | uint32_le length | uint8 key | encrypted_data
length = struct.unpack_from('<I', data, off + 4)[0]
key = data[off + 8]
start = off + 9
end = start + length

if length > 0x10000 or end > len(data):
    raise SystemExit('invalid config length')

plain = bytes(value ^ key for value in data[start:end])
config = json.loads(plain.decode('utf-8'))

# 避免把令牌直接输出到共享终端
for name in ('token', 'campaign_id'):
    if name in config:
        config[name] = '[redacted]'

print(json.dumps(config, ensure_ascii=False, indent=2))

提取结果中通常值得关注的字段包括 C2 主机、端口、URI、休眠间隔、抖动比例、活动时间段、互斥体和安装路径。配置中的域名与 IP 应先作为待验证 IOC,不能仅凭字符串存在就直接封禁,因为未使用的测试地址或旧配置也可能残留在样本中。

三、动态分析:确认真实行为

动态分析环境建议使用快照虚拟机、Host-Only 网卡、FakeNet-NG 或 INetSim,并确认虚拟机无法访问生产 DNS、代理和共享目录。分析前启动 Procmon、Process Explorer、Sysmon 和网络抓包。

# 在隔离分析机中启动网络模拟
fakenet.exe

# 采集系统事件,时间范围按实际样本运行窗口调整
$start = (Get-Date).AddMinutes(-20)
Get-WinEvent -FilterHashtable @{
    LogName  = 'Microsoft-Windows-Sysmon/Operational'
    Id       = 1,3,7,8,10,11,12,13,22
    StartTime = $start
} | Select-Object TimeCreated,Id,Message | Out-File .\sysmon-timeline.txt

# 检查常见用户级持久化位置
reg query 'HKCU\Software\Microsoft\Windows\CurrentVersion\Run'
reg query 'HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce'
schtasks /query /fo LIST /v > scheduled-tasks.txt

Sysmon 事件可以按以下关系串联:

  • 事件 1:确认父进程、命令行、当前目录、文件哈希和完整性级别。
  • 事件 11:观察样本是否复制到 AppData、ProgramData 或临时目录。
  • 事件 12、13:确认 Run 键、服务配置或其他注册表持久化。
  • 事件 3、22:关联 DNS 查询、目标地址和发起网络连接的进程。
  • 事件 7:检查异常 DLL 加载路径,特别是用户可写目录。
  • 事件 8、10:排查远程线程创建和跨进程访问。单条事件不足以证明注入,应结合源进程、目标进程、访问权限和调用栈判断。

本例运行后先复制自身至 %APPDATA%\UpdateHelper\update.exe,再写入当前用户 Run 键。网络侧每 60 秒发起一次 POST,请求间隔存在约 20% 抖动。FakeNet-NG 返回模拟响应后,样本继续请求任务 URI,说明该地址是实际通信路径而不是未引用字符串。

如果样本使用 HTTPS,不建议为了“看明文”而让隔离机访问真实 C2。可以从 SNI、证书、目标地址、报文长度和周期性建立关联;若需要解析协议,应在本地模拟服务端,或在调试器中于加密前的请求缓冲区下断点。

四、识别进程注入与权限边界

远控木马常把通信或插件代码放入其他进程。逆向时可重点寻找 OpenProcess、VirtualAllocEx、WriteProcessMemory、NtWriteVirtualMemory、CreateRemoteThread、NtCreateThreadEx、QueueUserAPC 等组合,但不要把单个 API 当作确定结论。

判断注入是否成功,至少需要同时满足若干证据:

  • 源进程对另一进程申请了包含写入或创建线程能力的句柄。
  • 目标进程出现无文件映射的可执行内存区域,或私有内存中的 PE 头。
  • 目标进程随后发起与其业务不符的外联。
  • 线程起始地址不属于已加载模块,调用栈落在匿名内存区域。

权限边界也应单独记录。如果样本仅写入 HKCU Run 且保持中完整性,说明它获得的是用户级持久化;若创建服务、写入 HKLM、修改系统目录或访问 LSASS,则通常涉及管理员权限、提权利用或错误配置。修复时不能把“删除 Run 键”等同于完成处置。

五、构建样本特定检测规则

检测规则应选择多个相对稳定的特征组合,避免只使用文件名、IP 或单个字符串。下面的 YARA 规则基于本例的配置标记、URI 和互斥体,仅适合初步搜索,部署前必须用正常软件样本集测试误报。

rule RAT_UpdateHelper_Config_Family
{
    meta:
        description = "Detects the analyzed UpdateHelper RAT family"
        scope = "sample-specific"

    strings:
        $cfg = "CFG0" ascii
        $uri = "/api/v2/checkin" ascii
        $mutex = "Global\\UpdateHelper-" ascii wide
        $run = "Software\\Microsoft\\Windows\\CurrentVersion\\Run" ascii wide

    condition:
        uint16(0) == 0x5A4D and
        filesize < 5MB and
        $cfg and 2 of ($uri, $mutex, $run)
}

主机侧还可以围绕行为建立检测:用户目录中的未签名程序创建 Run 键后,在短时间内周期性外联;办公软件或压缩软件启动后,出现落地 PE、注册表持久化和网络连接的连续事件。这类行为规则通常比固定哈希更能覆盖重编译变种。

六、影响范围排查

完成单机逆向后,应把静态和动态结果转成可检索条件,在 EDR、Sysmon、DNS、代理、防火墙和身份日志中做范围确认:

  • 搜索 SHA256、原始文件名、落地路径、互斥体和注册表值数据。
  • 查询相同域名、目标 IP、URI、User-Agent 和固定周期外联。
  • 检查样本父进程是否为邮件客户端、浏览器、Office 或脚本解释器。
  • 检查受影响账户在样本首次执行后的远程登录、文件共享、计划任务和服务创建记录。
  • 如果存在进程注入或凭据访问迹象,扩大到同账号登录过的其他主机,不要只处理告警终端。

七、风险处置与修复建议

  • 先隔离主机,再采集内存、样本、事件日志、计划任务、服务、网络连接和自启动项。直接删除文件会破坏时间线。
  • 在完成取证后移除 Run 键、恶意计划任务、服务和落地文件,并检查同目录下的配置、插件与更新副本。
  • 如果确认存在代码注入、凭据读取、内核驱动或无法解释的高权限行为,优先重装或恢复可信镜像,不建议只做手工清理。
  • 从干净设备重置受影响账户的密码、会话令牌和相关密钥。仅修改本机密码不能使已签发的云端会话失效。
  • 在出口策略中限制普通终端直接访问公网,统一经过可审计代理,并启用 DNS、进程创建、网络连接和 PowerShell 日志。
  • 修复完成后复核原持久化位置、异常外联、内存注入迹象和账号登录记录,至少覆盖一个完整的原始回连周期。

总结

远控木马逆向分析的价值不只是得到一个 C2 地址,而是把样本内部逻辑、终端行为和现有日志连接起来。静态分析用于定位配置和关键函数,隔离动态分析用于验证真实执行路径,Sysmon、EDR 与网络日志用于确认影响范围。最终处置应围绕权限边界和证据闭环展开,避免仅删除样本后就判断事件结束。

逆向分析与样本观察示意图
逆向分析、样本行为与调试流程示意
服务器与云环境安全示意图
服务器、云资产与权限边界梳理示意

这类样本建议把“持久化、配置、通信、日志”按时间线串起来分析,单独看某个注册表键很容易误判。尤其要注意:有些远控木马首次运行只创建计划任务或服务,后续进程才解密 C2 配置。

我一般会先做一份基线,再启动样本:

reg.exe export HKCU\Software\Microsoft\Windows\CurrentVersion\Run before.reg
schtasks /query /fo LIST /v > tasks-before.txt
sc.exe query type= service state= all > services-before.txt
wmic startup get Caption,Command,Location,User > startup-before.txt

样本运行后再次执行并对比,重点看任务的 Actions、Triggers 和服务的 ImagePath,不要只看名称。若命令行包含 rundll32、regsvr32、mshta 或临时目录路径,建议沿着实际加载模块继续跟踪。

配置提取方面,比直接在字符串窗口搜索域名更可靠的是在网络 API 入口截获明文参数。x64 下可以在 WinHttpConnect、WinHttpOpenRequest、InternetConnectW、WSAConnect 处下断点;如果使用自定义加密,则在加密函数返回后、发送函数调用前检查缓冲区。动态调试时记录以下字段即可形成可复现样本:

时间
进程 PID / 线程 ID
目标地址与端口
解密后配置缓冲区地址和长度
发送前数据摘要(SHA-256)
持久化写入的路径或注册表键

日志闭环建议同时采集进程创建、文件落地、注册表修改和网络连接,单靠样本自身日志可能被清理。Windows 侧可以先用 Sysmon 关注 Event ID 1、3、11、12/13、19-21,再把 PID 和时间戳对齐;如果发现网络连接早于配置落地,通常说明配置来自资源段、环境变量或二阶段下载,而不是本地配置文件。

另外,分析持久化时最好验证重启后的实际触发链:入口程序 → 解密/解包 → 子进程 → 网络模块。很多样本创建的任务只是启动器,真正的 C2 配置和通信代码在子进程中,若只对首个进程下断点,容易漏掉关键行为。

创建帐户或登录后发表意见

最近浏览 0

  • 没有会员查看此页面。