How to download Windows image files from the Microsoft symbol server using C# and DbgHelp

During my journeys through CorDebug I’ve often needed to access Windows operating system image files that I didn’t have on my local machine. This is actually a pretty normal situation to be in when debugging crash dumps. More often that not the crash dump you’ll be analyzing would have originated from a machine other than your own, like one of your servers. That server would most likely have been running operating system files with a version different to that running on your local machine. Your local machine might not even have the files at all. Naturally that makes analyzing the crash dump a challenge as all of the data contained in it references the files on the machine it was created on, not the machine it’s being analyzed on. This is especially true of “mscordacwks.dll”, which is vital when it comes to analyzing crash dumps of .Net processes (at least when using WinDBG and SOS).

I knew that it was possible to download symbol files from the Microsoft symbol server. That lead me to wonder whether it was possible to download operating system files as well. I asked in the MSDN forums and my suspicions were confirmed: you can indeed download image files from the symbol server. Finding out how to download them wasn’t so easy though.

I couldn’t find any mention of an API call that could be used to download image files, so I eventually just went through the Symbol Handling API (scroll down to the “Symbol Handler” heading) method by method until I found SymFindFileInPath. This looked pretty promising, since the parameters matched the information I had on hand. I tried it and it worked, one image file downloaded! What follows is a description of the C# code involved to get this working.

DbgHelp and the Symbol Handling API

First things first: the functions I’ll be using are all contained in the DbgHelp.dll library. This library contains various debugging functions, mostly importantly: symbol handling functions and minidump handling functions. For those interested you can read my write up on the minidump functions here. The library is included as part of the operating system, however that version is almost never going to be the most recent version, so you should always get the latest from the Debugging Tools For Windows page. See here for more details. In addition, for the Symbol handling functions you will also need “symsrv.dll”, which does not seem to ship with operating system, but is included with the Debugging Tools. Make sure you include both of these files in the same folder as the one your .exe is in.

For the basic functionality I’ll be using 3 functions:

To enable logging (which I highly recommend when you first start) I’ll use:

If you haven’t called native methods from C# in the past then I recommend you quickly read my previous post which will take you through the basics. Now lets move on to writing the C# versions of the functions that will be used.


SymInitialize initializes the symbol handler for a process. It’s important to note the “for a process” part. This call should only be invoked once during the lifetime of your process, unless you have called SymCleanup, in which case it can be called again.

It’s native declaration is:

BOOL WINAPI SymInitialize(
_In_ HANDLE hProcess,
_In_opt_ PCTSTR UserSearchPath,
_In_ BOOL fInvadeProcess

Converting that to C# we get:

[DllImport("dbghelp.dll", CharSet = CharSet.Unicode)]
public static extern bool SymInitialize(
IntPtr hProcess,
[MarshalAs(UnmanagedType.LPWStr)] string UserSearchPath,
bool fInvadeProcess);
  • hProcess. This is a handle to your process. You can use System.Diagnostics.Process.GetCurrentProcess() to get access to it.
  • UserSearchPath. This parameter tells the symbol handler where to look for symbols. It is a delimited list of folders or symbol servers that should be searched when attempting to find a requested symbol. If you pass null then either the current directory or environment variables will be used. I have the _NT_SYMBOL_PATH environment variable set to symsrv*symsrv.dll*c:\symbols*, so I pass null to make sure the environment variable is used.
  • fInvadeProcess. I’ll be setting this to false as I’m not interesting in looking up the symbols for my current process (I want the symbols of the crash dump I’m looking at instead).


Call this function once you are done using the symbol handler in order for it’s resources to be cleaned up.

Native declaration:

 _In_ HANDLE hProcess

C# declaration:

public static extern bool SymCleanup(IntPtr hProcess);
  • hProcess. This is the same process Id you passed in to SymInitialize.

Now that we can initialize and cleanup the symbol handler it’s time to put it to use.


As I mentioned I’m going to be using SymFindFileInPath to download Windows image files. This function can actually be used in one of two ways: to either download pdb files or image files. The values you pass in to the parameters will depend on which kind of files you intend retrieving. I’ll naturally be focusing on the values needed for image files.

Native declaration:

BOOL WINAPI SymFindFileInPath(
 _In_ HANDLE hProcess,
 _In_opt_ PCTSTR SearchPath,
 _In_ PCTSTR FileName,
 _In_opt_ PVOID id,
 _In_ DWORD two,
 _In_ DWORD three,
 _In_ DWORD flags,
 _Out_ PTSTR FilePath,
 _In_opt_ PVOID context

C# declaration:

 [DllImport("dbghelp.dll", CharSet=CharSet.Unicode)]
 public static extern bool SymFindFileInPath(
 IntPtr hProcess,
 [MarshalAs(UnmanagedType.LPWStr)] string SearchPath,
 [MarshalAs(UnmanagedType.LPWStr)] string FileName,
 IntPtr id,
 Int32 two,
 Int32 three,
 Int32 flags,
 [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder filePath,
 IntPtr callback,
 IntPtr context);
  • hProcess. This is the same process Id you passed in to SymInitialize.
  • SearchPath. I initialized the search path when I called SymInitialize, so I’ll be passing null here, indicating that the current search path should be used.
  • FileName. This is the name of the file you are looking for e.g. mscorwks.dll
  • id. For image files this is the TimeDateStamp of the original image as found in its PE header e.g. 0x4D8C16AC
  • two. For image files this is the SizeOfImage field, also extracted from the PE header.
  • three. For image files this is 0 (unused).
  • flags. This parameter indicates the type of data in the id parameter. I’ll be passing SSRVOPT_DWORD as the id parameter contains a DWORD.
  • filePath. This is the path of the returned file. A note on marshalling this parameter: I’ve flag the function with “CharSet=CharSet.Unicode”, this allows me to use the Unicode version of it, and thus I marshal the strings as wide strings using UnmanagedType.LPWStr.
  • callback. This is a user defined function that you can use to determine whether searching should stop or continue when a file is located. I pass null for this parameter as I have no need to use it.
  • context. You can use this parameter to pass custom data to the callback function. I haven’t used the callback function, so I pass null.

Here’s an example of what a call would look like:

 const int MAX_PATH = 260;
 int processId = System.Diagnostics.Process.GetCurrentProcess().Id;
 StringBuilder outPath = new StringBuilder(MAX_PATH);

 success = SymFindFileInPath((IntPtr)processId,
 (IntPtr) 1301026476, // 0x4D8C16AC
 5943296, // 0x005AB000

That’s all you need to be able to download image files from a symbol server. It took a bit of work to figure out and get it working but at the end it’s pretty simple.

One challenge getting this working is figuring out what’s gone wrong when it doesn’t work! I’ve lost quite a bit of time during my testing trying to figure out why it was returning false with a GetLastError() of ERROR_FILE_NOT_FOUND. In that case it was because I didn’t have symsrv.dll in the same folder as my test application.

I’ll write up a separate post on how to view the debugging/logging information included in the SymSrv functions, but as a sneak peak: you’ll need to use
SymSetOptions and SymRegisterCallbackProc64.

Posted in Crash Dumps | Tagged , , | Leave a comment

Minidump Explorer v0.4 released

I’ve released a new version of Minidump Explorer on CodePlex. You can find the download here.

Included in this release:

Posted in Crash Dumps | Tagged | Leave a comment

Minidump Explorer v0.3 released

I’ve released a new version of Minidump Explorer on CodePlex. You can find the download here.

Included in this release:

Write-ups on each stream will follow soon.

Posted in Crash Dumps | Tagged | Leave a comment

Minidump Explorer v0.2: Reading minidump ThreadListStream

Version 0.2 of Minidump Explorer included 4 new data streams: MemoryListStream, Memory64ListStream, HandleDataStream and ThreadListStream. These are all fairly simple streams to read and use but 3 of them are going to be vitally important when we start hooking into CorDebug: MemoryListStream, Memory64ListStream and ThreadListStream. I spoke about the 2 memory list streams last time. This time I’ll talk about the ThreadListStream.


First up lets have a look at the structures we’ll be using when reading MemoryListStream:

typedef struct _MINIDUMP_THREAD_LIST {
  ULONG32         NumberOfThreads;

typedef struct _MINIDUMP_THREAD {
  ULONG32                      ThreadId;
  ULONG32                      SuspendCount;
  ULONG32                      PriorityClass;
  ULONG32                      Priority;
  ULONG64                      Teb;

There’s no need to discuss MINIDUMP_THREAD_LIST as it’s quite self explanatory and we’ve seen it previously when reading the ModuleListStream and memory streams. Our interest is in the MINIDUMP_THREAD structure.

I haven’t really needed to use most of the fields provided by MINIDUMP_THREAD, so I won’t be going into too much detail about most of them for now. I will provide references to extra information just in case they’re of interest to you.

The first 4 fields provide fairly basic thread info: it’s id, how many times it has been suspended and it’s priority class and priority. The Id is self-explanatory. This one is obviously quite important. I haven’t needed to use the suspend count and priority fields yet. You can find more information about the suspend count by looking at the documentation for SuspendThread and ResumeThread. Simply put: it’s a count of how many times the thread has been suspended. If the count is greater than 0 then the thread has been suspended and will not run. Each call to SuspendThread and ResumeThread increases and decreases the count respectively. Once the count reaches 0 the thread is allowed to run again.

There’s a detailed write up on the priority fields here. The documentation is clear enough (mostly), but I looked at a sample crash dump and I couldn’t tie the priorty/priority class I saw back to the documentation.

The last 3 fields are where things start to get interesting.

Teb. This is the “thread environment block”. This contains very low level information about a thread and as you can see from the documentation it can change between different versions of Windows.

Stack. I mentioned in a previous post that the minidump API (or rather the DbgHelp API) only provides methods to read the raw data contained in a minidump. Well here’s a good example of that. The Stack field tells us where the data for the stack of the thread is located, and how big it is, but it doesn’t provide a way to decode the information contained there. If you want to make sense of the data you have to go through the stack frames one by one and piece the information together yourself. That’s quite a daunting task. This where the CorDebug API comes in: it’ll reconstruct the stack for us. It does still leave some work for us to do, but it’s a lot better that piecing it together ourselves. Suffice it to say that I haven’t found a reason to use this field yet.

Context. This field points to the location in the crash dump where the context information of the thread can be found. This is also very low level thread information e.g. the value of the cpu registers, etc. The explanation about the Stack field applies here also: you can access the raw context data, but decoding it is up to you. Luckily I haven’t needed to get into the details of the context structure; all CorDebug needs is the raw data, it’ll figure the rest out itself.

Show me the code

I won’t go through the all of the field types individually as they’re all types I have covered previously. The definitions for MINIDUMP_MEMORY_DESCRIPTOR and MINIDUMP_LOCATION_DESCRIPTOR were covered when I discussed reading the two memory streams.

[StructLayout(LayoutKind.Sequential, Pack = 4)]
internal struct MINIDUMP_THREAD_LIST
    public UInt32 NumberOfThreads;
    public IntPtr Threads; // MINIDUMP_THREAD[] 

[StructLayout(LayoutKind.Sequential, Pack = 4)]
internal struct MINIDUMP_THREAD
    public UInt32 ThreadId;
    public UInt32 SuspendCount;
    public UInt32 PriorityClass;
    public UInt32 Priority;
    public UInt64 Teb;

As far as reading the stream: you’ll follow the same steps as we did when reading the ModuleListStream. You can find the full source code on my CodePlex project (I’ve made a few small updates since the original article).

That’s it for the ThreadListStream. Other than the Id and Context fields there’s not much I’ll be using from this stream. Those 2 fields are vital though!

Next time: the HandleDataStream.

Posted in Crash Dumps | Tagged , , | Leave a comment

Minidump Explorer v0.2: Reading minidump MemoryListStream and Memory64ListStream

Version 0.2 of Minidump Explorer included 4 new data streams: MemoryListStream, Memory64ListStream, HandleDataStream and ThreadListStream. These are all fairly simple streams to read and use but 3 of them are going to be vitally important when we start hooking into CorDebug: MemoryListStream, Memory64ListStream and ThreadListStream. The 2 memory list streams will naturally give us access to some, or all, of the memory of the crashed process, while the thread list stream, amongst other things, give us access to the thread’s Context information. The handle data is interesting, but not essential at this point in time.

MemoryListStream and Memory64ListStream

MemoryListStream and Memory64ListStream provide you with a list of memory regions that are contained in the crash dump. The difference between the two is that Memory64ListStream is used for full-memory dumps, while MemoryListStream is used when only partial memory is available. You can see the difference when you look at the declaration of the structures they return:

MemoryListStream (C++)

  ULONG32 DataSize;
  RVA     Rva;

  ULONG64                      StartOfMemoryRange;

typedef struct _MINIDUMP_MEMORY_LIST {
  ULONG32                    NumberOfMemoryRanges;

If you look at MINIDUMP_MEMORY_LIST you’ll notice that it contains an array of MINIDUMP_MEMORY_DESCRIPTOR’s (MemoryRanges). Each MINIDUMP_MEMORY_DESCRIPTOR represents a region of memory included with the minidump. It contains the starting address of the region of memory represented (StartOfMemoryRange) and a MINIDUMP_LOCATION_DESCRIPTOR (Memory) indicating how big the region is and where in the minidump file to find it. What’s important to note here, is that each region of memory could be in a different physical location inside the minidump file. Because of this each MINIDUMP_LOCATION_DESCRIPTOR has an Rva field which you need to use to find the correct location in the minidump to read from. Full memory dumps are different: the memory is all stored in one sequential block at the end of the dump. As a result you don’t need individual RVA’s for each region. You can see the difference here:

Memory64ListStream (C++)

    ULONG64 StartOfMemoryRange;
    ULONG64 DataSize;

typedef struct _MINIDUMP_MEMORY64_LIST {
    ULONG64 NumberOfMemoryRanges;
    RVA64 BaseRva;

You’ll notice that MINIDUMP_MEMORY64_LIST also has an array of descriptors (MINIDUMP_MEMORY_DESCRIPTOR64). The difference here is that MINIDUMP_MEMORY_DESCRIPTOR64 doesn’t include a location descriptor as MINIDUMP_MEMORY_DESCRIPTOR did. This is as a result of all of the memory being in one block at the end of the minidump: you don’t need individual RVA’s for each block since they all follow each other starting from MINIDUMP_MEMORY64_LIST.BaseRva.

Reading memory data from a minidump

So how do you go about reading from a location in memory?

If you have a crash dump containing partial memory (MINIDUMP_MEMORY_LIST) you would loop through each MINIDUMP_MEMORY_DESCRIPTOR and check for a region containing the address you were looking for: (myReadAddress >= StartOfMemoryRange) && (myReadAddress < (StartOfMemoryRange + Memory.DataSize)). If you find a matching MINIDUMP_MEMORY_DESCRIPTOR you would then add it’s Memory.Rva field (from MINIDUMP_LOCATION_DESCRIPTOR) to the address of the minidump file mapping in order to get the physical location to read from.

Reading from MINIDUMP_MEMORY64_LIST is a bit different. You would still loop through each MINIDUMP_MEMORY_DESCRIPTOR64 looking for the region that holds the address you want to read from, but the difference is in how you read the data once you’ve found the correct region. Since a full-memory dump has all of the memory stored sequentially at the end of the dump file there is only one RVA and that RVA points to the beginning of the memory data inside the minidump. In order to read the actual memory you need to keep a running total of the DataSize of each MINIDUMP_MEMORY_DESCRIPTOR64 that precedes the one that you need and add that to the BaseRva. Then add that to the address of the memory mapped file of the crash dump. So the end result logic would look similar to this:

// addressOfBlockToReadFrom is the address in the minidump file of 
// the start of the block you want to read from.
long addressOfBlockToReadFrom = memoryMappedFileAddress + memory64List.BaseRva + allPreceedingDataSizes;

// offsetToReadFrom is the offset from the beginning of the 
// block that you want to read from.
// e.g. if you want to read from 0x23 and the block starts 
// at 0x20 then the offset is 0x3.
long offsetToReadFrom = addressIWantToReadFrom - blockToReadFrom.StartOfMemoryRange;

// addressToReadFrom is the physical address in the minidump file
// where you should start reading from.
long addressToReadFrom = addressOfBlockToReadFrom + offsetToReadFrom;

Show me the code

I won’t go through the all of the field types individually as they’re all types I have covered previously. The only new one is RVA64 which is a ULONG64 and translates to a UInt64 in c#.

MemoryListStream (C#)

[StructLayout(LayoutKind.Sequential, Pack = 4)]
    public UInt32 DataSize;
    public uint Rva;

[StructLayout(LayoutKind.Sequential, Pack = 4)]
    public UInt64 StartOfMemoryRange;

[StructLayout(LayoutKind.Sequential, Pack = 4)]
internal struct MINIDUMP_MEMORY_LIST
    public UInt32 NumberOfMemoryRanges;
    public IntPtr MemoryRanges; // MINIDUMP_MEMORY_DESCRIPTOR[]


[StructLayout(LayoutKind.Sequential, Pack = 4)]
    public UInt64 StartOfMemoryRange;
    public UInt64 DataSize;

[StructLayout(LayoutKind.Sequential, Pack = 4)]
internal struct MINIDUMP_MEMORY64_LIST
    public UInt64 NumberOfMemoryRanges;
    public UInt64 BaseRva;
    public IntPtr MemoryRanges; // MINIDUMP_MEMORY_DESCRIPTOR64[]

As far as reading the streams: you’ll follow the same steps as we did when reading the ModuleListStream. You can find the full source code on my CodePlex project (I’ve made a few small updates since the original article).

That’s it for the memory streams, next time I’ll cover the ThreadListStream.

Posted in Crash Dumps | Tagged , , , , | Leave a comment

Minidump Explorer v0.2 released

I’ve released a new version of Minidump Explorer on CodePlex. You can find the download here.

Included in this release:

Write-ups on each stream will follow soon :)

Posted in Crash Dumps | Tagged , , | Leave a comment

Reading minidump files, part 4 of 4: Putting it all together

All code is available on my CodePlex project.

This is the last in a 4 part series on how to use MiniDumpReadDumpStream to read data streams contained within minidump files. The first article discussed how to access memory mapped files from c#, the second how to call MiniDumpReadDumpStream and the third how to interpret the data returned (using ModuleListStream as an example). This post wraps everything up and introduces the Minidump Explorer Windows Form application. The posts that follow this one will discuss each data stream as I work towards creating an application (Minidump Explorer is just a stepping stone) that will let you analyze and visualize minidumps of processes that were running the CLR.

Analyzing the information contained in minidumps is still going to take some time; that requires using an entirely different API and a lot more work. For now we’ll just look at the raw data contained in a minidump file and create an application that can view that data. We’ll use that as a stepping stone to something bigger. Given that, let me introduce the Minidump Explorer Windows Form application! Remember those Firefox crash dumps I found lying around in my first post? Well here’s our first look at the contents of those files:

Display of a module list

Minidump Explorer displaying a module list stream.

You can see that I’m using the module stream information I spoke about in the previous article to display a list of modules that were loaded at the time of the crash. Some of this module information (e.g. the base address, timestamp, size & module name) is going to be vital to us in the future when we start trying to interpret the minidump i.e. trying to look at threads and calls stacks, or heaps and objects. That’s still a ways off, but I want to take a moment to explain the difference between looking at the raw minidump stream data and looking at what’s happening inside the application that crashed.

What is a minidump and how do we interpret them?

You’ll notice that I always mention analyzing minidumps of processes “running the CLR”. I’ve been very careful to deliberately word it that way. Minidumps are crash dumps of a process from an operating system point of view. By that I mean that from the operating system point of view, it was running a process; that process stopped working and a crash dump was created. The operating system doesn’t know what that process was, or what it was doing. It’s knows it had resources allocated to it, there were one or more threads and it had a list of instructions that it was executing. But it doesn’t know whether it was running a Python interpreter, a Java VM, the CLR or just a regular native application. From the operating system point of view everything is a native process. Think about it this way: the operating system is running the CLR, and the CLR is running your code.

When we look at a minidump we’re seeing what the operating system see’s i.e. the CLR. It has no knowledge of the data structures or workings of the CLR; it just does what it’s told to do.

For example: the operating system doesn’t know about CLR threads. It knows about threads that the CLR asks it to create, but it doesn’t know about threads created internally by the CLR. Did you know that CLR threads don’t necessarily match one-to-one with operating system threads? Just because you create a System.Threading.Thread object in your .Net code doesn’t mean the CLR will create a matching thread in the operating system. This is because the CLR sits on top of the operating system and manages itself and its own resources; just like the Java VM does.

What does this all mean? Well we don’t want to see what the operating was doing when the application crashed. If we looked from that point of view we’d see that the operating system was running the CLR. We want to know what was happening in our .Net code when it crashed, or rather what the CLR was doing. This means we need something that knows how the CLR works and can translate between what the operating system saw and what the CLR was doing, like this:

Operating system running CLR code

Operating system running CLR code

Hopefully that helps to illustrate where we’re heading towards. It’s a bit more technical than that, but it should help you understand.

Viewing module information

Back to Minidump Explorer! As I was saying: I’ve used the module stream to display the list of modules. You can also double click each module to get more detailed information:

General module properties

General module properties

Module fixed info

By the way: I’m not picking on Firefox! It just happens to be one of the few applications that will create a minidump when something does go wrong. I’m sure the problem was probably Flash related ;)

Creating minidumps

I’ve also included the ability to capture crash dumps. I discussed that here. It’s a simple wizard that lets you select a process, choose what information you want captured and create the crash dump. The process will be unaffected once the dump has been created.


I’ve created a project on codeplex and uploaded all of the code I’ve done so far, you’ll find it at Have a look around, download the application and give some comments/suggestions, feedback is very welcome.

Moving forward

Now that the basics are done we should be able to add the other data streams fairly quickly. Next up: thread, memory/memory 64 and handle streams.

Posted in Crash Dumps | Tagged , , | 3 Comments