public StringTable(string mod_name, metadata.AssemblyLoader al, target.Target t) { Label = mod_name + "_StringTable"; var corlib = al.GetAssembly("mscorlib"); StringObject = corlib.GetTypeSpec("System", "String"); var fs_len = corlib.GetFieldDefRow("m_stringLength", StringObject); length_offset = layout.Layout.GetFieldOffset(StringObject, fs_len, t, out var is_tls); var fs_start = corlib.GetFieldDefRow("m_firstChar", StringObject); string_obj_len = layout.Layout.GetFieldOffset(StringObject, fs_start, t, out is_tls); }
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); }