MSIL Injection

MSIL Injection, also known as MSIL Insertion, involves modifying the MSIL instructions of an existing method. This process is often referred to as injecting or inserting new instructions into an existing flow.

Injecting IL instructions is just a part of IL-level weaving. Modifying existing code requires the completion of the following tasks:

  1. Reading the metadata of the .NET module.
  2. Decoding the stream of IL instructions in a meaningful way.
  3. Identifying the points where new instructions should be injected.
  4. Restructuring the method body if exception handlers need to be added.
  5. Injecting the IL instructions.
  6. Assembling the in-memory representation back into a binary file.

An IL reader/writer performs all these tasks, except for the third task (detection of injection points), which is typically the responsibility of the code weaver.

How to Inject MSIL Instructions

If you are determined to directly inject MSIL instructions, be prepared for a challenging task. You have a few approaches to choose from.

Standard System.Reflection/System.Reflection.Emit API

While the .NET Framework includes this API, it may not be the best choice for this task. These APIs are suitable for creating new classes and methods, but they are less appropriate for injecting instructions, i.e., modifying an existing method. The main issue is that the API is strictly stream oriented: you have to write the entire method in a single pass, which is not always feasible and is seldom easy.

Another limitation is that the System.Reflection API does not provide an exact representation of a .NET module. It may cover 99% of your needs, but you will not have the ability to support the remaining 1%. For instance, System.Reflection does not distinguish between void* and System.IntPtr or int32 and System.Int32. Other advanced features, such as security attributes or marshaling, may have incomplete support.

Mono Cecil

Mono Cecil is a viable option if you are in search of an IL reader/writer. It boasts a strong community and has been used in commercial applications, which is a solid assurance of its quality. Although the project is associated with Mono, it also supports the Microsoft implementation. You can find more information at http://www.mono-project.com/Cecil .

PostSharp

PostSharp includes an IL reader/writer that covers the complete .NET specification for managed code. The APIs are optimized for usability, leading some users to find it easier to use than Cecil. The key difference with Cecil is that PostSharp is designed as a platform where the IL reader/writer is just one component. The platform manages the entire post-compilation process, including integration with MSBuild, and provides a host of additional services typically used by code weavers (such as type hierarchy analysis, use/used by analysis, etc.).

Microsoft Phoenix

Phoenix is Microsoft's new framework for the next generation of compilers. It abstracts the target machine, allowing it to work with MSIL assembly as well as Intel x86 assembly. Some users argue that the trade-off is increased complexity. The greatest advantage is undoubtedly the guarantee of support and continuity. However, be aware of the license—it is currently reserved for academic research.

Rail

Rail was initially designed to implement an API that allows CLR assemblies to be manipulated and instrumented before they are loaded and executed. It employs static weaving of IL instructions. The Rail APIs are often used as an IL reader/writer with some additional advanced weaving capabilities. More information can be found at http://rail.dei.uc.pt/ .