Example #1
0
        protected string ReadNullTerminatedString(int offset)
        {
            var stringLength = 0;

            while (PeBytes.Span[offset + stringLength] != byte.MinValue)
            {
                stringLength += 1;
            }

            return(Encoding.UTF8.GetString(PeBytes.Slice(offset, stringLength).Span.ToArray()));
        }
Example #2
0
        private IEnumerable <BaseRelocation> ReadBaseRelocations()
        {
            // Calculate the offset of the first base relocation block

            if (!PeHeaders.TryGetDirectoryOffset(PeHeaders.PEHeader.BaseRelocationTableDirectory, out var currentRelocationBlockOffset))
            {
                yield break;
            }

            while (true)
            {
                // Read the current base relocation block

                var relocationBlock = MemoryMarshal.Read <ImageBaseRelocation>(PeBytes.Slice(currentRelocationBlockOffset).Span);

                if (relocationBlock.SizeOfBlock == 0)
                {
                    yield break;
                }

                // Read the base relocations from the base relocation block

                var relocationBlockSize = (relocationBlock.SizeOfBlock - Unsafe.SizeOf <ImageBaseRelocation>()) / sizeof(short);

                var relocationBlockOffset = RvaToOffset(relocationBlock.VirtualAddress);

                for (var relocationIndex = 0; relocationIndex < relocationBlockSize; relocationIndex++)
                {
                    // Read the base relocation

                    var relocationOffset = currentRelocationBlockOffset + Unsafe.SizeOf <ImageBaseRelocation>() + sizeof(short) * relocationIndex;

                    var relocation = MemoryMarshal.Read <ushort>(PeBytes.Slice(relocationOffset).Span);

                    // The offset is located in the upper 4 bits of the base relocation

                    var offset = relocation & 0xFFF;

                    // The type is located in the lower 12 bits of the base relocation

                    var type = relocation >> 12;

                    yield return(new BaseRelocation(relocationBlockOffset + offset, (BaseRelocationType)type));
                }

                // Calculate the offset of the next base relocation block

                currentRelocationBlockOffset += relocationBlock.SizeOfBlock;
            }
        }
Example #3
0
        private IEnumerable <ImportDescriptor> ReadImportDescriptors()
        {
            // Calculate the import table offset

            if (!PeHeaders.TryGetDirectoryOffset(PeHeaders.PEHeader.ImportTableDirectory, out var importTableOffset))
            {
                yield break;
            }

            for (var descriptorIndex = 0;; descriptorIndex++)
            {
                // Read the import descriptor

                var descriptorOffset = importTableOffset + Unsafe.SizeOf <ImageImportDescriptor>() * descriptorIndex;

                var descriptor = MemoryMarshal.Read <ImageImportDescriptor>(PeBytes.Slice(descriptorOffset).Span);

                if (descriptor.Name == 0)
                {
                    break;
                }

                // Read the import descriptor name

                var descriptorNameOffset = RvaToOffset(descriptor.Name);

                var descriptorName = ReadNullTerminatedString(descriptorNameOffset);

                // Read the functions imported under the import descriptor

                var descriptorThunkOffset = descriptor.OriginalFirstThunk == 0 ? RvaToOffset(descriptor.FirstThunk) : RvaToOffset(descriptor.OriginalFirstThunk);

                var importAddressTableOffset = RvaToOffset(descriptor.FirstThunk);

                var importedFunctions = ReadImportedFunctions(descriptorThunkOffset, importAddressTableOffset);

                yield return(new ImportDescriptor(importedFunctions, descriptorName));
            }
        }
Example #4
0
        private IEnumerable <ImportDescriptor> ReadDelayImportDescriptors()
        {
            // Calculate the offset of the delay import table

            if (!PeHeaders.TryGetDirectoryOffset(PeHeaders.PEHeader.DelayImportTableDirectory, out var delayImportTableOffset))
            {
                yield break;
            }

            for (var descriptorIndex = 0;; descriptorIndex++)
            {
                // Read the delay import descriptor

                var descriptorOffset = delayImportTableOffset + Unsafe.SizeOf <ImageDelayLoadDescriptor>() * descriptorIndex;

                var descriptor = MemoryMarshal.Read <ImageDelayLoadDescriptor>(PeBytes.Slice(descriptorOffset).Span);

                if (descriptor.DllNameRva == 0)
                {
                    break;
                }

                // Read the name of the delay import descriptor

                var descriptorNameOffset = RvaToOffset(descriptor.DllNameRva);

                var descriptorName = ReadNullTerminatedString(descriptorNameOffset);

                // Read the functions imported under the delay import descriptor

                var descriptorThunkOffset = RvaToOffset(descriptor.ImportNameTableRva);

                var importAddressTableOffset = RvaToOffset(descriptor.ImportAddressTableRva);

                var delayImportedFunctions = ReadDelayImportedFunctions(descriptorThunkOffset, importAddressTableOffset);

                yield return(new ImportDescriptor(delayImportedFunctions, descriptorName));
            }
        }
Example #5
0
        private IEnumerable <ExportedFunction> ReadExportedFunctions()
        {
            // Calculate the offset of the export table

            if (!PeHeaders.TryGetDirectoryOffset(PeHeaders.PEHeader.ExportTableDirectory, out var exportTableOffset))
            {
                yield break;
            }

            // Read the export table

            var exportTable = MemoryMarshal.Read <ImageExportDirectory>(PeBytes.Slice(exportTableOffset).Span);

            // Read the exported functions

            var functionNameBaseOffset = RvaToOffset(exportTable.AddressOfNames);

            var functionOffsetBaseOffset = RvaToOffset(exportTable.AddressOfFunctions);

            var functionOrdinalBaseOffset = RvaToOffset(exportTable.AddressOfNameOrdinals);

            for (var functionIndex = 0; functionIndex < exportTable.NumberOfNames; functionIndex++)
            {
                // Read the name of the function

                var functionNameOffsetOffset = functionNameBaseOffset + sizeof(int) * functionIndex;

                var functionNameOffset = RvaToOffset(MemoryMarshal.Read <int>(PeBytes.Slice(functionNameOffsetOffset).Span));

                var functionName = ReadNullTerminatedString(functionNameOffset);

                // Read the ordinal of the function

                var functionOrdinalOffset = functionOrdinalBaseOffset + sizeof(short) * functionIndex;

                var functionOrdinal = MemoryMarshal.Read <short>(PeBytes.Slice(functionOrdinalOffset).Span);

                // Read the offset of the function

                var functionOffsetOffset = functionOffsetBaseOffset + sizeof(int) * functionOrdinal;

                var functionOffset = MemoryMarshal.Read <int>(PeBytes.Slice(functionOffsetOffset).Span);

                // Determine if the function is forwarded to another function

                var exportTableStartOffset = PeHeaders.PEHeader.ExportTableDirectory.RelativeVirtualAddress;

                var exportTableEndOffset = exportTableStartOffset + PeHeaders.PEHeader.ExportTableDirectory.Size;

                if (functionOffset < exportTableStartOffset || functionOffset > exportTableEndOffset)
                {
                    yield return(new ExportedFunction(null, functionName, functionOffset, exportTable.Base + functionOrdinal));

                    continue;
                }

                // Read the forwarder string of the function

                var forwarderStringOffset = RvaToOffset(functionOffset);

                var forwarderString = ReadNullTerminatedString(forwarderStringOffset);

                yield return(new ExportedFunction(forwarderString, functionName, functionOffset, exportTable.Base + functionOrdinal));
            }
        }
Example #6
0
        private int ReadSecurityCookieOffset()
        {
            // Calculate the offset of the load config table

            if (!PeHeaders.TryGetDirectoryOffset(PeHeaders.PEHeader.LoadConfigTableDirectory, out var loadConfigTableOffset))
            {
                return(0);
            }

            if (PeHeaders.PEHeader.Magic == PEMagic.PE32)
            {
                // Read the load config table

                var loadConfigTable = MemoryMarshal.Read <ImageLoadConfigDirectory32>(PeBytes.Slice(loadConfigTableOffset).Span);

                // Calculate the offset of the security cookie

                return(loadConfigTable.SecurityCookie == 0 ? 0 : loadConfigTable.SecurityCookie - (int)PeHeaders.PEHeader.ImageBase);
            }

            else
            {
                // Read the load config table

                var loadConfigTable = MemoryMarshal.Read <ImageLoadConfigDirectory64>(PeBytes.Slice(loadConfigTableOffset).Span);

                // Calculate the offset of the security cookie

                return(loadConfigTable.SecurityCookie == 0 ? 0 : (int)(loadConfigTable.SecurityCookie - (long)PeHeaders.PEHeader.ImageBase));
            }
        }
Example #7
0
        private IEnumerable <int> ReadTlsCallbackOffsets()
        {
            // Calculate offset of the TLS table

            if (!PeHeaders.TryGetDirectoryOffset(PeHeaders.PEHeader.ThreadLocalStorageTableDirectory, out var tlsTableOffset))
            {
                yield break;
            }

            if (PeHeaders.PEHeader.Magic == PEMagic.PE32)
            {
                // Calculate the offset of the TLS callbacks

                var tlsTable = MemoryMarshal.Read <ImageTlsDirectory32>(PeBytes.Slice(tlsTableOffset).Span);

                if (tlsTable.AddressOfCallbacks == 0)
                {
                    yield break;
                }

                var tlsCallbacksOffset = RvaToOffset(tlsTable.AddressOfCallbacks - (int)PeHeaders.PEHeader.ImageBase);

                // Read the offsets of the TLS callbacks

                for (var tlsCallbackIndex = 0;; tlsCallbackIndex++)
                {
                    var tlsCallbackVaOffset = tlsCallbacksOffset + sizeof(int) * tlsCallbackIndex;

                    var tlsCallbackVa = MemoryMarshal.Read <int>(PeBytes.Slice(tlsCallbackVaOffset).Span);

                    if (tlsCallbackVa == 0)
                    {
                        break;
                    }

                    yield return(tlsCallbackVa - (int)PeHeaders.PEHeader.ImageBase);
                }
            }

            else
            {
                // Calculate the offset of the TLS callbacks

                var tlsTable = MemoryMarshal.Read <ImageTlsDirectory64>(PeBytes.Slice(tlsTableOffset).Span);

                if (tlsTable.AddressOfCallbacks == 0)
                {
                    yield break;
                }

                var tlsCallbacksOffset = RvaToOffset((int)(tlsTable.AddressOfCallbacks - (long)PeHeaders.PEHeader.ImageBase));

                // Read the offsets of the TLS callbacks

                for (var tlsCallbackIndex = 0;; tlsCallbackIndex++)
                {
                    var tlsCallbackVaOffset = tlsCallbacksOffset + sizeof(long) * tlsCallbackIndex;

                    var tlsCallbackVa = MemoryMarshal.Read <long>(PeBytes.Slice(tlsCallbackVaOffset).Span);

                    if (tlsCallbackVa == 0)
                    {
                        break;
                    }

                    yield return((int)(tlsCallbackVa - (long)PeHeaders.PEHeader.ImageBase));
                }
            }
        }
Example #8
0
        private IEnumerable <ImportedFunction> ReadImportedFunctions(int descriptorThunkOffset, int importAddressTableOffset)
        {
            for (var functionIndex = 0;; functionIndex++)
            {
                int functionOffset;

                int functionDataOffset;

                if (PeHeaders.PEHeader.Magic == PEMagic.PE32)
                {
                    // Read the thunk data of the function

                    var functionThunkDataOffset = descriptorThunkOffset + sizeof(int) * functionIndex;

                    var functionThunkData = MemoryMarshal.Read <int>(PeBytes.Slice(functionThunkDataOffset).Span);

                    if (functionThunkData == 0)
                    {
                        break;
                    }

                    // Calculate the offset of the function

                    functionOffset = importAddressTableOffset + sizeof(int) * functionIndex;

                    // Determine if the function is imported via ordinal

                    if ((functionThunkData & int.MinValue) != 0)
                    {
                        yield return(new ImportedFunction(null, functionOffset, functionThunkData & ushort.MaxValue));

                        continue;
                    }

                    functionDataOffset = RvaToOffset(functionThunkData);
                }

                else
                {
                    // Read the thunk data of the function

                    var functionThunkDataOffset = descriptorThunkOffset + sizeof(long) * functionIndex;

                    var functionThunkData = MemoryMarshal.Read <long>(PeBytes.Slice(functionThunkDataOffset).Span);

                    if (functionThunkData == 0)
                    {
                        break;
                    }

                    // Calculate the offset of the function

                    functionOffset = importAddressTableOffset + sizeof(long) * functionIndex;

                    // Determine if the function is imported via ordinal

                    if ((functionThunkData & long.MinValue) != 0)
                    {
                        yield return(new ImportedFunction(null, functionOffset, (int)functionThunkData & ushort.MaxValue));

                        continue;
                    }

                    functionDataOffset = RvaToOffset((int)functionThunkData);
                }

                // Read the name of the function

                var functionName = ReadNullTerminatedString(functionDataOffset + sizeof(short));

                // Read the ordinal of the function

                var functionOrdinal = MemoryMarshal.Read <short>(PeBytes.Slice(functionDataOffset).Span);

                yield return(new ImportedFunction(functionName, functionOffset, functionOrdinal));
            }
        }