Files
capa/capa/render/verbose.py
2021-06-09 18:06:51 -06:00

129 lines
4.4 KiB
Python

"""
example::
send data
namespace communication
author william.ballenthin@fireeye.com
description all known techniques for sending data to a potential C2 server
scope function
examples BFB9B5391A13D0AFD787E87AB90F14F5:0x13145D60
matches 0x10004363
0x100046c9
0x1000454e
0x10003a13
0x10003415
0x10003797
Copyright (C) 2020 FireEye, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at: [package root]/LICENSE.txt
Unless required by applicable law or agreed to in writing, software distributed under the License
is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
"""
import tabulate
import capa.rules
import capa.render.utils as rutils
import capa.render.result_document
def render_meta(ostream, doc):
"""
like:
md5 84882c9d43e23d63b82004fae74ebb61
sha1 c6fb3b50d946bec6f391aefa4e54478cf8607211
sha256 5eced7367ed63354b4ed5c556e2363514293f614c2c2eb187273381b2ef5f0f9
path /tmp/suspicious.dll_
timestamp 2020-07-03T10:17:05.796933
capa version 0.0.0
format auto
extractor VivisectFeatureExtractor
base address 0x10000000
rules (embedded rules)
function count 42
total feature count 1918
"""
rows = [
("md5", doc["meta"]["sample"]["md5"]),
("sha1", doc["meta"]["sample"]["sha1"]),
("sha256", doc["meta"]["sample"]["sha256"]),
("path", doc["meta"]["sample"]["path"]),
("timestamp", doc["meta"]["timestamp"]),
("capa version", doc["meta"]["version"]),
("format", doc["meta"]["analysis"]["format"]),
("extractor", doc["meta"]["analysis"]["extractor"]),
("base address", hex(doc["meta"]["analysis"]["base_address"])),
("rules", doc["meta"]["analysis"]["rules"]),
("function count", len(doc["meta"]["analysis"]["feature_counts"]["functions"])),
("library function count", len(doc["meta"]["analysis"]["library_functions"])),
(
"total feature count",
doc["meta"]["analysis"]["feature_counts"]["file"]
+ sum(doc["meta"]["analysis"]["feature_counts"]["functions"].values()),
),
]
ostream.writeln(tabulate.tabulate(rows, tablefmt="plain"))
def render_rules(ostream, doc):
"""
like:
receive data (2 matches)
namespace communication
description all known techniques for receiving data from a potential C2 server
scope function
matches 0x10003A13
0x10003797
"""
had_match = False
for rule in rutils.capability_rules(doc):
count = len(rule["matches"])
if count == 1:
capability = rutils.bold(rule["meta"]["name"])
else:
capability = "%s (%d matches)" % (rutils.bold(rule["meta"]["name"]), count)
ostream.writeln(capability)
had_match = True
rows = []
for key in ("namespace", "description", "scope"):
if key == "name" or key not in rule["meta"]:
continue
v = rule["meta"][key]
if isinstance(v, list) and len(v) == 1:
v = v[0]
rows.append((key, v))
if rule["meta"]["scope"] != capa.rules.FILE_SCOPE:
locations = doc["rules"][rule["meta"]["name"]]["matches"].keys()
rows.append(("matches", "\n".join(map(rutils.hex, locations))))
ostream.writeln(tabulate.tabulate(rows, tablefmt="plain"))
ostream.write("\n")
if not had_match:
ostream.writeln(rutils.bold("no capabilities found"))
def render_verbose(doc):
ostream = rutils.StringIO()
render_meta(ostream, doc)
ostream.write("\n")
render_rules(ostream, doc)
ostream.write("\n")
return ostream.getvalue()
def render(meta, rules, capabilities):
doc = capa.render.result_document.convert_capabilities_to_result_document(meta, rules, capabilities)
return render_verbose(doc)