diff --git a/capa/features/extractors/common.py b/capa/features/extractors/common.py index 0d68247c..0981f547 100644 --- a/capa/features/extractors/common.py +++ b/capa/features/extractors/common.py @@ -12,8 +12,6 @@ import capa.features.extractors.pefile from capa.features.common import OS, FORMAT_PE, FORMAT_ELF, OS_WINDOWS, FORMAT_FREEZE, Arch, Format, String, Feature from capa.features.freeze import is_freeze from capa.features.address import NO_ADDRESS, Address, FileOffsetAddress -from capa.features.common import OS, FORMAT_PE, FORMAT_ELF, OS_WINDOWS, FORMAT_FREEZE, Arch, Format, String -from capa.features.freeze import is_freeze logger = logging.getLogger(__name__) diff --git a/capa/features/extractors/dnfile/file.py b/capa/features/extractors/dnfile/file.py index 99e2643c..eac653d6 100644 --- a/capa/features/extractors/dnfile/file.py +++ b/capa/features/extractors/dnfile/file.py @@ -14,22 +14,23 @@ if TYPE_CHECKING: import dnfile from capa.features.common import Feature, Format from capa.features.file import Import + from capa.features.address import Address import capa.features.extractors -def extract_file_import_names(pe: dnfile.dnPE) -> Iterator[Tuple[Import, int]]: +def extract_file_import_names(pe: dnfile.dnPE) -> Iterator[Tuple[Import, Address]]: yield from capa.features.extractors.dotnetfile.extract_file_import_names(pe) -def extract_file_format(pe: dnfile.dnPE) -> Iterator[Tuple[Format, int]]: +def extract_file_format(pe: dnfile.dnPE) -> Iterator[Tuple[Format, Address]]: yield from capa.features.extractors.dotnetfile.extract_file_format(pe=pe) -def extract_features(pe: dnfile.dnPE) -> Iterator[Tuple[Feature, int]]: +def extract_features(pe: dnfile.dnPE) -> Iterator[Tuple[Feature, Address]]: for file_handler in FILE_HANDLERS: - for (feature, token) in file_handler(pe): - yield feature, token + for (feature, address) in file_handler(pe): + yield feature, address FILE_HANDLERS = ( diff --git a/capa/features/extractors/dnfile/helpers.py b/capa/features/extractors/dnfile/helpers.py index c7304462..ac9b0bb9 100644 --- a/capa/features/extractors/dnfile/helpers.py +++ b/capa/features/extractors/dnfile/helpers.py @@ -152,12 +152,12 @@ def get_dotnet_unmanaged_imports(pe: dnfile.dnPE) -> Iterator[Tuple[int, str]]: yield token, imp -def get_dotnet_managed_method_bodies(pe: dnfile.dnPE) -> Iterator[CilMethodBody]: +def get_dotnet_managed_method_bodies(pe: dnfile.dnPE) -> Iterator[Tuple[int, CilMethodBody]]: """get managed methods from MethodDef table""" if not hasattr(pe.net.mdtables, "MethodDef"): return - for row in pe.net.mdtables.MethodDef: + for (rid, row) in enumerate(pe.net.mdtables.MethodDef): if not row.ImplFlags.miIL or any((row.Flags.mdAbstract, row.Flags.mdPinvokeImpl)): # skip methods that do not have a method body continue @@ -166,4 +166,5 @@ def get_dotnet_managed_method_bodies(pe: dnfile.dnPE) -> Iterator[CilMethodBody] if body is None: continue - yield body + token: int = calculate_dotnet_token_value(dnfile.enums.MetadataTables.MethodDef.value, rid + 1) + yield token, body diff --git a/capa/features/extractors/dnfile_.py b/capa/features/extractors/dnfile_.py index 9921f8a1..7a459bec 100644 --- a/capa/features/extractors/dnfile_.py +++ b/capa/features/extractors/dnfile_.py @@ -11,15 +11,15 @@ from capa.features.extractors.base_extractor import FeatureExtractor logger = logging.getLogger(__name__) -def extract_file_format(**kwargs): +def extract_file_format(**kwargs) -> Iterator[Tuple[Feature, Address]]: yield Format(FORMAT_DOTNET), NO_ADDRESS -def extract_file_os(**kwargs): +def extract_file_os(**kwargs) -> Iterator[Tuple[Feature, Address]]: yield OS(OS_ANY), NO_ADDRESS -def extract_file_arch(pe, **kwargs): +def extract_file_arch(pe, **kwargs) -> Iterator[Tuple[Feature, Address]]: # to distinguish in more detail, see https://stackoverflow.com/a/23614024/10548020 # .NET 4.5 added option: any CPU, 32-bit preferred if pe.net.Flags.CLR_32BITREQUIRED and pe.PE_TYPE == pefile.OPTIONAL_HEADER_MAGIC_PE: diff --git a/capa/features/extractors/ida/insn.py b/capa/features/extractors/ida/insn.py index 28bd35c0..b75e6c3a 100644 --- a/capa/features/extractors/ida/insn.py +++ b/capa/features/extractors/ida/insn.py @@ -12,8 +12,6 @@ import idautils import capa.features.extractors.helpers import capa.features.extractors.ida.helpers -from capa.features.insn import API, Number, Offset, Mnemonic, OperandNumber, OperandOffset -from capa.features.common import MAX_BYTES_FEATURE_SIZE, THUNK_CHAIN_DEPTH_DELTA, Bytes, String, Characteristic from capa.features.insn import API, MAX_STRUCTURE_SIZE, Number, Offset, Mnemonic, OperandNumber, OperandOffset from capa.features.common import MAX_BYTES_FEATURE_SIZE, THUNK_CHAIN_DEPTH_DELTA, Bytes, String, Characteristic diff --git a/capa/features/extractors/smda/basicblock.py b/capa/features/extractors/smda/basicblock.py index 4f277379..f59a1a4a 100644 --- a/capa/features/extractors/smda/basicblock.py +++ b/capa/features/extractors/smda/basicblock.py @@ -3,7 +3,7 @@ import struct from typing import Tuple, Iterator from capa.features.common import Feature, Characteristic -from capa.features.address import Address, AbsoluteVirtualAddress +from capa.features.address import Address from capa.features.basicblock import BasicBlock from capa.features.extractors.helpers import MIN_STACKSTRING_LEN from capa.features.extractors.base_extractor import BBHandle, FunctionHandle diff --git a/capa/features/extractors/smda/insn.py b/capa/features/extractors/smda/insn.py index f0492896..4b4054a5 100644 --- a/capa/features/extractors/smda/insn.py +++ b/capa/features/extractors/smda/insn.py @@ -10,8 +10,6 @@ from capa.features.insn import API, MAX_STRUCTURE_SIZE, Number, Offset, Mnemonic from capa.features.common import MAX_BYTES_FEATURE_SIZE, THUNK_CHAIN_DEPTH_DELTA, Bytes, String, Feature, Characteristic from capa.features.address import Address, AbsoluteVirtualAddress from capa.features.extractors.base_extractor import BBHandle, InsnHandle, FunctionHandle -from capa.features.insn import API, MAX_STRUCTURE_SIZE, Number, Offset, Mnemonic, OperandNumber, OperandOffset -from capa.features.common import MAX_BYTES_FEATURE_SIZE, THUNK_CHAIN_DEPTH_DELTA, Bytes, String, Characteristic # security cookie checks may perform non-zeroing XORs, these are expected within a certain # byte range within the first and returning basic blocks, this helps to reduce FP features diff --git a/capa/features/extractors/viv/insn.py b/capa/features/extractors/viv/insn.py index b92c5cc3..cf9923a5 100644 --- a/capa/features/extractors/viv/insn.py +++ b/capa/features/extractors/viv/insn.py @@ -19,26 +19,10 @@ import envi.archs.amd64.disasm import capa.features.extractors.helpers import capa.features.extractors.viv.helpers -<<<<<<< HEAD from capa.features.insn import API, MAX_STRUCTURE_SIZE, Number, Offset, Mnemonic, OperandNumber, OperandOffset from capa.features.common import MAX_BYTES_FEATURE_SIZE, THUNK_CHAIN_DEPTH_DELTA, Bytes, String, Feature, Characteristic from capa.features.address import Address, AbsoluteVirtualAddress from capa.features.extractors.base_extractor import BBHandle, InsnHandle, FunctionHandle -||||||| de312d8 -from capa.features.insn import API, Number, Offset, Mnemonic, OperandNumber, OperandOffset -from capa.features.common import ( - BITNESS_X32, - BITNESS_X64, - MAX_BYTES_FEATURE_SIZE, - THUNK_CHAIN_DEPTH_DELTA, - Bytes, - String, - Characteristic, -) -======= -from capa.features.insn import API, MAX_STRUCTURE_SIZE, Number, Offset, Mnemonic, OperandNumber, OperandOffset -from capa.features.common import MAX_BYTES_FEATURE_SIZE, THUNK_CHAIN_DEPTH_DELTA, Bytes, String, Characteristic ->>>>>>> 580a2d7e4519ea5d353650d66468020968f0f27d from capa.features.extractors.viv.indirect_calls import NotFoundError, resolve_indirect_call # security cookie checks may perform non-zeroing XORs, these are expected within a certain @@ -46,23 +30,7 @@ from capa.features.extractors.viv.indirect_calls import NotFoundError, resolve_i SECURITY_COOKIE_BYTES_DELTA = 0x40 -<<<<<<< HEAD -def interface_extract_instruction_XXX( - f: FunctionHandle, bb: BBHandle, insn: InsnHandle -) -> Iterator[Tuple[Feature, Address]]: -||||||| de312d8 -def get_bitness(vw): - bitness = vw.getMeta("Architecture") - if bitness == "i386": - return BITNESS_X32 - elif bitness == "amd64": - return BITNESS_X64 - - def interface_extract_instruction_XXX(f, bb, insn): -======= -def interface_extract_instruction_XXX(f, bb, insn): ->>>>>>> 580a2d7e4519ea5d353650d66468020968f0f27d """ parse features from the given instruction. diff --git a/capa/main.py b/capa/main.py index 8fae7f84..8e98b3ae 100644 --- a/capa/main.py +++ b/capa/main.py @@ -65,24 +65,6 @@ from capa.features.common import ( FORMAT_FREEZE, ) from capa.features.address import NO_ADDRESS -from capa.helpers import ( - get_format, - get_file_taste, - get_auto_format, - log_unsupported_os_error, - log_unsupported_arch_error, - log_unsupported_format_error, -) -from capa.exceptions import UnsupportedOSError, UnsupportedArchError, UnsupportedFormatError, UnsupportedRuntimeError -from capa.features.common import ( - FORMAT_PE, - FORMAT_ELF, - FORMAT_AUTO, - FORMAT_SC32, - FORMAT_SC64, - FORMAT_DOTNET, - FORMAT_FREEZE, -) from capa.features.extractors.base_extractor import BBHandle, InsnHandle, FunctionHandle, FeatureExtractor RULES_PATH_DEFAULT_STRING = "(embedded rules)" diff --git a/tests/fixtures.py b/tests/fixtures.py index 7f5abc73..09b8494a 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -325,21 +325,21 @@ def sample(request): def get_function(extractor, fva): for f in extractor.get_functions(): - if int(f) == fva: + if str(f) == fva: return f raise ValueError("function not found") def get_basic_block(extractor, f, va): for bb in extractor.get_basic_blocks(f): - if int(bb) == va: + if str(bb) == va: return bb raise ValueError("basic block not found") def get_instruction(extractor, f, bb, va): for insn in extractor.get_instructions(f, bb): - if int(insn) == va: + if str(insn) == va: return insn raise ValueError("instruction not found") @@ -824,10 +824,10 @@ def mixed_mode_64_dotnetfile_extractor(): @pytest.fixture -def hello_world_dnfile_extractor(): +def hello_world_dotnetfile_extractor(): return get_dnfile_extractor(get_data_path_by_name("hello-world")) @pytest.fixture -def _1c444_dnfile_extractor(): +def _1c444_dotnetfile_extractor(): return get_dnfile_extractor(get_data_path_by_name("1c444...")) diff --git a/tests/test_dotnet_features.py b/tests/test_dotnet_features.py index b6714419..9980a730 100644 --- a/tests/test_dotnet_features.py +++ b/tests/test_dotnet_features.py @@ -24,12 +24,12 @@ def test_dnfile_features(sample, scope, feature, expected): @parametrize( "extractor,function,expected", [ - ("b9f5b_dnfile_extractor", "is_dotnet_file", True), - ("b9f5b_dnfile_extractor", "is_mixed_mode", False), - ("mixed_mode_64_dnfile_extractor", "is_mixed_mode", True), - ("b9f5b_dnfile_extractor", "get_entry_point", 0x6000007), - ("b9f5b_dnfile_extractor", "get_runtime_version", (2, 5)), - ("b9f5b_dnfile_extractor", "get_meta_version_string", "v2.0.50727"), + ("b9f5b_dotnetfile_extractor", "is_dotnet_file", True), + ("b9f5b_dotnetfile_extractor", "is_mixed_mode", False), + ("mixed_mode_64_dotnetfile_extractor", "is_mixed_mode", True), + ("b9f5b_dotnetfile_extractor", "get_entry_point", 0x6000007), + ("b9f5b_dotnetfile_extractor", "get_runtime_version", (2, 5)), + ("b9f5b_dotnetfile_extractor", "get_meta_version_string", "v2.0.50727"), ], ) def test_dnfile_extractor(request, extractor, function, expected):