mirror of
https://github.com/mandiant/capa.git
synced 2026-04-28 11:53:20 -07:00
tests: cleanup tests and fixtures
This commit is contained in:
@@ -16,20 +16,19 @@ from typing import Iterator
|
||||
|
||||
import idaapi
|
||||
|
||||
import capa.ida.helpers
|
||||
import capa.features.extractors.elf
|
||||
import capa.features.extractors.ida.file
|
||||
import capa.features.extractors.ida.insn
|
||||
import capa.features.extractors.ida.global_
|
||||
import capa.features.extractors.ida.function
|
||||
import capa.features.extractors.ida.basicblock
|
||||
import capa.features.extractors.ida.file
|
||||
import capa.features.extractors.ida.function
|
||||
import capa.features.extractors.ida.global_
|
||||
import capa.features.extractors.ida.insn
|
||||
import capa.ida.helpers
|
||||
from capa.features.address import AbsoluteVirtualAddress, Address
|
||||
from capa.features.common import Feature
|
||||
from capa.features.address import Address, AbsoluteVirtualAddress
|
||||
from capa.features.extractors.base_extractor import (
|
||||
BBHandle,
|
||||
FunctionHandle,
|
||||
InsnHandle,
|
||||
SampleHashes,
|
||||
FunctionHandle,
|
||||
StaticFeatureExtractor,
|
||||
)
|
||||
|
||||
@@ -44,7 +43,9 @@ class IdaFeatureExtractor(StaticFeatureExtractor):
|
||||
)
|
||||
)
|
||||
self.global_features: list[tuple[Feature, Address]] = []
|
||||
self.global_features.extend(capa.features.extractors.ida.file.extract_file_format())
|
||||
self.global_features.extend(
|
||||
capa.features.extractors.ida.file.extract_file_format()
|
||||
)
|
||||
self.global_features.extend(capa.features.extractors.ida.global_.extract_os())
|
||||
self.global_features.extend(capa.features.extractors.ida.global_.extract_arch())
|
||||
|
||||
@@ -68,7 +69,9 @@ class IdaFeatureExtractor(StaticFeatureExtractor):
|
||||
f = idaapi.get_func(ea)
|
||||
return FunctionHandle(address=AbsoluteVirtualAddress(f.start_ea), inner=f)
|
||||
|
||||
def extract_function_features(self, fh: FunctionHandle) -> Iterator[tuple[Feature, Address]]:
|
||||
def extract_function_features(
|
||||
self, fh: FunctionHandle
|
||||
) -> Iterator[tuple[Feature, Address]]:
|
||||
yield from capa.features.extractors.ida.function.extract_features(fh)
|
||||
|
||||
def get_basic_blocks(self, fh: FunctionHandle) -> Iterator[BBHandle]:
|
||||
@@ -77,13 +80,19 @@ class IdaFeatureExtractor(StaticFeatureExtractor):
|
||||
for bb in ida_helpers.get_function_blocks(fh.inner):
|
||||
yield BBHandle(address=AbsoluteVirtualAddress(bb.start_ea), inner=bb)
|
||||
|
||||
def extract_basic_block_features(self, fh: FunctionHandle, bbh: BBHandle) -> Iterator[tuple[Feature, Address]]:
|
||||
def extract_basic_block_features(
|
||||
self, fh: FunctionHandle, bbh: BBHandle
|
||||
) -> Iterator[tuple[Feature, Address]]:
|
||||
yield from capa.features.extractors.ida.basicblock.extract_features(fh, bbh)
|
||||
|
||||
def get_instructions(self, fh: FunctionHandle, bbh: BBHandle) -> Iterator[InsnHandle]:
|
||||
def get_instructions(
|
||||
self, fh: FunctionHandle, bbh: BBHandle
|
||||
) -> Iterator[InsnHandle]:
|
||||
import capa.features.extractors.ida.helpers as ida_helpers
|
||||
|
||||
for insn in ida_helpers.get_instructions_in_range(bbh.inner.start_ea, bbh.inner.end_ea):
|
||||
for insn in ida_helpers.get_instructions_in_range(
|
||||
bbh.inner.start_ea, bbh.inner.end_ea
|
||||
):
|
||||
yield InsnHandle(address=AbsoluteVirtualAddress(insn.ea), inner=insn)
|
||||
|
||||
def extract_insn_features(self, fh: FunctionHandle, bbh: BBHandle, ih: InsnHandle):
|
||||
|
||||
@@ -21,7 +21,3 @@
|
||||
# https://www.revsys.com/tidbits/pytest-fixtures-are-magic/
|
||||
# https://lobste.rs/s/j8xgym/pytest_fixtures_are_magic
|
||||
from fixtures import * # noqa: F403 [unable to detect undefined names]
|
||||
from fixtures import _692f_dotnetfile_extractor # noqa: F401 [imported but unused]
|
||||
from fixtures import _1c444_dotnetfile_extractor # noqa: F401 [imported but unused]
|
||||
from fixtures import _039a6_dotnetfile_extractor # noqa: F401 [imported but unused]
|
||||
from fixtures import _0953c_dotnetfile_extractor # noqa: F401 [imported but unused]
|
||||
|
||||
1322
tests/fixtures.py
1322
tests/fixtures.py
File diff suppressed because it is too large
Load Diff
17
tests/fixtures/features/README.md
vendored
17
tests/fixtures/features/README.md
vendored
@@ -126,16 +126,17 @@ For example:
|
||||
```python
|
||||
import fixtures
|
||||
|
||||
BACKEND = fixtures.BackendFeaturePolicy(
|
||||
name="viv",
|
||||
get_extractor=fixtures.get_viv_extractor,
|
||||
exclude_tags={"dotnet"},
|
||||
|
||||
@fixtures.parametrize_backend_feature_fixtures(
|
||||
fixtures.BackendFeaturePolicy(
|
||||
name="viv",
|
||||
include_tags={"static"},
|
||||
exclude_tags={"dotnet", "ghidra"},
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@fixtures.parametrize_backend_feature_fixtures(BACKEND)
|
||||
def test_viv_features(feature_fixture):
|
||||
fixtures.run_feature_fixture(BACKEND, feature_fixture)
|
||||
extractor = fixtures.get_viv_extractor(feature_fixture.sample_path)
|
||||
fixtures.run_feature_fixture(extractor, feature_fixture)
|
||||
```
|
||||
|
||||
Module-level availability checks are still allowed. runtime-specific hooks are allowed only when they depend on the installed backend or tool version and cannot be represented declaratively in the fixture manifests.
|
||||
|
||||
752
tests/fixtures/features/binexport.json
vendored
752
tests/fixtures/features/binexport.json
vendored
File diff suppressed because it is too large
Load Diff
805
tests/fixtures/features/static.json
vendored
805
tests/fixtures/features/static.json
vendored
File diff suppressed because it is too large
Load Diff
@@ -15,11 +15,13 @@
|
||||
|
||||
import re
|
||||
import logging
|
||||
from typing import Any
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
import fixtures
|
||||
|
||||
CD = Path(__file__).resolve().parent
|
||||
from google.protobuf.json_format import ParseDict
|
||||
|
||||
import capa.features.extractors.binexport2.helpers
|
||||
@@ -39,7 +41,6 @@ from capa.features.extractors.binexport2.arch.arm.helpers import is_stack_regist
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CD = Path(__file__).resolve().parent
|
||||
|
||||
|
||||
# found via https://www.virustotal.com/gui/search/type%253Aelf%2520and%2520size%253A1.2kb%252B%2520and%2520size%253A1.4kb-%2520and%2520tag%253Aarm%2520and%2520not%2520tag%253Arelocatable%2520and%2520tag%253A64bits/files
|
||||
@@ -583,7 +584,7 @@ def test_pattern_matching_not_stack():
|
||||
assert match_address_with_be2(BE2_EXTRACTOR_687, queries, 0x107918) is None
|
||||
|
||||
|
||||
BE2_EXTRACTOR_MIMI = fixtures.get_binexport_extractor(CD / "data" / "binexport2" / "mimikatz.exe_.ghidra.BinExport")
|
||||
BE2_EXTRACTOR_MIMI = fixtures.get_binexport_extractor(fixtures.CD / "data" / "binexport2" / "mimikatz.exe_.ghidra.BinExport")
|
||||
|
||||
|
||||
def test_pattern_matching_x86():
|
||||
|
||||
@@ -11,57 +11,15 @@
|
||||
# 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.
|
||||
|
||||
from typing import cast
|
||||
|
||||
import fixtures
|
||||
import pytest
|
||||
|
||||
import capa.features.common
|
||||
|
||||
BACKEND = fixtures.BackendFeaturePolicy(
|
||||
name="binexport",
|
||||
get_extractor=fixtures.get_binexport_extractor,
|
||||
include_tags={"binexport"},
|
||||
)
|
||||
|
||||
|
||||
@fixtures.parametrize_backend_feature_fixtures(BACKEND)
|
||||
def test_binexport_features_elf_aarch64(feature_fixture):
|
||||
fixtures.run_feature_fixture(BACKEND, feature_fixture)
|
||||
|
||||
|
||||
@fixtures.parametrize(
|
||||
"sample,scope,feature,expected",
|
||||
fixtures.FEATURE_PRESENCE_TESTS,
|
||||
indirect=["sample", "scope"],
|
||||
)
|
||||
def test_binexport_features_pe_x86(sample, scope, feature, expected):
|
||||
if "mimikatz.exe_" not in sample.name:
|
||||
pytest.skip("for now only testing mimikatz.exe_ Ghidra BinExport file")
|
||||
|
||||
if isinstance(
|
||||
feature, capa.features.common.Characteristic
|
||||
) and "stack string" in cast(str, feature.value):
|
||||
pytest.skip("for now only testing basic features")
|
||||
|
||||
sample = sample.parent / "binexport2" / (sample.name + ".ghidra.BinExport")
|
||||
assert sample.exists()
|
||||
fixtures.do_test_feature_presence(
|
||||
fixtures.get_binexport_extractor, sample, scope, feature, expected
|
||||
@fixtures.parametrize_backend_feature_fixtures(
|
||||
fixtures.BackendFeaturePolicy(
|
||||
name="binexport",
|
||||
include_tags={"binexport"},
|
||||
)
|
||||
|
||||
|
||||
@fixtures.parametrize(
|
||||
"sample,scope,feature,expected",
|
||||
fixtures.FEATURE_COUNT_TESTS_GHIDRA,
|
||||
indirect=["sample", "scope"],
|
||||
)
|
||||
def test_binexport_feature_counts_ghidra(sample, scope, feature, expected):
|
||||
if "mimikatz.exe_" not in sample.name:
|
||||
pytest.skip("for now only testing mimikatz.exe_ Ghidra BinExport file")
|
||||
sample = sample.parent / "binexport2" / (sample.name + ".ghidra.BinExport")
|
||||
assert sample.exists()
|
||||
fixtures.do_test_feature_count(
|
||||
fixtures.get_binexport_extractor, sample, scope, feature, expected
|
||||
)
|
||||
def test_binexport_features(feature_fixture):
|
||||
extractor = fixtures.get_binexport_extractor(feature_fixture.sample_path)
|
||||
fixtures.run_feature_fixture(extractor, feature_fixture)
|
||||
|
||||
@@ -13,12 +13,10 @@
|
||||
# limitations under the License.
|
||||
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
import fixtures
|
||||
import pytest
|
||||
|
||||
import capa.features.common
|
||||
import capa.main
|
||||
|
||||
logger = logging.getLogger(__file__)
|
||||
@@ -41,23 +39,22 @@ except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
BACKEND = fixtures.BackendFeaturePolicy(
|
||||
name="binja",
|
||||
# binja also loads .bndb database files natively, so include `binja-db`
|
||||
# alongside the regular static-binary fixtures.
|
||||
get_extractor=fixtures.get_binja_extractor,
|
||||
include_tags={"static", "binja-db"},
|
||||
exclude_tags={"dotnet", "ghidra"},
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
binja_present is False,
|
||||
reason="Skip binja tests if the binaryninja Python API is not installed",
|
||||
)
|
||||
@fixtures.parametrize_backend_feature_fixtures(BACKEND)
|
||||
@fixtures.parametrize_backend_feature_fixtures(
|
||||
fixtures.BackendFeaturePolicy(
|
||||
name="binja",
|
||||
# binja also loads .bndb database files natively, so include `binja-db`
|
||||
# alongside the regular static-binary fixtures.
|
||||
include_tags={"static", "binja-db"},
|
||||
exclude_tags={"dotnet", "ghidra"},
|
||||
)
|
||||
)
|
||||
def test_binja_features(feature_fixture):
|
||||
fixtures.run_feature_fixture(BACKEND, feature_fixture)
|
||||
extractor = fixtures.get_binja_extractor(feature_fixture.sample_path)
|
||||
fixtures.run_feature_fixture(extractor, feature_fixture)
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
@@ -65,10 +62,7 @@ def test_binja_features(feature_fixture):
|
||||
reason="Skip binja tests if the binaryninja Python API is not installed",
|
||||
)
|
||||
def test_standalone_binja_backend():
|
||||
CD = Path(__file__).resolve().parent
|
||||
test_path = (
|
||||
CD / ".." / "tests" / "data" / "Practical Malware Analysis Lab 01-01.exe_"
|
||||
)
|
||||
test_path = fixtures.CD / "data" / "Practical Malware Analysis Lab 01-01.exe_"
|
||||
assert capa.main.main([str(test_path), "-b", capa.main.BACKEND_BINJA]) == 0
|
||||
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import textwrap
|
||||
|
||||
import capa.rules
|
||||
import capa.features.common
|
||||
import fixtures
|
||||
import capa.capabilities.common
|
||||
import capa.features.extractors.null
|
||||
from capa.features.address import AbsoluteVirtualAddress
|
||||
@@ -212,7 +213,8 @@ def test_byte_matching(z9324d_extractor):
|
||||
assert "byte match test" in capabilities.matches
|
||||
|
||||
|
||||
def test_com_feature_matching(z395eb_extractor):
|
||||
def test_com_feature_matching():
|
||||
extractor = fixtures.get_viv_extractor(fixtures.CD / "data" / "395eb0ddd99d2c9e37b6d0b73485ee9c.exe_")
|
||||
rules = capa.rules.RuleSet([
|
||||
capa.rules.Rule.from_yaml(
|
||||
textwrap.dedent("""
|
||||
@@ -230,7 +232,7 @@ def test_com_feature_matching(z395eb_extractor):
|
||||
""")
|
||||
)
|
||||
])
|
||||
capabilities = capa.capabilities.common.find_capabilities(rules, z395eb_extractor)
|
||||
capabilities = capa.capabilities.common.find_capabilities(rules, extractor)
|
||||
assert "initialize IWebBrowser2" in capabilities.matches
|
||||
|
||||
|
||||
|
||||
@@ -11,17 +11,15 @@
|
||||
# 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 fixtures
|
||||
|
||||
BACKEND = fixtures.BackendFeaturePolicy(
|
||||
name="cape",
|
||||
get_extractor=fixtures.get_cape_extractor,
|
||||
include_tags={"cape"},
|
||||
|
||||
@fixtures.parametrize_backend_feature_fixtures(
|
||||
fixtures.BackendFeaturePolicy(
|
||||
name="cape",
|
||||
include_tags={"cape"},
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@fixtures.parametrize_backend_feature_fixtures(BACKEND)
|
||||
def test_cape_features(feature_fixture):
|
||||
fixtures.run_feature_fixture(BACKEND, feature_fixture)
|
||||
extractor = fixtures.get_cape_extractor(feature_fixture.sample_path)
|
||||
fixtures.run_feature_fixture(extractor, feature_fixture)
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
import gzip
|
||||
from typing import Type
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
import fixtures
|
||||
@@ -22,8 +21,7 @@ import fixtures
|
||||
from capa.exceptions import EmptyReportError, UnsupportedFormatError
|
||||
from capa.features.extractors.cape.models import Call, CapeReport
|
||||
|
||||
CD = Path(__file__).resolve().parent
|
||||
CAPE_DIR = CD / "data" / "dynamic" / "cape"
|
||||
CAPE_DIR = fixtures.CD / "data" / "dynamic" / "cape"
|
||||
|
||||
|
||||
@fixtures.parametrize(
|
||||
|
||||
@@ -11,16 +11,15 @@
|
||||
# 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 fixtures
|
||||
|
||||
BACKEND = fixtures.BackendFeaturePolicy(
|
||||
name="dnfile",
|
||||
get_extractor=fixtures.get_dnfile_extractor,
|
||||
include_tags={"dotnet"},
|
||||
|
||||
@fixtures.parametrize_backend_feature_fixtures(
|
||||
fixtures.BackendFeaturePolicy(
|
||||
name="dnfile",
|
||||
include_tags={"dotnet"},
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@fixtures.parametrize_backend_feature_fixtures(BACKEND)
|
||||
def test_dnfile_features(feature_fixture):
|
||||
fixtures.run_feature_fixture(BACKEND, feature_fixture)
|
||||
extractor = fixtures.get_dnfile_extractor(feature_fixture.sample_path)
|
||||
fixtures.run_feature_fixture(extractor, feature_fixture)
|
||||
|
||||
@@ -14,37 +14,53 @@
|
||||
|
||||
import fixtures
|
||||
|
||||
BACKEND = fixtures.BackendFeaturePolicy(
|
||||
name="dotnetfile",
|
||||
get_extractor=fixtures.get_dotnetfile_extractor,
|
||||
include_tags={"dotnet"},
|
||||
exclude_tags={
|
||||
# dotnetfile is a file-scope extractor; drop non-file scopes
|
||||
"function",
|
||||
"basic-block",
|
||||
"instruction",
|
||||
# and drop feature types dotnetfile doesn't produce
|
||||
"function-name",
|
||||
},
|
||||
|
||||
@fixtures.parametrize_backend_feature_fixtures(
|
||||
fixtures.BackendFeaturePolicy(
|
||||
name="dotnetfile",
|
||||
include_tags={"dotnet"},
|
||||
exclude_tags={
|
||||
# dotnetfile is a file-scope extractor; drop non-file scopes
|
||||
"function",
|
||||
"basic-block",
|
||||
"instruction",
|
||||
# and drop feature types dotnetfile doesn't produce
|
||||
"function-name",
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@fixtures.parametrize_backend_feature_fixtures(BACKEND)
|
||||
def test_dotnetfile_features(feature_fixture):
|
||||
fixtures.run_feature_fixture(BACKEND, feature_fixture)
|
||||
extractor = fixtures.get_dotnetfile_extractor(feature_fixture.sample_path)
|
||||
fixtures.run_feature_fixture(extractor, feature_fixture)
|
||||
|
||||
|
||||
@fixtures.parametrize(
|
||||
"extractor,function,expected",
|
||||
[
|
||||
("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_dotnetfile_extractor(request, extractor, function, expected):
|
||||
extractor_function = getattr(request.getfixturevalue(extractor), function)
|
||||
assert extractor_function() == expected
|
||||
def test_dotnetfile_extractor_is_dotnet_file():
|
||||
extractor = fixtures.get_dotnetfile_extractor(fixtures.CD / "data" / "b9f5bd514485fb06da39beff051b9fdc.exe_")
|
||||
assert extractor.is_dotnet_file() is True
|
||||
|
||||
|
||||
def test_dotnetfile_extractor_is_not_mixed_mode():
|
||||
extractor = fixtures.get_dotnetfile_extractor(fixtures.CD / "data" / "b9f5bd514485fb06da39beff051b9fdc.exe_")
|
||||
assert extractor.is_mixed_mode() is False
|
||||
|
||||
|
||||
def test_dotnetfile_extractor_mixed_mode_64_is_mixed_mode():
|
||||
extractor = fixtures.get_dotnetfile_extractor(
|
||||
fixtures.DNFILE_TESTFILES / "mixed-mode" / "ModuleCode" / "bin" / "ModuleCode_amd64.exe"
|
||||
)
|
||||
assert extractor.is_mixed_mode() is True
|
||||
|
||||
|
||||
def test_dotnetfile_extractor_get_entry_point():
|
||||
extractor = fixtures.get_dotnetfile_extractor(fixtures.CD / "data" / "b9f5bd514485fb06da39beff051b9fdc.exe_")
|
||||
assert extractor.get_entry_point() == 0x6000007
|
||||
|
||||
|
||||
def test_dotnetfile_extractor_get_runtime_version():
|
||||
extractor = fixtures.get_dotnetfile_extractor(fixtures.CD / "data" / "b9f5bd514485fb06da39beff051b9fdc.exe_")
|
||||
assert extractor.get_runtime_version() == (2, 5)
|
||||
|
||||
|
||||
def test_dotnetfile_extractor_get_meta_version_string():
|
||||
extractor = fixtures.get_dotnetfile_extractor(fixtures.CD / "data" / "b9f5bd514485fb06da39beff051b9fdc.exe_")
|
||||
assert extractor.get_meta_version_string() == "v2.0.50727"
|
||||
|
||||
@@ -11,17 +11,15 @@
|
||||
# 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 fixtures
|
||||
|
||||
BACKEND = fixtures.BackendFeaturePolicy(
|
||||
name="drakvuf",
|
||||
get_extractor=fixtures.get_drakvuf_extractor,
|
||||
include_tags={"drakvuf"},
|
||||
|
||||
@fixtures.parametrize_backend_feature_fixtures(
|
||||
fixtures.BackendFeaturePolicy(
|
||||
name="drakvuf",
|
||||
include_tags={"drakvuf"},
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@fixtures.parametrize_backend_feature_fixtures(BACKEND)
|
||||
def test_drakvuf_features(feature_fixture):
|
||||
fixtures.run_feature_fixture(BACKEND, feature_fixture)
|
||||
extractor = fixtures.get_drakvuf_extractor(feature_fixture.sample_path)
|
||||
fixtures.run_feature_fixture(extractor, feature_fixture)
|
||||
|
||||
@@ -65,7 +65,7 @@ def filter_threads(extractor: DynamicFeatureExtractor, ppid: int, pid: int, tid:
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def get_0000a657_thread3064():
|
||||
extractor = fixtures.get_cape_extractor(fixtures.get_data_path_by_name("0000a657"))
|
||||
extractor = fixtures.get_cape_extractor(fixtures.CD / "data" / "dynamic" / "cape" / "v2.2" / "0000a65749f5902c4d82ffa701198038f0b4870b00a27cfca109f8f933476d82.json.gz")
|
||||
extractor = filter_threads(extractor, 2456, 3052, 3064)
|
||||
return extractor
|
||||
|
||||
|
||||
@@ -15,13 +15,14 @@
|
||||
import io
|
||||
from pathlib import Path
|
||||
|
||||
import fixtures
|
||||
|
||||
from elftools.elf.elffile import ELFFile
|
||||
|
||||
from capa.features.extractors.elffile import extract_file_export_names, extract_file_import_names
|
||||
|
||||
CD = Path(__file__).resolve().parent
|
||||
SAMPLE_PATH = CD / "data" / "055da8e6ccfe5a9380231ea04b850e18.elf_"
|
||||
STRIPPED_SAMPLE_PATH = CD / "data" / "bb38149ff4b5c95722b83f24ca27a42b.elf_"
|
||||
SAMPLE_PATH = fixtures.CD / "data" / "055da8e6ccfe5a9380231ea04b850e18.elf_"
|
||||
STRIPPED_SAMPLE_PATH = fixtures.CD / "data" / "bb38149ff4b5c95722b83f24ca27a42b.elf_"
|
||||
|
||||
|
||||
def check_import_features(sample_path, expected_imports):
|
||||
|
||||
@@ -24,7 +24,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def test_viv_hash_extraction():
|
||||
assert fixtures.get_viv_extractor(fixtures.get_data_path_by_name("mimikatz")).get_sample_hashes() == SampleHashes(
|
||||
assert fixtures.get_viv_extractor(fixtures.CD / "data" / "mimikatz.exe_").get_sample_hashes() == SampleHashes(
|
||||
md5="5f66b82558ca92e54e77f216ef4c066c",
|
||||
sha1="e4f82e4d7f22938dc0a0ff8a4a7ad2a763643d38",
|
||||
sha256="131314a6f6d1d263c75b9909586b3e1bd837036329ace5e69241749e861ac01d",
|
||||
@@ -33,7 +33,7 @@ def test_viv_hash_extraction():
|
||||
|
||||
def test_pefile_hash_extraction():
|
||||
assert fixtures.get_pefile_extractor(
|
||||
fixtures.get_data_path_by_name("mimikatz")
|
||||
fixtures.CD / "data" / "mimikatz.exe_"
|
||||
).get_sample_hashes() == SampleHashes(
|
||||
md5="5f66b82558ca92e54e77f216ef4c066c",
|
||||
sha1="e4f82e4d7f22938dc0a0ff8a4a7ad2a763643d38",
|
||||
@@ -42,7 +42,7 @@ def test_pefile_hash_extraction():
|
||||
|
||||
|
||||
def test_dnfile_hash_extraction():
|
||||
assert fixtures.get_dnfile_extractor(fixtures.get_data_path_by_name("b9f5b")).get_sample_hashes() == SampleHashes(
|
||||
assert fixtures.get_dnfile_extractor(fixtures.CD / "data" / "b9f5bd514485fb06da39beff051b9fdc.exe_").get_sample_hashes() == SampleHashes(
|
||||
md5="b9f5bd514485fb06da39beff051b9fdc",
|
||||
sha1="c72a2e50410475a51d897d29ffbbaf2103754d53",
|
||||
sha256="34acc4c0b61b5ce0b37c3589f97d1f23e6d84011a241e6f85683ee517ce786f1",
|
||||
@@ -51,7 +51,7 @@ def test_dnfile_hash_extraction():
|
||||
|
||||
def test_dotnetfile_hash_extraction():
|
||||
assert fixtures.get_dotnetfile_extractor(
|
||||
fixtures.get_data_path_by_name("b9f5b")
|
||||
fixtures.CD / "data" / "b9f5bd514485fb06da39beff051b9fdc.exe_"
|
||||
).get_sample_hashes() == SampleHashes(
|
||||
md5="b9f5bd514485fb06da39beff051b9fdc",
|
||||
sha1="c72a2e50410475a51d897d29ffbbaf2103754d53",
|
||||
@@ -60,7 +60,7 @@ def test_dotnetfile_hash_extraction():
|
||||
|
||||
|
||||
def test_cape_hash_extraction():
|
||||
assert fixtures.get_cape_extractor(fixtures.get_data_path_by_name("0000a657")).get_sample_hashes() == SampleHashes(
|
||||
assert fixtures.get_cape_extractor(fixtures.CD / "data" / "dynamic" / "cape" / "v2.2" / "0000a65749f5902c4d82ffa701198038f0b4870b00a27cfca109f8f933476d82.json.gz").get_sample_hashes() == SampleHashes(
|
||||
md5="e2147b5333879f98d515cd9aa905d489",
|
||||
sha1="ad4d520fb7792b4a5701df973d6bd8a6cbfbb57f",
|
||||
sha256="0000a65749f5902c4d82ffa701198038f0b4870b00a27cfca109f8f933476d82",
|
||||
@@ -84,7 +84,7 @@ except ImportError:
|
||||
|
||||
@pytest.mark.skipif(binja_present is False, reason="Skip binja tests if the binaryninja Python API is not installed")
|
||||
def test_binja_hash_extraction():
|
||||
extractor = fixtures.get_binja_extractor(fixtures.get_data_path_by_name("mimikatz"))
|
||||
extractor = fixtures.get_binja_extractor(fixtures.CD / "data" / "mimikatz.exe_")
|
||||
hashes = SampleHashes(
|
||||
md5="5f66b82558ca92e54e77f216ef4c066c",
|
||||
sha1="e4f82e4d7f22938dc0a0ff8a4a7ad2a763643d38",
|
||||
|
||||
@@ -160,7 +160,7 @@ def test_freeze_bytes_roundtrip():
|
||||
def test_freeze_load_sample(tmpdir):
|
||||
o = tmpdir.mkdir("capa").join("test.frz")
|
||||
|
||||
extractor = fixtures.get_cape_extractor(fixtures.get_data_path_by_name("d46900"))
|
||||
extractor = fixtures.get_cape_extractor(fixtures.CD / "data" / "dynamic" / "cape" / "v2.2" / "d46900384c78863420fb3e297d0a2f743cd2b6b3f7f82bf64059a168e07aceb7.json.gz")
|
||||
|
||||
Path(o.strpath).write_bytes(capa.features.freeze.dump(extractor))
|
||||
|
||||
|
||||
@@ -15,11 +15,10 @@
|
||||
import textwrap
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
import fixtures
|
||||
|
||||
import capa.main
|
||||
import capa.rules
|
||||
import capa.helpers
|
||||
import capa.features.file
|
||||
import capa.features.insn
|
||||
import capa.features.common
|
||||
@@ -192,26 +191,15 @@ def test_no_address_lt_irreflexivity():
|
||||
assert not (no_addr < no_addr)
|
||||
|
||||
|
||||
def test_freeze_sample(tmpdir, z9324d_extractor):
|
||||
def test_freeze_sample(tmpdir):
|
||||
# tmpdir fixture handles cleanup
|
||||
o = tmpdir.mkdir("capa").join("test.frz").strpath
|
||||
path = z9324d_extractor.path
|
||||
path = str(fixtures.CD / "data" / "9324d1a8ae37a36ae560c37448c9705a.exe_")
|
||||
assert capa.features.freeze.main([path, o, "-v"]) == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"extractor",
|
||||
[
|
||||
pytest.param("z9324d_extractor"),
|
||||
],
|
||||
)
|
||||
def test_freeze_load_sample(tmpdir, request, extractor):
|
||||
def test_freeze_load_sample(tmpdir, z9324d_extractor):
|
||||
o = tmpdir.mkdir("capa").join("test.frz")
|
||||
|
||||
extractor = request.getfixturevalue(extractor)
|
||||
|
||||
Path(o.strpath).write_bytes(capa.features.freeze.dump(extractor))
|
||||
|
||||
Path(o.strpath).write_bytes(capa.features.freeze.dump(z9324d_extractor))
|
||||
null_extractor = capa.features.freeze.load(Path(o.strpath).read_bytes())
|
||||
|
||||
compare_extractors(extractor, null_extractor)
|
||||
compare_extractors(z9324d_extractor, null_extractor)
|
||||
|
||||
@@ -23,15 +23,14 @@ ghidra_present = (
|
||||
)
|
||||
|
||||
|
||||
BACKEND = fixtures.BackendFeaturePolicy(
|
||||
name="ghidra",
|
||||
get_extractor=fixtures.get_ghidra_extractor,
|
||||
include_tags={"static"},
|
||||
exclude_tags={"dotnet"},
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.skipif(ghidra_present is False, reason="PyGhidra not installed")
|
||||
@fixtures.parametrize_backend_feature_fixtures(BACKEND)
|
||||
@fixtures.parametrize_backend_feature_fixtures(
|
||||
fixtures.BackendFeaturePolicy(
|
||||
name="ghidra",
|
||||
include_tags={"static"},
|
||||
exclude_tags={"dotnet"},
|
||||
)
|
||||
)
|
||||
def test_ghidra_features(feature_fixture):
|
||||
fixtures.run_feature_fixture(BACKEND, feature_fixture)
|
||||
extractor = fixtures.get_ghidra_extractor(feature_fixture.sample_path)
|
||||
fixtures.run_feature_fixture(extractor, feature_fixture)
|
||||
|
||||
@@ -16,18 +16,19 @@ import logging
|
||||
import fixtures
|
||||
import pytest
|
||||
|
||||
import capa.features.extractors.ida.idalib
|
||||
import capa.features.extractors.ida.idalib as idalib
|
||||
from capa.features.common import Characteristic
|
||||
from capa.features.file import FunctionName
|
||||
from capa.features.insn import API
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
idalib_present = capa.features.extractors.ida.idalib.has_idalib()
|
||||
idalib_present = idalib.has_idalib()
|
||||
if idalib_present:
|
||||
try:
|
||||
if True:
|
||||
import idapro # noqa: F401 [imported but unused]
|
||||
import ida_kernwin
|
||||
import idapro # noqa: F401 [imported but unused]
|
||||
|
||||
kernel_version: str = ida_kernwin.get_kernel_version()
|
||||
except ImportError:
|
||||
@@ -37,19 +38,17 @@ else:
|
||||
kernel_version = "0.0"
|
||||
|
||||
|
||||
BACKEND = fixtures.BackendFeaturePolicy(
|
||||
name="idalib",
|
||||
get_extractor=fixtures.get_idalib_extractor,
|
||||
include_tags={"static"},
|
||||
exclude_tags={"dotnet", "ghidra"},
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
idalib_present is False,
|
||||
reason="Skip idalib tests if the idalib Python API is not installed",
|
||||
)
|
||||
@fixtures.parametrize_backend_feature_fixtures(BACKEND)
|
||||
@fixtures.parametrize_backend_feature_fixtures(
|
||||
fixtures.BackendFeaturePolicy(
|
||||
name="idalib",
|
||||
include_tags={"static"},
|
||||
exclude_tags={"dotnet", "ghidra"},
|
||||
)
|
||||
)
|
||||
def test_idalib_features(feature_fixture):
|
||||
# apply runtime-conditional xfails for specific IDA versions.
|
||||
# version-specific behavior stays in the test body because it
|
||||
@@ -79,7 +78,8 @@ def test_idalib_features(feature_fixture):
|
||||
pytest.xfail("idalib 9.0 does not support loading resource segments")
|
||||
|
||||
try:
|
||||
fixtures.run_feature_fixture(BACKEND, feature_fixture)
|
||||
extractor = fixtures.get_idalib_extractor(feature_fixture.sample_path)
|
||||
fixtures.run_feature_fixture(extractor, feature_fixture)
|
||||
finally:
|
||||
import idapro
|
||||
|
||||
|
||||
@@ -21,13 +21,11 @@ import fixtures
|
||||
|
||||
import capa.main
|
||||
import capa.rules
|
||||
import capa.engine
|
||||
import capa.features
|
||||
|
||||
|
||||
def test_main(z9324d_extractor):
|
||||
def test_main():
|
||||
# tests rules can be loaded successfully and all output modes
|
||||
path = z9324d_extractor.path
|
||||
path = str(fixtures.PMA1601)
|
||||
assert capa.main.main([path, "-vv"]) == 0
|
||||
assert capa.main.main([path, "-v"]) == 0
|
||||
assert capa.main.main([path, "-j"]) == 0
|
||||
@@ -35,7 +33,7 @@ def test_main(z9324d_extractor):
|
||||
assert capa.main.main([path]) == 0
|
||||
|
||||
|
||||
def test_main_single_rule(z9324d_extractor, tmpdir):
|
||||
def test_main_single_rule(tmpdir):
|
||||
# tests a single rule can be loaded successfully
|
||||
RULE_CONTENT = textwrap.dedent("""
|
||||
rule:
|
||||
@@ -49,12 +47,11 @@ def test_main_single_rule(z9324d_extractor, tmpdir):
|
||||
features:
|
||||
- string: test
|
||||
""")
|
||||
path = z9324d_extractor.path
|
||||
rule_file = tmpdir.mkdir("capa").join("rule.yml")
|
||||
rule_file.write(RULE_CONTENT)
|
||||
assert (
|
||||
capa.main.main([
|
||||
path,
|
||||
str(fixtures.PMA1601),
|
||||
"-v",
|
||||
"-r",
|
||||
rule_file.strpath,
|
||||
@@ -63,16 +60,17 @@ def test_main_single_rule(z9324d_extractor, tmpdir):
|
||||
)
|
||||
|
||||
|
||||
def test_main_non_ascii_filename(pingtaest_extractor, tmpdir, capsys):
|
||||
def test_main_non_ascii_filename(tmpdir, capsys):
|
||||
# here we print a string with unicode characters in it
|
||||
# (specifically, a byte string with utf-8 bytes in it, see file encoding)
|
||||
# only use one rule to speed up analysis
|
||||
assert capa.main.main(["-q", pingtaest_extractor.path, "-r", "rules/communication/icmp"]) == 0
|
||||
path = str(fixtures.CD / "./data/ping_täst.exe_")
|
||||
assert capa.main.main(["-q", path, "-r", "rules/communication/icmp"]) == 0
|
||||
|
||||
std = capsys.readouterr()
|
||||
# but here, we have to use a unicode instance,
|
||||
# because capsys has decoded the output for us.
|
||||
assert pingtaest_extractor.path in std.out
|
||||
assert path in std.out
|
||||
|
||||
|
||||
def test_main_non_ascii_filename_nonexistent(tmpdir, caplog):
|
||||
@@ -82,8 +80,9 @@ def test_main_non_ascii_filename_nonexistent(tmpdir, caplog):
|
||||
assert NON_ASCII_FILENAME in caplog.text
|
||||
|
||||
|
||||
def test_main_shellcode(z499c2_extractor):
|
||||
path = z499c2_extractor.path
|
||||
def test_main_shellcode():
|
||||
path = str(fixtures.CD / "./data/499c2a85f6e8142c3f48d4251c9c7cd6.raw32")
|
||||
|
||||
assert capa.main.main([path, "-vv", "-f", "sc32"]) == 0
|
||||
assert capa.main.main([path, "-v", "-f", "sc32"]) == 0
|
||||
assert capa.main.main([path, "-j", "-f", "sc32"]) == 0
|
||||
@@ -200,8 +199,8 @@ def test_ruleset():
|
||||
assert len(rules.call_rules) == 2
|
||||
|
||||
|
||||
def test_fix262(pma16_01_extractor, capsys):
|
||||
path = pma16_01_extractor.path
|
||||
def test_fix262(capsys):
|
||||
path = str(fixtures.CD / "./data/Practical Malware Analysis Lab 16-01.exe_")
|
||||
assert capa.main.main([path, "-vv", "-t", "send HTTP request", "-q"]) == 0
|
||||
|
||||
std = capsys.readouterr()
|
||||
@@ -209,11 +208,11 @@ def test_fix262(pma16_01_extractor, capsys):
|
||||
assert "www.practicalmalwareanalysis.com" not in std.out
|
||||
|
||||
|
||||
def test_not_render_rules_also_matched(z9324d_extractor, capsys):
|
||||
def test_not_render_rules_also_matched(capsys):
|
||||
# rules that are also matched by other rules should not get rendered by default.
|
||||
# this cuts down on the amount of output while giving approx the same detail.
|
||||
# see #224
|
||||
path = z9324d_extractor.path
|
||||
path = str(fixtures.CD / "./data/9324d1a8ae37a36ae560c37448c9705a.exe_")
|
||||
|
||||
# `act as TCP client` matches on
|
||||
# `connect TCP client` matches on
|
||||
@@ -236,7 +235,7 @@ def test_not_render_rules_also_matched(z9324d_extractor, capsys):
|
||||
|
||||
|
||||
def test_json_meta(capsys):
|
||||
path = str(fixtures.get_data_path_by_name("pma01-01"))
|
||||
path = str(fixtures.CD / "./data/Practical Malware Analysis Lab 01-01.dll_")
|
||||
assert capa.main.main([path, "-j"]) == 0
|
||||
std = capsys.readouterr()
|
||||
std_json = json.loads(std.out)
|
||||
@@ -250,9 +249,9 @@ def test_json_meta(capsys):
|
||||
assert {"address": ["absolute", 0x10001179]} in info["matched_basic_blocks"]
|
||||
|
||||
|
||||
def test_main_dotnet(_1c444_dotnetfile_extractor):
|
||||
def test_main_dotnet():
|
||||
# tests successful execution and all output modes
|
||||
path = _1c444_dotnetfile_extractor.path
|
||||
path = str(fixtures.CD / "./data/dotnet/1c444ebeba24dcba8628b7dfe5fec7c6.exe_")
|
||||
assert capa.main.main([path, "-vv"]) == 0
|
||||
assert capa.main.main([path, "-v"]) == 0
|
||||
assert capa.main.main([path, "-j"]) == 0
|
||||
@@ -260,27 +259,27 @@ def test_main_dotnet(_1c444_dotnetfile_extractor):
|
||||
assert capa.main.main([path]) == 0
|
||||
|
||||
|
||||
def test_main_dotnet2(_692f_dotnetfile_extractor):
|
||||
def test_main_dotnet2():
|
||||
# tests successful execution and one rendering
|
||||
# above covers all output modes
|
||||
path = _692f_dotnetfile_extractor.path
|
||||
path = str(fixtures.CD / "./data/dotnet/692f7fd6d198e804d6af98eb9e390d61.exe_")
|
||||
assert capa.main.main([path, "-vv"]) == 0
|
||||
|
||||
|
||||
def test_main_dotnet3(_0953c_dotnetfile_extractor):
|
||||
def test_main_dotnet3():
|
||||
# tests successful execution and one rendering
|
||||
path = _0953c_dotnetfile_extractor.path
|
||||
path = str(fixtures.CD / "./data/0953cc3b77ed2974b09e3a00708f88de931d681e2d0cb64afbaf714610beabe6.exe_")
|
||||
assert capa.main.main([path, "-vv"]) == 0
|
||||
|
||||
|
||||
def test_main_dotnet4(_039a6_dotnetfile_extractor):
|
||||
def test_main_dotnet4():
|
||||
# tests successful execution and one rendering
|
||||
path = _039a6_dotnetfile_extractor.path
|
||||
path = str(fixtures.CD / "./data/039a6336d0802a2255669e6867a5679c7eb83313dbc61fb1c7232147379bd304.exe_")
|
||||
assert capa.main.main([path, "-vv"]) == 0
|
||||
|
||||
|
||||
def test_main_rd():
|
||||
path = str(fixtures.get_data_path_by_name("pma01-01-rd"))
|
||||
path = str(fixtures.CD / "./data/rd/Practical Malware Analysis Lab 01-01.dll_.json")
|
||||
assert capa.main.main([path, "-vv"]) == 0
|
||||
assert capa.main.main([path, "-v"]) == 0
|
||||
assert capa.main.main([path, "-j"]) == 0
|
||||
@@ -295,7 +294,7 @@ def extract_cape_report(tmp_path: Path, gz: Path) -> Path:
|
||||
|
||||
|
||||
def test_main_cape1(tmp_path):
|
||||
path = extract_cape_report(tmp_path, fixtures.get_data_path_by_name("0000a657"))
|
||||
path = extract_cape_report(tmp_path, fixtures.CD / "./data/dynamic/cape/v2.2/0000a65749f5902c4d82ffa701198038f0b4870b00a27cfca109f8f933476d82.json.gz")
|
||||
|
||||
# TODO(williballenthin): use default rules set
|
||||
# https://github.com/mandiant/capa/pull/1696
|
||||
@@ -344,5 +343,5 @@ def test_main_cape1(tmp_path):
|
||||
|
||||
def test_main_cape_gzip():
|
||||
# tests successful execution of .json.gz
|
||||
path = str(fixtures.get_data_path_by_name("0000a657"))
|
||||
path = str(fixtures.CD / "./data/dynamic/cape/v2.2/0000a65749f5902c4d82ffa701198038f0b4870b00a27cfca109f8f933476d82.json.gz")
|
||||
assert capa.main.main([path]) == 0
|
||||
|
||||
@@ -14,9 +14,8 @@
|
||||
|
||||
import io
|
||||
import zlib
|
||||
from pathlib import Path
|
||||
|
||||
from fixtures import get_data_path_by_name
|
||||
import fixtures
|
||||
|
||||
import capa.features.extractors.elf
|
||||
import capa.features.extractors.common
|
||||
@@ -31,8 +30,8 @@ def test_elf_sh_notes():
|
||||
# guess: ABI versions needed: None
|
||||
# guess: symtab: None
|
||||
# guess: needed dependencies: None
|
||||
path = get_data_path_by_name("2f7f5f")
|
||||
with Path(path).open("rb") as f:
|
||||
path = fixtures.CD / "data" / "2f7f5fb5de175e770d7eae87666f9831.elf_"
|
||||
with path.open("rb") as f:
|
||||
assert capa.features.extractors.elf.detect_elf_os(f) == "linux"
|
||||
|
||||
|
||||
@@ -44,8 +43,8 @@ def test_elf_pt_notes():
|
||||
# guess: ABI versions needed: OS.LINUX
|
||||
# guess: symtab: None
|
||||
# guess: needed dependencies: None
|
||||
path = get_data_path_by_name("7351f.elf")
|
||||
with Path(path).open("rb") as f:
|
||||
path = fixtures.CD / "data" / "7351f8a40c5450557b24622417fc478d.elf_"
|
||||
with path.open("rb") as f:
|
||||
assert capa.features.extractors.elf.detect_elf_os(f) == "linux"
|
||||
|
||||
|
||||
@@ -57,8 +56,8 @@ def test_elf_so_needed():
|
||||
# guess: ABI versions needed: OS.HURD
|
||||
# guess: symtab: None
|
||||
# guess: needed dependencies: OS.HURD
|
||||
path = get_data_path_by_name("b5f052")
|
||||
with Path(path).open("rb") as f:
|
||||
path = fixtures.CD / "data" / "b5f0524e69b3a3cf636c7ac366ca57bf5e3a8fdc8a9f01caf196c611a7918a87.elf_"
|
||||
with path.open("rb") as f:
|
||||
assert capa.features.extractors.elf.detect_elf_os(f) == "hurd"
|
||||
|
||||
|
||||
@@ -70,8 +69,8 @@ def test_elf_abi_version_hurd():
|
||||
# guess: ABI versions needed: OS.HURD
|
||||
# guess: symtab: None
|
||||
# guess: needed dependencies: None
|
||||
path = get_data_path_by_name("bf7a9c")
|
||||
with Path(path).open("rb") as f:
|
||||
path = fixtures.CD / "data" / "bf7a9c8bdfa6d47e01ad2b056264acc3fd90cf43fe0ed8deec93ab46b47d76cb.elf_"
|
||||
with path.open("rb") as f:
|
||||
assert capa.features.extractors.elf.detect_elf_os(f) == "hurd"
|
||||
|
||||
|
||||
@@ -83,8 +82,8 @@ def test_elf_symbol_table():
|
||||
# guess: ABI versions needed: None
|
||||
# guess: symtab: OS.LINUX
|
||||
# guess: needed dependencies: None
|
||||
path = get_data_path_by_name("2bf18d")
|
||||
with Path(path).open("rb") as f:
|
||||
path = fixtures.CD / "data" / "2bf18d0403677378adad9001b1243211.elf_"
|
||||
with path.open("rb") as f:
|
||||
assert capa.features.extractors.elf.detect_elf_os(f) == "linux"
|
||||
|
||||
|
||||
@@ -95,14 +94,14 @@ def test_elf_android_notes():
|
||||
# DEBUG:capa.features.extractors.elf:guess: linker: None
|
||||
# DEBUG:capa.features.extractors.elf:guess: ABI versions needed: None
|
||||
# DEBUG:capa.features.extractors.elf:guess: needed dependencies: OS.ANDROID
|
||||
path = get_data_path_by_name("1038a2")
|
||||
with Path(path).open("rb") as f:
|
||||
path = fixtures.CD / "data" / "1038a23daad86042c66bfe6c9d052d27048de9653bde5750dc0f240c792d9ac8.elf_"
|
||||
with path.open("rb") as f:
|
||||
assert capa.features.extractors.elf.detect_elf_os(f) == "android"
|
||||
|
||||
|
||||
def test_elf_go_buildinfo():
|
||||
path = get_data_path_by_name("3da7c")
|
||||
with Path(path).open("rb") as f:
|
||||
path = fixtures.CD / "data" / "3da7c2c70a2d93ac4643f20339d5c7d61388bddd77a4a5fd732311efad78e535.elf_"
|
||||
with path.open("rb") as f:
|
||||
assert capa.features.extractors.elf.detect_elf_os(f) == "linux"
|
||||
|
||||
|
||||
|
||||
@@ -11,26 +11,25 @@
|
||||
# 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 fixtures
|
||||
|
||||
BACKEND = fixtures.BackendFeaturePolicy(
|
||||
name="pefile",
|
||||
get_extractor=fixtures.get_pefile_extractor,
|
||||
include_tags={"static"},
|
||||
exclude_tags={
|
||||
"dotnet",
|
||||
"elf",
|
||||
# pefile is a file-scope extractor; drop non-file scopes
|
||||
"function",
|
||||
"basic-block",
|
||||
"instruction",
|
||||
# and drop feature types pefile doesn't produce
|
||||
"function-name",
|
||||
},
|
||||
|
||||
@fixtures.parametrize_backend_feature_fixtures(
|
||||
fixtures.BackendFeaturePolicy(
|
||||
name="pefile",
|
||||
include_tags={"static"},
|
||||
exclude_tags={
|
||||
"dotnet",
|
||||
"elf",
|
||||
# pefile is a file-scope extractor; drop non-file scopes
|
||||
"function",
|
||||
"basic block",
|
||||
"instruction",
|
||||
# and drop feature types pefile doesn't produce
|
||||
"function-name",
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@fixtures.parametrize_backend_feature_fixtures(BACKEND)
|
||||
def test_pefile_features(feature_fixture):
|
||||
fixtures.run_feature_fixture(BACKEND, feature_fixture)
|
||||
extractor = fixtures.get_pefile_extractor(feature_fixture.sample_path)
|
||||
fixtures.run_feature_fixture(extractor, feature_fixture)
|
||||
|
||||
@@ -284,12 +284,12 @@ def test_round_trip(request, rd_file):
|
||||
|
||||
|
||||
def test_json_to_rdoc():
|
||||
path = fixtures.get_data_path_by_name("pma01-01-rd")
|
||||
path = fixtures.CD / "data" / "rd" / "Practical Malware Analysis Lab 01-01.dll_.json"
|
||||
assert isinstance(rdoc.ResultDocument.from_file(path), rdoc.ResultDocument)
|
||||
|
||||
|
||||
def test_rdoc_to_capa():
|
||||
path = fixtures.get_data_path_by_name("pma01-01-rd")
|
||||
path = fixtures.CD / "data" / "rd" / "Practical Malware Analysis Lab 01-01.dll_.json"
|
||||
|
||||
rd = rdoc.ResultDocument.from_file(path)
|
||||
|
||||
|
||||
@@ -22,22 +22,22 @@ from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
import fixtures
|
||||
|
||||
CD = Path(__file__).resolve().parent
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_script_path(s: str):
|
||||
return str(CD / ".." / "scripts" / s)
|
||||
return str(fixtures.CD /".." / "scripts" / s)
|
||||
|
||||
|
||||
def get_binary_file_path():
|
||||
return str(CD / "data" / "9324d1a8ae37a36ae560c37448c9705a.exe_")
|
||||
return str(fixtures.CD /"data" / "9324d1a8ae37a36ae560c37448c9705a.exe_")
|
||||
|
||||
|
||||
def get_cape_report_file_path():
|
||||
return str(
|
||||
CD
|
||||
fixtures.CD
|
||||
/ "data"
|
||||
/ "dynamic"
|
||||
/ "cape"
|
||||
@@ -47,11 +47,11 @@ def get_cape_report_file_path():
|
||||
|
||||
|
||||
def get_binexport2_file_path():
|
||||
return str(CD / "data" / "binexport2" / "mimikatz.exe_.ghidra.BinExport")
|
||||
return str(fixtures.CD /"data" / "binexport2" / "mimikatz.exe_.ghidra.BinExport")
|
||||
|
||||
|
||||
def get_rules_path():
|
||||
return str(CD / ".." / "rules")
|
||||
return str(fixtures.CD /".." / "rules")
|
||||
|
||||
|
||||
def get_rule_path():
|
||||
@@ -65,7 +65,7 @@ def get_rule_path():
|
||||
pytest.param("capafmt.py", [get_rule_path()]),
|
||||
pytest.param(
|
||||
"capa2sarif.py",
|
||||
[Path(__file__).resolve().parent / "data" / "rd" / "Practical Malware Analysis Lab 01-01.dll_.json"],
|
||||
[fixtures.CD /"data" / "rd" / "Practical Malware Analysis Lab 01-01.dll_.json"],
|
||||
),
|
||||
# testing some variations of linter script
|
||||
pytest.param("lint.py", ["-t", "create directory", get_rules_path()]),
|
||||
@@ -96,7 +96,7 @@ def test_scripts(script, args):
|
||||
)
|
||||
def test_binexport_scripts(script, args):
|
||||
# define sample bytes location
|
||||
os.environ["CAPA_SAMPLES_DIR"] = str(Path(CD / "data"))
|
||||
os.environ["CAPA_SAMPLES_DIR"] = str(fixtures.CD / "data")
|
||||
|
||||
script_path = get_script_path(script)
|
||||
p = run_program(script_path, args)
|
||||
@@ -108,7 +108,7 @@ def test_bulk_process(tmp_path):
|
||||
t = tmp_path / "test"
|
||||
t.mkdir()
|
||||
|
||||
source_file = Path(__file__).resolve().parent / "data" / "ping_täst.exe_"
|
||||
source_file = fixtures.CD /"data" / "ping_täst.exe_"
|
||||
dest_file = t / "test.exe_"
|
||||
|
||||
dest_file.write_bytes(source_file.read_bytes())
|
||||
@@ -127,7 +127,7 @@ def run_program(script_path, args):
|
||||
def test_proto_conversion(tmp_path):
|
||||
t = tmp_path / "proto-test"
|
||||
t.mkdir()
|
||||
json_file = Path(__file__).resolve().parent / "data" / "rd" / "Practical Malware Analysis Lab 01-01.dll_.json"
|
||||
json_file = fixtures.CD /"data" / "rd" / "Practical Malware Analysis Lab 01-01.dll_.json"
|
||||
|
||||
p = run_program(get_script_path("proto-from-results.py"), [json_file])
|
||||
assert p.returncode == 0
|
||||
|
||||
@@ -11,17 +11,17 @@
|
||||
# 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 fixtures
|
||||
|
||||
BACKEND = fixtures.BackendFeaturePolicy(
|
||||
name="viv",
|
||||
get_extractor=fixtures.get_viv_extractor,
|
||||
include_tags={"static"},
|
||||
exclude_tags={"dotnet", "ghidra"},
|
||||
|
||||
|
||||
@fixtures.parametrize_backend_feature_fixtures(
|
||||
fixtures.BackendFeaturePolicy(
|
||||
name="viv",
|
||||
include_tags={"static"},
|
||||
exclude_tags={"dotnet", "ghidra"},
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@fixtures.parametrize_backend_feature_fixtures(BACKEND)
|
||||
def test_viv_features(feature_fixture):
|
||||
fixtures.run_feature_fixture(BACKEND, feature_fixture)
|
||||
extractor = fixtures.get_viv_extractor(feature_fixture.sample_path)
|
||||
fixtures.run_feature_fixture(extractor, feature_fixture)
|
||||
|
||||
@@ -11,24 +11,22 @@
|
||||
# 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 fixtures
|
||||
|
||||
BACKEND = fixtures.BackendFeaturePolicy(
|
||||
name="vmray",
|
||||
get_extractor=fixtures.get_vmray_extractor,
|
||||
include_tags={"vmray"},
|
||||
|
||||
@fixtures.parametrize_backend_feature_fixtures(
|
||||
fixtures.BackendFeaturePolicy(
|
||||
name="vmray",
|
||||
include_tags={"vmray"},
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@fixtures.parametrize_backend_feature_fixtures(BACKEND)
|
||||
def test_vmray_features(feature_fixture):
|
||||
fixtures.run_feature_fixture(BACKEND, feature_fixture)
|
||||
extractor = fixtures.get_vmray_extractor(feature_fixture.sample_path)
|
||||
fixtures.run_feature_fixture(extractor, feature_fixture)
|
||||
|
||||
|
||||
def test_vmray_processes():
|
||||
# see #2394
|
||||
path = fixtures.get_data_path_by_name("2f8a79-vmray")
|
||||
path = fixtures.CD / "data" / "dynamic" / "vmray" / "2f8a79b12a7a989ac7e5f6ec65050036588a92e65aeb6841e08dc228ff0e21b4_min_archive.zip"
|
||||
vmre = fixtures.get_vmray_extractor(path)
|
||||
assert len(vmre.analysis.monitor_processes) == 9
|
||||
|
||||
Reference in New Issue
Block a user