public void Analyze(BinaryAnalyzerContext context)
        {
            PEHeader           peHeader           = context.PE.PEHeaders.PEHeader;
            DllCharacteristics dllCharacteristics = peHeader.DllCharacteristics;

            CoffHeader      coffHeader      = context.PE.PEHeaders.CoffHeader;
            Characteristics characteristics = coffHeader.Characteristics;


            bool highEntropyVA = ((int)dllCharacteristics & 0x0020 /*IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA*/) == 0x0020;

            //  /LARGEADDRESSAWARE is necessary for HIGH_ENTROPY_VA to have effect
            bool largeAddressAware = (characteristics & Characteristics.LargeAddressAware /*IMAGE_FILE_LARGE_ADDRESS_AWARE*/) == Characteristics.LargeAddressAware;

            if (!highEntropyVA && !largeAddressAware)
            {
                // '{0}' does not declare itself as high entropy ASLR compatible. High entropy allows
                // Address Space Layout Randomization to be more effective in mitigating memory
                // corruption vulnerabilities. To resolve this issue, configure your tool chain to
                // mark the program high entropy compatible; e.g. by supplying /HIGHENTROPYVA as well
                // as /LARGEADDRESSAWARE to the C or C++ linker command line.
                context.Logger.Log(MessageKind.Fail, context,
                                   RuleUtilities.BuildMessage(context,
                                                              RulesResources.EnableHighEntropyVirtualAddresses_NeitherHighEntropyVANorLargeAddressAware_FAIL));
                return;
            }

            if (!highEntropyVA)
            {
                // '{0}' does not declare itself as high entropy ASLR compatible. High entropy allows
                // Address Space Layout Randomization to be more effective in mitigating memory
                // corruption vulnerabilities. To resolve this issue, configure your tool chain to
                // mark the program high entropy compatible; e.g. by supplying /HIGHENTROPYVA to the
                // C or C++ linker command line. (This image was determined to have been properly
                // compiled as /LARGEADDRESSAWARE.)
                context.Logger.Log(MessageKind.Fail, context,
                                   RuleUtilities.BuildMessage(context,
                                                              RulesResources.EnableHighEntropyVirtualAddresses_NoHighEntropyVA_FAIL));
                return;
            }

            if (!largeAddressAware)
            {
                // '{0}' does not declare itself as high entropy ASLR compatible. High entropy allows
                // Address Space Layout Randomization to be more effective in mitigating memory
                // corruption vulnerabilities. To resolve this issue, configure your tool chain to
                // mark the program high entropy compatible by supplying /LARGEADDRESSAWARE to the C
                // or C++ linker command line. (This image was determined to have been properly
                // compiled as /HIGHENTROPYVA.)
                context.Logger.Log(MessageKind.Fail, context,
                                   RuleUtilities.BuildMessage(context,
                                                              RulesResources.EnableHighEntropyVirtualAddresses_NoLargeAddressAware_FAIL));
                return;
            }

            //'{0}' is high entropy ASLR compatible.
            context.Logger.Log(MessageKind.Pass, context,
                               RuleUtilities.BuildMessage(context,
                                                          RulesResources.EnableHighEntropyVirtualAddresses_Pass));
        }
            private void _read()
            {
                _peSignature      = m_io.EnsureFixedContents(new byte[] { 80, 69, 0, 0 });
                _coffHdr          = new CoffHeader(m_io, this, m_root);
                __raw_optionalHdr = m_io.ReadBytes(CoffHdr.SizeOfOptionalHeader);
                var io___raw_optionalHdr = new KaitaiStream(__raw_optionalHdr);

                _optionalHdr = new OptionalHeader(io___raw_optionalHdr, this, m_root);
                _sections    = new List <Section>((int)(CoffHdr.NumberOfSections));
                for (var i = 0; i < CoffHdr.NumberOfSections; i++)
                {
                    _sections.Add(new Section(m_io, this, m_root));
                }
            }
Exemple #3
0
        public static void GetEmbeddedModule(ModuleReader reader)
        {
            // Read the MZ signature.
            if (reader.ReadByte() != 'M' || reader.ReadByte() != 'Z')
            {
                throw new ModuleException("Invalid PE signature.");
            }

            // Read the PE offset.
            reader.SetPosition(0x3c);
            uint peOffset = reader.ReadUInt();

            // Read the PE\0\0 sinature
            reader.SetPosition(peOffset);
            if (reader.ReadByte() != 'P' || reader.ReadByte() != 'E' ||
                reader.ReadByte() != 0 || reader.ReadByte() != 0)
            {
                throw new ModuleException("Unsupported MS DOS programs.");
            }

            // Read the COFF header.
            CoffHeader header = new CoffHeader();

            header.Read(reader);

            // Ignore the optional header.
            reader.Skip(header.optionalHeaderSize);

            // Read the sections until finding the .cbm section.
            CoffSectionHeader sectionHeader = new CoffSectionHeader();

            for (int i = 0; i < header.numSections; ++i)
            {
                // Read the section header.
                sectionHeader.Read(reader);

                // If this is the .cbm section, done.
                if (sectionHeader.name == ".cbm")
                {
                    reader.SetPosition(sectionHeader.rawDataPointer);
                    return;
                }
            }

            // Couldn't find embedded module.
            throw new ModuleException("Couldn't find embedded Chela module.");
        }
Exemple #4
0
            private void _read()
            {
                _peSignature = m_io.ReadBytes(4);
                if (!((KaitaiStream.ByteArrayCompare(PeSignature, new byte[] { 80, 69, 0, 0 }) == 0)))
                {
                    throw new ValidationNotEqualError(new byte[] { 80, 69, 0, 0 }, PeSignature, M_Io, "/types/pe_header/seq/0");
                }
                _coffHdr          = new CoffHeader(m_io, this, m_root);
                __raw_optionalHdr = m_io.ReadBytes(CoffHdr.SizeOfOptionalHeader);
                var io___raw_optionalHdr = new KaitaiStream(__raw_optionalHdr);

                _optionalHdr = new OptionalHeader(io___raw_optionalHdr, this, m_root);
                _sections    = new List <Section>();
                for (var i = 0; i < CoffHdr.NumberOfSections; i++)
                {
                    _sections.Add(new Section(m_io, this, m_root));
                }
            }
Exemple #5
0
        public static void GetEmbeddedModule(ModuleReader reader)
        {
            // Read the MZ signature.
            if(reader.ReadByte() != 'M' || reader.ReadByte() != 'Z')
                throw new ModuleException("Invalid PE signature.");

            // Read the PE offset.
            reader.SetPosition(0x3c);
            uint peOffset = reader.ReadUInt();

            // Read the PE\0\0 sinature
            reader.SetPosition(peOffset);
            if(reader.ReadByte() != 'P' || reader.ReadByte() != 'E' ||
                reader.ReadByte() != 0 || reader.ReadByte() != 0)
                throw new ModuleException("Unsupported MS DOS programs.");

            // Read the COFF header.
            CoffHeader header = new CoffHeader();
            header.Read(reader);

            // Ignore the optional header.
            reader.Skip(header.optionalHeaderSize);

            // Read the sections until finding the .cbm section.
            CoffSectionHeader sectionHeader = new CoffSectionHeader();
            for(int i = 0; i < header.numSections; ++i)
            {
                // Read the section header.
                sectionHeader.Read(reader);

                // If this is the .cbm section, done.
                if(sectionHeader.name == ".cbm")
                {
                    reader.SetPosition(sectionHeader.rawDataPointer);
                    return;
                }
            }

            // Couldn't find embedded module.
            throw new ModuleException("Couldn't find embedded Chela module.");
        }
Exemple #6
0
        private void FillInNtHeader(
            List<SectionHeader> sectionHeaders, 
            int entryPointAddress,
            DirectoryEntry corHeader,
            DirectoryEntry importTable,
            DirectoryEntry importAddressTable,
            DirectoryEntry debugTable,
            out CoffHeader coffHeader,
            out NtHeader ntHeader)
        {
            short sectionCount = (short)sectionHeaders.Count;

            coffHeader = new CoffHeader(
                machine: (_properties.Machine == 0) ? Machine.I386 : _properties.Machine,
                numberOfSections: sectionCount,
                timeDateStamp: _timeStamp,
                pointerToSymbolTable: 0,
                numberOfSymbols: 0,
                sizeOfOptionalHeader: (short)(_is32bit ? 224 : 240), // TODO: constants
                characteristics: _properties.ImageCharacteristics);

            SectionHeader codeSection = sectionHeaders.FirstOrDefault(sh => (sh.Characteristics & SectionCharacteristics.ContainsCode) != 0);
            SectionHeader dataSection = sectionHeaders.FirstOrDefault(sh => (sh.Characteristics & SectionCharacteristics.ContainsInitializedData) != 0);

            ntHeader = new NtHeader();
            ntHeader.Magic = _is32bit ? PEMagic.PE32 : PEMagic.PE32Plus;
            ntHeader.MajorLinkerVersion = _properties.LinkerMajorVersion;
            ntHeader.MinorLinkerVersion = _properties.LinkerMinorVersion;
            ntHeader.AddressOfEntryPoint = entryPointAddress;
            ntHeader.BaseOfCode = codeSection?.RelativeVirtualAddress ?? 0;
            ntHeader.BaseOfData = dataSection?.RelativeVirtualAddress ?? 0;
            ntHeader.ImageBase = _properties.BaseAddress;
            ntHeader.FileAlignment = _properties.FileAlignment;
            ntHeader.MajorSubsystemVersion = _properties.MajorSubsystemVersion;
            ntHeader.MinorSubsystemVersion = _properties.MinorSubsystemVersion;

            ntHeader.Subsystem = _properties.Subsystem;
            ntHeader.DllCharacteristics = _properties.DllCharacteristics;

            ntHeader.SizeOfStackReserve = _properties.SizeOfStackReserve;
            ntHeader.SizeOfStackCommit = _properties.SizeOfStackCommit;
            ntHeader.SizeOfHeapReserve = _properties.SizeOfHeapReserve; 
            ntHeader.SizeOfHeapCommit = _properties.SizeOfHeapCommit;

            ntHeader.SizeOfCode = codeSection?.SizeOfRawData ?? 0;

            ntHeader.SizeOfInitializedData = sectionHeaders.Sum(
                sectionHeader => (sectionHeader.Characteristics & SectionCharacteristics.ContainsInitializedData) != 0 ? sectionHeader.SizeOfRawData : 0);

            ntHeader.SizeOfHeaders = BitArithmeticUtilities.Align(ComputeSizeOfPeHeaders(sectionCount), _properties.FileAlignment);

            var lastSection = sectionHeaders.Last();
            ntHeader.SizeOfImage = BitArithmeticUtilities.Align(lastSection.RelativeVirtualAddress + lastSection.VirtualSize, _properties.SectionAlignment);
            ntHeader.SizeOfUninitializedData = 0;

            ntHeader.ImportAddressTable = importAddressTable;
            ntHeader.CliHeaderTable = corHeader;
            ntHeader.ImportTable = importTable;

            var relocSection = sectionHeaders.FirstOrDefault(sectionHeader => sectionHeader.Name == RelocationSectionName);
            if (relocSection != null)
            {
                ntHeader.BaseRelocationTable = new DirectoryEntry(relocSection.RelativeVirtualAddress, relocSection.VirtualSize);
            }

            ntHeader.DebugTable = debugTable;

            var resourceSection = sectionHeaders.FirstOrDefault(sectionHeader => sectionHeader.Name == ResourceSectionName);
            if (resourceSection != null)
            {
                ntHeader.ResourceTable = new DirectoryEntry(resourceSection.RelativeVirtualAddress, resourceSection.VirtualSize);
            }
        }
Exemple #7
0
        private void WriteHeaders(Stream peStream, NtHeader ntHeader, CoffHeader coffHeader, List<SectionHeader> sectionHeaders, out long ntHeaderTimestampPosition)
        {
            var writer = PooledBlobBuilder.GetInstance();

            // MS-DOS stub (128 bytes)
            writer.WriteBytes(s_dosHeader);

            // PE Signature "PE\0\0" 
            writer.WriteUInt32(0x00004550);

            // COFF Header (20 bytes)
            writer.WriteUInt16((ushort)coffHeader.Machine);
            writer.WriteUInt16((ushort)coffHeader.NumberOfSections);
            ntHeaderTimestampPosition = writer.Position + peStream.Position;
            writer.WriteUInt32((uint)coffHeader.TimeDateStamp);
            writer.WriteUInt32((uint)coffHeader.PointerToSymbolTable);
            writer.WriteUInt32((uint)coffHeader.NumberOfSymbols);
            writer.WriteUInt16((ushort)(_is32bit ? 224 : 240)); // SizeOfOptionalHeader
            writer.WriteUInt16((ushort)coffHeader.Characteristics);

            // PE Headers:
            writer.WriteUInt16((ushort)(_is32bit ? PEMagic.PE32 : PEMagic.PE32Plus)); // 2
            writer.WriteByte(ntHeader.MajorLinkerVersion); // 3
            writer.WriteByte(ntHeader.MinorLinkerVersion); // 4
            writer.WriteUInt32((uint)ntHeader.SizeOfCode); // 8
            writer.WriteUInt32((uint)ntHeader.SizeOfInitializedData); // 12
            writer.WriteUInt32((uint)ntHeader.SizeOfUninitializedData); // 16
            writer.WriteUInt32((uint)ntHeader.AddressOfEntryPoint); // 20
            writer.WriteUInt32((uint)ntHeader.BaseOfCode); // 24

            if (_is32bit)
            {
                writer.WriteUInt32((uint)ntHeader.BaseOfData); // 28
                writer.WriteUInt32((uint)ntHeader.ImageBase); // 32
            }
            else
            {
                writer.WriteUInt64(ntHeader.ImageBase); // 32
            }

            // NT additional fields:
            writer.WriteUInt32((uint)ntHeader.SectionAlignment); // 36
            writer.WriteUInt32((uint)ntHeader.FileAlignment); // 40
            writer.WriteUInt16(ntHeader.MajorOperatingSystemVersion); // 42
            writer.WriteUInt16(ntHeader.MinorOperatingSystemVersion); // 44
            writer.WriteUInt16(ntHeader.MajorImageVersion); // 46
            writer.WriteUInt16(ntHeader.MinorImageVersion); // 48
            writer.WriteUInt16(ntHeader.MajorSubsystemVersion); // MajorSubsystemVersion 50
            writer.WriteUInt16(ntHeader.MinorSubsystemVersion); // MinorSubsystemVersion 52

            // Win32VersionValue (reserved, should be 0)
            writer.WriteUInt32(0); // 56

            writer.WriteUInt32((uint)ntHeader.SizeOfImage); // 60
            writer.WriteUInt32((uint)ntHeader.SizeOfHeaders); // 64
            writer.WriteUInt32(ntHeader.Checksum); // 68            
            writer.WriteUInt16((ushort)ntHeader.Subsystem); // 70
            writer.WriteUInt16((ushort)ntHeader.DllCharacteristics);

            if (_is32bit)
            {
                writer.WriteUInt32((uint)ntHeader.SizeOfStackReserve); // 76
                writer.WriteUInt32((uint)ntHeader.SizeOfStackCommit); // 80
                writer.WriteUInt32((uint)ntHeader.SizeOfHeapReserve); // 84
                writer.WriteUInt32((uint)ntHeader.SizeOfHeapCommit); // 88
            }
            else
            {
                writer.WriteUInt64(ntHeader.SizeOfStackReserve); // 80
                writer.WriteUInt64(ntHeader.SizeOfStackCommit); // 88
                writer.WriteUInt64(ntHeader.SizeOfHeapReserve); // 96
                writer.WriteUInt64(ntHeader.SizeOfHeapCommit); // 104
            }

            // LoaderFlags
            writer.WriteUInt32(0); // 92|108

            // The number of data-directory entries in the remainder of the header.
            writer.WriteUInt32(16); //  96|112

            // directory entries:
            writer.WriteUInt32((uint)ntHeader.ExportTable.RelativeVirtualAddress); // 100|116
            writer.WriteUInt32((uint)ntHeader.ExportTable.Size); // 104|120
            writer.WriteUInt32((uint)ntHeader.ImportTable.RelativeVirtualAddress); // 108|124
            writer.WriteUInt32((uint)ntHeader.ImportTable.Size); // 112|128
            writer.WriteUInt32((uint)ntHeader.ResourceTable.RelativeVirtualAddress); // 116|132
            writer.WriteUInt32((uint)ntHeader.ResourceTable.Size); // 120|136
            writer.WriteUInt32((uint)ntHeader.ExceptionTable.RelativeVirtualAddress); // 124|140
            writer.WriteUInt32((uint)ntHeader.ExceptionTable.Size); // 128|144
            writer.WriteUInt32((uint)ntHeader.CertificateTable.RelativeVirtualAddress); // 132|148
            writer.WriteUInt32((uint)ntHeader.CertificateTable.Size); // 136|152
            writer.WriteUInt32((uint)ntHeader.BaseRelocationTable.RelativeVirtualAddress); // 140|156
            writer.WriteUInt32((uint)ntHeader.BaseRelocationTable.Size); // 144|160
            writer.WriteUInt32((uint)ntHeader.DebugTable.RelativeVirtualAddress); // 148|164
            writer.WriteUInt32((uint)ntHeader.DebugTable.Size); // 152|168
            writer.WriteUInt32((uint)ntHeader.CopyrightTable.RelativeVirtualAddress); // 156|172
            writer.WriteUInt32((uint)ntHeader.CopyrightTable.Size); // 160|176
            writer.WriteUInt32((uint)ntHeader.GlobalPointerTable.RelativeVirtualAddress); // 164|180
            writer.WriteUInt32((uint)ntHeader.GlobalPointerTable.Size); // 168|184
            writer.WriteUInt32((uint)ntHeader.ThreadLocalStorageTable.RelativeVirtualAddress); // 172|188
            writer.WriteUInt32((uint)ntHeader.ThreadLocalStorageTable.Size); // 176|192
            writer.WriteUInt32((uint)ntHeader.LoadConfigTable.RelativeVirtualAddress); // 180|196
            writer.WriteUInt32((uint)ntHeader.LoadConfigTable.Size); // 184|200
            writer.WriteUInt32((uint)ntHeader.BoundImportTable.RelativeVirtualAddress); // 188|204
            writer.WriteUInt32((uint)ntHeader.BoundImportTable.Size); // 192|208
            writer.WriteUInt32((uint)ntHeader.ImportAddressTable.RelativeVirtualAddress); // 196|212
            writer.WriteUInt32((uint)ntHeader.ImportAddressTable.Size); // 200|216
            writer.WriteUInt32((uint)ntHeader.DelayImportTable.RelativeVirtualAddress); // 204|220
            writer.WriteUInt32((uint)ntHeader.DelayImportTable.Size); // 208|224
            writer.WriteUInt32((uint)ntHeader.CliHeaderTable.RelativeVirtualAddress); // 212|228
            writer.WriteUInt32((uint)ntHeader.CliHeaderTable.Size); // 216|232
            writer.WriteUInt64(0); // 224|240

            // Section Headers
            foreach (var sectionHeader in sectionHeaders)
            {
                WriteSectionHeader(sectionHeader, writer);
            }

            writer.WriteContentTo(peStream);
            writer.Free();
        }
        public override void Analyze(BinaryAnalyzerContext context)
        {
            PEBinary target         = context.PEBinary();
            PEHeader optionalHeader = target.PE.PEHeaders.PEHeader;

            if ((optionalHeader.DllCharacteristics & DllCharacteristics.DynamicBase) != DllCharacteristics.DynamicBase)
            {
                // '{0}' is not marked as DYNAMICBASE. This means that the binary is not eligible for relocation
                // by Address Space Layout Randomization (ASLR). ASLR is an important mitigation that makes it
                // more difficult for an attacker to exploit memory corruption vulnerabilities. To resolve this
                // issue, configure your tool chain to build with this feature enabled. For C and C++ binaries,
                // add /DYNAMICBASE to your linker command line. For .NET applications, use a compiler shipping
                // with Visual Studio 2008 or later.
                context.Logger.Log(this,
                                   RuleUtilities.BuildResult(FailureLevel.Error, context, null,
                                                             nameof(RuleResources.BA2009_Error_NotDynamicBase),
                                                             context.TargetUri.GetFileName()));
                return;
            }

            CoffHeader coffHeader = target.PE.PEHeaders.CoffHeader;

            if ((coffHeader.Characteristics & Characteristics.RelocsStripped) == Characteristics.RelocsStripped)
            {
                // '{0}' is marked as DYNAMICBASE but relocation data has been stripped
                // from the image, preventing address space layout randomization.
                context.Logger.Log(this,
                                   RuleUtilities.BuildResult(FailureLevel.Error, context, null,
                                                             nameof(RuleResources.BA2009_Error_RelocsStripped),
                                                             context.TargetUri.GetFileName()));
                return;
            }

            if (target.PE.Subsystem == Subsystem.WindowsCEGui)
            {
                Debug.Assert(target.PE.OSVersion >= OSVersions.WindowsCE7);

                bool relocSectionFound = false;


                // For WinCE 7+ ASLR is a machine-wide setting and binaries must
                // have relocation info present in order to be dynamically rebased.
                foreach (SectionHeader sectionHeader in target.PE.PEHeaders.SectionHeaders)
                {
                    if (sectionHeader.Name.Equals(".reloc", StringComparison.OrdinalIgnoreCase) &&
                        sectionHeader.SizeOfRawData > 0)
                    {
                        relocSectionFound = true;
                        break;
                    }
                }

                if (!relocSectionFound)
                {
                    // EnableAddressSpaceLayoutRandomization_WinCENoRelocationSection_Error	'{0}'
                    // is a Windows CE image but does not contain any relocation data, preventing
                    // address space layout randomization.
                    context.Logger.Log(this,
                                       RuleUtilities.BuildResult(FailureLevel.Error, context, null,
                                                                 nameof(RuleResources.BA2009_Error_WinCENoRelocationSection),
                                                                 context.TargetUri.GetFileName()));
                    return;
                }
            }

            //'{0}' is properly compiled to enable address space layout randomization.
            context.Logger.Log(this,
                               RuleUtilities.BuildResult(ResultKind.Pass, context, null,
                                                         nameof(RuleResources.BA2009_Pass),
                                                         context.TargetUri.GetFileName()));
        }
Exemple #9
0
        public static int Bind(string exefname, string pdbfname, int timestamp, Guid guid, int age)
        {
            pdbfname = Path.GetFileName(pdbfname);

            FileStream   stm = File.Open(exefname, FileMode.Open, FileAccess.ReadWrite);
            BinaryReader rdr = new BinaryReader(stm);
            BinaryWriter wrr = new BinaryWriter(stm);

            byte[] utf8pdbname        = Encoding.UTF8.GetBytes(pdbfname);
            int    debugDirectorySize = 0x1C;
            int    debugInfoSize      = 0x18 + utf8pdbname.Length + 1;
            int    debugSize          = debugDirectorySize + debugInfoSize;

            short magic = rdr.ReadInt16();

            if (magic != 0x5a4d)
            {
                Console.WriteLine("Error: invalid magic in DOS header");
                return(1);
            }
            stm.Position = 0x3c;
            int peoffset = rdr.ReadInt32();

            stm.Position = peoffset;
            int pemagic = rdr.ReadInt32();

            if (pemagic != 0x4550)
            {
                Console.WriteLine("Error: invalid pe magic");
                return(1);
            }
            CoffHeader coffHdr = new CoffHeader();

            coffHdr.Machine              = rdr.ReadInt16();
            coffHdr.NumberOfSections     = rdr.ReadInt16();
            coffHdr.TimeDateStamp        = rdr.ReadInt32();
            coffHdr.PointerToSymbolTable = rdr.ReadInt32();
            coffHdr.NumberOfSymbols      = rdr.ReadInt32();
            coffHdr.SizeOfOptionalHeader = rdr.ReadInt16();
            coffHdr.Flags = rdr.ReadInt16();
            int   optionalHeaderOffset = (int)stm.Position;
            int   sectionsOffset       = optionalHeaderOffset + coffHdr.SizeOfOptionalHeader;
            short optmagic             = rdr.ReadInt16();

            if (optmagic != 0x10b)
            {
                Console.WriteLine("Error: invalid or unsupported optional header magic");
                return(1);
            }
            stm.Position = optionalHeaderOffset + 32;
            int sectionAlignment         = rdr.ReadInt32();
            int fileAlignment            = rdr.ReadInt32();
            int numberOfDirEntriesOffset = optionalHeaderOffset + 92;

            stm.Position = numberOfDirEntriesOffset;
            int       numberOfDirEntries = rdr.ReadInt32();
            const int DEBUG_TABLE        = 6;

            if (numberOfDirEntries < DEBUG_TABLE + 1)
            {
                stm.Position = numberOfDirEntriesOffset;
                wrr.Write(DEBUG_TABLE + 1);
            }
            int debugTableEntryOffset = optionalHeaderOffset + 144;
            int debugTableEntryEnd    = optionalHeaderOffset + 152;

            if (debugTableEntryEnd > sectionsOffset)
            {
                Console.WriteLine("Error: not enough space for Debug directory entry, optional header must be resized, not implemented");
                return(1);
            }
            stm.Position = sectionsOffset;
            SectionHeader[] sectionHeaders = new SectionHeader[coffHdr.NumberOfSections];
            for (int i = 0; i < coffHdr.NumberOfSections; i++)
            {
                byte[] encname = rdr.ReadBytes(8);
                int    l       = 0;
                for (l = 0; l < 8; l++)
                {
                    if (encname[l] == 0)
                    {
                        break;
                    }
                }
                sectionHeaders[i].Name        = Encoding.UTF8.GetString(encname, 0, l);
                sectionHeaders[i].VirtualSize = rdr.ReadInt32();
                sectionHeaders[i].Rva         = rdr.ReadInt32();
                sectionHeaders[i].FileSize    = rdr.ReadInt32();
                sectionHeaders[i].FileOffset  = rdr.ReadInt32();
                sectionHeaders[i].RelocOffset = rdr.ReadInt32();
                sectionHeaders[i].LineOffset  = rdr.ReadInt32();
                sectionHeaders[i].RelocNum    = rdr.ReadInt16();
                sectionHeaders[i].LineNum     = rdr.ReadInt16();
                sectionHeaders[i].Flags       = rdr.ReadInt32();
            }
            int rdataIndex = -1;

            for (int i = 0; i < coffHdr.NumberOfSections; i++)
            {
                if (sectionHeaders[i].Name == ".rdata")
                {
                    rdataIndex = i;
                    break;
                }
            }
            if (rdataIndex == -1)
            {
                Console.WriteLine("Error: .rdata section not found");
                return(1);
            }
            SectionHeader rdataSect = sectionHeaders[rdataIndex];

            int debugSizeFileAligned       = RoundUp(debugSize, fileAlignment);
            int newRdataSizeFileAligned    = rdataSect.FileSize + debugSizeFileAligned;
            int newRdataSizeSectionAligned = RoundUp(newRdataSizeFileAligned, sectionAlignment);

            if (rdataSect.VirtualSize < newRdataSizeSectionAligned)
            {
                Console.WriteLine("Error: crossing section alignment boundary, relocation required, not implemented");
                return(1);
            }
            // injecting debug data
            // moving remains data
            int debugDataOffset     = rdataSect.FileOffset + rdataSect.FileSize;
            int debugDataEndAligned = debugDataOffset + debugSizeFileAligned;

            stm.Position = debugDataOffset;
            int remainsSize = (int)(stm.Length - stm.Position);

            byte[] remainsBuffer = new byte[remainsSize];
            stm.Read(remainsBuffer, 0, remainsSize);
            stm.Position = debugDataEndAligned;
            stm.Write(remainsBuffer, 0, remainsSize);
            // writing debug data directory
            stm.Position = debugDataOffset;
            wrr.Write((int)0);             // charateristics, reserved
            wrr.Write((int)timestamp);
            wrr.Write((int)0x0);           // version of debugging information format
            wrr.Write((int)2);             // CodeView type
            wrr.Write(debugInfoSize);
            int debugInfoRva = rdataSect.Rva + rdataSect.FileSize + debugDirectorySize;

            wrr.Write(debugInfoRva);
            int debugInfoFileOffset = rdataSect.FileOffset + rdataSect.FileSize + debugDirectorySize;

            wrr.Write(debugInfoFileOffset);
            // writing debug info
            wrr.Write(Encoding.UTF8.GetBytes("RSDS"));
            wrr.Write(guid.ToByteArray());
            wrr.Write(age);
            wrr.Write(utf8pdbname);
            wrr.Write((byte)0);
            int paddingSize = fileAlignment - (debugSize - debugSize / fileAlignment * fileAlignment);

            byte[] pad = new byte[paddingSize];
            wrr.Write(pad);
            // updating debug directory address in table
            int debugDirectoryRva = rdataSect.Rva + rdataSect.FileSize;

            stm.Position = debugTableEntryOffset;
            wrr.Write(debugDirectoryRva);
            wrr.Write(debugDirectorySize);
            // update rdata file size
            int sectionHeaderSize = 40;
            int sectionHeaderFileSizeFieldOffset   = 16;
            int sectionHeaderFileOffsetFieldOffset = 20;

            stm.Position = sectionsOffset + sectionHeaderSize * rdataIndex + sectionHeaderFileSizeFieldOffset;
            wrr.Write(newRdataSizeFileAligned);
            // updating sections offsets
            int delta = debugSizeFileAligned;

            for (int i = rdataIndex + 1; i < coffHdr.NumberOfSections; i++)
            {
                sectionHeaders[i].FileOffset += delta;
                stm.Position = sectionsOffset + sectionHeaderSize * i + sectionHeaderFileOffsetFieldOffset;
                wrr.Write(sectionHeaders[i].FileOffset);
            }
            stm.Close();
            return(0);
        }
Exemple #10
0
        public static int Bind(string exefname, string pdbfname, int timestamp, Guid guid, int age)
        {
            pdbfname = Path.GetFileName(pdbfname);

            FileStream stm = File.Open(exefname, FileMode.Open, FileAccess.ReadWrite);
            BinaryReader rdr = new BinaryReader(stm);
            BinaryWriter wrr = new BinaryWriter(stm);

            byte[] utf8pdbname = Encoding.UTF8.GetBytes(pdbfname);
            int debugDirectorySize = 0x1C;
            int debugInfoSize = 0x18 + utf8pdbname.Length + 1;
            int debugSize = debugDirectorySize + debugInfoSize;

            short magic = rdr.ReadInt16();
            if (magic != 0x5a4d)
            {
                Console.WriteLine("Error: invalid magic in DOS header");
                return 1;
            }
            stm.Position = 0x3c;
            int peoffset = rdr.ReadInt32();
            stm.Position = peoffset;
            int pemagic = rdr.ReadInt32();
            if (pemagic != 0x4550)
            {
                Console.WriteLine("Error: invalid pe magic");
                return 1;
            }
            CoffHeader coffHdr = new CoffHeader();
            coffHdr.Machine = rdr.ReadInt16();
            coffHdr.NumberOfSections = rdr.ReadInt16();
            coffHdr.TimeDateStamp = rdr.ReadInt32();
            coffHdr.PointerToSymbolTable = rdr.ReadInt32();
            coffHdr.NumberOfSymbols = rdr.ReadInt32();
            coffHdr.SizeOfOptionalHeader = rdr.ReadInt16();
            coffHdr.Flags = rdr.ReadInt16();
            int optionalHeaderOffset = (int)stm.Position;
            int sectionsOffset = optionalHeaderOffset + coffHdr.SizeOfOptionalHeader;
            short optmagic = rdr.ReadInt16();
            if (optmagic != 0x10b)
            {
                Console.WriteLine("Error: invalid or unsupported optional header magic");
                return 1;
            }
            stm.Position = optionalHeaderOffset + 32;
            int sectionAlignment = rdr.ReadInt32();
            int fileAlignment = rdr.ReadInt32();
            int numberOfDirEntriesOffset = optionalHeaderOffset + 92;
            stm.Position = numberOfDirEntriesOffset;
            int numberOfDirEntries = rdr.ReadInt32();
            const int DEBUG_TABLE = 6;
            if (numberOfDirEntries < DEBUG_TABLE + 1)
            {
                stm.Position = numberOfDirEntriesOffset;
                wrr.Write(DEBUG_TABLE + 1);
            }
            int debugTableEntryOffset = optionalHeaderOffset + 144;
            int debugTableEntryEnd = optionalHeaderOffset + 152;
            if (debugTableEntryEnd > sectionsOffset)
            {
                Console.WriteLine("Error: not enough space for Debug directory entry, optional header must be resized, not implemented");
                return 1;
            }
            stm.Position = sectionsOffset;
            SectionHeader[] sectionHeaders = new SectionHeader[coffHdr.NumberOfSections];
            for (int i = 0; i < coffHdr.NumberOfSections; i++)
            {
                byte[] encname = rdr.ReadBytes(8);
                int l = 0;
                for (l = 0; l < 8; l++)
                    if (encname[l] == 0)
                        break;
                sectionHeaders[i].Name = Encoding.UTF8.GetString(encname, 0, l);
                sectionHeaders[i].VirtualSize = rdr.ReadInt32();
                sectionHeaders[i].Rva = rdr.ReadInt32();
                sectionHeaders[i].FileSize = rdr.ReadInt32();
                sectionHeaders[i].FileOffset = rdr.ReadInt32();
                sectionHeaders[i].RelocOffset = rdr.ReadInt32();
                sectionHeaders[i].LineOffset = rdr.ReadInt32();
                sectionHeaders[i].RelocNum = rdr.ReadInt16();
                sectionHeaders[i].LineNum = rdr.ReadInt16();
                sectionHeaders[i].Flags = rdr.ReadInt32();
            }
            int rdataIndex = -1;
            for (int i = 0; i < coffHdr.NumberOfSections; i++)
            {
                if (sectionHeaders[i].Name == ".rdata")
                {
                    rdataIndex = i;
                    break;
                }
            }
            if (rdataIndex == -1)
            {
                Console.WriteLine("Error: .rdata section not found");
                return 1;
            }
            SectionHeader rdataSect = sectionHeaders[rdataIndex];

            int debugSizeFileAligned = RoundUp(debugSize, fileAlignment);
            int newRdataSizeFileAligned = rdataSect.FileSize + debugSizeFileAligned;
            int newRdataSizeSectionAligned = RoundUp(newRdataSizeFileAligned, sectionAlignment);
            if (rdataSect.VirtualSize < newRdataSizeSectionAligned)
            {
                Console.WriteLine("Error: crossing section alignment boundary, relocation required, not implemented");
                return 1;
            }
            // injecting debug data
            // moving remains data
            int debugDataOffset = rdataSect.FileOffset + rdataSect.FileSize;
            int debugDataEndAligned = debugDataOffset + debugSizeFileAligned;
            stm.Position = debugDataOffset;
            int remainsSize = (int)(stm.Length - stm.Position);
            byte[] remainsBuffer = new byte[remainsSize];
            stm.Read(remainsBuffer, 0, remainsSize);
            stm.Position = debugDataEndAligned;
            stm.Write(remainsBuffer, 0, remainsSize);
            // writing debug data directory
            stm.Position = debugDataOffset;
            wrr.Write((int)0); // charateristics, reserved
            wrr.Write((int)timestamp);
            wrr.Write((int)0x0); // version of debugging information format
            wrr.Write((int)2); // CodeView type
            wrr.Write(debugInfoSize);
            int debugInfoRva = rdataSect.Rva + rdataSect.FileSize + debugDirectorySize;
            wrr.Write(debugInfoRva);
            int debugInfoFileOffset = rdataSect.FileOffset + rdataSect.FileSize + debugDirectorySize;
            wrr.Write(debugInfoFileOffset);
            // writing debug info
            wrr.Write(Encoding.UTF8.GetBytes("RSDS"));
            wrr.Write(guid.ToByteArray());
            wrr.Write(age);
            wrr.Write(utf8pdbname);
            wrr.Write((byte)0);
            int paddingSize = fileAlignment - (debugSize - debugSize / fileAlignment * fileAlignment);
            byte[] pad = new byte[paddingSize];
            wrr.Write(pad);
            // updating debug directory address in table
            int debugDirectoryRva = rdataSect.Rva + rdataSect.FileSize;
            stm.Position = debugTableEntryOffset;
            wrr.Write(debugDirectoryRva);
            wrr.Write(debugDirectorySize);
            // update rdata file size
            int sectionHeaderSize = 40;
            int sectionHeaderFileSizeFieldOffset = 16;
            int sectionHeaderFileOffsetFieldOffset = 20;
            stm.Position = sectionsOffset + sectionHeaderSize * rdataIndex + sectionHeaderFileSizeFieldOffset;
            wrr.Write(newRdataSizeFileAligned);
            // updating sections offsets
            int delta = debugSizeFileAligned;
            for (int i = rdataIndex + 1; i < coffHdr.NumberOfSections; i++)
            {
                sectionHeaders[i].FileOffset += delta;
                stm.Position = sectionsOffset + sectionHeaderSize * i + sectionHeaderFileOffsetFieldOffset;
                wrr.Write(sectionHeaders[i].FileOffset);
            }
            stm.Close();
            return 0;
        }
Exemple #11
0
        private void FillInNtHeader(MetadataSizes metadataSizes, int mappedFieldDataStreamRva)
        {
            // In the PE File Header this is a "Time/Date Stamp" whose description is "Time and date
            // the file was created in seconds since January 1st 1970 00:00:00 or 0"
            // However, when we want to make it deterministic we fill it in (later) with bits from the hash of the full PE file.
            int timeStamp = _deterministic ? 0 : (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;

            int textSectionRva = _textSection.RelativeVirtualAddress;
            
            _coffHeader = new CoffHeader(
                machine: (_properties.Machine == 0) ? Machine.I386 : _properties.Machine,
                numberOfSections: GetSectionCount(),
                timeDateStamp: timeStamp,
                pointerToSymbolTable: 0,
                numberOfSymbols: 0,
                sizeOfOptionalHeader: (short)(_is32bit ? 224 : 240), // TODO: constants
                characteristics: _properties.ImageCharacteristics);

            var ntHeader = _ntHeader = new NtHeader();
            ntHeader.Magic = _is32bit ? PEMagic.PE32 : PEMagic.PE32Plus;
            ntHeader.MajorLinkerVersion = _properties.LinkerMajorVersion;
            ntHeader.MinorLinkerVersion = _properties.LinkerMinorVersion;
            ntHeader.AddressOfEntryPoint = _properties.RequiresStartupStub ? mappedFieldDataStreamRva - (_is32bit ? 6 : 10) : 0; // TODO: constants
            ntHeader.BaseOfCode = textSectionRva;
            ntHeader.BaseOfData = _rdataSection.RelativeVirtualAddress;
            ntHeader.ImageBase = _properties.BaseAddress;
            ntHeader.FileAlignment = _properties.FileAlignment;
            ntHeader.MajorSubsystemVersion = _properties.MajorSubsystemVersion;
            ntHeader.MinorSubsystemVersion = _properties.MinorSubsystemVersion;

            ntHeader.Subsystem = _properties.Subsystem;
            ntHeader.DllCharacteristics = _properties.DllCharacteristics;

            ntHeader.SizeOfStackReserve = _properties.SizeOfStackReserve;
            ntHeader.SizeOfStackCommit = _properties.SizeOfStackCommit;
            ntHeader.SizeOfHeapReserve = _properties.SizeOfHeapReserve; 
            ntHeader.SizeOfHeapCommit = _properties.SizeOfHeapCommit;

            ntHeader.SizeOfCode = _textSection.SizeOfRawData;
            ntHeader.SizeOfInitializedData = _rdataSection.SizeOfRawData + _coverSection.SizeOfRawData + _sdataSection.SizeOfRawData + _tlsSection.SizeOfRawData + _resourceSection.SizeOfRawData + _relocSection.SizeOfRawData;
            ntHeader.SizeOfHeaders = BitArithmeticUtilities.Align(ComputeSizeOfPeHeaders(), _properties.FileAlignment);
            ntHeader.SizeOfImage = BitArithmeticUtilities.Align(_relocSection.RelativeVirtualAddress + _relocSection.VirtualSize, 0x2000);
            ntHeader.SizeOfUninitializedData = 0;

            ntHeader.ImportAddressTable = new DirectoryEntry(
                (_properties.RequiresStartupStub) ? textSectionRva : 0,
                _sizeOfImportAddressTable);

            ntHeader.CliHeaderTable = new DirectoryEntry(
                textSectionRva + _sizeOfImportAddressTable,
                size: 72); // TODO: constants

            if (_properties.RequiresStartupStub)
            {
                ntHeader.ImportTable = new DirectoryEntry(
                    textSectionRva + ComputeOffsetToImportTable(metadataSizes),
                    (_is32bit ? 66 : 70) + 13); // TODO: constants
            }

            ntHeader.BaseRelocationTable = new DirectoryEntry(
                (_properties.RequiresStartupStub) ? _relocSection.RelativeVirtualAddress : 0,
                _relocSection.VirtualSize);

            if (EmitPdb)
            {
                // Only the size of the fixed part of the debug table goes here.
                ntHeader.DebugTable = new DirectoryEntry(
                    _textSection.RelativeVirtualAddress + ComputeOffsetToDebugTable(metadataSizes),
                    ImageDebugDirectoryBaseSize);
            }

            if (_resourceSection.SizeOfRawData > 0)
            {
                ntHeader.ResourceTable = new DirectoryEntry(
                    _resourceSection.RelativeVirtualAddress,
                    _resourceSection.VirtualSize);
            }

            if (_tlsSection.SizeOfRawData > 0)
            {
                ntHeader.ThreadLocalStorageTable = new DirectoryEntry(
                   _tlsSection.RelativeVirtualAddress,
                   _tlsSection.SizeOfRawData);
            }
        }