.NET Inside Out Part 12 — Modifying managed library on an IL level

This is the twelfth part of the .NET Inside Out series. For your convenience you can find other parts in the table of contents in Part 1 – Virtual and non-virtual calls in C#

Imagine that you have a managed library which doesn’t work as expected and you need to tweak it a bit without accessing the source code. How to do it?

Debugging

First, you probably need to figure out what to modify and what the library does currently. To do that you ideally want to decompile the library and debug it step by step.

The best tool for that is by far dnSpy. It is a mix of ILSpy and VS-like UI which allows you to debug the code and enter any assembly you like. Just load your application calling the library, add breakpoints and debug. Works perfectly.

If you cannot use dnSpy, you can try generating PDB files using ReSharper. This is much slower approach but still works and you can debug the application using any debugger (Visual Studio, WinDBG etc).

If you cannot debug the binary at all, consider just decompiling it and reading the code. Try ILSpy and dotPeek, they work great.

Keep in mind that you will need to modify the library on IL level (most likely) so after you find the “C#” line you want to change, decompile the code to IL to see how it looks like. Also, be aware that decompiling may not be possible because of obfuscators and packers. This is generally a land of reverse engineering and a lot of people will try to stop you from doing that.

Dumping the code

You now should know what to modify (and how). Use ILDasm to dump the library to IL format.

Run ILDasm (most likely somewhere around C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6 Tools\ildasm.exe), load the library (File -> Open) and you should see a bare GUI with library content. Select File -> Dump to dump the project. I typically choose “Dump IL Code” with “Expand try/catch” only and “UTF-8” as encoding, this works for me.

After dumping you should see file with intermediate code (.il), probably resources (.res and .resources), and some other files included in the library (images, assets etc).

Modifying the code

Open IL file and apply any modifications you need. Just keep in mind that the easiest way is to find the function you want to change and then replace it entirely. Don’t write IL by hand, just write the function in some scratch project, decompile to IL and copy the generated code. It is very easy to generate unverifiable code and crash the library so you probably want to avoid risking that.

Also, if the library is signed with strong key, you need to either modify it or remove it. Look for .publickey and .hash instructions and them either modify them or remove them completely.

Packing library again

Now you have IL modified and you need to pack the library again. For that use ILAsm (most likely around C:\Windows\Microsoft.NET\Framework\v4.0.30319\ilasm.exe) and run something like this:

Adjust flags as you need and run the command. It should generate the library library.dll back. Add it as a reference and you are good to go.