Dynamically Creating .NET Assembly with System.Reflection and Emit
While creating DeleteAfterRunning application which allows to build self-deleting executable files, I come across System.Reflection class in .NET for creating assemblies in the run-time. All .NET assemblies are made from IL code which you can examine using any .NET dissembler. I use IL Dasm which comes with a Visual Studio.
Dynamically Creating a New .NET Assembly
Classes we need to examine are:
- AppDomain – controls isolated environment where our assemblies are running
- AssemblyName – allows us to identify our assembly
- AssemblyBuilder – key class for creating a new assembly dinamically
- ModuleBuilder, TypeBuilder, MethodBuilder – additional classes used to define methods, types, etc
- ILGenerator – class which generates .NET IL code for us
Code:
using System.Reflection; using System.Reflection.Emit;
private static void GenerateNewAssembly(string name, string fileName)
{
// get an instance to our isolated environment, aka ApplicationDomain
AppDomain appDomain = AppDomain.CurrentDomain;
// create a descriptor for our new assembly and define its name
AssemblyName assemblyName = new AssemblyName(name);
// define AssemblyBuilder and assign its rights
AssemblyBuilder aBuilder = appDomain.DefineDynamicAssembly(assemblyName,
AssemblyBuilderAccess.Save); // AssemblyBuilder can only save our new assembly
// creating assembly's core module specifying name and file name (location)
ModuleBuilder mBuilder = aBuilder.DefineDynamicModule(name, fileName);
// define a Type that we'll use
TypeBuilder tBuilder = mBuilder.DefineType(name + "Type", TypeAttributes.Public);
// and finally let's define our first method - Main() (which is required for any executable file)
MethodBuilder methodBuilder = tBuilder.DefineMethod("Main",
MethodAttributes.Public | MethodAttributes.Static, // method attributes == public static void Main() {}
null, null);
// declare that your Main function will be an entry point for our assembly
aBuilder.SetEntryPoint(methodBuilder,
PEFileKinds.ConsoleApplication); // we will set a target to CUI rather than GUI for this example
// IL code generator for our Main method
ILGenerator il = methodBuilder.GetILGenerator();
// create our IL code
CreateIL(il);
// create our defined Type
tBuilder.CreateType();
// save our new assembly
aBuilder.Save(fileName);
}
private static void CreateIL(ILGenerator il)
{
// System.Console.WriteLine("Hello World!"); translated to IL code with ILGenerator help
il.EmitWriteLine("Hello World!");
// end Main method with a return call
il.Emit(OpCodes.Ret);
}
Adding IL Code
Now we can call GenerateNewAssembly(“Test”, “test.exe”) method to generate a new Test assembly in “test.exe” file. The new executable file can be used as any other .NET .exe assembly, but all it does – displays a simple “Hello World!” text and quits. What if we want to add some functionality? Let’s say, add Console.ReadKey() method to wait for user’s input before closing. Time to expand our CreateIL() method and dive into IL code.
First, we need to figure out what IL operation codes we need to use to call Console.ReadKey() method. Let’s create a simple console application that has only a Console.ReadKey() in it. Compile. Run Visual Studio Command Prompt and start IL Dasm (execute “ildasm” command in the command prompt). Open the assembly and check IL code.
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 8 (0x8)
.maxstack 8
IL_0000: nop
IL_0001: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
IL_0006: pop
IL_0007: ret
} // end of method Program::Main
- Line 8 – nop operation that does absolutely nothing. Just skips the CPU cycle (mainly used to reduce overhead).
- Line 9 – call operation with provided argument to specific method.
- Line 10 – pop operation, which “pops” last entry in the assembly allocated stack. Stack is a place where methods pass their results, and since ReadKey() method returns us ConsoleKeyInfo object, we need to retrieve (“pop”) it from the stack, even if we won’t use it.
- Line 11 – ret operation equivalent to return call, which ends our method’s execution.
So, let’s extend our CreateIL() method to incorporate this IL.
private static void CreateIL(ILGenerator il)
{
// System.Console.WriteLine("Hello World!"); translated to IL code with ILGenerator help
il.EmitWriteLine("Hello World!");
// get ReadKey() method information
// GetMethod() will searh for specified method in .NET
MethodInfo mInfo = typeof(System.Console).GetMethod("ReadKey",
Type.EmptyTypes); // we're not passing any parameters therefore Type.EmptyTypes
// if we're looking for a method with additional parameters, you would need to specify their type
// ...new Type[] { typeof(..), .. }
// i.e. WriteLine("Hello") would be:
// MethodInfo mInfo = typeof(System.Console).GetMethod("WriteLine", new Type[] { typeof(String) });
// write "call" OP code with ReadKey method's information
il.Emit(OpCodes.Call, mInfo);
// pop the stack - retrieving the result
il.Emit(OpCodes.Pop);
// end Main method with a return call
il.Emit(OpCodes.Ret);
}
Conclusion
There you have it. By using ILDasm, you can easily explore all OP Codes for any .NET assembly and then using System.Reflection classes recreate it dynamically. Analyzing our newly created test.exe with ILDasm, we can see that our IL looks exactly the same as we originally wanted.

You can explore DeleteAfterRunning sources for more examples of Emit class usage.
DeleteAfterRunning
Small open source application allowing you to convert any file to self-deleting executable file. You have a picture, audio file or a document you want to share, but don’t want anyone to keep a copy? Simply create a self-deleting package using DeleteAfterRunning that can be opened once, and when the user finished viewing the file, it will automatically destroys itself, preventing making a copy.

Here’s how it works:
- You select a file from your computer. Can be any file – picture, document, video, you name it.
- Use DeleteAfterRunning to create an executable (*.exe) file.
- Share your file.
- Once a user opens the file, it will run as any ordinary file.
- After a user closes the file, it will automatically securely deletes itself preventing making any copies or running it again.
Software is open-source (released under MIT license), fast and lightweight. No installation needed. Just download and run. Currently in Beta development stage. You can grab the latest copy from Codeplex.
Hey There!
Archive
- August 2011 (2)
- February 2011 (2)
- January 2011 (1)
- November 2010 (1)
- October 2010 (3)

Home
About Me
Blog
Projects
Ideas


