Static code analysis and more with MONO-CECIL

online-driver-profiling1You may have heard about tools like FxCop which are very useful in static code analysis, they basically check your code for possible performance hitting mistakes. Code analysers like FxCop can also help to discover many more issues/mistakes, all thanks to routines defined by their build-in, as well as your own custom rules – very handy in boosting code quality. The library I will describe here allows just that and much, MUCH more. Basically it allows for a LINQ like querying of assemblies and extracting related metadata and even actual source code itself from PDB files. On top of read capabilities it allows to add / modify existing methods inside of the compiled assembly! Sounds pretty powerful doesn’t it? Before I get into examples let me paint you a picture of a scenario in which I used it.

Very recently I had this idea of creating a massive legacy code analysis and logic “extraction” tool – think: Analysing code in a way of looking up methods decorated with a specific attributes CodeLogicDocumentationAttribute. Overall idea was to create a living documentation which updates its content each time the code is rebuilt. End result was supposed to be a hosted documentation hub capable of: quick search / categories and tag-based search of code logic so we could for example:

Search for all code logic descriptions and its usage in portals x and y assuming that particular logic is tagged with one of following: Policy / Cancellation.

glassIn my large legacy code scenario this would be helpful in such a way that we could move solution documentation responsibility to devs who actually spent all their time in it. Obviously we could have bunch of analytics document the solution but I am guessing by the time they would finish half of the content would be out of date as maintenance and size of our solution would work against any sensible means of documenting its core logic.

There are already tools that help you extract xml comments and build some forms of documentation out of it but these (unlike Cecil) didn’t support some features I felt we needed like:

  • Listing usage of methods decorated with custom attribute
  • Extracting tags for better searchability of related groups of logic
  • Extracting actual code out of PDB files

If you are impressed already, let me add to it a bit by listing other possible scenarios you could use this amazing library in your projects:

  • Adding code / attributes to assemblies (think: your own shiny AOP tool)
  • Scramble code inside of the assembly (Perhaps you could write your own obfuscation tool?)
  • Actually overwriting code inside of assemblies

I have mentioned overwriting code as a possible problem CECIL can solve for you so I think it’s about time to show some code now. Imagine a scenario when you have a nasty legacy app that you have lost the source code of. That’s bad but on top of this you have also lost an authentication key to its API… Now that’s just bad luck! If only you could hack the app somehow. If only you could replace a bit of code that handles unauthorized calls with the one handling authorized calls… Hmmm how about this bit of CECIL code below which does exactly that:

public void Run()
		{
			// Retrieve the target method onto which we want to add the attribute
			var targetType = _module.Types.Single(t => t.Name == "Target");
			var runMethod = targetType.Methods.Single(m => m.Name == "Run");

			// Get a ILProcessor for the Run method
			var il = runMethod.Body.GetILProcessor();

			// Retrieve the instruction calling the Unauthorized method
			var callUnauthorized = runMethod
				.Body
				.Instructions
				.Single(i =>
					i.OpCode == OpCodes.Call
					&& ((MethodReference) i.Operand).Name == "Unauthorized");


			// Retrieve the Authorized method
			var authorized = targetType.Methods.Single(m => m.Name == "Authorized");

			// Create a new instruction to call the Authorized method
			var callAuthorized = il.Create(OpCodes.Call, authorized);

			// Replace the call to Unauthorized by the call to Authorized
			il.Replace(callUnauthorized, callAuthorized);

			// Write the module with default parameters
			_module.Write(_targetFileName);
		}		

You have to admit this is some pretty amazing (border line magic) capabilities. Cecil can do a lot and it’s definitely a good idea to familiarize yourself with what it can do as it has a potential to be a powerful addition to your bat-belt. It has been around since 2004 and while initially lacked some useful documented, it’s getting there now. Well I guess all that’s left to do now is to check this samples GitHub space and unleash your imagination with the newly found powers of modifying assembled code on demand!

Hope you’ll find CECIL as useful as I did and as always I encourage you to leave your comments below.

Tags: ,