def render_capa_doc_feature_node(self, parent, feature, locations, doc): """process capa doc feature node @param parent: parent node to which child is assigned @param feature: capa doc feature node @param locations: locations identified for feature @param doc: capa doc """ display = self.capa_doc_feature_to_display(feature) if len(locations) == 1: # only one location for feature so no need to nest children parent2 = self.render_capa_doc_feature( parent, feature, next(iter(locations)), doc, display=display, ) else: # feature has multiple children, nest under one parent feature node parent2 = CapaExplorerFeatureItem(parent, display) for location in sorted(locations): self.render_capa_doc_feature(parent2, feature, location, doc) return parent2
def render_capa_doc_statement_node(self, parent, statement, locations, doc): """render capa statement read from doc @param parent: parent to which new child is assigned @param statement: statement read from doc @param locations: locations of children (applies to range only?) @param doc: result doc """ if statement["type"] in ("and", "or", "optional"): display = statement["type"] if statement.get("description"): display += " (%s)" % statement["description"] return CapaExplorerDefaultItem(parent, display) elif statement["type"] == "not": # TODO: do we display 'not' pass elif statement["type"] == "some": display = "%d or more" % statement["count"] if statement.get("description"): display += " (%s)" % statement["description"] return CapaExplorerDefaultItem(parent, display) elif statement["type"] == "range": # `range` is a weird node, its almost a hybrid of statement + feature. # it is a specific feature repeated multiple times. # there's no additional logic in the feature part, just the existence of a feature. # so, we have to inline some of the feature rendering here. display = "count(%s): " % self.capa_doc_feature_to_display( statement["child"]) if statement["max"] == statement["min"]: display += "%d" % (statement["min"]) elif statement["min"] == 0: display += "%d or fewer" % (statement["max"]) elif statement["max"] == (1 << 64 - 1): display += "%d or more" % (statement["min"]) else: display += "between %d and %d" % (statement["min"], statement["max"]) if statement.get("description"): display += " (%s)" % statement["description"] parent2 = CapaExplorerFeatureItem(parent, display=display) for location in locations: # for each location render child node for range statement self.render_capa_doc_feature(parent2, statement["child"], location, doc) return parent2 elif statement["type"] == "subscope": display = statement[statement["type"]] if statement.get("description"): display += " (%s)" % statement["description"] return CapaExplorerSubscopeItem(parent, display) else: raise RuntimeError("unexpected match statement type: " + str(statement))
def render_capa_doc_feature(self, parent, feature, location, doc, display="-"): """render capa feature read from doc @param parent: parent node to which new child is assigned @param feature: feature read from doc @param doc: capa feature doc @param location: address of feature @param display: text to display in plugin UI """ # special handling for characteristic pending type if feature["type"] == "characteristic": if feature[feature["type"]] in ("embedded pe", ): return CapaExplorerByteViewItem(parent, display, location) if feature[feature["type"]] in ("loop", "recursive call", "tight loop"): return CapaExplorerFeatureItem(parent, display=display) # default to instruction view for all other characteristics return CapaExplorerInstructionViewItem(parent, display, location) if feature["type"] == "match": # display content of rule for all rule matches return CapaExplorerRuleMatchItem(parent, display, source=doc["rules"].get( feature[feature["type"]], {}).get("source", "")) if feature["type"] == "regex": return CapaExplorerFeatureItem(parent, display, location, details=feature["match"]) if feature["type"] == "basicblock": return CapaExplorerBlockItem(parent, location) if feature["type"] in ( "bytes", "api", "mnemonic", "number", "offset", "number/x32", "number/x64", "offset/x32", "offset/x64", ): # display instruction preview return CapaExplorerInstructionViewItem(parent, display, location) if feature["type"] in ("section", ): # display byte preview return CapaExplorerByteViewItem(parent, display, location) if feature["type"] in ("string", ): # display string preview return CapaExplorerStringViewItem(parent, display, location) if feature["type"] in ("import", "export"): # display no preview return CapaExplorerFeatureItem(parent, display=display) raise RuntimeError("unexpected feature type: " + str(feature["type"]))
def render_capa_doc_feature(self, parent, feature, location, doc, display="-"): """render capa feature read from doc @param parent: parent node to which new child is assigned @param feature: feature read from doc @param doc: capa feature doc @param location: address of feature @param display: text to display in plugin UI """ # special handling for characteristic pending type if feature["type"] == "characteristic": if feature[feature["type"]] in ("embedded pe", ): return CapaExplorerByteViewItem(parent, display, location) if feature[feature["type"]] in ("loop", "recursive call", "tight loop"): return CapaExplorerFeatureItem(parent, display=display) # default to instruction view for all other characteristics return CapaExplorerInstructionViewItem(parent, display, location) if feature["type"] == "match": # display content of rule for all rule matches return CapaExplorerRuleMatchItem(parent, display, source=doc["rules"].get( feature[feature["type"]], {}).get("source", "")) if feature["type"] in ("regex", "substring"): for s, locations in feature["matches"].items(): if location in locations: return CapaExplorerStringViewItem( parent, display, location, '"' + capa.features.common.escape_string(s) + '"') # programming error: the given location should always be found in the regex matches raise ValueError("regex match at location not found") if feature["type"] == "basicblock": return CapaExplorerBlockItem(parent, location) if feature["type"] in ( "bytes", "api", "mnemonic", "number", "offset", ): # display instruction preview return CapaExplorerInstructionViewItem(parent, display, location) if feature["type"] in ("section", ): # display byte preview return CapaExplorerByteViewItem(parent, display, location) if feature["type"] in ("string", ): # display string preview return CapaExplorerStringViewItem( parent, display, location, '"%s"' % capa.features.common.escape_string(feature[feature["type"]])) if feature["type"] in ("import", "export", "function-name"): # display no preview return CapaExplorerFeatureItem(parent, location=location, display=display) if feature["type"] in ("arch", "os", "format"): return CapaExplorerFeatureItem(parent, display=display) raise RuntimeError("unexpected feature type: " + str(feature["type"]))