钓鱼网站:

下载的网址为 https://pub-5b1d8f3f01e7407cbbb26b935d2094f4.r2.dev/QuarkPC_V1.9.0.151_pc_pf30002.msi

通过钓鱼网站下载之后是一个 QuarkPC_V1.9.0.151_pc_pf30002.msi 安装包

这个.msi 文件是没有数字签名的
解包之后:

有三个文件
其中 QuarkPC_V1.9.0.151_pc_pf30002.exe 文件就是一个正常的夸克软件安装包

ziplib.dll
这个 dll 是用于解压文件的,这个文件应该就是 all.zip 文件
all.zip 文件有密码无法直接打开,因为有密码所以直接将 all.zip 丢进沙箱,并没有报毒

找不到压缩包的解压密码,直接安装.msi 文件,之后能在在 c 盘的目录用户下找到这个文件夹


这个文件夹中的文件和解包 msi 文件得到的一样,确认为这个文件夹,
这几个文件全部有数字签名,其中 vcruntime140_1.dll、VCRUNTIME140.dll、MSVCP140.dll 使用的是微软的数字签名

其中的 down.exe 和 libcef.dll 使用的是这个数字签名,查询得到,这个是一个游戏公司的数字签名,其中一个是过期的


看可执行文件的操作像一个白加黑操作,只是黑 dll 加了一个数字签名
ziplib.dll 分析
一个假的微软数字签名

.msi 文件中存在三个文件,一个是属于正常夸克安装包,属于在运行.msi 文件之后最后执行的,剩下一个有密码的 all.zip 文件和一个 ziplib.dll 猜测压缩包密码在这个里面,将这个 dll 丢进 ida

导出函数有两个,其中的 DllEntryPoint 没什么有用的东西,所以真正有用的东西在 ohwuu 这个函数中,
ohwuu

CoCreateGuid 生成随机标识符,然后格式化字符串用来命名之后创建的解压文件夹

通过后面的分析可以得知 all.zip 的压缩包密码就是 holle202411,而前面的路径就是.msi 运行之后 all.zip 存储的位置,之后会遍历当前进程,判断当前进程执行的进程名称是否为 msiexec.exe,是则进行后续创建文件解压的操作,不是则会直接退出
msiexec.exe 是 Windows Installer 的组件,所以这一步就是保证是以运行.msi 文件来进行的解压

第 292 行这里的函数就是进行解压文件的操作,进入分析
if ( sub_180002260(v52, v49, &v55, &pguid) )
sub_180002260

155 行到 179 行在进行 all.zip 文件路径的循环判断 C:\Users\Public\Documents\all.zip,然后运用上面的格式化名称,在 C:\Users\username\文件名称`

并判断是否存在这个名称的文件夹

231 行到 714 行的 while 循环进行将 zip 中的文件一个一个的读取进入缓冲区然后使用 CreateFileW 函数和 write 函数将其写入到相应路径 File 的文件下,


这里会对刚才创建和写入的文件最后三位进行判断,是否为 exe 结尾,之后会进行数据处理,猜测为后面自启动程序做准备

判断创建创建和写入的文件数量是否达到 7 个(也就是判断是否将 zip 中的文件全部读取完成
文件解压结束之后会判断当前系统的 CPU 数量(判断沙箱?,如果 CPU 数量大于等于 2 就会进行自启动 down.exe 文件,如果 CPU 小于二会用 MessageBoxW 回显“Error upc!”,自启动之后会将 documents 路径下的 all.zip 文件删除

自启动 down.exe 函数:

先使用 WideCharToMultiByte 函数将路径的格式转换为 UTF-8,然后
使用 WinExec 进行启动
WinExec("C:\Users\username\filename\down.exe", SW_SHOWMINIMIZED);
WinExec 是 Windows API 中的一个函数,用于启动一个新的进程
UINT WinExec(
LPCSTR lpCmdLine,
UINT uCmdShow
);
参数说明
- lpCmdLine: 指向一个以 null 结尾的字符串,表示要执行的命令行。可以是可执行文件的路径,或者是一个命令行指令。
- uCmdShow: 指定窗口的显示方式。常用的值包括:
SW_HIDE: 隐藏窗口。SW_SHOW: 显示窗口。SW_MINIMIZE: 最小化窗口。SW_MAXIMIZE: 最大化窗口。
返回值
- 返回值是一个
UINT类型,表示新进程的返回状态。具体的返回值可以表示各种状态:- 如果成功,返回值是新进程的可执行文件的返回值。
- 如果失败,返回值为 0。可以通过调用
GetLastError获取更多错误信息。
libcef.dll 分析
白加黑 down.exe 文件会调用 libcef.dll

主要操作函数是 DllEntryPoint 下的 sub_7FFFD4835204 函数

DllMain 函数

sub_7FFE13292F90 函数中加载了 ntdll.dll 中的 RtlLeaveCriticalSection、LdrFastFailInLoaderCallout、LdrGetDllFullName 的地址
以及解决线程死锁的情况

运用 13 行这个函数使用 GetCommandLineW 检索当前进程的命令行字符串,也就是 down.exe 的路径,然后判断当前运行的 down.exe 程序是否含有参数/aut


如果带有参数则会进入 15 行的函数
带有/aut 参数
通过 xor 之后得到注册表路径 Software\\\\DICKEXEPATH,之后 regedit 函数中进行添加注册表


完成注册表添加之后 sleep(0x7D0u),然后调用 17 行的函数进行读取 aut.png 中 shellcode 操作和执行 shellcode 的操作

进入 get_aut 函数

14 行的函数进行读取 aut.png 和将其中的 shellcode 提取的操作;具体实现和后面读取 vew.png 的一样

run_shellcode 函数的 34 行复制 shellcode 的运行

未带/aut 参数
sub_7FFE13292E80 函数通过 GetModuleFileNameW 获取当前的路径之后,在路径后面加上/aut,创建一个新进程

CreateProcessW(
L"C:\\Users\\30839\\Desktop\\FF073A6A-775A-4447-B229-00000A037368\\down.exe“,
L"C:\\Users\\30839\\Desktop\\FF073A6A-775A-4447-B229-00000A037368\\down.exe /aut“,
NULL,
NULL,
0,
0,
NULL,
NULL,
&StartupInfo,
&ProcessInformation)
之后调用 OpenEncryptedFileRawA 函数(疑似垃圾数据

然后通过 sub_7FFE13294060 函数中的 GetFileAttributesW 函数获取"C:\Program Files (x86)\360\360Safe\uninst.exe" 指定文件或目录的属性(判断是否存在杀软

未带杀软
sub_7FFE13292BA0 函数中获取 view.png 路径,然后开辟空间读取,

20 行的 sub_7FFE132911F0 函数,用 CreateFileW 打开文件 vew.png,然后用 CreateFileMappingW 函数创建映射对象,用 MapViewOfFile 将 vew.png 映射到 0000021AD7A4AB9E 这个地址
用 GetFileSize 计算图片 size 减去 png 头等多余数据,得到的就是一个可执行程序,


最后 IsBadReadPtr 判断一下映射可执行文件的地址是否可读,然后取消映射,return 存可执行文件的地址

VirtualAlloc 申请空间,然后将刚才从图片提取的执行文件复制到这个空间;用 CreateProcessA 创建一个处于挂起状态的 colorcpl.exe 进程,WriteProcessMemory 函数将刚才提取的文件注入,用 Context 结构体、SetThreadContext 调整寄存器、栈指针状态,最后运用 ResumeThread 将这个挂起的进程启动,进程注入完成

CurrentProcess = GetCurrentProcess();
TerminateProcess(CurrentProcess, 0);
用这个将当前进程中止
存在杀软
存在杀软的情况与上面带有/aut 参数的执行 shellcode 操作调用的是同一个函数

aut.exe 分析


28 行的函数中进行了 down.exe 白程序的快捷方式创建

RegOpenKeyExW 打开注册表,通过 RegQueryValueExW 将 down 的路径写到注册表中


接下来用 GetFileAttributesW 检测 C:\\ProgramData\\MyLnk 是否存在,不存在就会用 CreateDirectoryW 进行创建;
然后用 CoCreateInstance 创建一个调用编号为 {00021401-0000-0000-C000-000000000046} COM 组件的对象
(这个 COM 的 GUID 是 Windows 中的 Shell COM 组件,用于操作文件夹和快捷方式)

37 行的函数进行了将内存中的 Registry Workshop 写到对应路径中,通过 COM 组件创建了一个 Registry Workshop 的快捷方式,然后生成一个.reg 格式的注册表文件,并利用该文件通过快捷方式的形式附加参数,利用 Registry Workshop 写到注册表中

获取 down.exe 路径,并生成 GIUD,用于为接下来的 Registry Workshop 命名

117 行的函数用于将内存中的 Registry Workshop 读写到 C:\Users\UsersName\AppData\Local\Temp 路径下

26 行通过 write 写入,大小为 0x105A00


之后随机生成 GUID,然后以该 GUID 为名创建一个.reg 文件,然后将相应参数写入;之后同样的方法生成 GUID,用这个 GUID 命名创建的 Registry Workshop 快捷方式,之后通过{9BA05972-F6A8-11CF-A442-00A0C90A8F39}COM 组件以 explorer 的方式运行生成的 Registry Workshop 的快捷方式;最后将刚生成的 Registry Workshop 工具以及快捷方式,.reg 文件全部删除

快捷方式目标用的是.reg 文件,运行的是 Registry Workshop,通过这个方式将 GoogleUpdata_Service"="C:\\programdata\\Mylnk\\down.lnk 写入注册表

快捷方式的运行是通过{9BA05972-F6A8-11CF-A442-00A0C90A8F39}COM 组件实现以 explorer 方式运行



上面是将 down.exe 的快捷方式写入到注册表,后面以同样的方式将 down.exe 写入到注册表
view.exe 分析
这个 exe 是从 view.png 中 dump 出来的后门文件

创建 StartAddress 线程实现后门操作

StartAddress 函数
首先获取一下本机上线时间,然后设置一个注册异常处理(线程崩溃重启;

beginthreadex 函数通过创建新线程的操作进行调用 sub_7FF7286D8570 函数进行键盘记录的获取与保存

通过注册表的方式判断是否开启键盘监听
通过 DirectInput8Create 函数获取键盘记录、 GetKeyState 函数处理大写锁定状态,然后调用 sub_7FF7286DDF00 对键盘记录进行保存

保存键盘记录会对获取方式进行一个检测,从剪贴板获取 or 从当前活动窗口获取;然后都是通过创建文件写入的方式进行实现保存


注册表 HKEY_CURRENT_USER\SOFTWARE\W1nUUI 下写入 IpConfig 文件(便于后面更换登录 ip

之后进行一个火绒杀软的进程检测,,用来判断是否将 IpDates_info 文件写到注册表下
后续就是三个主机以及端口的选择,然后通过 connect 进行连接,如果成功就进行下面的获取计算机信息然后回传的操作

(这部分后续进行详细分析)
接下来进行获取计算机信息

获取本机主机名,用户键盘停止使用时间、系统信息

内存、处理器,CPU 型号、硬盘信息,硬盘空闲空间、显卡与显示屏信息,前景窗口、用户分组信息、计算机位数、进程权限、

通过 COM 组件获取摄像头信息,然后在注册表的 HKEY_CURRENT_USER\Software\Microsoft\IdentityCRL\UserExtendedProperties 下获取 QQ 号

遍历获取杀软进程信息,微信进程、Telegram 进程


发送后进入循环监听发送心跳包,然后回溯 RIP 进入执行功能的函数

功能分析
0x0:加载插件,普通内存加载,使用导出函数
0x1:加载插件,进程注入模式,写入注册表
0x2:结束连接
0x3:发送当前本机状态和心跳包
0x4:获取屏幕截图
0x5:上传执行文件
0x6:下载执行文件
0x7:备注信息与分组信息
0x8:获取进程列表
0x9:发送屏幕监控状态
0xB:清除系统日志
0xC:重启进程
0xD:退出
0xE:注销
0xF:关机
0x10:重启
0x12:修改配置信息重启
0x66:线程开启监控剪贴板
0x67:关闭剪贴板线程
0xC9:心跳包
0x0(加载插件,普通内存加载,使用导出函数)
0x1(加载插件,进程注入模式,写入注册表)

0x0 直接实现加载插件操作

0x1 实现将插件名称 md5 之后,写到注册表进行保存,然后使用进程注入的方法加载插件
0x2 使用 disconnect 断开连接

0x3 发送当前本机状态和心跳包


0x4 获取本机的截图

使用 GetObject、GetDC 等函数实现截图操作
0x5 上传执行文件


隐藏执行和显示执行的区别:通过传入的参数来判断是否添加 StartupInfo.lpDesktop = L"WinSta0\\Default"; 使用这个字段来定义该进程将在哪个桌面上运行
0x6:下载执行文件


通过 InternetOpenUrlW、InternetReadFile 从网络下载执行文件;然后创建新线程执行
0x7:分组信息与备注信息


0x8:遍历当前所有进程

使用很常规的 Process32Fristw 和 Process32Nextw 实现遍历
0x9:发送屏幕监控状态


在 send 之后再次执行运行插件的操作,猜测为使用插件实现获取屏幕监控状态
0xA:获取屏幕状态;与截图操作类似

0xB:清除系统日志

使用 OpenEventLogW 函数清楚系统日志
0xC:重启进程
这个重启进程的操作与上面线程崩溃重启的操作一样

0xD:退出
使用 ExitProcess 函数进行结束线程
0xE:注销
0xF:关机
0x10:重启

这三个操作类似,最终通过 v102 这个变量来传入 ExitWindowsEx 的参数实现不同的功能
BOOL ExitWindowsEx(
UINT uFlags,
DWORD dwReason
);
- uFlags: 指定关机操作的类型,可以是以下标志的组合:
EWX_LOGOFF: 注销当前用户。EWX_SHUTDOWN: 关闭计算机。EWX_REBOOT: 重启计算机。EWX_FORCE: 强制关闭应用程序,未保存的数据将丢失。EWX_FORCEIFHUNG: 强制关闭应用程序,但仅在它们挂起时。
- dwReason: 指定关机的原因代码,通常使用
SHTDN_REASON_*常量,例如SHTDN_REASON_APPLICATION。
0x12:修改配置信息重启

通过注册表修改配置信息
0x66:开启监控剪贴板

通过 GetClipboardData、SetClipboardData 函数等实现监控剪贴板数据
0x67:关闭剪贴板监控进程

使用 TerminateThread 结束剪贴板线程