How to extract C# source code from dump file?

Posted by sneha1234 on Tue, 08 Mar 2022 12:09:32 +0100

1: Background

I believe that many friends took down a dump file after encountering various wonderful problems in the application, worked hard for a long time, and finally found a suspicious method on the call stack of a thread, but windbg often displays the method code in the form of assembly. Unfortunately, today's assembly, How many code farmers like us can understand it? 😂😂😂

Then comes the sharp question, how to convert these assembly codes into C# source code. If not, it's better to convert them into IL code. At least I can try to understand them with my efforts...

In this article, I'll share how to extract the method source code in dump.

2: Extract source code from dump file

1. Case demonstration

For the convenience of demonstration, I use netcore 3.1 wrote a simple demo with the following code:

namespace ConsoleApp6
{
    class Program
    {
        static void Main(string[] args)
        {
            Run();
        }

        static void Run()
        {
            Console.WriteLine("hello world!");
            Console.ReadLine();
        }
    }
}

After running the program, use task manager, adplus and procdump to grab dump.

2. Use lm + savemodule command to extract

If your program is simple enough, you can directly use lm to obtain all modules in the program, and then use savemodule to export the modules as exe/dll physical files, as shown below:

  • Extract all modules using lm
0:000> lm
start             end                 module name
000002c2`264b0000 000002c2`264b8000   ConsoleApp6_2c2264b0000   (deferred)             
00007ff7`e4a50000 00007ff7`e4a7f000   ConsoleApp6   (deferred)             
00007ffa`a4b50000 00007ffa`a546d000   System_Private_CoreLib   (deferred)             
00007ffa`a5470000 00007ffa`a59df000   coreclr    (deferred)             
00007ffa`df070000 00007ffa`df1b2000   clrjit     (deferred)             
...

You can vaguely see that I have one called ConsoleApp6_2c2264b0000 module, which is the consoleapp6 I want to extract Exe, by the way, that annoying ConsoleApp6 (deferred) is a PE file. How do I know? Just give it a try 😁

  • Extract using savemodule

You can see from the first row of console eapp6 above_ The start ing address of 2c2264b0000 is 000002c2264b0000, and then export it to E:\dump with savemodule.

0:000> !savemodule 000002c2`264b0000 E:\dump\ConsoleApp6.exe
3 sections in file
section 0 - VA=2000, VASize=6c4, FileAddr=200, FileSize=800
section 1 - VA=4000, VASize=564, FileAddr=a00, FileSize=600
section 2 - VA=6000, VASize=c, FileAddr=1000, FileSize=200

Then you can see that there is an additional consoleapp6 in E:\dump exe 🐂, With this thing, it's much easier to see the source code. You can decompile it directly with ILSpy.

3. Use dumpdomain/module + savemodule to extract

In the actual development, your program may be very complex. You can't find the Module directly by using lm. The best way is to find the Module you want by following the diagram. Remember the relationship between AppDomain, assembly and Module mentioned in CLR Via C#? If you want to know more about it, I suggest you look through it. I'll briefly describe here. Assembly generally includes several Module + resource files. Assembly is a dll/exe file. After the program runs, the assembly is properly placed in AppDomain.

With the above idea, can you find the module through the process AppDomain - > assembly - > module? Next, let's see how to implement it.

  • use! dumpdomain find the program domain where ConsoleApp6 is located
0:000> !dumpdomain
--------------------------------------
System Domain:      00007ffaa59996f0
LowFrequencyHeap:   00007FFAA5999C58
HighFrequencyHeap:  00007FFAA5999CE8
StubHeap:           00007FFAA5999D78
Stage:              OPEN
Name:               None
--------------------------------------
Domain 1:           000002c224b6ca80
LowFrequencyHeap:   00007FFAA5999C58
HighFrequencyHeap:  00007FFAA5999CE8
StubHeap:           00007FFAA5999D78
Stage:              OPEN
Name:               clrhost
Assembly:           000002c224bf1c00 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\3.1.12\System.Private.CoreLib.dll]
ClassLoader:        000002C224B61820
  Module
  00007ffa45984020    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\3.1.12\System.Private.CoreLib.dll

Assembly:           000002c224bf1980 [E:\net5\ConsoleApp3\ConsoleApp6\bin\Debug\netcoreapp3.1\ConsoleApp6.dll]
ClassLoader:        000002C224BE3F80
  Module
  00007ffa45b5f7d0    E:\net5\ConsoleApp3\ConsoleApp6\bin\Debug\netcoreapp3.1\ConsoleApp6.dll

Embarrassed, remember good words, in NET Framework has three application domains by default.

  • System Domain
  • Shared Domain
  • Domain 1

How did you get there NET Core lost a Shard Domain 😄😄😄, Forget it first. From the figure, you can clearly see that there is my DLL e: \ net5 \ consoleapp3 \ consoleapp6 \ bin \ debug \ netcoreapp3 on Domian 1 1\ConsoleApp6. DLL and a module address 00007ffa45b5f7d0.

  • use! dumpmodule get module details
0:000> !DumpModule /d 00007ffa45b5f7d0
Name: E:\net5\ConsoleApp3\ConsoleApp6\bin\Debug\netcoreapp3.1\ConsoleApp6.dll
Attributes:              PEFile SupportsUpdateableMethods 
Assembly:                000002c224bf1980
BaseAddress:             000002C2264B0000
PEFile:                  000002C224BF2300
ModuleId:                00007FFA45B5FB98
ModuleIndex:             0000000000000001
LoaderHeap:              0000000000000000
TypeDefToMethodTableMap: 00007FFA45B3C8D0
TypeRefToMethodTableMap: 00007FFA45B3C8E8
MethodDefToDescMap:      00007FFA45B3C958
FieldDefToDescMap:       00007FFA45B3C978
MemberRefToDescMap:      0000000000000000
FileReferencesMap:       00007FFA45B3C988
AssemblyReferencesMap:   00007FFA45B3C990
MetaData start address:  000002C2264B2078 (1304 bytes)

From the BaseAddress: 000002C2264B0000 above, we can see that the start address of the module is 000002C2264B0000. Is it consistent with the address I just extracted with lm? Finally, export it with savemodule. For differentiation, I call it consoleapp7 Exe, as follows:

0:000> !savemodule 000002C2264B0000 E:\dump\ConsoleApp7.exe
3 sections in file
section 0 - VA=2000, VASize=6c4, FileAddr=200, FileSize=800
section 1 - VA=4000, VASize=564, FileAddr=a00, FileSize=600
section 2 - VA=6000, VASize=c, FileAddr=1000, FileSize=200

Ha ha, the rest is to decompile CosoleApp7 with ILSpy.