mirror of
https://github.com/mandiant/capa.git
synced 2025-12-21 23:00:29 -08:00
87 lines
2.7 KiB
Python
87 lines
2.7 KiB
Python
# run this script from within IDA with ./tests/data/mimikatz.exe open
|
|
import logging
|
|
import binascii
|
|
import traceback
|
|
import collections
|
|
|
|
import pytest
|
|
from fixtures import *
|
|
|
|
import capa.features
|
|
import capa.features.file
|
|
import capa.features.insn
|
|
import capa.features.basicblock
|
|
from capa.features import ARCH_X32, ARCH_X64
|
|
|
|
logger = logging.getLogger("test_ida_features")
|
|
|
|
|
|
def check_input_file(wanted):
|
|
import idautils
|
|
|
|
# some versions (7.4) of IDA return a truncated version of the MD5.
|
|
# https://github.com/idapython/bin/issues/11
|
|
try:
|
|
found = idautils.GetInputFileMD5()[:31].decode("ascii").lower()
|
|
except UnicodeDecodeError:
|
|
# in IDA 7.5 or so, GetInputFileMD5 started returning raw binary
|
|
# rather than the hex digest
|
|
found = binascii.hexlify(idautils.GetInputFileMD5()[:15]).decode("ascii").lower()
|
|
if not wanted.startswith(found):
|
|
raise RuntimeError("please run the tests against `mimikatz.exe`")
|
|
|
|
|
|
def get_ida_extractor(_path):
|
|
check_input_file("5f66b82558ca92e54e77f216ef4c066c")
|
|
|
|
# have to import import this inline so pytest doesn't bail outside of IDA
|
|
import capa.features.extractors.ida
|
|
|
|
return capa.features.extractors.ida.IdaFeatureExtractor()
|
|
|
|
|
|
@pytest.mark.skip(reason="IDA Pro tests must be run within IDA")
|
|
def test_ida_features():
|
|
for (sample, scope, feature, expected) in FEATURE_PRESENCE_TESTS:
|
|
# resolve sample
|
|
# resolve scope
|
|
pass
|
|
|
|
id = make_test_id((sample, scope, feature, expected))
|
|
|
|
try:
|
|
do_test_feature_presence(get_ida_extractor, sample, scope, feature, expected)
|
|
except AssertionError as e:
|
|
print("FAIL %s" % (id))
|
|
traceback.print_exc()
|
|
else:
|
|
print("OK %s" % (id))
|
|
|
|
|
|
@pytest.mark.skip(reason="IDA Pro tests must be run within IDA")
|
|
@parametrize(
|
|
"sample,scope,feature,expected", FEATURE_COUNT_TESTS, indirect=["sample", "scope"],
|
|
)
|
|
def test_ida_feature_counts(sample, scope, feature, expected):
|
|
do_test_feature_count(get_ida_extractor, sample, scope, feature, expected)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
print("-" * 80)
|
|
|
|
# invoke all functions in this module that start with `test_`
|
|
for name in dir(sys.modules[__name__]):
|
|
if not name.startswith("test_"):
|
|
continue
|
|
|
|
test = getattr(sys.modules[__name__], name)
|
|
logger.debug("invoking test: %s", name)
|
|
sys.stderr.flush()
|
|
try:
|
|
test()
|
|
except AssertionError as e:
|
|
print("FAIL %s" % (name))
|
|
traceback.print_exc()
|
|
else:
|
|
print("OK %s" % (name))
|