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()));
            }
        }
Exemplo n.º 2
0
        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()));
            }
        }