As promised in the previous blog, I will share my understanding on the dotNet header and how to parse it.
dotNet CLI header is found in .text
section of the PE file. We only need to focused on this section to make things work ✌.
Thanks for the help of CFF Explorer
and dnSpy
to make this happen 🙌.
Calculate dotNet MetaData Directory Starting Offset
Basically this is the formula from RVA2OffSet.
- Check is VA of
.text
is larger or equal to VA ofdotNet MetaData Directory
- Check is sum of VA and SizeOfRawAddress of
.text
is larger than VA ofdotNet MetaData Directory
. - Calculate new offset by adding RawData offset of
.text
section to difference betweendotNet MetaData Directory
VA and.text
VA
Let’s move on to dotNet Directory!
Some short notes 📜 before moving on:
byte (size of 1)
word (size of 2)
dword (size of 4)
qword (size of 8)
dotNet Directory
It is quite easy to understand it as the structure is quite straight forward and the offset is exactly the real address.
Its information is ranged between 0x208 to 0x24F.
dotNet Directory Structure
cb dword
MajorRuntimeVersion word
MinorRuntimeVersion word
MetaData RVA dword
MetaData Size dword
Flags dword
EntryPointToken dword
Resources RVA dword
Resources Size dword
StrongNameSignature RVA dword
StringNameSignature Size dword
CodeManagerTable RVA dword
CodeManagerTable Size dword
VTableFixups RVA dword
VTableFixups Size dword
ExportAddressTableJumps RVA dword
ExportAddressTableJumps Size dword
ManagedNativeHeader RVA dword
ManagedNativeHeader Size dword
MetaData/Stream Directory
To calculate the starting offset of MetaData Directory, we need to get the difference between .text
RVA and VA (diff_va_rva
in the screenshot above). This value will then used to deduct the MetaData
RVA in the dotNet directory
to get the its real offset.
MetaData/Stream Directory Structure
The length of MetaData Header
ranged from the beginning of the Signature
until end of MetaData Streams
.
To get the Tables Count
, we need to perform AND
operation of the Mask Valid
value with list of constant value which can be found in dict_mask_table
in set_MaskValid()
.
Tables Count
indicates number of the table appear in the file. e.g. Module
count = 0x01 means it only appears for one time, same goes for other.
Example of Standard Resources file in Resources section
The way to calculate its starting offset is similar to MetaData Directory just deduct the Resource
RVA to diff_va_rva
.
For parsing the resource file in more detailed manner, the following link https://ntcore.com/files/manifestres.htm provided a write-up for that.
This can be found in set_ptr_resource_data_offset()
.
Standard Resources File Structure
Extraction of multiple files in single resource section is not support now. e.g.
However, sometime we did encountered some resource file which is just some random blob that did not comply with the structure of the dotNet resource. For example, a PE file.
Please correct me if there is any misinformation.
Hopefully it helps any dotNet malware researcher 😁!
Sample MD5:
98fd49a293efbf30152257f76b843672