Buy Me a Coffee

Buy Me a Coffee!

Wednesday, July 19, 2017

Reading Structured Binary files in C#: Part 17

Here we go again.  The last bit we did was pulling out the metadata stream headers which spat out this list:

Starting Address: 0x290
iOffset: 0x6C
iSize: 0x104
rcName: #~

Starting Address: 0x29C
iOffset: 0x170
iSize: 0x100
rcName: #Strings

Starting Address: 0x2B0
iOffset: 0x270
iSize: 0x1C
rcName: #US

Starting Address: 0x2BC
iOffset: 0x28C
iSize: 0x10
rcName: #GUID

Starting Address: 0x2CC
iOffset: 0x29C
iSize: 0x50
rcName: #Blob

for the HelloWorld_CSC_2.0.exe file I tested it with.  The first stream on the list is named #~ which means it is going to be fun to deal with because it is a compressed metadata stream.  The .NET IL Assembler book has a nifty drawing showing all 5 of the streams above:


and looking at the far right, you can see that we have yet another header to dissect.  The structure of the header is:

Size
Field
Description
4 bytes
Reserved
Reserved; set to 0.
1 byte
Major
Major version of the table schema (1 for v1.0 and v1.1; 2 for v2.0 or later).
1 byte
Minor
Minor version of the table schema (0 for all versions).
1 byte
Heaps
Binary flags indicate the offset sizes to be used within the heaps
.•        4-byte unsigned integer offset is indicated by 0x01 for a string heap, 0x02 for a GUID heap, and 0x04 for a blob heap
.•        If a flag is not set, the respective heap offset is a 2-byte unsigned integer
.•        A #- stream can also have special flags set: flag 0x20, indicating that the stream contains only changes made during an edit-and-continue session, and flag 0x80, indicating that the metadata might contain items marked as deleted.
1 byte
Rid
Bit width of the maximal record index to all tables of the metadata; calculated at run time (during the metadata stream initialization).
8 bytes
MaskValid
Bit vector of present tables, each bit representing one table (1 if present).
8 bytes
Sorted
Bit vector of sorted tables, each bit representing a respective table (1 if sorted).


It is all nice and fixed, so it will be easy to get started so let's dig right into the metadata stream header for the metadata...what?  How about the metadata metadata stream header?  All this naming stuff is hard.

So, here is the code:
But there is a catch.  The bits in the MaskValid represent tables, and this is followed by a bunch of 4 byte unsigned integers for each '1' representing the number of records in the table.  I will work on that part next, this is good enough for now.

Keep compiling!