mirror of
https://github.com/mandiant/capa.git
synced 2025-12-12 23:59:48 -08:00
105 lines
3.0 KiB
Python
105 lines
3.0 KiB
Python
# run this script from within IDA with ./tests/data/mimikatz.exe open
|
|
import sys
|
|
import logging
|
|
import os.path
|
|
import binascii
|
|
import traceback
|
|
|
|
import pytest
|
|
|
|
try:
|
|
sys.path.append(os.path.dirname(__file__))
|
|
from fixtures import *
|
|
finally:
|
|
sys.path.pop()
|
|
|
|
|
|
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 sample with MD5: `%s`" % (wanted))
|
|
|
|
|
|
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:
|
|
id = make_test_id((sample, scope, feature, expected))
|
|
|
|
try:
|
|
check_input_file(get_sample_md5_by_name(sample))
|
|
except RuntimeError:
|
|
print("SKIP %s" % (id))
|
|
continue
|
|
|
|
scope = resolve_scope(scope)
|
|
sample = resolve_sample(sample)
|
|
|
|
try:
|
|
do_test_feature_presence(get_ida_extractor, sample, scope, feature, expected)
|
|
except Exception 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")
|
|
def test_ida_feature_counts():
|
|
for (sample, scope, feature, expected) in FEATURE_COUNT_TESTS:
|
|
id = make_test_id((sample, scope, feature, expected))
|
|
|
|
try:
|
|
check_input_file(get_sample_md5_by_name(sample))
|
|
except RuntimeError:
|
|
print("SKIP %s" % (id))
|
|
continue
|
|
|
|
scope = resolve_scope(scope)
|
|
sample = resolve_sample(sample)
|
|
|
|
try:
|
|
do_test_feature_count(get_ida_extractor, sample, scope, feature, expected)
|
|
except Exception as e:
|
|
print("FAIL %s" % (id))
|
|
traceback.print_exc()
|
|
else:
|
|
print("OK %s" % (id))
|
|
|
|
|
|
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()
|
|
test()
|
|
|
|
print("DONE")
|