近期有威胁情报检测到伪装成知名系统清理工具 CCleaner 的恶意软件。攻击者搭建了仿冒的官方网站(ccleanerwind[.]top ),诱导受害者下载伪造的安装程序 CCleaner.exe 。该程序安装运行后,会进行 DLL 侧加载、无文件内存加载、用户态 Rootkit 等操作,并最终以 Chrome 浏览器的恶意扩展落地,目的在于监控和窃取受害者的敏感信息,包括加密货币钱包地址。
(下文记录了多次调试,可能存在PID、内存地址前后不一致的地方,见谅)
CCleaner.exe 安装运行后,向 %APPDATA%\Microsoft\Vault 路径写入三个文件
接着 CCleaner.exe 会创建进程,运行 cscript.exe。 cscript.exe 进程被拉起后,加载 version.dll ,立即扫描同目录下的 .dat 文件,找到 AppxState.dat 后读取。

cscript.exe 读取 AppxState.dat 后,会将注册表 Environment\UserInitMprLogonScript 的键值设置为 cscript.exe 所在路径

当用户登录 Windows 时,进程 winlogon.exe 会启动 userinit.exe 初始化用户环境。userinit.exe 会自动检测 HKCU\Environment 下是否存在 UserInitMprLogonScript。若存在该项,userinit.exe 会以后台方式静默启动该项中指定的程序或脚本(如 .bat、.vbs、.ps1 或恶意 exe/cscript.exe 等)。与Run 键设置相比,这种方式更为隐蔽地实现了恶意程序的开机自启动
IDA 查看 version.dll,看到开始部分有函数 DisableThreadLibraryCalls,这个是 kernel32.dll 的导出函数; x64dbg 调试cscript.exe,程序加载 version.dll 后,先在这个函数下个断点


成功断了下来,接着往下单步运行,可以看到函数 GetModuleHandleW()
获取 ntdll.dll 句柄后,可以看到接下来应该是解密某个函数名称,再通过 GetProcAddress 获取这个函数地址。
再往下运行,验证了猜想。

先是获取了 ntdll!TpAllocWork 和 ntdll!TpPostWork 的函数地址并保存在 rsi 和 rdi 这两个寄存器当中,然后调用了这两个函数


ntdll!TpAllocWork 和 ntdll!TpPostWork 函数的调用是很明显的线程池注入特征。使用 CreateThread 太容易引发 安全软件的告警,攻击者选择利用线程池机制,更隐蔽一点。
TpPostWork 执行后,操作系统内置线程池中一个已存在的休眠 Worker 线程被唤醒,读取回调函数地址(即 sub_1800035C0,动态调试界面中 RDX 保存的地址 0x00007FFF6C3035C0)并直接跳转执行。
这个线程的入口是合法的线程池调度器,引发告警的可能性要小一点。

在 0x00007FFF6C3035C0下断点,成功断了下来
调用 Sleep(0x64)(100毫秒)
调用 GetCurrentProcessId() 获取宿主(cscript.exe)的 PID
调用 EnumWindows(EnumFunc, CurrentProcessId)
EnumFunc 遍历所有顶级窗口,找到属于当前 PID 的窗口后,调用 ShowWindow(hwnd, SW_HIDE),将 cscript.exe 的黑框控制台窗口隐藏(这个可以在桌面观察到)

接下来获取文件所在路径,找到后缀为.dat 的文件,调用 readfile() 函数读取文件

然后调用 Windows 的 BCrypt 密码学库,对文件进行哈希校验和解密

最后通过修改内存属性(VirtualProtect)并冲刷指令缓存(FlushInstructionCache),直接在内存中执行dll

sub_1800010F 函数实现在内存中加载恶意 PE 文件

调试时,可以看到内存地址 0x24C0000 有解密后的 PE 文件

将内存中加载的 dump 下来,是一个dll 文件,IDA 看一下,导出函数名为SynTPEnhService_1()。
SynTPEnhService 是 Synaptics 触控板服务的 API 名称,攻击者将载荷导出为同名函数,可能会骗过一些安全软件。

暂且命名为 SynTPHelper.dll,然后继续动态调试;搜索内存加载 dll 关键函数结尾的部分,看到 call rax ,version.dll 的基址+0x149A,像是比较明显的 Payload 执行入口。


然后步进,在函数LoadLibraryW 设置硬件断点,在加载 runtimebroker.dll 断下来
payload 运行后,可以观察到,实现了持久化机制,创建了文件 runtimebroker.dll 和runtimebroker.cfg

runtimebroker.cfg 其中的内容为
解密后的核心载荷一经 call rax 启动,在 14:25:07 这一秒钟内,突然暴增了十几个相同堆地址入口的线程,负责剪贴板文本监控、网络监听等功能

接着运行,来到了runtimebroker.dll 的入口处

下硬件断点

以下是 hook 的 API

断下来之后,查看NtQueryDirectoryFile 处的指令,最开头的 5 个字节不再是原本的 mov r10, rcx / mov eax, 32h,而是被强制覆写成了一条跳转指令 jmp 7FFF36A10238,这是比较明显的钩子特征。

使用 PCHunter 可以看到这些 API 确实被 Hook 了

runtimebroker.dll 被加载后会读取runtimebroker.cfg 文件中的字符,

runtimebroker.cfg 第一行 7788 正是 C2 主通道端口。该钩子使 netstat -ano、Wireshark 、Process Hacker 等工具无法显示该端口的连接记录