面向即时通讯工具的输入伪装与检测绕过:银狐类生态中Hook组件的技术迭代

admin 2026-09-10 04:38:14 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 腾讯安全威胁情报中心披露银狐类恶意软件针对即时通讯工具的Hook组件技术迭代。样本通过HookGetCurrentInputMessageSource将合成输入伪装为硬件输入,绕过自动化输入校验,并叠加RawInput屏蔽与TCP表欺骗构建三层防御体系。溯源发现2024-03及2024-05早期版本,呈现功能精简与防护上移的演进趋势,以中等置信度归因银狐组织。 综合评分: 85 文章分类: 恶意软件,威胁情报,逆向分析,安全工具


面向即时通讯工具的输入伪装与检测绕过:银狐类生态中 Hook 组件的技术迭代

腾讯安全威胁情报 腾讯安全威胁情报

腾讯安全威胁情报中心

2026年9月9日 19:33 上海

在小说阅读器读本章

去阅读

在公众号小说中沉浸阅读

开篇

SEO 投毒、高强度对抗、拉群扩散,这些都是银狐组织的典型传播手法。现今成熟的即时通讯工具会对系统环境和用户输入的真实性进行校验,使简单的模拟点击和自动发消息难以直接奏效。银狐样本如何绕过这些校验,将自动化操作伪装成真实用户行为?

最近我们从沙箱集群捕获了一个高度可疑的无 PE 头内存 dump ,沿代码特征逐层扩线,最终定位了样本来源于银狐家族,并且深入还原了银狐类生态中面向即时通讯工具的 Hook 组件技术迭代。我们根据关联特征捕获到了多个早期关联样本,这些样本与 2026样本共享同一个核心手法:Hook Windows 输入来源查询 API,把软件合成输入改归为硬件输入类别;基于功能丰富度和构建时间可以推测出一条演进关系。围绕这个核心,设计者在不同版本间动态调整验证封堵和自隐藏策略,并在 2024-05 版将防护对抗上移到独立的外层加载器。


核心发现

  • • 我们定位了样本注入即时通讯工具绕过检测的核心机制:通过 Hook GetCurrentInputMessageSource 把 IMO_INJECTED 合成输入改写为 IMO_HARDWARE 硬件输入类别,绕过即时通讯工具对自动化输入来源的校验。2026样本与 Hunt 到的早期样本均共享此特征
  • • 我们通过特征溯源识别到多个早期版本:版本之间的迭代呈现出极强的对抗适应性
  • • 我们通过IOC溯源定位样本来自银狐组织,以中等置信度归为银狐类一致活动,明确排除具有国家背景的APT行为体

调查起点:一个无 PE 头的内存 dump

2026年7月,我们从威胁情报沙箱集群捕获了一个高度可疑的样本,运行过程中释放一个无PE头的内存dump。我们的调查从这里开始。文件 shellcode.bin 大小 114,688 字节(0x1C000),SHA-256 e5a9de2b6dad1cd9005e816965c047c6441e194e52759d24c50b9512fbdfd491,文件偏移 0 直接是正常 x86 函数序言而非 PE DOS 头。这是一个加载后 x86 DLL 从 RVA 0x1000 起的连续内存映像,缺少首个 0x1000 PE 头页,不能作为完整 PE 或独立 shellcode 运行。

通过代码中的绝对地址引用可反推 ImageBase = 0x16FE0000,文件偏移 0 对应 VA 0x16FE1000。由于 PE 头缺失,节边界由绝对地址引用、链接器 section-contribution 元数据和内容类型共同恢复:

dump%20中可见 .detour.dogec.doged 节名和%20MSVC%20CRT%20相关字符串,说明模块静态链接了%20Microsoft%20Detours。.dogec / .doged 是样本对%20Detours%20上游 .detourc / .detourd 数据节的改名,非微软默认节名。它们说明%20Detours%20代码谱系,但单独不能判恶,合法使用%20Detours%20的软件也可能存在这些节。

5%20个%20API%20名、注册表路径、value%20名和%20mutex%20并非明文保存,而是由栈上常量经%20SSE/XOR%20临时解密。普通 strings 看不到它们。dump%20中偶然出现的明文 Policy 来自%20CRT%20字符串 AppPolicyGetProcessTerminationMethod,不能当作恶意%20value-name%20的明文证据。

文件偏移 0x15D98 存在宿主进程路径明文。该字符串更可能是%20CRT/运行时进程路径状态,只能证明%20dump%20与%2032%20位即时通讯工具进程环境有关,不能单独证明固定投递目标或初始入口。

Hook%20组件的技术演进与样本关系 2026样本的分析:三层防御规避体系

下文将捕获的样本称为%202026样本。它在所有已知样本中功能最丰富,在被注入进程内构建了三层防御规避体系:输入来源伪装、Raw%20Input%20交叉验证封堵、TCP%20连接表自省欺骗。这个版本没有编译时间戳,无法确定其具体出现的时间,但活跃时间明显定位在%202026%20年的时间窗口。三层规避机制叠加的目标是在被注入进程内制造一个自洽的可信操作环境。

核心层:GetCurrentInputMessageSource%20输入来源伪装

Hook%20位于%20VA 0x16FE1740,精确行为如下:

BOOL hook(INPUT_MESSAGE_SOURCE%20*source) {
 %20 %20BOOL%20result%20=%20real_GetCurrentInputMessageSource(source);
 %20 %20if (source->originId%20== 2) %20 %20 %20 //%20IMO_INJECTED
 %20 %20 %20 %20source->originId%20= 1; %20 %20 %20 %20//%20IMO_HARDWARE
 %20 %20return result;
}

Windows%20中 INPUT_MESSAGE_SOURCE.originId 标识输入来源:IMO_INJECTED%20(2) 表示普通非%20UIAccess%20应用通过 SendInput 注入的合成输入,IMO_HARDWARE%20(1) 表示硬件设备输入或由%20UIAccess%20应用注入。样本把普通软件注入输入改归为硬件/UIAccess%20来源类别。

上述行为可直接从样本字节复核。值%201%20代表硬件或%20UIAccess%20来源类别,不严格等于物理硬件。样本不生成输入、不记录键盘,也不改变底层设备事件。让目标进程把 SendInput 注入的合成输入判定为硬件输入,可能直接绕过即时通讯工具对自动化输入来源的校验,但样本中没有宿主检测函数可证明具体绕过对象。

交叉验证封堵层:GetRawInputData%20屏蔽

仅有输入来源伪装不足以应对具备交叉验证能力的宿主。Hook%20位于%20VA 0x16FE1990,精确行为如下:

UINT hook_GetRawInputData(...,%20PUINT%20pcbSize,%20...) {
 %20 %20if (pcbSize%20!= NULL)
 %20 %20 %20 %20*pcbSize%20= 0;
 %20 %20return 0;
}

Hook%20不调用真实%20API,直接将输出参数 pcbSize 置零并返回%200。这一行为可直接从样本字节复核。GetRawInputData 是应用获取%20Raw%20Input%20原始数据的唯一用户态接口,无论调用方查询所需缓冲区长度还是读取实际 RAWINPUT 数据,都会得到零长度,即没有原始输入数据可读。

这一机制与输入来源伪装配合:宿主检测到 GetCurrentInputMessageSource 返回硬件输入类别,但 GetRawInputData 读不到对应的原始硬件事件数据,交叉验证通道即被封堵,输入伪装的假象在进程内自洽。该功能是屏蔽%20Raw%20Input%20交叉检查,不是键盘记录。

网络环境自省欺骗层:三个%20TCP%20表%20Hook

第三层针对宿主进程对自身网络环境的自省检查。三个%20Hook%20分别位于%20VA 0x16FE1A70GetTcpTable)、0x16FE19B0GetTcpTable2)和 0x16FE1760GetExtendedTcpTable),共享相同逻辑:

status%20=%20real_api(...);
if (status%20==%20NO_ERROR)%20{
 %20 %20for each%20IPv4%20row%20{
 %20 %20 %20 %20if (row.dwState%20!=%20MIB_TCP_STATE_LISTEN)
 %20 %20 %20 %20 %20 %20row.dwRemoteAddr%20=%20generated_private_address;
 %20 %20}
}
return status;

伪造地址字节为 0A,%20rand()%256,%20rand()%256,%20(rand()%252)+2,显示为 10.x.x.[2..253],每次以 time(NULL) / srand 初始化随机种子(非密码学随机)。三个%20API%20的结构差异如下:

上述行为可直接从样本字节复核。Hook%20只修改被注入进程的用户态返回缓冲区,端口、PID、TCP%20状态、内核连接、真实报文和外部%20EDR%20视图不变。这三个%20API%20不是网络客户端,不能证明%20DLL%20创建了%20socket、发送数据或连接%20C2。宿主进程检查自身%20TCP%20连接表时,看到的远端全是 10.x.x.x 私有地址。

2026样本功能组合的整体效果

2026样本同时具备输入来源类别改写、Raw%20Input%20查询屏蔽、进程内%20TCP%20表远端%20IPv4%20欺骗、当前小时%20Policy%20门禁、mutex%20单实例和%20Detours%20Hook%20安装/卸载。三层叠加后,被注入进程的视图是:输入来自硬件、没有%20Raw%20Input%20矛盾、网络连接远端是内网地址。上述功能均可由样本字节直接复核。组合用途高度符合绕过即时通讯工具对自动化输入、远控输入或运行环境风险的交叉检查,但样本中没有宿主检测函数或操作者配置可证明具体绕过对象。外部%20EDR、内核遥测或另一个未被注入的进程仍可看到真实情况。

2026样本三层防御规避体系

2024-03%20版:精简与自隐藏

依据%202026样本中的%20Detours%20节名特征、注册表门禁代码和%20Hook%20语义组合,我们提取特征进行样本狩猎(Hunt),获得两枚%202024-03-13%20编译的%20x64%20DLL。这是目前已知最早的编译版本:

两文件加载后的有效映像和行为相同,是同一构建的四字节尾部变体。

功能变化:输入伪装不变,引入自隐藏,不具备封堵层

2024-03%20版与%202026样本共享核心 GetCurrentInputMessageSource Hook(VA 0x180001000),originId%202%20→%201 的改写逻辑逐字节一致。2024-03%20版额外引入 Module32NextW Hook(VA 0x180001030):

//%20伪代码
BOOL hook_Module32NextW(HANDLE%20snapshot,%20LPMODULEENTRY32W%20me) {
 %20 %20BOOL%20result%20=%20real_Module32NextW(snapshot,%20me);
 %20 %20if (result%20&&%20wcscmp(me->szExePath,%20own_dll_path)%20== 0)%20{
 %20 %20 %20 %20return real_Module32NextW(snapshot,%20me); //%20跳过自身,再取下一项
 %20 %20}
 %20 %20return result;
}

Module32NextW 是%20Toolhelp%20进程/模块快照枚举的核心%20API。当枚举结果的模块路径等于自身%20DLL%20路径时,Hook%20再调用一次真实%20API%20跳过自身,使该%20DLL%20不出现在进程的模块枚举结果中。

上述行为可直接从%20DLL%20字节复核。Hook%20只影响调用该%20API%20的当前进程的%20Toolhelp%20枚举结果,不会从内核、EDR、内存扫描或其他模块枚举机制中全局消失。即时通讯工具或其安全模块用%20Toolhelp%20遍历自身加载的%20DLL%20列表时,该%20DLL%20会从列表中消失。

2026样本具备%20Raw%20Input%20屏蔽和三个%20TCP%20表%20Hook,2024-03%20版不具备这两项功能。

Oreans-family%20VM%20保护入口跳板

DLL%20入口附近使用%20Oreans-family%20控制流虚拟机保护启动跳板。PE%20entry%20位于 0x180004008,VM%20链为 0x180004040%20→%200x180036A2B%20→%200x18004B5C1DLL_PROCESS_ATTACH 路径执行%2036,006%20条%20VM%20指令后到达%20CRT%20entry 0x180003ED4。还原后入口语义仅为:

BOOL RecoveredDllEntry(HINSTANCE%20module,%20DWORD%20reason,%20LPVOID%20reserved) {
 %20 %20if (reason%20==%20DLL_PROCESS_ATTACH)
 %20 %20 %20 %20__security_init_cookie();
 %20 %20return _DllMainCRTStartup(module,%20reason,%20reserved);
}

上述还原结果可由离线仿真轨迹直接复核。.m<g 是%20Oreans-family%20控制流%20VM,主要保护%20DLL%20启动跳板,不是隐藏第二个网络载荷的自解密容器。还原后的业务逻辑中没有第二个网络模块,也没有支持 getaddrinfo 解出%20C2%20的调用路径。分析方式使用受控离线%20CPU%20仿真器解释入口指令语义,未在宿主%20Windows%20原生加载/运行或联网。

设计意图推断

2024-03%20版面向不做%20Raw%20Input/TCP%20自省检查的目标环境,只需绕过输入来源校验和模块枚举检测即可。任务分工有所调整,部分验证封堵交由上游组件完成。

2024-05%20版:极简核心%20+%20外层强化

2024-05-07%20编译的双架构%20DLL%20及其外层%20loader%20是目前已知最晚的构建版本。DLL%20本体缩减至只剩输入来源伪装这一个核心%20Hook,防护对抗和注入能力全部上移到独立的外层加载器(loader)。

DLL%20本体:仅具备输入来源伪装

内嵌%20x86%20DLL(SHA-256 97965e9127928d0a0d387ed211f356d78cc0fca2e307cc4dfe08674f147035ad,链接时间%202024-05-07%2012:12:59%20UTC)和%20x64%20DLL(SHA-256 8d6af90b48574e8f6d3c46dc60893e49d9bd1ae53e73eb948839b3b5bc16fac5,链接时间%202024-05-07%2012:10:22%20UTC)相隔%20157%20秒构建,使用%20Microsoft%20linker%2014.29,无导出、无%20TLS%20callback、无资源载荷和%20overlay。

两枚%20DLL%20的唯一自定义恶意功能是当前小时门禁、单实例%20mutex%20和 GetCurrentInputMessageSource Hook。attach%20路径如下:

BOOL&nbsp;payload_attach(void)&nbsp;{
&nbsp;%20&nbsp;%20if&nbsp;(DetourIsHelperProcess())
&nbsp;%20&nbsp;%20&nbsp;%20&nbsp;%20return&nbsp;TRUE;
&nbsp;%20&nbsp;%20if&nbsp;(!policy_gate())
&nbsp;%20&nbsp;%20&nbsp;%20&nbsp;%20return&nbsp;FALSE;

&nbsp;%20&nbsp;%20mutex%20=%20CreateMutexA(NULL,%20FALSE,&nbsp;"AAAAAAAAAAAAAAAAB");
&nbsp;%20&nbsp;%20if&nbsp;(!mutex%20||%20GetLastError()%20==%20ERROR_ALREADY_EXISTS)
&nbsp;%20&nbsp;%20&nbsp;%20&nbsp;%20return&nbsp;FALSE;

&nbsp;%20&nbsp;%20DetourRestoreAfterWith();
&nbsp;%20&nbsp;%20real_api%20=%20GetProcAddress(LoadLibraryA("user32.dll"),
&nbsp;%20&nbsp;%20&nbsp;%20&nbsp;%20&nbsp;%20&nbsp;%20&nbsp;%20&nbsp;%20&nbsp;%20&nbsp;%20&nbsp;%20&nbsp;%20&nbsp;%20&nbsp;%20&nbsp;%20"GetCurrentInputMessageSource");
&nbsp;%20&nbsp;%20DetourTransactionBegin();
&nbsp;%20&nbsp;%20DetourUpdateThread(GetCurrentThread());
&nbsp;%20&nbsp;%20DetourAttach(&real_api,%20hook_wrapper);
&nbsp;%20&nbsp;%20return&nbsp;DetourTransactionCommit()%20==%20NO_ERROR;
}

上述行为可直接从%20DLL%20字节复核。2026样本具备的%20Raw%20Input/TCP%20Hook%20不存在于这两枚%20DLL,2024-03%20版的 Module32NextW Hook%20也不存在于%202026样本。两枚%20DLL%20实现相同的源码级行为,仅适配不同进程架构。

外层%20loader%20接管防护对抗

外层样本%20SHA-256 4f3b57fc0d48f9f36ead99d010830f5d84290dc6d4d7e3511101367c0ca67ea8,PE32/x86%20GUI,1,589,760%20字节,链接时间%202024-05-07%2012:27:29%20UTC。保护层将原始节内容的%20raw%20size%20清零,真实 .text / .rdata / .data / .1Q[ 以四条%20raw%20LZMA1%20流(lc=3,%20lp=0,%20pb=2,%20dict=16%20MiB)保存在高熵 .sc= 节中。

ApplicationData%20ChaCha20%20门禁

loader%20读取 HKLM\SOFTWARE\IMUpdate\ApplicationData(64%20位注册表视图,最多 0x100 字节),用标准%2020%20轮%20ChaCha20%20解密:

key%20&nbsp;%20&nbsp;%20=%207b2afa6c5f6a06061453bdb5f735e129c131b926ef1bded8e403d6635242745c
nonce%20&nbsp;%20=%20313939310d0ad6cc954e1a20
counter%20=%200
rounds%20&nbsp;=%2020

解密后逐字节要求:值至少为%202,且不能被 2..sqrt(byte) 中任何整数整除。任一字节非素数即退出。

Defender%20排除

loader%20的%20Defender%20worker%20每%203%20秒循环,每第%2010%20次检查 msmpeng.exe(约%2030%20秒一次)。发现后用 ShellExecuteA(...,%20"powershell",%20...,%20SW_HIDE) 隐藏启动:

-c&nbsp;if&nbsp;(Get-Process&nbsp;-Name&nbsp;HAhahaha)%20{}&nbsp;else&nbsp;{"Add-MpPreference%20-ExclusionPath&nbsp;$env:localappdata,'C:\','C:\Windows','%s',([environment]::CurrentDirectory)%20-ExclusionExtension%20'.png' -Force"}

%s 替换为 loader 自身路径。意图是排除 LocalAppData、整个 C:\C:\Windows、自身文件、当前目录和 .png 扩展名。

代码构造并隐藏启动 PowerShell 的行为可直接从 loader 字节复核,意图是排除 LocalAppData、整个 C:\C:\Windows、自身文件、当前目录和 .png 扩展名。但字符串放在双引号中可能只产生字符串表达式,即使 cmdlet 被执行,Tamper Protection、策略和权限也可阻止生效。

双架构注入

loader 启用 SeDebugPrivilege 后每 3 秒轮询目标即时通讯工具进程,根据目标位数选择 x86 或 x64 反射注入:

RtlAdjustPrivilege(20, TRUE, FALSE, &old_state);&nbsp;// SeDebugPrivilege

for&nbsp;(;;) {
&nbsp; &nbsp; pid = find_process_by_name("IM.exe");
&nbsp; &nbsp; if&nbsp;(pid && payload_mutex_B_not_alive()) {
&nbsp; &nbsp; &nbsp; &nbsp; write_current_hour_policy();
&nbsp; &nbsp; &nbsp; &nbsp; if&nbsp;(target_is_x86(pid))
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; inject_x86(pid);
&nbsp; &nbsp; &nbsp; &nbsp; else
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; inject_x64_from_wow64(pid);
&nbsp; &nbsp; }
&nbsp; &nbsp; Sleep(3000);
}

x86 目标使用 VirtualAllocEx → WriteProcessMemory → VirtualProtectEx → CreateRemoteThread。x64 目标由 32 位 WoW64 loader 经 Heaven’s Gate 解析 64 位 ntdll,调用 NtAllocateVirtualMemoryNtWriteVirtualMemoryNtProtectVirtualMemoryRtlCreateUserThread 完成注入。反射 blob 所有字节静态 +1,使用前 -1 恢复;内嵌 DLL 的 DOS magic 从 MZ 改为 0D 0A 以躲避简单 PE 扫描。外层 mutex 为 AAAAAAAAAAAAAAAAC,注入 DLL mutex 为 AAAAAAAAAAAAAAAAB

上述注入路径可直接从 loader 代码复核。loader 主动轮询某即时通讯工具的可执行文件,这个目标与 2026样本中的另一个即时通讯工具路径来自不同构建。loader 具备 x86 与 x64 两条完整远程注入路径,调用 Native API,不等于直接 syscall。

设计意图推断

2024-05 版 DLL 极简化,环境准备和防护对抗上移到 loader 层。目标进程不做 Raw Input 交叉验证和 TCP 自省检查,只需绕过输入来源校验即可。loader 接管注入和防护对抗后,DLL 只需保留最小核心功能。

小结

本次分析从一个无 PE 头的内存 dump 出发,通过代码特征逐层扩线,定位了银狐类生态中面向即时通讯工具的 Hook 组件谱系。我们获得了三个样本:2024-03-13 编译的 x64 DLL、2024-05-07 编译的双架构 DLL 及外层 loader、以及 2026 年从失陷机器取得的 dump(2026样本)。三个样本共享同一个核心手法:Hook GetCurrentInputMessageSource 把合成输入改写为硬件输入类别,originId 2→1 逻辑逐字节一致。

围绕这个核心功能,各版本的功能组合存在明显差异。2026样本构建了三层防御规避体系(输入来源伪装、Raw Input 屏蔽、TCP 表欺骗),是功能最丰富的全功能组件。2024-03 版引入 Module32NextW 模块枚举自隐藏,不具备 Raw Input/TCP 封堵。2024-05 版将 DLL 缩减至仅输入伪装,防护对抗和注入能力上移到 loader。三个样本之间有同源证据,但除 loader→内嵌 DLL 外无直接父子链,功能差异可解读为迭代升级或面向不同目标的定制裁剪。

这套 Hook 组件属于环境准备层,服务于上游自动化操作或远控操作。本地样本中未发现键盘记录、账号凭据窃取、屏幕截图或远控协议,上层意图需要其他载荷或主机遥测证明。整体与银狐类黑灰产使用云对象存储分发多阶段载荷、再接入 ValleyRAT/Gh0st 衍生远控的技术模式相符。


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:腾讯安全威胁情报中心 腾讯安全威胁情报 腾讯安全威胁情报《面向即时通讯工具的输入伪装与检测绕过:银狐类生态中 Hook 组件的技术迭代》

评论:0   参与:  0