/**<summary>Get an assembly by name</summary>*/ public virtual MetadataStream GetAssembly(string name) { MetadataStream ms; if (name == "netstandard") { name = "mscorlib"; } var simple_name = StripPathAndExtension(name); if (cache.TryGetValue(simple_name, out ms)) { return(ms); } var s = LoadAssembly(name); if (s == null) { return(null); } PEFile p = new metadata.PEFile(); ms = p.Parse(s, this); cache[simple_name] = ms; return(ms); }
/**<summary>Get an assembly by name and version</summary>*/ public virtual MetadataStream GetAssembly(string name, int major, int minor, int build, int revision) { MetadataStream ms; var simple_name = StripPathAndExtension(name); if (cache.TryGetValue(simple_name, out ms)) { if (ms.MajorVersion == major && ms.MinorVersion == minor && ms.BuildVersion == build && ms.RevisionVersion == revision || RequireVersionMatch == false || major == -1) { return(ms); } } var s = LoadAssembly(name); if (s == null) { return(null); } PEFile p = new metadata.PEFile(); ms = p.Parse(s, this); if (ms == null) { return(null); } if (ms.MajorVersion == major && ms.MinorVersion == minor && ms.BuildVersion == build && ms.RevisionVersion == revision || RequireVersionMatch == false || major == -1) { cache[simple_name] = ms; return(ms); } return(null); }
public MetadataStream Parse(DataInterface file, AssemblyLoader al, bool fail_refs = true, bool is_pdb = false) { var m = new MetadataStream(); m.al = al; long mroot_offset; if (is_pdb) { mroot_offset = 0; pdbf = true; } else { pefh = new PE_File_Header(); uint pefh_start = file.ReadUInt(0x3c) + 4; uint pesig = file.ReadUInt((int)pefh_start - 4); System.Diagnostics.Debugger.Log(0, "metadata", "PEFile.Parse: PE Signature: " + pesig.ToString("X8")); pefh.NumberOfSections = file.ReadUShort((int)pefh_start + 2); pefh.Sections = new SectionHeader[pefh.NumberOfSections]; TimeSpan t = new TimeSpan(0, 0, (int)(file.ReadUInt((int)pefh_start + 4) & 0x7fffffff)); // csc /deterministic sets top bit - ignore for timestamp purposes System.Diagnostics.Debugger.Log(0, "metadata", "PEFile.Parse: t: " + ((int)file.ReadUInt((int)pefh_start + 4)).ToString()); pefh.TimeDateStamp = new DateTime(1970, 1, 1) + t; pefh.OptHeaderSize = file.ReadUShort((int)pefh_start + 16); if (pefh.OptHeaderSize < 224) { throw new Exception("PE optional header too small"); } pefh.Chars = file.ReadUShort((int)pefh_start + 18); if ((pefh.Chars & 0x3) != 0x2) { System.Diagnostics.Debugger.Log(0, "metadata", "PEFile.Parse: Invalid PE file header characteristics: " + pefh.Chars.ToString()); System.Diagnostics.Debugger.Break(); throw new Exception("Invalid PE file header characteristics"); } int pe32plusoffset = 0; ushort magic = file.ReadUShort((int)pefh_start + 20); if (magic == 0x20b) { pe32plusoffset = 16; } pefh.CliHeader = new DataDir(); pefh.CliHeader.RVA = file.ReadUInt((int)pefh_start + 228 + pe32plusoffset); pefh.CliHeader.Size = file.ReadUInt((int)pefh_start + 232 + pe32plusoffset); // Read the section headers uint sections_start = pefh_start + 20 + pefh.OptHeaderSize; for (uint i = 0; i < pefh.NumberOfSections; i++) { uint s_start = sections_start + i * 40; pefh.Sections[i] = new SectionHeader(); char[] w_str = new char[9]; for (int j = 0; j < 8; j++) { w_str[j] = (char)file.ReadByte((int)s_start + j); } w_str[8] = '\0'; pefh.Sections[i].Name = new String(w_str); pefh.Sections[i].Name = pefh.Sections[i].Name.Remove(pefh.Sections[i].Name.IndexOf("\0")); System.Diagnostics.Debugger.Log(0, "metadata", "PEFile.Parse: section name: " + pefh.Sections[i].Name + "\n"); pefh.Sections[i].VSize = file.ReadUInt((int)s_start + 8); pefh.Sections[i].VAddress = file.ReadUInt((int)s_start + 12); pefh.Sections[i].PSize = file.ReadUInt((int)s_start + 16); pefh.Sections[i].PAddress = file.ReadUInt((int)s_start + 20); pefh.Sections[i].Chars = file.ReadUInt((int)s_start + 36); } // Read the Cli header if (pefh.CliHeader.RVA == 0) { return(null); } long clih_offset = ResolveRVA(pefh.CliHeader.RVA); clih = new Cli_Header(); clih.Metadata.RVA = file.ReadUInt((int)clih_offset + 8); clih.Metadata.Size = file.ReadUInt((int)clih_offset + 12); clih.EntryPointToken = file.ReadUInt((int)clih_offset + 20); clih.Resources.RVA = file.ReadUInt((int)clih_offset + 24); clih.Resources.Size = file.ReadUInt((int)clih_offset + 28); m.entry_point_token = clih.EntryPointToken; System.Diagnostics.Debugger.Log(0, "metadata", "PEFile.Parse: CLI header parsed"); // First, read the metadata root mroot_offset = ResolveRVA(clih.Metadata.RVA); } uint sig = file.ReadUInt((int)mroot_offset); if (sig != 0x424A5342) { throw new Exception("Invalid metadata root"); } uint vstr_len = file.ReadUInt((int)mroot_offset + 12); m.VersionString = ReadSZ(file, (int)mroot_offset + 16); ushort nstr = file.ReadUShort((int)mroot_offset + 16 + (int)vstr_len + 2); int cur_offset = (int)mroot_offset + 16 + (int)vstr_len + 4; // Now, read the stream headers for (ushort i = 0; i < nstr; i++) { StreamHeader sh = new StreamHeader(); sh.Offset = file.ReadUInt(cur_offset); sh.FileOffset = ResolveRVA((is_pdb ? 0 : clih.Metadata.RVA) + sh.Offset); sh.Size = file.ReadUInt(cur_offset + 4); cur_offset += 8; StringBuilder sb = new StringBuilder(); while (true) { byte strb = file.ReadByte(cur_offset++); if (strb == 0) { break; } else { sb.Append((char)strb); } } while ((cur_offset & 0x3) != 0) { cur_offset++; } sh.Name = sb.ToString(); System.Diagnostics.Debugger.Log(0, "metadata", "PEFile.Parse: stream name: " + sh.Name); sh.di = file.Clone((int)sh.FileOffset); if (sh.Name == "#Strings") { m.sh_string = sh; } else if (sh.Name == "#US") { m.sh_us = sh; } else if (sh.Name == "#GUID") { m.sh_guid = sh; } else if (sh.Name == "#Blob") { m.sh_blob = sh; } else if (sh.Name == "#~") { m.sh_tables = sh; } else if (sh.Name == "#Pdb") { m.sh_pdb = sh; } else { System.Diagnostics.Debugger.Log(0, "metadata", "PEFile.Parse: unknown table \"" + sh.Name + "\""); throw new Exception("Unknown metadata table"); } } // Parse tables if (m.sh_tables != null) { var di = m.sh_tables.di; var maj = di.ReadByte(4); var min = di.ReadByte(5); System.Diagnostics.Debugger.Log(0, "metadata", "PEFile.Parse: parsing tables"); System.Diagnostics.Debugger.Log(0, "metadata", "PEFile.Parse: metadata table schema v" + maj.ToString() + "." + min.ToString()); // Determine size of indices into the heaps var heapsizes = di.ReadByte(6); if ((heapsizes & 0x1) == 0x1) { m.wide_string = true; } if ((heapsizes & 0x2) == 0x2) { m.wide_guid = true; } if ((heapsizes & 0x4) == 0x4) { m.wide_blob = true; } // Get list of valid tables var valid = di.ReadULong(8); int valid_count = 0; List <int> valid_tables = new List <int>(); for (int i = 0; i < 64; i++) { if (((valid >> i) & 0x1) == 0x1) { m.valid_tables[i] = true; valid_count++; valid_tables.Add(i); } } // Get number of rows in each table int table_id = 0; foreach (var valid_table in valid_tables) { m.table_rows[valid_table] = (int)di.ReadUInt(24 + 4 * table_id++); } // Interpret the schema of each table foreach (var valid_table in valid_tables) { InterpretSchema(valid_table, m); } // Determine start offsets of each table int offset = 24 + 4 * valid_count; foreach (var valid_table in valid_tables) { m.table_offsets[valid_table] = offset; offset += m.table_rows[valid_table] * m.table_entry_size[valid_table]; } } m.pef = this; m.file = file; /* Get this assembly name */ if (m.table_rows[MetadataStream.tid_Assembly] == 1) { m.assemblyName = m.GetStringEntry(MetadataStream.tid_Assembly, 1, 7); // Handle dotnet coreclr mscorlib having a different name if (m.assemblyName == "System.Private.CoreLib") { m.assemblyName = "mscorlib"; } System.Diagnostics.Debugger.Log(0, "metadata", "PEFile.Parse: current assembly is " + m.assemblyName); } /* Load up all referenced assemblies */ m.referenced_assemblies = new MetadataStream[m.table_rows[MetadataStream.tid_AssemblyRef]]; for (int i = 1; i <= m.table_rows[MetadataStream.tid_AssemblyRef]; i++) { var ass_name = m.GetStringEntry(MetadataStream.tid_AssemblyRef, i, 6); var maj = (int)m.GetIntEntry(MetadataStream.tid_AssemblyRef, i, 0); var min = (int)m.GetIntEntry(MetadataStream.tid_AssemblyRef, i, 1); var build = (int)m.GetIntEntry(MetadataStream.tid_AssemblyRef, i, 2); var rev = (int)m.GetIntEntry(MetadataStream.tid_AssemblyRef, i, 3); if (ass_name == "netstandard") { ass_name = "mscorlib"; maj = -1; } System.Diagnostics.Debugger.Log(0, "metadata", "PEFile.Parse: loading referenced assembly " + ass_name); if ((m.referenced_assemblies[i - 1] = al.GetAssembly(ass_name, maj, min, build, rev)) == null && fail_refs) { var ale = new AssemblyLoadException(); ale.ReferencedAssembly = new AssemblyLoadException.ALEAssembly { Name = ass_name, Major = maj, Minor = min, Revision = rev, Build = build }; ale.CurrentAssembly = new AssemblyLoadException.ALEAssembly { Name = m.AssemblyName, Major = m.MajorVersion, Minor = m.MinorVersion, Revision = m.RevisionVersion, Build = m.BuildVersion }; foreach (var la in al.LoadedAssemblies) { var cla = al.GetAssembly(la); var clale = new AssemblyLoadException.ALEAssembly { Name = cla.AssemblyName, Major = cla.MajorVersion, Minor = cla.MinorVersion, Revision = cla.RevisionVersion, Build = cla.BuildVersion }; ale.CurrentlyLoadedAssemblies.Add(clale); } throw ale; } } m.PatchMethodDefOwners(); m.PatchFieldDefOwners(); m.PatchFieldRVAs(); m.PatchClassLayouts(); m.PatchFieldConstants(); m.PatchGTypes(); if (m.assemblyName == "mscorlib") { m.is_corlib = true; m.PatchSimpleTypes(); } m.PatchNestedTypes(); m.PatchCustomAttrs(); m.LoadBuiltinTypes(); System.Diagnostics.Debugger.Log(0, "metadata", "PEFile.Parse: parsing complete"); /* Load up a .pdb sidecar file if necessary */ if (m.sh_pdb != null) { m.pdb = m; } else { var fname = file.Name; if (fname != null) { if (fname.EndsWith(".dll") || fname.EndsWith(".exe")) { fname = fname.Substring(0, fname.Length - 4); } var pdbf = al.LoadAssembly(fname + ".pdb"); if (pdbf != null) { var pef = new metadata.PEFile(); try { m.pdb = pef.Parse(pdbf, al, true, true); } catch (Exception) { m.pdb = null; } } } } return(m); }