How to Determine if a file is a .Net assembly (in Delphi and C#)

Given a file, we would like to check if it is a valid .Net assembly file.
How would you go about it?

1. A couple of words about the PE file format

.Net assemblies are valid PE files.   A PE file consists of:

      *     MS-DOS header  
      *     Stub Program
      *     PE file signature
      *     PE file header (This is where we position our stream)
      *     PE optional header
      *     Section headers   (This is where the RVA15 is)
      *     Section bodies

The PE file header is where we position our file stream at byte offset 60. The 32 bits at this position are the magical number whose value determine if this is a 32 bit (value = 0x010B) or 64 bit (value=0x020B) PE image.   This is important since there is a different offset to the data dictionary for these different types of images. 32 bit images have 0x60 offset to dictionary while 64bit images have a 32 bit offset to the data dictionary. The RVA dictionary is a sequence of 16 pairs of 32 bit. Each RVA entry is 8 bytes. Skipping to RVA15 means skipping 14*8 = 112 = 0x70

A PE file is   considered a .Net assembly   when RVA15 contains a non zero value. RVA 15 points to the CLI header.
For Further details about the CLI header:
Microsoft PE file format:

2. IsDotNetAssembly - Delphi version

function IsDotNetAssembly(FileName:  string):boolean;
fs: TFileStream;
peHeader: LongWord;
peMagicNumber: Word; //contains if it is 32bit or 64bit image
RVA15Value: LongWord;
DictionaryOffset: LongWord;

result := false;
fs := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone);

fs.Position := $3C; //PE Header start offset.

fs.Position := peHeader + $18;
fs.ReadBuffer(peMagicNumber, sizeOf(peMagicNumber));

case peMagicNumber of
$010B: DictionaryOffset := $60; //32 bit Image
$020B: DictionaryOffset := $70; //64 bit Image
raise Exception.Create('Invalid Image Format');

//Position to RVA 15 of the DataDictionary.
fs.Position := peHeader + $18 + DictionaryOffset + $70;

//Read the value.

//If this value is non zero this is a clr assembly
result := RVA15Value <> 0;


3. IsDotNetAssembly C# Implementation  

Just for the fun of it, here is the C# version.

private bool IsDotNetAssembly(string fileName)
        using (FileStream fs =
FileStream(fileName, FileMode.Open, FileAccess.Read))

                        using (BinaryReader binReader = new BinaryReader(fs))

            fs.Position = 0x3C; //PE Header start offset
      uint headerOffset = binReader.ReadUInt32();  

                                      fs.Position = headerOffset + 0x18;
                              UInt16 magicNumber = binReader.ReadUInt16();

                                      int dictionaryOffset;
              switch (magicNumber)
                                              case 0x010B: dictionaryOffset = 0x60; break;
                                      case 0x020B: dictionaryOffset = 0x70; break;
                              throw new Exception("Invalid Image Format");

                                      //position to RVA 15
                              fs.Position = headerOffset + 0x18 +

dictionaryOffset + 0x70;

                      //Read the value
      uint rva15value = binReader.ReadUInt32();
      return rva15value != 0;




Comments are closed