public unsafe void GetReader_Offset() { var array = ImmutableArray.Create(new byte[] { 0, 1, 2, 3, 4 }); var provider = new ByteArrayMemoryProvider(array); var block = provider.GetMemoryBlock(); var peBlock = new PEMemoryBlock(block, offset: 1); var reader1 = peBlock.GetReader(); Assert.Equal(4, reader1.Length); AssertEx.Equal(new byte[] { 1, 2, 3 }, reader1.ReadBytes(3)); AssertEx.Equal(new byte[] { 4 }, reader1.ReadBytes(1)); var reader2 = peBlock.GetReader(1, 2); Assert.Equal(2, reader2.Length); AssertEx.Equal(new byte[] { 2, 3 }, reader2.ReadBytes(2)); var reader3 = peBlock.GetReader(4, 0); Assert.Equal(0, reader3.Length); AssertEx.Equal(new byte[] { }, reader3.ReadBytes(0)); Assert.Throws<ArgumentOutOfRangeException>(() => peBlock.GetReader(0, 5)); Assert.Throws<ArgumentOutOfRangeException>(() => peBlock.GetReader(4, 1)); Assert.Throws<ArgumentOutOfRangeException>(() => peBlock.GetReader(5, 0)); }
private void ApplyRelocations(ModuleInfo module, PEReader reader, int dataVA, byte[] data) { PEMemoryBlock relocations = reader.GetSectionData(".reloc"); if (relocations.Length > 0) { ulong baseDelta = module.ImageBase - reader.PEHeaders.PEHeader.ImageBase; Trace.TraceInformation("ApplyRelocations: dataVA {0:X8} dataCB {1} baseDelta: {2:X16}", dataVA, data.Length, baseDelta); BlobReader blob = relocations.GetReader(); while (blob.RemainingBytes > 0) { // Read IMAGE_BASE_RELOCATION struct int virtualAddress = blob.ReadInt32(); int sizeOfBlock = blob.ReadInt32(); // Each relocation block covers 4K if (dataVA >= virtualAddress && dataVA < (virtualAddress + 4096)) { int entryCount = (sizeOfBlock - 8) / 2; // (sizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD) Trace.TraceInformation("ApplyRelocations: reloc VirtualAddress {0:X8} SizeOfBlock {1:X8} entry count {2}", virtualAddress, sizeOfBlock, entryCount); int relocsApplied = 0; for (int e = 0; e < entryCount; e++) { // Read relocation type/offset ushort entry = blob.ReadUInt16(); if (entry == 0) { break; } var type = (BaseRelocationType)(entry >> 12); // type is 4 upper bits int relocVA = virtualAddress + (entry & 0xfff); // offset is 12 lower bits // Is this relocation in the data? if (relocVA >= dataVA && relocVA < (dataVA + data.Length)) { int offset = relocVA - dataVA; switch (type) { case BaseRelocationType.ImageRelBasedAbsolute: break; case BaseRelocationType.ImageRelBasedHighLow: { uint value = BitConverter.ToUInt32(data, offset); value += (uint)baseDelta; byte[] source = BitConverter.GetBytes(value); Array.Copy(source, 0, data, offset, source.Length); break; } case BaseRelocationType.ImageRelBasedDir64: { ulong value = BitConverter.ToUInt64(data, offset); value += baseDelta; byte[] source = BitConverter.GetBytes(value); Array.Copy(source, 0, data, offset, source.Length); break; } default: Debug.Fail($"ApplyRelocations: invalid relocation type {type}"); break; } relocsApplied++; } } Trace.TraceInformation("ApplyRelocations: relocs {0} applied", relocsApplied); } else { // Skip to the next relocation block blob.Offset += sizeOfBlock - 8; } } } }
private PEExportTable(PEReader peReader) { _namedExportRva = new Dictionary <string, int>(); _ordinalRva = new Dictionary <int, int>(); DirectoryEntry exportTable = peReader.PEHeaders.PEHeader.ExportTableDirectory; PEMemoryBlock peImage = peReader.GetEntireImage(); BlobReader exportTableHeader = peImage.GetReader(peReader.GetOffset(exportTable.RelativeVirtualAddress), exportTable.Size); if (exportTableHeader.Length == 0) { return; } // +0x00: reserved exportTableHeader.ReadUInt32(); // +0x04: TODO: time/date stamp exportTableHeader.ReadUInt32(); // +0x08: major version exportTableHeader.ReadUInt16(); // +0x0A: minor version exportTableHeader.ReadUInt16(); // +0x0C: DLL name RVA exportTableHeader.ReadUInt32(); // +0x10: ordinal base int minOrdinal = exportTableHeader.ReadInt32(); // +0x14: number of entries in the address table int addressEntryCount = exportTableHeader.ReadInt32(); // +0x18: number of name pointers int namePointerCount = exportTableHeader.ReadInt32(); // +0x1C: export address table RVA int addressTableRVA = exportTableHeader.ReadInt32(); // +0x20: name pointer RVA int namePointerRVA = exportTableHeader.ReadInt32(); // +0x24: ordinal table RVA int ordinalTableRVA = exportTableHeader.ReadInt32(); int[] addressTable = new int[addressEntryCount]; BlobReader addressTableReader = peImage.GetReader(peReader.GetOffset(addressTableRVA), sizeof(int) * addressEntryCount); for (int entryIndex = 0; entryIndex < addressEntryCount; entryIndex++) { addressTable[entryIndex] = addressTableReader.ReadInt32(); } ushort[] ordinalTable = new ushort[namePointerCount]; BlobReader ordinalTableReader = peImage.GetReader(peReader.GetOffset(ordinalTableRVA), sizeof(ushort) * namePointerCount); for (int entryIndex = 0; entryIndex < namePointerCount; entryIndex++) { ushort ordinalIndex = ordinalTableReader.ReadUInt16(); ordinalTable[entryIndex] = ordinalIndex; _ordinalRva.Add(entryIndex + minOrdinal, addressTable[ordinalIndex]); } BlobReader namePointerReader = peImage.GetReader(peReader.GetOffset(namePointerRVA), sizeof(int) * namePointerCount); for (int entryIndex = 0; entryIndex < namePointerCount; entryIndex++) { int nameRVA = namePointerReader.ReadInt32(); if (nameRVA != 0) { int nameOffset = peReader.GetOffset(nameRVA); BlobReader nameReader = peImage.GetReader(nameOffset, peImage.Length - nameOffset); StringBuilder nameBuilder = new StringBuilder(); for (byte ascii; (ascii = nameReader.ReadByte()) != 0;) { nameBuilder.Append((char)ascii); } _namedExportRva.Add(nameBuilder.ToString(), addressTable[ordinalTable[entryIndex]]); } } }
internal unsafe int ReadVirtualForWindows( IntPtr self, ulong address, IntPtr buffer, uint bytesRequested, uint *pbytesRead) { if (DataReader.ReadMemory(address, buffer, unchecked ((int)bytesRequested), out int bytesRead)) { Write(pbytesRead, (uint)bytesRead); return(S_OK); } // The memory read failed. Check if there is a module that contains the // address range being read and map it into the virtual address space. foreach (ModuleInfo module in DataReader.EnumerateModules()) { ulong start = module.ImageBase; ulong end = start + module.FileSize; if (start <= address && end > address) { Trace.TraceInformation("ReadVirtualForWindows: address {0:X16} size {1:X8} found module {2}", address, bytesRequested, module.FileName); // We found a module that contains the memory requested. Now find or download the PE image. PEReader reader = GetPEReader(module); if (reader != null) { // Read the memory from the PE image. There are a few limitions: // 1) Fix ups are NOT applied to the sections // 2) Memory regions that cross/contain heap memory into module image memory int rva = (int)(address - start); try { PEMemoryBlock block = reader.GetSectionData(rva); if (block.Pointer == null) { Trace.TraceInformation("ReadVirtualForWindows: rva {0:X8} not in any section; reading from entire image", rva); // If the address isn't contained in one of the sections, assume that SOS is reader the PE headers directly. block = reader.GetEntireImage(); } else { rva = 0; } BlobReader blob = block.GetReader(rva, (int)bytesRequested); byte[] data = blob.ReadBytes((int)bytesRequested); Marshal.Copy(data, 0, buffer, data.Length); Write(pbytesRead, (uint)data.Length); return(S_OK); } catch (Exception ex) when(ex is BadImageFormatException || ex is InvalidOperationException || ex is IOException) { Trace.TraceError("ReadVirtualForWindows: exception {0}", ex); } } break; } } return(E_FAIL); }
internal unsafe InternalManifestResourceInfo GetInternalManifestResourceInfo(string resourceName) { MetadataReader reader = Reader; InternalManifestResourceInfo result = new InternalManifestResourceInfo(); ManifestResourceHandleCollection manifestResources = reader.ManifestResources; foreach (ManifestResourceHandle resourceHandle in manifestResources) { ManifestResource resource = resourceHandle.GetManifestResource(reader); if (resource.Name.Equals(resourceName, reader)) { result.Found = true; if (resource.Implementation.IsNil) { checked { // Embedded data resource result.ResourceLocation = ResourceLocation.Embedded | ResourceLocation.ContainedInManifestFile; PEReader pe = _guardedPEReader.PEReader; PEMemoryBlock resourceDirectory = pe.GetSectionData(pe.PEHeaders.CorHeader.ResourcesDirectory.RelativeVirtualAddress); BlobReader blobReader = resourceDirectory.GetReader((int)resource.Offset, resourceDirectory.Length - (int)resource.Offset); uint length = blobReader.ReadUInt32(); result.PointerToResource = blobReader.CurrentPointer; // Length check the size of the resource to ensure it fits in the PE file section, note, this is only safe as its in a checked region if (length + sizeof(Int32) > blobReader.Length) { throw new BadImageFormatException(); } result.SizeOfResource = length; } } else { if (resource.Implementation.Kind == HandleKind.AssemblyFile) { // Get file name result.ResourceLocation = default(ResourceLocation); AssemblyFile file = ((AssemblyFileHandle)resource.Implementation).GetAssemblyFile(reader); result.FileName = file.Name.GetString(reader); if (file.ContainsMetadata) { EcmaModule module = (EcmaModule)Assembly.GetModule(result.FileName); if (module == null) { throw new BadImageFormatException(SR.Format(SR.ManifestResourceInfoReferencedBadModule, result.FileName)); } result = module.GetInternalManifestResourceInfo(resourceName); } } else if (resource.Implementation.Kind == HandleKind.AssemblyReference) { // Resolve assembly reference result.ResourceLocation = ResourceLocation.ContainedInAnotherAssembly; RoAssemblyName destinationAssemblyName = ((AssemblyReferenceHandle)resource.Implementation).ToRoAssemblyName(reader); result.ReferencedAssembly = Loader.ResolveAssembly(destinationAssemblyName); } } } } return(result); }
internal unsafe static MetadataReader ToMetadataReader(this PEMemoryBlock metadata) { return(new MetadataReader(metadata.Pointer, metadata.Length, MetadataReaderOptions.None)); }
internal unsafe ImportedModule(PEMemoryBlock metadataBlock) { _reader = new MetadataReader(metadataBlock.Pointer, metadataBlock.Length); }
/// <summary> /// Read memory from a PE module for the memory cache. Finds locally or downloads a module /// and "maps" it into the address space. This function can return more than requested which /// means the block should not be cached. /// </summary> /// <param name="address">memory address</param> /// <param name="bytesRequested">number of bytes</param> /// <returns>bytes read or null if error</returns> private byte[] ReadMemoryFromModule(ulong address, int bytesRequested) { Debug.Assert((address & ~_memoryService.SignExtensionMask()) == 0); IModule module = _moduleService.GetModuleFromAddress(address); if (module != null) { // Recursion can happen in the case where the PE, ELF or MachO headers (in the module.Services.GetService<>() calls) // used to get the timestamp/filesize or build id are not in the dump. if (!_recursionProtection.Contains(address)) { _recursionProtection.Add(address); try { // We found a module that contains the memory requested. Now find or download the PE image. PEReader reader = module.Services.GetService <PEReader>(); if (reader is not null) { int rva = (int)(address - module.ImageBase); Debug.Assert(rva >= 0); Debug.Assert(!reader.IsLoadedImage); Debug.Assert(reader.IsEntireImageAvailable); #if TRACE_VERBOSE Trace.TraceInformation($"ReadMemoryFromModule: address {address:X16} rva {rva:X8} bytesRequested {bytesRequested:X8} {module.FileName}"); #endif // Not reading anything in the PE's header if (rva > reader.PEHeaders.PEHeader.SizeOfHeaders) { // This property can cause recursion because this PE being mapped here is read to determine the layout if (!module.IsFileLayout.GetValueOrDefault(true)) { // If the PE image that we are mapping into has the "loaded" layout convert the rva to a flat/file based one. for (int i = 0; i < reader.PEHeaders.SectionHeaders.Length; i++) { SectionHeader section = reader.PEHeaders.SectionHeaders[i]; if (rva >= section.VirtualAddress && rva < (section.VirtualAddress + section.VirtualSize)) { rva = section.PointerToRawData + (rva - section.VirtualAddress); break; } } } } try { byte[] data = null; // Read the memory from the PE image found/downloaded above PEMemoryBlock block = reader.GetEntireImage(); if (rva < block.Length) { int size = Math.Min(block.Length - rva, bytesRequested); if ((rva + size) <= block.Length) { data = block.GetReader(rva, size).ReadBytes(size); ApplyRelocations(module, reader, (int)(address - module.ImageBase), data); } else { Trace.TraceError($"ReadMemoryFromModule: FAILED address {address:X16} rva {rva:X8} {module.FileName}"); } } return(data); } catch (Exception ex) when(ex is BadImageFormatException || ex is InvalidOperationException || ex is IOException) { Trace.TraceError($"ReadMemoryFromModule: exception: address {address:X16} {ex.Message} {module.FileName}"); } } else { // Find or download the ELF image, if one. Reader virtualAddressReader = module.Services.GetService <ELFFile>()?.VirtualAddressReader; if (virtualAddressReader is null) { // Find or download the MachO image, if one. virtualAddressReader = module.Services.GetService <MachOFile>()?.VirtualAddressReader; } if (virtualAddressReader is not null) { // Read the memory from the image. ulong rva = address - module.ImageBase; Debug.Assert(rva >= 0); try { #if TRACE_VERBOSE Trace.TraceInformation($"ReadMemoryFromModule: address {address:X16} rva {rva:X16} size {bytesRequested:X8} in ELF or MachO file {module.FileName}"); #endif byte[] data = new byte[bytesRequested]; uint read = virtualAddressReader.Read(rva, data, 0, (uint)bytesRequested); if (read == 0) { Trace.TraceError($"ReadMemoryFromModule: FAILED address {address:X16} rva {rva:X16} {module.FileName}"); data = null; } return(data); } catch (Exception ex) when(ex is BadInputFormatException || ex is InvalidVirtualAddressException) { Trace.TraceError($"ReadMemoryFromModule: ELF or MachO file exception: address {address:X16} {ex.Message} {module.FileName}"); } } } } finally { _recursionProtection.Remove(address); } } else { Trace.TraceError($"ReadMemoryFromModule: recursion: address {address:X16} size {bytesRequested:X8} {module.FileName}"); } } return(null); }
public unsafe void GetContent_Offset() { var array = ImmutableArray.Create(new byte[] { 0, 1, 2, 3, 4 }); var provider = new ByteArrayMemoryProvider(array); var block = provider.GetMemoryBlock(); var peBlock = new PEMemoryBlock(block, offset: 1); AssertEx.Equal(new byte[] { 1, 2, 3, 4 }, peBlock.GetContent()); AssertEx.Equal(new byte[] { 2, 3 }, peBlock.GetContent(1, 2)); AssertEx.Equal(new byte[] { }, peBlock.GetContent(4, 0)); Assert.Throws<ArgumentOutOfRangeException>(() => peBlock.GetContent(0, 5)); Assert.Throws<ArgumentOutOfRangeException>(() => peBlock.GetContent(4, 1)); Assert.Throws<ArgumentOutOfRangeException>(() => peBlock.GetContent(5, 0)); }