/// <summary> /// Serialized #Pdb stream. /// </summary> protected override void SerializeStandalonePdbStream(BlobBuilder builder) { int startPosition = builder.Position; // the id will be filled in later _pdbIdBlob = builder.ReserveBytes(MetadataSizes.PdbIdSize); builder.WriteInt32(_entryPoint.IsNil ? 0 : MetadataTokens.GetToken(_entryPoint)); builder.WriteUInt64(MetadataSizes.ExternalTablesMask); MetadataWriterUtilities.SerializeRowCounts(builder, MetadataSizes.ExternalRowCounts); int endPosition = builder.Position; Debug.Assert(MetadataSizes.CalculateStandalonePdbStreamSize() == endPosition - startPosition); }
public ExceptionRegionEncoder WriteInstructions(ImmutableArray<byte> instructions, out int bodyOffset, out Blob instructionBlob) { bodyOffset = WriteHeader(instructions.Length); instructionBlob = Builder.ReserveBytes(instructions.Length); new BlobWriter(instructionBlob).WriteBytes(instructions); return CreateExceptionEncoder(); }
private int WriteHeader(int codeSize, bool codeSizeFixup, out Blob codeSizeBlob) { const int TinyFormat = 2; const int FatFormat = 3; const int MoreSections = 8; const byte InitLocals = 0x10; int offset; if (IsTiny(codeSize)) { offset = Builder.Count; Builder.WriteByte((byte)((codeSize << 2) | TinyFormat)); Debug.Assert(!codeSizeFixup); codeSizeBlob = default(Blob); } else { Builder.Align(4); offset = Builder.Count; ushort flags = (3 << 12) | FatFormat; if (_exceptionRegionCount > 0) { flags |= MoreSections; } if ((_attributes & (int)MethodBodyAttributes.InitLocals) != 0) { flags |= InitLocals; } Builder.WriteUInt16((ushort)(_attributes | flags)); Builder.WriteUInt16(_maxStack); if (codeSizeFixup) { codeSizeBlob = Builder.ReserveBytes(sizeof(int)); } else { codeSizeBlob = default(Blob); Builder.WriteInt32(codeSize); } Builder.WriteInt32(_localVariablesSignature.IsNil ? 0 : MetadataTokens.GetToken(_localVariablesSignature)); } return offset; }
private void WriteCoffHeader(BlobBuilder builder, ImmutableArray<SerializedSection> sections, out Blob stampFixup) { // Machine builder.WriteUInt16((ushort)(Header.Machine == 0 ? Machine.I386 : Header.Machine)); // NumberOfSections builder.WriteUInt16((ushort)sections.Length); // TimeDateStamp: stampFixup = builder.ReserveBytes(sizeof(uint)); // PointerToSymbolTable (TODO: not supported): // The file pointer to the COFF symbol table, or zero if no COFF symbol table is present. // This value should be zero for a PE image. builder.WriteUInt32(0); // NumberOfSymbols (TODO: not supported): // The number of entries in the symbol table. This data can be used to locate the string table, // which immediately follows the symbol table. This value should be zero for a PE image. builder.WriteUInt32(0); // SizeOfOptionalHeader: // The size of the optional header, which is required for executable files but not for object files. // This value should be zero for an object file (TODO). builder.WriteUInt16((ushort)(Header.Is32Bit ? 224 : 240)); // Characteristics builder.WriteUInt16((ushort)Header.ImageCharacteristics); }
public DynamicAnalysisDataReader(byte* buffer, int size) { var reader = new BlobReader(buffer, size); // header: if (reader.ReadByte() != 'D' || reader.ReadByte() != 'A' || reader.ReadByte() != 'M' || reader.ReadByte() != 'D') { throw new BadImageFormatException(); } // version byte major = reader.ReadByte(); byte minor = reader.ReadByte(); if (major != 0 || minor < 1 || minor > 2) { throw new NotSupportedException(); } // table sizes: int documentRowCount = reader.ReadInt32(); int methodSpanRowCount = reader.ReadInt32(); // blob heap sizes: int stringHeapSize = (minor == 1) ? reader.ReadInt32() : 0; int userStringHeapSize = (minor == 1) ? reader.ReadInt32() : 0; int guidHeapSize = reader.ReadInt32(); int blobHeapSize = reader.ReadInt32(); // TODO: check size ranges bool isBlobHeapSmall = blobHeapSize <= ushort.MaxValue; bool isGuidHeapSmall = guidHeapSize / GuidSize <= ushort.MaxValue; var documentsBuilder = ArrayBuilder<DynamicAnalysisDocument>.GetInstance(documentRowCount); for (int i = 0; i < documentRowCount; i++) { var name = MetadataTokens.BlobHandle(ReadReference(ref reader, isBlobHeapSmall)); var hashAlgorithm = MetadataTokens.GuidHandle(ReadReference(ref reader, isGuidHeapSmall)); var hash = MetadataTokens.BlobHandle(ReadReference(ref reader, isBlobHeapSmall)); documentsBuilder.Add(new DynamicAnalysisDocument(name, hashAlgorithm, hash)); } Documents = documentsBuilder.ToImmutableAndFree(); var methodsBuilder = ArrayBuilder<DynamicAnalysisMethod>.GetInstance(methodSpanRowCount); for (int i = 0; i < methodSpanRowCount; i++) { methodsBuilder.Add(new DynamicAnalysisMethod(MetadataTokens.BlobHandle(ReadReference(ref reader, isBlobHeapSmall)))); } Methods = methodsBuilder.ToImmutableAndFree(); int stringHeapOffset = reader.Offset; int userStringHeapOffset = stringHeapOffset + stringHeapSize; int guidHeapOffset = userStringHeapOffset + userStringHeapSize; int blobHeapOffset = guidHeapOffset + guidHeapSize; if (reader.Length != blobHeapOffset + blobHeapSize) { throw new BadImageFormatException(); } _guidHeapBlob = new Blob(buffer + guidHeapOffset, guidHeapSize); _blobHeapBlob = new Blob(buffer + blobHeapOffset, blobHeapSize); }
internal void Sign(BlobBuilder peImage, Blob strongNameSignatureFixup, Func<IEnumerable<Blob>, byte[]> signatureProvider) { Debug.Assert(peImage != null); Debug.Assert(signatureProvider != null); int peHeadersSize = Header.ComputeSizeOfPEHeaders(GetSections().Length); byte[] signature = signatureProvider(GetContentToSign(peImage, peHeadersSize, Header.FileAlignment, strongNameSignatureFixup)); // signature may be shorter (the rest of the reserved space is padding): if (signature == null || signature.Length > strongNameSignatureFixup.Length) { throw new InvalidOperationException(SR.SignatureProviderReturnedInvalidSignature); } uint checksum = CalculateChecksum(peImage, _lazyChecksum); new BlobWriter(_lazyChecksum).WriteUInt32(checksum); var writer = new BlobWriter(strongNameSignatureFixup); writer.WriteBytes(signature); }
// internal for testing internal static uint CalculateChecksum(BlobBuilder peImage, Blob checksumFixup) { return CalculateChecksum(GetContentToChecksum(peImage, checksumFixup)) + (uint)peImage.Count; }
internal static Blob GetSuffixBlob(Blob container, Blob blob) => new Blob(container.Buffer, blob.Start + blob.Length, container.Start + container.Length - blob.Start - blob.Length);
// internal for testing internal static IEnumerable<Blob> GetContentToChecksum(BlobBuilder peImage, Blob checksumFixup) { foreach (var blob in peImage.GetBlobs()) { if (blob.Buffer == checksumFixup.Buffer) { yield return GetPrefixBlob(blob, checksumFixup); yield return GetSuffixBlob(blob, checksumFixup); } else { yield return blob; } } }
// internal for testing internal static Blob GetPrefixBlob(Blob container, Blob blob) => new Blob(container.Buffer, container.Start, blob.Start - container.Start);
// internal for testing internal static IEnumerable<Blob> GetContentToSign(BlobBuilder peImage, int peHeadersSize, int peHeaderAlignment, Blob strongNameSignatureFixup) { // Signed content includes // - PE header without its alignment padding // - all sections including their alignment padding and excluding strong name signature blob // PE specification: // To calculate the PE image hash, Authenticode orders the sections that are specified in the section table // by address range, then hashes the resulting sequence of bytes, passing over the exclusion ranges. // // Note that sections are by construction ordered by their address, so there is no need to reorder. int remainingHeaderToSign = peHeadersSize; int remainingHeader = BitArithmetic.Align(peHeadersSize, peHeaderAlignment); foreach (var blob in peImage.GetBlobs()) { int blobStart = blob.Start; int blobLength = blob.Length; while (blobLength > 0) { if (remainingHeader > 0) { int length; if (remainingHeaderToSign > 0) { length = Math.Min(remainingHeaderToSign, blobLength); yield return new Blob(blob.Buffer, blobStart, length); remainingHeaderToSign -= length; } else { length = Math.Min(remainingHeader, blobLength); } remainingHeader -= length; blobStart += length; blobLength -= length; } else if (blob.Buffer == strongNameSignatureFixup.Buffer) { yield return GetPrefixBlob(new Blob(blob.Buffer, blobStart, blobLength), strongNameSignatureFixup); yield return GetSuffixBlob(new Blob(blob.Buffer, blobStart, blobLength), strongNameSignatureFixup); break; } else { yield return new Blob(blob.Buffer, blobStart, blobLength); break; } } } }
private void WritePEHeader(BlobBuilder builder, PEDirectoriesBuilder directories, ImmutableArray<SerializedSection> sections) { builder.WriteUInt16((ushort)(Header.Is32Bit ? PEMagic.PE32 : PEMagic.PE32Plus)); builder.WriteByte(Header.MajorLinkerVersion); builder.WriteByte(Header.MinorLinkerVersion); // SizeOfCode: builder.WriteUInt32((uint)SumRawDataSizes(sections, SectionCharacteristics.ContainsCode)); // SizeOfInitializedData: builder.WriteUInt32((uint)SumRawDataSizes(sections, SectionCharacteristics.ContainsInitializedData)); // SizeOfUninitializedData: builder.WriteUInt32((uint)SumRawDataSizes(sections, SectionCharacteristics.ContainsUninitializedData)); // AddressOfEntryPoint: builder.WriteUInt32((uint)directories.AddressOfEntryPoint); // BaseOfCode: int codeSectionIndex = IndexOfSection(sections, SectionCharacteristics.ContainsCode); builder.WriteUInt32((uint)(codeSectionIndex != -1 ? sections[codeSectionIndex].RelativeVirtualAddress : 0)); if (Header.Is32Bit) { // BaseOfData: int dataSectionIndex = IndexOfSection(sections, SectionCharacteristics.ContainsInitializedData); builder.WriteUInt32((uint)(dataSectionIndex != -1 ? sections[dataSectionIndex].RelativeVirtualAddress : 0)); builder.WriteUInt32((uint)Header.ImageBase); } else { builder.WriteUInt64(Header.ImageBase); } // NT additional fields: builder.WriteUInt32((uint)Header.SectionAlignment); builder.WriteUInt32((uint)Header.FileAlignment); builder.WriteUInt16(Header.MajorOperatingSystemVersion); builder.WriteUInt16(Header.MinorOperatingSystemVersion); builder.WriteUInt16(Header.MajorImageVersion); builder.WriteUInt16(Header.MinorImageVersion); builder.WriteUInt16(Header.MajorSubsystemVersion); builder.WriteUInt16(Header.MinorSubsystemVersion); // Win32VersionValue (reserved, should be 0) builder.WriteUInt32(0); // SizeOfImage: var lastSection = sections[sections.Length - 1]; builder.WriteUInt32((uint)BitArithmetic.Align(lastSection.RelativeVirtualAddress + lastSection.VirtualSize, Header.SectionAlignment)); // SizeOfHeaders: builder.WriteUInt32((uint)BitArithmetic.Align(Header.ComputeSizeOfPEHeaders(sections.Length), Header.FileAlignment)); // Checksum: // Shall be zero for strong name signing. _lazyChecksum = builder.ReserveBytes(sizeof(uint)); new BlobWriter(_lazyChecksum).WriteUInt32(0); builder.WriteUInt16((ushort)Header.Subsystem); builder.WriteUInt16((ushort)Header.DllCharacteristics); if (Header.Is32Bit) { builder.WriteUInt32((uint)Header.SizeOfStackReserve); builder.WriteUInt32((uint)Header.SizeOfStackCommit); builder.WriteUInt32((uint)Header.SizeOfHeapReserve); builder.WriteUInt32((uint)Header.SizeOfHeapCommit); } else { builder.WriteUInt64(Header.SizeOfStackReserve); builder.WriteUInt64(Header.SizeOfStackCommit); builder.WriteUInt64(Header.SizeOfHeapReserve); builder.WriteUInt64(Header.SizeOfHeapCommit); } // LoaderFlags builder.WriteUInt32(0); // The number of data-directory entries in the remainder of the header. builder.WriteUInt32(16); // directory entries: builder.WriteUInt32((uint)directories.ExportTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.ExportTable.Size); builder.WriteUInt32((uint)directories.ImportTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.ImportTable.Size); builder.WriteUInt32((uint)directories.ResourceTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.ResourceTable.Size); builder.WriteUInt32((uint)directories.ExceptionTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.ExceptionTable.Size); // Authenticode CertificateTable directory. Shall be zero before the PE is signed. builder.WriteUInt32(0); builder.WriteUInt32(0); builder.WriteUInt32((uint)directories.BaseRelocationTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.BaseRelocationTable.Size); builder.WriteUInt32((uint)directories.DebugTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.DebugTable.Size); builder.WriteUInt32((uint)directories.CopyrightTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.CopyrightTable.Size); builder.WriteUInt32((uint)directories.GlobalPointerTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.GlobalPointerTable.Size); builder.WriteUInt32((uint)directories.ThreadLocalStorageTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.ThreadLocalStorageTable.Size); builder.WriteUInt32((uint)directories.LoadConfigTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.LoadConfigTable.Size); builder.WriteUInt32((uint)directories.BoundImportTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.BoundImportTable.Size); builder.WriteUInt32((uint)directories.ImportAddressTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.ImportAddressTable.Size); builder.WriteUInt32((uint)directories.DelayImportTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.DelayImportTable.Size); builder.WriteUInt32((uint)directories.CorHeaderTable.RelativeVirtualAddress); builder.WriteUInt32((uint)directories.CorHeaderTable.Size); // Reserved, should be 0 builder.WriteUInt64(0); }
/// <summary> /// Serializes .text section data into a specified <paramref name="builder"/>. /// </summary> /// <param name="builder">An empty builder to serialize section data to.</param> /// <param name="relativeVirtualAddess">Relative virtual address of the section within the containing PE file.</param> /// <param name="entryPointTokenOrRelativeVirtualAddress">Entry point token or RVA (<see cref="CorHeader.EntryPointTokenOrRelativeVirtualAddress"/>)</param> /// <param name="corFlags">COR Flags (<see cref="CorHeader.Flags"/>).</param> /// <param name="baseAddress">Base address of the PE image.</param> /// <param name="metadataBuilder"><see cref="BlobBuilder"/> containing metadata. Must be populated with data. Linked into the <paramref name="builder"/> and can't be expanded afterwards.</param> /// <param name="ilBuilder"><see cref="BlobBuilder"/> containing IL stream. Must be populated with data. Linked into the <paramref name="builder"/> and can't be expanded afterwards.</param> /// <param name="mappedFieldDataBuilderOpt"><see cref="BlobBuilder"/> containing mapped field data. Must be populated with data. Linked into the <paramref name="builder"/> and can't be expanded afterwards.</param> /// <param name="resourceBuilderOpt"><see cref="BlobBuilder"/> containing managed resource data. Must be populated with data. Linked into the <paramref name="builder"/> and can't be expanded afterwards.</param> /// <param name="debugDataBuilderOpt"><see cref="BlobBuilder"/> containing PE debug table and data. Must be populated with data. Linked into the <paramref name="builder"/> and can't be expanded afterwards.</param> /// <param name="strongNameSignature">Blob reserved in the <paramref name="builder"/> for strong name signature.</param> public void Serialize( BlobBuilder builder, int relativeVirtualAddess, int entryPointTokenOrRelativeVirtualAddress, CorFlags corFlags, ulong baseAddress, BlobBuilder metadataBuilder, BlobBuilder ilBuilder, BlobBuilder mappedFieldDataBuilderOpt, BlobBuilder resourceBuilderOpt, BlobBuilder debugDataBuilderOpt, out Blob strongNameSignature) { Debug.Assert(builder.Count == 0); Debug.Assert(metadataBuilder.Count == MetadataSize); Debug.Assert(metadataBuilder.Count % 4 == 0); Debug.Assert(ilBuilder.Count == ILStreamSize); Debug.Assert((mappedFieldDataBuilderOpt?.Count ?? 0) == MappedFieldDataSize); Debug.Assert((resourceBuilderOpt?.Count ?? 0) == ResourceDataSize); Debug.Assert((resourceBuilderOpt?.Count ?? 0) % 4 == 0); // TODO: avoid recalculation int importTableRva = GetImportTableDirectoryEntry(relativeVirtualAddess).RelativeVirtualAddress; int importAddressTableRva = GetImportAddressTableDirectoryEntry(relativeVirtualAddess).RelativeVirtualAddress; if (RequiresStartupStub) { WriteImportAddressTable(builder, importTableRva); } WriteCorHeader(builder, relativeVirtualAddess, entryPointTokenOrRelativeVirtualAddress, corFlags); // IL: ilBuilder.Align(4); builder.LinkSuffix(ilBuilder); // metadata: builder.LinkSuffix(metadataBuilder); // managed resources: if (resourceBuilderOpt != null) { builder.LinkSuffix(resourceBuilderOpt); } // strong name signature: strongNameSignature = builder.ReserveBytes(StrongNameSignatureSize); // The bytes are required to be 0 for the purpose of calculating hash of the PE content // when strong name signing. new BlobWriter(strongNameSignature).WriteBytes(0, StrongNameSignatureSize); // debug directory and data: if (debugDataBuilderOpt != null) { builder.LinkSuffix(debugDataBuilderOpt); } if (RequiresStartupStub) { WriteImportTable(builder, importTableRva, importAddressTableRva); WriteNameTable(builder); WriteRuntimeStartupStub(builder, importAddressTableRva, baseAddress); } // mapped field data: if (mappedFieldDataBuilderOpt != null) { builder.LinkSuffix(mappedFieldDataBuilderOpt); } Debug.Assert(builder.Count == ComputeSizeOfTextSection()); }
public BlobWriter(Blob blob) : this(blob.Buffer, blob.Start, blob.Length) { }