Buy Me a Coffee

Buy Me a Coffee!

Saturday, January 21, 2017

Dissecting C# Executables: Part 13


In the last post we identified the next section as the Metadata Table Header which has the following structure:


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).

 

Here is the data:

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·=···_·=·

00000340   06 00 EA 00 3D 00 00 00  00 00 01 00 00 00 00 00   ··ê·=···········

00000350   01 00 01 00 00 00 10 00  21 00 29 00 05 00 01 00   ········!·)·····

00000360   01 00 50 20 00 00 00 00  91 00 4B 00 0A 00 01 00   ··P ····?·K·····

00000370   66 20 00 00 00 00 86 18  50 00 10 00 02 00 00 00   f ····?·P·······

00000380   01 00 C7 00 11 00 50 00  14 00 19 00 50 00 10 00   ··Ç···P·····P···

00000390   21 00 D4 00 19 00 29 00  F2 00 1E 00 21 00 D4 00   !·O···)·ò···!·O·

000003A0   23 00 09 00 50 00 10 00  2E 00 0B 00 28 00 2E 00   #···P···.···(·.·

000003B0   13 00 31 00 04 80 00 00  00 00 00 00 00 00 00 00   ··1··?··········

000003C0   00 00 00 00 00 00 B4 00  00 00 02 00 00 00 00 00   ······'·········

000003D0   00 00 00 00 00 00 01 00  34 00 00 00 00 00 00 00   ········4·······

 

We start with 4 reserved bytes, followed by the 1 byte Major and 1 byte Minor version of the table Schema which are 0x02 and 0x00 respectively.  That means that the data in the stream is stored in the v2.0 schema.  Next is the Heaps which contains a flag field for the offset size stored in the heap which contains 0x00 indicating that we are using a 2 byte unsigned integer to store the heap offset.  Here is a table showing the options:


Binary Flag Value
Meaning
0x00
2 byte offset values
0x01
4 byte offset values for a string heap
0x02
4 byte offset values for a GUID heap
0x04
4 byte offset values for a blob heap
0x20
The stream contains only changes from an edit and continue session
0x80
The stream might contain data that is marked as deleted

 

The next value is the RID containing 0x01 which is the bit width of the maximal record index in all of the tables.  Next we have the MaskValid which is 8 bytes containing the value 0x0000000900001547 which is a bit vector indicating which tables are contained within the stream.  The  Sorted bit vector is also 8 bytes and contains 0x000016003301FA00 and indicates if the table is sorted.

The MaskValid bit vector pattern is:

00000000 00000000 00000000 00001001 00000000 00000000 00010101 01000111

And the Sorted bit vector pattern is:

00000000 00000000 00010110 00000000 00110011 00000001 11111010 00000000
Which seems strange to me since it is telling me that there are tables that are not there but are sorted.  Anyway, the list of table types is a bit long, so here is the MetadataTable Type List.  What the MaskValid bit vector pattern tells us is that the tables stored are 0, 1, 2, 6, 8, 10, 12, 32, 35 or Module, TypeRef, TypeDef, Method, Param, MemberRef, CustomAttribute, Assembly, and AssemblyRef.
What the Sorted bit vector tells us that the sorted tables are 9, 11, 12, 13, 14, 15, 16, 24, 25, 28, 29, 41, 42, and 44 or InterfaceImpl, Constant, CustomAttribute, FieldMarshal, DeclSecurity, ClassLayout, FieldLayout, MethodSemantics, MethodImpl, ImplMap, FieldRVA, NestedClass, GenericParam, and GenericParamConstraint.

The next part is a series of 4 byte unsigned integers which indicate the number of records in each of the tables indicated by the MaskValid bit vector.  There are 9 1s so there are 9 values:
0x0001, 0x0006, 0x0002, 0x0002, 0x0001, 0x0006, 0x0002, 0x0001, 0x0001
They tell us that the Module table has 1 entry, the TypeRef table has 6 entries, the TypeDef table has 2 entries, the Method table has 2 entries, the Param table has 1 entry, the MemberRef table has 6 entries, the CustomAttribute table has 2 entries, the Assembly table has 1 entry, and the AssemblyRef table has 1 entry.
That is it for tonight, we will pick back up and decode the tables tomorrow.  Keep your code clean!