How to: Extract code from a dump file


Dump file -> WinDbg -> .Net Code


Introduction

Sometimes when we are debugging a Dump file analyzing a performance issue (e.g. Hang, Crash, Exceptions, memory pressure etc.) we don't necessarily possess the actual code (DLL, EXE) for any reason. (E.g. a friend sent us the dump file w/o its corresponding code)

In such cases, when we encounter a problem that requires examining the source code, it's possible to save the managed code to a file (managed binary), and then disassemble it using a de-compiler, such as: .Net Reflector, ILDASM, ILSpy etc.

In this post I'll demonstrate a simple process with a Hang issue (the process is exploiting lots of CPU time), and how to restore the source code from its corresponding Dump file.

I'll use the PSSCOR2 debugger extension.




Demo - planning

In this demo we'll perform the following:
            1.      Create a simple class.
            2.      Build the code.
            3.      Run the code.
            4.      Generate a Dump file using 'Task Manager'.
            5.      Open the Dump file in WinDbg.
            6.      Extract the code from the Dump.
            7.      Open the new EXE in a De-compiler.
            8.      Summary & Conclusions.



Demo

1.     Create a simple class:

I've created the following simple class to illustrate a Hang issue, meaning the process is exploiting a lot of CPU time.

I named the file Demo1.cs, and saved it under: E:\MyCode\FromDumpFileToCode\Demo1.cs





      -        As you could see from the code above, it's a simple Main() method with an infinite 'while loop' that keeps incrementing a variable.
      -        This should cause a Hang issue in our process, since it's never advance to the next instruction, and always consume CPU time.



2.     Build the code:

Next, I built the code using the C# compiler (csc.exe) in the 'Developer Command Prompt for VS2015'.

E:\MyCode\FromDumpFileToCode>csc Demo1.cs

Microsoft (R) Visual C# Compiler version 1.1.0.51204
Copyright (C) Microsoft Corporation. All rights reserved.





3.     Run the code:

I run the code and examined 'Windows Task Manager' and verified that the process is Hang.





As we could see from the image above, the Demo1.exe process is taking as much as 25% from the entire CPU usage, thus it's Hang.



4.     Generate a Dump file using 'Task Manager':








After taking the Dump file, I terminated the process and opened WinDbg with the 'Demo1.DMP' dump file.



5.     Open the Dump file in WinDbg:

I opened the 'Demo1.DMP' dump file and performed the following:

           -        Loaded symbols.
           -        Set symbols local path.
           -        Loaded the PSSCOR2 debugger extension (psscor2.dll).
           -        Loaded the CLR debugging modules (mscordacwks.dll).


0:000> .symfix

DBGHELP: Symbol Search Path:
DBGHELP: Symbol Search Path: cache*;SRV*http://msdl.microsoft.com/download/symbols
DBGHELP: Symbol Search Path: cache*;SRV*http://msdl.microsoft.com/download/symbols

0:000> .sympath+ E:\MyCode\FromDumpFileToCode
DBGHELP: Symbol Search Path: cache*;SRV*http://msdl.microsoft.com/download/symbols;e:\mycode\fromdumpfiletocode

. . .

0:000> .load psscor2

0:000> .chain
Extension DLL search Path:

    C:\Program Files\Windows Kits\8.1\Debuggers\x86\WINXP;

Extension DLL chain:
    psscor2: image 2.0.0.1, API 1.0.0, built Wed Mar 24 21:24:57 2010
        [path: C:\Program Files\Windows Kits\8.1\Debuggers\x86\psscor2.dll]
    dbghelp: image 6.3.9600.17237, API 6.3.6, built Wed Jul 16 20:35:59 2014
        [path: C:\Program Files\Windows Kits\8.1\Debuggers\x86\dbghelp.dll]

. . .
   
0:000> .cordll -ve -u –l

Automatically loaded SOS Extension

CLRDLL: Loaded DLL C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscordacwks.dll
CLR DLL status: Loaded DLL C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscordacwks.dll


0:000> !Threads
ThreadCount:      2
UnstartedThread:  0
BackgroundThread: 1
PendingThread:    0
DeadThread:       0
Hosted Runtime:   no
                                                                         Lock 
       ID OSID ThreadOBJ    State GC Mode     GC Alloc Context  Domain   Count Apt Exception
   0    1 1098 002952c0     2a020 Cooperative 01CD271C:00000000 0028d4a8 0     MTA
   2    2 1a1c 002a2050     2b220 Preemptive  00000000:00000000 0028d4a8 0     MTA (Finalizer)



6.     Extract the code from the Dump:

We are using the PSSCOR2 '!SaveModule' command to save the code from the Dump file to new EXE file.

The !SaveModule command takes 2 parameters:

1.     Base Address
-        We could find the image base address using the 'LM' debugger command.
-        Alternately, we could use the module name, as it appears in the 'LM' command output.
2.     File Name (and path)


First, we'll list the loaded modules, and copy the module base address:

0:000> lm

start    end        module name

010c0000 010c8000   Demo1      (deferred)            
50ff0000 516a1000   clr        (pdb symbols)          C:\ProgramData\dbg\sym\clr.pdb\1C6AD585F62042AEB690C4C105CB9B962\clr.pdb
53000000 530f5000   MSVCR120_CLR0400   (deferred)            
6aef0000 6af69000   mscoreei   (deferred)            
6af70000 6afba000   mscoree    (deferred)             
6c420000 6c49e000   clrjit     (deferred)            
6dfe0000 6e01f000   snxhk      (deferred)            

. . .

76f30000 7706c000   ntdll      (pdb symbols)          C:\ProgramData\dbg\sym\ntdll.pdb\CD4062A231154A17A18DAE7D1A0FBACC2\ntdll.pdb
77090000 77159000   user32     (deferred)            
79240000 7a38a000   mscorlib_ni   (deferred)


Next, we'll run the !SaveModule command, with the Base address and a File Name to save the new generated EXE file:

0:000> !SaveModule Demo1.exe E:\MyCode\FromDumpFileToCode\Code\NewDemo1.exe

3 sections in file
section 0 - VA=2000, VASize=4d8, FileAddr=200, FileSize=600
section 1 - VA=4000, VASize=4ac, FileAddr=800, FileSize=600
section 2 - VA=6000, VASize=c, FileAddr=e00, FileSize=200


We could see from the command output that the operation was successful, and we could find the new generated executable (source code) in the desired folder:

E:\MyCode\FromDumpFileToCode\Code>dir /b

NewDemo1.exe



7.     Open the new EXE in a De-compiler:

In this example I used ILSpy and was able to review the C# code of the problem I encountered in the Dump file.
This could help resolving the issue.







Summary & Conclusions  

We learned & demonstrated how to extract the managed source code from a Dump file and saved it to a binary file, in cases we don't have the original code and we need to explore it.
We performed it using the PSSCOR2 debugger extension, using the !SaveModule command.





The End

Hope you enjoyed!
Appreciate your comments…

Yonatan Fedaeli


1 comment:

Anonymous said...

This is a great tutorial. I've been able to recover the source code of an application that I lost.
Thank you very much!!