• 一例疑似MMCore下载器分析


    概述

    这是一例文件夹病毒,手法相对比较高级,通过域名关联到MMCore样本,可能与印度方向APT组织有关联。
    这个病毒使用了分离免杀技术,有2个样本,一个加载器,一个payload。
    加载器(文件名为dwm22.exe)的主要功能是从C2加载payload在内存执行,若无法连接C2,会解密本地的payload(文件名为tpe64.dll),最终会在内存加载一个反射型dll。
    该病毒使用文件夹图标,通过U盘传播,将U盘根目录的目录隐藏,创建同名的副本,诱导用户点击。

    这个样本的payload文件(tpe64.dll)使用了多层加密,边解密边执行,并且采用了随机值异或的方式加密,导致每次落地的文件都不一样。

    加载器 dwm22.exe

    样本的基本信息

    文件大小: 69.5 KB (71,168 字节)
    MD5: b36ff48c880c206606a293b6afeb6c20
    SHA1: 230a6889fe730d08a3711a9af24ba54e551af15e
    SHA256: 169ec38530734ee1f0e8a8c01fa2567feaed2708ba6317cd69ee245021cccd31
    CRC32: 657ecd4f
    Verified:    Unsigned
    Link date:    15:48 2013/12/12
    MachineType:    32-bit
    编译器: EP:Microsoft Visual C/C++(2008-2010)[EXE32]
    链接程序: Microsoft Linker(9.0)[GUI32]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    使用win7的文件夹图标
    使用文件夹图标

    静态分析

    这个样本比较简单,主要功能是在内存中加载payload,功能如下图所示
    img

    首先解密了两个硬编码的字符串,分别是域名和uri
    域名为 adnetwork33.redirectme.net
    uri为 /wp-content/themes/booswrap/layers.png,解密方式如下图所示。
    img
    然后将工作目录切换到当前程序目录下。
    分配了一个全局数组,主要是存储几个全局变量,这个数组会多次使用,后面会传递给要加载的dll,这时将其命名为 gArgv,里面的内容如下,前4个参数winmain函数的输入参数,后2个是Payload的信息 。

    DWORD gArgv_40BF90[6]
    0   hInstance;
    1   hPrevInstance;
    2   lpCmdLine;
    3   nShowCmd;
    4   payload文件的内容
    5   payload的大小
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    若当前目录下存在 tpe64.dll文件,读取其内容存储在 gArgv_40BF90[4]中,文件大小存储在 gArgv_40BF90[5]中。

    若当前目录下没有tpe64.dll,则从下面链接 下载文件
    http://adnetwork33.redirectme.net/wp-content/themes/booswrap/layers.png
    保存在 gArgv[4]中,gArgv[5]保存其大小,下载失败的话,休眠5s再试

    接下来对获取到的tpe64.dll文件内容或下载的payload进行解密,解密首先使用遍历的方式找到异或加密所使用的参数(byte大小),遍历范围为 [0,0x100),找到后用这个参数进行解密。(解密后的shellcode开始4字节为 EB 02 CC F1,后面会看到,这样下面这段代码就比较好理解了)

    最后,在内存中加载解密后的payload执行,传递给shellcode有2个参数: 0xDEFACEDgArgv(gArgv是传递给后面的dll用的,0xDEFACED是用于在内存中标记gArgv的位置的,看后面)
    img

    动态分析

    为了分析payload的行为,需要动态调试。将dwm22.exe和tpe64.dll放在同一目录下,用OD调试dwm22.exe。
    在函数401070处(上一图的函数起始位置)设置断点,单步运行到下面的位置。

    img
    可以看到shellcode的位置是0x00230000,gArgv的地址为0x004EB8A0,其中的内容如下。(这两个地址、下面的gArgv[2]和gArgv[4]每次调试会有不同)

    00 00 40 00  0   hInstance;
    00 00 00 00  1   hPrevInstance;
    3C 1D 4D 00  2   lpCmdLine; 内存地址为0X4D1D3C
    0A 00 00 00  3   nShowCmd; 0x0000000A = SW_SHOWDEFAULT
    00 00 2F 00  4   解密后的payload 内存地址 0x002f0000
    95 10 01 00  6   解密后的payload的大小 0x00011095=69781
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    解密后的payload的大小与tpe64.dll的大小一致

    下面进入shellcode看一下。
    这个shellcode比较复杂,总共进行了5次解密。
    第一次解密
    img
    写成C的伪代码更好理解

    char* t = shellcode + 0x4;
    short cx = 0x441E;
    do 
    {
        *(DWORD*)(t+0x19) ^= 0xBA3B337D;
        *(DWORD*)(t+0x19) += 0xBA3B337D;
        t+=4;
    } while (cx-- > 0);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    第二次解密

    char* t = shellcode+ 0x26;
    short cx = 0x4416;
    do 
    {
        *(DWORD*)(t+0x13) ^= 0x687F9462;
        *(DWORD*)(t+0x13) += 0x687F9462;
        t+=4;
    } while (cx-- > 0);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    第三次解密

    char* t = shellcode+ 0x3E;
    short cx = 0x440F;
    do 
    {
        *(DWORD*)(t+0x1B) ^= 0x705C17CC;
        t +=4;
        *(DWORD*)(t+0x17)  += 0x705C17CC;
    } while (cx-- > 0);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    第四次解密

    char* t = shellcode+ 0x60;
    short cx = 0x4408;
    do 
    {
        t +=4;
        *(DWORD*)(t+0x11) ^= 0x0CA13F46F;
        *(DWORD*)(t+0x11)  += 0x0CA13F46F;
    } while (cx-- > 0);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    第五次解密

    char* t = shellcode+ 0x7D;
    short cx = 0x4401;
    do 
    {
        *(DWORD*)(t+0x14) ^= 0x0D3363D3D;
        t +=4;
        *(DWORD*)(t+0x10)  += 0x0D3363D3D;
    } while (cx-- > 0);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    经过5层解密后,跳转到0x231a95处

    这里可以看到有处理PE头部的代码,推测这是一个pe加载器
    img

    为了方便分析,将解密后的shellcode从内存中dump出来。
    shellcode地址为0x230000,大小为0x00011095,这里使用pchunter进行dump。
    dump出来的文件的hash为

    MD5: 9c51e4ec3c555cb13a77e33fce50d739
    SHA1: 0c36009e5823e2291abf6d4f0a010c4cff4ee218
    
    • 1
    • 2

    下面分析一个上面这个pe加载函数

    dll加载函数

    使用IDA加载dump出来的文件,定位到0x1a95处,F5看伪代码

    该函数首先从shellcode+0x1aa2处向前检索PE文件。

    然后找到PEB结构,找到kernel32.dll的基址。(dll和后面API都通过name作hash比对找到的,这是shellcode的常用操作)
    img
    进而获取LoadLibaryA、GetProcAddress、VirtualAlloc这三个API的地址。
    img
    分配内存,复制pe头部和各节,加载导入表的dll,构造导入地址表。
    img
    然后进行地址重定位,最后跳转到dll入口执行。
    img

    通过上面的分析说明这个dump文件中应该含有一个dll文件,通过010editor很容易实现将这个dll提取出来 。
    这个dll的偏移在0x95,大小为0x11000,暂且命名为 0x95-0x11000.dll,下面重点分析这个dll。

    0x95-0x11000.dll

    样本的基本信息

    文件大小: 68.0 KB (69,632 字节)
    MD5: 6a789f158162d3aa617aa117ff8add2a
    SHA1: ca6276a84c251f2d49c4a315b4dd69409b986994
    Link date:    17:57 2013/11/18
    MachineType:    32-bit
    DIE识别的信息:
    编译器: EP:Microsoft Visual C/C++(2008-2010)[DLL32]
    链接程序: Microsoft Linker(9.0)[DLL32]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这个dll的导出表有两个函数,其中ReflectiveLoader上面已经分析过了,样本的主要功能在DllEntryPoint中

    Name    Address    Ordinal
    ReflectiveLoader(void)    10002600    1
    DllEntryPoint    100035D0    [main entry]
    
    • 1
    • 2
    • 3

    DllMain函数

    进入DllMain函数,发现一段有意思的汇编代码,这段代码的功能是在内存中检索0x0DEFACED(这是前文中dwm22.exe中传入的第1个参数,用来标识 gAarv的位置),检索的范围是[ebp-1ch,ebp+4000000ch],当找到这个标识后,它的下一个位置就是gArgv,就是dwm22.exe中构造的数组。

    将找到的gArgv保存到一个全局变量中,将dwm22.exe的基址传递给DoWork_10001320函数,将dwm22.exe的commandline存储在eax中,这样就完成dwm22.exe向dll的参数传递。然后进入DoWork_10001320开始干坏事。

    img

    DoWork_10001320

    下面进入DoWork_10001320
    首先会处理命令行参数(sub_10001D00函数),再根据不同的返回值来执行不同的逻辑,有4种情况。

    情况1

    若参数是空串,即没有参数的话,返回值为0x70000015,这是从U盘中启动的情况,用户点击了伪装成文件夹的病毒副本,将执行感染系统的操作。

    情况1是在U盘上执行的情况,情况2-4都是在主机上运行的场景。

    img
    首先调用资源管理器打开与当前文件同名的文件夹,用户以为自己打开了一个普通的目录,其实是点击了一个exe。

    创建互斥量 B2B27EA7-6F32-4465-8C7C-D2A6E4BAEFA3,若存在同名的互斥量,退出本实例(返回0x70000011)。

    创建目录 C:\ProgramData\WindowMan,若创建失败的话,会选择 %appdata%作为宿主目录,将自身拷贝到其中,命名为 dwm22.exe

    创建开机启动项:在系统Startup目录中创建一个名为WindowManager.lnk的快捷方式文件,这个lnk指向 C:\ProgramData\WindowMan\dwm22.exe -c2%appdata%dwm22.exe -c2

    C:\Users\\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\WindowManager.lnk
    
    • 1

    执行C:\ProgramData\WindowMan\dwm22.exe -c2%appdata%dwm22.exe -c2,若执行成功,退出本实例(返回0x07000013),否则执行后续代码。

    情况2

    若参数为-c1,执行 .exe -c2,返回值为0x70000013,退出本实例
    img

    情况3

    若参数是-c2,设置工作目录为当前程序目录,返回值为 0x70000014

    创建名为 B2B27EA7-6F32-4465-8C7C-D2A6E4BAEFA3的互斥量
    若存在同名互斥量,退出(返回0x70000011)

    否则执行后续的代码
    img

    情况4

    若参数不是-c1也不是-c2,返回值为0xF0000007,执行后续代码

    后续的代码

    后续代码如下图

    img

    首先创建一个名为 BrowserMgr的窗口,通过windows消息机制,监听DBT_DEVICEARRIVAL类型的消息,检测U盘的插入操作,当有U盘插入时,执行感染操作。

    将U盘根目录下的文件夹隐藏,将 tpe64.dll加密释放到U盘根目录并隐藏,将 dwm22.exe拷贝成与文件夹同名的文件,诱导用户单击。

    在当前目录下创建一个文本文件 x22.dd,将运行日期、U盘插入的日期和在U盘中创建的副本数记录下来。如下图所示,其中S表示运行,I表示U盘插入,C表示在U盘中创建的副本数。
    img

    然后创建一个线程,负责从后台下载载荷执行。
    img
    这个线程是个死while循环,首先创建互斥量 GGM-KRTYUA1-B1NHHTYU,若存在同名的互斥量,跳出。

    进而测试网络的连通性,只要与下列地址之一的80端口建立连接即可,不通的话休眠5分钟再试。

    74.125.224.112
    74.125.224.113
    74.125.224.114
    74.125.224.115
    74.125.224.116
    207.46.197.32
    207.46.232.182
    129.42.38.1
    198.133.219.25
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    若连通的话,从C2下载payload保存为临时文件,
    C2地址为

    adnetwork33.redirectme.net/wp-content/themes/booswrap/main.php 
    
    • 1

    临时文件名为 %temp%\setupGZ[uuuu].tmp

    若下载的文件头两个字节是MZ,说明是一个PE文件,不用解密。
    若不是PE格式的话,对其进行解密,从1到0xff开始遍历,寻找加密的使用XOR参数,找到后使用异或解密。
    img
    最后执行下载的程序。

    IOC

    文件路径
    C:\ProgramData\WindowMan\dwm22.exe 
    C:\ProgramData\WindowMan\tpe64.dll 
    C:\ProgramData\WindowMan\x22.dd 
    %appdata%\dwm22.exe
    %appdata%\tpe64.dll
    %appdata%\x22.dd 保存感染和U盘记录
    %temp%\setupGZ[uuuu].tmp 从C2下载的文件
    可移动存储介质
    X:\dwm22.exe
    X:\tpe64.dll
    快捷方式启动项
    C:\Users\\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\WindowManager.lnk
    
    hash 
    b36ff48c880c206606a293b6afeb6c20 dwm22.exe
    9c51e4ec3c555cb13a77e33fce50d739 tpe64.dll解密后的内存dump文件
    6a789f158162d3aa617aa117ff8add2a tpe64.dll解密后提取的dll
    
    
    域名
    http://adnetwork33.redirectme.net/wp-content/themes/booswrap/layers.png
    http://adnetwork33.redirectme.net/wp-content/themes/booswrap/main.php 
    
    User-Agent:
    Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko)
    
    IP
    74.125.224.112
    74.125.224.113
    74.125.224.114
    74.125.224.115
    74.125.224.116
    207.46.197.32
    207.46.232.182
    129.42.38.1
    198.133.219.25
    
    
    互斥量 
    B2B27EA7-6F32-4465-8C7C-D2A6E4BAEFA3
    GGM-KRTYUA1-B1NHHTYU
    
    创建了一个名为BrowserMgr的窗口
    
    内存的使用0x0DEFACED标识参数
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    yara规则

    loader的检测规则

    rule MMCore
    {
        meta:
            description = ""
    
        strings:
            $s1 = { 50 32 57 34 5B 36 52 38 4D 3A 4C 3C 52 3E 4D 40 2A 42 70 44 76 46 69 48 3B 4A 2E 4C 29 4E 26 50 23 52 36 54 36 56 23 58 34 5A 3E 5C 73 5E 31 60} //加密的域名
            $s2 = { 1E 32 44 34 45 36 1A 38 5A 3A 54 3C 53 3E 4B 40 24 42 2D 44 31 46 68 48 3D 4A 23 4C 28 4E 22 50 34 52 20 54 7A 56 35 58 36 5A 34 5C 2E 5E 28 60 } //加密的Uri
            $s3 = { 8A CB 80 C1 31 30 0E 43 46 } //解密算法
    
        condition:
            any of them
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    归因分析

    这样样本与MMCore存在一定的关联性

    多重xor加密

    使用IDA打开从内存dump出来的解密后shellcode,可以比较直观的看清楚5层解密

    这种多次解密的方式与参考资料1中的图很相似,可以推断出这个样本与MMCore有一定的联系。

    域名相关

    adnetwork33.redirectme.net 在参考资料1和2都有提及

    总结

    这样的样本的的功能比较简单,但是的还是有很高明的地方

    1. 在内存的使用0x0DEFACED来标识参数,实现加载器和dll之间的参数传递
    2. 使用随机值来进行异或加密,解密进再遍历找到这个随机值来解密
    3. shellcode使用了5次解密,解密一段执行一段

    确实非常聪明。

    参考资料

  • 相关阅读:
    晶振与定时时间的简单理解
    老版本kafka查询topic消费情况(python查询)
    ORB-SLAM2 ---- ORBmatcher::SearchForInitialization函数
    后台管理---新建编辑优化
    YB203H系列是一组CMOS技术实现的三端低功耗高电压稳压器
    Java、前端、Python 现在应该如何选择,学习哪个更好?
    阿里云安全恶意程序检测(速通二)
    FebHost:荷兰.NL域名一个富有影响力域名
    基于webservice 使用HttpClient调用
    OG 488, acid|195136-52-8|Oregon Green 488 Carboxylic Acid
  • 原文地址:https://blog.csdn.net/a854596855/article/details/133389964