Sunday, May 7, 2017

Reading Structured Binary files in C#: Part 14

In the last post, we read the DebugDirectory from the .text section of the file and found a pointer to a CodeView header.  Let's read it!  First, we need to find out what it is!  I have been relying on the .Net IL Assembler of late, and didn't think to look back in our old trusty MS PE COFF spec to see if it had a definition of the DebugDirectory, but it does!  Here is the spec from there:

Offset
Size
Field
Description
  0
4
Characteristics
Reserved, must be zero.
  4
4
TimeDateStamp
The time and date that the debug data was created.
  8
2
MajorVersion
The major version number of the debug data format.
10
2
MinorVersion
The minor version number of the debug data format.
12
4
Type
The format of debugging information. This field enables support of multiple debuggers. For more information, see section 6.1.2, “Debug Type.”
16
4
SizeOfData
The size of the debug data (not including the debug directory itself).
20
4
AddressOfRawData
The address of the debug data when loaded, relative to the image base.
24
4
PointerToRawData
The file pointer to the debug data.

and it even provides an updated list of Debug Type definitions that I have updated in the code:

Constant
Value
Description
IMAGE_DEBUG_TYPE_UNKNOWN
  0
An unknown value that is ignored by all tools.
IMAGE_DEBUG_TYPE_COFF
  1
The COFF debug information (line numbers, symbol table, and string table). This type of debug information is also pointed to by fields in the file headers.
IMAGE_DEBUG_TYPE_CODEVIEW
  2
The Visual C++ debug information.
IMAGE_DEBUG_TYPE_FPO
  3
The frame pointer omission (FPO) information. This information tells the debugger how to interpret nonstandard stack frames, which use the EBP register for a purpose other than as a frame pointer.
IMAGE_DEBUG_TYPE_MISC
  4
The location of DBG file.
IMAGE_DEBUG_TYPE_EXCEPTION
  5
A copy of .pdata section.
IMAGE_DEBUG_TYPE_FIXUP
  6
Reserved.
IMAGE_DEBUG_TYPE_OMAP_TO_SRC
  7
The mapping from an RVA in image to an RVA in source image.
IMAGE_DEBUG_TYPE_OMAP_FROM_SRC
  8
The mapping from an RVA in source image to an RVA in image.
IMAGE_DEBUG_TYPE_BORLAND
  9
Reserved for Borland.
IMAGE_DEBUG_TYPE_RESERVED10
10
Reserved.
IMAGE_DEBUG_TYPE_CLSID
11
Reserved.
IMAGE_DEBUG_TYPE_REPRO
16
PE determinism or reproducibility.

However, I struck out when looking for a definition of the CodeView header.  I was able to find some example code on DebugInfo which helped significantly.  From it I found that the structure looks something like:

// CodeView RSDS debug information 
// (used when debug information is stored in a PDB 7.00 file) 
struct CV_INFO_PDB70 
{
 DWORD      CvSignature; 
 GUID       Signature;       // unique identifier 
 DWORD      Age;             // an always-incrementing value 
 BYTE       PdbFileName[1];  // zero terminated string with the name of the PDB file 
};

When I dig in I run into a couple of issues.  First, Guid is a fine C# class, but it won't deserialize directly.  Easy enough, PInvoke.Net has a Guid definition that I can leverage.  The next issue is with the null terminated string.  I can't use the same type of deserialization with a variable length, but the SizeOfData in all of the instances with debug information was the same value (0x11C) so I might be able to fake it enough to get data back.  Let's see.  Here is the code I came up with:

Notice that the size of the array is 0x104?  Wait, let me change that to decimal and see if it helps, 0x104 = 260.  Now, is that a familiar number to any of you Windows users?  You got it, it is the maximum length for a path (MAX_PATH).  That means that my 'kludge' is going to be fine for Windows, mainly.  I can't wait (but will) to try longer paths in other systems and via the command prompt and...and...

Ok, that will do it for now.  Next time we will look at the Metadata section and see what it has in store for us.

Keep Coding!

No comments:

Post a Comment