def render_statement(ostream, match, statement, indent=0): ostream.write(" " * indent) if statement["type"] in ("and", "or", "optional", "not", "subscope"): if statement["type"] == "subscope": # emit `basic block:` # rather than `subscope:` ostream.write(statement["subscope"]) else: # emit `and:` ostream.write(statement["type"]) ostream.write(":") if statement.get("description"): ostream.write(" = %s" % statement["description"]) ostream.writeln("") elif statement["type"] == "some": ostream.write("%d or more:" % (statement["count"])) if statement.get("description"): ostream.write(" = %s" % statement["description"]) ostream.writeln("") 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. child = statement["child"] if child[child["type"]]: if child["type"] == "string": value = '"%s"' % capa.features.common.escape_string( child[child["type"]]) else: value = child[child["type"]] value = rutils.bold2(value) 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): " % child["type"]) if statement["max"] == statement["min"]: ostream.write("%d" % (statement["min"])) elif statement["min"] == 0: ostream.write("%d or fewer" % (statement["max"])) elif statement["max"] == (1 << 64 - 1): ostream.write("%d or more" % (statement["min"])) else: ostream.write("between %d and %d" % (statement["min"], statement["max"])) if statement.get("description"): ostream.write(" = %s" % statement["description"]) render_locations(ostream, match) ostream.writeln("") else: raise RuntimeError("unexpected match statement type: " + str(statement))
def render_feature(ostream, match, feature, indent=0): ostream.write(" " * indent) key = feature["type"] value = feature[feature["type"]] if key not in ("regex", "substring"): # like: # number: 10 = SOME_CONSTANT @ 0x401000 if key == "string": value = render_string_value(value) ostream.write(key) ostream.write(": ") if value: ostream.write(rutils.bold2(value)) if "description" in feature: ostream.write(capa.rules.DESCRIPTION_SEPARATOR) ostream.write(feature["description"]) if key not in ("os", "arch"): render_locations(ostream, match) ostream.write("\n") else: # like: # regex: /blah/ = SOME_CONSTANT # - "foo blah baz" @ 0x401000 # - "aaa blah bbb" @ 0x402000, 0x403400 ostream.write(key) ostream.write(": ") ostream.write(value) ostream.write("\n") for match, locations in sorted(feature["matches"].items(), key=lambda p: p[0]): ostream.write(" " * (indent + 1)) ostream.write("- ") ostream.write(rutils.bold2(render_string_value(match))) render_locations(ostream, {"locations": locations}) ostream.write("\n")
def render_statement(ostream, match, statement, indent=0): ostream.write(" " * indent) if statement["type"] in ("and", "or", "optional"): ostream.write(statement["type"]) ostream.writeln(":") elif statement["type"] == "not": # this statement is handled specially in `render_match` using the MODE_SUCCESS/MODE_FAILURE flags. ostream.writeln("not:") elif statement["type"] == "some": ostream.write(statement["count"] + " or more") ostream.writeln(":") 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. child = statement["child"] 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): " % child["type"]) if statement["max"] == statement["min"]: ostream.write("%d" % (statement["min"])) elif statement["min"] == 0: ostream.write("%d or fewer" % (statement["max"])) elif statement["max"] == (1 << 64 - 1): ostream.write("%d or more" % (statement["min"])) else: ostream.write("between %d and %d" % (statement["min"], statement["max"])) render_locations(ostream, match) ostream.write("\n") elif statement["type"] == "subscope": ostream.write(statement["subscope"]) ostream.writeln(":") else: raise RuntimeError("unexpected match statement type: " + str(statement))
def render_feature(ostream, match, feature, indent=0): ostream.write(" " * indent) key = feature["type"] value = feature[feature["type"]] if key == "regex": key = "string" # render string for regex to mirror the rule source value = feature["match"] # the match provides more information than the value for regex ostream.write(key) ostream.write(": ") if value: ostream.write(rutils.bold2(value)) if "description" in feature: ostream.write(capa.rules.DESCRIPTION_SEPARATOR) ostream.write(feature["description"]) render_locations(ostream, match) ostream.write("\n")