.NET Reflector Automation: Add-in From Scratch

Guest post by David Connell (with a little help from Dom Smith, Jason Crease, Clive Tong, and Chris Massey)

Background

My name is David Connell, and I’m currently a software developer working in “DevOps” here at Red Gate. One of the great many opportunities we have here is what is known as ‘Down Tools Week’. Every few months, all development work on existing projects stops for one week to allow us time to develop pretty much anything we think is interesting.

Down Tools

For my last Down Tools Week project, I decided to write an Explorer Add-In to show some extra information about .NET assemblies; specifically, I really wanted to see the following information:

  • .NET Target Runtime
  • Platform: (eg 32 Bit, Itanium….)
  • Obfuscator
  • General Assembly attributes.

Explorer .NET Reflector Add-in results
I should also add that this is interesting in and of itself, but it’s also just a single step along the road to something that niggles me – more effective automatic obfuscation checking (or rather, the lack thereof). But more of that later, let’s just focus on the Explorer add-in for now (if you want to download the code samples, scroll to the bottom of the post).

Project design

Naturally, my first issue was how to design this system. .NET 4 allows you to run different versions of .NET side by side in one process, but I was concerned that this might not afford me adequate control (which is a nice way of saying that I don’t think side-by-side execution works very well for .NET Assemblies, but that’s a whole other story). Consequently, I decided to go for a slightly more complex solution:

  1. A native add-in is loaded in Windows Explorer.
    (I used this example of writing a native add-in to help.)
  2. The add-in calls a Windows Service (written in .NET) through a named pipe.
  3. The Windows Service analyzes the assembly and sends the results back to the Explorer add-in.
  4. The results are displayed by the add-in.

As a quick aside, I also wanted to compile the native code for 32Bit and 64bit, and this seemed to mean that I needed to use Microsoft Visual Studio 2010 Professional. Earlier versions of Visual Studio Professional did not seem to support 64Bit native C++. I did look at using Google’s Protobuf as a way of serializing data between C# and C++, but this did not seem to work out of the box. As a result, I just used a very simple serialization across the named pipe.

Having decided on this architecture, the challenge was to work out how the Windows Service should actually analyze the target assembly. Although I wrote my service to be “AnyCPU”, I could not see how to load 64-bit-only assemblies on a 32-bit environment or other platform targets, and this prevented me from using simple reflection.

Loading .NET Reflector

After speaking to Clive Tong, one of the developers of .NET Reflector, I realised that I could use .NET Reflector to solve my problem. This probably sounds odd: .NET Reflector is an application, so how can you use it to provide information to a Windows Service? The answer is that you can load .NET Reflector like any other assembly, and call its public classes and methods!

Setting up .NET Reflector

I wanted my code to attempt to load Reflector if it was already installed on the machine. To do this, here’s the process my add-in steps through:

  1. Look for any installed products by MSI UpgradeCode.
  2. If that fails because .NET Reflector was just “Xcopied” on to the machine, look in the registry for artifacts of .NET Reflector running.
  3. If that fails, then just use my somewhat-outdated local copy, which comes with the application (essentially, just use the best version of the tool possible).

Initializing .NET Reflector

Initializing .NET Reflector is a little unintuitive. First, you declare a member (before you ask, while I am referencing the DLL in the usual way, I’m trying to load it dynamically):

 

private IAssemblyManager m_AssemblyManager;

 

…then assign that member:

 

ApplicationManager appManager = new ApplicationManager(null, true);
        m_AssemblyManager = (IAssemblyManager)appManager.GetService(typeof
                            (IAssemblyManager));
        m_AssemblyManager.Resolver = null;

 

Note that Reflector uses log4net, so I had to allow for resolving log4net items dynamically from the location that I’ve loaded .NET Reflector.

Loading an assembly into .NET Reflector

To load an assembly, I need to call call:

 

m_Assembly  = m_AssemblyManager.LoadFile(fileName);

 

AssemblyManager.LoadFile loads a .NET assembly and returns an IAssembly interface. You can then call methods on that interface to find out about the assembly you loaded.

Checking assembly references

Now that the target assembly is loaded, you can iterate through the modules it contains, and then use .NET Reflector’s public API to obtain information about the module. For example, to ask which assemblies are referenced by each module:

 

foreach (IModule module in m_Assembly.Modules)
    {
        foreach (IAssemblyReference reference in module.AssemblyReferences)
        {
            Console.WriteLine(reference.Name);
        }
    }

 

Going further

The .NET Reflector API is really quite comprehensive. The main interface returned is IAssembly, which encapsulates what an assembly looks like, and contains a list of Attributes, AssemblyReferences, MethodsDeclarations, Modules and Resources:

 

public interface IAssembly : IAssemblyLocation, IAssemblyReference, 
IComparable, ICustomAttributeProvider
    {
        IAssemblyManager AssemblyManager { get; set; }
        HashAlgorithm HashAlgorithm { get; set; }
        AssemblyType Type { get; set; }
        IMethodDeclaration EntryPoint { get; set; }
        IModuleCollection Modules { get; }
        IResourceCollection Resources { get; }
        string Status { get; }
    }

 

The Modules collection contains the Attributes, types, the references to other assemblies, references to Modules and unmanaged Resources:

 

public interface IModule : IModuleReference, IComparable, 
ICustomAttributeProvider
    {
        IAssembly Assembly { get; set; }
        string Location { get; set; }
        Guid Version { get; set; }
        string TargetRuntimeVersion { get; set; }
        int FileAlignment { get; set; }
        ITypeDeclarationCollection Types { get; }
        IAssemblyReferenceCollection AssemblyReferences { get; }
        IModuleReferenceCollection ModuleReferences { get; }
        IUnmanagedResourceCollection UnmanagedResources { get; }
        bool Pe32Plus { get; set; }
        bool Required32Bit { get; set; }
        bool Itanium { get; }
    }

 

I would recommend using the Visual Studio debugger to investigate the API and discover more about how to look inside a loaded assembly. This is all just a first step towards a greater goal I have in mind – automatic checking for obfuscation, for which I have provided some code samples. Feel free to take a look and have a play, the .NET Reflector API is documented (with links to walkthroughs and examples).

I’m still discovering more about what I can do with the API, and I’m still investigating the types by looking at the ITypeDeclarationCollection from within the module. My next task will be to attempt to load up the IL instructions for a specific method; I have no idea whether this is possible, but it sounds like fun to me!

Download Obfuscation Checker Code Samples.

This entry was posted in extensions, Reflector and tagged , on by .

About Chris

A background in technical publishing; editing articles on Simple-Talk and SQLServerCentral for 3 years now. When I’ve not been editing articles, I’ve been editing or proofing books covering everything from .NET performance testing to Exchange Server, XML Schema Design, and the SQL Server Query Optimizer. I built a few websites to help pay my way through college, but the less said about them, the better.

Leave a Reply

Your email address will not be published. Required fields are marked *