I'd like to improve my reverse engineering skills, so I made this WPF application (targeting x64, of course):


<Window x:Class="ApplicationTest.MainWindow"
        <Button Content="Go" Click="Button_Click"/>


namespace ApplicationTest
    public partial class MainWindow : Window
        public MainWindow()

        private void Button_Click(object sender, RoutedEventArgs e)
            var value = "No";
            if (value.Equals("No", StringComparison.OrdinalIgnoreCase))
                MessageBox.Show("You cannot proceed.");
                MessageBox.Show("Well done, lad.");

When I debug it with x64dbg, I'm trying to find the location of the value.Equals("No", StringComparison.OrdinalIgnoreCase) comparison, but I am having trouble finding a way to trace the application to its button click event. Ideally, I want to use x64dbg to modify my application's executable and have it run the else statement and print "Well done, lad." instead. How can this be achieved?

In my Symbols window, under the applicationtest.exe symbol, I see Button_Click at a particular address, but when I try to set breakpoints in or around here in the Disassembler view it never hits them when I click the actual button.


C# is a bad language to compare source code with assembly, because your source code doesn't get compiled to assembly (*). Instead, the source is translated to some intermediate code; running the program means starting an interpreter which takes over and interprets that intermediate code. So the only thing you can trace is that interpreter itself, not the code it's interpreting. (Even if you find a tool that allows you to single-step compiled .net code, it won't be x86 assembly you're single-stepping).

Try a C program instead, or any other language that gets compiled instead of being translated .NET intermediate code.

(*) ignoring jit compilation because the won't help the OP much


Modifying a Release-Mode .NET Assembly

Since IL is so simple, one way to achieve the same result without a debugger is to simply decompile the executable using ILDASM on a corresponding .NET release mode x64 executable using the following command line command:

"C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\ildasm.exe" ApplicationTest.exe /out:Disassembly.asm

In the disassembly, you will see the following IL instructions under the Button_Click method:

IL_000d:  callvirt   instance bool [mscorlib]System.String::Equals(string,
                                                                       valuetype [mscorlib]System.StringComparison)
    IL_0012:  brfalse.s  IL_0020

    IL_0014:  ldstr      "You cannot proceed."

It's very verbose and looks almost identical to your original .NET code so it makes it really easy to find the location of your corresponding code. Modify the text brfalse to be brtrue, and compile it using ILASM:

"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\ilasm.exe" Disassembly.asm

The result will be an assembly named Disassembly.exe which is nearly identical to the original assembly except that it has rerouted application logic. Now when you execute it, clicking the button will print Well done, lad..

Note: You may need to download the Windows SDK or corresponding .NET Framework your .NET project is running in order to get access to ILDASM or ILASM. Also, these tools may not work if your .NET application uses a different version of the .NET framework than the .NET versions that the version of ILDASM or ILASM you are using target.

Debugging a Release-Mode .NET Assembly's MSIL Assembly Code Line-by-Line

To directly answer the question, you can debug release-mode .NET assemblies line by line. You first need to decompile any .NET assembly into IL code as I have shown above, using ildasm. Then, you can recompile your assembly in ilasm using the /pdb flag (ilasm Disassembly.asm /pdb) to create a debug database that will let you debug any .NET assembly line by line. Here is a simple demonstration of how to do that. Once you have compiled using ilasm Disassembly.asm /pdb, launch the executable (Disassembly.exe). In Visual Studio, go to Tools -> Attach to process and attach the debugger to Disassembly.exe. Once attached, go to Debug -> Options and Settings -> Debugger -> Symbols and make sure you add the location of the folder hosting the Disassembly.pdb file (it should be the same folder that Disassembly.exe is in if you followed this guide correctly thus far. Hit the pause button in Visual Studio to freeze execution and go to Debug -> Windows -> Threads and view your threads. Navigate through the threads by double clicking on them. You may need to disable Just my code. If it prompts you, go ahead and do it, it should be a single click in the thread view. Eventually, you will see that one of your threads shows you the IL Disassembly.asm. You can add breakpoints in and debug it line by line. Here is a screenshot:

enter image description here

Just a quick note, you may need to resume then freeze again after loading symbols so that Visual Studio synchronizes them. Also, for this to work, you will need the corresponding Disassembly.asm file in the same directory as well.

Also, Visual Studio has a handy Disassembly View (Debug -> Windows -> Disassembly) which shows you the machine instructions generated by JIT instead of IL instructions, but this window you cannot debug, presumably because JIT generates this stuff dynamically.

  • This is well-known and might work, however I ask myself in which scenarios. In case you have the C# or VB source, you will probably never apply this method. In case you do not have the original source but only the assembly - as is usual in Reverse Engineering - what is the benefit of this method? IMO, a much more efficient method is e.g. to use Reflector and modify the assembly with Reflexil to produce idagnostic behaviour or output e.g. in form of MessageBoxes. – josh Jul 20 '15 at 18:27
  • @josh What do you mean? The whole point of my answer is that you don't need a .NET assembly's source code to debug its IL language code line-by-line, and, as a result you can modify it to do what you want by finding out where it does things you don't want it to do. The benefit? You can debug it on run-time so that you see what part of the IL code performs the operations you desire to remove. IMO, you're not going to be able to do much in a multi-threaded application just by looking at the IL code using tools like Reflector or Reflexil for any sizeable application. Plus, its a waste of time. – Alexandru Jul 20 '15 at 18:33
  • @josh This is a faster method of doing things for any sizeable application. – Alexandru Jul 20 '15 at 18:37
  • All I wanted to express that this method does not seem very practical to apply for reverse engineering of .net assemblies. IMO, to associate the x86 assembly output with IL or C# code might not be a trivial task. And for a practical application, what would be needed were an assembler/compiler for modified x86 assembler code to IL. Does that exist?? – josh Jul 20 '15 at 18:38
  • @josh "to associate the x86 assembly output with IL or C# code might not be a trivial task" - I never said anything like that in my answer. I talk about modifying IL code, not x86-64 assembly code. I talk about modifying the IL code since that's all you need to do to reroute .NET application logic to make it do what you want it to do. You don't even need to get anywhere near the x86-64 assembly code as the JIT compiler handles that translation for you. – Alexandru Jul 20 '15 at 18:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.