Using Mono Cecil Decompiler within Windbg to decompile

I have been hacking Mono lately and one of the coolest projects I have seen is the Mono Decompiler. It’s like Reflector but no UI and an API to decompile. Guess what, even reflector is built on top of Mono Cecil.  Most of times when I have to debug I would end up using  !dumpil  sos command to get  the IL  of the method desc.  I am not an IL guru, I am much comfortable reading C# than IL. I could have used reflector to do the same thing, but here are couple of reasons for doing this.

  • I don’t have to open another application and I am comfortable with cdb.exe
  • I like to understand this library , which I could use in the future.

Here is a simple app that would return C# code.  I could have written a windbg extension, but I am lazy

using System;
using System.IO;
using System.Linq;
using System.Text;
using Mono.Cecil;
using Cecil.Decompiler.Languages;

namespace Conosole
 class Decompiler
 static void Main(string[] args)
 var function = args[1].Split(new[] { '.' });
 var methodName = function.Last();
 var typeName = function.ElementAt(function.Length - 2);
 var ns = function.TakeWhile((c, i) => i < function.Length - 2).Aggregate(new StringBuilder(),(sb,s) => sb.Append(s+".")).ToString().Trim(new [] {'.'}) ;

 Console.WriteLine((from module in AssemblyFactory.GetAssembly(args[0]).Modules.Cast<ModuleDefinition>()
 from type in module.Types.Cast<TypeDefinition>()
 from method in type.Methods.Cast<MethodDefinition>()
 where type.Namespace == ns && type.Name == typeName && method.Name == methodName
 select method.SourceCode()).First());
 public static class Extensions
 public static string SourceCode(this MethodDefinition methodName)
 var writer = new StringWriter();
 CSharp.GetLanguage(CSharpVersion.V3).GetWriter(new PlainTextFormatter(writer)).Write(methodName);
 return writer.ToString();

And here is the usage within windbg. I am using LinqPad as an example. Here is the !clrstack output

0:000> !CLRStack
OS Thread Id: 0x16e0 (0)
Child SP IP       Call Site
001ae758 7695438d [InlinedCallFrame: 001ae758] System.Windows.Forms.UnsafeNativeMethods.WaitMessage()
001ae754 61fc737a System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr, Int32, Int32) [f:\dd\ndp\fx\src\WinForms\Managed\System\WinForms\Application.cs @ 2198]
001ae7f0 61fc6e2c System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32, System.Windows.Forms.ApplicationContext) [f:\dd\ndp\fx\src\WinForms\Managed\System\WinForms\Application.cs @ 3422]
001ae848 61fc6c81 System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32, System.Windows.Forms.ApplicationContext) [f:\dd\ndp\fx\src\WinForms\Managed\System\WinForms\Application.cs @ 3306]
001ae878 61f5366d System.Windows.Forms.Application.Run(System.Windows.Forms.Form) [f:\dd\ndp\fx\src\WinForms\Managed\System\WinForms\Application.cs @ 1496]
001ae88c 0038316b LINQPad.Program.Run(System.String, Boolean, Boolean, Boolean, System.String)
001ae96c 003813f1 LINQPad.Program.Go(System.String[])
001aeb84 00380554 LINQPad.Program.Start(System.String[])
001aebc4 0038034f LINQPad.ProgramStarter.Run(System.String[])
001aebd0 003800f5 LINQPad.Loader.Main(System.String[])
001aee18 6d7e21db [GCFrame: 001aee18]

I am going to try and decompile this method “003813f1 LINQPad.Program.Go”  into c#

Here is the output from !ip2md 003813f1 to get the method name and class address

0:000> !ip2md 003813f1
MethodDesc:   002c9024
Method Name:  LINQPad.Program.Go(System.String[])
Class:        0036f404
MethodTable:  002c9230
mdToken:      0600025e
Module:       002c2e9c
IsJitted:     yes
CodeAddr:     00380590
Transparency: Critical

The next command is to get the location of the assembly and here I am using the class address from the above command

.shell -ci "!dumpclass  0036f404" findstr File:

And then issued the following commands


d:\tools\Decompiler “D:\tools\LINQPad.exe” “LINQPad.Program.Go”

Here is the C# code within windbg

So next time, I might not be looking at IL Code inside the debugger.

4 thoughts on “Using Mono Cecil Decompiler within Windbg to decompile

  1. Hmm Great Article. I don’t know what’s the status of Cecil.Decompiler (I think that JB wants to refactor it).
    Anyway, maybe there’s a possibility to print the original var names instead of V_XXX.
    The method definition contains a field “Parameters”, that’s a ParameterDefinitionCollection. Each of the items is a ParameterDefinition, and then you have the fields ParameterType and Name. So maybe you can add to your hack to use the original var names so that it will be even more intuitive.
    Thanks for the post!

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s