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