Injecting Debug Tracing in a .NET EXE

Previously with .NET Reflector ( and Reflexil ( we patched a .NET race condition

This time I’d come across another app that only broke when a debugger was NOT attached. Using dmp files and analysis with WinDbg I had been able to trace the cause to a global variable being set to an empty string. This variable was being set by a function called QueryValue but from static analysis of decompiled code and the dmp hadn’t been able to determine how it got into that state.

So I decided to insert a trace function to output all the inputs and outputs of the function in question. For API tracing I have often used Rohitab API’s Monitor ( However have found this works best with Win32, and non .NET applications.

To insert the trace function we will need to write it in MSIL, in this case one line of C# will come out to about 30 lines in MSIL…


When starting it is important that .NET reflector has the correct versions of .NET assemblies loaded – i.e. Only .NET 2.0 assemblies loaded for a .NET app, etc.

First we look at IL decompiled section of our function we want to trace:

.method public instance object QueryValue(int32& lhKey, string& szKeyName, string& szValueName, [opt] bool& bSupressErrorMessage) cil managed noinlining nooptimization

Important to note here is:

– Is the method an instance or static. If “instance” then argument 0 will be “this” and argument 1 will be lhKey. szKeyName argument 2, etc. If “static” then argument 0 will be lhKey, szKeyName argument 1, etc.

– Next we need to know how many items we are going to put in our trace – in this case 4 parameters.

We add each line of code with this method – in .NET reflector click Tools –> Reflexil, this will enable this view of instructions.


However first we are going to need to create an object array variable, we do this via variable tab and right clicking “Create New…”

– We gave it name logger

– Type scope is Type reference

– For type we browsed mscorlib –> CommonLanguageRuntimeLibrary –> System –> Object

– For specification we choose array

Then we click Append


Our variable ready to go:


Now we insert our msil code in the instructions tab, right clicking “Create New” for each one, ensuring to insert code in right order.

ldstr “lhKey: ‘{0}’ szKeyName ‘{1}’ szValueName: ‘{2}’bSupress: ‘{3}'”
ldc.i4.4 ; load integer “4” – for our array of 4 items
newarr object ; initialize array
stloc.s logger ; store in our logger variable (Variable Reference)
ldloc.s logger ; load our variable (Variable Reference)
ldc.i4.0       ; load integer 0 – position in array
ldarg.1        ; load arg 1 – lhKey
ldind.i4       ; loads value of type int32 onto evaluation stack indirectly
box int32      ; convert our lhKey Int32 to an object reference
stelem.ref     ; store lhKey in our array
ldloc.s logger ; load our variable (Variable Reference)
ldc.i4.1       ; load integer 1 – position in array
ldarg.2        ; load arg 2 – szKeyName
ldind.ref      ; loads object reference as object reference
stelem.ref     ; store szKeyName in our array
ldloc.s logger ; load our variable (Variable Reference)
ldc.i4.2       ; load integer 2 – position in array
ldarg.3        ; load arg 3 – szValueName
ldind.ref      ; loads object reference as object reference
stelem.ref     ; store szValueName in our array
ldloc.s logger ; load our variable (Variable reference)
ldc.i4.3       ; load integer 3 – position in array
ldarg bSupressErrorMessage ; load argument bSupressErrorMessage (Parameter Reference)
ldind.i1       ; loads value of type int8 as int32
box bool       ; convert bool to object reference
stelem.ref     ; store bSupressErrorMessage in our array
ldloc.s logger ; load our variable
; call MethodReference to String.Format.
; Note because our logger variable is object array
; we must use the string.Format that is string, object[]
call string [mscorlib]System.String::Format(string, object[])
; call MethodRefrence to output debug trace
call void [System]System.Diagnostics.Trace::WriteLine(string)

Now to debug output of function we notice ldloc 2 just before the end of function ret

This loads local variable at position 2 – obj2


So we add this code:

ldstr “RETURN VALUE: \'{0}\'”
call object [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::GetObjectValue(object)
call string [mscorlib]System.String::Format(string, object)
call void [System]System.Diagnostics.Trace::WriteLine(string)

Now we save the EXE


And if there are no bugs in your MSIL code you can now use (or WinDbg – although in this case WinDbg stops issue occurring) to view the trace code



About chentiangemalc

specializes in end-user computing technologies. disclaimer 1) use at your own risk. test any solution in your environment. if you do not understand the impact/consequences of what you're doing please stop, and ask advice from somebody who does. 2) views are my own at the time of posting and do not necessarily represent my current view or the view of my employer and family members/relatives. 3) over the years Microsoft/Citrix/VMWare have given me a few free shirts, pens, paper notebooks/etc. despite these gifts i will try to remain unbiased.
This entry was posted in .NET, Patching, Reflexil, Reverse Engineering and tagged . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s