美文网首页
恶意代码分析实战 第十三章 实验部分

恶意代码分析实战 第十三章 实验部分

作者: doinb1517 | 来源:发表于2022-03-30 16:39 被阅读0次

    实验

    Q

    Lab13-1

    1、比较恶意代码中的字符串(字符串命令的输出)与动态分析提供的有用信息,基于这些比较,哪些元素可能被加密?

    2、使用IDAPro搜索恶意代码中字符串xor,以此来查找潜在的加密,你发现了哪些加密类型?

    3、恶意代码使用什么密钥加密,加密了什么内容?

    4、使用静态工具FindCrypt2Krypto ANALyzer(KANAL)以及 IDA熵插件识别一些其他类型的加密机制,你发现了什么?

    5、什么类型的加密被恶意代码用来发送部分网络流量?

    6、Base64编码函数在反汇编的何处?

    7、恶意代码发送的 Base64加密数据的最大长度是什么?加密了什么内容?

    8、恶意代码中,你是否在 Base64加密数据中看到了填充字符(=或者==)?

    9、这个恶意代码做了什么?

    Lab13-2

    1、使用动态分析,确定恶意代码创建了什么?

    2、使用静态分析技术,例如 xor指令搜索、FindCrypt2KANAL以及IDA熵插件,查找潜在的加密,你发现了什么?

    3、基于问题1的回答,哪些导入函数将是寻找加密函数比较好的一个证据?

    4、加密函数在反汇编的何处?

    5、从加密函数追溯原始的加密内容,原始加密内容是什么?

    6、你是否能够找到加密算法?如果没有,你如何解密这些内容?

    7、使用解密工具,你是否能够恢复加密文件中的一个文件到原始文件?

    Lab13-3

    1、比较恶意代码的输出字符串和动态分析提供的信息,通过这些比较,你发现哪些元素可能被加密?

    2、使用静态分析搜索字符串xor来查找潜在的加密。通过这种方法,你发现什么类型的加密?

    3、使用静态工具,如FindCrypt2KANAL 以及 IDA嫡插件识别一些其他类型的加密机制。发现的结果与搜索字符XOR结果比较如何?

    4、恶意代码使用哪两种加密技术?

    5、对于每一种加密技术,它们的密钥是什么?

    6、对于加密算法,它的密钥足够可靠吗?另外你必须知道什么?

    7.恶意代码做了什么?

    8、构造代码来解密动态分析过程中生成的一些内容,解密后的内容是什么?

    A

    Lab13-01

    先拖进IDA Pro中观察,导入表中有网络连接有关的函数,怀疑有网络连接行为。还有资源相关的函数,怀疑资源节中有东西。

    01_import1.png

    进行网络连接函数为sub_4011c9

    4011c9.png

    a1来自sub_401300,就是资源节中的数据用sub_401190进行了解码。

    401300.png

    解码逻辑就是和0x3B进行异或操作。

    01encode.png

    资源节中数据如下:

    01rs.png

    解码后如下:

    01rs2.png

    所以恶意代码访问的域名是www.practicalmalwareanalysis.com

    继续看a8来源,拿到了主机名的前12个字节,然后将第十三字节置为0,截断。使用sub_4010B1进行处理。

    01a8.png

    继续跟进sub_4010B1,看着比较麻烦,调用了sub_401000

    4010b1.png

    继续跟进sub_401000,调用了byte_4050E8

    01401000.png

    该处是一个标准的Base64索引,所以怀疑sub_4010B1应该是一个Base64编码函数,实际看代码确实是这样。

    01base64.png

    使用PEID的插件寻找加密,可以看到这里找到了一个Base64表,也给出了详细位置。

    kanal.png

    下面动态分析一下,开启wireshark抓包,我的wireshark在宿主机,恶意代码运行在win10虚拟机中,注意选择正确接口。抓到流量如下:

    wireshark.png

    REVTS1RPUC0zMVVN进行Base64解码,解码结果为,正是我的主机名。这也与静态分析结果相符。

    01baseencode.png hostname.png

    如果前面的今天分析没有将逻辑分析的很清楚,其实可以动态调试,看看sprintf格式化的url,直接提取IOC

    01sprintf.png

    然后看看浏览器返回的数据,因为后面要判断浏览器返回的数据的第一个字母是o,这里我们提取数据如下

    01ie.png

    就是拿到了一些注释,程序的基本流程就分析结束

    01content.png

    Lab13-02

    直接运行文件,同时打开Process Monitor,可以看到在和Lab13-03.exe同级的文件夹下创建了很多新文件,而且数量还在不断增加,大小都是7042950字节。

    processmonitor.png 02size.png

    将文件拖进IDA Pro中进行分析。

    可以看到创建的文件名是GetTickCount的返回值,返回值是系统启动以来经过的毫秒数。

    gettickcount.png

    使用PEID的插件寻找加密,没有任何发现。

    03kanal.png

    IDA Pro的插件FindCrypt也没有找到相关信息。在IDA Pro中搜索XOR的结果如下,sub_401739函数大量使用xor,查看引用

    02xor.png

    查看引用,可以判断sub_401851可能是加密相关的函数。

    02xrf.png

    sub_401070函数如下,主要作用是对桌面截屏。

    void *__cdecl sub_401070(void **a1, _DWORD *a2)
    {
      void *result; // eax
      HGLOBAL hMem; // [esp+0h] [ebp-78h]
      UINT dwBytes; // [esp+8h] [ebp-70h]
      char pv[4]; // [esp+Ch] [ebp-6Ch] BYREF
      LONG v6; // [esp+10h] [ebp-68h]
      UINT cLines; // [esp+14h] [ebp-64h]
      HGLOBAL v8; // [esp+24h] [ebp-54h]
      void *v9; // [esp+28h] [ebp-50h]
      HDC hdc; // [esp+2Ch] [ebp-4Ch]
      struct tagBITMAPINFO bmi; // [esp+30h] [ebp-48h] BYREF
      int v12; // [esp+5Ch] [ebp-1Ch]
      HGDIOBJ h; // [esp+60h] [ebp-18h]
      __int16 Src[7]; // [esp+64h] [ebp-14h] BYREF
      int cy; // [esp+74h] [ebp-4h]
    
      v12 = GetSystemMetrics(0);
      cy = GetSystemMetrics(1);
      hWnd = GetDesktopWindow();
      hDC = GetDC(hWnd);
      hdc = CreateCompatibleDC(hDC);
      h = CreateCompatibleBitmap(hDC, v12, cy);
      SelectObject(hdc, h);
      BitBlt(hdc, 0, 0, v12, cy, hDC, 0, 0, 0xCC0020u);
      GetObjectA(h, 24, pv);
      bmi.bmiHeader.biSize = 40;
      bmi.bmiHeader.biWidth = v6;
      bmi.bmiHeader.biHeight = cLines;
      bmi.bmiHeader.biPlanes = 1;
      bmi.bmiHeader.biBitCount = 32;
      bmi.bmiHeader.biCompression = 0;
      bmi.bmiHeader.biSizeImage = 0;
      bmi.bmiHeader.biXPelsPerMeter = 0;
      bmi.bmiHeader.biYPelsPerMeter = 0;
      bmi.bmiHeader.biClrUsed = 0;
      bmi.bmiHeader.biClrImportant = 0;
      dwBytes = cLines * 4 * ((32 * v6 + 31) / 32);
      hMem = GlobalAlloc(0x42u, dwBytes);
      bmi.bmiColors[0] = (RGBQUAD)GlobalLock(hMem);
      GetDIBits(hDC, (HBITMAP)h, 0, cLines, *(LPVOID *)bmi.bmiColors, &bmi, 0);
      *(_DWORD *)&Src[5] = 54;
      *(_DWORD *)&Src[1] = dwBytes + 54;
      Src[0] = 19778;
      v8 = GlobalAlloc(0x42u, dwBytes + 54);
      v9 = GlobalLock(v8);
      memcpy(v9, Src, 0xEu);
      memcpy((char *)v9 + 14, &bmi, 0x28u);
      memcpy((char *)v9 + 54, *(const void **)bmi.bmiColors, dwBytes);
      GlobalUnlock(hMem);
      GlobalFree(hMem);
      ReleaseDC(hWnd, hDC);
      DeleteDC(hdc);
      DeleteObject(h);
      result = v9;
      *a1 = v9;
      *a2 = dwBytes + 54;
      return result;
    }
    

    关于此部分代码的分析可以参考MSDN

    https://docs.microsoft.com/en-us/windows/win32/gdi/capturing-an-image

    开始动态调试,在0x401880位置打上断点,这时栈上是缓冲区地址(0x030F5020)和大小(0x006B7786)。

    40181f.png

    查阅资料可知此处格式为BMP,详细信息参考wiki:https://zh.wikipedia.org/wiki/BMP

    偏移量 大小 用途
    0000h 2字节 用于标识BMP和DIB文件的魔数,一般为0x42 0x4D,即ASCII的BM。以下为可能的取值:BM – Windows 3.1x, 95, NT, ... etc.BA – OS/2 struct Bitmap ArrayCI – OS/2 struct Color IconCP – OS/2 const Color PointerIC – OS/2 struct IconPT – OS/2 Pointer
    0002h 4字节 BMP文件的大小(单位为字节)
    0006h 2字节 保留;实际值因创建程序而异
    0008h 2字节 保留;实际值因创建程序而异
    000Ah 4字节 位图数据(像素数组)的地址偏移,也就是起始地址。

    再看缓冲区的内容,第一二个字节为0x420x4D,后面四个字节为0x6B7786就是十进制的7,042,950,和最初发现的temp文件大小是一致的。

    接下来到解密环节,可以直接将未加密的文件给dump出来,脚本如下:

    from idc import *
    
    RunTo(0x401880)
    GetDebuggerEvent(WFNE_SUSP, -1)
    stack = GetRegValue("esp")
    buffer_addr = Dword(stack)
    print("buffer_addr:{}".format(hex(buffer_addr)))
    buffer_length = Dword(stack + 4)
    print("buffer_length:{}".format(hex(buffer_length)))
    
    
    
    tmp_list = []
    for byte in idc.GetManyBytes(buffer_addr, buffer_length):
        tmp_list.append(byte)
    
    with open("dump.bmp", "wb") as f:
        f.write(bytes(tmp_list))
    print("success")
    
    02dump.png

    dump出的文件如下,可以看到是一个全屏截图。

    bmp文件渲染不了。。。

    假设此加密函数是可逆的(可以对加密后的数据再次运行加密函数得到加密前的数据),可以使用手动或者自动化的方式解密。

    使用x32dbg进行解密

    使用winhex打开加密后的文件,以16进制形式复制。再使用x32dbg打开Lab13-02.exe,在0x4018800x40190A两处下断点,复制加密后的数据到buffer地址,再F9运行,即可得到解密后的文件,将后缀名改为.bmp即可打开

    02copy.png

    使用脚本对上面操作自动化

    //使用PathchByte()对内存数据进行修改(不适合修改大量数据,时间非常久)
    
    eg:对XOR的数据进行解密
    addr = 0xaaaa
    for i in range(xxxx):
        PatchByte(addr +i, Byte(addr + i)^ 0x123)
        
    eg:读取文件数据进行Patch
    with open(file_path, "rb") as f:
        buffer = f.read()
        for index, byte in enumerate(buffer):
            PatchByte(buffer_addr +index, byte)
    

    回答:

    1、在当前目录创建了大小为7,042,950byte的文件,文件名为temp加8个十六进制数

    2、XOR大量出现在sub_401739,其他检测加密的插件没有发现什么有效信息。

    3、WriteFile调用之前可能会出现加密逻辑。

    4、加密函数是sub_40181F

    5、原内容是屏幕截图

    6、可以在文件未加密之前dump出来,也可以对加密的文件再次执行加密函数进行解密

    7、还原文件不再赘述

    Lab13-03

    使用IDA Pro打开文件,查看strings窗口,可以看到可能使用了自定义的Base64加密。

    03strings.png

    可以看到函数sub_4015B7可能使用了AES加密数据。

    034015b7.png

    使用PEID的插件KANAL也发现了AES加密的特征。

    03kanal1111.png

    sub_401AC2sub_4015B7两个函数都和加密相关,中间部分有网络连接行为。

    03connect.png

    修改Lab13-03.exe运行机器的hosts文件,将对应IP改为我们自己的机器,使用NC查看连接

    03nc.png

    捕获的数据包如下,根据行为可以判断应该是一个反弹shell程序,但是对应输出为乱码,应该是进行了加密。

    03connect_pcap.png

    开始分析代码,查找xor指令,去掉清空寄存器和库函数相关的指令,重命名相关函数。(快捷键N

    重命名函数名 函数地址
    s_xor1 401AC2
    s_xor2 40223A
    s_xor3 4027ED
    s_xor4 402DA8
    s_xor5 403166
    s_xor6 403990

    使用IDA Pro的插件寻找加密,可以看到运用了AES加密,对应有三个常量,分别查看引用。

    03findcrypt2.png

    0x40C908地址上的数据在s_xor1s_xor2s_xor4中被使用

    0x40CA08地址上的数据在s_xor3s_xor5中被使用

    0x40CB08地址上的数据在s_xor2s_xor4中被使用

    查看0x40CB08位置上的数据,可以看到这是硬编码的S Box,可以重命名为s_box。与此数据关联的函数与AES加密相关。

    03sbox.png

    查看0x40CA08位置上的数据,可以看到这是硬编码的逆 S Box,可以重命名为reverse-s_box。与此数据关联的函数与AES解密相关。

    03_reverse_s_box.png

    查看s_xor6的交叉引用,函数sub_40352D调用了s_xor6

    03_s_xor6.png

    查看sub_40352D调用了那些函数。可以判断s_xor6也是和AES加密相关,将sub_40352D重命名为s_AES_encrypt

    03_40352d_to.png

    查看s_xor5的交叉引用,该函数在0x4037EE0x40392D位置被调用了,但是这两个位置并没有被识别为代码,说明这个解密函数可能没有被调用执行。

    查看函数s_xor1首先有几个判断条件,条件不正确时给出错误提示,而且包含以下部分,所以判断这应该是AES加密函数的初始部分。

    密钥扩展

    字循环

    字节代换,涉及到S盒

    轮常量异或 (byte_40FB08

    _main函数中调用了s_xor1函数,在调用此函数之前,使用了mov ecx, offset unk_412EF8,查看unk_412EF8的交叉引用,发现几个调用的地方都是这样使用,可以判断unk_412EF8是一个初始化的对象AES。(这里的调用方式是thiscall,第一个参数this保存在ecx32位

    参考:https://zh.wikipedia.org/wiki/X86%E8%B0%83%E7%94%A8%E7%BA%A6%E5%AE%9A#thiscall

    查看AES加密函数sub_40352D的交叉引用,发现是在ReadFileWriteFile之间被调用的。该函数是sub_40132B

    0340352d.png

    继续向上查找交叉引用,发现这是一个新的线程,重命名为aes_thread

    aes_new_thread.png

    同理可以重命名Base64相关函数,Base64解密函数和AES加密函数都出现在函数sub_4015B7中,这两个新线程与两个管道和一个cmd的输入输出相关联:

    • 使用自定义的Base64解密反向shell传回的命令,并发给cmd执行
    • cmd标准输出和标准错误通过AES加密以后传给反向shell控制端。
    base64_and_aes.png

    分析到这里基本流程已经清晰,将命令dir使用自定义Base64加密,加密以后为BInaEi==,重新抓取流量。

    03base642.png

    对上述response流量进行AES解密,结果符合预期。

    03aesde.png

    使用AES解密脚本进行解密,模式为CBC

    # pip install pycryptodome
    from Crypto.Cipher import AES
    import binascii
    
    raw = 'eb 63 85 35 e8 45 cc e9  5c 92 36 9d 31 d5 3c 01' + \
          '8e bf e5 8b 06 e1 48 3f  42 5c 5a 0a 4c 75 b2 fa' + \
          '7a c5 3c 27 f2 04 d2 25  d8 e6 c5 d5 78 03 34 98' + \
          '49 5e 4f fd f7 dd 63 a6  91 0e 81 06 cc a8 62 ac' + \
          '74 f2 4a 26 e7 b2 55 03  d3 71 c8 a9 4c 61 c0 65'
    ciphertext = binascii.unhexlify(raw.replace(' ', ''))
    obj = AES.new('ijklmnopqrstuvwx', AES.MODE_CBC)
    print obj.decrypt(ciphertext)
    

    练习题目

    分析恶意文件 f622a03f9c746e551b6467930413fff9,分析该程序是如何加密恶意负载的。提取相应IOC

    微步在线:https://s.threatbook.cn/report/file/f73c40dd16a7299eb7ae42283e5d37757d43625a2aa95f0a03c982dd5051ebd4/?sign=history&env=win7_sp1_enx86_office2013

    此文件为真实病毒,注意防护

    参考

    【解决IDA Python报错】https://bbs.pediy.com/thread-269644.htm

    【对称密码体制和非对称密码体制】https://www.cnblogs.com/Leo_wl/p/10714011.html

    【AES加密算法的详细介绍与实现】https://blog.csdn.net/qq_28205153/article/details/55798628

    【AES C语言实现】https://www.ghostscript.com/doc/base/aes.c

    相关文章

      网友评论

          本文标题:恶意代码分析实战 第十三章 实验部分

          本文链接:https://www.haomeiwen.com/subject/ethwjrtx.html