public override void Analyze(BinaryAnalyzerContext context) { PEHeader peHeader = context.PE.PEHeaders.PEHeader; if (context.Pdb == null) { Errors.LogExceptionLoadingPdb(context, context.PdbParseException); return; } Pdb di = context.Pdb; TruncatedCompilandRecordList warningTooLowModules = new TruncatedCompilandRecordList(); TruncatedCompilandRecordList disabledWarningModules = new TruncatedCompilandRecordList(); TruncatedCompilandRecordList unknownLanguageModules = new TruncatedCompilandRecordList(); TruncatedCompilandRecordList allWarningLevelLowModules = new TruncatedCompilandRecordList(); string exampleTooLowWarningCommandLine = null; int overallMinimumWarningLevel = Int32.MaxValue; string exampleDisabledWarningCommandLine = null; List <int> overallDisabledWarnings = new List <int>(); foreach (DisposableEnumerableView <Symbol> omView in di.CreateObjectModuleIterator()) { Symbol om = omView.Value; ObjectModuleDetails omDetails = om.GetObjectModuleDetails(); if (omDetails.Language == Language.Unknown) { // See if this module contributed to an executable section. If not, we can ignore the module. if (di.CompilandWithIdIsInExecutableSectionContrib(om.SymIndexId)) { unknownLanguageModules.Add(om.CreateCompilandRecord()); } continue; } if ((omDetails.Language != Language.C) && (omDetails.Language != Language.Cxx)) { continue; } if (omDetails.Compiler != "Microsoft (R) Optimizing Compiler") { continue; } if (!om.CreateChildIterator(SymTagEnum.SymTagFunction).Any()) { // uninteresting... continue; } int warningLevel = omDetails.WarningLevel; List <int> requiredDisabledWarnings = omDetails.ExplicitlyDisabledWarnings .Where(context.Policy.GetProperty(RequiredCompilerWarnings).Contains).ToList(); if (warningLevel >= 3 && requiredDisabledWarnings.Count == 0) { // We duplicate this condition to bail out early and avoid writing the // module description or newline into sbBadWarningModules if everything // in the module is OK. continue; } List <string> suffix = new List <string>(2); overallMinimumWarningLevel = Math.Min(overallMinimumWarningLevel, warningLevel); if (warningLevel < 3) { exampleTooLowWarningCommandLine = exampleTooLowWarningCommandLine ?? omDetails.CommandLine; string msg = "[warning level: " + warningLevel.ToString(CultureInfo.InvariantCulture) + "]"; warningTooLowModules.Add(om.CreateCompilandRecordWithSuffix(msg)); suffix.Add(msg); } if (requiredDisabledWarnings.Count != 0) { MergeInto(overallDisabledWarnings, requiredDisabledWarnings); exampleDisabledWarningCommandLine = exampleDisabledWarningCommandLine ?? omDetails.CommandLine; string msg = "[Explicitly disabled warnings: " + CreateTextWarningList(requiredDisabledWarnings) + "]"; disabledWarningModules.Add(om.CreateCompilandRecordWithSuffix(msg)); suffix.Add(msg); } allWarningLevelLowModules.Add(om.CreateCompilandRecordWithSuffix(String.Join(" ", suffix))); } if (unknownLanguageModules.Empty && exampleTooLowWarningCommandLine == null && exampleDisabledWarningCommandLine == null) { // '{0}' was compiled at a secure warning level ({1}) and does not // include any modules that disable specific warnings which are // required by policy. As a result, there is a greater likelihood // that memory corruption, information disclosure, double-free and // other security-related vulnerabilities do not exist in code. context.Logger.Log(this, RuleUtilities.BuildResult(ResultLevel.Pass, context, null, nameof(RuleResources.BA2007_Pass), overallMinimumWarningLevel.ToString())); return; } if (!unknownLanguageModules.Empty) { // '{0}' contains code from an unknown language, preventing a // comprehensive analysis of the compiler warning settings. // The language could not be identified for the following modules: {1} context.Logger.Log(this, RuleUtilities.BuildResult(ResultLevel.Error, context, null, nameof(RuleResources.BA2007_Error_UnknownModuleLanguage), unknownLanguageModules.CreateSortedObjectList())); } if (exampleTooLowWarningCommandLine != null) { // '{0}' was compiled at too low a warning level. Warning level 3 enables // important static analysis in the compiler to flag bugs that can lead // to memory corruption, information disclosure, or double-free // vulnerabilities.To resolve this issue, compile at warning level 3 or // higher by supplying / W3, / W4, or / Wall to the compiler, and resolve // the warnings emitted. // An example compiler command line triggering this check: {1} // Modules triggering this check: {2} context.Logger.Log(this, RuleUtilities.BuildResult(ResultLevel.Error, context, null, nameof(RuleResources.BA2007_Error_InsufficientWarningLevel), overallMinimumWarningLevel.ToString(), exampleTooLowWarningCommandLine, warningTooLowModules.CreateTruncatedObjectList())); } if (exampleDisabledWarningCommandLine != null) { // '{0}' disables compiler warning(s) which are required by policy. A // compiler warning is typically required if it has a high likelihood of // flagging memory corruption, information disclosure, or double-free // vulnerabilities. To resolve this issue, enable the indicated warning(s) // by removing /Wxxxx switches (where xxxx is a warning id indicated here) // from your command line, and resolve any warnings subsequently raised // during compilation. // An example compiler command line triggering this check was: {1} // Modules triggering this check were: {2} context.Logger.Log(this, RuleUtilities.BuildResult(ResultLevel.Error, context, null, nameof(RuleResources.BA2007_Error_WarningsDisabled), exampleDisabledWarningCommandLine, disabledWarningModules.CreateTruncatedObjectList())); } }
public override void Analyze(BinaryAnalyzerContext context) { PEHeader peHeader = context.PE.PEHeaders.PEHeader; Pdb pdb = context.Pdb; if (pdb == null) { Errors.LogExceptionLoadingPdb(context, context.PdbParseException); return; } TruncatedCompilandRecordList noGsModules = new TruncatedCompilandRecordList(); TruncatedCompilandRecordList unknownLanguageModules = new TruncatedCompilandRecordList(); foreach (DisposableEnumerableView <Symbol> omView in pdb.CreateObjectModuleIterator()) { Symbol om = omView.Value; ObjectModuleDetails details = om.GetObjectModuleDetails(); if (details.Language == Language.Unknown) { // See if this module contributed to an executable section. // If not, we can ignore the module. if (pdb.CompilandWithIdIsInExecutableSectionContrib(om.SymIndexId)) { unknownLanguageModules.Add(om.CreateCompilandRecord()); } continue; } // Detection applies to C/C++ produced by MS compiler only if ((details.Language != Language.C) && (details.Language != Language.Cxx) || details.Compiler != "Microsoft (R) Optimizing Compiler") { continue; } if (!details.HasSecurityChecks && om.CreateChildIterator(SymTagEnum.SymTagFunction).Any()) { noGsModules.Add(om.CreateCompilandRecord()); } } if (unknownLanguageModules.Empty && noGsModules.Empty) { // '{0}' is a C or C++ binary built with the stack protector buffer security // feature enabled for all modules, making it more difficult for an attacker to // exploit stack buffer overflow memory corruption vulnerabilities. context.Logger.Log(this, RuleUtilities.BuildResult(ResultLevel.Pass, context, null, nameof(RuleResources.BA2011_Pass))); return; } if (!unknownLanguageModules.Empty) { // '{0}' contains code from unknown language, preventing a comprehensive analysis of the // stack protector buffer security features. The language could not be identified for // the following modules: {1}. context.Logger.Log(this, RuleUtilities.BuildResult(ResultLevel.Error, context, null, nameof(RuleResources.BA2011_Error_UnknownModuleLanguage), unknownLanguageModules.CreateSortedObjectList())); } if (!noGsModules.Empty) { // '{0}' is a C or C++ binary built with the stack protector buffer security feature // disabled in one or more modules. The stack protector (/GS) is a security feature // of the compiler which makes it more difficult to exploit stack buffer overflow // memory corruption vulnerabilities. To resolve this issue, ensure that your code // is compiled with the stack protector enabled by supplying /GS on the Visual C++ // compiler command line. The affected modules were: {1} context.Logger.Log(this, RuleUtilities.BuildResult(ResultLevel.Error, context, null, nameof(RuleResources.BA2011_Error), noGsModules.ToString())); } }