result document: wire analysis flavor through metadata

ref #1711
This commit is contained in:
Willi Ballenthin
2023-08-11 09:33:30 +00:00
committed by GitHub
parent f48e4a8ad8
commit c91dc71e75
7 changed files with 3708 additions and 125 deletions

View File

@@ -153,6 +153,7 @@ def collect_metadata(rules: List[Path]):
sha256=sha256,
path=idaapi.get_input_file_path(),
),
flavor="static",
analysis=rdoc.StaticAnalysis(
format=idaapi.get_file_type_name(),
arch=arch,

View File

@@ -21,7 +21,7 @@ import itertools
import contextlib
import collections
from enum import Enum
from typing import Any, Dict, List, Tuple, Callable, Optional
from typing import Any, Dict, List, Tuple, Literal, Callable, Optional
from pathlib import Path
import halo
@@ -29,6 +29,7 @@ import tqdm
import colorama
import tqdm.contrib.logging
from pefile import PEFormatError
from typing_extensions import assert_never
from elftools.common.exceptions import ELFError
import capa.perf
@@ -1022,6 +1023,14 @@ def collect_metadata(
arch = get_arch(sample_path)
os_ = get_os(sample_path) if os_ == OS_AUTO else os_
flavor: Literal["static", "dynamic"]
if isinstance(extractor, StaticFeatureExtractor):
flavor = "static"
elif isinstance(extractor, DynamicFeatureExtractor):
flavor = "dynamic"
else:
assert_never(extractor)
return rdoc.Metadata(
timestamp=datetime.datetime.now(),
version=capa.version.__version__,
@@ -1032,6 +1041,7 @@ def collect_metadata(
sha256=sha256,
path=str(Path(sample_path).resolve()),
),
flavor=flavor,
analysis=get_sample_analysis(
format_,
arch,

View File

@@ -25,7 +25,7 @@ $ protoc.exe --python_out=. --mypy_out=. <path_to_proto> (e.g. capa/render/proto
Alternatively, --pyi_out=. can be used to generate a Python Interface file that supports development
"""
import datetime
from typing import Any, Dict, Union
from typing import Any, Dict, Union, Literal
import google.protobuf.json_format
@@ -128,6 +128,7 @@ def metadata_to_pb2(meta: rd.Metadata) -> capa_pb2.Metadata:
version=meta.version,
argv=meta.argv,
sample=google.protobuf.json_format.ParseDict(meta.sample.model_dump(), capa_pb2.Sample()),
flavor=meta.flavor,
analysis=capa_pb2.Analysis(
format=meta.analysis.format,
arch=meta.analysis.arch,
@@ -480,6 +481,11 @@ def scope_from_pb2(scope: capa_pb2.Scope.ValueType) -> capa.rules.Scope:
assert_never(scope)
def flavor_from_pb2(flavor: str) -> Literal["static", "dynamic"]:
assert flavor in ("static", "dynamic")
return flavor # type: ignore
def metadata_from_pb2(meta: capa_pb2.Metadata) -> rd.Metadata:
return rd.Metadata(
timestamp=datetime.datetime.fromisoformat(meta.timestamp),
@@ -491,6 +497,7 @@ def metadata_from_pb2(meta: capa_pb2.Metadata) -> rd.Metadata:
sha256=meta.sample.sha256,
path=meta.sample.path,
),
flavor=flavor_from_pb2(meta.flavor),
analysis=rd.StaticAnalysis(
format=meta.analysis.format,
arch=meta.analysis.arch,

View File

@@ -198,6 +198,7 @@ message Metadata {
repeated string argv = 3;
Sample sample = 4;
Analysis analysis = 5;
string flavor = 6;
}
message MnemonicFeature {

File diff suppressed because one or more lines are too long

View File

@@ -776,6 +776,7 @@ class Metadata(google.protobuf.message.Message):
ARGV_FIELD_NUMBER: builtins.int
SAMPLE_FIELD_NUMBER: builtins.int
ANALYSIS_FIELD_NUMBER: builtins.int
FLAVOR_FIELD_NUMBER: builtins.int
timestamp: builtins.str
"""iso8601 format, like: 2019-01-01T00:00:00Z"""
version: builtins.str
@@ -785,6 +786,7 @@ class Metadata(google.protobuf.message.Message):
def sample(self) -> global___Sample: ...
@property
def analysis(self) -> global___Analysis: ...
flavor: builtins.str
def __init__(
self,
*,
@@ -793,9 +795,10 @@ class Metadata(google.protobuf.message.Message):
argv: collections.abc.Iterable[builtins.str] | None = ...,
sample: global___Sample | None = ...,
analysis: global___Analysis | None = ...,
flavor: builtins.str = ...,
) -> None: ...
def HasField(self, field_name: typing_extensions.Literal["analysis", b"analysis", "sample", b"sample"]) -> builtins.bool: ...
def ClearField(self, field_name: typing_extensions.Literal["analysis", b"analysis", "argv", b"argv", "sample", b"sample", "timestamp", b"timestamp", "version", b"version"]) -> None: ...
def ClearField(self, field_name: typing_extensions.Literal["analysis", b"analysis", "argv", b"argv", "flavor", b"flavor", "sample", b"sample", "timestamp", b"timestamp", "version", b"version"]) -> None: ...
global___Metadata = Metadata

View File

@@ -125,6 +125,7 @@ class Metadata(Model):
version: str
argv: Optional[Tuple[str, ...]]
sample: Sample
flavor: Literal["static", "dynamic"]
analysis: Analysis