Patching (legacy) Common Intermediate Language (CIL) assembly, because it can be done.

In the occassion that you need to patch some bugs in (legacy) code that you don't have (anymore), you can make the patch using common intermediate language. In the case of old and legacy code you are sure that there will be no other changes and the risks are minimal.

Every .NET application is being compiled to CIL. The CIL makes sure that the application can run on each devices, independent of the hardware (or operating system).

Using the default .NET tools, ilasm and ildasm, you can decompile the binary to CIL, and then compile it back again to binary.

In this example we will patch a binary of a .NET web application. The .NET application doesn't have any source code any more, but it needed to migrate to an other server. The application enforces SSL, but in the new situation this is being offloaded. We will remove the check for the SSL, which will skip the redirection loop to the https site. Of course we still have the source code, but this way is much more fun.

C:\Windows\Microsoft.NET>"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\x64\ildasm.exe" c:\temp\App_Web_login.aspx.cdcab7d2.dll /all /out=c:\temp\login.il

This will decompile the binary to Common Intermediate Language.

IL_0000:  /* 02   |                  */ ldarg.0
IL_0001:  /* 28   | (0A)000007       */ call       instance class [System.Web/*23000001*/]System.Web.HttpRequest/*01000014*/ [System.Web/*23000001*/]System.Web.UI.Page/*01000004*/::get_Request() /* 0A000007 */
IL_0006:  /* 6F   | (0A)000008       */ callvirt   instance bool [System.Web/*23000001*/]System.Web.HttpRequest/*01000014*/::get_IsSecureConnection() /* 0A000008 */
IL_000b:  /* 2C   | 31               */ brfalse.s  IL_003e

IL_000d:  /* 02   |                  */ ldarg.0
IL_000e:  /* 28   | (0A)000007       */ call       instance class [System.Web/*23000001*/]System.Web.HttpRequest/*01000014*/ [System.Web/*23000001*/]System.Web.UI.Page/*01000004*/::get_Request() /* 0A000007 */
IL_0013:  /* 6F   | (0A)000009       */ callvirt   instance class [System/*23000007*/]System.Uri/*01000015*/ [System.Web/*23000001*/]System.Web.HttpRequest/*01000014*/::get_Url() /* 0A000009 */
IL_0018:  /* 6F   | (0A)00000A       */ callvirt   instance bool [System/*23000007*/]System.Uri/*01000015*/::get_IsLoopback() /* 0A00000A */
IL_001d:  /* 2D   | 1F               */ brtrue.s   IL_003e

IL_001f:  /* 02   |                  */ ldarg.0
IL_0020:  /* 28   | (0A)00000B       */ call       instance class [System.Web/*23000001*/]System.Web.HttpResponse/*01000016*/ [System.Web/*23000001*/]System.Web.UI.Page/*01000004*/::get_Response() /* 0A00000B */
IL_0025:  /* 28   | (0A)00000C       */ call       string [Intelligencia.UrlRewriter/*23000008*/]Intelligencia.UrlRewriter.RewriterHttpModule/*01000017*/::get_RawUrl() /* 0A00000C */
IL_002a:  /* 72   | (70)000001       */ ldstr      "http" /* 70000001 */
IL_002f:  /* 72   | (70)00000B       */ ldstr      "https" /* 7000000B */
IL_0034:  /* 28   | (0A)00000D       */ call       string [System/*23000007*/]System.Text.RegularExpressions.Regex/*01000018*/::Replace(string,
                                                                                                                                        string,
                                                                                                                                        string) /* 0A00000D */
IL_0039:  /* 6F   | (0A)00000E       */ callvirt   instance void [System.Web/*23000001*/]System.Web.HttpResponse/*01000016*/::Redirect(string) /* 0A00000E */
IL_003e:  /* 02   |                  */ ldarg.0

The code above shows at line IL_000b a branch false (when there is no secure connection), changing this command in a brtrue.s will keep the same numbering, but will branch if there is a secure connection (and the application is never aware of a secure connection, because of offloading and the method IsSecureConnection doesn't look at X-Forwarded-Ssl headers). Now you can assemble it again and test.

C:\Windows\Microsoft.NET>"c:\windows\microsoft.net\Framework\v2.0.50727\ilasm.exe" c:\temp\login.il /dll /output=c:\temp\App_Web_login.aspx.cdcab7d2.dll

This will compile the DLL back again.

Copy the DLL back, over the old one and test it. Works!


References: