PEFileReader.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / AddIn / AddIn / System / Addin / MiniReflection / MetadataReader / PEFileReader.cs / 1305376 / PEFileReader.cs

                            using System; 
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.IO; 
using System.Diagnostics;
using System.Diagnostics.Contracts; 
 
namespace System.AddIn.MiniReflection.MetadataReader
{ 
    internal sealed class StreamDesc
    {
        private UInt32 offset;    // Offset from metadata root
        private UInt32 position;    // Absolute start in file 
        internal String Name;
 
        internal StreamDesc(BinaryReader B, UInt32 metadataRoot) 
        {
            this.offset = B.ReadUInt32(); 
            this.position = offset + metadataRoot;
            /*Size =*/ B.ReadUInt32();
            int i = 1;
            StringBuilder sb = new StringBuilder(); 
            char c;
            while ((c = (char)B.ReadByte()) != 0) 
            { 
                sb.Append(c);
                i += 1; 
            }
            while ((i++ & 0x3) != 0)
            {
                B.ReadByte(); 
            }
            this.Name = sb.ToString(); 
            // Console.WriteLine("Stream {0}", this.Name); 
        }
 
        internal void SeekTo(BinaryReader B, UInt32 Nth)
        {
            B.BaseStream.Seek(position + Nth, SeekOrigin.Begin);
        } 
    }
 
    internal sealed class PEFileReader : IDisposable 
    {
        private static readonly UTF8Encoding Encoder = new UTF8Encoding(false, true); 

        internal BinaryReader B;
        private SectionDesc[] Sections;
        private UInt32 MetadataRoot; // Absolute start of metadata in file 
        private StreamDesc[] Streams;
 
        private UInt32 MetaDataDDRVA; 
        private MDTables metaData;
 
        private bool parsedMetaData;
        private string _fileName;

        public PEFileReader(String fileName) 
        {
            _fileName = fileName; 
            FileStream TheFile = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.RandomAccess); 
            B = new BinaryReader(TheFile);
            B.BaseStream.Seek(0x3C, SeekOrigin.Begin);     // Pointer to signature 
            UInt32 signatureAt = B.ReadUInt32();
            B.BaseStream.Seek(signatureAt, SeekOrigin.Begin);
            if ((B.ReadByte() != (byte)'P') || (B.ReadByte() != (byte)'E') ||
                (B.ReadByte() != 0) || (B.ReadByte() != 0)) 
                throw new BadImageFormatException(String.Format(CultureInfo.CurrentCulture, Res.BadPEFile, fileName));
 
            // Read the magic number to determine whether this is a PE32 or a PE32+ file 
            UInt32 MagicAt = signatureAt + 24;
            B.BaseStream.Seek(MagicAt, SeekOrigin.Begin); 
            UInt16 magic = B.ReadUInt16();

            UInt16 dataDirectoriesOffset = 0;
            if (magic == 0x10B) { 
                dataDirectoriesOffset = 96;  // PE32
            } 
            else if (magic == 0x20B) { 
                dataDirectoriesOffset = 112;  // PE32+ (applies to /platform:x64)
            } 
            else
                throw new BadImageFormatException(String.Format(CultureInfo.CurrentCulture, Res.BadPEFile, fileName));

            UInt32 PEFileHeaderAt = signatureAt + 4; 
            UInt32 NSectionsAt = PEFileHeaderAt + 2;
            UInt32 PEOptionalHeaderAt = PEFileHeaderAt + 20; 
            UInt32 CLIHeaderDDAt = PEOptionalHeaderAt + dataDirectoriesOffset + 112; 
            B.BaseStream.Seek(CLIHeaderDDAt, SeekOrigin.Begin);
            UInt32 CLIHeaderRVA = B.ReadUInt32(); 
            MetaDataDDRVA = CLIHeaderRVA + 8;
            UInt32 sectionHeadersAt = PEOptionalHeaderAt + dataDirectoriesOffset + 128;
            B.BaseStream.Seek(NSectionsAt, SeekOrigin.Begin);
            UInt16 NSections = B.ReadUInt16(); 
            B.BaseStream.Seek(sectionHeadersAt, SeekOrigin.Begin);
            Sections = new SectionDesc[NSections]; 
            for (UInt16 i = 0; i < NSections; i++) 
            {
                B.BaseStream.Seek(sectionHeadersAt + i * 40, SeekOrigin.Begin); 
                Sections[i].Read(B);
            }
        }
 
        public void Dispose()
        { 
            if (B != null) { 
                B.Close();
                B = null; 
            }
        }

        private struct SectionDesc 
        {
            private String Name; 
            UInt32 VirtualAddress; 
            UInt32 Size;
            UInt32 FileOffset; 

            internal UInt32 RVAToFileAddress(UInt32 RVA)
            { // returns 0 if not in this section
                if ((RVA < VirtualAddress) || (RVA >= VirtualAddress + Size)) return 0; 
                return (RVA - VirtualAddress) + FileOffset;
            } 
 
            private static String ReadString(BinaryReader B, UInt32 NChars)
            { 
                StringBuilder sb = new StringBuilder((Int32)NChars);
                for (int i = 1; i <= NChars; i++)
                {
                    byte Next = B.ReadByte(); 
                    sb.Append(Next == 0 ? ' ' : (char)Next);
                } 
                return sb.ToString(); 
            }
 
            internal void Read(BinaryReader B)
            {
                this.Name = ReadString(B, 8);
                // Console.WriteLine("Section {0}", Name); 
                this.Size = B.ReadUInt32();
                this.VirtualAddress = B.ReadUInt32(); 
                B.ReadUInt32(); // SizeOfRawData 
                this.FileOffset = B.ReadUInt32();
            } 
        }

        internal MDTables MetaData {
            get { 
                if (!parsedMetaData)
                    InitMetaData(); 
                return metaData; 
            }
        } 

        private bool FindStream(String name, out StreamDesc result)
        {
            foreach (StreamDesc s in Streams) { 
                if (s.Name.Equals(name)) {
                    result = s; 
                    return true; 
                }
            } 
            result = null;
            return false;
        }
 
        private String ReadUTF8String(UInt32 NChars)
        { 
            return Encoder.GetString(B.ReadBytes((Int32) NChars)); 
        }
 
        private UInt32 RVAToFileAddress(UInt32 RVA)
        {
            foreach (SectionDesc s in Sections)
            { 
                UInt32 FileOffset = s.RVAToFileAddress(RVA);
                if (FileOffset != 0) return FileOffset; 
            } 
            throw new BadImageFormatException(String.Format(CultureInfo.CurrentCulture, Res.BadRVA, _fileName));
        } 

        private void SeekToRVA(UInt32 RVA)
        {
            B.BaseStream.Seek(RVAToFileAddress(RVA), SeekOrigin.Begin); 
        }
 
        /* 
        private static UInt32 PadTo4(UInt32 RVA)
        { 
            UInt32 Cleared = RVA & ~0x3U;
            return (RVA == Cleared) ? RVA : RVA + 0x4U;
        }
        */ 

        internal void InitMetaData() 
        { 
            if (B == null)
                throw new ObjectDisposedException(null); 
            if (parsedMetaData)
                return;

            SeekToRVA(MetaDataDDRVA); 
            UInt32 MetaDataRVA = B.ReadUInt32();
            UInt32 MetaDataSize = B.ReadUInt32(); 
            if ((MetaDataRVA == 0) || (MetaDataSize == 0)) 
                throw new BadImageFormatException();
            MetadataRoot = RVAToFileAddress(MetaDataRVA); 

            UInt32 VersionLengthRVA = MetaDataRVA + 12;
            UInt32 VersionStringRVA = VersionLengthRVA + 4;
            SeekToRVA(VersionLengthRVA); 
            UInt32 VersionLength = B.ReadUInt32();
            String Version = ReadUTF8String(VersionLength); 
            UInt32 FlagsRVA = VersionStringRVA + VersionLength; 
            UInt32 NStreamsRVA = FlagsRVA + 2;
            SeekToRVA(NStreamsRVA); 
            UInt16 NStreams = B.ReadUInt16();

            Streams = new StreamDesc[NStreams];
            for (int i = 0; i < NStreams; i++) Streams[i] = new StreamDesc(B, MetadataRoot); 
            StreamDesc stringStream, blobStream, TablesStream;
            if (!FindStream("#~", out TablesStream)) 
                if (!FindStream("#-", out TablesStream)) 
                    throw new BadImageFormatException();
            if (!FindStream("#Strings", out stringStream)) 
                throw new BadImageFormatException();
            if (!FindStream("#Blob", out blobStream))
                throw new BadImageFormatException();
            TablesStream.SeekTo(B, 0); 
            metaData = new MDTables(B, stringStream, blobStream);
            // metaData.DumpStringHeap(); 
            parsedMetaData = true; 
        }
 
        private static String HexChar(int x)
        {
            switch (x)
            { 
                case 0: return "0";
                case 1: return "1"; 
                case 2: return "2"; 
                case 3: return "3";
                case 4: return "4"; 
                case 5: return "5";
                case 6: return "6";
                case 7: return "7";
                case 8: return "8"; 
                case 9: return "9";
                case 10: return "a"; 
                case 11: return "b"; 
                case 12: return "c";
                case 13: return "d"; 
                case 14: return "e";
                case 15: return "f";
                default: throw new ArgumentOutOfRangeException("x");
            } 
        }
 
        internal static String ByteToHexString(byte b) 
        {
            String result = HexChar((b & 0xF0) >> 4) + HexChar(b & 0xF); 
            return result;
        }

        internal static String BytesToHexString(byte[] bytes) 
        {
            if (bytes == null) return null; 
            StringBuilder sb = new StringBuilder(2 * bytes.Length); 
            for (int i = 0; i < bytes.Length; i++)
                sb.Append(ByteToHexString(bytes[i])); 
            return sb.ToString();
        }

        public bool GetAssemblyInfo(ref AssemblyInfo result) 
        {
            InitMetaData(); 
            // Bunches of test code below here; may be out of date! 
            /*
            UInt32 Flags; 
            String Name;
            MDTables.MetadataToken Parent;

 
            MetaData.SeekToRowOfTable(MDTables.Tables.XModule, 0);
            UInt16 Generation = B.ReadUInt16(); 
             Name = MetaData.ReadString(); 
            UInt32 MvidIndex = MetaData.ReadGUIDIndex();
            UInt32 EncIdIndex = MetaData.ReadGUIDIndex(); 
            UInt32 EncBaseIdIndex = MetaData.ReadGUIDIndex();

            MetaData.DumpStringHeap(Console.Out);
 
            for (UInt32 i = 0; i < MetaData.RowsInTable(MDTables.Tables.TypeRef); i++)
            { 
                MetaData.SeekToRowOfTable(MDTables.Tables.TypeRef, i); 
                MDTables.MetadataToken Scope = MetaData.ReadMetadataToken(MDTables.Encodings.ResolutionScope);
                Name = MetaData.ReadString(); 
                String NameSpace = MetaData.ReadString();
                Console.WriteLine("Type ref {0} to {1}, {2} in scope {3}", i, NameSpace, Name, Scope);
            }
 
            UInt32 NRows = MetaData.RowsInTable(MDTables.Tables.MethodDef);
            for (UInt32 i = 0; i < NRows; i++) 
            { 
                MetaData.SeekToRowOfTable(MDTables.Tables.MethodDef, i);
                UInt32 RVA = B.ReadUInt32(); 
                UInt16 ImplFlags = B.ReadUInt16();
                Flags = B.ReadUInt16();
                Name = MetaData.ReadString();
                UInt32 SigIndex = MetaData.ReadBlobIndex(); 
                UInt32 ParamIndex = MetaData.ReadRowIndex(MDTables.Tables.ParamDef);
                Console.WriteLine("Method {0}: {1}", i, Name); 
            } 

            for (UInt32 i = 0; i < MetaData.RowsInTable(MDTables.Tables.ParamDef); i++) 
            {
                MetaData.SeekToRowOfTable(MDTables.Tables.ParamDef, i);
                Flags = B.ReadUInt16();
                UInt16 Sequence = B.ReadUInt16(); 
                Name = MetaData.ReadString();
                Console.WriteLine("Param {0} named {1}", i, Name); 
            } 

            MetaData.SeekToRowOfTable(MDTables.Tables.InterfaceImpl, 0U); 
            UInt32 Class = MetaData.ReadRowIndex(MDTables.Tables.TypeDef);
            MDTables.MetadataToken Iface = MetaData.ReadMetadataToken(MDTables.Encodings.TypeDefOrRef);

            MetaData.SeekToRowOfTable(MDTables.Tables.MemberRef, 3); 
            MDTables.MetadataToken MemberRefClass = MetaData.ReadMetadataToken(MDTables.Encodings.MemberRefParent);
            Name = MetaData.ReadString(); 
            UInt32 Signature = MetaData.ReadBlobIndex(); 

            MetaData.SeekToRowOfTable(MDTables.Tables.FieldMarshal, 0x10U); 
            Parent = MetaData.ReadMetadataToken(MDTables.Encodings.HasFieldMarshall);
            UInt32 NativeType = MetaData.ReadBlobIndex();

            MetaData.SeekToRowOfTable(MDTables.Tables.FieldMarshal, 3U); 
            Parent = MetaData.ReadMetadataToken(MDTables.Encodings.HasFieldMarshall);
            NativeType = MetaData.ReadBlobIndex(); 
 
            MetaData.SeekToRowOfTable(MDTables.Tables.XEvent, 0U);
            Flags = B.ReadUInt16(); 
            Name = MetaData.ReadString();
            MDTables.MetadataToken EventType = MetaData.ReadMetadataToken(MDTables.Encodings.TypeDefOrRef);
            */
 

            MetaData.SeekToRowOfTable(MDTables.Tables.XAssembly, 0U); 
 
            UInt32 HashAlgorithm = B.ReadUInt32();
            UInt16 Major  = B.ReadUInt16(); 
            UInt16 Minor = B.ReadUInt16();
            UInt16 Build = B.ReadUInt16();
            UInt16 Revision = B.ReadUInt16();
            Version V = new Version(Major, Minor, Build, Revision); 
            UInt32 AssemblyFlags = B.ReadUInt32();
            byte[] PublicKey = MetaData.ReadBlob(); 
            String SimpleName = MetaData.ReadString(); 
            String Culture = MetaData.ReadString();
            if ((Culture != null) && (Culture.Length == 0)) Culture = null; 
            result = new AssemblyInfo(V, AssemblyFlags, PublicKey, SimpleName, Culture);
            return true;
        }
 
        /*
        public AssemblyInfo[] GetReferencedAssemblies() 
        { 
            InitMetaData();
 
            UInt32 NRefs = MetaData.RowsInTable(MDTables.Tables.AssemblyRef);
            AssemblyInfo[] result = new AssemblyInfo[NRefs];
            for (UInt32 i = 0; i < NRefs; i++)
            { 
                MetaData.SeekToRowOfTable(MDTables.Tables.AssemblyRef, i);
                UInt16 Major = B.ReadUInt16(); 
                UInt16 Minor = B.ReadUInt16(); 
                UInt16 Build = B.ReadUInt16();
                UInt16 Revision = B.ReadUInt16(); 
                Version V = new Version(Major, Minor, Build, Revision);
                UInt32 Flags = B.ReadUInt32();
                byte[] PublicKey = MetaData.ReadBlob();
                String Name = MetaData.ReadString(); 
                String Culture = MetaData.ReadString();
                if ((Culture != null) && (Culture.Length == 0)) Culture = null; 
                // Ignore HashValue, index into Blob heap, which follows 
                result[i] = new AssemblyInfo(V, Flags, PublicKey, Name, Culture);
            } 
            return result;
        }
        */
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK