Example #1
0
        /// <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);
        }
Example #2
0
 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();
 }
Example #3
0
        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;
        }
Example #4
0
        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);
        }
Example #6
0
        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);
        }
Example #7
0
 // internal for testing
 internal static uint CalculateChecksum(BlobBuilder peImage, Blob checksumFixup)
 {
     return CalculateChecksum(GetContentToChecksum(peImage, checksumFixup)) + (uint)peImage.Count;
 }
Example #8
0
 internal static Blob GetSuffixBlob(Blob container, Blob blob) => new Blob(container.Buffer, blob.Start + blob.Length, container.Start + container.Length - blob.Start - blob.Length);
Example #9
0
 // 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;
         }
     }
 }
Example #10
0
 // internal for testing
 internal static Blob GetPrefixBlob(Blob container, Blob blob) => new Blob(container.Buffer, container.Start, blob.Start - container.Start);
Example #11
0
        // 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;
                    }
                }
            }
        }
Example #12
0
        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);
        }
Example #13
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());
        }
Example #14
0
 public BlobWriter(Blob blob)
     : this(blob.Buffer, blob.Start, blob.Length)
 {
 }