mirror of
https://github.com/mandiant/capa.git
synced 2025-12-23 07:28:34 -08:00
@@ -103,6 +103,7 @@ It includes many new rules, including all new techniques introduced in MITRE ATT
|
|||||||
- show-features: don't show features from library functions #569 @williballenthin
|
- show-features: don't show features from library functions #569 @williballenthin
|
||||||
- linter: summarize results at the end #571 @williballenthin
|
- linter: summarize results at the end #571 @williballenthin
|
||||||
- meta: added `library_functions` field, `feature_counts.functions` does not include library functions any more #562 @mr-tz
|
- meta: added `library_functions` field, `feature_counts.functions` does not include library functions any more #562 @mr-tz
|
||||||
|
- linter: check for `or` with always true child statement, e.g. `optional`, colors #348 @mr-tz
|
||||||
|
|
||||||
### Development
|
### Development
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import argparse
|
|||||||
import itertools
|
import itertools
|
||||||
import posixpath
|
import posixpath
|
||||||
|
|
||||||
|
import termcolor
|
||||||
import ruamel.yaml
|
import ruamel.yaml
|
||||||
|
|
||||||
import capa.main
|
import capa.main
|
||||||
@@ -36,9 +37,21 @@ import capa.features.insn
|
|||||||
logger = logging.getLogger("lint")
|
logger = logging.getLogger("lint")
|
||||||
|
|
||||||
|
|
||||||
|
def red(s):
|
||||||
|
return termcolor.colored(s, "red")
|
||||||
|
|
||||||
|
|
||||||
|
def orange(s):
|
||||||
|
return termcolor.colored(s, "yellow")
|
||||||
|
|
||||||
|
|
||||||
|
def green(s):
|
||||||
|
return termcolor.colored(s, "green")
|
||||||
|
|
||||||
|
|
||||||
class Lint(object):
|
class Lint(object):
|
||||||
WARN = "WARN"
|
WARN = orange("WARN")
|
||||||
FAIL = "FAIL"
|
FAIL = red("FAIL")
|
||||||
|
|
||||||
name = "lint"
|
name = "lint"
|
||||||
level = FAIL
|
level = FAIL
|
||||||
@@ -241,6 +254,30 @@ class StatementWithSingleChildStatement(Lint):
|
|||||||
return self.violation
|
return self.violation
|
||||||
|
|
||||||
|
|
||||||
|
class OrStatementWithAlwaysTrueChild(Lint):
|
||||||
|
name = "rule contains an `or` statement that's always True because of an `optional` or other child statement that's always True"
|
||||||
|
recommendation = "clarify the rule logic, e.g. by moving the always True child statement"
|
||||||
|
recommendation_template = "clarify the rule logic, e.g. by moving the always True child statement: {:s}"
|
||||||
|
violation = False
|
||||||
|
|
||||||
|
def check_rule(self, ctx, rule):
|
||||||
|
self.violation = False
|
||||||
|
|
||||||
|
def rec(statement):
|
||||||
|
if isinstance(statement, capa.engine.Or):
|
||||||
|
children = list(statement.get_children())
|
||||||
|
for child in children:
|
||||||
|
# `Some` implements `optional` which is an alias for `0 or more`
|
||||||
|
if isinstance(child, capa.engine.Some) and child.count == 0:
|
||||||
|
self.recommendation = self.recommendation_template.format(str(child))
|
||||||
|
self.violation = True
|
||||||
|
rec(child)
|
||||||
|
|
||||||
|
rec(rule.statement)
|
||||||
|
|
||||||
|
return self.violation
|
||||||
|
|
||||||
|
|
||||||
class UnusualMetaField(Lint):
|
class UnusualMetaField(Lint):
|
||||||
name = "unusual meta field"
|
name = "unusual meta field"
|
||||||
recommendation = "Remove the meta field"
|
recommendation = "Remove the meta field"
|
||||||
@@ -498,6 +535,7 @@ def get_rule_features(rule):
|
|||||||
LOGIC_LINTS = (
|
LOGIC_LINTS = (
|
||||||
DoesntMatchExample(),
|
DoesntMatchExample(),
|
||||||
StatementWithSingleChildStatement(),
|
StatementWithSingleChildStatement(),
|
||||||
|
OrStatementWithAlwaysTrueChild(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -578,7 +616,7 @@ def lint_rule(ctx, rule):
|
|||||||
if (not lints_failed) and (not lints_warned) and has_examples:
|
if (not lints_failed) and (not lints_warned) and has_examples:
|
||||||
print("")
|
print("")
|
||||||
print("%s%s" % (" (nursery) ", rule.name))
|
print("%s%s" % (" (nursery) ", rule.name))
|
||||||
print("%s %s: %s: %s" % (" ", Lint.WARN, "no lint failures", "Graduate the rule"))
|
print("%s %s: %s: %s" % (" ", Lint.WARN, green("no lint failures"), "Graduate the rule"))
|
||||||
print("")
|
print("")
|
||||||
else:
|
else:
|
||||||
lints_failed = len(tuple(filter(lambda v: v.level == Lint.FAIL, violations)))
|
lints_failed = len(tuple(filter(lambda v: v.level == Lint.FAIL, violations)))
|
||||||
@@ -718,18 +756,18 @@ def main(argv=None):
|
|||||||
logger.debug("lints ran for ~ %02d:%02dm", min, sec)
|
logger.debug("lints ran for ~ %02d:%02dm", min, sec)
|
||||||
|
|
||||||
if warned_rules:
|
if warned_rules:
|
||||||
print("rules with WARN:")
|
print(orange("rules with WARN:"))
|
||||||
for warned_rule in sorted(warned_rules):
|
for warned_rule in sorted(warned_rules):
|
||||||
print(" - " + warned_rule)
|
print(" - " + warned_rule)
|
||||||
print()
|
print()
|
||||||
|
|
||||||
if failed_rules:
|
if failed_rules:
|
||||||
print("rules with FAIL:")
|
print(red("rules with FAIL:"))
|
||||||
for failed_rule in sorted(failed_rules):
|
for failed_rule in sorted(failed_rules):
|
||||||
print(" - " + failed_rule)
|
print(" - " + failed_rule)
|
||||||
return 1
|
return 1
|
||||||
else:
|
else:
|
||||||
logger.info("no lints failed, nice!")
|
logger.info(green("no lints failed, nice!"))
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user