/// <summary> /// Initialize non-generic R2RMethods with method signatures from MethodDefHandle, and runtime function indices from MethodDefEntryPoints /// </summary> private void ParseMethodDefEntrypoints(bool[] isEntryPoint) { if (!R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_METHODDEF_ENTRYPOINTS)) { return; } 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(); for (uint rid = 1; rid <= nMethodEntryPoints; rid++) { int offset = 0; if (methodEntryPoints.TryGetAt(Image, rid - 1, ref offset)) { int runtimeFunctionId; FixupCell[] fixups; GetRuntimeFunctionIndexFromOffset(offset, out runtimeFunctionId, out fixups); R2RMethod method = new R2RMethod(R2RMethods.Count, MetadataReader, rid, runtimeFunctionId, null, null, fixups); if (method.EntryPointRuntimeFunctionId < 0 || method.EntryPointRuntimeFunctionId >= isEntryPoint.Length) { throw new BadImageFormatException("EntryPointRuntimeFunctionId out of bounds"); } isEntryPoint[method.EntryPointRuntimeFunctionId] = true; R2RMethods.Add(method); } } }
/// <summary> /// Initialize non-generic R2RMethods with method signatures from MethodDefHandle, and runtime function indices from MethodDefEntryPoints /// </summary> private void ParseMethodDefEntrypoints(bool[] isEntryPoint) { 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(); for (uint rid = 1; rid <= nMethodEntryPoints; rid++) { int offset = 0; if (methodEntryPoints.TryGetAt(Image, rid - 1, ref offset)) { R2RMethod method = new R2RMethod(_mdReader, rid, GetEntryPointIdFromOffset(offset), null, null); if (method.EntryPointRuntimeFunctionId < 0 || method.EntryPointRuntimeFunctionId >= isEntryPoint.Length) { throw new BadImageFormatException("EntryPointRuntimeFunctionId out of bounds"); } isEntryPoint[method.EntryPointRuntimeFunctionId] = true; R2RMethods.Add(method); } } }
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="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> /// 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]); } } } }