Example #1
0
        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));
        }
Example #2
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]]);
                }
            }
        }
Example #4
0
        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);
        }
Example #5
0
        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);
        }
Example #6
0
 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);
        }
Example #9
0
        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));
        }