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())); }
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; } }
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)); } }
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)); } }
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)); } }
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)); } }
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)); } } }
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)); } }