Ildasm.exe (IL Disassembler) is an out-of-the box disassembler packaged with Visual Studio, and Ilasm.exe (IL Assembler) is an out-of-the-box assembler packaged with Visual Studio. Let’s try using Ildasm.exe and Ilasm.exe to disassemble and then re-assemble a portable executable from a C# Console Application. Take the following C# Console Application for example:
using System; namespace PrintSomething { class Program { static void Main(string[] args) { Console.WriteLine("Started the console application. Press any key to exit."); Console.ReadLine(); } } }
Build this code in Debug mode and run it. Figure out where the code was built and copy the path to your executable for this C# Console Application. Then do a search on your computer for the VS2012 x86 Native Tools Command Prompt and open it up (it will help us run the IL Assembler and Disassembler more easily). Try to change the directory somewhere where you have permissions…for me, the desktop is an alright place so the first command I ran was this:
cd "C:\Users\YourUserAccountName\Desktop"
Here comes the sweet stuff. To disassemble your executable, run this command on it (PrintSomething.exe is the name of the Console Application I’ve shown the code for above, but you can paste whatever path you have copied to your own executable):
ildasm "C:\PathToYourExecutable\PrintSomething.exe" /out:"Disassembly.asm"
You can inspect the assembly code in Disassembly.asm now by opening it up in your favourite text editor (you will find Disassembly.asm in your working directory, which I changed to be my desktop earlier):
// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.18020 // Copyright (c) Microsoft Corporation. All rights reserved. // Metadata version: v4.0.30319 .assembly extern mscorlib { .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. .ver 4:0:0:0 } .assembly PrintSomething { .custom instance void [mscorlib]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) = ( 01 00 1C 2E 4E 45 54 46 72 61 6D 65 77 6F 72 6B // ....NETFramework 2C 56 65 72 73 69 6F 6E 3D 76 34 2E 35 2E 31 01 // ,Version=v4.5.1. 00 54 0E 14 46 72 61 6D 65 77 6F 72 6B 44 69 73 // .T..FrameworkDis 70 6C 61 79 4E 61 6D 65 14 2E 4E 45 54 20 46 72 // playName..NET Fr 61 6D 65 77 6F 72 6B 20 34 2E 35 2E 31 ) // amework 4.5.1 .custom instance void [mscorlib]System.Reflection.AssemblyTitleAttribute::.ctor(string) = ( 01 00 0E 50 72 69 6E 74 53 6F 6D 65 74 68 69 6E // ...PrintSomethin 67 00 00 ) // g.. .custom instance void [mscorlib]System.Reflection.AssemblyDescriptionAttribute::.ctor(string) = ( 01 00 00 00 00 ) .custom instance void [mscorlib]System.Reflection.AssemblyConfigurationAttribute::.ctor(string) = ( 01 00 00 00 00 ) .custom instance void [mscorlib]System.Reflection.AssemblyCompanyAttribute::.ctor(string) = ( 01 00 00 00 00 ) .custom instance void [mscorlib]System.Reflection.AssemblyProductAttribute::.ctor(string) = ( 01 00 0E 50 72 69 6E 74 53 6F 6D 65 74 68 69 6E // ...PrintSomethin 67 00 00 ) // g.. .custom instance void [mscorlib]System.Reflection.AssemblyCopyrightAttribute::.ctor(string) = ( 01 00 12 43 6F 70 79 72 69 67 68 74 20 C2 A9 20 // ...Copyright .. 20 32 30 31 34 00 00 ) // 2014.. .custom instance void [mscorlib]System.Reflection.AssemblyTrademarkAttribute::.ctor(string) = ( 01 00 00 00 00 ) .custom instance void [mscorlib]System.Runtime.InteropServices.ComVisibleAttribute::.ctor(bool) = ( 01 00 00 00 00 ) .custom instance void [mscorlib]System.Runtime.InteropServices.GuidAttribute::.ctor(string) = ( 01 00 24 36 37 36 65 36 33 32 34 2D 38 65 62 34 // ..$676e6324-8eb4 2D 34 33 33 33 2D 39 33 37 37 2D 39 61 65 37 39 // -4333-9377-9ae79 38 62 33 31 61 30 39 00 00 ) // 8b31a09.. .custom instance void [mscorlib]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = ( 01 00 07 31 2E 30 2E 30 2E 30 00 00 ) // ...1.0.0.0.. // --- The following custom attribute is added automatically, do not uncomment ------- // .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows. .hash algorithm 0x00008004 .ver 1:0:0:0 } .module PrintSomething.exe // MVID: {5750456D-A154-4CDE-A849-0BC5414E34EE} .imagebase 0x00400000 .file alignment 0x00000200 .stackreserve 0x00100000 .subsystem 0x0003 // WINDOWS_CUI .corflags 0x00020003 // ILONLY 32BITPREFERRED // Image base: 0x009C0000 // =============== CLASS MEMBERS DECLARATION =================== .class private auto ansi beforefieldinit PrintSomething.Program extends [mscorlib]System.Object { .method private hidebysig static void Main(string[] args) cil managed { .entrypoint // Code size 19 (0x13) .maxstack 8 IL_0000: nop IL_0001: ldstr "Started the console application. Press any key to " + "exit." IL_0006: call void [mscorlib]System.Console::WriteLine(string) IL_000b: nop IL_000c: call string [mscorlib]System.Console::ReadLine() IL_0011: pop IL_0012: ret } // end of method Program::Main .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ret } // end of method Program::.ctor } // end of class PrintSomething.Program // ============================================================= // *********** DISASSEMBLY COMPLETE *********************** // WARNING: Created Win32 resource file Disassembly.res
Try changing the text in this file. For example, change this line:
IL_0001: ldstr "Started the console application. Press any key to " + "exit."
To this line:
IL_0001: ldstr "That just happened."
Now assemble the code with the following command:
ilasm "Disassembly.asm"
You should see a new executable pop out of this file in your current working directory (for me, its the desktop as I’ve shown before): Disassembly.exe. Run it, and voila, you’ll see that the assembler compiled your assembly (and included any changes you’ve made). Pretty nice for touching up some very low-level code in Visual Studio applications, or even for dynamically changing your application’s manifest information.