diff --git a/CHANGELOG.md b/CHANGELOG.md index b4f2bf86..15d56672 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - add new feature "operand[{0, 1, 2}].offset" for matching instruction operand offsets #767 @williballenthin - extract additional offset/number features in certain circumstances #320 @williballenthin - add detection and basic feature extraction for dotnet #987 @mr-tz, @mike-hunhoff, @williballenthin + - add file string extraction for dotnet files #1012 @mike-hunhoff ### Breaking Changes diff --git a/capa/features/extractors/dnfile/file.py b/capa/features/extractors/dnfile/file.py index 99e2643c..f0af0085 100644 --- a/capa/features/extractors/dnfile/file.py +++ b/capa/features/extractors/dnfile/file.py @@ -12,7 +12,7 @@ from typing import TYPE_CHECKING, Tuple, Iterator if TYPE_CHECKING: import dnfile - from capa.features.common import Feature, Format + from capa.features.common import Feature, Format, String from capa.features.file import Import import capa.features.extractors @@ -26,6 +26,10 @@ def extract_file_format(pe: dnfile.dnPE) -> Iterator[Tuple[Format, int]]: yield from capa.features.extractors.dotnetfile.extract_file_format(pe=pe) +def extract_file_strings(pe: dnfile.dnPE) -> Iterator[Tuple[String, int]]: + yield from capa.features.extractors.dotnetfile.extract_file_strings(pe=pe) + + def extract_features(pe: dnfile.dnPE) -> Iterator[Tuple[Feature, int]]: for file_handler in FILE_HANDLERS: for (feature, token) in file_handler(pe): @@ -34,7 +38,7 @@ def extract_features(pe: dnfile.dnPE) -> Iterator[Tuple[Feature, int]]: FILE_HANDLERS = ( extract_file_import_names, - # TODO extract_file_strings, + extract_file_strings, # TODO extract_file_function_names, extract_file_format, ) diff --git a/capa/features/extractors/dotnetfile.py b/capa/features/extractors/dotnetfile.py index a9a2c600..07a88147 100644 --- a/capa/features/extractors/dotnetfile.py +++ b/capa/features/extractors/dotnetfile.py @@ -7,7 +7,18 @@ import pefile import capa.features.extractors.helpers from capa.features.file import Import -from capa.features.common import OS, OS_ANY, ARCH_ANY, ARCH_I386, ARCH_AMD64, FORMAT_DOTNET, Arch, Format, Feature +from capa.features.common import ( + OS, + OS_ANY, + ARCH_ANY, + ARCH_I386, + ARCH_AMD64, + FORMAT_DOTNET, + Arch, + Format, + String, + Feature, +) from capa.features.extractors.base_extractor import FeatureExtractor from capa.features.extractors.dnfile.helpers import get_dotnet_managed_imports, get_dotnet_unmanaged_imports @@ -45,6 +56,10 @@ def extract_file_arch(pe: dnfile.dnPE, **kwargs) -> Iterator[Tuple[Arch, int]]: yield Arch(ARCH_ANY), 0x0 +def extract_file_strings(pe: dnfile.dnPE, **kwargs) -> Iterator[Tuple[String, int]]: + yield from capa.features.extractors.common.extract_file_strings(pe.__data__) + + def extract_file_features(pe: dnfile.dnPE) -> Iterator[Tuple[Feature, int]]: for file_handler in FILE_HANDLERS: for feature, va in file_handler(pe=pe): # type: ignore @@ -53,7 +68,7 @@ def extract_file_features(pe: dnfile.dnPE) -> Iterator[Tuple[Feature, int]]: FILE_HANDLERS = ( extract_file_import_names, - # TODO extract_file_strings, + extract_file_strings, # TODO extract_file_function_names, extract_file_format, ) diff --git a/tests/fixtures.py b/tests/fixtures.py index 7f5abc73..af56cb40 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -671,10 +671,13 @@ FEATURE_PRESENCE_TESTS_DOTNET = sorted( ("mixed-mode-64", "file", Arch(ARCH_I386), False), ("b9f5b", "file", OS(OS_ANY), True), ("b9f5b", "file", Format(FORMAT_DOTNET), True), + ("hello-world", "file", capa.features.common.String("Hello World!"), True), ("hello-world", "function=0x250", capa.features.common.String("Hello World!"), True), ("hello-world", "function=0x250, bb=0x250, insn=0x252", capa.features.common.String("Hello World!"), True), ("hello-world", "function=0x250", capa.features.insn.API("System.Console::WriteLine"), True), ("hello-world", "file", capa.features.file.Import("System.Console::WriteLine"), True), + ("_1c444", "file", capa.features.common.String(r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"), True), + ("_1c444", "file", capa.features.common.String("get_IsAlive"), True), ("_1c444", "file", capa.features.file.Import("gdi32.CreateCompatibleBitmap"), True), ("_1c444", "file", capa.features.file.Import("CreateCompatibleBitmap"), True), ("_1c444", "file", capa.features.file.Import("gdi32::CreateCompatibleBitmap"), False),