/// <summary> /// Initializes the fields of the R2RHeader /// </summary> /// <param name="image">PE image</param> /// <param name="rva">Relative virtual address of the ReadyToRun header</param> /// <param name="curOffset">Index in the image byte array to the start of the ReadyToRun header</param> /// <exception cref="BadImageFormatException">The signature must be 0x00525452</exception> public R2RHeader(byte[] image, uint rva, int curOffset) { RelativeVirtualAddress = rva; Offset = curOffset; byte[] signature = new byte[sizeof(uint)]; Array.Copy(image, curOffset, signature, 0, sizeof(uint)); SignatureString = System.Text.Encoding.UTF8.GetString(signature); Signature = (uint)GetField(image, ref curOffset, sizeof(uint)); if (Signature != READYTORUN_SIGNATURE) { throw new System.BadImageFormatException("Incorrect R2R header signature"); } MajorVersion = (ushort)GetField(image, ref curOffset, sizeof(ushort)); MinorVersion = (ushort)GetField(image, ref curOffset, sizeof(ushort)); Flags = (uint)GetField(image, ref curOffset, sizeof(uint)); NumberOfSections = (uint)GetField(image, ref curOffset, sizeof(uint)); Sections = new R2RSection[NumberOfSections]; for (int i = 0; i < NumberOfSections; i++) { Sections[i] = new R2RSection((int)GetField(image, ref curOffset, sizeof(int)), (uint)GetField(image, ref curOffset, sizeof(uint)), (uint)GetField(image, ref curOffset, sizeof(uint))); } Size = curOffset - Offset; }
private void ParseAvailableTypes() { R2RSection availableTypesSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_AVAILABLE_TYPES]; int availableTypesOffset = GetOffset(availableTypesSection.RelativeVirtualAddress); NativeParser parser = new NativeParser(Image, (uint)availableTypesOffset); NativeHashtable availableTypes = new NativeHashtable(Image, parser); NativeHashtable.AllEntriesEnumerator allEntriesEnum = availableTypes.EnumerateAllEntries(); NativeParser curParser = allEntriesEnum.GetNext(); while (!curParser.IsNull()) { uint rid = curParser.GetUnsigned(); rid = rid >> 1; TypeDefinitionHandle typeDefHandle = MetadataTokens.TypeDefinitionHandle((int)rid); TypeDefinition typeDef = _mdReader.GetTypeDefinition(typeDefHandle); string name = _mdReader.GetString(typeDef.Name); if (!typeDef.Namespace.IsNil) { name = _mdReader.GetString(typeDef.Namespace) + "." + name; } AvailableTypes.Add(name); curParser = allEntriesEnum.GetNext(); } }
/// <summary> /// Initializes the fields of the R2RHeader and R2RMethods /// </summary> /// <param name="filename">PE image</param> /// <exception cref="BadImageFormatException">The Cor header flag must be ILLibrary</exception> public unsafe R2RReader(string filename) { Filename = filename; Image = File.ReadAllBytes(filename); fixed(byte *p = Image) { IntPtr ptr = (IntPtr)p; _peReader = new PEReader(p, Image.Length); IsR2R = (_peReader.PEHeaders.CorHeader.Flags == CorFlags.ILLibrary); if (!IsR2R) { throw new BadImageFormatException("The file is not a ReadyToRun image"); } Machine = _peReader.PEHeaders.CoffHeader.Machine; ImageBase = _peReader.PEHeaders.PEHeader.ImageBase; // initialize R2RHeader DirectoryEntry r2rHeaderDirectory = _peReader.PEHeaders.CorHeader.ManagedNativeHeaderDirectory; int r2rHeaderOffset = GetOffset(r2rHeaderDirectory.RelativeVirtualAddress); R2RHeader = new R2RHeader(Image, r2rHeaderDirectory.RelativeVirtualAddress, r2rHeaderOffset); if (r2rHeaderDirectory.Size != R2RHeader.Size) { throw new BadImageFormatException("The calculated size of the R2RHeader doesn't match the size saved in the ManagedNativeHeaderDirectory"); } if (_peReader.HasMetadata) { _mdReader = _peReader.GetMetadataReader(); R2RMethods = new List <R2RMethod>(); if (R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS)) { int runtimeFunctionSize = CalculateRuntimeFunctionSize(); R2RSection runtimeFunctionSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS]; uint nRuntimeFunctions = (uint)(runtimeFunctionSection.Size / runtimeFunctionSize); int runtimeFunctionOffset = GetOffset(runtimeFunctionSection.RelativeVirtualAddress); bool[] isEntryPoint = new bool[nRuntimeFunctions]; // initialize R2RMethods ParseMethodDefEntrypoints(isEntryPoint); ParseInstanceMethodEntrypoints(isEntryPoint); ParseRuntimeFunctions(isEntryPoint, runtimeFunctionOffset, runtimeFunctionSize); } AvailableTypes = new List <string>(); ParseAvailableTypes(); CompileIdentifier = ParseCompilerIdentifier(); ImportSections = new List <R2RImportSection>(); ParseImportSections(); } } }
internal override void DumpSectionContents(R2RSection section, XmlNode parentNode) { XmlNode contentsNode = XmlDocument.CreateNode("element", "Contents", ""); parentNode.AppendChild(contentsNode); switch (section.Type) { case R2RSection.SectionType.READYTORUN_SECTION_AVAILABLE_TYPES: int availableTypesId = 0; foreach (string name in _r2r.AvailableTypes) { AddXMLNode("AvailableType", name, contentsNode, $"{availableTypesId++}"); } break; case R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS: int rtfOffset = _r2r.GetOffset(section.RelativeVirtualAddress); int rtfEndOffset = rtfOffset + section.Size; int rtfIndex = 0; while (rtfOffset < rtfEndOffset) { uint rva = NativeReader.ReadUInt32(_r2r.Image, ref rtfOffset); AddXMLNode($"id{rtfIndex}", $"0x{rva:X8}", contentsNode, $"{rtfIndex}"); rtfIndex++; } break; case R2RSection.SectionType.READYTORUN_SECTION_COMPILER_IDENTIFIER: AddXMLNode("CompilerIdentifier", _r2r.CompilerIdentifier, contentsNode); break; case R2RSection.SectionType.READYTORUN_SECTION_IMPORT_SECTIONS: foreach (R2RImportSection importSection in _r2r.ImportSections) { Serialize(importSection, contentsNode); if (_raw && importSection.Entries.Count != 0) { if (importSection.SectionRVA != 0) { DumpBytes(importSection.SectionRVA, (uint)importSection.SectionSize, contentsNode, "SectionBytes"); } if (importSection.SignatureRVA != 0) { DumpBytes(importSection.SignatureRVA, (uint)importSection.Entries.Count * sizeof(int), contentsNode, "SignatureBytes"); } if (importSection.AuxiliaryDataRVA != 0) { DumpBytes(importSection.AuxiliaryDataRVA, (uint)importSection.AuxiliaryData.Size, contentsNode, "AuxiliaryDataBytes"); } } foreach (R2RImportSection.ImportSectionEntry entry in importSection.Entries) { Serialize(entry, contentsNode); } } break; } }
/// <summary> /// Returns true if the name or value of the ReadyToRunSectionType of <param>section</param> matches <param>query</param> /// </summary> /// <remarks>Case-insensitive</remarks> private bool Match(R2RSection section, string query) { int queryInt; bool isNum = ArgStringToInt(query, out queryInt); string typeName = Enum.GetName(typeof(R2RSection.SectionType), section.Type); return((isNum && (int)section.Type == queryInt) || typeName.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0); }
public static void WriteTo(this R2RSection theThis, TextWriter writer, DumpOptions options) { writer.WriteLine($"Type: {Enum.GetName(typeof(R2RSection.SectionType), theThis.Type)} ({theThis.Type:D})"); if (!options.Naked) { writer.WriteLine($"RelativeVirtualAddress: 0x{theThis.RelativeVirtualAddress:X8}"); } writer.WriteLine($"Size: {theThis.Size} bytes"); }
/// <summary> /// Dumps one R2RSection /// </summary> private void DumpSection(R2RReader r2r, R2RSection section) { WriteSubDivider(); _writer.WriteLine(section.ToString()); if (_raw) { DumpBytes(r2r, section.RelativeVirtualAddress, (uint)section.Size); } }
private string ParseCompilerIdentifier() { R2RSection compilerIdentifierSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_COMPILER_IDENTIFIER]; byte[] identifier = new byte[compilerIdentifierSection.Size]; int identifierOffset = GetOffset(compilerIdentifierSection.RelativeVirtualAddress); Array.Copy(Image, identifierOffset, identifier, 0, compilerIdentifierSection.Size); return(Encoding.UTF8.GetString(identifier)); }
/// <summary> /// Iterates through a native hashtable to get all RIDs /// </summary> private void ParseAvailableTypes() { if (!R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_AVAILABLE_TYPES)) { return; } HashSet <uint> added = new HashSet <uint>(); R2RSection availableTypesSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_AVAILABLE_TYPES]; int availableTypesOffset = GetOffset(availableTypesSection.RelativeVirtualAddress); NativeParser parser = new NativeParser(Image, (uint)availableTypesOffset); NativeHashtable availableTypes = new NativeHashtable(Image, parser, (uint)(availableTypesOffset + availableTypesSection.Size)); NativeHashtable.AllEntriesEnumerator allEntriesEnum = availableTypes.EnumerateAllEntries(); NativeParser curParser = allEntriesEnum.GetNext(); while (!curParser.IsNull()) { uint rid = curParser.GetUnsigned(); rid = rid >> 1; if (added.Contains(rid)) { continue; } TypeDefinitionHandle typeDefHandle = MetadataTokens.TypeDefinitionHandle((int)rid); string typeDefName = MetadataNameFormatter.FormatHandle(MetadataReader, typeDefHandle); ExportedTypeHandle exportedTypeHandle = MetadataTokens.ExportedTypeHandle((int)rid); string exportedTypeName = GetExportedTypeFullName(MetadataReader, exportedTypeHandle); if (typeDefName == null && exportedTypeName == null) { R2RDump.WriteWarning($"AvailableType with rid {rid} is not a TypeDef or ExportedType"); } if (typeDefName != null) { AvailableTypes.Add(typeDefName); added.Add(rid); } if (exportedTypeName != null) { AvailableTypes.Add("exported " + exportedTypeName); added.Add(rid); } curParser = allEntriesEnum.GetNext(); } }
/// <summary> /// Dumps one R2RSection /// </summary> internal override void DumpSection(R2RSection section, XmlNode parentNode) { XmlNode sectionNode = _xmlDocument.CreateNode("element", "Section", ""); parentNode.AppendChild(sectionNode); Serialize(section, sectionNode); if (_raw) { DumpBytes(section.RelativeVirtualAddress, (uint)section.Size, sectionNode); } if (_sectionContents) { DumpSectionContents(section, sectionNode); } }
/// <summary> /// Dumps one R2RSection /// </summary> internal override void DumpSection(R2RSection section, XmlNode parentNode = null) { WriteSubDivider(); _writer.WriteLine(section.ToString()); if (_raw) { DumpBytes(section.RelativeVirtualAddress, (uint)section.Size); SkipLine(); } if (_sectionContents) { DumpSectionContents(section); SkipLine(); } }
/// <summary> /// Dumps one R2RSection /// </summary> internal override void DumpSection(R2RSection section, XmlNode parentNode = null) { WriteSubDivider(); section.WriteTo(_writer, _options); if (_options.Raw) { DumpBytes(section.RelativeVirtualAddress, (uint)section.Size); SkipLine(); } if (_options.SectionContents) { DumpSectionContents(section, parentNode); SkipLine(); } }
/// <summary> /// Initialize generic method instances with argument types and runtime function indices from InstanceMethodEntrypoints /// </summary> private void ParseInstanceMethodEntrypoints(bool[] isEntryPoint) { if (!R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS)) { return; } R2RSection instMethodEntryPointSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS]; int instMethodEntryPointsOffset = GetOffset(instMethodEntryPointSection.RelativeVirtualAddress); NativeParser parser = new NativeParser(Image, (uint)instMethodEntryPointsOffset); NativeHashtable instMethodEntryPoints = new NativeHashtable(Image, parser, (uint)(instMethodEntryPointsOffset + instMethodEntryPointSection.Size)); NativeHashtable.AllEntriesEnumerator allEntriesEnum = instMethodEntryPoints.EnumerateAllEntries(); NativeParser curParser = allEntriesEnum.GetNext(); while (!curParser.IsNull()) { uint methodFlags = curParser.GetCompressedData(); uint rid = curParser.GetCompressedData(); if ((methodFlags & (byte)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_MethodInstantiation) != 0) { uint nArgs = curParser.GetCompressedData(); CorElementType[] args = new CorElementType[nArgs]; uint[] tokens = new uint[nArgs]; for (int i = 0; i < nArgs; i++) { args[i] = (CorElementType)curParser.GetByte(); if (args[i] == CorElementType.ELEMENT_TYPE_VALUETYPE) { tokens[i] = curParser.GetCompressedData(); tokens[i] = (tokens[i] >> 2); } } int runtimeFunctionId; FixupCell[] fixups; GetRuntimeFunctionIndexFromOffset((int)curParser.Offset, out runtimeFunctionId, out fixups); R2RMethod method = new R2RMethod(R2RMethods.Count, MetadataReader, rid, runtimeFunctionId, args, tokens, fixups); if (method.EntryPointRuntimeFunctionId >= 0 && method.EntryPointRuntimeFunctionId < isEntryPoint.Length) { isEntryPoint[method.EntryPointRuntimeFunctionId] = true; } R2RMethods.Add(method); } curParser = allEntriesEnum.GetNext(); } }
/// <summary> /// Dumps one R2RSection /// </summary> internal override void DumpSection(R2RSection section, XmlNode parentNode) { XmlNode sectionNode = XmlDocument.CreateNode("element", "Section", ""); AddXMLAttribute(sectionNode, "Index", $"{section.Type}"); parentNode.AppendChild(sectionNode); Serialize(section, sectionNode); if (_options.Raw) { DumpBytes(section.RelativeVirtualAddress, (uint)section.Size, sectionNode); } if (_options.SectionContents) { DumpSectionContents(section, sectionNode); } }
/// <summary> /// Initialize generic method instances with argument types and runtime function indices from InstanceMethodEntrypoints /// </summary> private void ParseInstanceMethodEntrypoints(bool[] isEntryPoint) { if (!R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS)) { return; } R2RSection instMethodEntryPointSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS]; int instMethodEntryPointsOffset = GetOffset(instMethodEntryPointSection.RelativeVirtualAddress); NativeParser parser = new NativeParser(Image, (uint)instMethodEntryPointsOffset); NativeHashtable instMethodEntryPoints = new NativeHashtable(Image, parser, (uint)(instMethodEntryPointsOffset + instMethodEntryPointSection.Size)); NativeHashtable.AllEntriesEnumerator allEntriesEnum = instMethodEntryPoints.EnumerateAllEntries(); NativeParser curParser = allEntriesEnum.GetNext(); while (!curParser.IsNull()) { uint methodFlags = curParser.GetCompressedData(); uint rid = curParser.GetCompressedData(); if ((methodFlags & (byte)R2RMethod.EncodeMethodSigFlags.ENCODE_METHOD_SIG_MethodInstantiation) != 0) { uint nArgs = curParser.GetCompressedData(); R2RMethod.GenericElementTypes[] args = new R2RMethod.GenericElementTypes[nArgs]; uint[] tokens = new uint[nArgs]; for (int i = 0; i < nArgs; i++) { args[i] = (R2RMethod.GenericElementTypes)curParser.GetByte(); if (args[i] == R2RMethod.GenericElementTypes.ValueType) { tokens[i] = curParser.GetCompressedData(); tokens[i] = (tokens[i] >> 2); } } int id = GetEntryPointIdFromOffset((int)curParser.Offset); R2RMethod method = new R2RMethod(_mdReader, rid, id, args, tokens); if (method.EntryPointRuntimeFunctionId >= 0 && method.EntryPointRuntimeFunctionId < isEntryPoint.Length) { isEntryPoint[method.EntryPointRuntimeFunctionId] = true; } R2RMethods.Add(method); } curParser = allEntriesEnum.GetNext(); } }
private void ParseAvailableTypes() { R2RSection availableTypesSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_AVAILABLE_TYPES]; int availableTypesOffset = GetOffset(availableTypesSection.RelativeVirtualAddress); NativeParser parser = new NativeParser(Image, (uint)availableTypesOffset); NativeHashtable availableTypes = new NativeHashtable(Image, parser, (uint)(availableTypesOffset + availableTypesSection.Size)); NativeHashtable.AllEntriesEnumerator allEntriesEnum = availableTypes.EnumerateAllEntries(); NativeParser curParser = allEntriesEnum.GetNext(); while (!curParser.IsNull()) { uint rid = curParser.GetUnsigned(); rid = rid >> 1; TypeDefinitionHandle typeDefHandle = MetadataTokens.TypeDefinitionHandle((int)rid); AvailableTypes.Add(GetTypeDefFullName(_mdReader, typeDefHandle)); curParser = allEntriesEnum.GetNext(); } }
/// <summary> /// Iterates through a native hashtable to get all RIDs /// </summary> private void ParseAvailableTypes() { if (!R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_AVAILABLE_TYPES)) { return; } R2RSection availableTypesSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_AVAILABLE_TYPES]; int availableTypesOffset = GetOffset(availableTypesSection.RelativeVirtualAddress); NativeParser parser = new NativeParser(Image, (uint)availableTypesOffset); NativeHashtable availableTypes = new NativeHashtable(Image, parser, (uint)(availableTypesOffset + availableTypesSection.Size)); NativeHashtable.AllEntriesEnumerator allEntriesEnum = availableTypes.EnumerateAllEntries(); NativeParser curParser = allEntriesEnum.GetNext(); while (!curParser.IsNull()) { uint rid = curParser.GetUnsigned(); bool isExportedType = (rid & 1) != 0; rid = rid >> 1; if (isExportedType) { ExportedTypeHandle exportedTypeHandle = MetadataTokens.ExportedTypeHandle((int)rid); string exportedTypeName = GetExportedTypeFullName(MetadataReader, exportedTypeHandle); AvailableTypes.Add("exported " + exportedTypeName); } else { TypeDefinitionHandle typeDefHandle = MetadataTokens.TypeDefinitionHandle((int)rid); string typeDefName = MetadataNameFormatter.FormatHandle(MetadataReader, typeDefHandle); AvailableTypes.Add(typeDefName); } curParser = allEntriesEnum.GetNext(); } }
private void ParseDebugInfo() { if (!R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_DEBUG_INFO)) { return; } R2RSection debugInfoSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_DEBUG_INFO]; int debugInfoSectionOffset = GetOffset(debugInfoSection.RelativeVirtualAddress); NativeArray debugInfoArray = new NativeArray(Image, (uint)debugInfoSectionOffset); for (uint i = 0; i < debugInfoArray.GetCount(); ++i) { int offset = 0; if (!debugInfoArray.TryGetAt(Image, i, ref offset)) { continue; } var debugInfo = new DebugInfo(Image, offset, Machine); _runtimeFunctionToDebugInfo.Add((int)i, debugInfo); } }
/// <summary> /// Initializes the fields of the R2RHeader /// </summary> /// <param name="image">PE image</param> /// <param name="rva">Relative virtual address of the ReadyToRun header</param> /// <param name="curOffset">Index in the image byte array to the start of the ReadyToRun header</param> /// <exception cref="BadImageFormatException">The signature must be 0x00525452</exception> public R2RHeader(byte[] image, int rva, int curOffset) { RelativeVirtualAddress = rva; int startOffset = curOffset; byte[] signature = new byte[sizeof(uint)]; Array.Copy(image, curOffset, signature, 0, sizeof(uint)); SignatureString = System.Text.Encoding.UTF8.GetString(signature); Signature = NativeReader.ReadUInt32(image, ref curOffset); if (Signature != READYTORUN_SIGNATURE) { throw new System.BadImageFormatException("Incorrect R2R header signature"); } MajorVersion = NativeReader.ReadUInt16(image, ref curOffset); MinorVersion = NativeReader.ReadUInt16(image, ref curOffset); Flags = NativeReader.ReadUInt32(image, ref curOffset); int nSections = NativeReader.ReadInt32(image, ref curOffset); Sections = new Dictionary <R2RSection.SectionType, R2RSection>(); for (int i = 0; i < nSections; i++) { int type = NativeReader.ReadInt32(image, ref curOffset); var sectionType = (R2RSection.SectionType)type; if (!Enum.IsDefined(typeof(R2RSection.SectionType), type)) { R2RDump.OutputWarning("Invalid ReadyToRun section type"); } Sections[sectionType] = new R2RSection(sectionType, NativeReader.ReadInt32(image, ref curOffset), NativeReader.ReadInt32(image, ref curOffset)); } Size = curOffset - startOffset; }
/// <summary> /// Initializes the fields of the R2RHeader /// </summary> /// <param name="filename">PE image</param> /// <exception cref="BadImageFormatException">The Cor header flag must be ILLibrary</exception> public unsafe R2RReader(string filename) { Filename = filename; _image = File.ReadAllBytes(filename); fixed(byte *p = _image) { IntPtr ptr = (IntPtr)p; peReader = new PEReader(p, _image.Length); IsR2R = (peReader.PEHeaders.CorHeader.Flags == CorFlags.ILLibrary); if (!IsR2R) { throw new BadImageFormatException("The file is not a ReadyToRun image"); } Machine = peReader.PEHeaders.CoffHeader.Machine; ImageBase = peReader.PEHeaders.PEHeader.ImageBase; // initialize R2RHeader DirectoryEntry r2rHeaderDirectory = peReader.PEHeaders.CorHeader.ManagedNativeHeaderDirectory; int r2rHeaderOffset = GetOffset(r2rHeaderDirectory.RelativeVirtualAddress); R2RHeader = new R2RHeader(_image, r2rHeaderDirectory.RelativeVirtualAddress, r2rHeaderOffset); if (r2rHeaderDirectory.Size != R2RHeader.Size) { throw new BadImageFormatException("The calculated size of the R2RHeader doesn't match the size saved in the ManagedNativeHeaderDirectory"); } // initialize R2RMethods if (peReader.HasMetadata) { MetadataReader mdReader = peReader.GetMetadataReader(); int runtimeFunctionSize = 2; if (Machine == Machine.Amd64) { runtimeFunctionSize = 3; } runtimeFunctionSize *= sizeof(int); R2RSection runtimeFunctionSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS]; uint nRuntimeFunctions = (uint)(runtimeFunctionSection.Size / runtimeFunctionSize); int runtimeFunctionOffset = GetOffset(runtimeFunctionSection.RelativeVirtualAddress); bool[] isEntryPoint = new bool[nRuntimeFunctions]; for (int i = 0; i < nRuntimeFunctions; i++) { isEntryPoint[i] = false; } // initialize R2RMethods with method signatures from MethodDefHandle, and runtime function indices from MethodDefEntryPoints int methodDefEntryPointsRVA = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_METHODDEF_ENTRYPOINTS].RelativeVirtualAddress; int methodDefEntryPointsOffset = GetOffset(methodDefEntryPointsRVA); NativeArray methodEntryPoints = new NativeArray(_image, (uint)methodDefEntryPointsOffset); uint nMethodEntryPoints = methodEntryPoints.GetCount(); R2RMethods = new List <R2RMethod>(); for (uint rid = 1; rid <= nMethodEntryPoints; rid++) { int offset = 0; if (methodEntryPoints.TryGetAt(_image, rid - 1, ref offset)) { R2RMethod method = new R2RMethod(_image, mdReader, rid, GetEntryPointIdFromOffset(offset), null, null); if (method.EntryPointRuntimeFunctionId < 0 || method.EntryPointRuntimeFunctionId >= nRuntimeFunctions) { throw new BadImageFormatException("EntryPointRuntimeFunctionId out of bounds"); } isEntryPoint[method.EntryPointRuntimeFunctionId] = true; R2RMethods.Add(method); } } // instance method table R2RSection instMethodEntryPointSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS]; int instMethodEntryPointsOffset = GetOffset(instMethodEntryPointSection.RelativeVirtualAddress); NativeParser parser = new NativeParser(_image, (uint)instMethodEntryPointsOffset); NativeHashtable instMethodEntryPoints = new NativeHashtable(_image, parser); NativeHashtable.AllEntriesEnumerator allEntriesEnum = instMethodEntryPoints.EnumerateAllEntries(); NativeParser curParser = allEntriesEnum.GetNext(); while (!curParser.IsNull()) { byte methodFlags = curParser.GetByte(); byte rid = curParser.GetByte(); if ((methodFlags & (byte)R2RMethod.EncodeMethodSigFlags.ENCODE_METHOD_SIG_MethodInstantiation) != 0) { byte nArgs = curParser.GetByte(); R2RMethod.GenericElementTypes[] args = new R2RMethod.GenericElementTypes[nArgs]; uint[] tokens = new uint[nArgs]; for (int i = 0; i < nArgs; i++) { args[i] = (R2RMethod.GenericElementTypes)curParser.GetByte(); if (args[i] == R2RMethod.GenericElementTypes.ValueType) { tokens[i] = curParser.GetByte(); tokens[i] = (tokens[i] >> 2); } } uint id = curParser.GetUnsigned(); id = id >> 1; R2RMethod method = new R2RMethod(_image, mdReader, rid, (int)id, args, tokens); if (method.EntryPointRuntimeFunctionId >= 0 && method.EntryPointRuntimeFunctionId < nRuntimeFunctions) { isEntryPoint[method.EntryPointRuntimeFunctionId] = true; } R2RMethods.Add(method); } curParser = allEntriesEnum.GetNext(); } // get the RVAs of the runtime functions for each method int curOffset = 0; foreach (R2RMethod method in R2RMethods) { int runtimeFunctionId = method.EntryPointRuntimeFunctionId; if (runtimeFunctionId == -1) { continue; } curOffset = runtimeFunctionOffset + runtimeFunctionId * runtimeFunctionSize; do { int startRva = NativeReader.ReadInt32(_image, ref curOffset); int endRva = -1; if (Machine == Machine.Amd64) { endRva = NativeReader.ReadInt32(_image, ref curOffset); } int unwindRva = NativeReader.ReadInt32(_image, ref curOffset); method.RuntimeFunctions.Add(new RuntimeFunction(runtimeFunctionId, startRva, endRva, unwindRva)); runtimeFunctionId++; }while (runtimeFunctionId < nRuntimeFunctions && !isEntryPoint[runtimeFunctionId]); } } } }
/// <summary> /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/zap/zapimport.cpp">ZapImportSectionsTable::Save</a> /// </summary> private void ParseImportSections() { if (!R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_IMPORT_SECTIONS)) { return; } R2RSection importSectionsSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_IMPORT_SECTIONS]; int offset = GetOffset(importSectionsSection.RelativeVirtualAddress); int endOffset = offset + importSectionsSection.Size; while (offset < endOffset) { int rva = NativeReader.ReadInt32(Image, ref offset); int sectionOffset = GetOffset(rva); int startOffset = sectionOffset; int size = NativeReader.ReadInt32(Image, ref offset); CorCompileImportFlags flags = (CorCompileImportFlags)NativeReader.ReadUInt16(Image, ref offset); byte type = NativeReader.ReadByte(Image, ref offset); byte entrySize = NativeReader.ReadByte(Image, ref offset); if (entrySize == 0) { switch (Machine) { case Machine.I386: case Machine.ArmThumb2: entrySize = 4; break; case Machine.Amd64: case Machine.IA64: case Machine.Arm64: entrySize = 8; break; default: throw new NotImplementedException(Machine.ToString()); } } int entryCount = 0; if (entrySize != 0) { entryCount = size / entrySize; } int signatureRVA = NativeReader.ReadInt32(Image, ref offset); int signatureOffset = 0; if (signatureRVA != 0) { signatureOffset = GetOffset(signatureRVA); } List <R2RImportSection.ImportSectionEntry> entries = new List <R2RImportSection.ImportSectionEntry>(); for (int i = 0; i < entryCount; i++) { int entryOffset = sectionOffset - startOffset; long section = NativeReader.ReadInt64(Image, ref sectionOffset); uint sigRva = NativeReader.ReadUInt32(Image, ref signatureOffset); int sigOffset = GetOffset((int)sigRva); string cellName = MetadataNameFormatter.FormatSignature(this, sigOffset); entries.Add(new R2RImportSection.ImportSectionEntry(entries.Count, entryOffset, section, sigRva, cellName)); ImportCellNames.Add(rva + entrySize * i, cellName); } int auxDataRVA = NativeReader.ReadInt32(Image, ref offset); int auxDataOffset = 0; if (auxDataRVA != 0) { auxDataOffset = GetOffset(auxDataRVA); } ImportSections.Add(new R2RImportSection(ImportSections.Count, Image, rva, size, flags, type, entrySize, signatureRVA, entries, auxDataRVA, auxDataOffset, Machine, R2RHeader.MajorVersion)); } }
/// <summary> /// Initializes the fields of the R2RHeader and R2RMethods /// </summary> /// <param name="filename">PE image</param> /// <exception cref="BadImageFormatException">The Cor header flag must be ILLibrary</exception> public unsafe R2RReader(string filename) { Filename = filename; Image = File.ReadAllBytes(filename); fixed(byte *p = Image) { IntPtr ptr = (IntPtr)p; PEReader = new PEReader(p, Image.Length); IsR2R = ((PEReader.PEHeaders.CorHeader.Flags & CorFlags.ILLibrary) != 0); if (!IsR2R) { throw new BadImageFormatException("The file is not a ReadyToRun image"); } uint machine = (uint)PEReader.PEHeaders.CoffHeader.Machine; OS = OperatingSystem.Unknown; foreach (OperatingSystem os in Enum.GetValues(typeof(OperatingSystem))) { Machine = (Machine)(machine ^ (uint)os); if (Enum.IsDefined(typeof(Machine), Machine)) { OS = os; break; } } if (OS == OperatingSystem.Unknown) { throw new BadImageFormatException($"Invalid Machine: {machine}"); } ImageBase = PEReader.PEHeaders.PEHeader.ImageBase; // initialize R2RHeader DirectoryEntry r2rHeaderDirectory = PEReader.PEHeaders.CorHeader.ManagedNativeHeaderDirectory; int r2rHeaderOffset = GetOffset(r2rHeaderDirectory.RelativeVirtualAddress); R2RHeader = new R2RHeader(Image, r2rHeaderDirectory.RelativeVirtualAddress, r2rHeaderOffset); if (r2rHeaderDirectory.Size != R2RHeader.Size) { throw new BadImageFormatException("The calculated size of the R2RHeader doesn't match the size saved in the ManagedNativeHeaderDirectory"); } if (PEReader.HasMetadata) { MetadataReader = PEReader.GetMetadataReader(); ParseDebugInfo(); if (R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_EXCEPTION_INFO)) { R2RSection exceptionInfoSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_EXCEPTION_INFO]; EHLookupTable = new EHLookupTable(Image, GetOffset(exceptionInfoSection.RelativeVirtualAddress), exceptionInfoSection.Size); } R2RMethods = new List <R2RMethod>(); if (R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS)) { int runtimeFunctionSize = CalculateRuntimeFunctionSize(); R2RSection runtimeFunctionSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS]; uint nRuntimeFunctions = (uint)(runtimeFunctionSection.Size / runtimeFunctionSize); int runtimeFunctionOffset = GetOffset(runtimeFunctionSection.RelativeVirtualAddress); bool[] isEntryPoint = new bool[nRuntimeFunctions]; // initialize R2RMethods ParseMethodDefEntrypoints(isEntryPoint); ParseInstanceMethodEntrypoints(isEntryPoint); ParseRuntimeFunctions(isEntryPoint, runtimeFunctionOffset, runtimeFunctionSize); } AvailableTypes = new List <string>(); ParseAvailableTypes(); CompilerIdentifier = ParseCompilerIdentifier(); ImportSections = new List <R2RImportSection>(); ImportCellNames = new Dictionary <int, string>(); ParseImportSections(); } } }
internal override void DumpSectionContents(R2RSection section, XmlNode parentNode = null) { switch (section.Type) { case R2RSection.SectionType.READYTORUN_SECTION_AVAILABLE_TYPES: if (!_options.Naked) { uint availableTypesSectionOffset = (uint)_r2r.GetOffset(section.RelativeVirtualAddress); NativeParser availableTypesParser = new NativeParser(_r2r.Image, availableTypesSectionOffset); NativeHashtable availableTypes = new NativeHashtable(_r2r.Image, availableTypesParser, (uint)(availableTypesSectionOffset + section.Size)); _writer.WriteLine(availableTypes.ToString()); } foreach (string name in _r2r.AvailableTypes) { _writer.WriteLine(name); } break; case R2RSection.SectionType.READYTORUN_SECTION_METHODDEF_ENTRYPOINTS: if (!_options.Naked) { NativeArray methodEntryPoints = new NativeArray(_r2r.Image, (uint)_r2r.GetOffset(section.RelativeVirtualAddress)); _writer.Write(methodEntryPoints.ToString()); } break; case R2RSection.SectionType.READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS: if (!_options.Naked) { uint instanceSectionOffset = (uint)_r2r.GetOffset(section.RelativeVirtualAddress); NativeParser instanceParser = new NativeParser(_r2r.Image, instanceSectionOffset); NativeHashtable instMethodEntryPoints = new NativeHashtable(_r2r.Image, instanceParser, (uint)(instanceSectionOffset + section.Size)); _writer.Write(instMethodEntryPoints.ToString()); _writer.WriteLine(); } foreach (InstanceMethod instanceMethod in _r2r.InstanceMethods) { _writer.WriteLine($@"0x{instanceMethod.Bucket:X2} -> {instanceMethod.Method.SignatureString}"); } break; case R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS: int rtfOffset = _r2r.GetOffset(section.RelativeVirtualAddress); int rtfEndOffset = rtfOffset + section.Size; int rtfIndex = 0; while (rtfOffset < rtfEndOffset) { int startRva = NativeReader.ReadInt32(_r2r.Image, ref rtfOffset); int endRva = -1; if (_r2r.Machine == Machine.Amd64) { endRva = NativeReader.ReadInt32(_r2r.Image, ref rtfOffset); } int unwindRva = NativeReader.ReadInt32(_r2r.Image, ref rtfOffset); _writer.WriteLine($"Index: {rtfIndex}"); _writer.WriteLine($"\tStartRva: 0x{startRva:X8}"); if (endRva != -1) { _writer.WriteLine($"\tEndRva: 0x{endRva:X8}"); } _writer.WriteLine($"\tUnwindRva: 0x{unwindRva:X8}"); rtfIndex++; } break; case R2RSection.SectionType.READYTORUN_SECTION_COMPILER_IDENTIFIER: _writer.WriteLine(_r2r.CompilerIdentifier); break; case R2RSection.SectionType.READYTORUN_SECTION_IMPORT_SECTIONS: if (_options.Naked) { DumpNakedImportSections(); } else { foreach (R2RImportSection importSection in _r2r.ImportSections) { importSection.WriteTo(_writer); if (_options.Raw && importSection.Entries.Count != 0) { if (importSection.SectionRVA != 0) { _writer.WriteLine("Section Bytes:"); DumpBytes(importSection.SectionRVA, (uint)importSection.SectionSize); } if (importSection.SignatureRVA != 0) { _writer.WriteLine("Signature Bytes:"); DumpBytes(importSection.SignatureRVA, (uint)importSection.Entries.Count * sizeof(int)); } if (importSection.AuxiliaryDataRVA != 0 && importSection.AuxiliaryDataSize != 0) { _writer.WriteLine("AuxiliaryData Bytes:"); DumpBytes(importSection.AuxiliaryDataRVA, (uint)importSection.AuxiliaryDataSize); } } foreach (R2RImportSection.ImportSectionEntry entry in importSection.Entries) { entry.WriteTo(_writer, _options); _writer.WriteLine(); } _writer.WriteLine(); } } break; case R2RSection.SectionType.READYTORUN_SECTION_MANIFEST_METADATA: int assemblyRefCount = _r2r.MetadataReader.GetTableRowCount(TableIndex.AssemblyRef); _writer.WriteLine($"MSIL AssemblyRef's ({assemblyRefCount} entries):"); for (int assemblyRefIndex = 1; assemblyRefIndex <= assemblyRefCount; assemblyRefIndex++) { AssemblyReference assemblyRef = _r2r.MetadataReader.GetAssemblyReference(MetadataTokens.AssemblyReferenceHandle(assemblyRefIndex)); string assemblyRefName = _r2r.MetadataReader.GetString(assemblyRef.Name); _writer.WriteLine($"[ID 0x{assemblyRefIndex:X2}]: {assemblyRefName}"); } _writer.WriteLine($"Manifest metadata AssemblyRef's ({_r2r.ManifestReferenceAssemblies.Count} entries):"); for (int manifestAsmIndex = 0; manifestAsmIndex < _r2r.ManifestReferenceAssemblies.Count; manifestAsmIndex++) { _writer.WriteLine($"[ID 0x{manifestAsmIndex + assemblyRefCount + 2:X2}]: {_r2r.ManifestReferenceAssemblies[manifestAsmIndex]}"); } break; } }
private void DumpSectionContents(R2RReader r2r, R2RSection section) { switch (section.Type) { case R2RSection.SectionType.READYTORUN_SECTION_AVAILABLE_TYPES: uint availableTypesSectionOffset = (uint)r2r.GetOffset(section.RelativeVirtualAddress); NativeParser availableTypesParser = new NativeParser(r2r.Image, availableTypesSectionOffset); NativeHashtable availableTypes = new NativeHashtable(r2r.Image, availableTypesParser, (uint)(availableTypesSectionOffset + section.Size)); _writer.WriteLine(availableTypes.ToString()); foreach (string name in r2r.AvailableTypes) { _writer.WriteLine(name); } break; case R2RSection.SectionType.READYTORUN_SECTION_METHODDEF_ENTRYPOINTS: NativeArray methodEntryPoints = new NativeArray(r2r.Image, (uint)r2r.GetOffset(section.RelativeVirtualAddress)); _writer.Write(methodEntryPoints.ToString()); break; case R2RSection.SectionType.READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS: uint instanceSectionOffset = (uint)r2r.GetOffset(section.RelativeVirtualAddress); NativeParser instanceParser = new NativeParser(r2r.Image, instanceSectionOffset); NativeHashtable instMethodEntryPoints = new NativeHashtable(r2r.Image, instanceParser, (uint)(instanceSectionOffset + section.Size)); _writer.Write(instMethodEntryPoints.ToString()); break; case R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS: int rtfOffset = r2r.GetOffset(section.RelativeVirtualAddress); int rtfEndOffset = rtfOffset + section.Size; int rtfIndex = 0; while (rtfOffset < rtfEndOffset) { uint rva = NativeReader.ReadUInt32(r2r.Image, ref rtfOffset); _writer.WriteLine($"{rtfIndex}: 0x{rva:X8}"); rtfIndex++; } break; case R2RSection.SectionType.READYTORUN_SECTION_COMPILER_IDENTIFIER: _writer.WriteLine(r2r.CompileIdentifier); break; case R2RSection.SectionType.READYTORUN_SECTION_IMPORT_SECTIONS: foreach (R2RImportSection importSection in r2r.ImportSections) { _writer.Write(importSection.ToString()); if (_raw && importSection.Entries.Count != 0) { if (importSection.SectionRVA != 0) { _writer.WriteLine("Section Bytes:"); DumpBytes(r2r, importSection.SectionRVA, (uint)importSection.SectionSize); } if (importSection.SignatureRVA != 0) { _writer.WriteLine("Signature Bytes:"); DumpBytes(r2r, importSection.SignatureRVA, (uint)importSection.Entries.Count * sizeof(int)); } if (importSection.AuxiliaryDataRVA != 0) { _writer.WriteLine("AuxiliaryData Bytes:"); DumpBytes(r2r, importSection.AuxiliaryDataRVA, (uint)importSection.AuxiliaryData.Size); } } foreach (R2RImportSection.ImportSectionEntry entry in importSection.Entries) { _writer.WriteLine(); _writer.WriteLine(entry.ToString()); } _writer.WriteLine(); } break; } }
/// <summary> /// Initializes the fields of the R2RHeader /// </summary> /// <param name="filename">PE image</param> /// <exception cref="BadImageFormatException">The Cor header flag must be ILLibrary</exception> public unsafe R2RReader(string filename) { Filename = filename; _image = File.ReadAllBytes(filename); fixed(byte *p = _image) { IntPtr ptr = (IntPtr)p; peReader = new PEReader(p, _image.Length); IsR2R = (peReader.PEHeaders.CorHeader.Flags == CorFlags.ILLibrary); if (!IsR2R) { throw new BadImageFormatException("The file is not a ReadyToRun image"); } Machine = peReader.PEHeaders.CoffHeader.Machine; ImageBase = peReader.PEHeaders.PEHeader.ImageBase; // initialize R2RHeader DirectoryEntry r2rHeaderDirectory = peReader.PEHeaders.CorHeader.ManagedNativeHeaderDirectory; int r2rHeaderOffset = GetOffset(r2rHeaderDirectory.RelativeVirtualAddress); R2RHeader = new R2RHeader(_image, r2rHeaderDirectory.RelativeVirtualAddress, r2rHeaderOffset); if (r2rHeaderDirectory.Size != R2RHeader.Size) { throw new BadImageFormatException("The calculated size of the R2RHeader doesn't match the size saved in the ManagedNativeHeaderDirectory"); } // initialize R2RMethods if (peReader.HasMetadata) { var mdReader = peReader.GetMetadataReader(); int runtimeFunctionSize = 2; if (Machine == Machine.Amd64) { runtimeFunctionSize = 3; } runtimeFunctionSize *= sizeof(int); R2RSection runtimeFunctionSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS]; uint nRuntimeFunctions = (uint)(runtimeFunctionSection.Size / runtimeFunctionSize); int runtimeFunctionOffset = GetOffset(runtimeFunctionSection.RelativeVirtualAddress); bool[] isEntryPoint = new bool[nRuntimeFunctions]; for (int i = 0; i < nRuntimeFunctions; i++) { isEntryPoint[i] = false; } // initialize R2RMethods with method signatures from MethodDefHandle, and runtime function indices from MethodDefEntryPoints int methodDefEntryPointsRVA = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_METHODDEF_ENTRYPOINTS].RelativeVirtualAddress; int methodDefEntryPointsOffset = GetOffset(methodDefEntryPointsRVA); NativeArray methodEntryPoints = new NativeArray(_image, (uint)methodDefEntryPointsOffset); uint nMethodEntryPoints = methodEntryPoints.GetCount(); R2RMethods = new List <R2RMethod>(); for (uint rid = 1; rid <= nMethodEntryPoints; rid++) { uint offset = 0; if (methodEntryPoints.TryGetAt(_image, rid - 1, ref offset)) { R2RMethod method = new R2RMethod(_image, mdReader, methodEntryPoints, offset, rid); if (method.EntryPointRuntimeFunctionId >= nRuntimeFunctions) { throw new BadImageFormatException("Runtime function id out of bounds"); } isEntryPoint[method.EntryPointRuntimeFunctionId] = true; R2RMethods.Add(method); } } // get the RVAs of the runtime functions for each method int runtimeFunctionId = 0; foreach (R2RMethod method in R2RMethods) { int curOffset = (int)(runtimeFunctionOffset + method.EntryPointRuntimeFunctionId * runtimeFunctionSize); do { int startRva = ReadInt32(_image, ref curOffset); int endRva = -1; if (Machine == Machine.Amd64) { endRva = ReadInt32(_image, ref curOffset); } int unwindRva = ReadInt32(_image, ref curOffset); method.NativeCode.Add(new RuntimeFunction(startRva, endRva, unwindRva)); runtimeFunctionId++; }while (runtimeFunctionId < nRuntimeFunctions && !isEntryPoint[runtimeFunctionId]); } } } }
internal override void DumpSectionContents(R2RSection section, XmlNode parentNode = null) { switch (section.Type) { case R2RSection.SectionType.READYTORUN_SECTION_AVAILABLE_TYPES: uint availableTypesSectionOffset = (uint)_r2r.GetOffset(section.RelativeVirtualAddress); NativeParser availableTypesParser = new NativeParser(_r2r.Image, availableTypesSectionOffset); NativeHashtable availableTypes = new NativeHashtable(_r2r.Image, availableTypesParser, (uint)(availableTypesSectionOffset + section.Size)); _writer.WriteLine(availableTypes.ToString()); foreach (string name in _r2r.AvailableTypes) { _writer.WriteLine(name); } break; case R2RSection.SectionType.READYTORUN_SECTION_METHODDEF_ENTRYPOINTS: NativeArray methodEntryPoints = new NativeArray(_r2r.Image, (uint)_r2r.GetOffset(section.RelativeVirtualAddress)); _writer.Write(methodEntryPoints.ToString()); break; case R2RSection.SectionType.READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS: uint instanceSectionOffset = (uint)_r2r.GetOffset(section.RelativeVirtualAddress); NativeParser instanceParser = new NativeParser(_r2r.Image, instanceSectionOffset); NativeHashtable instMethodEntryPoints = new NativeHashtable(_r2r.Image, instanceParser, (uint)(instanceSectionOffset + section.Size)); _writer.Write(instMethodEntryPoints.ToString()); break; case R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS: int rtfOffset = _r2r.GetOffset(section.RelativeVirtualAddress); int rtfEndOffset = rtfOffset + section.Size; int rtfIndex = 0; while (rtfOffset < rtfEndOffset) { int startRva = NativeReader.ReadInt32(_r2r.Image, ref rtfOffset); int endRva = -1; if (_r2r.Machine == Machine.Amd64) { endRva = NativeReader.ReadInt32(_r2r.Image, ref rtfOffset); } int unwindRva = NativeReader.ReadInt32(_r2r.Image, ref rtfOffset); _writer.WriteLine($"Index: {rtfIndex}"); _writer.WriteLine($"\tStartRva: 0x{startRva:X8}"); if (endRva != -1) { _writer.WriteLine($"\tEndRva: 0x{endRva:X8}"); } _writer.WriteLine($"\tUnwindRva: 0x{unwindRva:X8}"); rtfIndex++; } break; case R2RSection.SectionType.READYTORUN_SECTION_COMPILER_IDENTIFIER: _writer.WriteLine(_r2r.CompilerIdentifier); break; case R2RSection.SectionType.READYTORUN_SECTION_IMPORT_SECTIONS: foreach (R2RImportSection importSection in _r2r.ImportSections) { _writer.Write(importSection.ToString()); if (_raw && importSection.Entries.Count != 0) { if (importSection.SectionRVA != 0) { _writer.WriteLine("Section Bytes:"); DumpBytes(importSection.SectionRVA, (uint)importSection.SectionSize); } if (importSection.SignatureRVA != 0) { _writer.WriteLine("Signature Bytes:"); DumpBytes(importSection.SignatureRVA, (uint)importSection.Entries.Count * sizeof(int)); } if (importSection.AuxiliaryDataRVA != 0 && importSection.AuxiliaryData != null) { _writer.WriteLine("AuxiliaryData Bytes:"); DumpBytes(importSection.AuxiliaryDataRVA, (uint)importSection.AuxiliaryData.Size); } } foreach (R2RImportSection.ImportSectionEntry entry in importSection.Entries) { _writer.WriteLine(entry.ToString()); } _writer.WriteLine(); } break; } }
/// <summary> /// Initializes the fields of the R2RHeader and R2RMethods /// </summary> /// <param name="filename">PE image</param> /// <exception cref="BadImageFormatException">The Cor header flag must be ILLibrary</exception> public unsafe R2RReader(DumpOptions options, string filename) : base(options, filename, new List <string>()) { IsR2R = ((PEReader.PEHeaders.CorHeader.Flags & CorFlags.ILLibrary) != 0); if (!IsR2R) { throw new BadImageFormatException("The file is not a ReadyToRun image"); } uint machine = (uint)PEReader.PEHeaders.CoffHeader.Machine; OS = OperatingSystem.Unknown; foreach (OperatingSystem os in Enum.GetValues(typeof(OperatingSystem))) { Machine = (Machine)(machine ^ (uint)os); if (Enum.IsDefined(typeof(Machine), Machine)) { OS = os; break; } } if (OS == OperatingSystem.Unknown) { throw new BadImageFormatException($"Invalid Machine: {machine}"); } switch (Machine) { case Machine.I386: Architecture = Architecture.X86; PointerSize = 4; break; case Machine.Amd64: Architecture = Architecture.X64; PointerSize = 8; break; case Machine.Arm: case Machine.Thumb: case Machine.ArmThumb2: Architecture = Architecture.Arm; PointerSize = 4; break; case Machine.Arm64: Architecture = Architecture.Arm64; PointerSize = 8; break; default: throw new NotImplementedException(Machine.ToString()); } ImageBase = PEReader.PEHeaders.PEHeader.ImageBase; // initialize R2RHeader DirectoryEntry r2rHeaderDirectory = PEReader.PEHeaders.CorHeader.ManagedNativeHeaderDirectory; int r2rHeaderOffset = GetOffset(r2rHeaderDirectory.RelativeVirtualAddress); R2RHeader = new R2RHeader(Image, r2rHeaderDirectory.RelativeVirtualAddress, r2rHeaderOffset); if (r2rHeaderDirectory.Size != R2RHeader.Size) { throw new BadImageFormatException("The calculated size of the R2RHeader doesn't match the size saved in the ManagedNativeHeaderDirectory"); } ParseDebugInfo(); if (R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_MANIFEST_METADATA)) { R2RSection manifestMetadata = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_MANIFEST_METADATA]; fixed(byte *image = Image) { MetadataReader manifestReader = new MetadataReader(image + GetOffset(manifestMetadata.RelativeVirtualAddress), manifestMetadata.Size); int assemblyRefCount = manifestReader.GetTableRowCount(TableIndex.AssemblyRef); for (int assemblyRefIndex = 1; assemblyRefIndex <= assemblyRefCount; assemblyRefIndex++) { AssemblyReferenceHandle asmRefHandle = MetadataTokens.AssemblyReferenceHandle(assemblyRefIndex); AssemblyReference asmRef = manifestReader.GetAssemblyReference(asmRefHandle); string asmRefName = manifestReader.GetString(asmRef.Name); ManifestReferenceAssemblies.Add(asmRefName); } } } if (R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_EXCEPTION_INFO)) { R2RSection exceptionInfoSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_EXCEPTION_INFO]; EHLookupTable = new EHLookupTable(Image, GetOffset(exceptionInfoSection.RelativeVirtualAddress), exceptionInfoSection.Size); } ImportSections = new List <R2RImportSection>(); ImportCellNames = new Dictionary <int, string>(); ParseImportSections(); R2RMethods = new List <R2RMethod>(); InstanceMethods = new List <InstanceMethod>(); if (R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS)) { int runtimeFunctionSize = CalculateRuntimeFunctionSize(); R2RSection runtimeFunctionSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS]; uint nRuntimeFunctions = (uint)(runtimeFunctionSection.Size / runtimeFunctionSize); int runtimeFunctionOffset = GetOffset(runtimeFunctionSection.RelativeVirtualAddress); bool[] isEntryPoint = new bool[nRuntimeFunctions]; // initialize R2RMethods ParseMethodDefEntrypoints(isEntryPoint); ParseInstanceMethodEntrypoints(isEntryPoint); ParseRuntimeFunctions(isEntryPoint, runtimeFunctionOffset, runtimeFunctionSize); } AvailableTypes = new List <string>(); ParseAvailableTypes(); CompilerIdentifier = ParseCompilerIdentifier(); }
private void ParseImportSections() { if (!R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_IMPORT_SECTIONS)) { return; } R2RSection importSectionsSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_IMPORT_SECTIONS]; int offset = GetOffset(importSectionsSection.RelativeVirtualAddress); int endOffset = offset + importSectionsSection.Size; while (offset < endOffset) { int rva = NativeReader.ReadInt32(Image, ref offset); int sectionOffset = GetOffset(rva); int startOffset = sectionOffset; int size = NativeReader.ReadInt32(Image, ref offset); R2RImportSection.CorCompileImportFlags flags = (R2RImportSection.CorCompileImportFlags)NativeReader.ReadUInt16(Image, ref offset); byte type = NativeReader.ReadByte(Image, ref offset); byte entrySize = NativeReader.ReadByte(Image, ref offset); int entryCount = 0; if (entrySize != 0) { entryCount = size / entrySize; } int signatureRVA = NativeReader.ReadInt32(Image, ref offset); int signatureOffset = 0; if (signatureRVA != 0) { signatureOffset = GetOffset(signatureRVA); } List <R2RImportSection.ImportSectionEntry> entries = new List <R2RImportSection.ImportSectionEntry>(); switch (flags) { case R2RImportSection.CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_EAGER: { int tempSignatureOffset = signatureOffset; int firstSigRva = NativeReader.ReadInt32(Image, ref tempSignatureOffset); uint sigRva = 0; while (sigRva != firstSigRva) { int entryOffset = sectionOffset - startOffset; sigRva = NativeReader.ReadUInt32(Image, ref signatureOffset); long section = NativeReader.ReadInt64(Image, ref sectionOffset); int sigOff = GetOffset((int)sigRva); int sigSampleLength = Math.Min(8, Image.Length - sigOff); byte[] signatureSample = new byte[sigSampleLength]; Array.Copy(Image, sigOff, signatureSample, 0, sigSampleLength); entries.Add(new R2RImportSection.ImportSectionEntry(entryOffset, section, sigRva, signatureSample)); } } break; case R2RImportSection.CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_CODE: case R2RImportSection.CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_PCODE: for (int i = 0; i < entryCount; i++) { int entryOffset = sectionOffset - startOffset; long section = NativeReader.ReadInt64(Image, ref sectionOffset); uint sigRva = NativeReader.ReadUInt32(Image, ref signatureOffset); int sigOff = GetOffset((int)sigRva); int sigSampleLength = Math.Min(8, Image.Length - sigOff); byte[] signatureSample = new byte[sigSampleLength]; Array.Copy(Image, sigOff, signatureSample, 0, sigSampleLength); entries.Add(new R2RImportSection.ImportSectionEntry(entryOffset, section, sigRva, signatureSample)); } break; } int auxDataRVA = NativeReader.ReadInt32(Image, ref offset); int auxDataOffset = 0; if (auxDataRVA != 0) { auxDataOffset = GetOffset(auxDataRVA); } ImportSections.Add(new R2RImportSection(Image, rva, size, flags, type, entrySize, signatureRVA, entries, auxDataRVA, auxDataOffset, Machine, R2RHeader.MajorVersion)); } }
abstract internal void DumpSectionContents(R2RSection section, XmlNode parentNode = null);
/// <summary> /// Initialize generic method instances with argument types and runtime function indices from InstanceMethodEntrypoints /// </summary> private void ParseInstanceMethodEntrypoints(bool[] isEntryPoint) { if (!R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS)) { return; } R2RSection instMethodEntryPointSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS]; int instMethodEntryPointsOffset = GetOffset(instMethodEntryPointSection.RelativeVirtualAddress); NativeParser parser = new NativeParser(Image, (uint)instMethodEntryPointsOffset); NativeHashtable instMethodEntryPoints = new NativeHashtable(Image, parser, (uint)(instMethodEntryPointsOffset + instMethodEntryPointSection.Size)); NativeHashtable.AllEntriesEnumerator allEntriesEnum = instMethodEntryPoints.EnumerateAllEntries(); NativeParser curParser = allEntriesEnum.GetNext(); while (!curParser.IsNull()) { SignatureDecoder decoder = new SignatureDecoder(this, (int)curParser.Offset); string owningType = null; uint methodFlags = decoder.ReadUInt(); if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType) != 0) { owningType = decoder.ReadTypeSignature(); } if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_SlotInsteadOfToken) != 0) { throw new NotImplementedException(); } EntityHandle methodHandle; int rid = (int)decoder.ReadUInt(); if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_MemberRefToken) != 0) { methodHandle = MetadataTokens.MemberReferenceHandle(rid); } else { methodHandle = MetadataTokens.MethodDefinitionHandle(rid); } string[] methodTypeArgs = null; if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_MethodInstantiation) != 0) { uint typeArgCount = decoder.ReadUInt(); methodTypeArgs = new string[typeArgCount]; for (int typeArgIndex = 0; typeArgIndex < typeArgCount; typeArgIndex++) { methodTypeArgs[typeArgIndex] = decoder.ReadTypeSignature(); } } string constrainedType = null; if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_Constrained) != 0) { constrainedType = decoder.ReadTypeSignature(); } int runtimeFunctionId; FixupCell[] fixups; GetRuntimeFunctionIndexFromOffset((int)decoder.Offset, out runtimeFunctionId, out fixups); R2RMethod method = new R2RMethod(R2RMethods.Count, this, methodHandle, runtimeFunctionId, owningType, constrainedType, methodTypeArgs, fixups); if (method.EntryPointRuntimeFunctionId >= 0 && method.EntryPointRuntimeFunctionId < isEntryPoint.Length) { isEntryPoint[method.EntryPointRuntimeFunctionId] = true; } R2RMethods.Add(method); InstanceMethods.Add(new InstanceMethod(curParser.LowHashcode, method)); curParser = allEntriesEnum.GetNext(); } }