00000210 70 20 00 00 EC 02 00 00 01 00 00 00 01 00 00 06 p ··ì···········
We have the word MetaData which is made up of the half-word MetaData RVA and MetaData Size which are 0x00002070 and 0x000002EC respectively. So if we start with the VirtualAddress from Part 7 of 0x00002000 and then know that that is where the PointerToRawData of 0x00000200 will be loaded. So subtracting the VirtualAddress and adding the result to the PointertoRawData we get to 0x00000270 as the start of the Metadata. The Metadata section is going to be 0x2EC in size. The Metadata Storage signature is as follows:
Type
|
Field
|
Description
|
DWORD
|
lSignature
|
“Magic” signature for physical metadata, currently 0x424A5342.
|
WORD
|
iMajorVer
|
Major version (1)
|
WORD
|
iMinorVer
|
Minor version (1)
|
DWORD
|
iExtraData
|
Reserved; set to 0
|
DWORD
|
iVersionString
|
Length of the version string
|
BYTE[]
|
pVersion
|
Version string
|
(Note: the Word in the chart is 16bits or what I call a Half-Word. The Dword is 4 bytes, or what I call a Word)
Let't start with what we had in Part 11:
00000270 42 53 4A 42 01 00 01 00 00 00 00 00 0C 00 00 00 BSJB············
00000280 76 32 2E 30 2E 35 30 37 32 37 00 00 00 00 05 00 v2.0.50727······
We start with the lSignature or "Magic" signature string which stands for Brian Harry, Susan Radke-Sproull, Jason Zander, and Bill Evans. The iMajorVer is 0x0001 and the iMinorVer is 0x0001. the iExtraData is 0x00 and the iVersionString is 0x0000000C or 12. The pVersion is thus 12 bytes long or 0x76322E302E35303732370000 or v2.0.50727.After the Storage Signature we have the Storage Header which has the following structure:
Type
|
Field
|
Description
|
BYTE
|
fFlags
|
Reserved;
set to 0
|
BYTE
|
[padding]
| |
WORD
|
iStreams
|
Number
of streams
|
The fFlags is set to 0x00 there is a padding byte which is also set to 0x00 and finally the iStreams which is 0x0005. Moving on, we get to one of the 5 Managed Metadata Stream Headers which has the following format:
Type
|
Field
|
Description
|
DWORD
|
iOffset
|
Offset
in the file for this stream.
|
DWORD
|
iSize
|
Size
of the stream in bytes.
|
char[32
]
|
rcName
|
Name
of the stream; a zero-terminated ASCII string no longer than 31 characters
(plus zero terminator). The name might be shorter, in which case the size of
the stream header is correspondingly reduced, padded to the 4-byte boundary.
|
00000290 6C 00 00 00 04 01 00 00 23 7E 00 00 70 01 00 00 l·······#~··p···
000002A0 00 01 00 00 23 53 74 72 69 6E 67 73 00 00 00 00 ····#Strings····
000002B0 70 02 00 00 1C 00 00 00 23 55 53 00 8C 02 00 00 p·······#US·?···
000002C0 10 00 00 00 23 47 55 49 44 00 00 00 9C 02 00 00 ····#GUID···?···
000002D0 50 00 00 00 23 42 6C 6F 62 00 00 00 00 00 00 00 P···#Blob·······
000002E0 02 00 00 01 47 15 00 00 09 00 00 00 00 FA 01 33 ····G········ú·3
000002F0 00 16 00 00 01 00 00 00 06 00 00 00 02 00 00 00 ················
00000300 02 00 00 00 01 00 00 00 06 00 00 00 02 00 00 00 ················
00000310 01 00 00 00 01 00 00 00 00 00 0A 00 01 00 00 00 ················
00000320 00 00 06 00 44 00 3D 00 06 00 76 00 56 00 06 00 ····D·=···v·V···
00000330 96 00 56 00 06 00 CC 00 3D 00 06 00 DE 00 3D 00 ?·V···I·=···_·=·
We see that the iOffset is 0x0000006C and the iSize is 0x00000104. The rcName is a null terminated Ascii string padded to a 4 byte boundry so the value is #~ and there is one padding byte. From the book, this is a compressed metadata stream which contains metadata tables. It is 0x104 or 260 bytes in length. It will start 0x6C or 108 bytes in.
The next header has an iOffset of 0x0000170 or 368 bytes and an iSize of 0x00000100 or 256 bytes. The rcName is #Strings. Note that it finishes the line because the null terminator for the string crosses into the next 4 byte section.
The next header has an iOffset of 0x00000270 or 624 bytes and an iSize of 0x0000001C or 28 bytes. The rcName is #US.
The fourth header contains an iOffset of 0x0000028C or 652 bytes and an iSize of 0x00000010 or 16. The rcName is #GUID.
The last, or fifth header has an iOffset of 0x000029C or 668 bytes and an iSize of 0x00000050 or 80 bytes. The rcName is #Blob. Note that the rest of the 4 byte section is padded out.
Now we get to the #~ stream because we started the section at 0x270 and we have an offset of 0x6C which means it starts at 0x2DC. The Metadata Table comes in both the #~ (optimized) and #- (un-optomized) versions, but they share a common header:
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).
|
Let's dig into that starting next time. Until then, keep your code clean!