diff --git a/CHANGELOG.md b/CHANGELOG.md index db5fe728..032ea971 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -70,6 +70,7 @@ - binja: add mypy config for top-level binaryninja module to fix mypy issues @devs6186 #2399 - ci: deprecate macos-13 runner and use Python v3.13 for testing @mike-hunhoff #2777 - ci: pin pip-audit action SHAs and update to v1.1.0 @kami922 #1131 +- tests: use dynamic test sample discovery @williballenthin #1743 ### Raw diffs - [capa v9.3.1...master](https://github.com/mandiant/capa/compare/v9.3.1...master) diff --git a/tests/fixtures.py b/tests/fixtures.py index dc10a284..857b7081 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import os +import hashlib import logging import contextlib import collections @@ -416,164 +418,71 @@ def extract_instruction_features(extractor, fh, bbh, ih) -> dict[Feature, set[Ad return features -# note: to reduce the testing time it's recommended to reuse already existing test samples, if possible +# index from various identifiers to the path to a test fixture file +# supported index facets include: +# - file name (foo.exe) +# - file base name (foo) +# - pma01-01.exe_ +# - md5 prefix (5, 8, all characters) +# - sha256 prefix (5, 8, all characters) +# - parent/file prefix (vmray/12345...) +# - file prefix (12345..., like .json.gz) +fixture_index: dict[str, Path] = {} +for base, _dirs, files in os.walk(CD): + for file in files: + path = Path(os.path.join(base, file)) + + # full name, like: hello_world.exe + fixture_index[path.name.lower()] = path + + # basename, like: hello_world + fixture_index[path.stem.lower()] = path + + if "Practical Malware Analysis Lab " in path.name: + # like: pma01-01.exe_ + fixture_index[path.name.replace("Practical Malware Analysis Lab ", "pma")] = path + + m = hashlib.md5() + m.update(path.read_bytes()) + fixture_index[m.hexdigest()] = path + fixture_index[m.hexdigest()[:5]] = path + + s = hashlib.sha256() + s.update(path.read_bytes()) + fixture_index[s.hexdigest()] = path + fixture_index[s.hexdigest()[:5]] = path + + if path.name.lower()[:8] not in fixture_index: + # like: 0000a657 + # to handle cases like data/dynamic/cape/v2.2/0000a657....json.gz + fixture_index[path.name.lower()[:8]] = path + + # like: drakvuf/12345 + fixture_index[f"{path.parent.name}/{path.name.lower()[:5]}"] = path + + def get_data_path_by_name(name) -> Path: - if name == "mimikatz": - return CD / "data" / "mimikatz.exe_" - elif name == "kernel32": - return CD / "data" / "kernel32.dll_" - elif name == "kernel32-64": - return CD / "data" / "kernel32-64.dll_" - elif name == "pma01-01": - return CD / "data" / "Practical Malware Analysis Lab 01-01.dll_" - elif name == "pma01-01-rd": - return CD / "data" / "rd" / "Practical Malware Analysis Lab 01-01.dll_.json" - elif name == "pma12-04": - return CD / "data" / "Practical Malware Analysis Lab 12-04.exe_" - elif name == "pma16-01": - return CD / "data" / "Practical Malware Analysis Lab 16-01.exe_" - elif name == "pma16-01_binja_db": - return CD / "data" / "Practical Malware Analysis Lab 16-01.exe_.bndb" - elif name == "pma21-01": - return CD / "data" / "Practical Malware Analysis Lab 21-01.exe_" - elif name == "al-khaser x86": - return CD / "data" / "al-khaser_x86.exe_" - elif name == "al-khaser x64": - return CD / "data" / "al-khaser_x64.exe_" - elif name.startswith("39c05"): - return CD / "data" / "39c05b15e9834ac93f206bc114d0a00c357c888db567ba8f5345da0529cbed41.dll_" - elif name.startswith("499c2"): - return CD / "data" / "499c2a85f6e8142c3f48d4251c9c7cd6.raw32" - elif name.startswith("9324d"): - return CD / "data" / "9324d1a8ae37a36ae560c37448c9705a.exe_" - elif name.startswith("395eb"): - return CD / "data" / "395eb0ddd99d2c9e37b6d0b73485ee9c.exe_" - elif name.startswith("a1982"): - return CD / "data" / "a198216798ca38f280dc413f8c57f2c2.exe_" - elif name.startswith("a933a"): - return CD / "data" / "a933a1a402775cfa94b6bee0963f4b46.dll_" - elif name.startswith("bfb9b"): - return CD / "data" / "bfb9b5391a13d0afd787e87ab90f14f5.dll_" - elif name.startswith("c9188"): - return CD / "data" / "c91887d861d9bd4a5872249b641bc9f9.exe_" - elif name.startswith("64d9f"): - return CD / "data" / "64d9f7d96b99467f36e22fada623c3bb.dll_" - elif name.startswith("82bf6"): - return CD / "data" / "82BF6347ACF15E5D883715DC289D8A2B.exe_" - elif name.startswith("pingtaest"): - return CD / "data" / "ping_täst.exe_" - elif name.startswith("77329"): - return CD / "data" / "773290480d5445f11d3dc1b800728966.exe_" - elif name.startswith("3b13b"): - return CD / "data" / "3b13b6f1d7cd14dc4a097a12e2e505c0a4cff495262261e2bfc991df238b9b04.dll_" - elif name == "7351f.elf": - return CD / "data" / "7351f8a40c5450557b24622417fc478d.elf_" - elif name.startswith("79abd"): - return CD / "data" / "79abd17391adc6251ecdc58d13d76baf.dll_" - elif name.startswith("946a9"): - return CD / "data" / "946a99f36a46d335dec080d9a4371940.dll_" - elif name.startswith("2f7f5f"): - return CD / "data" / "2f7f5fb5de175e770d7eae87666f9831.elf_" - elif name.startswith("b9f5b"): - return CD / "data" / "b9f5bd514485fb06da39beff051b9fdc.exe_" - elif name.startswith("mixed-mode-64"): - return DNFILE_TESTFILES / "mixed-mode" / "ModuleCode" / "bin" / "ModuleCode_amd64.exe" - elif name.startswith("hello-world"): - return DNFILE_TESTFILES / "hello-world" / "hello-world.exe" - elif name.startswith("_1c444"): - return DOTNET_DIR / "1c444ebeba24dcba8628b7dfe5fec7c6.exe_" - elif name.startswith("_387f15"): - return DOTNET_DIR / "387f15043f0198fd3a637b0758c2b6dde9ead795c3ed70803426fc355731b173.dll_" - elif name.startswith("_692f"): - return DOTNET_DIR / "692f7fd6d198e804d6af98eb9e390d61.exe_" - elif name.startswith("_0953c"): - return CD / "data" / "0953cc3b77ed2974b09e3a00708f88de931d681e2d0cb64afbaf714610beabe6.exe_" - elif name.startswith("_039a6"): - return CD / "data" / "039a6336d0802a2255669e6867a5679c7eb83313dbc61fb1c7232147379bd304.exe_" - elif name.startswith("b5f052"): - return CD / "data" / "b5f0524e69b3a3cf636c7ac366ca57bf5e3a8fdc8a9f01caf196c611a7918a87.elf_" - elif name.startswith("bf7a9c"): - return CD / "data" / "bf7a9c8bdfa6d47e01ad2b056264acc3fd90cf43fe0ed8deec93ab46b47d76cb.elf_" - elif name.startswith("294b8d"): - return CD / "data" / "294b8db1f2702b60fb2e42fdc50c2cee6a5046112da9a5703a548a4fa50477bc.elf_" - elif name.startswith("2bf18d"): - return CD / "data" / "2bf18d0403677378adad9001b1243211.elf_" - elif name.startswith("0000a657"): - return ( - CD - / "data" - / "dynamic" - / "cape" - / "v2.2" - / "0000a65749f5902c4d82ffa701198038f0b4870b00a27cfca109f8f933476d82.json.gz" - ) - elif name.startswith("d46900"): - return ( - CD - / "data" - / "dynamic" - / "cape" - / "v2.2" - / "d46900384c78863420fb3e297d0a2f743cd2b6b3f7f82bf64059a168e07aceb7.json.gz" - ) - elif name.startswith("93b2d1-drakvuf"): - return ( - CD - / "data" - / "dynamic" - / "drakvuf" - / "93b2d1840566f45fab674ebc79a9d19c88993bcb645e0357f3cb584d16e7c795.log.gz" - ) - elif name.startswith("93b2d1-vmray"): - return ( - CD - / "data" - / "dynamic" - / "vmray" - / "93b2d1840566f45fab674ebc79a9d19c88993bcb645e0357f3cb584d16e7c795_min_archive.zip" - ) - elif name.startswith("2f8a79-vmray"): - return ( - CD - / "data" - / "dynamic" - / "vmray" - / "2f8a79b12a7a989ac7e5f6ec65050036588a92e65aeb6841e08dc228ff0e21b4_min_archive.zip" - ) - elif name.startswith("eb1287-vmray"): - return ( - CD - / "data" - / "dynamic" - / "vmray" - / "eb12873c0ce3e9ea109c2a447956cbd10ca2c3e86936e526b2c6e28764999f21_min_archive.zip" - ) - elif name.startswith("ea2876"): - return CD / "data" / "ea2876e9175410b6f6719f80ee44b9553960758c7d0f7bed73c0fe9a78d8e669.dll_" - elif name.startswith("1038a2"): - return CD / "data" / "1038a23daad86042c66bfe6c9d052d27048de9653bde5750dc0f240c792d9ac8.elf_" - elif name.startswith("3da7c"): - return CD / "data" / "3da7c2c70a2d93ac4643f20339d5c7d61388bddd77a4a5fd732311efad78e535.elf_" - elif name.startswith("nested_typedef"): - return CD / "data" / "dotnet" / "dd9098ff91717f4906afe9dafdfa2f52.exe_" - elif name.startswith("nested_typeref"): - return CD / "data" / "dotnet" / "2c7d60f77812607dec5085973ff76cea.dll_" - elif name.startswith("687e79.ghidra.be2"): - return ( - CD - / "data" - / "binexport2" - / "687e79cde5b0ced75ac229465835054931f9ec438816f2827a8be5f3bd474929.elf_.ghidra.BinExport" - ) - elif name.startswith("d1e650.ghidra.be2"): - return ( - CD - / "data" - / "binexport2" - / "d1e6506964edbfffb08c0dd32e1486b11fbced7a4bd870ffe79f110298f0efb8.elf_.ghidra.BinExport" - ) - else: - raise ValueError(f"unexpected sample fixture: {name}") + try: + return fixture_index[name.rstrip(".")] + except KeyError: + if name.startswith("mixed-mode-64"): + return DNFILE_TESTFILES / "mixed-mode" / "ModuleCode" / "bin" / "ModuleCode_amd64.exe" + elif name.startswith("687e79.ghidra.be2"): + return ( + CD + / "data" + / "binexport2" + / "687e79cde5b0ced75ac229465835054931f9ec438816f2827a8be5f3bd474929.elf_.ghidra.BinExport" + ) + elif name.startswith("d1e650.ghidra.be2"): + return ( + CD + / "data" + / "binexport2" + / "d1e6506964edbfffb08c0dd32e1486b11fbced7a4bd870ffe79f110298f0efb8.elf_.ghidra.BinExport" + ) + else: + raise ValueError(f"unexpected sample fixture: {name}") def resolve_sample(sample): @@ -798,7 +707,7 @@ def parametrize(params, values, **kwargs): FEATURE_PRESENCE_TESTS = sorted( [ # file/characteristic("embedded pe") - ("pma12-04", "file", capa.features.common.Characteristic("embedded pe"), True), + ("pma12-04.exe_", "file", capa.features.common.Characteristic("embedded pe"), True), # file/string ("mimikatz", "file", capa.features.common.String("SCardControl"), True), ("mimikatz", "file", capa.features.common.String("SCardTransmit"), True), @@ -814,7 +723,7 @@ FEATURE_PRESENCE_TESTS = sorted( ("kernel32", "file", capa.features.file.Export("lstrlenW"), True), ("kernel32", "file", capa.features.file.Export("nope"), False), # forwarded export - ("ea2876", "file", capa.features.file.Export("vresion.GetFileVersionInfoA"), True), + ("ea287...", "file", capa.features.file.Export("vresion.GetFileVersionInfoA"), True), # file/imports ("mimikatz", "file", capa.features.file.Import("advapi32.CryptSetHashParam"), True), ("mimikatz", "file", capa.features.file.Import("CryptSetHashParam"), True), @@ -868,7 +777,7 @@ FEATURE_PRESENCE_TESTS = sorted( ("mimikatz", "function=0x40105D", capa.features.insn.Offset(0x4), True), ("mimikatz", "function=0x40105D", capa.features.insn.Offset(0xC), True), # insn/offset, issue #276 - ("64d9f", "function=0x10001510,bb=0x100015B0", capa.features.insn.Offset(0x4000), True), + ("64d9f...", "function=0x10001510,bb=0x100015B0", capa.features.insn.Offset(0x4000), True), # insn/offset: stack references ("mimikatz", "function=0x40105D", capa.features.insn.Offset(0x8), False), ("mimikatz", "function=0x40105D", capa.features.insn.Offset(0x10), False), @@ -924,32 +833,32 @@ FEATURE_PRESENCE_TESTS = sorted( # insn/api: x64 thunk ("kernel32-64", "function=0x1800202B0", capa.features.insn.API("RtlCaptureContext"), True), # insn/api: x64 nested thunk - ("al-khaser x64", "function=0x14004B4F0", capa.features.insn.API("__vcrt_GetModuleHandle"), True), + ("al-khaser_x64", "function=0x14004B4F0", capa.features.insn.API("__vcrt_GetModuleHandle"), True), # insn/api: call via jmp ("mimikatz", "function=0x40B3C6", capa.features.insn.API("LocalFree"), True), - ("c91887...", "function=0x40156F", capa.features.insn.API("CloseClipboard"), True), + ("c9188...", "function=0x40156F", capa.features.insn.API("CloseClipboard"), True), # insn/api: resolve indirect calls # not extracting dll anymore - ("c91887...", "function=0x401A77", capa.features.insn.API("kernel32.CreatePipe"), False), - ("c91887...", "function=0x401A77", capa.features.insn.API("kernel32.SetHandleInformation"), False), - ("c91887...", "function=0x401A77", capa.features.insn.API("kernel32.CloseHandle"), False), - ("c91887...", "function=0x401A77", capa.features.insn.API("kernel32.WriteFile"), False), - ("c91887...", "function=0x401A77", capa.features.insn.API("CreatePipe"), True), - ("c91887...", "function=0x401A77", capa.features.insn.API("SetHandleInformation"), True), - ("c91887...", "function=0x401A77", capa.features.insn.API("CloseHandle"), True), - ("c91887...", "function=0x401A77", capa.features.insn.API("WriteFile"), True), + ("c9188...", "function=0x401A77", capa.features.insn.API("kernel32.CreatePipe"), False), + ("c9188...", "function=0x401A77", capa.features.insn.API("kernel32.SetHandleInformation"), False), + ("c9188...", "function=0x401A77", capa.features.insn.API("kernel32.CloseHandle"), False), + ("c9188...", "function=0x401A77", capa.features.insn.API("kernel32.WriteFile"), False), + ("c9188...", "function=0x401A77", capa.features.insn.API("CreatePipe"), True), + ("c9188...", "function=0x401A77", capa.features.insn.API("SetHandleInformation"), True), + ("c9188...", "function=0x401A77", capa.features.insn.API("CloseHandle"), True), + ("c9188...", "function=0x401A77", capa.features.insn.API("WriteFile"), True), # insn/string ("mimikatz", "function=0x40105D", capa.features.common.String("SCardControl"), True), ("mimikatz", "function=0x40105D", capa.features.common.String("SCardTransmit"), True), ("mimikatz", "function=0x40105D", capa.features.common.String("ACR > "), True), ("mimikatz", "function=0x40105D", capa.features.common.String("nope"), False), - ("773290...", "function=0x140001140", capa.features.common.String(r"%s:\\OfficePackagesForWDAG"), True), + ("77329...", "function=0x140001140", capa.features.common.String(r"%s:\\OfficePackagesForWDAG"), True), # overlapping string, see #1271 - ("294b8d...", "function=0x404970,bb=0x404970,insn=0x40499F", capa.features.common.String("\r\n\x00:ht"), False), + ("294b8...", "function=0x404970,bb=0x404970,insn=0x40499F", capa.features.common.String("\r\n\x00:ht"), False), # insn/regex - ("pma16-01", "function=0x4021B0", capa.features.common.Regex("HTTP/1.0"), True), - ("pma16-01", "function=0x402F40", capa.features.common.Regex("www.practicalmalwareanalysis.com"), True), - ("pma16-01", "function=0x402F40", capa.features.common.Substring("practicalmalwareanalysis.com"), True), + ("pma16-01.exe_", "function=0x4021B0", capa.features.common.Regex("HTTP/1.0"), True), + ("pma16-01.exe_", "function=0x402F40", capa.features.common.Regex("www.practicalmalwareanalysis.com"), True), + ("pma16-01.exe_", "function=0x402F40", capa.features.common.Substring("practicalmalwareanalysis.com"), True), # insn/string, pointer to string ("mimikatz", "function=0x44EDEF", capa.features.common.String("INPUTEVENT"), True), # insn/string, direct memory reference @@ -1000,39 +909,39 @@ FEATURE_PRESENCE_TESTS = sorted( # function/characteristic(calls to) ("mimikatz", "function=0x40105D", capa.features.common.Characteristic("calls to"), True), # function/characteristic(forwarded export) - ("ea2876", "file", capa.features.common.Characteristic("forwarded export"), True), + ("ea287", "file", capa.features.common.Characteristic("forwarded export"), True), # before this we used ambiguous (0x4556E5, False), which has a data reference / indirect recursive call, see #386 ("mimikatz", "function=0x456BB9", capa.features.common.Characteristic("calls to"), False), # file/function-name - ("pma16-01", "file", capa.features.file.FunctionName("__aulldiv"), True), + ("pma16-01.exe_", "file", capa.features.file.FunctionName("__aulldiv"), True), # os & format & arch - ("pma16-01", "file", OS(OS_WINDOWS), True), - ("pma16-01", "file", OS(OS_LINUX), False), + ("pma16-01.exe_", "file", OS(OS_WINDOWS), True), + ("pma16-01.exe_", "file", OS(OS_LINUX), False), ("mimikatz", "file", OS(OS_WINDOWS), True), - ("pma16-01", "function=0x401100", OS(OS_WINDOWS), True), - ("pma16-01", "function=0x401100,bb=0x401130", OS(OS_WINDOWS), True), + ("pma16-01.exe_", "function=0x401100", OS(OS_WINDOWS), True), + ("pma16-01.exe_", "function=0x401100,bb=0x401130", OS(OS_WINDOWS), True), ("mimikatz", "function=0x40105D", OS(OS_WINDOWS), True), - ("pma16-01", "file", Arch(ARCH_I386), True), - ("pma16-01", "file", Arch(ARCH_AMD64), False), + ("pma16-01.exe_", "file", Arch(ARCH_I386), True), + ("pma16-01.exe_", "file", Arch(ARCH_AMD64), False), ("mimikatz", "file", Arch(ARCH_I386), True), - ("pma16-01", "function=0x401100", Arch(ARCH_I386), True), - ("pma16-01", "function=0x401100,bb=0x401130", Arch(ARCH_I386), True), + ("pma16-01.exe_", "function=0x401100", Arch(ARCH_I386), True), + ("pma16-01.exe_", "function=0x401100,bb=0x401130", Arch(ARCH_I386), True), ("mimikatz", "function=0x40105D", Arch(ARCH_I386), True), - ("pma16-01", "file", Format(FORMAT_PE), True), - ("pma16-01", "file", Format(FORMAT_ELF), False), + ("pma16-01.exe_", "file", Format(FORMAT_PE), True), + ("pma16-01.exe_", "file", Format(FORMAT_ELF), False), ("mimikatz", "file", Format(FORMAT_PE), True), # format is also a global feature - ("pma16-01", "function=0x401100", Format(FORMAT_PE), True), + ("pma16-01.exe_", "function=0x401100", Format(FORMAT_PE), True), ("mimikatz", "function=0x456BB9", Format(FORMAT_PE), True), # elf support - ("7351f.elf", "file", OS(OS_LINUX), True), - ("7351f.elf", "file", OS(OS_WINDOWS), False), - ("7351f.elf", "file", Format(FORMAT_ELF), True), - ("7351f.elf", "file", Format(FORMAT_PE), False), - ("7351f.elf", "file", Arch(ARCH_I386), False), - ("7351f.elf", "file", Arch(ARCH_AMD64), True), - ("7351f.elf", "function=0x408753", capa.features.common.String("/dev/null"), True), - ("7351f.elf", "function=0x408753,bb=0x408781", capa.features.insn.API("open"), True), + ("7351f...", "file", OS(OS_LINUX), True), + ("7351f...", "file", OS(OS_WINDOWS), False), + ("7351f...", "file", Format(FORMAT_ELF), True), + ("7351f...", "file", Format(FORMAT_PE), False), + ("7351f...", "file", Arch(ARCH_I386), False), + ("7351f...", "file", Arch(ARCH_AMD64), True), + ("7351f...", "function=0x408753", capa.features.common.String("/dev/null"), True), + ("7351f...", "function=0x408753,bb=0x408781", capa.features.insn.API("open"), True), ("79abd...", "function=0x10002385,bb=0x10002385", capa.features.common.Characteristic("call $+5"), True), ("946a9...", "function=0x10001510,bb=0x100015c0", capa.features.common.Characteristic("call $+5"), True), ], @@ -1106,68 +1015,73 @@ FEATURE_PRESENCE_TESTS_DOTNET = sorted( ("hello-world", "function=0x250, bb=0x250, insn=0x257", capa.features.common.Namespace("System"), True), ("hello-world", "function=0x250", capa.features.insn.API("System.Console::WriteLine"), True), ("hello-world", "file", capa.features.file.Import("System.Console::WriteLine"), True), - ("_1c444", "file", capa.features.common.String(r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"), True), - ("_1c444", "file", capa.features.common.String("get_IsAlive"), True), - ("_1c444", "file", capa.features.file.Import("gdi32.CreateCompatibleBitmap"), True), - ("_1c444", "file", capa.features.file.Import("CreateCompatibleBitmap"), True), - ("_1c444", "file", capa.features.file.Import("gdi32::CreateCompatibleBitmap"), False), - ("_1c444", "function=0x1F68", capa.features.insn.API("GetWindowDC"), True), + ("1c444...", "file", capa.features.common.String(r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"), True), + ("1c444...", "file", capa.features.common.String("get_IsAlive"), True), + ("1c444...", "file", capa.features.file.Import("gdi32.CreateCompatibleBitmap"), True), + ("1c444...", "file", capa.features.file.Import("CreateCompatibleBitmap"), True), + ("1c444...", "file", capa.features.file.Import("gdi32::CreateCompatibleBitmap"), False), + ("1c444...", "function=0x1F68", capa.features.insn.API("GetWindowDC"), True), # not extracting dll anymore - ("_1c444", "function=0x1F68", capa.features.insn.API("user32.GetWindowDC"), False), - ("_1c444", "function=0x1F68", capa.features.insn.Number(0xCC0020), True), - ("_1c444", "token=0x600001D", capa.features.common.Characteristic("calls to"), True), - ("_1c444", "token=0x6000018", capa.features.common.Characteristic("calls to"), False), - ("_1c444", "token=0x600001D", capa.features.common.Characteristic("calls from"), True), - ("_1c444", "token=0x600000F", capa.features.common.Characteristic("calls from"), False), - ("_1c444", "function=0x1F68", capa.features.insn.Number(0x0), True), - ("_1c444", "function=0x1F68", capa.features.insn.Number(0x1), False), - ("_692f", "token=0x6000004", capa.features.insn.API("System.Linq.Enumerable::First"), True), # generic method + ("1c444...", "function=0x1F68", capa.features.insn.API("user32.GetWindowDC"), False), + ("1c444...", "function=0x1F68", capa.features.insn.Number(0xCC0020), True), + ("1c444...", "token=0x600001D", capa.features.common.Characteristic("calls to"), True), + ("1c444...", "token=0x6000018", capa.features.common.Characteristic("calls to"), False), + ("1c444...", "token=0x600001D", capa.features.common.Characteristic("calls from"), True), + ("1c444...", "token=0x600000F", capa.features.common.Characteristic("calls from"), False), + ("1c444...", "function=0x1F68", capa.features.insn.Number(0x0), True), + ("1c444...", "function=0x1F68", capa.features.insn.Number(0x1), False), ( - "_692f", + "692f7...", + "token=0x6000004", + capa.features.insn.API("System.Linq.Enumerable::First"), + True, + ), # generic method + ( + "692f7...", "token=0x6000004", capa.features.insn.Property("System.Linq.Enumerable::First"), False, ), # generic method - ("_692f", "token=0x6000004", capa.features.common.Namespace("System.Linq"), True), # generic method - ("_692f", "token=0x6000004", capa.features.common.Class("System.Linq.Enumerable"), True), # generic method - ("_1c444", "token=0x6000020", capa.features.common.Namespace("Reqss"), True), # ldftn - ("_1c444", "token=0x6000020", capa.features.common.Class("Reqss.Reqss"), True), # ldftn + ("692f7...", "token=0x6000004", capa.features.common.Namespace("System.Linq"), True), # generic method + ("692f7...", "token=0x6000004", capa.features.common.Class("System.Linq.Enumerable"), True), # generic method + ("1c444...", "token=0x6000020", capa.features.common.Namespace("Reqss"), True), # ldftn + ("1c444...", "token=0x6000020", capa.features.common.Class("Reqss.Reqss"), True), # ldftn ( - "_1c444", + "1c444...", "function=0x1F59, bb=0x1F59, insn=0x1F5B", capa.features.common.Characteristic("unmanaged call"), True, ), - ("_1c444", "function=0x2544", capa.features.common.Characteristic("unmanaged call"), False), + ("1c444...", "function=0x2544", capa.features.common.Characteristic("unmanaged call"), False), # same as above but using token instead of function - ("_1c444", "token=0x6000088", capa.features.common.Characteristic("unmanaged call"), False), + ("1c444...", "token=0x6000088", capa.features.common.Characteristic("unmanaged call"), False), ( - "_1c444", + "1c444...", "function=0x1F68, bb=0x1F68, insn=0x1FF9", capa.features.insn.API("System.Drawing.Image::FromHbitmap"), True, ), - ("_1c444", "function=0x1F68, bb=0x1F68, insn=0x1FF9", capa.features.insn.API("FromHbitmap"), False), + ("1c444...", "function=0x1F68, bb=0x1F68, insn=0x1FF9", capa.features.insn.API("FromHbitmap"), False), ( - "_1c444", + "1c444...", "token=0x600002B", capa.features.insn.Property("System.IO.FileInfo::Length", access=FeatureAccess.READ), True, ), # MemberRef property access ( - "_1c444", + "1c444...", "token=0x600002B", capa.features.insn.Property("System.IO.FileInfo::Length"), True, ), # MemberRef property access ( - "_1c444", + "1c444...", "token=0x6000081", capa.features.insn.API("System.Diagnostics.Process::Start"), True, ), # MemberRef property access ( - "_1c444", + "1c444...", "token=0x6000081", capa.features.insn.Property( "System.Diagnostics.ProcessStartInfo::UseShellExecute", access=FeatureAccess.WRITE @@ -1175,7 +1089,7 @@ FEATURE_PRESENCE_TESTS_DOTNET = sorted( True, ), ( - "_1c444", + "1c444...", "token=0x6000081", capa.features.insn.Property( "System.Diagnostics.ProcessStartInfo::WorkingDirectory", access=FeatureAccess.WRITE @@ -1183,7 +1097,7 @@ FEATURE_PRESENCE_TESTS_DOTNET = sorted( True, ), ( - "_1c444", + "1c444...", "token=0x6000081", capa.features.insn.Property( "System.Diagnostics.ProcessStartInfo::FileName", access=FeatureAccess.WRITE @@ -1191,7 +1105,7 @@ FEATURE_PRESENCE_TESTS_DOTNET = sorted( True, ), ( - "_1c444", + "1c444...", "token=0x6000087", capa.features.insn.Property( "Sockets.MySocket::reConnectionDelay", access=FeatureAccess.WRITE @@ -1199,7 +1113,7 @@ FEATURE_PRESENCE_TESTS_DOTNET = sorted( True, ), ( - "_1c444", + "1c444...", "token=0x600008A", capa.features.insn.Property( "Sockets.MySocket::isConnected", access=FeatureAccess.WRITE @@ -1207,19 +1121,19 @@ FEATURE_PRESENCE_TESTS_DOTNET = sorted( True, ), ( - "_1c444", + "1c444...", "token=0x600008A", capa.features.common.Class("Sockets.MySocket"), # Field property access True, ), ( - "_1c444", + "1c444...", "token=0x600008A", capa.features.common.Namespace("Sockets"), # Field property access True, ), ( - "_1c444", + "1c444...", "token=0x600008A", capa.features.insn.Property( "Sockets.MySocket::onConnected", access=FeatureAccess.READ @@ -1227,7 +1141,7 @@ FEATURE_PRESENCE_TESTS_DOTNET = sorted( True, ), ( - "_0953c", + "0953c...", "token=0x6000004", capa.features.insn.Property( "System.Diagnostics.Debugger::IsAttached", access=FeatureAccess.READ @@ -1235,19 +1149,19 @@ FEATURE_PRESENCE_TESTS_DOTNET = sorted( True, ), ( - "_0953c", + "0953c...", "token=0x6000004", capa.features.common.Class("System.Diagnostics.Debugger"), # MemberRef property access True, ), ( - "_0953c", + "0953c...", "token=0x6000004", capa.features.common.Namespace("System.Diagnostics"), # MemberRef property access True, ), ( - "_692f", + "692f7...", "token=0x6000006", capa.features.insn.Property( "System.Management.Automation.PowerShell::Streams", access=FeatureAccess.READ @@ -1255,7 +1169,7 @@ FEATURE_PRESENCE_TESTS_DOTNET = sorted( False, ), ( - "_387f15", + "387f1...", "token=0x600009E", capa.features.insn.Property( "Modulo.IqQzcRDvSTulAhyLtZHqyeYGgaXGbuLwhxUKXYmhtnOmgpnPJDTSIPhYPpnE::geoplugin_countryCode", @@ -1264,7 +1178,7 @@ FEATURE_PRESENCE_TESTS_DOTNET = sorted( True, ), ( - "_387f15", + "387f1...", "token=0x600009E", capa.features.common.Class( "Modulo.IqQzcRDvSTulAhyLtZHqyeYGgaXGbuLwhxUKXYmhtnOmgpnPJDTSIPhYPpnE" @@ -1272,31 +1186,31 @@ FEATURE_PRESENCE_TESTS_DOTNET = sorted( True, ), ( - "_387f15", + "387f1...", "token=0x600009E", capa.features.common.Namespace("Modulo"), # MethodDef property access True, ), ( - "_039a6", + "039a6...", "token=0x6000007", capa.features.insn.API("System.Reflection.Assembly::Load"), True, ), ( - "_039a6", + "039a6...", "token=0x600001D", capa.features.insn.Property("StagelessHollow.Arac::Marka", access=FeatureAccess.READ), # MethodDef method True, ), ( - "_039a6", + "039a6...", "token=0x600001C", capa.features.insn.Property("StagelessHollow.Arac::Marka", access=FeatureAccess.READ), # MethodDef method False, ), ( - "_039a6", + "039a6...", "token=0x6000023", capa.features.insn.Property( "System.Runtime.CompilerServices.AsyncTaskMethodBuilder::Task", access=FeatureAccess.READ @@ -1304,109 +1218,109 @@ FEATURE_PRESENCE_TESTS_DOTNET = sorted( False, ), ( - "nested_typedef", + "dd909...", "file", capa.features.common.Class("mynamespace.myclass_outer0"), True, ), ( - "nested_typedef", + "dd909...", "file", capa.features.common.Class("mynamespace.myclass_outer1"), True, ), ( - "nested_typedef", + "dd909...", "file", capa.features.common.Class("mynamespace.myclass_outer0/myclass_inner0_0"), True, ), ( - "nested_typedef", + "dd909...", "file", capa.features.common.Class("mynamespace.myclass_outer0/myclass_inner0_1"), True, ), ( - "nested_typedef", + "dd909...", "file", capa.features.common.Class("mynamespace.myclass_outer1/myclass_inner1_0"), True, ), ( - "nested_typedef", + "dd909...", "file", capa.features.common.Class("mynamespace.myclass_outer1/myclass_inner1_1"), True, ), ( - "nested_typedef", + "dd909...", "file", capa.features.common.Class("mynamespace.myclass_outer1/myclass_inner1_0/myclass_inner_inner"), True, ), ( - "nested_typedef", + "dd909...", "file", capa.features.common.Class("myclass_inner_inner"), False, ), ( - "nested_typedef", + "dd909...", "file", capa.features.common.Class("myclass_inner1_0"), False, ), ( - "nested_typedef", + "dd909...", "file", capa.features.common.Class("myclass_inner1_1"), False, ), ( - "nested_typedef", + "dd909...", "file", capa.features.common.Class("myclass_inner0_0"), False, ), ( - "nested_typedef", + "dd909...", "file", capa.features.common.Class("myclass_inner0_1"), False, ), ( - "nested_typeref", + "2c7d6...", "file", capa.features.file.Import("Android.OS.Build/VERSION::SdkInt"), True, ), ( - "nested_typeref", + "2c7d6...", "file", capa.features.file.Import("Android.Media.Image/Plane::Buffer"), True, ), ( - "nested_typeref", + "2c7d6...", "file", capa.features.file.Import("Android.Provider.Telephony/Sent/Sent::ContentUri"), True, ), ( - "nested_typeref", + "2c7d6...", "file", capa.features.file.Import("Android.OS.Build::SdkInt"), False, ), ( - "nested_typeref", + "2c7d6...", "file", capa.features.file.Import("Plane::Buffer"), False, ), ( - "nested_typeref", + "2c7d6...", "file", capa.features.file.Import("Sent::ContentUri"), False, @@ -1426,33 +1340,33 @@ FEATURE_PRESENCE_TESTS_IDA = [ FEATURE_BINJA_DATABASE_TESTS = sorted( [ # insn/regex - ("pma16-01_binja_db", "function=0x4021B0", capa.features.common.Regex("HTTP/1.0"), True), + ("pma16-01.exe_.bndb", "function=0x4021B0", capa.features.common.Regex("HTTP/1.0"), True), ( - "pma16-01_binja_db", + "pma16-01.exe_.bndb", "function=0x402F40", capa.features.common.Regex("www.practicalmalwareanalysis.com"), True, ), ( - "pma16-01_binja_db", + "pma16-01.exe_.bndb", "function=0x402F40", capa.features.common.Substring("practicalmalwareanalysis.com"), True, ), - ("pma16-01_binja_db", "file", capa.features.file.FunctionName("__aulldiv"), True), + ("pma16-01.exe_.bndb", "file", capa.features.file.FunctionName("__aulldiv"), True), # os & format & arch - ("pma16-01_binja_db", "file", OS(OS_WINDOWS), True), - ("pma16-01_binja_db", "file", OS(OS_LINUX), False), - ("pma16-01_binja_db", "function=0x404356", OS(OS_WINDOWS), True), - ("pma16-01_binja_db", "function=0x404356,bb=0x4043B9", OS(OS_WINDOWS), True), - ("pma16-01_binja_db", "file", Arch(ARCH_I386), True), - ("pma16-01_binja_db", "file", Arch(ARCH_AMD64), False), - ("pma16-01_binja_db", "function=0x404356", Arch(ARCH_I386), True), - ("pma16-01_binja_db", "function=0x404356,bb=0x4043B9", Arch(ARCH_I386), True), - ("pma16-01_binja_db", "file", Format(FORMAT_PE), True), - ("pma16-01_binja_db", "file", Format(FORMAT_ELF), False), + ("pma16-01.exe_.bndb", "file", OS(OS_WINDOWS), True), + ("pma16-01.exe_.bndb", "file", OS(OS_LINUX), False), + ("pma16-01.exe_.bndb", "function=0x404356", OS(OS_WINDOWS), True), + ("pma16-01.exe_.bndb", "function=0x404356,bb=0x4043B9", OS(OS_WINDOWS), True), + ("pma16-01.exe_.bndb", "file", Arch(ARCH_I386), True), + ("pma16-01.exe_.bndb", "file", Arch(ARCH_AMD64), False), + ("pma16-01.exe_.bndb", "function=0x404356", Arch(ARCH_I386), True), + ("pma16-01.exe_.bndb", "function=0x404356,bb=0x4043B9", Arch(ARCH_I386), True), + ("pma16-01.exe_.bndb", "file", Format(FORMAT_PE), True), + ("pma16-01.exe_.bndb", "file", Format(FORMAT_ELF), False), # format is also a global feature - ("pma16-01_binja_db", "function=0x404356", Format(FORMAT_PE), True), + ("pma16-01.exe_.bndb", "function=0x404356", Format(FORMAT_PE), True), ], # order tests by (file, item) # so that our LRU cache is most effective. @@ -1470,8 +1384,8 @@ FEATURE_COUNT_TESTS = [ FEATURE_COUNT_TESTS_DOTNET = [ - ("_1c444", "token=0x600001D", capa.features.common.Characteristic("calls to"), 1), - ("_1c444", "token=0x600001D", capa.features.common.Characteristic("calls from"), 9), + ("1c444...", "token=0x600001D", capa.features.common.Characteristic("calls to"), 1), + ("1c444...", "token=0x600001D", capa.features.common.Characteristic("calls from"), 9), ] @@ -1539,12 +1453,12 @@ def z395eb_extractor(): @pytest.fixture def pma12_04_extractor(): - return get_extractor(get_data_path_by_name("pma12-04")) + return get_extractor(get_data_path_by_name("pma12-04.exe_")) @pytest.fixture def pma16_01_extractor(): - return get_extractor(get_data_path_by_name("pma16-01")) + return get_extractor(get_data_path_by_name("pma16-01.exe_")) @pytest.fixture @@ -1554,7 +1468,7 @@ def bfb9b_extractor(): @pytest.fixture def pma21_01_extractor(): - return get_extractor(get_data_path_by_name("pma21-01")) + return get_extractor(get_data_path_by_name("pma21-01.exe_")) @pytest.fixture @@ -1574,12 +1488,12 @@ def z499c2_extractor(): @pytest.fixture def al_khaser_x86_extractor(): - return get_extractor(get_data_path_by_name("al-khaser x86")) + return get_extractor(get_data_path_by_name("al-khaser_x86")) @pytest.fixture def pingtaest_extractor(): - return get_extractor(get_data_path_by_name("pingtaest")) + return get_extractor(get_data_path_by_name("ping_täst")) @pytest.fixture @@ -1599,22 +1513,22 @@ def hello_world_dotnetfile_extractor(): @pytest.fixture def _1c444_dotnetfile_extractor(): - return get_dnfile_extractor(get_data_path_by_name("_1c444")) + return get_dnfile_extractor(get_data_path_by_name("1c444...")) @pytest.fixture def _692f_dotnetfile_extractor(): - return get_dnfile_extractor(get_data_path_by_name("_692f")) + return get_dnfile_extractor(get_data_path_by_name("692f7...")) @pytest.fixture def _0953c_dotnetfile_extractor(): - return get_dnfile_extractor(get_data_path_by_name("_0953c")) + return get_dnfile_extractor(get_data_path_by_name("0953c...")) @pytest.fixture def _039a6_dotnetfile_extractor(): - return get_dnfile_extractor(get_data_path_by_name("_039a6")) + return get_dnfile_extractor(get_data_path_by_name("039a6...")) def get_result_doc(path: Path): diff --git a/tests/test_freeze_dynamic.py b/tests/test_freeze_dynamic.py index 74129f4f..8c30a6b0 100644 --- a/tests/test_freeze_dynamic.py +++ b/tests/test_freeze_dynamic.py @@ -158,7 +158,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.get_data_path_by_name("d4690...")) Path(o.strpath).write_bytes(capa.features.freeze.dump(extractor)) diff --git a/tests/test_main.py b/tests/test_main.py index 72ebd762..ddb3edf3 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -227,7 +227,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.get_data_path_by_name("pma01-01.dll_")) assert capa.main.main([path, "-j"]) == 0 std = capsys.readouterr() std_json = json.loads(std.out) @@ -271,7 +271,7 @@ def test_main_dotnet4(_039a6_dotnetfile_extractor): def test_main_rd(): - path = str(fixtures.get_data_path_by_name("pma01-01-rd")) + path = str(fixtures.get_data_path_by_name("pma01-01.dll_.json")) assert capa.main.main([path, "-vv"]) == 0 assert capa.main.main([path, "-v"]) == 0 assert capa.main.main([path, "-j"]) == 0 diff --git a/tests/test_result_document.py b/tests/test_result_document.py index 7775c033..e7b304be 100644 --- a/tests/test_result_document.py +++ b/tests/test_result_document.py @@ -279,12 +279,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.get_data_path_by_name("pma01-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.get_data_path_by_name("pma01-01.dll_.json") rd = rdoc.ResultDocument.from_file(path) diff --git a/tests/test_vmray_features.py b/tests/test_vmray_features.py index bf035b83..ae84d22a 100644 --- a/tests/test_vmray_features.py +++ b/tests/test_vmray_features.py @@ -35,7 +35,7 @@ DYNAMIC_VMRAY_FEATURE_PRESENCE_TESTS = sorted( ("93b2d1-vmray", "process=(2176:0),thread=2420", capa.features.insn.API("DoesNotExist"), False), # call/api ("93b2d1-vmray", "process=(2176:0),thread=2420,call=2361", capa.features.insn.API("GetAddrInfoW"), True), - ("eb1287-vmray", "process=(4968:0),thread=5992,call=10981", capa.features.insn.API("CreateMutexW"), True), + ("vmray/eb1287...", "process=(4968:0),thread=5992,call=10981", capa.features.insn.API("CreateMutexW"), True), # call/string argument ( "93b2d1-vmray",