Editing assemblies using ReflexIL
I have known ReflexIL for quite some time, so I thought I’ll write a line or two about this simple and yet power tool. This tool runs as a plug-in for Red Gate’s Reflector.
I’m not sure if I can cover all the features of this tool, but there are a couple that I really liked that we’ll just see those. In order to get it working, you unzip the contents of the file to some folder. In Reflector, under Tools->Add-Ins add the path to the Reflexil.Reflector.dll.
And, you’re set. To bring up the add-in, you just go Tools->ReflexIL.
I have a simple console application to calculate and display the area of a circle.
1: public const double Pi = 3.14;
2: public static void Main()
3: {
4: int radius = 10;
5:
6: double areaOfCircle = Pi*radius*radius;
7:
8: Console.WriteLine(areaOfCircle);
9: }
To let’s see what we can do with ReflexIL, I’ll add the .exe to Reflector.
So you see that there is no reference of the const member Pi in our code. Instead, the member Pi is replaced with it’s value at every reference. Why? See more here. Basically, since Pi is a compile time constant, its value is replaced at every location to optimize the code. What this also means, is that say if I got the const member Pi from a different assembly and if that was the only member I used from that assembly, I can physically delete that third party assembly from my bin directory and the application will just work fine. This is because the value is already replaced in the IL and no reference of that assembly exists in my code.
Now let’s go ahead and change that value to something else. I just right click on the instruction and choose Edit.
Here I have changed the value to 3. I click on update and right-click on the assembly to get the save option:
By default, it appends the file name with ‘.Patched’; you are free to change the name of the file. Now when I run the patched exe file, I , of course, get a ‘patched’ output!
That wasn’t hard now was it? But let’s do something a little more interesting.
The below snippet is bound to throw a null reference exception as the variable p is not instantiated before the GetInt method is called. The code compiles just fine however.
1: public static void Main()
2: {
3: try
4: {
5: Program p = null;
6: Console.WriteLine(p.GetInt());// In C#, NullReferenceException is thrown
7: }
8: catch (Exception exception)
9: {
10: Console.WriteLine(exception);
11: }
12: }
13:
14: public int GetInt()
15: {
16: return 10;
17: }
I again load the assembly in Reflector and see the instructions in ReflexIL. I’m specifically interested in the line that calls the GetInt method.
Now, all I do is to edit the line and change the OpCode from callvirt to call. Click on Update, save the assembly to a patched version.
Tadaa.. no exception. Here’s what happened.
I changed the OpCode to ‘call’ instead of ‘callvirt’. The call IL instruction assumes that the variable that refers to an object, in this case ‘p’, is not null. This is useful for say, static methods. The callvirt IL instruction however requires that the variable that refers to an object is never null. In other words, callvirt does a null check on that variable, but call does not. That’s the reason change the instruction to call made the exception just disappear. So things like this can be easily changed with a tool like ReflexIL.
ReflexIL also shows the meaning of the each of the instructions (you might not understand all of them at first, I know I didn’t). In the above screenshots you see the ‘Edit existing instruction’ window has a description field. This will help you understand CLR at a deeper level.
There are other things you can do with the tool like editing attributes, removing assembly strong name and updating referencing assemblies and removing, deleting or injecting entities
I recall the saying ‘With great power, comes great responsibility’ and have fun learning more of CLR stuff!