private unsafe DiscoveredAssembly DiscoverAssembly(string assemblyPath) { var fileInfo = new FileInfo(assemblyPath); long length = fileInfo.Length; var mapName = fileInfo.Name; var mode = FileMode.Open; var access = MemoryMappedFileAccess.Read; using (var file = MemoryMappedFile.CreateFromFile(assemblyPath, mode, mapName, length, access)) { using (var stream = file.CreateViewStream(0x0, length, access)) { var headers = new PEHeaders(stream); var start = (byte *)0; stream.SafeMemoryMappedViewHandle.AcquirePointer(ref start); var size = headers.MetadataSize; var reader = new MetadataReader(start + headers.MetadataStartOffset, size, default(MetadataReaderOptions), null); return(new DiscoveredAssembly(assemblyPath, reader)); } } }
void GetStorageInfoFromTemporaryStorage(FileKey moduleFileKey, out ITemporaryStreamStorage storage, out Stream stream, out IntPtr pImage) { int size; using (var copyStream = SerializableBytes.CreateWritableStream()) { // open a file and let it go as soon as possible using (var fileStream = FileUtilities.OpenRead(moduleFileKey.FullPath)) { var headers = new PEHeaders(fileStream); var offset = headers.MetadataStartOffset; size = headers.MetadataSize; // given metadata contains no metadata info. // throw bad image format exception so that we can show right diagnostic to user. if (size <= 0) { throw new BadImageFormatException(); } StreamCopy(fileStream, copyStream, offset, size); } // copy over the data to temp storage and let pooled stream go storage = _temporaryStorageService.CreateTemporaryStreamStorage(CancellationToken.None); copyStream.Position = 0; storage.WriteStream(copyStream); } // get stream that owns direct access memory stream = storage.ReadStream(CancellationToken.None); // stream size must be same as what metadata reader said the size should be. Contract.ThrowIfFalse(stream.Length == size); // under VS host, direct access should be supported var directAccess = (ISupportDirectMemoryAccess)stream; pImage = directAccess.GetPointer(); }
internal PeParser(byte[] dllBytes) { using (var peReader = new PEReader(new MemoryStream(dllBytes))) { DebugData = peReader.ReadCodeViewDebugDirectoryData(peReader.ReadDebugDirectory()[0]); PeHeaders = peReader.PEHeaders; } var peBufferHandle = GCHandle.Alloc(dllBytes, GCHandleType.Pinned); _peBuffer = peBufferHandle.AddrOfPinnedObject(); BaseRelocations = GetBaseRelocations(); ExportedFunctions = GetExportedFunctions(); ImportedFunctions = GetImportedFunctions(); TlsCallbacks = GetTlsCallbacks(); peBufferHandle.Free(); }
internal BaseRelocationDirectory(PEHeaders headers, Memory <byte> imageBuffer) : base(headers, imageBuffer) { BaseRelocations = ReadBaseRelocations(); }
internal static bool Requires64Bits(this PEHeaders headers) { return(headers.PEHeader != null && headers.PEHeader.Magic == PEMagic.PE32Plus || headers.CoffHeader.Machine == Machine.Amd64 || headers.CoffHeader.Machine == Machine.IA64); }
protected DataDirectory(ReadOnlyMemory <byte> peBytes, PEHeaders peHeaders) { PeBytes = peBytes; PeHeaders = peHeaders; }
internal LoadConfigDirectory(PEHeaders headers, Memory <byte> imageBytes) : base(headers.PEHeader !.LoadConfigTableDirectory, headers, imageBytes)
internal ExportDirectory(ReadOnlyMemory <byte> peBytes, PEHeaders peHeaders) : base(peBytes, peHeaders) { ExportedFunctions = ReadExportedFunctions().ToImmutableArray(); }
internal RelocationDirectory(PEHeaders headers, Memory <byte> imageBytes) : base(headers.PEHeader !.BaseRelocationTableDirectory, headers, imageBytes)
internal ResourceDirectory(PEHeaders headers, Memory <byte> imageBytes) : base(headers.PEHeader !.ResourceTableDirectory, headers, imageBytes)
public PELoadConfigDirectory(PEHeaders headers, Memory <byte> imageData) : base(headers, imageData, headers.PEHeader.LoadConfigTableDirectory) { }
public DataDirectoryEntry(PEHeaders headers, string name, DirectoryEntry entry) : this(name, entry.RelativeVirtualAddress, entry.Size, (headers.GetContainingSectionIndex(entry.RelativeVirtualAddress) >= 0) ? headers.SectionHeaders[headers.GetContainingSectionIndex(entry.RelativeVirtualAddress)].Name : "") { }
internal LoadConfigDirectory(PEHeaders headers, Memory <byte> imageBlock) : base(headers, imageBlock) { SecurityCookie = ReadSecurityCookie(); SehTable = ReadSehTable(); }
internal BaseRelocationDirectory(ReadOnlyMemory <byte> peBytes, PEHeaders peHeaders) : base(peBytes, peHeaders) { BaseRelocations = ReadBaseRelocations().ToImmutableArray(); }
public PETlsDirectory(PEHeaders headers, Memory<byte> imageData) : base(headers, imageData, headers.PEHeader.ThreadLocalStorageTableDirectory) { }
protected DataDirectory(PEHeaders headers, Memory <byte> imageBlock) { Headers = headers; ImageBlock = imageBlock; }
public PEImportDirectory(PEHeaders headers, Memory <byte> imageData) : base(headers, imageData, headers.PEHeader.ImportTableDirectory) { }
internal TlsDirectory(PEHeaders headers, Memory <byte> imageBytes) : base(headers, imageBytes, headers.PEHeader !.ThreadLocalStorageTableDirectory)
internal ImportDirectory(PEHeaders headers, Memory <byte> imageBlock) : base(headers, imageBlock) { ImportDescriptors = ReadImportDescriptors(); }
static internal Microsoft.Cci.ResourceSection ReadWin32ResourcesFromCOFF(Stream stream) { var peHeaders = new PEHeaders(stream); var rsrc1 = new SectionHeader(); var rsrc2 = new SectionHeader(); int foundCount = 0; foreach (var sectionHeader in peHeaders.SectionHeaders) { if (sectionHeader.Name == ".rsrc$01") { rsrc1 = sectionHeader; foundCount++; } else if (sectionHeader.Name == ".rsrc$02") { rsrc2 = sectionHeader; foundCount++; } } if (foundCount != 2) { throw new ResourceException(CodeAnalysisResources.CoffResourceMissingSection); } ConfirmSectionValues(rsrc1, stream.Length); ConfirmSectionValues(rsrc2, stream.Length); //This will be the final resource section bytes without a header. It contains the concatenation //of .rsrc$02 on to the end of .rsrc$01. var imageResourceSectionBytes = new byte[checked (rsrc1.SizeOfRawData + rsrc2.SizeOfRawData)]; stream.Seek(rsrc1.PointerToRawData, SeekOrigin.Begin); stream.TryReadAll(imageResourceSectionBytes, 0, rsrc1.SizeOfRawData); // ConfirmSectionValues ensured that data are available stream.Seek(rsrc2.PointerToRawData, SeekOrigin.Begin); stream.TryReadAll(imageResourceSectionBytes, rsrc1.SizeOfRawData, rsrc2.SizeOfRawData); // ConfirmSectionValues ensured that data are available const int SizeOfRelocationEntry = 10; try { var relocLastAddress = checked (rsrc1.PointerToRelocations + (rsrc1.NumberOfRelocations * SizeOfRelocationEntry)); if (relocLastAddress > stream.Length) { throw new ResourceException(CodeAnalysisResources.CoffResourceInvalidRelocation); } } catch (OverflowException) { throw new ResourceException(CodeAnalysisResources.CoffResourceInvalidRelocation); } //.rsrc$01 contains the directory tree. .rsrc$02 contains the raw resource data. //.rsrc$01 has references to spots in .rsrc$02. Those spots are expressed as relocations. //These will need to be fixed up when the RVA of the .rsrc section in the final image is known. var relocationOffsets = new uint[rsrc1.NumberOfRelocations]; //offsets into .rsrc$01 var relocationSymbolIndices = new uint[rsrc1.NumberOfRelocations]; var reader = new BinaryReader(stream, Encoding.Unicode); stream.Position = rsrc1.PointerToRelocations; for (int i = 0; i < rsrc1.NumberOfRelocations; i++) { relocationOffsets[i] = reader.ReadUInt32(); //What is being read and stored is the reloc's "Value" //This is the symbol's index. relocationSymbolIndices[i] = reader.ReadUInt32(); reader.ReadUInt16(); //we do nothing with the "Type" } //now that symbol indices are gathered, begin indexing the symbols stream.Position = peHeaders.CoffHeader.PointerToSymbolTable; const uint ImageSizeOfSymbol = 18; try { var lastSymAddress = checked (peHeaders.CoffHeader.PointerToSymbolTable + peHeaders.CoffHeader.NumberOfSymbols * ImageSizeOfSymbol); if (lastSymAddress > stream.Length) { throw new ResourceException(CodeAnalysisResources.CoffResourceInvalidSymbol); } } catch (OverflowException) { throw new ResourceException(CodeAnalysisResources.CoffResourceInvalidSymbol); } var outputStream = new MemoryStream(imageResourceSectionBytes); var writer = new BinaryWriter(outputStream); //encoding shouldn't matter. There are no strings being written. for (int i = 0; i < relocationSymbolIndices.Length; i++) { if (relocationSymbolIndices[i] > peHeaders.CoffHeader.NumberOfSymbols) { throw new ResourceException(CodeAnalysisResources.CoffResourceInvalidRelocation); } var offsetOfSymbol = peHeaders.CoffHeader.PointerToSymbolTable + relocationSymbolIndices[i] * ImageSizeOfSymbol; stream.Position = offsetOfSymbol; stream.Position += 8; //skip over symbol name var symValue = reader.ReadUInt32(); var symSection = reader.ReadInt16(); var symType = reader.ReadUInt16(); //ignore the rest of the fields. const ushort IMAGE_SYM_TYPE_NULL = 0x0000; if (symType != IMAGE_SYM_TYPE_NULL || symSection != 3) //3rd section is .rsrc$02 { throw new ResourceException(CodeAnalysisResources.CoffResourceInvalidSymbol); } //perform relocation. We are concatenating the contents of .rsrc$02 (the raw resource data) //on to the end of .rsrc$01 (the directory tree) to yield the final resource section for the image. //The directory tree has references into the raw resource data. These references are expressed //in the final image as file positions, not positions relative to the beginning of the section. //First make the resources be relative to the beginning of the section by adding the size //of .rsrc$01 to them. They will ultimately need the RVA of the final image resource section added //to them. We don't know that yet. That is why the array of offsets is preserved. outputStream.Position = relocationOffsets[i]; writer.Write((uint)(symValue + rsrc1.SizeOfRawData)); } return(new Cci.ResourceSection(imageResourceSectionBytes, relocationOffsets)); }
internal ImportDirectory(ReadOnlyMemory <byte> peBytes, PEHeaders peHeaders) : base(peBytes, peHeaders) { ImportDescriptors = ReadImportDescriptors().ToImmutableArray(); }
internal ExportDirectory(PEHeaders headers, Memory <byte> imageBuffer) : base(headers, imageBuffer) { ExportedFunctions = ReadExportedFunctions(); }
internal DelayImportDirectory(PEHeaders headers, Memory <byte> imageBuffer) : base(headers, imageBuffer) { DelayLoadImportDescriptors = ReadDelayLoadImportDescriptors(); }
internal ExportDirectory(PEHeaders headers, Memory <byte> imageBytes) : base(headers.PEHeader !.ExportTableDirectory, headers, imageBytes)
internal TlsDirectory(ReadOnlyMemory <byte> peBytes, PEHeaders peHeaders) : base(peBytes, peHeaders) { TlsCallbackOffsets = ReadTlsCallbackOffsets().ToImmutableArray(); }
internal static bool RequiresAmdInstructionSet(this PEHeaders headers) { return(headers.CoffHeader.Machine == Machine.Amd64); }
/// <summary> /// Copy PE headers into a PEHeaderBuilder used by PEBuilder. /// </summary> /// <param name="peHeaders">Headers to copy</param> /// <param name="target">Target architecture to set in the header</param> public static PEHeaderBuilder Copy(PEHeaders peHeaders, TargetDetails target) { bool is64BitTarget = target.PointerSize == sizeof(long); Characteristics imageCharacteristics = peHeaders.CoffHeader.Characteristics; if (is64BitTarget) { imageCharacteristics &= ~Characteristics.Bit32Machine; imageCharacteristics |= Characteristics.LargeAddressAware; } int fileAlignment = 0x200; if (!target.IsWindows && !is64BitTarget) { // To minimize wasted VA space on 32 bit systems align file to page bounaries (presumed to be 4K). fileAlignment = 0x1000; } int sectionAlignment = 0x1000; if (!target.IsWindows && is64BitTarget) { // On Linux, we must match the bottom 12 bits of section RVA's to their file offsets. For this reason // we need the same alignment for both. sectionAlignment = fileAlignment; } DllCharacteristics dllCharacteristics = DllCharacteristics.DynamicBase | DllCharacteristics.NxCompatible; if (!is64BitTarget) { dllCharacteristics |= DllCharacteristics.NoSeh; } // Copy over selected DLL characteristics bits from IL image dllCharacteristics |= peHeaders.PEHeader.DllCharacteristics & (DllCharacteristics.TerminalServerAware | DllCharacteristics.AppContainer); if (is64BitTarget) { dllCharacteristics |= DllCharacteristics.HighEntropyVirtualAddressSpace; } return(new PEHeaderBuilder( machine: target.MachineFromTarget(), sectionAlignment: sectionAlignment, fileAlignment: fileAlignment, imageBase: peHeaders.PEHeader.ImageBase, majorLinkerVersion: 11, minorLinkerVersion: 0, majorOperatingSystemVersion: 5, // Win2k = 5.0 for 32-bit images, Win2003 = 5.2 for 64-bit images minorOperatingSystemVersion: is64BitTarget ? (ushort)2 : (ushort)0, majorImageVersion: peHeaders.PEHeader.MajorImageVersion, minorImageVersion: peHeaders.PEHeader.MinorImageVersion, majorSubsystemVersion: peHeaders.PEHeader.MajorSubsystemVersion, minorSubsystemVersion: peHeaders.PEHeader.MinorSubsystemVersion, subsystem: peHeaders.PEHeader.Subsystem, dllCharacteristics: dllCharacteristics, imageCharacteristics: imageCharacteristics, sizeOfStackReserve: peHeaders.PEHeader.SizeOfStackReserve, sizeOfStackCommit: peHeaders.PEHeader.SizeOfStackCommit, sizeOfHeapReserve: 0, sizeOfHeapCommit: 0)); }
internal TlsDirectory(PEHeaders headers, Memory <byte> imageBuffer) : base(headers, imageBuffer) { TlsCallBacks = ReadTlsCallBacks(); }
internal LoadConfigDirectory(ReadOnlyMemory <byte> peBytes, PEHeaders peHeaders) : base(peBytes, peHeaders) { SecurityCookieOffset = ReadSecurityCookieOffset(); }
/// <summary> /// Validates that the given stream is marked as signed, the signature matches /// the public key, and the header checksum is correct. /// </summary> public static bool IsStreamFullSigned(Stream moduleContents) { var savedPosition = moduleContents.Position; try { moduleContents.Position = 0; var peHeaders = new PEHeaders(moduleContents); moduleContents.Position = 0; using (var metadata = ModuleMetadata.CreateFromStream(moduleContents, leaveOpen: true)) { var metadataReader = metadata.MetadataReader; var peReader = metadata.Module.PEReaderOpt; var flags = peHeaders.CorHeader.Flags; if (CorFlags.StrongNameSigned != (flags & CorFlags.StrongNameSigned)) { return(false); } var snDirectory = peReader.PEHeaders.CorHeader.StrongNameSignatureDirectory; if (!peHeaders.TryGetDirectoryOffset(snDirectory, out int snOffset)) { return(false); } moduleContents.Position = 0; int peSize; try { peSize = checked ((int)moduleContents.Length); } catch { return(false); } var peImage = new BlobBuilder(peSize); if (peSize != peImage.TryWriteBytes(moduleContents, peSize)) { return(false); } byte[] buffer = GetBlobBuffer(peImage.GetBlobs().Single()); uint expectedChecksum = peHeaders.PEHeader.CheckSum; Blob checksumBlob = MakeBlob(buffer, peHeaders.PEHeaderStartOffset + ChecksumOffset, sizeof(uint)); if (expectedChecksum != PeWriter.CalculateChecksum(peImage, checksumBlob)) { return(false); } int snSize = snDirectory.Size; byte[] hash = ComputeSigningHash(peImage, peHeaders, checksumBlob, snOffset, snSize); ImmutableArray <byte> publicKeyBlob = metadataReader.GetBlobContent(metadataReader.GetAssemblyDefinition().PublicKey); // RSA parameters start after the public key offset byte[] publicKeyParams = new byte[publicKeyBlob.Length - CryptoBlobParser.s_publicKeyHeaderSize]; publicKeyBlob.CopyTo(CryptoBlobParser.s_publicKeyHeaderSize, publicKeyParams, 0, publicKeyParams.Length); var snKey = publicKeyParams.ToRSAParameters(includePrivateParameters: false); using (var rsa = RSA.Create()) { rsa.ImportParameters(snKey); var reversedSignature = peReader.GetSectionData(snDirectory.RelativeVirtualAddress).GetContent(0, snSize).ToArray(); // Unknown why the signature is reversed, but this matches the behavior of the CLR // signing implementation. Array.Reverse(reversedSignature); if (!rsa.VerifyHash(hash, reversedSignature, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1)) { return(false); } } return(true); } } finally { moduleContents.Position = savedPosition; } }
private static bool TestChecksumAndAuthenticodeSignature(Stream peStream, byte[] privateKeyOpt = null) { var peHeaders = new PEHeaders(peStream); bool is32bit = peHeaders.PEHeader.Magic == PEMagic.PE32; uint expectedChecksum = peHeaders.PEHeader.CheckSum; int peHeadersSize = peHeaders.PEHeaderStartOffset + PEHeader.Size(is32bit) + SectionHeader.Size * peHeaders.SectionHeaders.Length; peStream.Position = 0; if (expectedChecksum == 0) { // not signed return false; } int peSize = (int)peStream.Length; var peImage = new BlobBuilder(peSize); Assert.Equal(peSize, peImage.TryWriteBytes(peStream, peSize)); var buffer = peImage.GetBlobs().Single().Buffer; var checksumBlob = new Blob(buffer, peHeaders.PEHeaderStartOffset + PEHeader.OffsetOfChecksum, sizeof(uint)); uint checksum = PEBuilder.CalculateChecksum(peImage, checksumBlob); Assert.Equal(expectedChecksum, checksum); // validate signature: if (privateKeyOpt != null) { // signature is calculated with checksum zeroed: new BlobWriter(checksumBlob).WriteUInt32(0); int snOffset; Assert.True(peHeaders.TryGetDirectoryOffset(peHeaders.CorHeader.StrongNameSignatureDirectory, out snOffset)); var snBlob = new Blob(buffer, snOffset, peHeaders.CorHeader.StrongNameSignatureDirectory.Size); var expectedSignature = snBlob.GetBytes().ToArray(); var signature = SigningUtilities.CalculateRsaSignature(PEBuilder.GetContentToSign(peImage, peHeadersSize, peHeaders.PEHeader.FileAlignment, snBlob), privateKeyOpt); AssertEx.Equal(expectedSignature, signature); } return true; }