一个简单的病毒样本,病毒样本呈现了相对基础但具有潜在危害的汇编代码结构。从逐句分析汇编代码的角度来看,病毒的主要行为主要包括以下几个方面:
01.
内存操作
接下来的汇编代码分析表明,通过将值1C(28)压入堆栈,可能为缓冲区的大小,然后将 ebp-1C 的值赋给 eax 寄存器,病毒准备调用 VirtualQuery 函数来获取指定地址的内存信息。这一步是病毒行为的关键部分,其目的可能是为了探查系统内存的状态以执行后续的操作。
00401B9A |. 6A 1C push 1C ; /BufSize = 1C (28.)
00401B9C |. 8D45 E4 lea eax, dword ptr [ebp-1C] ; |
00401B9F |. 50 push eax ; |Buffer
00401BA0 |. FF75 E0 push dword ptr [ebp-20] ; |Address
0401BA3 |. FF15 2C914000 call dword ptr [<&KERNEL32.VirtualQue>; VirtualQuery
00401BA9 |. 8B45 E8 mov eax, dword ptr [ebp-18] ; VirTualQuery获取内存信息
这里是微软的接口文档对他的解释:
https://learn.microsoft.com/zh-cn/windows/win32/api/memoryapi/nf-memoryapi-virtualquery
结构如下:
SIZE_T VirtualQuery(
LPCVOID lpAddress,
PMEMORY_BASIC_INFORMATION lpBuffer,
SIZE_T dwLength
);
在 VirtualQuery 函数的参数中,lpAddress 通常是待查询的内存地址,lpBuffer 是用于存储返回信息的缓冲区,而 dwLength 表示缓冲区的长度。病毒代码中将 ebp-1C 的值(可能是缓冲区的指针)传递给 VirtualQuery 函数,以便获取特定内存地址的详细信息。这种行为可能有助于病毒了解系统内存结构,识别可用的空间,或者为进一步的攻击做准备。这种手法表明病毒利用操作系统提供的 API 来执行具体的系统调用,这种方式通常能够绕过一些安全防御机制。
02.
模块基址检查
随后的汇编代码显示,将 eax 寄存器的值移动到内存地址 40DC38 处,可能是为了将先前获取的内存信息进行缓存。同时,将值 0 压入堆栈,然后调用 GetModuleHandleA 函数。此函数在系统中扮演着获取模块句柄的角色,用于判断程序是否发生了重载、卸载等情况。
详细而言,通过 GetModuleHandleA 函数,病毒获取当前程序的模块句柄。这个模块句柄可以用于识别程序的加载状态。如果获取到的模块句柄与之前缓存的内存信息不相等,这可能意味着程序已经发生了变化,可能会触发一些退出线程或重新加载的操作。这种检测程序状态的方式有助于病毒适应环境的变化,可能是为了提高存活性或逃避检测。
接下来的代码段中,病毒使用了 GetInputState 函数,该函数确定当前线程的消息队列中是否有需要处理的鼠标和键盘消息。通过调用 PostThreadMessageA 函数,发送 WM_NULL 消息给当前线程,可能是为了唤醒线程以执行消息队列中的任务。这种操作可能是为了在后续的代码中实施更高级的行为。
00401BAC |. A3 38DC4000 mov dword ptr [40DC38], eax
00401BB1 |. 6A 00 push 0 ; /pModule = NULL
00401BB3 |. FF15 04914000 call dword ptr [<&KERNEL32.GetModuleH>; GetModuleHandleA
00401BB9 |. 3B05 38DC4000 cmp eax, dword ptr [40DC38] ; GetModuleHandle获取当前模块基址
00401BBF |. 75 16 jnz short 00401BD7 ; 两者比较,不要相等则退出线程
00402056 . FF15 14924000 call dword ptr [<&USER32.GetInputStat>; [GetInputState
0040205C . 6A 00 push 0 ; /lParam = 0
0040205E . 6A 00 push 0 ; |wParam = 0
00402060 . 6A 00 push 0 ; |Message = WM_NULL
00402062 . FF15 48914000 call dword ptr [<&KERNEL32.GetCurrent>; |[GetCurrentThreadId
00402068 . 50 push eax ; |ThreadId
00402069 . FF15 18924000 call dword ptr [<&USER32.PostThreadMe>; PostThreadMessageA
0040206F . 6A 00 push 0 ; /MsgFilterMax = 0
00402071 . 6A 00 push 0 ; |MsgFilterMin = 0
00402073 . 6A 00 push 0 ; |hWnd = NULL
00402075 . 8D85 BCFDFFFF lea eax, dword ptr [ebp-244] ; |
0040207B . 50 push eax ; |pMsg
0040207C . FF15 0C924000 call dword ptr [<&USER32.GetMessageA>>; GetMessageA
004064B4 |. 68 04010000 push 104 ; /BufSize = 104 (260.)
004064B9 |. 8D85 D8FDFFFF lea eax, dword ptr [ebp-228] ; |
004064BF |. 50 push eax ; |PathBuffer
004064C0 |. 6A 00 push 0 ; |hModule = NULL
004064C2 |. FF15 00914000 call dword ptr [<&KERNEL32.GetModuleF>; GetModuleFileNameA
004064C8 |. 68 04010000 push 104 ; /获取当前路径
004064CD |. 6A 00 push 0 ; |c = 00
004064CF |. 8D85 E0FEFFFF lea eax, dword ptr [ebp-120] ; |
004064D5 |. 50 push eax ; |s
004064D6 |. E8 67290000 call <jmp.&MSVCRT.memset> ; memset
最后,通过调用GetModuleFileNameA 函数获取了当前程序的路径,这可能用于病毒的信息搜集或隐藏。整体而言,这段代码表明病毒通过操作系统 API 来监控程序状态、处理消息队列,以及获取当前程序的路径信息,这些都是其后续行为的基础。
03.
病毒破坏阶段
接下来的汇编代码揭示了程序使用 memset 分配了一个大小为 3 字节的内存,并通过 API 将内存内容提取出来,同时保留了原来路径的三个字节。这个过程实际上是提取之前获取的路径信息中的前三个字节,即磁盘的盘符。这一步的目的可能是为了对路径信息进行进一步的处理和识别。
004064D6 |. E8 67290000 call <jmp.&MSVCRT.memset> ; memset
004064DB |. 83C4 0C add esp, 0C
004064DE |. 8D85 D8FDFFFF lea eax, dword ptr [ebp-228]
004064E4 |. 50 push eax ; /String2
004064E5 |. 8D85 E0FEFFFF lea eax, dword ptr [ebp-120] ; |
004064EB |. 50 push eax ; |String1
004064EC |. FF15 1C914000 call dword ptr [<&KERNEL32.lstrcpyA>] ; lstrcpyA
004064F2 |. 68 01010000 push 101 ; /n = 101 (257.)
004064F7 |. 6A 00 push 0 ; |c = 00
004064F9 |. 8D85 E3FEFFFF lea eax, dword ptr [ebp-11D] ; |
004064FF |. 50 push eax ; |s
00406500 |. E8 3D290000 call <jmp.&MSVCRT.memset> ; memset
00406505 |. 83C4 0C add esp, 0C ; 保留路径前三个字节
随后,病毒通过对这个路径信息进行解析,并调用 GetDriveType 函数来判断磁盘的类型。这个函数用于确定磁盘驱动器是可移动的、固定的、CD-ROM、RAM 磁盘,还是网络驱动器。如果磁盘类型为2(可移动磁盘),则程序跳转到地址 00406553。
在 00406553 地址处,代码片段通过调用 wsprintfA 函数进行字符串的格式化,其中包含 explorer.exe 的路径。wsprintfA 函数用于将格式化的数据写入字符缓冲区。在这里,通过将路径信息和其他字符串组合成一个新的字符串,病毒可能在后续操作中使用这个新的路径字符串。
0040650F |. FF15 A4904000 call dword ptr [<&KERNEL32.GetDriveTy>; GetDriveTypeA
00406515 |. 83F8 02 cmp eax, 2 ; 判断当前磁盘类型
00406518 |. 75 39 jnz short 00406553 ; -------------------------------------------
0040651A |. 8D85 E0FEFFFF lea eax, dword ptr [ebp-120]
00406520 |. 50 push eax ; /<%s>
00406521 |. 68 A09A4000 push 00409AA0 ; |Format = "/n,%s"
00406526 |. 8D85 98FDFFFF lea eax, dword ptr [ebp-268] ; |
0040652C |. 50 push eax ; |s
0040652D |. FF15 10924000 call dword ptr [<&USER32.wsprintfA>] ; wsprintfA
00406533 |. 83C4 0C add esp, 0C
00406536 |. 6A 05 push 5 ; /IsShown = 5
00406538 |. 6A 00 push 0 ; |DefDir = NULL
0040653A |. 8D85 98FDFFFF lea eax, dword ptr [ebp-268] ; |
00406540 |. 50 push eax ; |Parameters
00406541 |. 68 A89A4000 push 00409AA8 ; |FileName = "explorer.exe"
00406546 |. 68 B89A4000 push 00409AB8 ; |Operation = "open"
0040654B |. 6A 00 push 0 ; |hWnd = NULL
0040654D |. FF15 E4914000 call dword ptr [<&SHELL32.ShellExecut>; ShellExecuteA
00406553 |> C745 EC C09A4>mov dword ptr [ebp-14], 00409AC0 ; ------------如果为移动磁盘则打开explorer-----
00401681 |> 6A 00 push 0 ; /hTemplateFile = NULL
00401683 |. 68 80000000 push 80 ; |Attributes = NORMAL
00401688 |. FFB5 E8FEFFFF push dword ptr [ebp-118] ; |Mode
0040168E |. 6A 00 push 0 ; |pSecurity = NULL
最后,通过调用 ShellExecuteA 函数,程序打开了资源管理器(explorer.exe)。这个步骤引起了关注,因为通常普通程序通过操作系统提供的 API 或其他适当的手段来实现其功能,而不直接调用 explorer.exe。这种直接调用系统资源管理器的方式可能是可疑的,因为它可能允许程序执行一些具有破坏性的操作,例如结束或修改进程,对主机进行文件写入等操作。
本文作者:西瓜麻辣烫
雷石安全实验室
商务咨询:
0571-87031601
商务邮箱:
原文始发于微信公众号(雷石安全实验室):雷石|病毒样本分析