diff --git a/capa/render/dictionary.py b/capa/render/dictionary.py index f1d72e31..fb068371 100644 --- a/capa/render/dictionary.py +++ b/capa/render/dictionary.py @@ -72,12 +72,13 @@ def render_capabilities(doc, ostream): else: capability = "%s (%d matches)" % (rule["meta"]["name"], count) - ostream["CAPABILITY"].setdefault(capability, rule["meta"]["namespace"]) + ostream["CAPABILITY"].setdefault(rule["meta"]["namespace"], list()) + ostream["CAPABILITY"][rule["meta"]["namespace"]].append(capability) def render_attack(doc, ostream): """ example:: - {'ATT&CK': {'COLLECTION': ['Input Capture::Keylogging [T1056.001]'], + {'ATTCK': {'COLLECTION': ['Input Capture::Keylogging [T1056.001]'], 'DEFENSE EVASION': ['Obfuscated Files or Information [T1027]', 'Virtualization/Sandbox Evasion::System Checks ' '[T1497.001]'], @@ -87,7 +88,7 @@ def render_attack(doc, ostream): 'EXECUTION': ['Shared Modules [T1129]']} } """ - ostream["ATT&CK"] = dict() + ostream["ATTCK"] = dict() tactics = collections.defaultdict(set) for rule in rutils.capability_rules(doc): if not rule["meta"].get("att&ck"): @@ -114,7 +115,7 @@ def render_attack(doc, ostream): inner_rows.append("%s::%s %s" % (technique, subtechnique, id)) else: raise RuntimeError("unexpected ATT&CK spec format") - ostream["ATT&CK"].setdefault(tactic.upper(), inner_rows) + ostream["ATTCK"].setdefault(tactic.upper(), inner_rows) def render_mbc(doc, ostream): diff --git a/scripts/capa_as_library.py b/scripts/capa_as_library.py index 6190c377..53725cd9 100644 --- a/scripts/capa_as_library.py +++ b/scripts/capa_as_library.py @@ -29,3 +29,5 @@ meta["analysis"].update(counts) capa_json = json.loads(capa.render.render_json(meta, rules, capabilities)) # ...as human readable text table capa_texttable = capa.render.render_default(meta, rules, capabilities) +# ...as python dictionary, simplified as textable but in dictionary +capa_dict = capa.render.render_dictionary(meta, rules, capabilities)