mirror of
https://github.com/mandiant/capa.git
synced 2025-12-12 23:59:48 -08:00
Improved parse routine based on suggestions. Co-Authored-By: Moritz <mr-tz@users.noreply.github.com>
88 lines
2.7 KiB
Python
88 lines
2.7 KiB
Python
import os
|
|
import argparse
|
|
|
|
import yaml
|
|
|
|
|
|
def findall_features(features):
|
|
feature_list = []
|
|
for feature in features:
|
|
if "and" in feature:
|
|
and_list = findall_features(feature["and"])
|
|
for x in and_list:
|
|
feature_list.append(x)
|
|
elif "or" in feature:
|
|
or_list = findall_features(feature["or"])
|
|
for y in or_list:
|
|
feature_list.append(y)
|
|
else:
|
|
feature_list.append(feature)
|
|
|
|
return feature_list
|
|
|
|
|
|
def find_overlapping_rules(new_rule_path, rules_path):
|
|
if not new_rule_path.endswith(".yml"):
|
|
raise ValueError("ERROR ! New rule path file name incorrect")
|
|
|
|
count = 0
|
|
|
|
with open(new_rule_path, "r") as f:
|
|
new_rule = yaml.safe_load(f)
|
|
|
|
if "rule" not in new_rule:
|
|
raise ValueError("ERROR ! given new rule path isn't a rule")
|
|
|
|
new_rule_features = findall_features(new_rule["rule"]["features"])
|
|
|
|
overlapping_rules = []
|
|
for rules in rules_path:
|
|
for dirpath, dirnames, filenames in os.walk(rules):
|
|
for filename in filenames:
|
|
if filename.endswith(".yml"):
|
|
rule_path = os.path.join(dirpath, filename)
|
|
with open(rule_path, "r") as f:
|
|
rule = yaml.safe_load(f)
|
|
if "rule" not in rule:
|
|
continue
|
|
rule_features = findall_features(rule["rule"]["features"])
|
|
count += 1
|
|
if any([feature in rule_features for feature in new_rule_features]):
|
|
overlapping_rules.append(rule_path)
|
|
|
|
result = {"overlapping_rules": overlapping_rules, "count": count}
|
|
|
|
return result
|
|
|
|
|
|
# python script.py --base-dir /path/to/capa/rules rules/anti-analysis/reference-analysis-tools-strings.yml rules
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Find overlapping features in Capa rules.")
|
|
|
|
parser.add_argument("rules", type=str, action="append", help="Path to rules")
|
|
parser.add_argument("new_rule", type=str, help="Path to new rule")
|
|
|
|
args = parser.parse_args()
|
|
|
|
new_rule_path = args.new_rule
|
|
rules_path = args.rules
|
|
|
|
try:
|
|
result = find_overlapping_rules(new_rule_path, rules_path)
|
|
print("New rule path : %s" % new_rule_path)
|
|
print("Number of rules checked : %s " % result["count"])
|
|
print("Paths to overlapping rules : ", result["overlapping_rules"])
|
|
print("Number of rules containing same features : %s" % len(result["overlapping_rules"]))
|
|
except Exception as e:
|
|
print(e)
|
|
try:
|
|
print(result)
|
|
except:
|
|
pass
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|