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)); }
internal void Read(PeReader rdr) { rdr.SetPosition(0); if (t == PeFileType.Image) { dos = new DOSHeader(this); dos.Read(rdr); rdr.SetPosition(dos.PEHeaderOffset); sign = rdr.ReadBytes(4); pe = new PEHeader(this); pe.Read(rdr); op = new OptionalHeader(this); op.Read(rdr); sects = new SectionHeaders(this); sects.Read(rdr); certs = new CertificateDirectory(op.DataDirectories[DataDirectoryType.Certificate]); certs.Load(rdr, op.DataDirectories[DataDirectoryType.Certificate].Address.Value); } else if (t == PeFileType.Object) { pe = new PEHeader(this); pe.Read(rdr); sects = new SectionHeaders(this); sects.Read(rdr); } }
/// <summary> /// Identifies if the specified executable is a Microsoft Portable Executable /// </summary> /// <returns><c>true</c> if the specified executable is a Microsoft Portable Executable, <c>false</c> otherwise.</returns> /// <param name="stream">Stream containing the executable.</param> public static bool Identify(FileStream stream) { FileStream baseStream = stream; MZ baseExecutable = new MZ(baseStream); if (!baseExecutable.Recognized) { return(false); } if (baseExecutable.Header.new_offset >= baseStream.Length) { return(false); } baseStream.Seek(baseExecutable.Header.new_offset, SeekOrigin.Begin); byte[] buffer = new byte[Marshal.SizeOf(typeof(PEHeader))]; baseStream.Read(buffer, 0, buffer.Length); IntPtr hdrPtr = Marshal.AllocHGlobal(buffer.Length); Marshal.Copy(buffer, 0, hdrPtr, buffer.Length); PEHeader header = (PEHeader)Marshal.PtrToStructure(hdrPtr, typeof(PEHeader)); Marshal.FreeHGlobal(hdrPtr); return(header.signature == SIGNATURE); }
public override void Analyze(BinaryAnalyzerContext context) { PEBinary target = context.PEBinary(); PEHeader peHeader = target.PE.PEHeaders.PEHeader; if ((peHeader.DllCharacteristics & DllCharacteristics.NxCompatible /*IMAGE_DLLCHARACTERISTICS_NX_COMPAT*/) == 0) { // '{0}' is not marked NX compatible. The NXCompat bit, also known as "Data Execution Prevention" // (DEP) or "Execute Disable" (XD), is a processor feature that allows a program to mark a piece // of memory as non - executable. This helps mitigate memory corruption vulnerabilities by // preventing an attacker from supplying direct shellcode in their exploit, because the exploit // comes in the form of input data to the exploited program on a data segment, rather than on an // executable code segment. To resolve this issue, ensure that your tool chain is configured to mark //your binaries as NX compatible, e.g. by passing / NXCOMPAT to the C / C++ linker. context.Logger.Log(this, RuleUtilities.BuildResult(ResultLevel.Error, context, null, nameof(RuleResources.BA2016_Error), context.TargetUri.GetFileName())); return; } // '{0}' is marked as NX compatible. context.Logger.Log(this, RuleUtilities.BuildResult(ResultLevel.Pass, context, null, nameof(RuleResources.BA2016_Pass), context.TargetUri.GetFileName())); }
private CLRHeader ReadCLRHeader(BinaryReader assemblyReader, PEHeader peHeader) { var clrDirectoryHeader = peHeader.Directories[(int)DataDirectoryName.CLRHeader]; var clrDirectoryData = ReadVirtualDirectory(assemblyReader, clrDirectoryHeader, peHeader.Sections); using (var reader = new BinaryReader(new MemoryStream(clrDirectoryData))) { var a = new CLRHeader { HeaderSize = reader.ReadUInt32(), MajorRuntimeVersion = reader.ReadUInt16(), MinorRuntimeVersion = reader.ReadUInt16(), MetaDataDirectoryAddress = reader.ReadUInt32(), MetaDataDirectorySize = reader.ReadUInt32(), Flags = reader.ReadUInt32(), EntryPointToken = reader.ReadUInt32(), ResourcesDirectoryAddress = reader.ReadUInt32(), ResourcesDirectorySize = reader.ReadUInt32(), StrongNameSignatureAddress = reader.ReadUInt32(), StrongNameSignatureSize = reader.ReadUInt32(), CodeManagerTableAddress = reader.ReadUInt32(), CodeManagerTableSize = reader.ReadUInt32(), VTableFixupsAddress = reader.ReadUInt32(), VTableFixupsSize = reader.ReadUInt32(), ExportAddressTableJumpsAddress = reader.ReadUInt32(), ExportAddressTableJumpsSize = reader.ReadUInt32(), ManagedNativeHeaderAddress = reader.ReadUInt32(), ManagedNativeHeaderSize = reader.ReadUInt32() }; return(a); } }
public override void Analyze(BinaryAnalyzerContext context) { PEHeader peHeader = context.PE.PEHeaders.PEHeader; UInt64 imageBase = peHeader.ImageBase; if (imageBase <= 0xFFFFFFFF) { // '{0}' is a 64-bit image with a preferred base address below the 4GB boundary. // Having a preferred base address below this boundary triggers a compatibility // mode in Address Space Layout Randomization (ASLR) on recent versions of // Windows that reduces the number of locations to which ASLR may relocate the // binary. This reduces the effectiveness of ASLR at mitigating memory corruption // vulnerabilities. To resolve this issue, either use the default preferred base // address by removing any uses of /baseaddress from compiler command lines, or // /BASE from linker command lines (recommended), or configure your program to // start at a base address above 4GB when compiled for 64 bit platforms (by // changing the constant passed to /baseaddress / /BASE). Note that if you choose // to continue using a custom preferred base address, you will need to make this // modification only for 64-bit builds, as base addresses above 4GB are not valid // for 32-bit binaries. context.Logger.Log(this, RuleUtilities.BuildResult(ResultKind.Error, context, null, nameof(RuleResources.BA2001_Fail))); return; } // '{0}' is marked as NX compatible. context.Logger.Log(this, RuleUtilities.BuildResult(ResultKind.Pass, context, null, nameof(RuleResources.BA2001_Pass))); }
public override void Analyze(BinaryAnalyzerContext context) { PEHeader peHeader = context.PE.PEHeaders.PEHeader; // TODO: do we really require this check? What is the proposed fix to this issue? if (peHeader.SectionAlignment < PAGE_SIZE) { // '{0}' has a section alignment ({1}) that is less than page size ({2}). context.Logger.Log(this, RuleUtilities.BuildResult(ResultKind.Error, context, null, nameof(RuleResources.BA2021_Fail), context.PE.FileName, "0x" + peHeader.SectionAlignment.ToString("x"), "0x" + PAGE_SIZE.ToString("x"))); return; } var sectionHeaders = context.PE.PEHeaders.SectionHeaders; List <string> badSections = new List <string>(); if (sectionHeaders != null) { foreach (SectionHeader sectionHeader in sectionHeaders) { SectionCharacteristics wxFlags = SectionCharacteristics.MemWrite | SectionCharacteristics.MemExecute; if ((sectionHeader.SectionCharacteristics & wxFlags) == wxFlags) { badSections.Add(sectionHeader.Name); } } } if (badSections.Count == 0) { // '{0}' contains no data or code sections marked as both shared and executable. context.Logger.Log(this, RuleUtilities.BuildResult(ResultKind.Pass, context, null, nameof(RuleResources.BA2021_Pass))); return; } string badSectionsText = String.Join(";", badSections); // '{0}' contains PE section(s)({ 1}) that are both writable and executable. // Writable and executable memory segments make it easier for an attacker to //exploit memory corruption vulnerabilities, because it may give an attacker // executable location(s) to inject shellcode. To resolve this // issue, configure your toolchain to not emit memory sections that are // writable and executable.For example, look for uses of / SECTION on the // linker command line for C and C++ programs, or #pragma section in C and // C++ source code, which mark a section with both attributes. context.Logger.Log(this, RuleUtilities.BuildResult(ResultKind.Error, context, null, nameof(RuleResources.BA2021_Fail), badSectionsText)); }
public void PEHeader() { var peh = new PEHeader(); peh.Machine = Machine.I386; peh.Characteristics = ImageCharacteristics.Bit32Machine; Assert.AreEqual("I386 Bit32Machine Sections[0]", peh.ToString()); }
/// <summary>Получить тело метода</summary> /// <returns>Массив байт описывающий CIL</returns> public Byte[] GetMethodBody() { PEHeader peHeader = this.Row.Row.Table.Root.Parent.Parent.Parent.Header; UInt32 padding = this.Row.RVA + this.Header.HeaderSize; UInt32 methodLength = this.Header.CodeSize; return(peHeader.ReadBytes(padding, methodLength)); }
private bool Validate32BitImage(BinaryAnalyzerContext context) { PEBinary target = context.PEBinary(); PEHeader peHeader = target.PE.PEHeaders.PEHeader; SafePointer sp = new SafePointer(target.PE.ImageBytes, peHeader.LoadConfigTableDirectory.RelativeVirtualAddress); SafePointer loadConfigVA = target.PE.RVA2VA(sp); ImageLoadConfigDirectory32 loadConfig = new ImageLoadConfigDirectory32(peHeader, loadConfigVA); UInt32 cookieVA = (UInt32)loadConfig.GetField(ImageLoadConfigDirectory32.Fields.SecurityCookie); UInt32 baseAddress = (UInt32)peHeader.ImageBase; // we need to find the offset in the file based on the cookie's VA UInt32 sectionSize, sectionVA = 0; SectionHeader ish = new SectionHeader(); bool foundCookieSection = false; foreach (SectionHeader t in target.PE.PEHeaders.SectionHeaders) { sectionVA = (UInt32)t.VirtualAddress + baseAddress; sectionSize = (UInt32)t.VirtualSize; if ((cookieVA >= sectionVA) && (cookieVA < sectionVA + sectionSize)) { ish = t; foundCookieSection = true; break; } } if (!foundCookieSection) { LogCouldNotLocateCookie(context); return(false); } UInt64 fileCookieOffset = (cookieVA - baseAddress) - (sectionVA - baseAddress) + (UInt32)ish.PointerToRawData; SafePointer fileCookiePtr = loadConfigVA; fileCookiePtr.Address = (int)fileCookieOffset; SafePointer boundsCheck = fileCookiePtr + 4; if (!CookieOffsetValid(context, boundsCheck)) { return(false); } UInt32 cookie = BitConverter.ToUInt32(fileCookiePtr.GetBytes(4), 0); if (!StackProtectionUtilities.DefaultCookiesX86.Contains(cookie) && target.PE.Machine == Machine.I386) { LogFailure(context, cookie.ToString("x")); return(false); } return(true); }
public PEHeaderModel(PEHeader peHeader, DosHeaderModel dosHeaderModel) : base("PE header") { this.peHeader = peHeader; this.Address = dosHeaderModel.lfanew; this.Length = PEHeader.Size; BindAddressToDosHeaderlfanew(dosHeaderModel); }
private bool EnablesControlFlowGuard(BinaryAnalyzerContext context) { PEHeader peHeader = context.PE.PEHeaders.PEHeader; if (((uint)peHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_CONTROLFLOWGUARD) == 0) { return(false); } SafePointer loadConfigRVA = new SafePointer(context.PE.ImageBytes, peHeader.LoadConfigTableDirectory.RelativeVirtualAddress); if (loadConfigRVA.Address == 0) { return(false); } SafePointer loadConfigVA = context.PE.RVA2VA(loadConfigRVA); if (context.PE.Is64Bit) { ImageLoadConfigDirectory64 loadConfig = new ImageLoadConfigDirectory64(peHeader, loadConfigVA); Int32 imageDirectorySize = (Int32)loadConfig.GetField(ImageLoadConfigDirectory32.Fields.Size); UInt64 guardCFCheckFunctionPointer = (UInt64)loadConfig.GetField(ImageLoadConfigDirectory64.Fields.GuardCFCheckFunctionPointer); UInt64 guardCFFunctionTable = (UInt64)loadConfig.GetField(ImageLoadConfigDirectory64.Fields.GuardCFFunctionTable); UInt32 guardFlags = (UInt32)loadConfig.GetField(ImageLoadConfigDirectory64.Fields.GuardFlags); if (imageDirectorySize >= IMAGE_LOAD_CONFIG_MINIMUM_SIZE_64 && guardCFCheckFunctionPointer != 0 && guardCFFunctionTable != 0 && (guardFlags & IMAGE_GUARD_CF_CHECKS) == IMAGE_GUARD_CF_CHECKS) { return(true); } } else { ImageLoadConfigDirectory32 loadConfig = new ImageLoadConfigDirectory32(peHeader, loadConfigVA); Int32 imageDirectorySize = (Int32)loadConfig.GetField(ImageLoadConfigDirectory32.Fields.Size); UInt32 guardCFCheckFunctionPointer = (UInt32)loadConfig.GetField(ImageLoadConfigDirectory32.Fields.GuardCFCheckFunctionPointer); UInt32 guardCFFunctionTable = (UInt32)loadConfig.GetField(ImageLoadConfigDirectory32.Fields.GuardCFFunctionTable); UInt32 guardFlags = (UInt32)loadConfig.GetField(ImageLoadConfigDirectory32.Fields.GuardFlags); if (imageDirectorySize >= IMAGE_LOAD_CONFIG_MINIMUM_SIZE_32 && guardCFCheckFunctionPointer != 0 && guardCFFunctionTable != 0 && (guardFlags & IMAGE_GUARD_CF_CHECKS) == IMAGE_GUARD_CF_CHECKS) { return(true); } } return(false); }
public override void Analyze(BinaryAnalyzerContext context) { PEBinary target = context.PEBinary(); string executableImportSection = null; PEHeader peHeader = target.PE.PEHeaders.PEHeader; DirectoryEntry importTable = peHeader.ImportTableDirectory; if (importTable.RelativeVirtualAddress != 0 && target.PE.PEHeaders.SectionHeaders != null) { int importSize = peHeader.ImportTableDirectory.Size; foreach (SectionHeader sectionHeader in target.PE.PEHeaders.SectionHeaders) { SectionCharacteristics memExecute = SectionCharacteristics.MemExecute; if ((sectionHeader.SectionCharacteristics & memExecute) == 0) { continue; } int size = sectionHeader.SizeOfRawData; int address = sectionHeader.VirtualAddress; if ((address <= importTable.RelativeVirtualAddress) && (address + size >= importTable.RelativeVirtualAddress + importTable.Size)) { // Our import section is in a writable section - bad executableImportSection = sectionHeader.Name; break; } } } if (executableImportSection != null) { // '{0}' has the imports section marked executable. Because the loader will always mark // the imports section as writable, it is important to mark this section as non-executable, // so that an attacker cannot place shellcode here. To resolve this issue, ensure that your //program does not mark the imports section as executable. Look for uses of /SECTION or // /MERGE on the linker command line, or #pragma segment in source code, which change the // imports section to be executable, or which merge the ".rdata" segment into an executable // section. context.Logger.Log(this, RuleUtilities.BuildResult(FailureLevel.Error, context, null, nameof(RuleResources.BA2010_Error), context.TargetUri.GetFileName())); return; } // '{0}' does not have an imports section that is marked as executable. context.Logger.Log(this, RuleUtilities.BuildResult(ResultKind.Pass, context, null, nameof(RuleResources.BA2010_Pass), context.TargetUri.GetFileName())); }
/// <summary>Получить информацию по импорту</summary> /// <param name="offset">Сдвиг по PE файлу</param> /// <param name="isRva">Получить импорт по Relative Virtual Address адресу. В противном случае передаётся Virtual Address</param> /// <returns>Структура</returns> private WinNT.IMAGE_IMPORT_BY_NAME GetImageImport(UInt32 offset, Boolean isRva) { PEHeader header = this.Directory.Parent.Header; UInt64 forwarderString; if (header.Is64Bit) { WinNT.IMAGE_THUNK_DATA64 thunk64 = header.PtrToStructure <WinNT.IMAGE_THUNK_DATA64>(offset); forwarderString = thunk64.ForwarderString; //TODO: Вот тут может быть ошибка } else { WinNT.IMAGE_THUNK_DATA32 thunk32 = header.PtrToStructure <WinNT.IMAGE_THUNK_DATA32>(offset); forwarderString = thunk32.ForwarderString; } WinNT.IMAGE_IMPORT_BY_NAME result; if ((forwarderString & 0x80000000) != 0) { result = new WinNT.IMAGE_IMPORT_BY_NAME() { Hint = (UInt16)(forwarderString & 0x7FFFFFFF), Name = null, }; } else if ((forwarderString & 0x8000000000000000) != 0) { result = new WinNT.IMAGE_IMPORT_BY_NAME() { Hint = (UInt16)(forwarderString & 0x7FFFFFFFFFFFFFFF), Name = null, }; } else { if (!isRva) { UInt64 imageBase; if (header.Is64Bit) { imageBase = header.HeaderNT64.OptionalHeader.ImageBase; } else { imageBase = header.HeaderNT32.OptionalHeader.ImageBase; } forwarderString -= imageBase; } result = header.PtrToStructure <WinNT.IMAGE_IMPORT_BY_NAME>((UInt32)forwarderString); } return(result); }
/// <summary>Get fat method header sections</summary> /// <returns>Method header sections</returns> public IEnumerable <MethodSection> GetSections() { UInt32 padding = this.Row.RVA + this.Header.HeaderSize; UInt32 methodLength = this.Header.CodeSize; if ((this.Header.Format & Cor.CorILMethod.FatFormat) == Cor.CorILMethod.FatFormat && (this.Header.Format & Cor.CorILMethod.MoreSects) == Cor.CorILMethod.MoreSects) { padding += methodLength; PEHeader header = this.Row.Row.Table.Root.Parent.Parent.Parent.Header; Boolean moreSections = true; while (moreSections) { //Each section should start on a 4 byte boundary //so let's read from the stream until we find the next boundary. padding = NativeMethods.AlignToInt(padding); Cor.CorILMethodSection section = header.PtrToStructure <Cor.CorILMethodSection>(padding); padding += MethodBody.SizeOfMethodSection; //I have never seen anything else than an exception handling section... //According to the documentation "Currently, the method data sections //are only used for exception tables." if ((section.Kind & Cor.CorILMethod_Sect.EHTable) != Cor.CorILMethod_Sect.EHTable) { throw new NotImplementedException("Only exception table supported"); } //Check whether more sections follow after this one. moreSections = section.HasMoreSections; Cor.CorILMethodExceptionFat[] fat = new Cor.CorILMethodExceptionFat[section.IsFatFormat ? section.ClauseNumber : 0]; Cor.CorILMethodExceptionSmall[] small = new Cor.CorILMethodExceptionSmall[section.IsFatFormat ? 0 : section.ClauseNumber]; //Let's read the clauses... for (Int32 clauseIndex = 0; clauseIndex < section.ClauseNumber; clauseIndex++) { //The structure of the clauses are the same in both Fat and //Small format, only the sizes are different. if (section.IsFatFormat) { fat[clauseIndex] = header.PtrToStructure <Cor.CorILMethodExceptionFat>(padding); padding += MethodBody.SizeOfMethodExceptionFat; } else { small[clauseIndex] = header.PtrToStructure <Cor.CorILMethodExceptionSmall>(padding); padding += MethodBody.SizeOfMethodExceptionSmall; } } yield return(new MethodSection(section, fat, small)); } } }
protected override bool Parse(PEHeader peHeader) { #region Sanity checks if (peHeader == null) throw new ArgumentNullException(nameof(peHeader)); #endregion Architecture = new Architecture(OS.All, GetCpu(peHeader.FileHeader.Machine)); if (peHeader.Subsystem >= Subsystem.WindowsCui) NeedsTerminal = true; return peHeader.Is32BitHeader ? (peHeader.OptionalHeader32.CLRRuntimeHeader.VirtualAddress != 0) : (peHeader.OptionalHeader64.CLRRuntimeHeader.VirtualAddress != 0); }
public void Sizes() { Assert.Equal(20, CoffHeader.Size); Assert.Equal(224, PEHeader.Size(is32Bit: true)); Assert.Equal(240, PEHeader.Size(is32Bit: false)); Assert.Equal(8, SectionHeader.NameSize); Assert.Equal(40, SectionHeader.Size); Assert.Equal(128 + 4 + 20 + 224, new PEHeaderBuilder(Machine.I386).ComputeSizeOfPEHeaders(0)); Assert.Equal(128 + 4 + 20 + 224 + 16, new PEHeaderBuilder(Machine.Amd64).ComputeSizeOfPEHeaders(0)); Assert.Equal(128 + 4 + 20 + 224 + 16 + 40 * 1, new PEHeaderBuilder(Machine.Amd64).ComputeSizeOfPEHeaders(1)); Assert.Equal(128 + 4 + 20 + 224 + 16 + 40 * 2, new PEHeaderBuilder(Machine.Amd64).ComputeSizeOfPEHeaders(2)); }
/// <summary> /// Reads the contents of the PeCoff file in to our custom data structures /// </summary> /// <exception Cref="NotAManagedLibraryException"> /// Thrown when a file which is not a managed PE file is loaded. /// </exception> private void ReadFileContents() { _fileContents = _fileSystem.ReadAllBytes(_fileName); Offset offset = _fileContents[PeCoffFile.PeSignitureOffsetLocation]; offset += 4; // skip past the PE signature bytes FileHeader fileHeader = new FileHeader(_fileContents, offset); PEHeader peHeader = new PEHeader(_fileContents, offset); ReadSectionHeaders(fileHeader.NumberOfSections, offset); ReadDirectories(peHeader.DataDirectories); }
public void PEHeader_When64Bit_OffsetIsMovedOn() { byte[] contents = new byte[112]; Offset offset = 0; // set it to a 64 magic contents[0] = 0x0b; contents[1] = 0x02; PEHeader header = new PEHeader(contents, offset); Assert.AreEqual(FileMagicNumbers.Bit64, header.Magic); Assert.AreEqual(112, header.Size); }
public void PEHeader_When32Bit_OffsetIsMovedOn() { byte[] contents = new byte[96]; Offset offset = 0; // set it to a 32 magic contents[0] = 0x0b; contents[1] = 0x01; PEHeader header = new PEHeader(contents, offset); Assert.AreEqual(FileMagicNumbers.Bit32, header.Magic); Assert.AreEqual(96, header.Size); }
public PEFileParser(PEFile file, string filename, MemoryMappedViewAccessor accessor = null) { PEFile = file; Header = file.Header; if (accessor == null) { _stm = File.OpenRead(filename); _memFile = MemoryMappedFile.CreateFromFile(_stm, null, 0, MemoryMappedFileAccess.Read, null, HandleInheritability.None, false); accessor = _memFile.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read); _isOwner = true; } Accessor = accessor; Filename = filename; }
public IPEResult Package(IPEInfo param) { var peHeader = new PEHeader { Characteristics = param.Characteristics, Architecture = param.Architecture, CreationTimePOSIX = (uint)((DateTimeOffset)param.TimeStamp).ToUnixTimeSeconds(), NumberOfSections = param.NumberOfSections, Magic = BitConverter.ToUInt32(Encoding.ASCII.GetBytes("PE\0\0")), OptionalHeaderSize = (ushort)Marshal.SizeOf <PE32PlusOptionalHeader>() }; return(new PEResult(StructConverter.GetBytes(peHeader))); }
public PEAssembly(StreamParser parser) { DOSHeader dosHeader = new DOSHeader(parser); parser.Seek(dosHeader.PEHeaderOffset); PEHeader peHeader = new PEHeader(parser); if (peHeader.SizeOfOptionalHeader == 0) throw new ParseFailedException("PE missing NT header"); PEOptionalHeader peOptionalHeader = new PEOptionalHeader(parser); PESectionHeader[] sectionHeaders = new PESectionHeader[peHeader.NumberOfSections]; for (int i = 0; i < peHeader.NumberOfSections; i++) sectionHeaders[i] = new PESectionHeader(parser); SectionHeaders = sectionHeaders; DataDirectory = peOptionalHeader.DataDirectory; }
public override void Analyze(BinaryAnalyzerContext context) { PEBinary target = context.PEBinary(); PEHeader peHeader = target.PE.PEHeaders.PEHeader; if (peHeader.LoadConfigTableDirectory.RelativeVirtualAddress == 0) { // LOAD_CONFIG block absent. This can occur in 2 cases: // 1. The user has C or C++ code linked with a linker older than Dev11 (VS2010) // 2. The code is not C or C++ code at all. // // In the first case we expect CompilerVersionCheck to fire on this code. In the // second case we don't want to warn because the code is likely safe; // e.g. .NET ngen'd images fall into this bucket. //'{0}' is C or C++binary that does not contain a load config table, which // indicates either that it was compiled and linked with a version of the // compiler that precedes stack protection features or is a binary (such as // an ngen'ed assembly) that is not subject to relevant security issues. context.Logger.Log(this, RuleUtilities.BuildResult(ResultLevel.Pass, context, null, nameof(RuleResources.BA2012_Pass_NoLoadConfig), context.TargetUri.GetFileName())); return; } if (target.PE.Is64Bit) { if (!Validate64BitImage(context)) { return; } } else if (!Validate32BitImage(context)) { return; } // '{0}' is a C or C++ binary built with the buffer security feature // that properly preserves the stack protecter cookie. This has the // effect of enabling a significant increase in entropy provided by // the operating system over that produced by the C runtime start-up // code. context.Logger.Log(this, RuleUtilities.BuildResult(ResultLevel.Pass, context, null, nameof(RuleResources.BA2012_Pass), context.TargetUri.GetFileName())); }
private bool Validate64BitImage(BinaryAnalyzerContext context) { PEHeader peHeader = context.PE.PEHeaders.PEHeader; SafePointer sp = new SafePointer(context.PE.ImageBytes, peHeader.LoadConfigTableDirectory.RelativeVirtualAddress); SafePointer loadConfigVA = context.PE.RVA2VA(sp); ImageLoadConfigDirectory64 loadConfig = new ImageLoadConfigDirectory64(peHeader, loadConfigVA); UInt64 cookieVA = (UInt64)loadConfig.GetField(ImageLoadConfigDirectory64.Fields.SecurityCookie); UInt64 baseAddress = peHeader.ImageBase; // we need to find the offset in the file based on the cookie's VA UInt64 sectionSize, sectionVA = 0; SectionHeader ish = new SectionHeader(); bool foundCookieSection = false; foreach (SectionHeader t in context.PE.PEHeaders.SectionHeaders) { sectionVA = (UInt64)(UInt32)t.VirtualAddress + baseAddress; sectionSize = (UInt32)t.VirtualSize; if ((cookieVA >= sectionVA) && (cookieVA < sectionVA + sectionSize)) { ish = t; foundCookieSection = true; break; } } if (!foundCookieSection) { LogCouldNotLocateCookie(context); return(false); } UInt64 fileCookieOffset = (cookieVA - baseAddress) - (sectionVA - baseAddress) + (UInt32)ish.PointerToRawData; SafePointer fileCookiePtr = loadConfigVA; fileCookiePtr.Address = (int)fileCookieOffset; UInt64 cookie = BitConverter.ToUInt64(fileCookiePtr.GetBytes(8), 0); if (cookie != StackProtectionUtilities.DefaultCookieX64) { LogFailure(context, cookie.ToString("x")); return(false); } return(true); }
public PEHeader ReadPEHeader(ushort headerAddress, BinaryReader _assemblyReader) { _assemblyReader.BaseStream.Seek(headerAddress, SeekOrigin.Begin); var header = new PEHeader { Signature = _assemblyReader.ReadUInt32(), Machine = _assemblyReader.ReadUInt16(), NumberOfSections = _assemblyReader.ReadUInt16(), DateTimeStamp = _assemblyReader.ReadUInt32(), PtrToSymbolTable = _assemblyReader.ReadUInt32(), NumberOfSymbols = _assemblyReader.ReadUInt32(), SizeOfOptionalHeaders = _assemblyReader.ReadUInt16(), Characteristics = _assemblyReader.ReadUInt16(), OptionalMagic = _assemblyReader.ReadUInt16(), MajorLinkerVersion = _assemblyReader.ReadByte(), MinorLinkerVersion = _assemblyReader.ReadByte(), SizeOfCode = _assemblyReader.ReadUInt32(), SizeOfInitData = _assemblyReader.ReadUInt32(), SizeOfUninitData = _assemblyReader.ReadUInt32(), AddressOfEntryPoint = _assemblyReader.ReadUInt32(), BaseOfCode = _assemblyReader.ReadUInt32(), BaseOfData = _assemblyReader.ReadUInt32(), ImageBase = _assemblyReader.ReadUInt32(), SectionAlignment = _assemblyReader.ReadUInt32(), FileAlignment = _assemblyReader.ReadUInt32(), MajorOSVersion = _assemblyReader.ReadUInt16(), MinorOSVersion = _assemblyReader.ReadUInt16(), MajorImageVersion = _assemblyReader.ReadUInt16(), MinorImageVersion = _assemblyReader.ReadUInt16(), MajorSubsystemVersion = _assemblyReader.ReadUInt16(), MinorSubsystemVersion = _assemblyReader.ReadUInt16(), Reserved1 = _assemblyReader.ReadUInt32(), SizeOfImage = _assemblyReader.ReadUInt32(), SizeOfHeaders = _assemblyReader.ReadUInt32(), PEChecksum = _assemblyReader.ReadUInt32(), Subsystem = _assemblyReader.ReadUInt16(), DLLCharacteristics = _assemblyReader.ReadUInt16(), SizeOfStackReserve = _assemblyReader.ReadUInt32(), SizeOfStackCommit = _assemblyReader.ReadUInt32(), SizeOfHeapReserve = _assemblyReader.ReadUInt32(), SizeOfHeapCommit = _assemblyReader.ReadUInt32(), LoaderFlags = _assemblyReader.ReadUInt32(), DirectoryLength = _assemblyReader.ReadUInt32() }; return(header); }
public static int GetTypeLen(this ImageFieldData fi) { int res = 0; bool b64bit = false; PEHeader ioh = fi.ParentHeader; if (ioh != null) { b64bit = (ioh.Magic == PEMagic.PE32Plus); } if (b64bit && fi.Is32BitOnly) { return(0); } switch (fi.Type) { case Type.BYTE: res = 1; break; case Type.SBYTE: res = 1; break; case Type.UINT16: res = 2; break; case Type.INT16: res = 2; break; case Type.UINT32: res = 4; break; case Type.INT32: res = 4; break; case Type.UINT64: res = 8; break; case Type.INT64: res = 8; break; case Type.POINTER: res = 4; break; case Type.HEADER: res = fi.Header.Size; break; case Type.NATIVEINT: res = b64bit ? 8 : 4; break; default: throw new Exception("Unknown type"); } return(res); }
protected virtual bool Parse(PEHeader peHeader) { #region Sanity checks if (peHeader == null) { throw new ArgumentNullException(nameof(peHeader)); } #endregion Architecture = new(OS.Windows, GetCpu(peHeader.FileHeader.Machine)); if (peHeader.Subsystem >= PESubsystem.WindowsCui) { NeedsTerminal = true; } return(peHeader.Is32BitHeader ? (peHeader.OptionalHeader32.CLRRuntimeHeader.VirtualAddress == 0) : (peHeader.OptionalHeader64.CLRRuntimeHeader.VirtualAddress == 0)); }
private static bool TestChecksumAndAuthenticodeSignature(Stream peStream, byte[] privateKeyOpt = null) { var peHeaders = new PEHeaders(peStream); bool is32bit = peHeaders.PEHeader.Magic == PEMagic.PE32; uint expectedChecksum = peHeaders.PEHeader.CheckSum; int peHeadersSize = peHeaders.PEHeaderStartOffset + PEHeader.Size(is32bit) + SectionHeader.Size * peHeaders.SectionHeaders.Length; peStream.Position = 0; if (expectedChecksum == 0) { // not signed return(false); } int peSize = (int)peStream.Length; var peImage = new BlobBuilder(peSize); Assert.Equal(peSize, peImage.TryWriteBytes(peStream, peSize)); var buffer = peImage.GetBlobs().Single().Buffer; var checksumBlob = new Blob(buffer, peHeaders.PEHeaderStartOffset + PEHeader.OffsetOfChecksum, sizeof(uint)); uint checksum = PEBuilder.CalculateChecksum(peImage, checksumBlob); Assert.Equal(expectedChecksum, checksum); // validate signature: if (privateKeyOpt != null) { // signature is calculated with checksum zeroed: new BlobWriter(checksumBlob).WriteUInt32(0); int snOffset; Assert.True(peHeaders.TryGetDirectoryOffset(peHeaders.CorHeader.StrongNameSignatureDirectory, out snOffset)); var snBlob = new Blob(buffer, snOffset, peHeaders.CorHeader.StrongNameSignatureDirectory.Size); var expectedSignature = snBlob.GetBytes().ToArray(); var signature = SigningUtilities.CalculateRsaSignature(PEBuilder.GetContentToSign(peImage, peHeadersSize, peHeaders.PEHeader.FileAlignment, snBlob), privateKeyOpt); AssertEx.Equal(expectedSignature, signature); } return(true); }
public static object SafePointerToType(this SafePointer sp, ImageFieldData fi) { object res = null; switch (fi.Type) { case Type.BYTE: res = (byte)sp; break; case Type.SBYTE: res = (sbyte)(byte)sp; break; case Type.UINT16: res = (UInt16)sp; break; case Type.INT16: res = (Int16)(UInt16)sp; break; case Type.UINT32: res = (UInt32)sp; break; case Type.UINT64: res = (UInt64)sp; break; case Type.INT32: res = (Int32)(UInt32)sp; break; case Type.INT64: res = (Int64)(UInt64)sp; break; case Type.POINTER: res = new SafePointer(sp._array, sp._stream, (Int32)(UInt32)sp); break; case Type.HEADER: res = fi.Header.Create(fi.ParentHeader, sp); break; case Type.NATIVEINT: PEHeader ioh = fi.ParentHeader; if ((ioh != null) && (ioh.Magic == PEMagic.PE32Plus)) { res = (UInt64)sp; } else { res = (UInt32)sp; } break; default: throw new Exception("Unknown type"); } return(res); }
static void WritePEHeader(PEHeader peHeader, BinaryStreamWriter writer) { writer.WriteUInt32((uint)PESignature.PE00); writer.WriteUInt16((ushort)peHeader.Machine); writer.WriteUInt16(peHeader.NumberOfSections); double timestampDouble = (peHeader.Timestamp - TimestampEpochUTC).TotalSeconds; uint timestampNum = checked ((uint)timestampDouble); if (timestampDouble - timestampNum > 0.5) { timestampNum++; } writer.WriteUInt32(timestampNum); writer.WriteUInt32(peHeader.PointerToSymbolTable); writer.WriteUInt32(peHeader.NumberOfSymbols); writer.WriteUInt16(peHeader.SizeOfOptionalHeader); writer.WriteUInt16((ushort)peHeader.Characteristics); }
public static void Init(byte[] input) { // find headers entry header = PEHeader.Find(input); if (header == null) { throw new Exception("Failed to find PE header! Unsupported Version?"); } var prevSec = header.Sections.Last(); // new code section ucpSec = new SectionHeader(".ucp") { VirtAddr = prevSec.VirtAddr + GetMultiples(prevSec.VirtSize, header.SectionAlignment), RawAddr = prevSec.RawAddr + GetMultiples(prevSec.RawSize, header.FileAlignment), Characteristics = 0xE0000020 // writable, //0x60000020, // executable, readable, contains code }; }
/// <summary> /// 获得PE的文件头 /// </summary> /// <param name="Fileindex"></param> /// <returns></returns> private void LoadPEHeader() { _PEHeader = new PEHeader(); _PEHeader.FileStarIndex = PEFileIndex; Loadbyte(ref _PEHeader.Header); Loadbyte(ref _PEHeader.Machine); Loadbyte(ref _PEHeader.NumberOfSections); Loadbyte(ref _PEHeader.TimeDateStamp); Loadbyte(ref _PEHeader.PointerToSymbolTable); Loadbyte(ref _PEHeader.NumberOfSymbols); Loadbyte(ref _PEHeader.SizeOfOptionalHeader); Loadbyte(ref _PEHeader.Characteristics); _PEHeader.FileEndIndex = PEFileIndex; }
/// <summary> /// /// </summary> /// <param name="bytes"></param> /// <param name="IconFilePath"></param> /// <returns></returns> private static bool TryExtractIcon(byte[] bytes, string IconFilePath) { try { PEHeader header = new PEHeader(bytes); return header.TryExtractIconFromExe(bytes, IconFilePath); } catch { return false; } }
/// <summary> /// /// </summary> /// <param name="bytes"></param> /// <param name="SubsystemType"></param> /// <returns></returns> private static bool TryGetSubsystemType(byte[] bytes, out SubsystemTypes SubsystemType) { SubsystemType = SubsystemTypes.Unknown; try { PEHeader header = new PEHeader(bytes); SubsystemType = header.SubsystemType; return true; } catch { return false; } }