/* * PERWAPI - An API for Reading and Writing PE Files * * Copyright (c) Diane Corney, Queensland University of Technology, 2004. * * This program is free software; you can redistribute it and/or modify * it under the terms of the PERWAPI Copyright as included with this * distribution in the file PERWAPIcopyright.rtf. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY as is explained in the copyright notice. * * The author may be contacted at d.corney@qut.edu.au * * Version Date: 26/01/07 */ using System; using System.IO; using System.Collections; namespace QUT.PERWAPI { /**************************************************************************/ // Class to Read PE Files /**************************************************************************/ internal class PEReader : BinaryReader { private bool x64; internal static long blobStreamStartOffset = 0; private static readonly int cliIx = 14; private Section[] inputSections; int numSections = 0; uint[] DataDirectoryRVA = new uint[16]; uint[] DataDirectorySize = new uint[16]; uint[] streamOffsets, streamSizes; String[] streamNames; private TableRow[][] tables = new TableRow[MetaData.NumMetaDataTables][]; uint[] tableLengths = new uint[MetaData.NumMetaDataTables]; MetaData md = new MetaData(); MetaDataStringStream userstring; MetaDataInStream blob, strings, guid; Sentinel sentinel = new Sentinel(); Pinned pinned = new Pinned(); //CorFlags corFlags; uint metaDataRVA = 0, metaDataSize = 0, flags = 0; uint entryPoint = 0, resourcesRVA = 0, resourcesSize = 0; uint strongNameRVA = 0, strongNameSize = 0, vFixupsRVA = 0, vFixupsSize = 0; //ushort dllFlags = 0, subSystem = 0; //uint fileAlign = 0; //char[] verString; bool refsOnly = false; long[] tableStarts; ResolutionScope thisScope; PEFileVersionInfo verInfo = new PEFileVersionInfo(); internal Method currentMethodScope; internal Class currentClassScope; int genInstNestLevel = 0; internal bool skipBody = true; private PEReader(PEFile pefile, System.IO.FileStream file, bool refs, bool skipBody) : base(new MemoryStream(new BinaryReader(file).ReadBytes(System.Convert.ToInt32(file.Length)))) { this.skipBody = skipBody; thisScope = pefile; refsOnly = refs; verInfo.fromExisting = true; try { ReadDOSHeader(); } catch (PEFileException) { Console.WriteLine("Bad DOS header"); return; } ReadFileHeader(); ReadSectionHeaders(); ReadCLIHeader(); ReadMetaData(); if (refsOnly) this.ReadMetaDataTableRefs(); else { this.ReadMetaDataTables(); pefile.metaDataTables = new MetaDataTables(tables); this.SaveUnmanagedResources(); } file.Close(); if (thisScope != null) { thisScope.buffer = this; if (pefile != null) { pefile.versionInfo = verInfo; } } strings = null; userstring = null; blob = null; guid = null; } private static System.IO.FileStream GetFile(string filename) { if (Diag.DiagOn) { Console.WriteLine("Current directory is " + System.Environment.CurrentDirectory); Console.WriteLine("Looking for file " + filename); } if (System.IO.File.Exists(filename)) { return System.IO.File.OpenRead(filename); } else throw (new System.IO.FileNotFoundException("File Not Found", filename)); } public static PEFile ReadPEFile(string filename, bool skipBody) { System.IO.FileStream file = GetFile(filename); PEFile pefile = new PEFile(filename); PEReader reader = new PEReader(pefile, file, false, skipBody); return pefile; } internal static ReferenceScope GetExportedInterface(string filename) { System.IO.FileStream file = GetFile(filename); PEReader reader = new PEReader(null, file, true, true); return (ReferenceScope)reader.thisScope; } //internal ResolutionScope GetThisScope() { return thisScope; } internal string[] GetAssemblyRefNames() { string[] assemNames = new string[tableLengths[(int)MDTable.AssemblyRef]]; for (int i = 0; i < assemNames.Length; i++) { assemNames[i] = ((AssemblyRef)tables[(int)MDTable.AssemblyRef][i]).Name(); } return assemNames; } internal AssemblyRef[] GetAssemblyRefs() { AssemblyRef[] assemRefs = new AssemblyRef[tableLengths[(int)MDTable.AssemblyRef]]; for (int i = 0; i < assemRefs.Length; i++) { assemRefs[i] = (AssemblyRef)tables[(int)MDTable.AssemblyRef][i]; } return assemRefs; } /*----------------------------- Reading ----------------------------------------*/ internal void InputError() { throw new PEFileException("Error in input"); } internal void MetaDataError(string msg) { msg = "ERROR IN METADATA: " + msg; if (thisScope != null) msg = "MODULE " + thisScope.Name() + ": " + msg; throw new PEFileException(msg); } internal Section GetSection(uint rva) { for (int i = 0; i < inputSections.Length; i++) { if (inputSections[i].ContainsRVA(rva)) return inputSections[i]; } return null; } internal uint GetOffset(uint rva) { for (int i = 0; i < inputSections.Length; i++) { if (inputSections[i].ContainsRVA(rva)) return inputSections[i].GetOffset(rva); } return 0; } internal void ReadZeros(int num) { for (int i = 0; i < num; i++) { byte next = ReadByte(); if (next != 0) InputError(); } } private void ReadDOSHeader() { for (int i = 0; i < FileImage.PESigOffset; i++) { if (FileImage.DOSHeader[i] != ReadByte()) { InputError(); } } uint sigOffset = ReadUInt32(); for (int i = FileImage.PESigOffset + 4; i < FileImage.DOSHeader.Length - 4; i++) { if (FileImage.DOSHeader[i] != ReadByte()) { InputError(); } } BaseStream.Seek(sigOffset, SeekOrigin.Begin); if ((char)ReadByte() != 'P') InputError(); if ((char)ReadByte() != 'E') InputError(); if (ReadByte() != 0) InputError(); if (ReadByte() != 0) InputError(); } private void ReadFileHeader() { // already read PE signature ushort machineid = ReadUInt16(); if (machineid != FileImage.machine && machineid != FileImage.machinex64) InputError(); numSections = ReadUInt16(); uint TimeStamp = ReadUInt32(); ReadZeros(8); /* Pointer to Symbol Table, Number of Symbols */ int optHeadSize = ReadUInt16(); verInfo.characteristics = ReadUInt16(); verInfo.isDLL = (verInfo.characteristics & FileImage.dllFlag) != 0; /* Now read PE Optional Header */ /* Standard Fields */ ushort magic = ReadUInt16(); if (magic != FileImage.magic && magic != FileImage.magic64) InputError(); x64 = magic == FileImage.magic64; verInfo.lMajor = ReadByte(); // != FileImage.lMajor) InputError(); verInfo.lMinor = ReadByte(); // != FileImage.lMinor) InputError(); uint codeSize = ReadUInt32(); if (Diag.DiagOn) Console.WriteLine("codeSize = " + Hex.Int(codeSize)); uint initDataSize = ReadUInt32(); if (Diag.DiagOn) Console.WriteLine("initDataSize = " + Hex.Int(initDataSize)); uint uninitDataSize = ReadUInt32(); if (Diag.DiagOn) Console.WriteLine("uninitDataSize = " + Hex.Int(uninitDataSize)); uint entryPointRVA = ReadUInt32(); if (Diag.DiagOn) Console.WriteLine("entryPointRVA = " + Hex.Int(entryPointRVA)); uint baseOfCode = ReadUInt32(); if (Diag.DiagOn) Console.WriteLine("baseOfCode = " + Hex.Int(baseOfCode)); //uint baseOfData = ReadUInt32(); if (!x64) { uint baseOfData = ReadUInt32(); if (Diag.DiagOn) Console.WriteLine("baseOfData = " + Hex.Int(baseOfData)); } /* NT-Specific Fields */ ulong imageBase = x64 ? ReadUInt64() : ReadUInt32(); if (Diag.DiagOn) Console.WriteLine("imageBase = " + Hex.Long(imageBase)); uint sectionAlign = ReadUInt32(); if (Diag.DiagOn) Console.WriteLine("sectionAlign = " + Hex.Int(sectionAlign)); verInfo.fileAlign = ReadUInt32(); if (Diag.DiagOn) Console.WriteLine("fileAlign = " + Hex.Int(verInfo.fileAlign)); verInfo.osMajor = ReadUInt16(); if (Diag.DiagOn) Console.WriteLine("osMajor = " + Hex.Int(verInfo.osMajor)); //ReadZeros(6); // osMinor, userMajor, userMinor verInfo.osMinor = ReadUInt16(); verInfo.userMajor = ReadUInt16(); verInfo.userMinor = ReadUInt16(); verInfo.subSysMajor = ReadUInt16(); if (Diag.DiagOn) Console.WriteLine("subsysMajor = " + Hex.Int(verInfo.subSysMajor)); verInfo.subSysMinor = ReadUInt16(); ReadZeros(4); // Reserved uint imageSize = ReadUInt32(); if (Diag.DiagOn) Console.WriteLine("imageSize = " + Hex.Int(imageSize)); uint headerSize = ReadUInt32(); if (Diag.DiagOn) Console.WriteLine("headerSize = " + Hex.Int(headerSize)); uint checkSum = ReadUInt32(); if (Diag.DiagOn) Console.WriteLine("checkSum = " + Hex.Int(checkSum)); verInfo.subSystem = (SubSystem)ReadUInt16(); if (Diag.DiagOn) Console.WriteLine("subSystem = " + Hex.Short((int)verInfo.subSystem)); verInfo.DLLFlags = ReadUInt16(); if (Diag.DiagOn) Console.WriteLine("DLLFlags = " + Hex.Short(verInfo.DLLFlags)); ulong stackReserve = x64 ? ReadUInt64() : ReadUInt32(); // if (ReadUInt32() != FileImage.StackReserveSize) InputError(); ulong stackCommit = x64 ? ReadUInt64() : ReadUInt32(); // if (ReadUInt32() != FileImage.StackCommitSize) InputError(); ulong heapReserve = x64 ? ReadUInt64() : ReadUInt32(); // if (ReadUInt32() != FileImage.HeapReserveSize) InputError(); ulong heapCommit = x64 ? ReadUInt64() : ReadUInt32(); // if (ReadUInt32() != FileImage.HeapCommitSize) InputError(); ReadUInt32(); // if (ReadUInt32() != 0) InputError(); // LoaderFlags uint numdict = ReadUInt32(); if (numdict != FileImage.NumDataDirectories) InputError(); /* Data Directories */ DataDirectoryRVA = new uint[FileImage.NumDataDirectories]; DataDirectorySize = new uint[FileImage.NumDataDirectories]; // (Index 2 is resource table address and size) for (int i = 0; i < FileImage.NumDataDirectories; i++) { DataDirectoryRVA[i] = ReadUInt32(); DataDirectorySize[i] = ReadUInt32(); } if (Diag.DiagOn) { Console.WriteLine("RVA = " + Hex.Int(DataDirectoryRVA[1]) + " Size = " + Hex.Int(DataDirectorySize[1]) + " Import Table"); Console.WriteLine("RVA = " + Hex.Int(DataDirectoryRVA[2]) + " Size = " + Hex.Int(DataDirectorySize[2]) + " Resource Table"); Console.WriteLine("RVA = " + Hex.Int(DataDirectoryRVA[5]) + " Size = " + Hex.Int(DataDirectorySize[5]) + " Base Relocation Table"); Console.WriteLine("RVA = " + Hex.Int(DataDirectoryRVA[12]) + " Size = " + Hex.Int(DataDirectorySize[12]) + " IAT"); Console.WriteLine("RVA = " + Hex.Int(DataDirectoryRVA[14]) + " Size = " + Hex.Int(DataDirectorySize[14]) + " CLI Header"); } } private void ReadSectionHeaders() { if (Diag.DiagOn) Console.WriteLine("Sections"); inputSections = new Section[numSections]; for (int i = 0; i < numSections; i++) { inputSections[i] = new Section(this); } } private void ReadCLIHeader() { BaseStream.Seek(GetOffset(DataDirectoryRVA[cliIx]), SeekOrigin.Begin); uint cliSize = ReadUInt32(); verInfo.cliMajVer = ReadUInt16(); // check verInfo.cliMinVer = ReadUInt16(); // check metaDataRVA = ReadUInt32(); metaDataSize = ReadUInt32(); //Console.WriteLine("Meta Data at rva " + PEConsts.Hex(metaDataRVA) + " size = " + PEConsts.Hex(metaDataSize)); verInfo.corFlags = (CorFlags)ReadUInt32(); entryPoint = ReadUInt32(); resourcesRVA = ReadUInt32(); resourcesSize = ReadUInt32(); strongNameRVA = ReadUInt32(); strongNameSize = ReadUInt32(); ReadZeros(8); // CodeManagerTable vFixupsRVA = ReadUInt32(); vFixupsSize = ReadUInt32(); ReadZeros(16); // ExportAddressTableJumps/ManagedNativeHeader } private String ReadStreamName() { char[] strName = new char[9]; strName[0] = (char)ReadByte(); char ch = (char)ReadByte(); int i = 1; while (ch != '\0') { strName[i++] = ch; ch = (char)ReadByte(); } strName[i++] = '\0'; if (i % 4 != 0) { for (int j = 4 - i % 4; j > 0; j--) ReadByte(); } return new String(strName, 0, i - 1); } private void ReadMetaData() { if (Diag.DiagOn) Console.WriteLine("MetaData at RVA = " + Hex.Int(metaDataRVA) + " and offset = " + Hex.Int(GetOffset(metaDataRVA))); BaseStream.Seek(GetOffset(metaDataRVA), SeekOrigin.Begin); uint sig = ReadUInt32(); // check verInfo.mdMajVer = ReadUInt16(); // check verInfo.mdMinVer = ReadUInt16(); // check ReadZeros(4); int verStrLen = ReadInt32(); int end = -1; char[] verString = new char[verStrLen + 1]; for (int i = 0; i < verStrLen; i++) { verString[i] = (char)ReadByte(); if ((verString[i] == 0) && (end == -1)) end = i; } verString[verStrLen] = (char)0; // check if (end == -1) end = verStrLen; verInfo.netVerString = new string(verString, 0, end); verInfo.SetVersionFromString(); // Beware of unknown netVerString values here ... Needs a better fix (kjg 31-Oct-2007) GenericParam.extraField = verInfo.netVersion < NetVersion.Whidbey41; if (Diag.DiagOn && GenericParam.extraField) { Console.WriteLine("Version = " + verInfo.netVerString + " has extra field for GenericParam"); } int alignNum = 0; if ((verStrLen % 4) != 0) alignNum = 4 - (verStrLen % 4); ReadZeros(alignNum); flags = ReadUInt16(); // check int numStreams = ReadUInt16(); streamOffsets = new uint[numStreams]; streamSizes = new uint[numStreams]; streamNames = new String[numStreams]; if (Diag.DiagOn) Console.WriteLine("MetaData Streams"); for (int i = 0; i < numStreams; i++) { streamOffsets[i] = ReadUInt32(); streamSizes[i] = ReadUInt32(); streamNames[i] = ReadStreamName(); if (Diag.DiagOn) Console.WriteLine(" " + streamNames[i] + " Offset = " + Hex.Int(streamOffsets[i]) + " Size = " + Hex.Int(streamSizes[i])); } uint tildeIx = 0; for (uint i = 0; i < numStreams; i++) { String nam = streamNames[i]; if (MetaData.tildeName.CompareTo(nam) == 0) tildeIx = i; else { uint streamoff = GetOffset(metaDataRVA + streamOffsets[i]); if (Diag.DiagOn) Console.WriteLine("getting stream bytes at offset " + Hex.Int(streamoff)); BaseStream.Seek(GetOffset(metaDataRVA + streamOffsets[i]), SeekOrigin.Begin); long streamStart = BaseStream.Position; byte[] strBytes = ReadBytes((int)streamSizes[i]); if (MetaData.stringsName.CompareTo(nam) == 0) { strings = new MetaDataInStream(strBytes); } else if (MetaData.userstringName.CompareTo(nam) == 0) { userstring = new MetaDataStringStream(strBytes); } else if (MetaData.blobName.CompareTo(nam) == 0) { blobStreamStartOffset = streamStart; blob = new MetaDataInStream(strBytes); } else if (MetaData.guidName.CompareTo(nam) == 0) { guid = new MetaDataInStream(strBytes); } else if (nam.CompareTo("#-") == 0) { tildeIx = i; //throw new Exception("Illegal uncompressed data stream #-"); } else { Console.WriteLine("Unknown stream - " + nam); } } } // go to beginning of tilde stream BaseStream.Seek(GetOffset(metaDataRVA + streamOffsets[tildeIx]), SeekOrigin.Begin); ReadTildeStreamStart(); } private void SetUpTableInfo() { md.CalcElemSize(); tableStarts = new long[MetaData.NumMetaDataTables]; long currentPos = BaseStream.Position; for (int ix = 0; ix < MetaData.NumMetaDataTables; ix++) { tableStarts[ix] = currentPos; currentPos += tableLengths[ix] * md.elemSize[ix]; } } private void ReadTildeStreamStart() { if (Diag.DiagOn) Console.WriteLine("Reading meta data tables at offset = " + Hex.Int((int)BaseStream.Position)); // pre: at beginning of tilde stream ReadZeros(4); // reserved verInfo.tsMajVer = ReadByte(); // check verInfo.tsMinVer = ReadByte(); // check byte heapSizes = ReadByte(); if (heapSizes != 0) { md.largeStrings = (heapSizes & 0x01) != 0; md.largeGUID = (heapSizes & 0x02) != 0; md.largeBlob = (heapSizes & 0x04) != 0; } if (Diag.DiagOn) { if (md.largeStrings) Console.WriteLine("LARGE strings index"); if (md.largeGUID) Console.WriteLine("LARGE GUID index"); if (md.largeBlob) Console.WriteLine("LARGE blob index"); } int res = ReadByte(); // check if 1 ulong valid = ReadUInt64(); ulong sorted = this.ReadUInt64(); if (Diag.DiagOn) Console.WriteLine("Valid = " + Hex.Long(valid)); for (int i = 0; i < MetaData.NumMetaDataTables; i++) { if ((valid & FileImage.bitmasks[i]) != 0) { tableLengths[i] = ReadUInt32(); tables[i] = new TableRow[tableLengths[i]]; md.largeIx[i] = tableLengths[i] > MetaData.maxSmlIxSize; if (Diag.DiagOn) Console.WriteLine("Table Ix " + Hex.Short(i) + " has length " + tableLengths[i]); } else tableLengths[i] = 0; } if (tableLengths[0] != 1) this.MetaDataError("Module table has more than one entry"); for (int i = 0; i < MetaData.CIxTables.Length; i++) { for (int j = 0; j < MetaData.CIxTables[i].Length; j++) { if (Diag.DiagOn) Console.WriteLine("CIxTables " + i + " " + j + " tableLength = " + tableLengths[MetaData.CIxTables[i][j]] + " Max = " + MetaData.CIxMaxMap[i]); md.lgeCIx[i] = md.lgeCIx[i] || (tableLengths[MetaData.CIxTables[i][j]] > MetaData.CIxMaxMap[i]); } if (Diag.DiagOn) if (md.lgeCIx[i]) Console.WriteLine("LARGE CIx " + i); } } private void SetThisScope() { if (refsOnly) thisScope = Module.ReadModuleRef(this); else ((PEFile)thisScope).Read(this); tables[(int)MDTable.Module][0] = thisScope; if (tableLengths[(int)MDTable.Assembly] > 0) { SetElementPosition(MDTable.Assembly, 1); if (refsOnly) { ModuleRef thisMod = (ModuleRef)thisScope; thisScope = Assembly.ReadAssemblyRef(this); //if ((thisMod != null) && (thisMod.ismscorlib) && (thisScope != null)) { // ((AssemblyRef)thisScope).CopyVersionInfoToMSCorLib(); // thisScope = MSCorLib.mscorlib; //} tables[(int)MDTable.Assembly][0] = thisScope; } else { Assembly.Read(this, tables[(int)MDTable.Assembly], (PEFile)thisScope); ((PEFile)thisScope).SetThisAssembly((Assembly)tables[(int)MDTable.Assembly][0]); } } } /// /// Read the Module metadata for this PE file. /// If reading refs only, then thisModule is the ModuleRef /// If reading defs then pefile is the Module /// /* private void GetThisPEFileScope() { if (refsOnly) { thisModuleRef = Module.ReadModuleRef(this); } else { pefile.Read(this); tables[(int)MDTable.Module][0] = pefile; } } private AssemblyRef GetThisAssembly(bool atPos) { if (tableLengths[(int)MDTable.Assembly] == 0) return null; if (!atPos) BaseStream.Position = tableStarts[(int)MDTable.Assembly]; if (refsOnly) tables[(int)MDTable.Assembly][0] = Assembly.ReadAssemblyRef(this); else Assembly.Read(this,tables[(int)MDTable.Assembly],pefile); return (AssemblyRef)tables[(int)MDTable.Assembly][0]; } */ /* private ReferenceScope ReadRefsOnDemand() { ModuleRef thisModule; SetUpTableInfo(); ResolutionScope mod; AssemblyRef thisAssembly = GetThisAssemblyRef(); SetElementPosition(MDTable.Module,0); ReadZeros(2); name = buff.GetString(); mvid = buff.GetGUID(); ModuleRef thisMod = ModuleRef.GetModuleRef(name); if (thisMod == null) { thisMod = new ModuleRef(name); Module.AddToList(thisMod); } else { } if (thisModule == null) { thisModule = new ModuleRef(name); thisModule.readAsDef = true; if (mod != null) ((Module)mod).refOf = thisModule; else Module.AddToList(thisModule); } else { if (thisModule.readAsDef) return thisModule; return Merge(thisModule); } ReferenceScope thisScope = thisAssembly; if (thisScope == null) thisScope = thisModule; ClassRef defClass = ReadDefaultClass(); thisScope.SetDefaultClass(defClass); ClassDef.GetClassRefNames(this,thisScope); return null; } */ private void ReadMetaDataTableRefs() { SetUpTableInfo(); SetThisScope(); // ReadAssemblyRefs SetElementPosition(MDTable.AssemblyRef, 1); if (tableLengths[(int)MDTable.AssemblyRef] > 0) AssemblyRef.Read(this, tables[(int)MDTable.AssemblyRef]); // Read File Table (for ModuleRefs) //SetElementPosition(MDTable.File,1); if (tableLengths[(int)MDTable.File] > 0) FileRef.Read(this, tables[(int)MDTable.File]); // Read Exported Classes //SetElementPosition(MDTable.ExportedType,1); if (tableLengths[(int)MDTable.ExportedType] > 0) ExternClass.GetClassRefs(this, tables[(int)MDTable.ExportedType]); // Read ModuleRefs if (tableLengths[(int)MDTable.ModuleRef] > 0) { BaseStream.Position = tableStarts[(int)MDTable.ModuleRef]; ModuleRef.Read(this, tables[(int)MDTable.ModuleRef], true); } uint[] parIxs = new uint[tableLengths[(int)MDTable.TypeDef]]; BaseStream.Position = tableStarts[(int)MDTable.NestedClass]; MapElem.ReadNestedClassInfo(this, tableLengths[(int)MDTable.NestedClass], parIxs); BaseStream.Position = tableStarts[(int)MDTable.TypeRef]; // Read ClassRefs if (tableLengths[(int)MDTable.TypeRef] > 0) ClassRef.Read(this, tables[(int)MDTable.TypeRef], true); // Read ClassDefs and fields and methods ClassDef.GetClassRefs(this, tables[(int)MDTable.TypeDef], (ReferenceScope)thisScope, parIxs); for (int i = 0; i < tableLengths[(int)MDTable.ExportedType]; i++) { ((ClassRef)tables[(int)MDTable.ExportedType][i]).ResolveParent(this, true); } } internal void SetElementPosition(MDTable tabIx, uint ix) { BaseStream.Position = tableStarts[(int)tabIx] + (md.elemSize[(int)tabIx] * (ix - 1)); } internal void ReadMethodImpls(ClassDef theClass, uint classIx) { SetElementPosition(MDTable.InterfaceImpl, 0); for (int i = 0; (i < tableLengths[(int)MDTable.MethodImpl]); i++) { uint clIx = GetIndex(MDTable.TypeDef); uint bodIx = GetCodedIndex(CIx.MethodDefOrRef); uint declIx = GetCodedIndex(CIx.MethodDefOrRef); if (clIx == classIx) { MethodImpl mImpl = new MethodImpl(this, theClass, bodIx, declIx); theClass.AddMethodImpl(mImpl); tables[(int)MDTable.MethodImpl][i] = mImpl; } } } internal void InsertInTable(MDTable tabIx, uint ix, MetaDataElement elem) { tables[(int)tabIx][ix - 1] = elem; } private void CheckForRefMerges() { if (tableLengths[(int)MDTable.TypeRef] > 0) { for (int i = 0; i < tableLengths[(int)MDTable.TypeRef]; i++) { ((ClassRef)tables[(int)MDTable.TypeRef][i]).ResolveParent(this, false); } } if (tableLengths[(int)MDTable.MemberRef] > 0) { for (int i = 0; i < tableLengths[(int)MDTable.MemberRef]; i++) { Member memb = (Member)tables[(int)MDTable.MemberRef][i]; tables[(int)MDTable.MemberRef][i] = memb.ResolveParent(this); } } } internal void ReplaceSig(Signature sig, Type sigType) { tables[(int)MDTable.StandAloneSig][sig.Row - 1] = sigType; } internal void GetGenericParams(MethodDef meth) { if (tables[(int)MDTable.GenericParam] != null) { for (int j = 0; j < tables[(int)MDTable.GenericParam].Length; j++) { ((GenericParam)tables[(int)MDTable.GenericParam][j]).CheckParent(meth, this); } } } private void ReadMetaDataTables() { ((PEFile)thisScope).Read(this); tables[(int)MDTable.Module][0] = thisScope; for (int ix = 1; ix < MetaData.NumMetaDataTables; ix++) { if (tableLengths[ix] > 0) { switch (ix) { case ((int)MDTable.Assembly): Assembly.Read(this, tables[ix], (PEFile)thisScope); break; case ((int)MDTable.AssemblyOS): case ((int)MDTable.AssemblyProcessor): case ((int)MDTable.AssemblyRefOS): case ((int)MDTable.AssemblyRefProcessor): // ignore Console.WriteLine("Got uncompressed table " + (MDTable)ix); BaseStream.Seek(tableLengths[ix] * md.elemSize[ix], SeekOrigin.Current); break; case ((int)MDTable.AssemblyRef): AssemblyRef.Read(this, tables[ix]); break; //case 0x25 : AssemblyRefOS.Read(this,tables[ix]); break; //case 0x24 : AssemblyRefProcessor.Read(this,tables[ix]); break; case ((int)MDTable.ClassLayout): ClassLayout.Read(this, tables[ix]); break; case ((int)MDTable.Constant): ConstantElem.Read(this, tables[ix]); break; case ((int)MDTable.CustomAttribute): CustomAttribute.Read(this, tables[ix]); break; case ((int)MDTable.DeclSecurity): DeclSecurity.Read(this, tables[ix]); break; case ((int)MDTable.Event): Event.Read(this, tables[ix]); break; case ((int)MDTable.EventMap): MapElem.Read(this, tables[ix], MDTable.EventMap); break; case ((int)MDTable.ExportedType): ExternClass.Read(this, tables[ix]); break; case ((int)MDTable.Field): FieldDef.Read(this, tables[ix]); break; case ((int)MDTable.FieldLayout): FieldLayout.Read(this, tables[ix]); break; case ((int)MDTable.FieldMarshal): FieldMarshal.Read(this, tables[ix]); break; case ((int)MDTable.FieldRVA): FieldRVA.Read(this, tables[ix]); break; case ((int)MDTable.File): FileRef.Read(this, tables[ix]); break; case ((int)MDTable.GenericParam): GenericParam.Read(this, tables[ix]); break; case ((int)MDTable.GenericParamConstraint): GenericParamConstraint.Read(this, tables[ix]); break; case ((int)MDTable.ImplMap): ImplMap.Read(this, tables[ix]); break; case ((int)MDTable.InterfaceImpl): InterfaceImpl.Read(this, tables[ix]); break; case ((int)MDTable.ManifestResource): ManifestResource.Read(this, tables[ix]); break; case ((int)MDTable.MemberRef): Member.ReadMember(this, tables[ix]); break; case ((int)MDTable.Method): MethodDef.Read(this, tables[ix]); break; case ((int)MDTable.MethodImpl): MethodImpl.Read(this, tables[ix]); break; case ((int)MDTable.MethodSemantics): MethodSemantics.Read(this, tables[ix]); break; case ((int)MDTable.MethodSpec): MethodSpec.Read(this, tables[ix]); break; case ((int)MDTable.ModuleRef): ModuleRef.Read(this, tables[ix], false); break; case ((int)MDTable.NestedClass): MapElem.Read(this, tables[ix], MDTable.NestedClass); tables[ix] = null; break; case ((int)MDTable.Param): Param.Read(this, tables[ix]); break; case ((int)MDTable.Property): Property.Read(this, tables[ix]); break; case ((int)MDTable.PropertyMap): MapElem.Read(this, tables[ix], MDTable.PropertyMap); break; case ((int)MDTable.StandAloneSig): Signature.Read(this, tables[ix]); break; case ((int)MDTable.TypeDef): ClassDef.Read(this, tables[ix], ((PEFile)thisScope).isMSCorLib()); break; case ((int)MDTable.TypeRef): ClassRef.Read(this, tables[ix], false); break; case ((int)MDTable.TypeSpec): TypeSpec.Read(this, tables[ix]); break; default: throw (new PEFileException("Unknown MetaData Table Type")); } } } CheckForRefMerges(); for (int ix = 0; ix < MetaData.NumMetaDataTables; ix++) { if ((tables[ix] != null) && (ix != (int)MDTable.TypeSpec) && (ix != (int)MDTable.MethodSpec)) { // resolve type/method specs when referenced for (int j = 0; j < tables[ix].Length; j++) { //tables[ix][j].Row = (uint)j+1; // KJG fix 2005:02:23 // Everett ILASM leaves gaps in table[10][x] ... // so protect with a null test. // // ((MetaDataElement)tables[ix][j]).Resolve(this); // old line ... // if (tables[ix][j] != null) { ((MetaDataElement)tables[ix][j]).Resolve(this); } } } } if (tableLengths[(int)MDTable.Assembly] > 0) ((PEFile)thisScope).SetThisAssembly((Assembly)tables[(int)MDTable.Assembly][0]); ((PEFile)thisScope).SetDefaultClass((ClassDef)tables[(int)MDTable.TypeDef][0]); for (int j = 1; j < tables[(int)MDTable.TypeDef].Length; j++) { ((PEFile)thisScope).AddToClassList((ClassDef)tables[(int)MDTable.TypeDef][j]); } if (tableLengths[(int)MDTable.ManifestResource] > 0) { for (int j = 0; j < tables[(int)MDTable.ManifestResource].Length; j++) { ((PEFile)thisScope).AddToResourceList((ManifestResource)tables[(int)MDTable.ManifestResource][j]); } } // We must protect the following code, since it seems possible // that "entryPoint" is a random value if isDLL is false, // leading to an index out of bounds error in some cases. if (!verInfo.isDLL && entryPoint != 0) { MetaDataElement ep = GetTokenElement(entryPoint); if (ep is MethodDef) ((MethodDef)ep).DeclareEntryPoint(); else ((ModuleFile)ep).SetEntryPoint(); } } /// /// This method saves any *unmanaged* resources in the input PE-file /// to the PEResourcesDirectory field PEFile.unmanagedResourceRoot. /// These should be written out to the .rscr section in the PE-file. /// Managed resources appear as ManifestResouces in metadata, and are /// handled completely differently. /// private void SaveUnmanagedResources() { if (this.DataDirectorySize[2] != 0) { uint resourceRVA = this.DataDirectoryRVA[2]; uint fileOffset = this.GetOffset(resourceRVA); long savedPos = this.BaseStream.Position; this.BaseStream.Seek(fileOffset, SeekOrigin.Begin); PEFile client = thisScope as PEFile; if (client != null) { client.unmanagedResourceRoot = new PEResourceDirectory(); client.unmanagedResourceRoot.PopulateResourceDirectory(this, fileOffset); } this.BaseStream.Seek(savedPos, SeekOrigin.Begin); } } internal uint GetIndex(MDTable tabIx) { if (md.largeIx[(int)tabIx]) return ReadUInt32(); return ReadUInt16(); } internal uint GetCodedIndex(CIx codedIx) { if (md.lgeCIx[(int)codedIx]) return ReadUInt32(); return ReadUInt16(); } internal uint GetTableSize(MDTable tabIx) { return (uint)tableLengths[(int)tabIx]; } internal byte[] GetResource(uint offset) { BaseStream.Position = GetOffset(resourcesRVA) + offset; uint resSize = ReadUInt32(); return ReadBytes((int)resSize); } internal MetaDataElement GetTokenElement(uint token) { uint tabIx = (token & FileImage.TableMask) >> 24; uint elemIx = (token & FileImage.ElementMask) - 1; MetaDataElement elem = (MetaDataElement)tables[tabIx][(int)elemIx]; if ((elem != null) && (elem.unresolved)) { elem.Resolve(this); elem = (MetaDataElement)tables[tabIx][(int)elemIx]; } return elem; } internal MetaDataElement GetElement(MDTable tabIx, uint ix) { if (ix == 0) return null; MetaDataElement elem = (MetaDataElement)tables[(int)tabIx][(int)ix - 1]; if ((elem != null) && (elem.unresolved)) { elem.Resolve(this); elem = (MetaDataElement)tables[(int)tabIx][(int)ix - 1]; } return elem; } internal MetaDataElement GetCodedElement(CIx code, uint ix) { uint mask = (uint)MetaData.CIxBitMasks[MetaData.CIxShiftMap[(uint)code]]; int tabIx = MetaData.CIxTables[(int)code][(ix & mask)]; ix >>= MetaData.CIxShiftMap[(uint)code]; if (ix == 0) return null; MetaDataElement elem = (MetaDataElement)tables[tabIx][(int)ix - 1]; if ((elem != null) && (elem.unresolved)) { elem.Resolve(this); elem = (MetaDataElement)tables[tabIx][(int)ix - 1]; } return elem; } internal uint MakeCodedIndex(CIx code, MDTable tab, uint ix) { ix <<= MetaData.CIxShiftMap[(uint)code]; ix &= (uint)tab; return ix; } internal MDTable CodedTable(CIx code, uint ix) { uint mask = (uint)MetaData.CIxBitMasks[MetaData.CIxShiftMap[(uint)code]]; return (MDTable)MetaData.CIxTables[(int)code][(ix & mask)]; } internal uint CodedIndex(CIx code, uint ix) { ix >>= MetaData.CIxShiftMap[(uint)code]; return ix; } internal byte[] GetBlob() { /* pre: buffer is at correct position to read blob index */ uint ix; if (md.largeBlob) ix = ReadUInt32(); else ix = ReadUInt16(); return blob.GetBlob(ix); } internal byte[] GetBlob(uint ix) { return blob.GetBlob(ix); } internal uint GetBlobIx() { /* pre: buffer is at correct position to read blob index */ //if (Diag.CADiag) Console.WriteLine("Getting blob index at " + BaseStream.Position); if (md.largeBlob) return ReadUInt32(); return ReadUInt16(); } internal byte FirstBlobByte(uint ix) { blob.GoToIndex(ix); uint blobSize = blob.ReadCompressedNum(); return blob.ReadByte(); } internal Constant GetBlobConst(int constType) { uint ix; if (md.largeBlob) ix = ReadUInt32(); else ix = ReadUInt16(); blob.GoToIndex(ix); uint blobSize = blob.ReadCompressedNum(); if (constType == (int)ElementType.String) return new StringConst(blob.ReadBytes((int)blobSize)); return ReadConst(constType, blob); } /* internal Constant ReadConstBlob(int constType, uint blobIx) { blob.GoToIndex(blobIx); Console.WriteLine("Reading constant blob at index " + blobIx ); uint blobSize = blob.ReadCompressedNum(); Console.WriteLine("Got constant blob size of " + blobSize); return ReadConst(constType); } */ internal static Constant ReadConst(int constType, BinaryReader blob) { switch (constType) { case ((int)ElementType.Boolean): return new BoolConst(blob.ReadByte() != 0); case ((int)ElementType.Char): return new CharConst(blob.ReadChar()); case ((int)ElementType.I1): return new IntConst(blob.ReadSByte()); case ((int)ElementType.U1): return new UIntConst(blob.ReadByte()); case ((int)ElementType.I2): return new IntConst(blob.ReadInt16()); case ((int)ElementType.U2): return new UIntConst(blob.ReadUInt16()); case ((int)ElementType.I4): return new IntConst(blob.ReadInt32()); case ((int)ElementType.U4): return new UIntConst(blob.ReadUInt32()); case ((int)ElementType.I8): return new IntConst(blob.ReadInt64()); case ((int)ElementType.U8): return new UIntConst(blob.ReadUInt64()); case ((int)ElementType.R4): return new FloatConst(blob.ReadSingle()); case ((int)ElementType.R8): return new DoubleConst(blob.ReadDouble()); case ((int)ElementType.ClassType): return new ClassTypeConst(blob.ReadString()); //GetBlobString()); case ((int)ElementType.String): return new StringConst(blob.ReadString()); //GetBlobString()); case ((int)ElementType.Class): return new ClassTypeConst(blob.ReadString()); //GetBlobString()); //uint junk = blob.ReadUInt32(); // need to read name?? //return new NullRefConst(); case ((int)ElementType.ValueType): // only const value type is enum?? return new IntConst(blob.ReadInt32()); default: return null; } } internal string GetBlobString() { uint ix; if (md.largeBlob) ix = ReadUInt32(); else ix = ReadUInt16(); return blob.GetBlobString(ix); } internal string GetString() { uint ix; if (md.largeStrings) ix = ReadUInt32(); else ix = ReadUInt16(); return strings.GetString(ix); } internal string GetString(uint ix) { return strings.GetString(ix); } internal uint GetStringIx() { if (md.largeStrings) return ReadUInt32(); else return ReadUInt16(); } internal uint GetGUIDIx() { /* pre: buffer is at correct position to read GUID index */ if (md.largeGUID) return ReadUInt32(); return ReadUInt16(); } public Guid GetGUID() { uint ix; if (md.largeGUID) ix = ReadUInt32(); else ix = ReadUInt16(); return new Guid(guid.GetBlob(((ix - 1) * 16), 16)); } public string GetUserString() { uint ix; if (md.largeUS) ix = ReadUInt32(); else ix = ReadUInt16(); return userstring.GetUserString(ix); } internal bool IsFieldSig(uint blobIx) { blob.GoToIndex(blobIx); uint blobSize = blob.ReadCompressedNum(); byte fldByte = blob.ReadByte(); return fldByte == Field.FieldTag; } internal MethSig ReadMethSig(Method thisMeth, uint blobIx) { blob.GoToIndex(blobIx); uint blobSize = blob.ReadCompressedNum(); return ReadMethSig(thisMeth, false); } internal MethSig ReadMethSig(Method thisMeth, string name, uint blobIx) { blob.GoToIndex(blobIx); uint blobSize = blob.ReadCompressedNum(); MethSig mSig = ReadMethSig(thisMeth, false); mSig.name = name; return mSig; } private MethSig ReadMethSig(Method currMeth, bool firstByteRead) { MethSig meth = new MethSig(null); if (!firstByteRead) { byte firstByte = blob.ReadByte(); if (firstByte == Field.FieldTag) return null; meth.callConv = (CallConv)firstByte; } if ((meth.callConv & CallConv.Generic) != 0) { meth.numGenPars = blob.ReadCompressedNum(); if (currMeth is MethodRef) { ((MethodRef)currMeth).MakeGenericPars(meth.numGenPars); } } uint parCount = blob.ReadCompressedNum(); if (Diag.DiagOn) Console.WriteLine("Method sig has " + parCount + " parameters"); meth.retType = GetBlobType();//currClass,currMeth); if (meth.retType == null) System.Diagnostics.Debug.Assert(meth.retType != null); int optParStart = -1; ArrayList pTypes = new ArrayList(); for (int i = 0; i < parCount; i++) { Type pType = GetBlobType();//currClass,currMeth); if (pType == sentinel) { optParStart = i; pType = GetBlobType();//currClass,currMeth); } if (Diag.DiagOn) if (pType == null) Console.WriteLine("Param type is null"); pTypes.Add(pType); } if (optParStart > -1) { meth.numPars = (uint)optParStart; meth.numOptPars = parCount - meth.numPars; meth.optParTypes = new Type[meth.numOptPars]; for (int i = 0; i < meth.numOptPars; i++) { meth.optParTypes[i] = (Type)pTypes[i + optParStart]; } } else meth.numPars = parCount; meth.parTypes = new Type[meth.numPars]; for (int i = 0; i < meth.numPars; i++) { meth.parTypes[i] = (Type)pTypes[i]; } return meth; } internal Type[] ReadMethSpecSig(uint blobIx) { //ClassDef currClass, Method currMeth, uint blobIx) { blob.GoToIndex(blobIx); uint blobSize = blob.ReadCompressedNum(); if (blob.ReadByte() != MethodSpec.GENERICINST) throw new Exception("Not a MethodSpec signature"); return GetListOfType(); //currClass,currMeth); } internal Type GetFieldType(uint blobIx) { //Console.WriteLine("Getting field type"); blob.GoToIndex(blobIx); uint blobSize = blob.ReadCompressedNum(); byte fldByte = blob.ReadByte(); if (fldByte != 0x6) throw new Exception("Expected field signature"); //if ((currClass != null) && (currClass is ClassRef)) // currClass = null; return GetBlobType(); //currClass,null); } internal Type GetBlobType(uint blobIx) { //Class currClass, Method currMeth, uint blobIx) { blob.GoToIndex(blobIx); uint blobSize = blob.ReadCompressedNum(); return GetBlobType(); //currClass,currMeth); } private Type[] GetListOfType() { //Class currClass | Method currMeth) { uint numPars = blob.ReadCompressedNum(); Type[] gPars = new Type[numPars]; for (int i = 0; i < numPars; i++) { gPars[i] = GetBlobType(); //currClass|currMeth); } return gPars; } private Type GetBlobType() { //Class currClass, Method currMeth) { byte typeIx = blob.ReadByte(); if (Diag.DiagOn) Console.WriteLine("Getting blob type " + (ElementType)typeIx); if (typeIx < PrimitiveType.primitives.Length) return PrimitiveType.primitives[typeIx]; switch (typeIx) { case ((int)ElementType.Ptr): return new UnmanagedPointer(GetBlobType()); //currClass,currMeth)); case ((int)ElementType.ByRef): return new ManagedPointer(GetBlobType()); //currClass,currMeth)); case ((int)ElementType.ValueType): //Console.WriteLine("Reading value type"); uint vcIx = blob.ReadCompressedNum(); Class vClass = (Class)GetCodedElement(CIx.TypeDefOrRef, vcIx); vClass.MakeValueClass(); return vClass; case ((int)ElementType.Class): return (Class)GetCodedElement(CIx.TypeDefOrRef, blob.ReadCompressedNum()); case ((int)ElementType.Array): Type elemType = GetBlobType(); //currClass,currMeth); int rank = (int)blob.ReadCompressedNum(); int numSizes = (int)blob.ReadCompressedNum(); int[] sizes = null; int[] hiBounds = null; if (numSizes > 0) { sizes = new int[numSizes]; hiBounds = new int[numSizes]; for (int i = 0; i < numSizes; i++) sizes[i] = (int)blob.ReadCompressedNum(); } int numLoBounds = (int)blob.ReadCompressedNum(); int[] loBounds = null; // // We have the constraints: // 0 <= numSizes <= numLoBounds <= rank // if (numLoBounds > 0) { int constraint = (numLoBounds < numSizes ? numSizes : numLoBounds); loBounds = new int[constraint]; //loBounds = new int[numLoBounds]; for (int i = 0; i < numLoBounds; i++) loBounds[i] = blob.ReadCompressedInt(); if (numSizes > 0) for (int i = 0; i < numSizes; i++) hiBounds[i] = loBounds[i] + sizes[i] - 1; } if (numLoBounds == 0) // Implies numSizes == 0 also return new BoundArray(elemType, rank); else return new BoundArray(elemType, rank, loBounds, hiBounds); case ((int)ElementType.TypedByRef): return PrimitiveType.TypedRef; case ((int)ElementType.I): return PrimitiveType.IntPtr; case ((int)ElementType.U): return PrimitiveType.UIntPtr; case ((int)ElementType.FnPtr): MethSig mSig = ReadMethSig(null, false); return new MethPtrType(mSig); case ((int)ElementType.Object): return PrimitiveType.Object; case ((int)ElementType.SZArray): return new ZeroBasedArray(GetBlobType()); //currClass,currMeth)); case ((int)ElementType.CmodReqd): case ((int)ElementType.CmodOpt): Class modType = (Class)GetCodedElement(CIx.TypeDefOrRef, blob.ReadCompressedNum()); return new CustomModifiedType(GetBlobType(), (CustomModifier)typeIx, modType); case ((int)ElementType.Sentinel): return sentinel; case ((int)ElementType.Pinned): return pinned; case ((int)ElementType.GenericInst): Class instType = (Class)GetBlobType(); Class scopeSave = currentClassScope; if (genInstNestLevel > 0) { currentClassScope = instType; } genInstNestLevel++; ClassSpec newClassSpec = new ClassSpec(instType, GetListOfType()); genInstNestLevel--; if (genInstNestLevel > 0) { currentClassScope = scopeSave; } return newClassSpec; case ((int)ElementType.Var): if (currentClassScope == null) { //Console.WriteLine("GenericParam with currClass == null"); return GenericParam.AnonClassPar(blob.ReadCompressedNum()); //throw new Exception("No current class set"); } return currentClassScope.GetGenPar(blob.ReadCompressedNum()); case ((int)ElementType.MVar): if (currentMethodScope == null) { //Console.WriteLine("GenericParam with currMeth == null"); return GenericParam.AnonMethPar(blob.ReadCompressedNum()); //throw new Exception("No current method set"); } return currentMethodScope.GetGenericParam((int)blob.ReadCompressedNum()); default: break; } return null; } internal NativeType GetBlobNativeType(uint blobIx) { blob.GoToIndex(blobIx); uint blobSize = blob.ReadCompressedNum(); return GetBlobNativeType(); } internal NativeType GetBlobNativeType() { byte typeIx = blob.ReadByte(); if (typeIx == (byte)NativeTypeIx.Array) { return new NativeArray(GetBlobNativeType(), blob.ReadCompressedNum(), blob.ReadCompressedNum(), blob.ReadCompressedNum()); } else return NativeType.GetNativeType(typeIx); } internal Local[] ReadLocalSig(uint sigIx) { //Class currClass, Method currMeth, uint sigIx) { blob.GoToIndex(sigIx); uint blobSize = blob.ReadCompressedNum(); if (blob.ReadByte() != LocalSig.LocalSigByte) InputError(); uint count = blob.ReadCompressedNum(); Local[] locals = new Local[count]; for (uint i = 0; i < count; i++) { Type lType = GetBlobType(); //currClass,currMeth); bool pinnedLocal = lType == pinned; if (pinnedLocal) lType = GetBlobType(); //currClass,currMeth); locals[i] = new Local("loc" + i, lType, pinnedLocal); } return locals; } internal void ReadPropertySig(uint sigIx, Property prop) { blob.GoToIndex(sigIx); uint blobSize = blob.ReadCompressedNum(); if ((blob.ReadByte() & Property.PropertyTag) != Property.PropertyTag) InputError(); uint count = blob.ReadCompressedNum(); Type[] pars = new Type[count]; prop.SetPropertyType(GetBlobType()); //prop.GetParent(),null)); for (int i = 0; i < count; i++) pars[i] = GetBlobType(); //prop.GetParent(),null); prop.SetPropertyParams(pars); } internal DataConstant GetDataConstant(uint rva, Type constType) { ManagedPointer pointer = null; ClassDef image = null; BaseStream.Seek(GetOffset(rva), SeekOrigin.Begin); if (constType is PrimitiveType) { switch (constType.GetTypeIndex()) { case ((int)ElementType.I1): return new IntConst(ReadByte()); case ((int)ElementType.I2): return new IntConst(ReadInt16()); case ((int)ElementType.I4): return new IntConst(ReadInt32()); case ((int)ElementType.I8): return new IntConst(ReadInt64()); case ((int)ElementType.R4): return new FloatConst(ReadSingle()); case ((int)ElementType.R8): return new DoubleConst(ReadDouble()); case ((int)ElementType.String): return new StringConst(ReadString()); } } else if ((pointer = constType as ManagedPointer) != null) { uint dataRVA = ReadUInt32(); Type baseType = pointer.GetBaseType(); return new AddressConstant(GetDataConstant(dataRVA, baseType)); } // need to do repeated constant?? else if ((image = constType as ClassDef) != null && image.Layout != null) { byte[] data = new byte[image.Layout.GetSize()]; for (int i = 0; i < data.Length; i++) data[i] = ReadByte(); return new ByteArrConst(data); } return null; } internal ModuleFile GetFileDesc(string name) { if (tables[(int)MDTable.File] == null) return null; for (int i = 0; i < tables[(int)MDTable.File].Length; i++) { FileRef fr = (FileRef)tables[(int)MDTable.File][i]; if (fr.Name() == name) { if (fr is ModuleFile) return (ModuleFile)fr; fr = new ModuleFile(fr.Name(), fr.GetHash()); tables[(int)MDTable.File][i] = fr; return (ModuleFile)fr; } } return null; } /* private long GetOffset(int rva) { for (int i=0; i < inputSections.Length; i++) { long offs = inputSections[i].GetOffset(rva); if (offs > 0) return offs; } return 0; } public bool ReadPadding(int boundary) { while ((Position % boundary) != 0) { if (buffer[index++] != 0) { return false; } } return true; } public String ReadName() { int len = NAMELEN; char [] nameStr = new char[NAMELEN]; char ch = (char)ReadByte(); int i=0; for (; (i < NAMELEN) && (ch != '\0'); i++) { nameStr[i] = ch; ch = (char)ReadByte(); } return new String(nameStr,0,i); } internal String ReadString() { char [] str = new char[STRLEN]; int i=0; char ch = (char)ReadByte(); for (; ch != '\0'; i++) { str[i] = ch; ch = (char)ReadByte(); } return new String(str,0,i); } public long GetPos() { return BaseStream.Position; } public void SetPos(int ix) { BaseStream.Position = ix; } */ /* public void SetToRVA(int rva) { index = PESection.GetOffset(rva); // Console.WriteLine("Setting buffer to rva " + PEConsts.Hex(rva) + " = index " + PEConsts.Hex(index)); // Console.WriteLine("Setting buffer to rva " + rva + " = index " + index); } public byte[] GetBuffer() { return buffer; } */ private CILInstruction[] DoByteCodes(uint len, MethodDef thisMeth) { uint pos = 0; ArrayList instrList = new ArrayList(); //int instrIx = 0; while (pos < len) { uint offset = pos; uint opCode = ReadByte(); pos++; IType iType = IType.op; if (opCode == 0xFE) { uint ix = ReadByte(); pos++; opCode = (opCode << 8) + ix; iType = FileImage.longInstrMap[ix]; } else iType = FileImage.instrMap[opCode]; if (Diag.DiagOn) Console.WriteLine("Got instruction type " + iType); CILInstruction nextInstr = null; if (iType == IType.specialOp) { pos += 4; if (Diag.DiagOn) Console.WriteLine("Got instruction " + Hex.Byte((int)opCode)); switch (opCode) { case ((int)SpecialOp.ldc_i8): nextInstr = new LongInstr((SpecialOp)opCode, ReadInt64()); pos += 4; break; case ((int)SpecialOp.ldc_r4): nextInstr = new FloatInstr((SpecialOp)opCode, ReadSingle()); break; case ((int)SpecialOp.ldc_r8): nextInstr = new DoubleInstr((SpecialOp)opCode, ReadDouble()); pos += 4; break; case ((int)SpecialOp.calli): nextInstr = new SigInstr((SpecialOp)opCode, (CalliSig)GetTokenElement(ReadUInt32())); break; case ((int)SpecialOp.Switch): // switch uint count = ReadUInt32(); int[] offsets = new int[count]; for (uint i = 0; i < count; i++) offsets[i] = ReadInt32(); pos += (4 * count); nextInstr = new SwitchInstr(offsets); break; case ((int)SpecialOp.ldstr): // ldstr uint strIx = ReadUInt32(); strIx = strIx & FileImage.ElementMask; nextInstr = new StringInstr((SpecialOp)opCode, userstring.GetUserString(strIx)); break; case ((int)MethodOp.ldtoken): MetaDataElement elem = GetTokenElement(ReadUInt32()); if (elem is Method) nextInstr = new MethInstr((MethodOp)opCode, (Method)elem); else if (elem is Field) nextInstr = new FieldInstr((FieldOp)opCode, (Field)elem); else nextInstr = new TypeInstr((TypeOp)opCode, (Type)elem); break; } } else if (iType == IType.branchOp) { if (Diag.DiagOn) Console.WriteLine("Got instruction " + Hex.Byte((int)opCode)); if ((opCode < 0x38) || (opCode == 0xDE)) { // br or leave.s nextInstr = new BranchInstr(opCode, ReadSByte()); pos++; } else { nextInstr = new BranchInstr(opCode, ReadInt32()); pos += 4; } } else { if (Diag.DiagOn) Console.Write(Hex.Byte((int)opCode)); switch (iType) { case (IType.op): if (Diag.DiagOn) Console.WriteLine("Got instruction " + (Op)opCode); nextInstr = new Instr((Op)opCode); break; case (IType.methOp): if (Diag.DiagOn) Console.WriteLine("Got instruction " + (MethodOp)opCode); nextInstr = new MethInstr((MethodOp)opCode, (Method)GetTokenElement(ReadUInt32())); pos += 4; break; case (IType.typeOp): if (Diag.DiagOn) Console.WriteLine("Got instruction " + (TypeOp)opCode); uint ttok = ReadUInt32(); Type typeToken = (Type)GetTokenElement(ttok); if (typeToken is GenericParTypeSpec) typeToken = ((GenericParTypeSpec)typeToken).GetGenericParam(thisMeth); nextInstr = new TypeInstr((TypeOp)opCode, typeToken); pos += 4; break; case (IType.fieldOp): if (Diag.DiagOn) Console.WriteLine("Got instruction " + (FieldOp)opCode); nextInstr = new FieldInstr((FieldOp)opCode, (Field)GetTokenElement(ReadUInt32())); pos += 4; break; case (IType.int8Op): nextInstr = new IntInstr((IntOp)opCode, ReadSByte()); pos++; break; case (IType.uint8Op): nextInstr = new UIntInstr((IntOp)opCode, ReadByte()); pos++; break; case (IType.uint16Op): nextInstr = new UIntInstr((IntOp)opCode, ReadUInt16()); pos++; break; case (IType.int32Op): nextInstr = new IntInstr((IntOp)opCode, ReadInt32()); pos += 4; break; } } if (nextInstr != null) nextInstr.Resolve(); instrList.Add(nextInstr); } CILInstruction[] instrs = new CILInstruction[instrList.Count]; for (int i = 0; i < instrs.Length; i++) { instrs[i] = (CILInstruction)instrList[i]; } return instrs; } public void ReadByteCodes(MethodDef meth, uint rva) { if (rva == 0) return; BaseStream.Seek(GetOffset(rva), SeekOrigin.Begin); CILInstructions instrs = meth.CreateCodeBuffer(); uint formatByte = ReadByte(); uint format = formatByte & 0x3; if (Diag.DiagOn) Console.WriteLine("code header format = " + Hex.Byte((int)formatByte)); uint size = 0; if (format == CILInstructions.TinyFormat) { size = formatByte >> 2; if (Diag.DiagOn) Console.WriteLine("Tiny Format, code size = " + size); instrs.SetAndResolveInstructions(DoByteCodes(size, meth)); } else if (format == CILInstructions.FatFormat) { uint headerSize = ReadByte(); bool initLocals = (formatByte & CILInstructions.InitLocals) != 0; bool moreSects = (formatByte & CILInstructions.MoreSects) != 0; meth.SetMaxStack((int)ReadUInt16()); size = ReadUInt32(); if (Diag.DiagOn) Console.WriteLine("Fat Format, code size = " + size); uint locVarSig = ReadUInt32(); CILInstruction[] instrList = this.DoByteCodes(size, meth); while (moreSects) { // find next 4 byte boundary long currPos = BaseStream.Position; if (currPos % 4 != 0) { long pad = 4 - (currPos % 4); for (int p = 0; p < pad; p++) ReadByte(); } uint flags = ReadByte(); //while (flags == 0) flags = ReadByte(); // maximum of 3 to get 4 byte boundary?? moreSects = (flags & CILInstructions.SectMoreSects) != 0; bool fatSect = (flags & CILInstructions.SectFatFormat) != 0; if ((flags & CILInstructions.EHTable) == 0) throw new Exception("Section not an Exception Handler Table"); int sectLen = ReadByte() + (ReadByte() << 8) + (ReadByte() << 16); int numClauses = sectLen; // -4; if (fatSect) numClauses /= 24; else numClauses /= 12; for (int i = 0; i < numClauses; i++) { EHClauseType eFlag; if (fatSect) eFlag = (EHClauseType)ReadUInt32(); else eFlag = (EHClauseType)ReadUInt16(); uint tryOff = 0, tryLen = 0, hOff = 0, hLen = 0; if (fatSect) { tryOff = ReadUInt32(); tryLen = ReadUInt32(); hOff = ReadUInt32(); hLen = ReadUInt32(); } else { tryOff = ReadUInt16(); tryLen = ReadByte(); hOff = ReadUInt16(); hLen = ReadByte(); } EHClause ehClause = new EHClause(eFlag, tryOff, tryLen, hOff, hLen); if (eFlag == EHClauseType.Exception) ehClause.ClassToken(GetTokenElement(ReadUInt32())); else ehClause.FilterOffset(ReadUInt32()); instrs.AddEHClause(ehClause); } } if (locVarSig != 0) { LocalSig lSig = (LocalSig)GetTokenElement(locVarSig); lSig.Resolve(this, meth); meth.AddLocals(lSig.GetLocals(), initLocals); } instrs.SetAndResolveInstructions(instrList); } else { Console.WriteLine("byte code format error"); } } } }