diff --git a/capa/features/extractors/cape/global_.py b/capa/features/extractors/cape/global_.py index 83cb62728..62eeff204 100644 --- a/capa/features/extractors/cape/global_.py +++ b/capa/features/extractors/cape/global_.py @@ -12,14 +12,12 @@ from capa.features.common import ( OS, OS_ANY, - ARCH_ANY, OS_LINUX, ARCH_I386, FORMAT_PE, ARCH_AMD64, FORMAT_ELF, OS_WINDOWS, - FORMAT_UNKNOWN, Arch, Format, Feature, diff --git a/capa/main.py b/capa/main.py index fe6f78b2a..3a753cf8e 100644 --- a/capa/main.py +++ b/capa/main.py @@ -1007,13 +1007,13 @@ def collect_metadata( os_ = get_os(sample_path) if os_ == OS_AUTO else os_ if isinstance(extractor, StaticFeatureExtractor): - flavor = rdoc.Flavor.STATIC + meta_class: type = rdoc.StaticMetadata elif isinstance(extractor, DynamicFeatureExtractor): - flavor = rdoc.Flavor.DYNAMIC + meta_class = rdoc.DynamicMetadata else: assert_never(extractor) - return rdoc.Metadata( + return meta_class( timestamp=datetime.datetime.now(), version=capa.version.__version__, argv=tuple(argv) if argv else None, @@ -1023,7 +1023,6 @@ def collect_metadata( sha256=sha256, path=Path(sample_path).resolve().as_posix(), ), - flavor=flavor, analysis=get_sample_analysis( format_, arch, diff --git a/capa/render/result_document.py b/capa/render/result_document.py index 87790e53e..11066d0b9 100644 --- a/capa/render/result_document.py +++ b/capa/render/result_document.py @@ -136,6 +136,16 @@ class Metadata(Model): analysis: Analysis +class StaticMetadata(Metadata): + flavor: Flavor = Flavor.STATIC + analysis: StaticAnalysis + + +class DynamicMetadata(Metadata): + flavor: Flavor = Flavor.DYNAMIC + analysis: DynamicAnalysis + + class CompoundStatementType: AND = "and" OR = "or" diff --git a/capa/render/verbose.py b/capa/render/verbose.py index ae353855a..f8aa95b25 100644 --- a/capa/render/verbose.py +++ b/capa/render/verbose.py @@ -23,6 +23,7 @@ See the License for the specific language governing permissions and limitations under the License. """ import enum +from typing import cast import tabulate @@ -75,7 +76,7 @@ def format_address(address: frz.Address) -> str: raise ValueError("unexpected address type") -def render_static_meta(ostream, meta: rd.Metadata): +def render_static_meta(ostream, meta: rd.StaticMetadata): """ like: @@ -96,7 +97,6 @@ def render_static_meta(ostream, meta: rd.Metadata): total feature count 1918 """ - assert isinstance(meta.analysis, rd.StaticAnalysis) rows = [ ("md5", meta.sample.md5), ("sha1", meta.sample.sha1), @@ -122,7 +122,7 @@ def render_static_meta(ostream, meta: rd.Metadata): ostream.writeln(tabulate.tabulate(rows, tablefmt="plain")) -def render_dynamic_meta(ostream, meta: rd.Metadata): +def render_dynamic_meta(ostream, meta: rd.DynamicMetadata): """ like: @@ -141,7 +141,6 @@ def render_dynamic_meta(ostream, meta: rd.Metadata): total feature count 1918 """ - assert isinstance(meta.analysis, rd.DynamicAnalysis) rows = [ ("md5", meta.sample.md5), ("sha1", meta.sample.sha1), @@ -166,10 +165,10 @@ def render_dynamic_meta(ostream, meta: rd.Metadata): def render_meta(osstream, doc: rd.ResultDocument): - if isinstance(doc.meta.analysis, rd.StaticAnalysis): - render_static_meta(osstream, doc.meta) - elif isinstance(doc.meta.analysis, rd.DynamicAnalysis): - render_dynamic_meta(osstream, doc.meta) + if doc.meta.flavor is rd.Flavor.STATIC: + render_static_meta(osstream, cast(rd.StaticMetadata, doc.meta)) + elif doc.meta.flavor is rd.Flavor.DYNAMIC: + render_dynamic_meta(osstream, cast(rd.DynamicMetadata, doc.meta)) else: raise ValueError("invalid meta analysis") diff --git a/scripts/profile-time.py b/scripts/profile-time.py index db9a99fe3..9acd60ff4 100644 --- a/scripts/profile-time.py +++ b/scripts/profile-time.py @@ -54,7 +54,6 @@ import capa.features import capa.features.common import capa.features.freeze -from capa.features.extractors.base_extractor import FeatureExtractor, StaticFeatureExtractor logger = logging.getLogger("capa.profile") diff --git a/tests/test_dynamic_freeze.py b/tests/test_dynamic_freeze.py new file mode 100644 index 000000000..e69de29bb