From d0f3a90aef5105ecd58cc9a2b26b8ba1224265b7 Mon Sep 17 00:00:00 2001 From: Michael Hunhoff Date: Tue, 14 Jul 2020 21:41:02 -0600 Subject: [PATCH] adding code to handle features with no value e.g. basic block features --- capa/features/__init__.py | 9 ++++++--- capa/features/basicblock.py | 3 +++ capa/ida/explorer/model.py | 9 ++++++--- capa/render/vverbose.py | 21 +++++++++++++-------- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/capa/features/__init__.py b/capa/features/__init__.py index 5c22b376..abb38168 100644 --- a/capa/features/__init__.py +++ b/capa/features/__init__.py @@ -39,10 +39,13 @@ class Feature(object): return self.value def __str__(self): - if self.description: - return "%s(%s = %s)" % (self.name, self.get_value_str(), self.description) + if self.value: + if self.description: + return "%s(%s = %s)" % (self.name, self.get_value_str(), self.description) + else: + return "%s(%s)" % (self.name, self.get_value_str()) else: - return "%s(%s)" % (self.name, self.get_value_str()) + return "%s" % self.name def __repr__(self): return str(self) diff --git a/capa/features/basicblock.py b/capa/features/basicblock.py index 90a96138..aa103fd7 100644 --- a/capa/features/basicblock.py +++ b/capa/features/basicblock.py @@ -8,6 +8,9 @@ class BasicBlock(Feature): def __str__(self): return "basic block" + def get_value_str(self): + return "" + def freeze_serialize(self): return (self.__class__.__name__, []) diff --git a/capa/ida/explorer/model.py b/capa/ida/explorer/model.py index 76f00a87..ef1dddc2 100644 --- a/capa/ida/explorer/model.py +++ b/capa/ida/explorer/model.py @@ -467,10 +467,13 @@ class CapaExplorerDataModel(QtCore.QAbstractItemModel): bytes(01 14 02 00 00 00 00 00 C0 00 00 00 00 00 00 46 = CLSID_ShellLink) """ - if feature.get("description", ""): - return "%s(%s = %s)" % (feature["type"], feature[feature["type"]], feature["description"]) + if feature[feature["type"]]: + if feature.get("description", ""): + return "%s(%s = %s)" % (feature["type"], feature[feature["type"]], feature["description"]) + else: + return "%s(%s)" % (feature["type"], feature[feature["type"]]) else: - return "%s(%s)" % (feature["type"], feature[feature["type"]]) + return "%s" % feature["type"] def render_capa_doc_feature_node(self, parent, feature, locations, doc): """ process capa doc feature node diff --git a/capa/render/vverbose.py b/capa/render/vverbose.py index adf53dd8..c2e6dce1 100644 --- a/capa/render/vverbose.py +++ b/capa/render/vverbose.py @@ -44,12 +44,15 @@ def render_statement(ostream, match, statement, indent=0): # so, we have to inline some of the feature rendering here. child = statement["child"] - value = rutils.bold2(child[child["type"]]) - if child.get("description"): - ostream.write("count(%s(%s = %s)): " % (child["type"], value, child["description"])) + if child[child["type"]]: + value = rutils.bold2(child[child["type"]]) + if child.get("description"): + ostream.write("count(%s(%s = %s)): " % (child["type"], value, child["description"])) + else: + ostream.write("count(%s(%s)): " % (child["type"], value)) else: - ostream.write("count(%s(%s)): " % (child["type"], value)) + ostream.write("count(%s): " % child["type"]) if statement["max"] == statement["min"]: ostream.write("%d" % (statement["min"])) @@ -79,11 +82,13 @@ def render_feature(ostream, match, feature, indent=0): ostream.write(feature["type"]) ostream.write(": ") - ostream.write(rutils.bold2(feature[feature["type"]])) - if "description" in feature: - ostream.write(capa.rules.DESCRIPTION_SEPARATOR) - ostream.write(feature["description"]) + if feature[feature["type"]]: + ostream.write(rutils.bold2(feature[feature["type"]])) + + if "description" in feature: + ostream.write(capa.rules.DESCRIPTION_SEPARATOR) + ostream.write(feature["description"]) render_locations(ostream, match) ostream.write("\n")