mirror of
https://github.com/mandiant/capa.git
synced 2026-04-28 11:53:20 -07:00
fix lints
This commit is contained in:
@@ -16,19 +16,19 @@ from typing import Iterator
|
||||
|
||||
import idaapi
|
||||
|
||||
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
|
||||
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
|
||||
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,
|
||||
)
|
||||
|
||||
@@ -43,9 +43,7 @@ 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())
|
||||
|
||||
@@ -69,9 +67,7 @@ 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]:
|
||||
@@ -80,19 +76,13 @@ 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):
|
||||
|
||||
@@ -817,7 +817,14 @@ def build_feature(
|
||||
assert isinstance(value, str)
|
||||
return Feature(value, description=description)
|
||||
|
||||
case capa.features.common.StringFactory | capa.features.common.Substring:
|
||||
case capa.features.common.StringFactory:
|
||||
assert isinstance(value, str)
|
||||
return cast(
|
||||
capa.features.common.Feature,
|
||||
capa.features.common.StringFactory(value, description=description),
|
||||
)
|
||||
|
||||
case capa.features.common.Substring:
|
||||
assert isinstance(value, str)
|
||||
return Feature(value, description=description)
|
||||
|
||||
|
||||
@@ -12,32 +12,32 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import collections
|
||||
import contextlib
|
||||
import functools
|
||||
import json
|
||||
import logging
|
||||
from dataclasses import dataclass, field
|
||||
import functools
|
||||
import contextlib
|
||||
import collections
|
||||
from typing import Union, Literal, Optional
|
||||
from pathlib import Path
|
||||
from typing import Literal, Optional, Union
|
||||
from dataclasses import field, dataclass
|
||||
|
||||
import pytest
|
||||
|
||||
import capa.rules
|
||||
import capa.engine as ceng
|
||||
import capa.loader
|
||||
import capa.rules
|
||||
import capa.render.result_document
|
||||
from capa.features.common import OS_AUTO, FORMAT_AUTO, Feature
|
||||
from capa.features.address import Address
|
||||
from capa.features.common import FORMAT_AUTO, OS_AUTO, Feature
|
||||
from capa.features.extractors.base_extractor import (
|
||||
BBHandle,
|
||||
CallHandle,
|
||||
DynamicFeatureExtractor,
|
||||
FunctionHandle,
|
||||
InsnHandle,
|
||||
ProcessHandle,
|
||||
StaticFeatureExtractor,
|
||||
ThreadHandle,
|
||||
ProcessHandle,
|
||||
FunctionHandle,
|
||||
StaticFeatureExtractor,
|
||||
DynamicFeatureExtractor,
|
||||
)
|
||||
from capa.features.extractors.dnfile.extractor import DnfileFeatureExtractor
|
||||
|
||||
@@ -207,16 +207,12 @@ def load_fixture_file_references() -> dict[str, FixtureFile]:
|
||||
for entry in data["files"]:
|
||||
key = entry["key"]
|
||||
if key in files:
|
||||
raise ValueError(
|
||||
f"duplicate fixture file key {key!r} in {file_sources[key]} and {manifest_path}"
|
||||
)
|
||||
raise ValueError(f"duplicate fixture file key {key!r} in {file_sources[key]} and {manifest_path}")
|
||||
|
||||
tags = frozenset(entry.get("tags", []))
|
||||
unknown = tags - KNOWN_FIXTURE_TAGS
|
||||
if unknown:
|
||||
raise ValueError(
|
||||
f"unknown fixture tag(s) on file {key!r} in {manifest_path}: {sorted(unknown)}"
|
||||
)
|
||||
raise ValueError(f"unknown fixture tag(s) on file {key!r} in {manifest_path}: {sorted(unknown)}")
|
||||
files[key] = FixtureFile(
|
||||
key=key,
|
||||
path=CD / entry["path"],
|
||||
@@ -320,14 +316,12 @@ def _fixture_test_id(fixture: FeatureFixture) -> str:
|
||||
|
||||
mirrors the legacy `make_test_id` shape: sample-location-statement-expected.
|
||||
"""
|
||||
return "-".join(
|
||||
[
|
||||
fixture.sample_key,
|
||||
fixture.location,
|
||||
str(fixture.statement),
|
||||
str(fixture.expected),
|
||||
]
|
||||
)
|
||||
return "-".join([
|
||||
fixture.sample_key,
|
||||
fixture.location,
|
||||
str(fixture.statement),
|
||||
str(fixture.expected),
|
||||
])
|
||||
|
||||
|
||||
def parametrize_backend_feature_fixtures(policy: BackendFeaturePolicy):
|
||||
@@ -349,9 +343,7 @@ def parametrize_backend_feature_fixtures(policy: BackendFeaturePolicy):
|
||||
elif mark.mark == "xfail":
|
||||
marks.append(pytest.mark.xfail(reason=mark.reason))
|
||||
else:
|
||||
raise ValueError(
|
||||
f"unknown mark {mark.mark!r} for backend {policy.name!r}"
|
||||
)
|
||||
raise ValueError(f"unknown mark {mark.mark!r} for backend {policy.name!r}")
|
||||
params.append(pytest.param(fixture, marks=marks, id=_fixture_test_id(fixture)))
|
||||
return pytest.mark.parametrize("feature_fixture", params)
|
||||
|
||||
@@ -419,7 +411,7 @@ def extract_global_features(extractor):
|
||||
return features
|
||||
|
||||
|
||||
@functools.lru_cache()
|
||||
@functools.lru_cache
|
||||
def extract_file_features(extractor):
|
||||
features = collections.defaultdict(set)
|
||||
for feature, va in extractor.extract_file_features():
|
||||
@@ -540,9 +532,7 @@ def get_basic_block(extractor, fh: FunctionHandle, va: int) -> BBHandle:
|
||||
raise ValueError("basic block not found")
|
||||
|
||||
|
||||
def get_instruction(
|
||||
extractor, fh: FunctionHandle, bbh: BBHandle, va: int
|
||||
) -> InsnHandle:
|
||||
def get_instruction(extractor, fh: FunctionHandle, bbh: BBHandle, va: int) -> InsnHandle:
|
||||
for ih in extractor.get_instructions(fh, bbh):
|
||||
if isinstance(extractor, DnfileFeatureExtractor):
|
||||
addr = ih.inner.offset
|
||||
@@ -709,26 +699,20 @@ def get_result_doc(path: Path):
|
||||
@pytest.fixture
|
||||
def pma0101_rd():
|
||||
# python -m capa.main tests/data/Practical\ Malware\ Analysis\ Lab\ 01-01.dll_ --json > tests/data/rd/Practical\ Malware\ Analysis\ Lab\ 01-01.dll_.json
|
||||
return get_result_doc(
|
||||
CD / "data" / "rd" / "Practical Malware Analysis Lab 01-01.dll_.json"
|
||||
)
|
||||
return get_result_doc(CD / "data" / "rd" / "Practical Malware Analysis Lab 01-01.dll_.json")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def dotnet_1c444e_rd():
|
||||
# .NET sample
|
||||
# python -m capa.main tests/data/dotnet/1c444ebeba24dcba8628b7dfe5fec7c6.exe_ --json > tests/data/rd/1c444ebeba24dcba8628b7dfe5fec7c6.exe_.json
|
||||
return get_result_doc(
|
||||
CD / "data" / "rd" / "1c444ebeba24dcba8628b7dfe5fec7c6.exe_.json"
|
||||
)
|
||||
return get_result_doc(CD / "data" / "rd" / "1c444ebeba24dcba8628b7dfe5fec7c6.exe_.json")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def a3f3bbc_rd():
|
||||
# python -m capa.main tests/data/3f3bbcf8fd90bdcdcdc5494314ed4225.exe_ --json > tests/data/rd/3f3bbcf8fd90bdcdcdc5494314ed4225.exe_.json
|
||||
return get_result_doc(
|
||||
CD / "data" / "rd" / "3f3bbcf8fd90bdcdcdc5494314ed4225.exe_.json"
|
||||
)
|
||||
return get_result_doc(CD / "data" / "rd" / "3f3bbcf8fd90bdcdcdc5494314ed4225.exe_.json")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -746,9 +730,7 @@ def al_khaserx64_rd():
|
||||
@pytest.fixture
|
||||
def a076114_rd():
|
||||
# python -m capa.main tests/data/0761142efbda6c4b1e801223de723578.dll_ --json > tests/data/rd/0761142efbda6c4b1e801223de723578.dll_.json
|
||||
return get_result_doc(
|
||||
CD / "data" / "rd" / "0761142efbda6c4b1e801223de723578.dll_.json"
|
||||
)
|
||||
return get_result_doc(CD / "data" / "rd" / "0761142efbda6c4b1e801223de723578.dll_.json")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -756,10 +738,7 @@ def dynamic_a0000a6_rd():
|
||||
# python -m capa.main tests/data/dynamic/cape/v2.2/0000a65749f5902c4d82ffa701198038f0b4870b00a27cfca109f8f933476d82.json --json > tests/data/rd/0000a65749f5902c4d82ffa701198038f0b4870b00a27cfca109f8f933476d82.json
|
||||
# gzip tests/data/rd/0000a65749f5902c4d82ffa701198038f0b4870b00a27cfca109f8f933476d82.json
|
||||
return get_result_doc(
|
||||
CD
|
||||
/ "data"
|
||||
/ "rd"
|
||||
/ "0000a65749f5902c4d82ffa701198038f0b4870b00a27cfca109f8f933476d82.json.gz"
|
||||
CD / "data" / "rd" / "0000a65749f5902c4d82ffa701198038f0b4870b00a27cfca109f8f933476d82.json.gz"
|
||||
)
|
||||
|
||||
|
||||
@@ -771,8 +750,8 @@ z9324 = CD / "data" / "9324d1a8ae37a36ae560c37448c9705a.exe_"
|
||||
# as well as some fixtures below
|
||||
@functools.lru_cache(maxsize=1)
|
||||
def get_viv_extractor(path: Path):
|
||||
import capa.features.extractors.viv.extractor
|
||||
import capa.main
|
||||
import capa.features.extractors.viv.extractor
|
||||
|
||||
sigpaths = [
|
||||
CD / "data" / "sigs" / "test_aulldiv.pat",
|
||||
@@ -790,13 +769,11 @@ def get_viv_extractor(path: Path):
|
||||
vw = capa.loader.get_workspace(path, FORMAT_AUTO, sigpaths=sigpaths)
|
||||
vw.saveWorkspace()
|
||||
|
||||
extractor = capa.features.extractors.viv.extractor.VivisectFeatureExtractor(
|
||||
vw, path, OS_AUTO
|
||||
)
|
||||
extractor = capa.features.extractors.viv.extractor.VivisectFeatureExtractor(vw, path, OS_AUTO)
|
||||
|
||||
#
|
||||
# fixups to overcome differences between backends
|
||||
#
|
||||
#
|
||||
if "3b13b" in path.name:
|
||||
# vivisect only recognizes calling thunk function at 0x10001573
|
||||
extractor.vw.makeFunction(0x10006860)
|
||||
@@ -961,8 +938,8 @@ def get_idalib_extractor(path: Path):
|
||||
import shutil
|
||||
import tempfile
|
||||
|
||||
import capa.features.extractors.ida.extractor
|
||||
import capa.features.extractors.ida.idalib as idalib
|
||||
import capa.features.extractors.ida.extractor
|
||||
|
||||
if not idalib.has_idalib():
|
||||
raise RuntimeError("cannot find IDA idalib module.")
|
||||
@@ -1034,11 +1011,7 @@ def get_binexport_extractor(path):
|
||||
|
||||
be2 = capa.features.extractors.binexport2.get_binexport2(path)
|
||||
search_paths = [CD / "data", CD / "data" / "aarch64"]
|
||||
path = capa.features.extractors.binexport2.get_sample_from_binexport2(
|
||||
path, be2, search_paths
|
||||
)
|
||||
path = capa.features.extractors.binexport2.get_sample_from_binexport2(path, be2, search_paths)
|
||||
buf = path.read_bytes()
|
||||
|
||||
return capa.features.extractors.binexport2.extractor.BinExport2FeatureExtractor(
|
||||
be2, buf
|
||||
)
|
||||
return capa.features.extractors.binexport2.extractor.BinExport2FeatureExtractor(be2, buf)
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
|
||||
import re
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
import fixtures
|
||||
@@ -42,7 +42,6 @@ from capa.features.extractors.binexport2.arch.arm.helpers import is_stack_regist
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
||||
# 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
|
||||
# Ghidra disassembly of c7f38027552a3eca84e2bfc846ac1307fbf98657545426bb93a2d63555cbb486
|
||||
GHIDRA_DISASSEMBLY = """
|
||||
@@ -584,7 +583,9 @@ 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(fixtures.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():
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
|
||||
import logging
|
||||
|
||||
import fixtures
|
||||
import pytest
|
||||
import fixtures
|
||||
|
||||
import capa.main
|
||||
|
||||
@@ -30,9 +30,7 @@ try:
|
||||
try:
|
||||
binaryninja.load(source=b"\x90")
|
||||
except RuntimeError:
|
||||
logger.warning(
|
||||
"Binary Ninja license is not valid, provide via $BN_LICENSE or license.dat"
|
||||
)
|
||||
logger.warning("Binary Ninja license is not valid, provide via $BN_LICENSE or license.dat")
|
||||
else:
|
||||
binja_present = True
|
||||
except ImportError:
|
||||
|
||||
@@ -17,6 +17,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
|
||||
|
||||
@@ -65,7 +65,14 @@ def filter_threads(extractor: DynamicFeatureExtractor, ppid: int, pid: int, tid:
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def get_0000a657_thread3064():
|
||||
extractor = fixtures.get_cape_extractor(fixtures.CD / "data" / "dynamic" / "cape" / "v2.2" / "0000a65749f5902c4d82ffa701198038f0b4870b00a27cfca109f8f933476d82.json.gz")
|
||||
extractor = fixtures.get_cape_extractor(
|
||||
fixtures.CD
|
||||
/ "data"
|
||||
/ "dynamic"
|
||||
/ "cape"
|
||||
/ "v2.2"
|
||||
/ "0000a65749f5902c4d82ffa701198038f0b4870b00a27cfca109f8f933476d82.json.gz"
|
||||
)
|
||||
extractor = filter_threads(extractor, 2456, 3052, 3064)
|
||||
return extractor
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ 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
|
||||
|
||||
@@ -32,9 +32,7 @@ def test_viv_hash_extraction():
|
||||
|
||||
|
||||
def test_pefile_hash_extraction():
|
||||
assert fixtures.get_pefile_extractor(
|
||||
fixtures.CD / "data" / "mimikatz.exe_"
|
||||
).get_sample_hashes() == SampleHashes(
|
||||
assert fixtures.get_pefile_extractor(fixtures.CD / "data" / "mimikatz.exe_").get_sample_hashes() == SampleHashes(
|
||||
md5="5f66b82558ca92e54e77f216ef4c066c",
|
||||
sha1="e4f82e4d7f22938dc0a0ff8a4a7ad2a763643d38",
|
||||
sha256="131314a6f6d1d263c75b9909586b3e1bd837036329ace5e69241749e861ac01d",
|
||||
@@ -42,7 +40,9 @@ def test_pefile_hash_extraction():
|
||||
|
||||
|
||||
def test_dnfile_hash_extraction():
|
||||
assert fixtures.get_dnfile_extractor(fixtures.CD / "data" / "b9f5bd514485fb06da39beff051b9fdc.exe_").get_sample_hashes() == SampleHashes(
|
||||
assert fixtures.get_dnfile_extractor(
|
||||
fixtures.CD / "data" / "b9f5bd514485fb06da39beff051b9fdc.exe_"
|
||||
).get_sample_hashes() == SampleHashes(
|
||||
md5="b9f5bd514485fb06da39beff051b9fdc",
|
||||
sha1="c72a2e50410475a51d897d29ffbbaf2103754d53",
|
||||
sha256="34acc4c0b61b5ce0b37c3589f97d1f23e6d84011a241e6f85683ee517ce786f1",
|
||||
@@ -60,7 +60,14 @@ def test_dotnetfile_hash_extraction():
|
||||
|
||||
|
||||
def test_cape_hash_extraction():
|
||||
assert fixtures.get_cape_extractor(fixtures.CD / "data" / "dynamic" / "cape" / "v2.2" / "0000a65749f5902c4d82ffa701198038f0b4870b00a27cfca109f8f933476d82.json.gz").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",
|
||||
|
||||
@@ -160,7 +160,14 @@ def test_freeze_bytes_roundtrip():
|
||||
def test_freeze_load_sample(tmpdir):
|
||||
o = tmpdir.mkdir("capa").join("test.frz")
|
||||
|
||||
extractor = fixtures.get_cape_extractor(fixtures.CD / "data" / "dynamic" / "cape" / "v2.2" / "d46900384c78863420fb3e297d0a2f743cd2b6b3f7f82bf64059a168e07aceb7.json.gz")
|
||||
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))
|
||||
|
||||
|
||||
@@ -11,16 +11,13 @@
|
||||
# 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 importlib.util
|
||||
import os
|
||||
import importlib.util
|
||||
|
||||
import fixtures
|
||||
import pytest
|
||||
import fixtures
|
||||
|
||||
ghidra_present = (
|
||||
importlib.util.find_spec("pyghidra") is not None
|
||||
and "GHIDRA_INSTALL_DIR" in os.environ
|
||||
)
|
||||
ghidra_present = importlib.util.find_spec("pyghidra") is not None and "GHIDRA_INSTALL_DIR" in os.environ
|
||||
|
||||
|
||||
@pytest.mark.skipif(ghidra_present is False, reason="PyGhidra not installed")
|
||||
|
||||
@@ -13,13 +13,13 @@
|
||||
# limitations under the License.
|
||||
import logging
|
||||
|
||||
import fixtures
|
||||
import pytest
|
||||
import fixtures
|
||||
|
||||
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
|
||||
from capa.features.common import Characteristic
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -57,10 +57,7 @@ def test_idalib_features(feature_fixture):
|
||||
statement = feature_fixture.statement
|
||||
|
||||
if kernel_version in {"9.0", "9.1"} and sample_name.startswith("2bf18d"):
|
||||
if (
|
||||
isinstance(statement, (API, FunctionName))
|
||||
and statement.value == "__libc_connect"
|
||||
):
|
||||
if isinstance(statement, (API, FunctionName)) and statement.value == "__libc_connect":
|
||||
# see discussion here: https://github.com/mandiant/capa/pull/2742#issuecomment-3674146335
|
||||
#
|
||||
# > i confirmed that there were changes in 9.2 related to the ELF loader handling names,
|
||||
@@ -68,9 +65,7 @@ def test_idalib_features(feature_fixture):
|
||||
# > prevented this name from surfacing.
|
||||
pytest.xfail(f"IDA {kernel_version} does not extract all ELF symbols")
|
||||
|
||||
if kernel_version in {"9.0"} and sample_name.startswith(
|
||||
"Practical Malware Analysis Lab 12-04.exe_"
|
||||
):
|
||||
if kernel_version in {"9.0"} and sample_name.startswith("Practical Malware Analysis Lab 12-04.exe_"):
|
||||
if isinstance(statement, Characteristic) and statement.value == "embedded pe":
|
||||
# see discussion here: https://github.com/mandiant/capa/pull/2742#issuecomment-3667086165
|
||||
#
|
||||
|
||||
@@ -82,7 +82,7 @@ def test_main_non_ascii_filename_nonexistent(tmpdir, caplog):
|
||||
|
||||
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
|
||||
@@ -294,7 +294,11 @@ def extract_cape_report(tmp_path: Path, gz: Path) -> Path:
|
||||
|
||||
|
||||
def test_main_cape1(tmp_path):
|
||||
path = extract_cape_report(tmp_path, fixtures.CD / "./data/dynamic/cape/v2.2/0000a65749f5902c4d82ffa701198038f0b4870b00a27cfca109f8f933476d82.json.gz")
|
||||
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
|
||||
@@ -343,5 +347,8 @@ def test_main_cape1(tmp_path):
|
||||
|
||||
def test_main_cape_gzip():
|
||||
# tests successful execution of .json.gz
|
||||
path = str(fixtures.CD / "./data/dynamic/cape/v2.2/0000a65749f5902c4d82ffa701198038f0b4870b00a27cfca109f8f933476d82.json.gz")
|
||||
path = str(
|
||||
fixtures.CD
|
||||
/ "./data/dynamic/cape/v2.2/0000a65749f5902c4d82ffa701198038f0b4870b00a27cfca109f8f933476d82.json.gz"
|
||||
)
|
||||
assert capa.main.main([path]) == 0
|
||||
|
||||
@@ -21,18 +21,17 @@ import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
import fixtures
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_script_path(s: str):
|
||||
return str(fixtures.CD /".." / "scripts" / s)
|
||||
return str(fixtures.CD / ".." / "scripts" / s)
|
||||
|
||||
|
||||
def get_binary_file_path():
|
||||
return str(fixtures.CD /"data" / "9324d1a8ae37a36ae560c37448c9705a.exe_")
|
||||
return str(fixtures.CD / "data" / "9324d1a8ae37a36ae560c37448c9705a.exe_")
|
||||
|
||||
|
||||
def get_cape_report_file_path():
|
||||
@@ -47,11 +46,11 @@ def get_cape_report_file_path():
|
||||
|
||||
|
||||
def get_binexport2_file_path():
|
||||
return str(fixtures.CD /"data" / "binexport2" / "mimikatz.exe_.ghidra.BinExport")
|
||||
return str(fixtures.CD / "data" / "binexport2" / "mimikatz.exe_.ghidra.BinExport")
|
||||
|
||||
|
||||
def get_rules_path():
|
||||
return str(fixtures.CD /".." / "rules")
|
||||
return str(fixtures.CD / ".." / "rules")
|
||||
|
||||
|
||||
def get_rule_path():
|
||||
@@ -65,7 +64,7 @@ def get_rule_path():
|
||||
pytest.param("capafmt.py", [get_rule_path()]),
|
||||
pytest.param(
|
||||
"capa2sarif.py",
|
||||
[fixtures.CD /"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()]),
|
||||
@@ -108,7 +107,7 @@ def test_bulk_process(tmp_path):
|
||||
t = tmp_path / "test"
|
||||
t.mkdir()
|
||||
|
||||
source_file = fixtures.CD /"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 +126,7 @@ def run_program(script_path, args):
|
||||
def test_proto_conversion(tmp_path):
|
||||
t = tmp_path / "proto-test"
|
||||
t.mkdir()
|
||||
json_file = fixtures.CD /"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
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
import fixtures
|
||||
|
||||
|
||||
|
||||
@fixtures.parametrize_backend_feature_fixtures(
|
||||
fixtures.BackendFeaturePolicy(
|
||||
name="viv",
|
||||
|
||||
@@ -27,6 +27,12 @@ def test_vmray_features(feature_fixture):
|
||||
|
||||
def test_vmray_processes():
|
||||
# see #2394
|
||||
path = fixtures.CD / "data" / "dynamic" / "vmray" / "2f8a79b12a7a989ac7e5f6ec65050036588a92e65aeb6841e08dc228ff0e21b4_min_archive.zip"
|
||||
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