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); }
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); }
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); }
private bool CookieOffsetValid(BinaryAnalyzerContext context, SafePointer boundsCheck) { if (boundsCheck.IsValid) { return(true); } if (context.PE.IsPacked) { LogInvalidCookieOffsetForKnownPackedFile(context); } else { LogInvalidCookieOffset(context); } return(false); }
public override 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(this, RuleUtilities.BuildResult(ResultKind.Pass, context, null, nameof(RuleResources.BA2018_Pass_NoSEH))); 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(this, RuleUtilities.BuildResult(ResultKind.Error, context, null, nameof(RuleResources.BA2018_Fail), RuleResources.BA2018_Fail_NoLoadConfigurationTable)); 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(RuleResources.BA2018_Fail_LoadConfigurationIsTooSmall, seHandlerSize.ToString()); context.Logger.Log(this, RuleUtilities.BuildResult(ResultKind.Error, context, null, nameof(RuleResources.BA2018_Fail), RuleResources.BA2018_Fail_LoadConfigurationIsTooSmall, 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 = RuleResources.BA2018_Fail_EmptySEHandlerTable; } else if (seHandlerCount == 0) { // has zero SE handlers in the load configuration table failureKind = RuleResources.BA2018_Fail_NoSEHandlers; } // '{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(this, RuleUtilities.BuildResult(ResultKind.Error, context, null, nameof(RuleResources.BA2018_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(this, RuleUtilities.BuildResult(ResultKind.Pass, context, null, nameof(RuleResources.BA2018_Pass))); }
private bool Validate64BitImage(BinaryAnalyzerContext context) { PEBinary target = context.PEBinary(); PEHeader peHeader = target.PE.PEHeaders.PEHeader; var sp = new SafePointer(target.PE.ImageBytes, peHeader.LoadConfigTableDirectory.RelativeVirtualAddress); SafePointer loadConfigVA = target.PE.RVA2VA(sp); var loadConfig = new ImageLoadConfigDirectory64(peHeader, loadConfigVA); ulong cookieVA = (ulong)loadConfig.GetField(ImageLoadConfigDirectory64.Fields.SecurityCookie); ulong baseAddress = peHeader.ImageBase; // we need to find the offset in the file based on the cookie's VA ulong sectionSize, sectionVA = 0; var ish = new SectionHeader(); bool foundCookieSection = false; foreach (SectionHeader t in target.PE.PEHeaders.SectionHeaders) { sectionVA = (uint)t.VirtualAddress + baseAddress; sectionSize = (uint)t.VirtualSize; if ((cookieVA >= sectionVA) && (cookieVA < sectionVA + sectionSize)) { ish = t; foundCookieSection = true; break; } } if (!foundCookieSection) { this.LogCouldNotLocateCookie(context); return(false); } ulong fileCookieOffset = (cookieVA - baseAddress) - (sectionVA - baseAddress) + (uint)ish.PointerToRawData; SafePointer fileCookiePtr = loadConfigVA; fileCookiePtr.Address = (int)fileCookieOffset; SafePointer boundsCheck = fileCookiePtr + 8; if (!this.CookieOffsetValid(context, boundsCheck)) { return(false); } if (!boundsCheck.IsValid && target.PE.IsPacked) { this.LogInvalidCookieOffsetForKnownPackedFile(context); return(false); } ulong cookie = BitConverter.ToUInt64(fileCookiePtr.GetBytes(8), 0); if (cookie != StackProtectionUtilities.DefaultCookieX64) { this.LogFailure(context, cookie.ToString("x")); return(false); } return(true); }
public string[] ImportFunctionsGet(PEFile OpenPE) { if (this.m_asImports == null) { if (((OpenPE.DirectoryEntries == null) || (OpenPE.DirectoryEntries.Length < 1)) || (OpenPE.DirectoryEntries[1] == null)) { return(null); } } ImageDataDirectory directory = OpenPE.DirectoryEntries[1]; SafePointer field = (SafePointer)directory.GetField(ImageDataDirectory.Fields.VirtualAddress); ArrayList list = new ArrayList(); if (field.Address != 0) { field = OpenPE.RVA2VA(field); while (((((uint)field) != 0) && (((uint)(field + 12)) != 0))) // IDT { SafePointer rva = field; rva.Address = (int)((uint)(field + 12)); // name of DLL string str = (string)OpenPE.RVA2VA(rva); /* * Ollie */ SafePointer rva2 = field; rva2.Address = (int)((uint)(field)); // ILT RVA SafePointer field2; field2 = OpenPE.RVA2VA(rva2); // get the ILT RVA pointed too address while (((uint)(field2)) != 0u) { if (OpenPE.Is64Bit == false) { try { SafePointer rva3 = field2; if (((int)((uint)(field2)) & 0x80000000) == 0x80000000) // ordinal { //Console.WriteLine("Ordinal"); //list.Add(str + " - Ordinal " + Convert.ToInt16((int)((uint)(field2))) ); } else { rva3.Address = (int)((uint)(field2)); string str2 = (string)(OpenPE.RVA2VA(rva3) + 2); //Console.WriteLine(str2.ToString()); if (list.Contains(str2) == false) { //list.Add(str2 + "(" + str +")"); list.Add(str2); } } } catch (SystemException exception) { throw (exception); } field2 += 4; // 32bit ILT } else { try { SafePointer rva3 = field2; if (((int)((uint)(field2 + 4)) & 0x80000000) == 0x80000000) // ordinal { //Console.WriteLine("Ordinal"); //list.Add(str + " - Ordinal " + Convert.ToInt16((int)((uint)(field2))) ); } else { rva3.Address = (int)((uint)(field2)); string str2 = (string)(OpenPE.RVA2VA(rva3) + 2); //Console.WriteLine(str2.ToString()); if (list.Contains(str2) == false) { //list.Add(str + " - " + str2); //list.Add(str2 + "(" + str + ")"); list.Add(str2); } } } catch (SystemException exception) { throw (exception); } field2 += 8; // 64bit ILT } } field += 20; // IDT } } list.Sort(); this.m_asImports = (string[])list.ToArray(typeof(string)); return(this.m_asImports); }
public string[] DelayLoadImportFunctionsGet(PEFile OpenPE, string strFilename) { ArrayList list = new ArrayList(); try { if (this.m_delayImports == null) { if (((OpenPE.DirectoryEntries == null) || (OpenPE.DirectoryEntries.Length < 13)) || (OpenPE.DirectoryEntries[ImageOptionalHeader.IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT] == null)) { return(null); } uint DirSize = (uint)OpenPE.DirectoryEntries[ImageOptionalHeader.IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].GetField(ImageDataDirectory.Fields.Size); if (DirSize == 0) { return(null); } } // This gets RVA of the delay import table SafePointer rva = (SafePointer)OpenPE.DirectoryEntries[ImageOptionalHeader.IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].GetField(ImageDataDirectory.Fields.VirtualAddress); if (rva.Address == 0) { return(null); } // Covert the address to the VA rva = OpenPE.RVA2VA(rva); while (((((uint)rva) != 0) && (((uint)(rva + 4)) != 0))) // IDT { uint uAttr = (uint)(OpenPE.RVA2VA(rva)); SafePointer rva2 = new SafePointer(); rva2.Address = (int)((uint)(rva + 4)); // address of the name SafePointer rva3 = new SafePointer(); rva3.Address = (int)((uint)(rva + 8)); // address of HMODULE SafePointer rva4 = new SafePointer(); rva4.Address = (int)((uint)(rva + 12)); // RVA of the IAT SafePointer rva5 = new SafePointer(); rva5.Address = (int)((uint)(rva + 16)); // RVA of the Hint table // Seek and get the DLL name rva2 = OpenPE.RVA2VA(rva2); byte[] dataArray = new byte[1024]; using (FileStream fileStream = new FileStream(strFilename, FileMode.Open, FileAccess.Read)) { fileStream.Seek(rva2.Address, SeekOrigin.Begin); for (int i = 0; i < fileStream.Length; i++) { dataArray[i] = (byte)fileStream.ReadByte(); if (dataArray[i] == 0x00) { break; } } } //Console.WriteLine(System.Text.Encoding.Default.GetString(dataArray)); list.Add(System.Text.Encoding.Default.GetString(dataArray)); /* * rva4 = OpenPE.RVA2VA(rva4); * int intIncr = 0; * if (PE.Is64Bit) intIncr = 64; * else intIncr = 32; * int intCount = 0; * using(FileStream fileStream = new FileStream(strFilename, FileMode.Open, FileAccess.Read)) * { * fileStream.Seek(rva4.Address, SeekOrigin.Begin); * for(int i = 0; i < fileStream.Length; i+=intIncr){ * Console.Write("."); * fileStream.Read(dataArray, 0, intIncr); * if (dataArray[0] == 0x00 && dataArray[1] == 0x00 && dataArray[2] == 0x00 && dataArray[3] == 0x00 && dataArray[4] == 0x00) break; * else intCount++; * * } * } */ //Console.WriteLine("[!]" + intCount.ToString()); /* * uint field2 = 0; * while( * while(((uint)(field2)) != 0u) * { * * if (OpenPE.Is64Bit == false) * { * try * { * if (((int)((uint)(field2)) & 0x80000000) == 0x80000000) // ordinal * { * Console.WriteLine("Ordinal"); * } * else * { * Console.WriteLine("Not Ordinal"); * } * * } * catch (SystemException exception) * { * throw (exception); * } * * field2 += 4; // 32bit ILT * } * else * { * try * { * if (((int)((uint)(field2+4)) & 0x80000000) == 0x80000000) // ordinal * { * Console.WriteLine("Ordinal"); * } * else * { * Console.WriteLine("NOT Ordinal"); * } * * } * catch (SystemException exception) * { * throw (exception); * } * * field2 += 8; // 64bit ILT * } * } * * field += 20; // IDT * } * * * */ rva += 32; // IDT } } catch { return(null); } list.Sort(); this.m_delayImports = (string[])list.ToArray(typeof(string)); return(this.m_delayImports); }
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) { // '{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; UInt64 cookie = BitConverter.ToUInt64(fileCookiePtr.GetBytes(8), 0); if (cookie != StackProtectionUtilities.DefaultCookieX64) { // '{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); }