Introduction
In real life, for any Software Product we have this in Development and Production. In development, we found issues and having the code it is more easy to detect and fix, which is not the case in QA (sometimes) and production environments.
As Quality Assurance engineer, our work is not just to find issues, the more important part of them is to isolate the problem, in order to give the developer the best information as possible. In QA, we need an environment similar to that the user has, and sometimes we are not able to use the source code for issue isolation.
In this example, we are going to show the most simple case “How to see the input parameters of a simple function in a class” without having the source code in runtime. To do this, we are going to use a very simple function contained inside an executable. Our main tool will be Windows Debugging for Windows and SOS for .NET Debugging. Let's suppose that we do not have a good Logger level from development
The main challenge here is: Find the interesting function to get Input Parameters, and print them directly from Process Memory. The article is a little longer, but the same article is applicable to ASP.NET processes or Windows Processes, I will post more articles in the future. If you need some help, please email me at rpally@reversingsoftware.com or jrpally@hotmail.com and I will be happy to assist you. To proceed with this article, please use the attached file to debug this one.
Let's Start
Install and download Windows Debugger tool from http://www.microsoft.com/whdc/devtools/debugging/installx86.mspx.
Once installed, copy the .NET helper debugging file from %WINDIR%\Microsoft.NET\Framework\v2.X.XXXXX\SOS.dll to %PROGRAMFILES%\Debugging Tools for Windows (x86).
Launch Windbg
:
Let's start the process with Windbg
(File->Open Executable):
At this time, the executable file did not start yet and Windbg
CMD prompt will be open.
Load the library SOS.DLL to load the .NET debugging helper. .load sos
Just press F5 to get the executable running.
Please note that the Sample.exe program is running under the debugger.
We would like to freeze our sample.exe process. To do this, just Click on the debugger and press CTRL+BREAK.
Let's explore the main thread of our executable and the stack trace until this time. To do this, we are going to use ~
(thread) *
(all) e
(Execute the command) !clrstack
(print the stack given a thread):
~*e !clrstack
We are displaying all threads and their stacks (Note that we are using !clrstack
which is included in the SOS.DLL file).
The output will be:
Interesting! Looks like the process is trying to read a string
from the user (System.Console.Readline
), and there is a Main
Function.
Now we want to get the methods that encapsulate the class ConsoleApplication12.Program
, to do this there are many ways. Let's explore this one:
!ip2md
: IP Instruction Pointer to Method Description, given an IP (EIP in this case) address, we want to convert this to method description which is an internal structure of CLR .NET that gives us their method name and IL CODE:
We got:
Cool, we got the address of the Method Table of this class, Method Table is an internal structure that contains the List of the Methods of a class.
Let's explore the Method Table:
!dumpmt
allows us to get the Method Table and –MD
gives us the method description for each Method contained in this Method Table.
We got:
Cool, we have a ConsoleApplication12.Program.NumberOfWords
method. What if we decide to set a breakpoint here? On Windbg
(Windows Debugger) unmanaged we have the command bp (Breakpoint) but we can observe that the method NumberOfWords
was not Jitted yet (The method has not run and we do not have their exact their Entry Point), but SOS allows us to set a breakpoint using Method Desc:
!bpmd –md 0097c011
The result:
0:000> !bpmd -md 00973378
MethodDesc = 00973378
Adding pending breakpoints...
We can continue running our application and use this (press F5):
And press ENTER in my small app.
Please note that if we press enter, our program freezes. What happened? Go back to Windbg
:
Good. Seems like our executable breaks at the expected function, to ensure this run the command !clrstack
.
Good! Our stack trace shows that the Executable stops on NumberOfWords
method, but what if we can show a more detailed stack? ;) Use !clrstack
with the flag –p
:
!clrstack –p (-p means parameters)
SOS helper has an interesting command (!do DumpObject
) let's use this. Given a Pointer of the Object
address, it prints for us the object
:
We got:
Cool, this is the string
that we entered in the Sample.exe console.
Printing the string
using !do
command could be a problem in display, since it also prints additional elements like name, method table and other ones.
We are interested in printing just the string
itself: Let's explore a little the memory for this object.
Click on Windbg View->Memory / on Virtual: write 014e9b90 (the address of the memory which contains the object:
Good, we have the string
in memory, how can we print this in console? (Please note that every character in the string
has a 00 byte) Unicode string
? The answer is YES.
But why the real string
(“rene pally from <country-region w:st="on"><place w:st="on">Bolivia”) do not starts in 0x014e9b90 address? The answer is: It because 0x014e9b90 is the address of the CLASS and not the address for the FIRST CHAR.
The first char has the bytes 00 72 Unicode Notation and their char is: r
.
As the picture shows, the first char starts at 0x014e9b90c and the initial address was 0x014e9b90.
Let's use:
.printf "%mu", 0x014e9b90+c
Executing the command:
Cool, we wrote the string .printf
prints an string
on the Windbg
screen given an address terminated in NULL
, %mu
is used to print an array of chars given in Unicode format.
We explained why we need to add the 0xc to the initial address of the string
, it has a logic, since in the String
structure, the OFFSET of the first char
shows as 0xc.
The String
Object Address can change the next time that the process is executed, what can we do? The object address for input addresses is stored in the stack, and in some processor registers:
After running a second time, the object address changed to 0x0155fe28. We used the command r to show the registers, and if we match ECX with the Object
address, they are equal, let's use:
.printf "%mu",ecx+c
Setting the breakpoint: Now that we have found the way to print a S<code>
tring class directly from memory, we can use BP and with their command:
bp eip ".printf \"\\n%mu\",ecx+c;gc"
Let's explain this breakpoint.
- BP = set a breakpoint
- EIP = the current EIP address (Current Instruction pointer), remember that we stopped the function in the start of the function
NumberOfWords
BP supports additional commands when the breakpoint stops, once we stopped in the breakpoint we need to print the ECX+C
, once we print this, we need to continue with GC
which is a command to continue the execution.
\” escape char
to be inside “” string
\\n=\n carriage return. Put F5 and continue using the Sample.exe.
Thanks! :)