一、写在前面
这篇文章的诞生方式有点不太一样。
整个分析过程并非传统意义上分析人员独自坐在IDA前逐行跟调的模式,而是我们尝试让AI深度参与其中,承担了从样本初筛、壳识别、入口点定位、加解密算法还原、字符串提取到C2通信协议解析等大量基础但耗时的逆向工作。我们的角色更像是指挥人员,在旁边配置 MCP环境、提供分析思路、复核 AI 给出的结论,并最终把碎片化的发现组织成一篇结构完整的技术文章。
之所以想尝试这种方式,是因为银狐木马的变种迭代速度确实很快,传统的人工逆向分析在面对大量相似样本时,时间成本会成倍上升。如果能借助AI的能力把体力活自动化,分析人员就可以把更多精力放在攻击链逻辑梳理和防御策略制定上。当然,AI也有错误的时候,在本次文中就发现了大模型存在多次幻觉的地方,如您在本篇文中有发现不妥或错误之处,烦请各位技术大牛指出。
本次分析完整覆盖了从钓鱼入口、样本落地、持久化驻留、内存解密加载到C2通信的全过程。过程中我们发现该样本沿用了银狐家族典型的"克隆钓鱼 + DLL白加黑 + XOR内存解密"攻击范式,同时在代码层面引入了 obfusheader.h 进行编译时混淆,增加了静态分析的难度。
关于样本来源的说明:分析所用样本来源于公开威胁情报平台的可疑文件抓取,非任何客户环境直接采集。我们在分析完成后对提取到的C2域名、邮箱地址进行了必要的脱敏处理,仅保留技术层面的关键特征用于研究交流。
二、攻击链全景速览
为了让各位在阅读细节前先有一个整体印象,我们把这次攻击的完整链路浓缩成一张全景图。
完整链路全景图
整个攻击流程可以概括为以下几个阶段:
| 阶段 |
核心动作 |
关键技术 |
| 入口投递 |
伪造百度网盘登录页,诱导下载 |
域名仿冒(pan-baidu.com)、前端克隆 |
| 样本落地 |
90MB NSIS安装包释放白文件+恶意DLL |
大体积压缩包规避云查杀、白加黑 |
| 持久化驻留 |
篡改Edge更新组件、创建LNK快捷方式 |
伪装浩辰CAD(Gstarsoft Co.)合法签名 |
| 内存解密加载 |
XOR 0x36逐字节解密shellcode并执行 |
无文件落地、内存执行 |
| C2通信与远控 |
HTTP GET心跳、隐私数据回传 |
COM接口调用、浏览器隐私窃取 |
三、钓鱼入口初探
3.1 域名层面的伪装
这次攻击的入口是一个伪装成百度网盘登录页的钓鱼站点。我们在情报监控中捕获到可疑域名 pan-baidu.com,第一反应就是去比对一下微步情报中心的记录。
微步情报中心对 pan-baidu.com 的查询结果,该域名已被标记为恶意钓鱼站点
情报显示该域名确实存在问题。有趣的是,攻击者在域名构造上玩了一个小心思,把大家耳熟能详的 pan.baidu.com 中的"."改为了"-",变成 pan-baidu.com。对于匆忙间扫一眼地址栏的用户来说,这种视觉欺骗的成功率其实不低。
我们打开了钓鱼页面,和官方正版做了一个并排对比,大家感受一下这个仿真度。
钓鱼站点(左)与官方百度网盘登录页(右)的界面对比。从布局、配色到LOGO位置,钓鱼页面的还原度相当高
3.2 样本获取
在钓鱼页面中点击下载按钮后,浏览器会获取到一个体积不小的压缩包。我们在监控中记录到了这次的下载行为。
文件下载记录。获取到的样本文件名为 bai_du_wangpan.exe_saAw8.zip,压缩包大小约 90,502 KB(约90MB)
这个体积其实是攻击者刻意为之。把恶意载荷打包进一个接近百兆的压缩包中,可以有效绕过不少云端杀毒引擎的实时扫描。很多云查服务对超大文件的处理策略是"先放行后补扫",而这个时间差足够恶意程序完成初次执行。
四、样本落地与执行
上机取证/攻击行为链
4.1 初扫样本
拿到样本后,第一步照例用 Detect It Easy(DIE)过一遍,看看基本文件属性。
DIE 扫描结果。文件类型识别为 NSIS安装器,压缩资源段被标记为高熵值,提示可能包含加密或压缩的隐藏数据
DIE 给出的信息很明确:这是一个 NSIS 打包的安装程序。NSIS 本身是一款开源的 Windows 安装程序制作工具,在很多合法软件中都有使用,所以单看文件类型并不能直接判定为恶意。但压缩资源段的高熵值是一个值得关注的信号,这意味着资源中可能嵌入了经过加密或强压缩的数据,需要进一步释放后才能看到真实内容。
4.2 样本落地后的杀毒告警
样本在落地执行后不久,Windows Defender 就弹出了告警。
Windows Defender 弹窗告警,识别威胁为 Trojan:Win32/Ravartar!rfn。这个家族特征与银狐木马的历史变种高度吻合
Ravartar 这个家族名在银狐的分析报告中出现频率相当高。虽然不同厂商对同一恶意家族的命名可能存在差异,但从我们的历史数据来看,Defender 的这次检出指向性还是比较明确的。
4.3 上机取证:火绒剑全程行为监控
- 在分析 VM 上启动火绒剑(HRSword)
- 勾选进程、文件、注册表、网络全量监控
- 双击运行
bai_du_wangpan.exe
- 等待约 2 分钟后停止抓取
- 可导出日志传给AI分析
火绒剑主界面 + 监控勾选项(进程/文件/注册表/网络全选)
4.4 行为时间线
| 时间 |
进程 |
行为 |
意义 |
| 14:07:19 |
explorer→bai_du_wangpan.exe |
投递器启动 |
用户双击 |
| 14:07:24 |
bai_du_wangpan→cmd |
tasklist | findstr "360tray.exe" "HipsTray.exe" |
杀软探测 |
| 14:07:40 |
bai_du_wangpan |
创建 comain_ev2f79\,写 ev2f79.exe + 二进制文件 |
释放 RAT 加载器① |
| 14:07:46 |
bai_du_wangpan |
创建 comain_ev2c34\,写 ev2c34.exe + 二进制文件 |
释放 RAT 加载器② |
| 14:07:55 |
UserAccountBroker.exe |
TCP→202.79.169.198:8853 |
C2 信标 |
双击启动投递器(伪装的百度网盘安装包)
4.5 杀软侦察
样本启动 5 秒即执行:
cmd.exe /C tasklist | findstr /I /C:"360tray.exe" /C:"HipsTray.exe"
枚举进程中是否存在 360 安全卫士(360tray.exe)和火绒(HipsTray.exe),用于判断是否进入对抗/隐藏路径。
火绒剑捕获的 tasklist|findstr 命令行
4.6 释放物
在 %AppData%\Roaming\ 下建两个随机目录("comain_" 前缀 + 4 位随机十六进制):
comain_ev2f79 完整释放清单(加载器1,文件名不同但功能相同):
| 文件 |
大小 |
角色 |
| ev2f79.exe |
1.5MB |
RAT 加载器(与 ev2c34 同源变种) |
| otrm.oi |
164KB |
XOR-0x36 加密 shellcode(对应 ev2c34 的 fhkan.oi) |
| ntrin.er |
169KB |
XOR-0x36 加密 shellcode |
| yinma.vc |
479KB |
XOR-0x36 加密 shellcode |
| dxyvnb.ti |
57KB |
XOR-0x36 加密 shellcode |
火绒剑文件行为监控。样本运行后在桌面释放目录 comain_ev2f79,目录名采用随机生成的"comain_"前缀加随机字符组合,这是银狐家族在释放阶段的一个典型命名规律
comain_ev2c34 完整释放清单(加载器2):
| 文件 |
大小 |
角色(后续逆向确认) |
| ev2c34.exe |
1.5MB |
RAT 加载器(Gstarsoft 白加黑,Omaha 伪装) |
| fhkan.oi |
184KB |
XOR-0x36 加密 shellcode → Horse_in.dll(RAT 核心) |
| bteuns.pt |
546KB |
XOR-0x36 加密 shellcode → Protect.dll(保护) |
| bnymir.ou |
413KB |
XOR-0x36 加密 shellcode → upline.dll(C2) |
| cmrsk.ce |
170KB |
XOR-0x36 加密 shellcode → CreateUandE.dll(持久化) |
| ap.asin |
260B |
加密的 C2 配置(IP/端口/密钥) |
火绒剑文件行为监控。同时释放的第二个目录 comain_ev2c34,两个目录分别对应不同阶段的载荷组件
从释放目录的命名规律来看,comain_ 前缀加随机字符串的组合方式在银狐家族的历史样本中反复出现。这种命名没有实际语义,推测只是为了规避基于目录名的静态检测规则。
4.7 持久化
- 注册表标记:
HKCU\SOFTWARE\MicrosoftUserAdmin\SOURCE = baiduwangpan
- 程序**快捷方式**:桌面
baiduwangpan.lnk → C:\Program Files (x86)\Community\baiduwangpan.exe
注册表 HKCU\SOFTWARE\MicrosoftUserAdmin\SOURCE=baiduwangpan
桌面 baiduwangpan.lnk 属性(目标指向 Community\baiduwangpan.exe)
4.8 网络:C2
UserAccountBroker.exe TCP → 202.79.169.198:8853
每 ~13 秒重复一轮;全程无 DNS,直连 IP
上行固定 13 字节(握手/心跳),下行恒为 831,528 字节(固定载荷)
| 周期 |
时间 |
上行(send) |
下行(recv) |
| 1 |
14:34:38 |
13 字节 / 2 包 |
831,528 字节 / 595 包 |
| 2 |
11:34:50 (~13s) |
13 字节 / 2 包 |
831,528 字节 / 593 包 |
| 3 |
11:35:40 (~13s) |
13 字节 / 2 包 |
831,528 字节 / 597 包 |
| ... |
... |
... |
... |
三条流量指纹:①周期 ~13 秒;②上行恒为 13 字节(握手/心跳);③下行恒为 831,528 字节(固定载荷推送)。固定尺寸下行意味着 C2 每次推送同一个模块/配置,可在 NDR/IDS 侧直接写成阈值规则。
发起进程 UserAccountBroker.exe 是正版微软签名系统组件(Valid / Microsoft Windows,v10.0.14393.0),未被替换,C2 流量是 RAT 进程注入到该合法进程后发出的。
火绒剑网络行为,UserAccountBroker → 202.79.169.198:8853
五、白加黑与持久化驻留
加载器静态反编译推理流程
5.1 签名伪装
银狐家族在持久化阶段一直有自己的独特之处,也就是 DLL 白加黑。所谓白加黑,就是用一个带有合法数字签名的白文件(通常是正规软件的可执行文件)去加载同目录下名称匹配的恶意 DLL。由于白文件本身的签名是合法的,很多安全产品在行为判定上会给它一定的信任,恶意 DLL 就借这个机会随着白文件的启动而被加载进内存。
这次样本使用的白文件伪装成了浩辰CAD(Gstarsoft Co., Ltd.)的组件。
ev2c34.exe 文件属性截图,显示数字签名来自 "Gstarsoft Co., Ltd."(浩辰CAD)。攻击者利用浩辰CAD的合法签名作为信任伪装
这里简单介绍一下浩辰CAD。浩辰CAD是国内一款知名度较高的CAD设计软件,在工程设计、制造业等领域有不少企业用户。攻击者选择它作为伪装对象,一方面是因为它的签名为大众所信任,另一方面也可能是考虑到CAD软件通常需要较高的系统权限运行,这在一定程度上降低了后续恶意行为被拦截的概率。
不过我们注意到,虽然签名显示为浩辰CAD,但实际的证书哈希并不匹配官方版本,这是一个典型的签名冒用手法。攻击者可能通过提取合法文件的重叠签名信息,或者利用某些历史漏洞获取到的私钥,对恶意文件进行签名伪装。
5.2 PowerShell 签名验证
为了确认签名状态,我们用 PowerShell 的 Get-AuthenticodeSignature 做了进一步验证。
Get-AuthenticodeSignature 'C:\Users\Administrator\AppData\Roaming\comain_ev2c34\ev2c34.exe'
PowerShell 签名验证输出。Status 显示为 HashMismatch,意味着文件哈希与签名中的哈希值不匹配,文件内容已被篡改,但签名信息仍被保留用于伪装
HashMismatch 这个结果印证了我们的判断:攻击者对原始白文件做了修改(可能是注入了加载恶意DLL的逻辑),但保留了原始的签名外壳。这种"借壳上市"的手法在银狐家族中相当常见。
5.3 Edge更新组件的篡改
持久化的另一个关键动作是篡改 Chrome/Edge 的更新组件。样本会把自身的恶意模块注册到系统的更新任务中,借助浏览器更新服务的定期触发机制来实现长期驻留。
IDA Pro 反编译 WinMain 函数的伪代码视图。可以看到代码中对 EdgeUpdate 相关注册表项的操作,通过篡改浏览器更新组件实现持久化驻留
具体的操作逻辑是:向 HKLM\SOFTWARE\Microsoft\EdgeUpdate\WindowsUpdateAttempts 写入特定的键值,把恶意DLL的路径注册为"更新模块"。由于 EdgeUpdate 是系统级的合法服务,安全软件在默认情况下通常不会拦截它的注册表操作,这就给了恶意程序一个稳定的驻留通道。
5.4 快捷方式的创建
除了篡改更新组件,样本还会在桌面和开始菜单创建快捷方式,诱导用户点击启动。
C:\Users\Public\Desktop\bai_du_wangpan.exe.lnk
%APPDATA%\Microsoft\Windows\Start Menu\Programs\baiduwanpan.lnk
快捷方式指向的目标实际上是白文件(ev2c34.exe),用户双击后白文件会加载同目录下的恶意载荷,整个"白加黑"链路就此激活。
5.5 载荷文件的发现
地址0x418DCD(xor36_shellcode_loader),这是整个加载链最关键的函数,完全运行时动态解析 API(静态 IAT 里 CreateFileA/GetFileSize/VirtualAlloc/ReadFile 一个都看不到),流程:
① XOR 解密内嵌常量 → 目标文件名 "fhkan.oi"
常量 v21[0]=842807599, v21[1]=976811831
key v1=0x14, v2=0xBD;算法 b = v1 ^ (b - v2)
② GetModuleFileNameA → 取 ev2c34.exe 自身路径 → 替换文件名得到同目录的 "fhkan.oi"
③ CreateFileA(path, GENERIC_READ, OPEN_EXISTING)
④ VirtualAlloc(..., PAGE_EXECUTE_READWRITE) ← 申请 RWX 内存
⑤ ReadFile ← 整文件读入 RWX
⑥ for k: buf[k] ^= 0x36 ← 整体异或 0x36 解密
⑦ call buf ← 跳入 RWX 执行 shellcode
IDA反编译 xor36_shellcode_loader 全貌
内联注释 XOR-0x36 解密循环(@0x418F43)+ call buf 执行(@0x418F4D)
文件名解密可复现(Python)
import struct
v21 = bytearray(struct.pack('<II', 842807599, 976811831))
for i in range(8):
v21[i] = (0x14 ^ ((v21[i] - 0xBD) & 0xFF)) & 0xFF
print(v21.decode('latin1')) # => fhkan.oi
Python 解密脚本执行结果。通过对加密数据进行 XOR 0x36 解密,成功还原出字符串 "fhkan.oi",确认了加密算法和密钥
六、核心载荷的内存解密与加载
6.1 加密算法的确认
解密后的文件头部呈现出典型的 shellcode 特征。
# decrypt_二进制文件.ps1
$b = [IO.File]::ReadAllBytes('C:\Users\Administrator\AppData\Roaming\comain_ev2c34\fhkan.oi')
for ($i=0; $i -lt $b.Length; $i++) { $b[$i] = $b[$i] -bxor 0x36 }
[IO.File]::WriteAllBytes("$env:TEMP\fhkan.dec.bin", $b)
010editor 打开 fhkan.oi,头部 DE 36 36 36 36...(加密态)
010 Editor 打开解密后的 fhkan.dec.bin。头部字节序列为 E8 00 00 00 00 58 55 89 E5,即 CALL $+5(调用下一条指令)的标准 shellcode 入口模式,确认解密后的数据为可执行载荷
E8 00 00 00 00 是 x86 汇编中 CALL 指令的编码,后面跟的四个字节是相对于下一条指令的偏移量。当偏移量为 0 时,CALL 会跳转到下一条指令本身,执行时会把下一条指令的地址压入栈中,然后跳转到该地址。这种 "CALL $+5" 的技巧在 shellcode 中非常常见,用于获取当前执行地址(相当于 call 后 pop eax 获取 EIP)。
6.2 PE 提取
解密后的 shellcode 内嵌一个 PE(DLL)。用脚本提取(carve_pe.ps1):
# 从解密后的 shellcode 取出内嵌 PE (取最大有效 PE)
$二进制文件 = "$env:TEMP\fhkan.dec.bin"
$b = [IO.File]::ReadAllBytes($二进制文件)
$s = [Text.Encoding]::GetEncoding(28591).GetString($b)
$best = -1; $bestSz = 0
foreach ($m in [regex]::Matches($s,'M')) {
if ($m.Index+1 -ge $b.Length) { continue }
if ($b[$m.Index] -ne 0x4D -or $b[$m.Index+1] -ne 0x5A) { continue }
$o = $m.Index; if ($o+0x42 -ge $b.Length) { continue }
$ep = [BitConverter]::ToInt32($b,$o+0x3C); if ($o+$ep+6 -ge $b.Length) { continue }
if ($b[$o+$ep] -eq 0x50 -and $b[$o+$ep+1] -eq 0x45) { if ($b.Length-$o -gt $bestSz) { $bestSz = $b.Length-$o; $best = $o } }
}
$pe = New-Object byte[] $bestSz; [Array]::Copy($b,$best,$pe,0,$bestSz)
$out = "$env:TEMP\Horse_in.dll"; [IO.File]::WriteAllBytes($out,$pe)
Write-Host "取出 PE: $($bestSz) bytes -> $out"
对 4 个 二进制文件各做同样处理:
| 二进制文件(XOR-0x36) |
解出的 DLL |
导出名 |
架构 |
推测功能 |
| fhkan.oi |
Horse_in.dll |
AndStop |
x86 |
RAT 核心 |
| bteuns.pt |
Protect.dll |
Guard |
x64 |
保护/抗分析 |
| bnymir.ou |
upline.dll |
AndUp |
x64 |
C2 通信 |
| cmrsk.ce |
CreateUandE.dll |
CreateEnv |
x64 |
持久化 |
说明:这 4 个 DLL 是分析产物(从加密二进制文件中 XOR 解密+PE 提取得到),并非病毒直接释放到磁盘的文件。病毒只在 %AppData%\Roaming\comain_ev2XXXX\ 下释放加密 二进制文件,DLL 仅在运行时于内存中解密存在。
七、4 DLL 的 IDA 分析:控制流平坦化 + 加密派发
在对四个 DLL 进行反编译分析时,我们发现它们的代码结构均呈现出明显的混淆特征。银狐家族在此变种中引入了 obfusheader.h (https://github.com/ac3ss0r/obfusheader.h)进行编译时混淆。
obfusheader.h 是一款开源的 C++14 头文件级混淆库,由 ac3ss0r 开发并维护。它的主要功能包括:
- 编译时常量加密:在编译阶段对字符串和数值常量进行加密,运行时解密
- 调用隐藏:通过编译时函数指针数组随机重排,隐藏真实的调用关系
- 控制流分支变异:对 if/else/while/for/switch 等控制流结构进行内联混淆和分支重定义
- 间接分支:使用非标准的内联汇编块和间接跳转,干扰反编译器(如 IDA Pro)的伪代码生成
- 假签名:向二进制中注入类似 VMProtect、Themida 等保护工具的假签名,迷惑检测工具
7.1 逐个打开 DLL
在 IDA 中分别打开 4 个 DLL(Horse_in 基址 0x10000000;其余三个基址 0x18000000)。按 G 跳到各 DLL 的导出函数地址:
| DLL |
导出地址 |
导出名 |
| Horse_in.dll |
G→0x10008AD4 |
AndStop(thunk → JMP 0x10003E91) |
| upline.dll |
G→0x18000B5BB |
AndUp |
| CreateUandE.dll |
G→0x180001000 |
CreateEnv(thunk → JMP 0x18002C000) |
| Protect.dll |
G→0x180001000 |
Guard(thunk → JMP 0x180083E3A) |
7.2 混淆特征(控制流平坦化 + 加密派发 + junk 指令)
按 F5 反编译任何一个导出函数的主体(如 Horse_in 的 0x10003E91,x86 基址 0x10000000),会看到:
特征一:控制流平坦化(CFF)
整个函数体是一个 while(1) { switch(v57) { case 0x4984383C...: ... } } 结构。一个状态变量 v57 驱动巨型 switch 循环,把原本线性的逻辑打散成散块。
反编译 AndStop_0(0x10003E91),显示巨型 while+switch 控制流平坦化
特征二:加密派发表间接调用
所有函数调用都不是直接 call,而是经位于 .data 的加密派发表间接调用:
// 静态 .data 中派发表 (off_10022220) 存有加密数据(如 5F BA BC 94...),不是明文函数地址
// 运行时控制流平坦化 + 加密派发引擎用 XOR(key) 解密后计算出真实函数地址
((funcptr)(base + (table[idx] ^ key) + 1))(args)
特征三:派发表静态存有加密数据(非明文)
按 G→0x10022220(Horse_in 的派发表),查看 hex:
IDA hex view 跳到 0x10022220,显示加密数据 5F BA BC 94 A2 9E BD 94...(非明文函数地址)
派发表在 PE 文件中存有加密的调度数据(不是明文指针),只有运行时用 XOR 密钥解密才能还原真实函数地址。静态逆向到此完全堵死。
7.3 四个 DLL 统一 混淆架构
4 个 DLL 使用同一套混淆架构(控制流平坦化 + 加密派发 + junk 指令),但各自用不同的 XOR 密钥:
| DLL |
派发密钥 |
| Horse_in.dll |
0x576AC834 / 0x576AC835 / 0x4FF4E7DE |
| upline.dll |
0x51367ED18B2612B3 / 0x66459CA9309E9B14 |
| CreateUandE.dll |
0x8193BA3DDE636C11 / 0x8D86F4DF4B8813A9 |
| Protect.dll |
0x1AB4DB6A0249524A / 0x176763759D4B98AE |
四个 DLL 各自导出函数的 F5 反编译,对比相同的控制流平坦化 + 加密派发模式
四个 DLL 各自导出函数的 F5 反编译,对比相同的控制流平坦化 + 加密派发模式
静态逆向结论:确认了 4 个 DLL 全部采用控制流平坦化 + 加密派发,但无法还原内部逻辑(C2 协议、保护机制、持久化手法)。需要转向动态分析。
八、动态调试:x32dbg 验证 XOR-0x36 加载链
动态调试流程
8.1 为什么需要动态调试
静态分析做出了以下预测:
- xor36_shellcode_loader 会被调用,读取 "fhkan.oi"
- 整体 XOR 0x36 解密 fhkan.oi 内容
- 解密后是 shellcode(E8 00 00 00 00 序言)
- shellcode 会加载 Horse_in.dll(VirtualAlloc + PE 映射 + DllMain)
这些预测需要动态验证,确认每一步都真实发生,且数据吻合。
8.2 x32dbg 界面介绍(新手必看)
打开 x32dbg 后,界面分为几个主要区域:
| 区域 |
位置 |
功能 |
常用快捷键 |
| 反汇编窗口 |
左上最大区域 |
显示当前 EIP 处的汇编指令 |
F2=下断点,F9=运行,F8=单步步过,F7=单步步入 |
| 寄存器窗口 |
右上 |
显示 EAX/EBX/EIP 等寄存器值 |
右键可修改 |
| 内存窗口 |
左下 |
显示指定地址的内存数据(hex+ASCII) |
Ctrl+G 或右键→Go to→Expression 跳转 |
| 堆栈窗口 |
右下 |
显示当前 ESP 指向的栈数据 |
— |
| 命令栏 |
最底部一行 |
输入命令(如 bp 0x401000) |
— |
| 全局快捷键 |
功能 |
| F9 |
运行(到下一个断点) |
| F8 |
单步步过(遇到 call 不进入) |
| F7 |
单步步入(遇到 call 进入) |
| Ctrl+F9 |
执行到当前函数返回 |
| Ctrl+G |
跳转到地址(在当前焦点窗口) |
| F2 |
在光标处下/取消断点 |
8.3 准备工作
- 在 x32dbg 中打开
ev2c34.exe(File → Open)
- 程序会停在系统断点(ntdll 区域),这是正常的
- 将
fhkan.oi 复制到 ev2c34.exe 的同目录(因为加载器用 GetModuleFileNameA 取同目录路径)
8.4 ASLR 偏移计算
由于 ASLR,x32dbg 中的基址与 IDA 不同。查看基址的方法:
方法一(推荐):点击 x32dbg 左侧 "Symbols"(符号)标签页,在模块列表中找到 ev2c34.exe,Base 列就是实际基址。
方法二:在底部命令栏输入表达式:
由于 ASLR,x32dbg 中的基址与 IDA 不同。在 x32dbg 命令栏输入:
modbase(ev2c34.exe)
通过x32dbg获取到ev2c34.exe程序ASLR基址
本例基址 = 0x420000(注意:每次运行 ASLR 基址不同,以实际为准)。IDA 基址 = 0x400000。
偏移 = 0x420000 - 0x400000 = 0x20000
x32dbg 地址 = IDA 地址 + 0x20000。例如:
- xor36_shellcode_loader:IDA
0x418DCD → x32dbg 0x438BCD
- XOR 循环:IDA
0x418F43 → x32dbg 0x438F43
- call shellcode:IDA
0x418F4D → x32dbg 0x438F4D
8.5 设置断点
在命令栏输入(或在反汇编窗口 Ctrl+G 跳到地址后按 F2):
bp 0x438DCD ← xor36_shellcode_loader 入口
bp 0x438F43 ← XOR-0x36内容循环
bp 0x438F4D ← XOR-0x36 内容解密完成后(call esi 之前)
针对指定基址下断点
8.6 动态验证链(10 步)
按 F9 运行。程序会依次命中断点。每步的操作和验证如下:
步骤 1:xor36_shellcode_loader 命中
按 F9 运行,命中0x438BCD。说明 ev2c34.exe 执行到了 XOR 加载器,静态预测的第一步被动态证实。
首次运行停在 ntdll系统断点(加载阶段)
第二次运行暂停在 0x438BCD ,反汇编窗口显示 xor36_shellcode_loader 入口
步骤 2:XOR 文件名解密完成 → 验证 "fhkan.oi"
继续按 F9 到断点 0x438F43(文件名 XOR 解密后、路径 API 调用前)。
此时文件名常量已解密。读取验证:
- 查看寄存器窗口,找到 EBP 的值(如
0x02EFF57C)
获取到EBP地址值
- 计算
EBP - 0x14 = 文件名 buffer 地址:EBP-0x14 = 0x02EFF57C-0x14 = 0x02EFF568
- 在内存窗口
Ctrl+G 跳到该地址
- 看到 ASCII =
fhkan.oi → 动态证实
内存窗口显示 [EBP-0x14] = "fhkan.oi"(XOR 解密后的明文文件名)
步骤 3:路径获取 → 验证实际调用的是 GetModuleFileNameA
静态分析中 IDA 标为 GetTempPathW(因为函数指针动态解析,静态只能猜),但动态调试发现实际调用的是 GetModuleFileNameA(返回 ev2c34.exe 自身路径,取同目录)。这是静态分析的一个修正。
验证方法(在断点 0x438E34 暂停时):
- 看反汇编窗口,应有一条
call dword ptr ss:[ebp-0x2C] 指令,这是调用路径 API(通过函数指针间接调用)
- 验证是哪个 API:在内存窗口
Ctrl+G → 输入 EBP - 0x2C 的实际地址(用当前 EBP 值减 0x2C)→ 读到 4 字节是一个函数地址 → 去 Symbols 标签查 kernel32.dll 的基址范围,确认这个地址在 kernel32 内
- 或更简单:按
F8 单步步过这个 call → 内存窗口 Ctrl+G 到 EBP - 0x13C(路径 buffer)→ ASCII 显示 C:\Users\...\ev2c34.exe → 证明是 GetModuleFileNameA(取的是 exe 自身路径)
反汇编窗口 call dword ptr [ebp-0x2C](标注 GetModuleFileNameA)+ 内存窗口路径 buffer 显示 ev2c34.exe 路径
步骤 4:CreateFileA 成功 → 命中 XOR 循环断点
按 F9 继续运行。代码执行顺序是:
CreateFileA(打开fhkan.oi) → VirtualAlloc(分配RWX内存) → ReadFile(读入内存) → XOR循环(0x438F43)
步骤 5:XOR-0x36 解密前 → 读加密内容
在 XOR 循环断点 0x438F43 处暂停。查看 ESI 寄存器(=buffer 基址,如 0x03200000)。
内存窗口 Ctrl+G → 0x03200000:
E8 36 36 36 36 6E 63 BF D3 BF F4 5E 36 36 36 36
# 此处E8 36 36 36和前面010editor打开fhkan.oi的DE 36 36 36首字节不同的原因是动调已经开始xor了,而010editor是静态打开磁盘原始文件
这就是 fhkan.oi 的加密态。
内存窗口 0x03200000,显示解密前 E8 36 36 36 36...(加密态)
步骤6:XOR-0x36 解密后 → 读解密内容
删除断点 0x438F43(在命令栏输入 bc 0x438F43),保留 0x438F4D 断点。按 F9 运行。
XOR 循环执行完毕(184,795 字节全部异或 0x36),命中 0x438F4D(call esi)。
再次内存窗口 Ctrl+G → 0x03200000:
E8 00 00 00 00 58 55 89 E5 89 C2 68 00 00 00 00
解读:
E8 00 00 00 00 = CALL $+5(获取自身 EIP,shellcode 序言)
58 = POP EAX
55 = PUSH EBP
89 E5 = MOV EBP, ESP
加密前**E8 36 36 36 36 → 解密后 E8 00 00 00 00**,逐字节 XOR 0x36 完全吻合。
内存窗口 0x03200000,显示解密后 E8 00 00 00 00 58 55 89 E5...(解密态 = shellcode)
步骤 7:VirtualAlloc(0x10000000, 0x31000) → Horse_in.dll 映射
call esi 执行后进入 shellcode。shellcode 调用 VirtualAlloc 为 Horse_in.dll 分配内存。栈参数验证:lpAddress = 0x10000000(ImageBase)、dwSize = 0x31000(SizeOfImage),与 IDA 分析完全吻合。
步骤 ⑧:Horse_in.dll DllEntryPoint 命中
shellcode 完成 PE 映射 + 导入解析后调用 DllMain,EIP 进入 0x1000DA13(Horse_in.dll 代码区),反汇编显示标准 DllMain 入口(push ebp; cmp [ebp+0x0C],1 , DLL_PROCESS_ATTACH 判断),内存 0x10000000 处可见 MZ 头,证明 PE 已完整映射。
步骤7,8通过 MCP 自动化调试完成验证,因 shellcode 内含反调试检测,手动 x32dbg 在此阶段会触发进程退出。
步骤 9:DllMain 不解密 VM 派发表
在 DllMain 执行前后分别读 0x10022220(VM 派发表):
- DllMain 前:
5F BA BC 94 A2 9E BD 94...(PE 原始加密态)
- DllMain 后:
5F BA BC 94 A2 9E BD 94...(完全未变化)
派发表在 DllMain 阶段不解密,解密发生在引擎运行时(按需解密)。
步骤 10:AndStop VM 主体 → junk 指令确认
继续运行命中 AndStop(0x10008AD4)→ JMP 到 VM 主体(0x10003E91)。反汇编显示 junk 指令(bts/cwd/cmc 等),确认混淆保护已激活。
8.7 静态 vs 动态对比总结
| 静态预测 |
动态验证 |
状态 |
| xor36_shellcode_loader 被调用 |
断点命中 0xC98DCD |
完成 |
| 加密常量 v21[0]=842807599 |
反汇编 mov [ebp-0x14], 0x323C392F |
完成 |
| XOR key v1=0x14, v2=0xBD |
反汇编 mov dl, 0x14 / mov bl, 0xBD |
完成 |
| XOR 解密后 → "fhkan.oi" |
内存读出 fhkan.oi\0 |
完成 |
| 路径 API(标为 GetTempPathW) |
修正为 GetModuleFileNameA(取同目录) |
完成,修正 |
| XOR 0x36 解密 fhkan.oi |
前 DE 36 36 36 → 后 E8 00 00 00 |
完成 |
| VirtualAlloc(Horse_in 基址) |
参数 0x10000000, 0x31000 完全吻合 |
完成 |
| DllMain 不解密 VM 表 |
前后数据一致 |
完成 |
| AndStop = 混淆主体 |
junk 指令确认 |
完成 |
九、家族判定:银狐(SilverFox)
综合特征,高置信判定为银狐家族:
- 白加黑使用浩辰 GstarCAD 签名程序做加载器
- 伪装 Google Omaha / Microsoft Edge Update(标记字符串
Gact2.0Omaha、SOFTWARE\Microsoft\EdgeUpdate 注册表操作)
- 模块化 DLL RAT(Horse_in / Protect / upline / CreateUandE)
- 网盘克隆站钓鱼投递
- 自定义端口、无 DNS、注入合法进程的 C2
- XOR-0x36 无文件 shellcode + 随机名 二进制文件 +
comain_ 前缀目录命名
- 威胁情报核实此IP确认为银狐
威胁情报核实IP:202.79.169.198为银狐团伙
十、IoC 附录
10.1 样本 Hash(SHA256)
| 角色 |
路径 |
SHA256 |
| NSIS 投递器 |
bai_du_wangpan.exe |
7d66f86c8ff0566fa9432999a9bc9d20a1765847e09cae1feef769d59ea6fa8f |
| 加载器① |
comain_ev2c34\ev2c34.exe |
b839468fde6636ebad9aadb05d059b82b2d9abc189657dea6473db135d661d05 |
| 加载器② |
comain_ev2f79\ev2f79.exe |
a5f989d3b915581f382358b4e81951728b45ceae13aab48a2e2bd662d2610683 |
| 持久化程序 |
Community\baiduwangpan.exe |
16227b599cbf34d9fa11effd59753448d567f656e148a149d3a204ccf7337575 |
| RAT 核心 DLL |
Horse_in.dll(←fhkan.oi) |
479084f8095877c38700053c7fa45a084b7f3277a641d71dbd2f765ba73f322b |
| C2 通信 DLL |
upline.dll(←bnymir.ou) |
532422f8662d576f867e116e74fdef3ac76daaf3719e891c5ae7cc2bfaf0b1ff |
| 保护 DLL |
Protect.dll(←bteuns.pt) |
6c3ed72e578890b39f82354509122c369af06bbf011bb183ce6ea0ffbd8366d2 |
| 持久化 DLL |
CreateUandE.dll(←cmrsk.ce) |
4a3f81596395d1fb30517e622c7dfeea71ac4545140fbf6e8015c5cc30e6dda6 |
| C2 配置 |
ap.asin |
91734df67c37feeb340b45f4f6a7c8ff2feb78cbca509e1ee8d8139a58a0a7f4 |
| 加密 二进制文件 |
fhkan.oi |
4846e03250931965df77d4fb897fb3d100d451b72a7910a2840630195cfe1246 |
10.2 网络
- C2:
202.79.169.198 : 8853(TCP,无 DNS,注入 UserAccountBroker.exe 回连,加密,约 13s 信标)
- 钓鱼站:
pan-baidu.com
10.3 主机
- 目录:
%AppData%\Roaming\comain_ev2XXXX\
- 程序:
C:\Program Files (x86)\Community\baiduwangpan.exe + 桌面/开始菜单 baiduwangpan.lnk
- 注册表:
HKCU\SOFTWARE\MicrosoftUserAdmin\SOURCE = baiduwangpan
- Omaha 框架标记字符串:
Gact2.0Omaha(位于函数 0x40413a)
- 侦察命令:
cmd /C tasklist | findstr /I /C:"360tray.exe" /C:"HipsTray.exe"
10.4 检测特征
- 二进制文件 头 magic:
DE 36 36 36 36(XOR-0x36 后 = E8 00 00 00 00,即 CALL $+5)
- 字符串:
Gact2.0Omaha、Horse_in.dll、Protect.dll、upline.dll、CreateUandE.dll、导出 AndStop
- 加密:载荷整体 XOR 0x36;文件名常量 XOR(v1=0x14, v2=0xBD, i=0x00BD14D1)
- 派发表 XOR key:
0x576AC834 / 0x576AC835 / 0x4FF4E7DE
- 签名链:CN=Gstarsoft Co., Ltd.(HashMismatch)
YARA 检测规则(示例)
rule SilverFox_BaiduPan_Loader {
meta:
description = "SilverFox loader - BaiduNetdisk lure, Omaha impersonation"
family = "SilverFox"
strings:
$s1 = "Gact2.0Omaha" ascii
$s2 = "Horse_in.dll" ascii nocase
$s3 = "upline.dll" ascii nocase
$s4 = "CreateUandE.dll" ascii nocase
$s5 = "Protect.dll" ascii nocase
$edge = "SOFTWARE\\Microsoft\\EdgeUpdate" wide ascii
condition:
uint16(0) == 0x5A4D and 3 of ($s*)
}
rule SilverFox_BaiduPan_XOR36_Blob {
meta:
description = "SilverFox XOR-0x36 encrypted payload blob (dropped file)"
family = "SilverFox"
strings:
$magic = { DE 36 36 36 36 }
condition:
$magic at 0 and filesize < 2MB
}
十一、清除方案
以下命令彻底清除本样本驻留。以管理员权限运行。
# 0) 结束相关进程
Get-Process ev2c34,ev2f79,bai_du_wangpan -ErrorAction SilentlyContinue | Stop-Process -Force
# 1) 删除 RAT 释放目录
$roaming = $env:APPDATA
Get-ChildItem -LiteralPath $roaming -Directory -Filter 'comain_ev2*' -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force
Remove-Item "$roaming\ap.asin","$roaming\bnymir.ou" -Force -ErrorAction SilentlyContinue
Remove-Item "$env:ProgramData\ntrin.er" -Force -ErrorAction SilentlyContinue
# 3) 删除程序与快捷方式
Remove-Item 'C:\Program Files (x86)\Community' -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item "$roaming\Microsoft\Windows\Start Menu\Programs\baiduwangpan.lnk" -Force -ErrorAction SilentlyContinue
Remove-Item "$env:USERPROFILE\Desktop\baiduwangpan.lnk" -Force -ErrorAction SilentlyContinue
Remove-Item "$env:USERPROFILE\Desktop\bai_du_wangpan.exe" -Force -ErrorAction SilentlyContinue
# 4) 清除注册表持久化
Remove-Item 'HKCU:\SOFTWARE\MicrosoftUserAdmin' -Recurse -Force -ErrorAction SilentlyContinue
Remove-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\EdgeUpdate' -Name 'WindowsUpdateAttempts' -ErrorAction SilentlyContinue
# 5) 复核:确认无隐藏账户(对应 CreateUandE.dll)
net user
net localgroup Administrators
# 6) 离线全盘扫描兜底
Windows defender查杀全盘
清除命令执行记录