public PE(string fileName) { this.FileName = Path.GetFullPath(fileName); this.Uri = new Uri(this.FileName); this.IsPEFile = false; try { this.fs = File.OpenRead(this.FileName); if (!CheckPEMagicBytes(this.fs)) { return; } this.peReader = new PEReader(this.fs); this.PEHeaders = this.peReader.PEHeaders; this.IsPEFile = true; this.pImage = new SafePointer(this.peReader.GetEntireImage().GetContent().ToBuilder().ToArray()); if (this.IsManaged) { this.metadataReader = this.peReader.GetMetadataReader(); } } catch (IOException e) { this.LoadException = e; } catch (BadImageFormatException e) { this.LoadException = e; } catch (UnauthorizedAccessException e) { this.LoadException = e; } }
public SafePointer RVA2VA(SafePointer rva) { // find which section is our rva in SectionHeader ish = new SectionHeader(); foreach (SectionHeader sectionHeader in PEHeaders.SectionHeaders) { if ((rva.Address >= sectionHeader.VirtualAddress) && (rva.Address < sectionHeader.VirtualAddress + sectionHeader.SizeOfRawData)) { ish = sectionHeader; break; } } if (ish.VirtualAddress == 0) { throw new InvalidOperationException("RVA does not belong to any section"); } // calculate the VA rva.Address = (rva.Address - ish.VirtualAddress + ish.PointerToRawData); return(rva); }
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; }
public PE(string fileName) { FileName = Path.GetFullPath(fileName); Uri = new Uri(FileName); IsPEFile = false; try { _fs = File.OpenRead(FileName); if (!CheckPEMagicBytes(_fs)) { return; } _peReader = new PEReader(_fs); PEHeaders = _peReader.PEHeaders; IsPEFile = true; m_pImage = new SafePointer(_peReader.GetEntireImage().GetContent().ToBuilder().ToArray()); if (IsManaged) { _metadataReader = _peReader.GetMetadataReader(); } } catch (IOException e) { LoadException = e; } catch (BadImageFormatException e) { LoadException = e; } catch (UnauthorizedAccessException e) { LoadException = e; } }
public PE(string fileName) { FileName = Path.GetFullPath(fileName); Uri = new Uri(FileName); IsPEFile = false; try { _fs = File.OpenRead(FileName); byte byteRead = (byte)_fs.ReadByte(); if (byteRead != 'M') { return; } byteRead = (byte)_fs.ReadByte(); if (byteRead != 'Z') { return; } _fs.Seek(0, SeekOrigin.Begin); _peReader = new PEReader(_fs); PEHeaders = _peReader.PEHeaders; IsPEFile = true; } catch (IOException e) { LoadException = e; } catch (BadImageFormatException e) { LoadException = e; } catch (UnauthorizedAccessException e) { LoadException = e; } if (IsPEFile) { m_pImage = new SafePointer(_peReader.GetEntireImage().GetContent().ToBuilder().ToArray()); if (IsManaged) { _metadataReader = _peReader.GetMetadataReader(); } } }
public object GetField(int n) { object res; ImageFieldData fi = GetFieldInfo(n); int count = fi.Count; int offset = GetFieldOffset(n);; Object o; int len; SafePointer sp = m_pHeader + offset; if (fi.VarLen) { // this assumes we can not have varlen arrays of headers count = GetFieldSize(n) / fi.GetTypeLen(); } if (count == 1) { return(sp.SafePointerToType(fi)); } // if a negative count is provided we tread it as an offset of // the field where to find the real count if (count < 0) { count = Convert.ToInt32(GetField(n + count)); } res = new object[count]; for (int i = 0; i < count; i++) { o = sp.SafePointerToType(fi); ((object[])res)[i] = o; if (o is ImageHeader) { len = ((ImageHeader)o).Size; } else { len = fi.GetTypeLen(); } sp = sp + len; } return(res); }
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); }
public PE(string fileName) { FileName = Path.GetFullPath(fileName); Uri = new Uri(FileName); IsPEFile = false; try { _fs = File.OpenRead(FileName); byte byteRead = (byte)_fs.ReadByte(); if (byteRead != 'M') { return; } byteRead = (byte)_fs.ReadByte(); if (byteRead != 'Z') { return; } _fs.Seek(0, SeekOrigin.Begin); _peReader = new PEReader(_fs); PEHeaders = _peReader.PEHeaders; IsPEFile = true; } catch (IOException e) { LoadException = e; } catch (BadImageFormatException e) { LoadException = e; } catch (UnauthorizedAccessException e) { LoadException = e; } if (IsPEFile) { m_pImage = new SafePointer(_peReader.GetEntireImage().GetContent().ToBuilder().ToArray()); if (IsManaged) { _metadataReader = _peReader.GetMetadataReader(); } } }
public static object SafePointerToType(this SafePointer sp, ImageFieldData fi) { object res; switch (fi.Type) { case Type.BYTE: res = (byte)sp; break; case Type.SBYTE: res = (sbyte)(byte)sp; break; case Type.UINT16: res = (ushort)sp; break; case Type.INT16: res = (short)(ushort)sp; break; case Type.UINT32: res = (uint)sp; break; case Type.UINT64: res = (ulong)sp; break; case Type.INT32: res = (int)(uint)sp; break; case Type.INT64: res = (long)(ulong)sp; break; case Type.POINTER: res = new SafePointer(sp.array, sp.stream, (int)(uint)sp); break; case Type.HEADER: res = fi.Header.Create(fi.ParentHeader, sp); break; case Type.NATIVEINT: PEHeader ioh = fi.ParentHeader; res = ((ioh != null) && (ioh.Magic == PEMagic.PE32Plus)) ? (ulong)sp : (uint)sp; break; default: throw new InvalidOperationException("Unknown type"); } return(res); }
private bool CookieOffsetValid(BinaryAnalyzerContext context, SafePointer boundsCheck) { if (boundsCheck.IsValid) { return true; } if (context.PE.IsPacked) { LogInvalidCookieOffsetForKnownPackedFile(context); } else { LogInvalidCookieOffset(context); } return false; }
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; SafePointer boundsCheck = fileCookiePtr + 8; if (!CookieOffsetValid(context, boundsCheck)) { return false; } if (!boundsCheck.IsValid && context.PE.IsPacked) { LogInvalidCookieOffsetForKnownPackedFile(context); return false; } UInt64 cookie = BitConverter.ToUInt64(fileCookiePtr.GetBytes(8), 0); if (cookie != StackProtectionUtilities.DefaultCookieX64) { LogFailure(context, cookie.ToString("x")); return false; } return true; }
public abstract ImageHeader Create(PEHeader parentHeader, SafePointer sp);
public ImageHeader(PEHeader parentHeader, SafePointer sp) { ParentHeader = parentHeader; m_pHeader = sp; }
private bool Validate32BitImage(BinaryAnalyzerContext context) { PEHeader peHeader = context.PE.PEHeaders.PEHeader; SafePointer sp = new SafePointer(context.PE.ImageBytes, peHeader.LoadConfigTableDirectory.RelativeVirtualAddress); SafePointer loadConfigVA = context.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 context.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) { // '{0}' is a C or C++binary that enables the stack protection feature but the security cookie could not be located. The binary may be corrupted. context.Logger.Log(MessageKind.Fail, context, RuleUtilities.BuildMessage(context, RulesResources.DoNotModifyStackProtectionCookie_CouldNotLocateCookie_Fail)); return false; } UInt64 fileCookieOffset = (cookieVA - baseAddress) - (sectionVA - baseAddress) + (UInt32)ish.PointerToRawData; SafePointer fileCookiePtr = loadConfigVA; fileCookiePtr.Address = (int)fileCookieOffset; UInt32 cookie = BitConverter.ToUInt32(fileCookiePtr.GetBytes(8), 0); if (!StackProtectionUtilities.DefaultCookiesX86.Contains(cookie) && context.PE.Machine == Machine.I386) { // '{0}' is a C or C++ binary that interferes with the stack protector. The // stack protector (/GS) is a security feature of the compiler which makes // it more difficult to exploit stack buffer overflow memory corruption // vulnerabilities. The stack protector relies on a random number, called // the "security cookie", to detect these buffer overflows. This 'cookie' // is statically linked with your binary from a Visual C++ library in the // form of the symbol __security_cookie. On recent Windows versions, the // loader looks for the magic statically linked value of this cookie, and // initializes the cookie with a far better source of entropy -- the system's // secure random number generator -- rather than the limited random number // generator available early in the C runtime startup code. When this symbol // is not the default value, the additional entropy is not injected by the // operating system, reducing the effectiveness of the stack protector. To // resolve this issue, ensure that your code does not reference or create a // symbol named __security_cookie or __security_cookie_complement. NOTE: // the modified cookie value detected was: {1} context.Logger.Log(MessageKind.Fail, context, RuleUtilities.BuildMessage(context, RulesResources.DoNotModifyStackProtectionCookie_Fail, cookie.ToString("x"))); return false; } return true; }
public override ImageHeader Create(PEHeader parentHeader, SafePointer sp) { return new ImageLoadConfigDirectory32(parentHeader, sp); }
public abstract ImageHeader Create(PEHeader parentHeader, SafePointer sp);
private bool Validate32BitImage(BinaryAnalyzerContext context) { PEHeader peHeader = context.PE.PEHeaders.PEHeader; SafePointer sp = new SafePointer(context.PE.ImageBytes, peHeader.LoadConfigTableDirectory.RelativeVirtualAddress); SafePointer loadConfigVA = context.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 context.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; UInt32 cookie = BitConverter.ToUInt32(fileCookiePtr.GetBytes(8), 0); if (!StackProtectionUtilities.DefaultCookiesX86.Contains(cookie) && context.PE.Machine == Machine.I386) { LogFailure(context, cookie.ToString("x")); return false; } return true; }
public ImageHeader(PEHeader parentHeader, SafePointer sp) { ParentHeader = parentHeader; m_pHeader = sp; }
public void Analyze(BinaryAnalyzerContext context) { PEHeader peHeader = context.PE.PEHeaders.PEHeader; /* IMAGE_DLLCHARACTERISTICS_NO_SEH */ if ((peHeader.DllCharacteristics & DllCharacteristics.NoSeh) == DllCharacteristics.NoSeh) { // '{0}' is an x86 binary that does not use SEH, making it an invalid // target for exploits that attempt to replace SEH jump targets with // attacker-controlled shellcode. context.Logger.Log(MessageKind.Pass, context, RuleUtilities.BuildMessage(context, RulesResources.EnableSafeSEH_NoSEH_Pass)); return; } // This will not raise false positives for non-C and C++ code, because the above // check for IMAGE_DLLCHARACTERISTICS_NO_SEH excludes things that don't actually // handle SEH exceptions like .NET ngen'd code. if (peHeader.LoadConfigTableDirectory.RelativeVirtualAddress == 0) { // '{0}' is an x86 binary which does not contain a load configuration table, // indicating that it does not enable the SafeSEH mitigation. SafeSEH makes // it more difficult to exploit memory corruption vulnerabilities that can // overwrite SEH control blocks on the stack, by verifying that the location // to which a thrown SEH exception would jump is indeed defined as an // exception handler in the source program (and not shellcode). To resolve // this issue, supply the /SafeSEH flag on the linker command line. Note // that you will need to configure your build system to supply this flag for // x86 builds only, as the /SafeSEH flag is invalid when linking for ARM and x64. context.Logger.Log(MessageKind.Fail, context, RuleUtilities.BuildMessage(context, RulesResources.EnableSafeSEH_NoLoadConfigurationTable_Fail)); return; } SafePointer sp = new SafePointer(context.PE.ImageBytes, peHeader.LoadConfigTableDirectory.RelativeVirtualAddress); SafePointer loadConfigVA = context.PE.RVA2VA(sp); ImageLoadConfigDirectory32 loadConfig = new ImageLoadConfigDirectory32(peHeader, loadConfigVA); Int32 seHandlerSize = (Int32)loadConfig.GetField(ImageLoadConfigDirectory32.Fields.Size); if (seHandlerSize < 72) { // contains an unexpectedly small load configuration table {size 0} string seHandlerSizeText = String.Format(RulesResources.EnableSafeSEH_LoadConfigurationIsTooSmall_Fail, seHandlerSize.ToString()); context.Logger.Log(MessageKind.Fail, context, RuleUtilities.BuildMessage(context, RulesResources.EnableSafeSEH_Formatted_Fail, RulesResources.EnableSafeSEH_LoadConfigurationIsTooSmall_Fail, seHandlerSizeText)); return; } UInt32 seHandlerTable = (UInt32)loadConfig.GetField(ImageLoadConfigDirectory32.Fields.SEHandlerTable); UInt32 seHandlerCount = (UInt32)loadConfig.GetField(ImageLoadConfigDirectory32.Fields.SEHandlerCount); if (seHandlerTable == 0 || seHandlerCount == 0) { string failureKind = null; if (seHandlerTable == 0) { // has an empty SE handler table in the load configuration table failureKind = RulesResources.EnableSafeSEH_EmptySEHandlerTable_Fail; } else if (seHandlerCount == 0) { // has zero SE handlers in the load configuration table failureKind = RulesResources.EnableSafeSEH_ZeroCountSEHandlers_Fail; } // '{0}' is an x86 binary which {1}, indicating that it does not enable the SafeSEH // mitigation. SafeSEH makes it more difficult to exploit memory corruption // vulnerabilities that can overwrite SEH control blocks on the stack, by verifying // that the location to which a thrown SEH exception would jump is indeed defined // as an exception handler in the source program (and not shellcode). To resolve // this issue, supply the /SafeSEH flag on the linker command line. Note that you // will need to configure your build system to supply this flag for x86 builds only, // as the /SafeSEH flag is invalid when linking for ARM and x64. context.Logger.Log(MessageKind.Fail, context, RuleUtilities.BuildMessage(context, RulesResources.EnableSafeSEH_Formatted_Fail, failureKind)); return; } // ''{0}' is an x86 binary that enables SafeSEH, a mitigation that verifies SEH exception // jump targets are defined as exception handlers in the program (and not shellcode). context.Logger.Log(MessageKind.Pass, context, RuleUtilities.BuildMessage(context, RulesResources.EnableSafeSEH_SafeSEHEnabled_Pass)); }
public ImageHeader(PEHeader parentHeader, SafePointer sp) { this.ParentHeader = parentHeader; this.m_pHeader = sp; }
public SafePointer RVA2VA(SafePointer rva) { // find which section is our rva in SectionHeader ish = new SectionHeader(); foreach (SectionHeader sectionHeader in PEHeaders.SectionHeaders) { if ((rva.Address >= sectionHeader.VirtualAddress) && (rva.Address < sectionHeader.VirtualAddress + sectionHeader.SizeOfRawData)) { ish = sectionHeader; break; } } if (ish.VirtualAddress == 0) throw new InvalidOperationException("RVA does not belong to any section"); // calculate the VA rva.Address = (int)(rva.Address - ish.VirtualAddress + ish.PointerToRawData); return rva; }
public ImageLoadConfigDirectory32(PEHeader parentHeader, SafePointer sp) : base(parentHeader, sp) { }
public int GetFieldSize(int n) { ImageFieldData fi = GetFieldInfo(n); int count = fi.Count; int padding = fi.PadTo; int size; int len; if (fi.VarLen) { SafePointer field_start = m_pHeader + GetFieldOffset(n); SafePointer field_end = field_start; while ((byte)field_end != fi.TrailingByte) { field_end++; } // if we have a VarLen and a PadTo specified we will make sure // we only skip up to PadTo trailing bytes if (padding != 0) { padding = padding - (field_end.Address - m_pHeader.Address) % padding; } else { padding = -1; } while (((byte)field_end == fi.TrailingByte) && (padding-- != 0)) { field_end++; } return(field_end - field_start); } if (fi.Type == Type.HEADER) { object o = GetField(n); if (o is Array) { len = ((ImageHeader)((object[])o)[0]).Size; } else { len = ((ImageHeader)o).Size; } } else { len = fi.GetTypeLen(); } if (count == 1) { return(len); } // if a negative count is provided we tread it as an offset of // the field where to find the real count if (count < 0) { count = Convert.ToInt32(GetField(n + count)); } size = len * count; // We don't pad is the size is already a multiple of padding if ((padding != 0) && (size % padding != 0)) { size += padding - (size % padding); } return(size); }
public override ImageHeader Create(PEHeader parentHeader, SafePointer sp) { return(new ImageLoadConfigDirectory32(parentHeader, sp)); }
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 ImageLoadConfigDirectory32(PEHeader parentHeader, SafePointer sp) : base(parentHeader, sp) { }