/// <summary> /// Decodes assembly metadata, headers and tables to required values ad file offsets /// </summary> /// <param name="fileName">Assembly path and filename</param> /// <param name="cliHeaderFlag">Reference to CLI Header flag value</param> /// <param name="cliHeaderFlagOffset">Reference to CLI Header flag file offset</param> /// <param name="strongNameSignatureOffset">Reference to CLI Header strong name signature file offset</param> /// <param name="publicKeyIndexOffset">Reference to Public Key Index in Assembly Table file offset</param> /// <param name="publicKeyOffset">Reference to Public Key file offset</param> /// <param name="assemblyFlag">Reference to Assembly Table Flag value</param> /// <param name="assemblyFlagOffset">Reference to Assembly Table Flag file offset</param> /// <param name="compiledRuntimeVersion">Reference to string with compiled runtime version</param> /// <param name="assemblyReferences">Reference to array to hold assembly references</param> /// <param name="blobIndexSize">Blob Index size in bytes</param> /// <param name="peKind">PE kind type / Executable architecture</param> /// <returns>Returns a bool indicating if assembly data can be retieved successfully</returns> public static bool GetAssemblyData(string fileName, ref uint cliHeaderFlag, ref long cliHeaderFlagOffset, ref long strongNameSignatureOffset, ref long publicKeyIndexOffset, ref long publicKeyOffset, ref uint assemblyFlag, ref long assemblyFlagOffset, ref string compiledRuntimeVersion, ref ArrayList assemblyReferences, ref int blobIndexSize, ref string peKind) { FileStream stream = null; cliHeaderFlag = 0; cliHeaderFlagOffset = 0; strongNameSignatureOffset = 0; publicKeyIndexOffset = 0; publicKeyOffset = 0; compiledRuntimeVersion = String.Empty; assemblyFlag = 0; assemblyFlagOffset = 0; assemblyReferences.Clear(); try { if (File.Exists(fileName)) { stream = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); BinaryReader r = new BinaryReader(stream); try { MModule mod = new MModule(r); if ((mod.ModHeaders != null) && (mod.ModHeaders.COR20Header != null)) { cliHeaderFlag = mod.ModHeaders.COR20Header.Flags; cliHeaderFlagOffset = mod.ModHeaders.COR20Header.Start + CLI_HEADER_FLAGS_OFFSET; // if Strong Name Signature RVA is zero, no Strong Signature is available strongNameSignatureOffset = (mod.ModHeaders.COR20Header.StrongNameSignature.Rva == 0 ? 0 : mod.ModHeaders.COR20Header.StrongNameSignature.Start); compiledRuntimeVersion = mod.ModHeaders.MetaDataHeaders.StorageSigAndHeader.VersionString.Replace("\0", String.Empty); peKind = mod.ModHeaders.OSHeaders.PEHeader.PEImageTypeDescription; blobIndexSize = mod.MDTables.GetBlobIndexSize(); // next loop sum tables byte length till reaching Assembly Table - this would give Assembly Table start offset long assemblyTableOffset = mod.ModHeaders.MetaDataTableHeader.End; for (int tablesCounter = 0; tablesCounter < (int)Types.Assembly; tablesCounter++) { assemblyTableOffset += mod.MDTables.Tables[tablesCounter].RawData.Length; } Table tableAssembly = mod.MDTables.GetTable(Types.Assembly); if (tableAssembly.Count > 0) // this should be 1 { if (tableAssembly[0][6].RawData == 0) { // Index for public key points to nothing publicKeyOffset = 0; } else { publicKeyOffset = mod.BlobHeap.Start + tableAssembly[0][6].RawData + 1; } assemblyFlag = (uint)tableAssembly[0][ASSEMBLY_TABLE_FLAGS_COLUMN_INDEX].Data; if (assemblyTableOffset > 0) { publicKeyIndexOffset = assemblyTableOffset + ASSEMBLY_TABLE_PUBLIC_KEY_INDEX_OFFSET; assemblyFlagOffset = assemblyTableOffset + ASSEMBLY_TABLE_FLAGS_OFFSET; } } // next loop sum tables byte length till reaching Assembly References Table - this would give Assembly References Table start offset long referenceTableOffset = mod.ModHeaders.MetaDataTableHeader.End; for (int tablesCounter = 0; tablesCounter < (int)Types.AssemblyRef; tablesCounter++) { referenceTableOffset += mod.MDTables.Tables[tablesCounter].RawData.Length; } if (referenceTableOffset > 0) { Table tableAssemblyReferences = mod.MDTables.GetTable(Types.AssemblyRef); if (tableAssemblyReferences.Count > 0) { for (int referencesCounter = 0; referencesCounter < tableAssemblyReferences.Count; referencesCounter++) { AssemblyReference reference = new AssemblyReference(tableAssemblyReferences[referencesCounter][6].Data.ToString(), tableAssemblyReferences[referencesCounter][0].Data + "." + tableAssemblyReferences[referencesCounter][1].Data + "." + tableAssemblyReferences[referencesCounter][2].Data + "." + tableAssemblyReferences[referencesCounter][3].Data, tableAssemblyReferences[referencesCounter][5].Data.ToString(), referenceTableOffset + (referencesCounter * tableAssemblyReferences.RowSize)); assemblyReferences.Add(reference); } } } } else { return(false); } } catch (Exception) { return(false); } finally { r.Close(); } } } catch (UnauthorizedAccessException) { return(false); } catch (IOException) { return(false); } finally { if (stream != null) { stream.Close(); } } return(true); }
public Relocations(BinaryReader reader, MModule mod) { uint start, end; if (mod.ModHeaders.OSHeaders.PEHeader.DataDirs[5].Rva == 0) return; start = mod.ModHeaders.Rva2Offset(mod.ModHeaders.OSHeaders.PEHeader.DataDirs[5].Rva); end = start + mod.ModHeaders.OSHeaders.PEHeader.DataDirs[5].Size; //fill in Region props Start = start; Length = end-start; reader.BaseStream.Position = start; RelocationBlock block; ArrayList arr = new ArrayList(); while(reader.BaseStream.Position < end) { block = new RelocationBlock(reader); arr.Add(block); } _blox = (RelocationBlock[])arr.ToArray(typeof(RelocationBlock)); }
public ImpExports(BinaryReader reader, MModule mod) { ArrayList ides = new ArrayList(); ImportDirectoryEntry ide = null; _exports = new ExportRecord[0]; _ith = new ImportDirectoryEntry[0]; //imports if (mod.ModHeaders.OSHeaders.PEHeader.DataDirs[1].Rva != 0) { uint start, end; start = mod.ModHeaders.Rva2Offset(mod.ModHeaders.OSHeaders.PEHeader.DataDirs[1].Rva); end = mod.ModHeaders.OSHeaders.PEHeader.DataDirs[1].Size + start; reader.BaseStream.Position = start; while (reader.BaseStream.Position < end) { ide = new ImportDirectoryEntry(reader, mod); //in older PEs it seems there is no null terminating entry, but in .NET ones there is. if (ide.Name == null) { break; } else { ides.Add(ide); } } _ith = (ImportDirectoryEntry[])ides.ToArray(typeof(ImportDirectoryEntry)); } //exports if (mod.ModHeaders.OSHeaders.PEHeader.DataDirs[0].Rva != 0) { reader.BaseStream.Position = mod.ModHeaders.Rva2Offset(mod.ModHeaders.OSHeaders.PEHeader.DataDirs[0].Rva); _extab = new ExportDirTable(reader, mod); _expAddrTab = new uint[_extab.AddressTableEntries]; _expNameTab = new string[_extab.NamePointerCount]; _expOrdTab = new uint[_extab.NamePointerCount]; reader.BaseStream.Position = mod.ModHeaders.Rva2Offset(_extab.ExportAddressTableRVA); for(int i=0; i< _extab.AddressTableEntries; ++i) { _expAddrTab[i] = reader.ReadUInt32(); } reader.BaseStream.Position = mod.ModHeaders.Rva2Offset(_extab.OrdinalRVA); for(int i=0; i< _extab.NamePointerCount; ++i) { _expOrdTab[i] = reader.ReadUInt16(); } reader.BaseStream.Position = mod.ModHeaders.Rva2Offset(_extab.NamePointerRVA); for(int i=0; i< _extab.NamePointerCount; ++i) { _expNameTab[i] = mod.StringFromRVA(reader, reader.ReadUInt32()); } //assemble array of exportrecords uint len = _extab.AddressTableEntries; if (len > _extab.NamePointerCount) len = _extab.NamePointerCount; _exports = new ExportRecord[len]; for(int i=0; i < len; ++i) { _exports[i] = new ExportRecord(_expOrdTab[i], _expAddrTab[i], _expNameTab[i]); } } }
public ExportDirTable(BinaryReader reader, MModule mod) { _ExportFlags = reader.ReadUInt32(); _TimeStamp = reader.ReadUInt32(); _MajorVersion = reader.ReadUInt16(); _MinorVersion = reader.ReadUInt16(); _Name = mod.StringFromRVA(reader, reader.ReadUInt32()); _OrdinalBase = reader.ReadUInt32(); _AddressTableEntries = reader.ReadUInt32(); _NamePointerCount = reader.ReadUInt32(); _ExportAddressTableRVA = reader.ReadUInt32(); _NamePointerRVA = reader.ReadUInt32(); _OrdinalRVA = reader.ReadUInt32(); }
public ImportDirectoryEntry(BinaryReader reader, MModule mod) { Start = reader.BaseStream.Position; uint iltRVA = reader.ReadUInt32(); _DateTimeStamp = reader.ReadUInt32(); _ForwarderChain = reader.ReadUInt32(); uint nameRVA = reader.ReadUInt32(); _Name = mod.StringFromRVA(reader, nameRVA); uint iatRVA = reader.ReadUInt32(); //can also get this from the PEHeader's data dirs Length = reader.BaseStream.Position - Start; long offs = reader.BaseStream.Position; // remember our position at the end of the imp dir entry record if (nameRVA == 0) { //indicate that this is not valid, because we reached the null terminating record //or because we are hopelessly lost _Name = null; return; } try { //get imp look table from RVA ArrayList arr; uint tableOffs, field; if (iltRVA != 0) { arr = new ArrayList(); tableOffs = mod.ModHeaders.Rva2Offset(iltRVA); reader.BaseStream.Position = tableOffs; field = reader.ReadUInt32(); while(field != 0) { arr.Add(new ImportAddress(field, reader, mod)); field = reader.ReadUInt32(); } _ImportLookupTable = (ImportAddress[])arr.ToArray(typeof(ImportAddress)); } //get imp Addr table from RVA if (iatRVA != 0) { arr = new ArrayList(); tableOffs = mod.ModHeaders.Rva2Offset(iatRVA); reader.BaseStream.Position = tableOffs; field = reader.ReadUInt32(); while(field != 0) { arr.Add(field); field = reader.ReadUInt32(); } _ImportAddressTable = (uint[])arr.ToArray(typeof(uint)); } } catch//(Exception e) { } finally { //restore stream pos reader.BaseStream.Position = offs; } }
public ImportAddress(uint n, BinaryReader reader, MModule mod) { if ((n & 0x80000000) != 0) _ByOrdinal = true; else _ByOrdinal = false; if (_ByOrdinal) { _Ordinal = n & 0x7fffffff; } else { uint nameOffs = n & 0x7fffffff; long offs = reader.BaseStream.Position; reader.BaseStream.Position = mod.ModHeaders.Rva2Offset(nameOffs); reader.ReadInt16();//hint byte b = reader.ReadByte(); while(b != 0) { _Name += (char) b; b = reader.ReadByte(); } reader.BaseStream.Position = offs; } }