From a162fceed44372864d4e2857dae2b76112bec88f Mon Sep 17 00:00:00 2001 From: Abyss Watcher Date: Tue, 4 Mar 2025 16:54:11 +0100 Subject: [PATCH] migrate windows and linux tests to dedicated files --- test/plugins/linux/__init__.py | 0 test/plugins/linux/linux.py | 617 ++++++++++++++++++++++++ test/plugins/windows/windows.py | 326 +++++++++++++ test/test_volatility.py | 800 +------------------------------- 4 files changed, 944 insertions(+), 799 deletions(-) create mode 100644 test/plugins/linux/__init__.py create mode 100644 test/plugins/linux/linux.py create mode 100644 test/plugins/windows/windows.py diff --git a/test/plugins/linux/__init__.py b/test/plugins/linux/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/test/plugins/linux/linux.py b/test/plugins/linux/linux.py new file mode 100644 index 000000000..8ec485735 --- /dev/null +++ b/test/plugins/linux/linux.py @@ -0,0 +1,617 @@ +import contextlib +import tempfile +import os +import re +from test import test_volatility, LinuxSamples + + +class TestLinuxVolshell: + def test_linux_volshell(self, image, volatility, python): + out = test_volatility.basic_volshell_test( + image, volatility, python, globalargs=("-l",) + ) + assert out.count(b" 100 + + +class TestLinuxPslist: + def test_linux_generic_pslist(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.pslist.PsList", image, volatility, python + ) + + assert rc == 0 + out = out.lower() + assert (out.find(b"init") != -1) or (out.find(b"systemd") != -1) + assert out.find(b"watchdog") != -1 + assert out.count(b"\n") > 10 + + +class TestLinuxCheckIdt: + def test_linux_generic_check_idt(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.check_idt.Check_idt", image, volatility, python + ) + + assert rc == 0 + out = out.lower() + assert out.count(b"__kernel__") >= 10 + assert out.count(b"\n") > 10 + + +class TestLinuxCheckSyscall: + def test_linux_generic_check_syscall(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.check_syscall.Check_syscall", image, volatility, python + ) + + assert rc == 0 + out = out.lower() + assert out.find(b"sys_close") != -1 + assert out.find(b"sys_open") != -1 + assert out.count(b"\n") > 100 + + +class TestLinuxLsmod: + def test_linux_generic_lsmod(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.lsmod.Lsmod", image, volatility, python + ) + + assert rc == 0 + out = out.lower() + assert out.count(b"\n") > 10 + + +class TestLinuxLsof: + def test_linux_generic_lsof(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.lsof.Lsof", image, volatility, python + ) + + assert rc == 0 + out = out.lower() + assert out.count(b"socket:") >= 10 + assert out.count(b"\n") > 35 + + +class TestLinuxProcMaps: + def test_linux_generic_proc_maps(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.proc.Maps", image, volatility, python + ) + + assert rc == 0 + out = out.lower() + assert out.count(b"anonymous mapping") >= 10 + assert out.count(b"\n") > 100 + + +class TestLinuxTtyCheck: + def test_linux_generic_tty_check(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.tty_check.tty_check", image, volatility, python + ) + + assert rc == 0 + out = out.lower() + assert out.find(b"__kernel__") != -1 + assert out.count(b"\n") >= 5 + + +class TestLinuxSockstat: + def test_linux_generic_sockstat(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.sockstat.Sockstat", image, volatility, python + ) + + assert rc == 0 + assert out.count(b"AF_UNIX") >= 354 + assert out.count(b"AF_BLUETOOTH") >= 5 + assert out.count(b"AF_INET") >= 32 + assert out.count(b"AF_INET6") >= 20 + assert out.count(b"AF_PACKET") >= 1 + assert out.count(b"AF_NETLINK") >= 43 + + +class TestLinuxLibraryList: + def test_linux_specific_library_list(self, volatility, python): + image = LinuxSamples.LINUX_GENERIC.value.path + rc, out, _err = test_volatility.runvol_plugin( + "linux.library_list.LibraryList", + image, + volatility, + python, + pluginargs=("--pids", "2363"), + ) + + assert rc == 0 + assert re.search( + rb"NetworkManager\s2363\s0x7f52cdda0000\s/lib/x86_64-linux-gnu/libnss_files.so.2", + out, + ) + + assert out.count(b"\n") > 10 + + +class TestLinuxPstree: + def test_linux_generic_pstree(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.pstree.PsTree", image, volatility, python + ) + + assert rc == 0 + out = out.lower() + assert (out.find(b"init") != -1) or (out.find(b"systemd") != -1) + assert out.count(b"\n") > 10 + + +class TestLinuxPidhashtable: + def test_linux_generic_pidhashtable(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.pidhashtable.PIDHashTable", image, volatility, python + ) + + assert rc == 0 + out = out.lower() + assert (out.find(b"init") != -1) or (out.find(b"systemd") != -1) + assert out.count(b"\n") > 10 + + +class TestLinuxBash: + def test_linux_bash(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.bash.Bash", image, volatility, python + ) + + assert rc == 0 + assert out.count(b"\n") > 10 + + +class TestLinuxBoottime: + def test_linux_generic_boottime(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.boottime.Boottime", image, volatility, python + ) + + assert rc == 0 + out = out.lower() + assert out.count(b"utc") >= 1 + + +class TestLinuxCapabilities: + def test_linux_generic_capabilities(self, image, volatility, python): + rc, out, err = test_volatility.runvol_plugin( + "linux.capabilities.Capabilities", + image, + volatility, + python, + globalargs=("-vvv",), + ) + + if rc != 0 and err.count(b"Unsupported kernel capabilities implementation") > 0: + # The linux-sample-1.bin kernel implementation isn't supported. + # However, we can still check that the plugin requirements are met. + return None + + assert rc == 0 + assert out.count(b"\n") > 10 + + +class TestLinuxCheckCreds: + def test_linux_generic_check_creds(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.check_creds.Check_creds", image, volatility, python + ) + + # linux-sample-1.bin has no processes sharing credentials. + # This validates that plugin requirements are met and exceptions are not raised. + assert rc == 0 + assert out.count(b"\n") >= 4 + + +class TestLinuxElfs: + def test_linux_generic_elfs(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.elfs.Elfs", image, volatility, python + ) + + assert rc == 0 + assert out.count(b"\n") > 10 + + +class TestLinuxEnvars: + def test_linux_generic_envars(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.envars.Envars", image, volatility, python + ) + + assert rc == 0 + assert out.count(b"\n") > 10 + + +class TestLinuxKthreads: + def test_linux_generic_kthreads(self, image, volatility, python): + rc, out, err = test_volatility.runvol_plugin( + "linux.kthreads.Kthreads", + image, + volatility, + python, + globalargs=("-vvv",), + ) + + if rc != 0 and err.count(b"Unsupported kthread implementation") > 0: + # The linux-sample-1.bin kernel implementation isn't supported. + # However, we can still check that the plugin requirements are met. + return None + + assert rc == 0 + assert out.count(b"\n") >= 4 + + +class TestLinuxMalfind: + def test_linux_generic_malfind(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.malfind.Malfind", image, volatility, python + ) + + # linux-sample-1.bin has no process memory ranges with potential injected code. + # This validates that plugin requirements are met and exceptions are not raised. + assert rc == 0 + assert out.count(b"\n") >= 4 + + +class TestLinuxMountinfo: + def test_linux_generic_mountinfo(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.mountinfo.MountInfo", image, volatility, python + ) + + assert rc == 0 + assert out.count(b"\n") > 10 + + +class TestLinuxPsaux: + def test_linux_generic_psaux(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.psaux.PsAux", image, volatility, python + ) + + assert rc == 0 + assert out.count(b"\n") > 50 + + +class TestLinuxPtrace: + def test_linux_generic_ptrace(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.ptrace.Ptrace", image, volatility, python + ) + + # linux-sample-1.bin has no processes being ptraced. + # This validates that plugin requirements are met and exceptions are not raised. + assert rc == 0 + assert out.count(b"\n") >= 4 + + +class TestLinuxVmaregexscan: + def test_linux_generic_vmaregexscan(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.vmaregexscan.VmaRegExScan", + image, + volatility, + python, + pluginargs=("--pid", "1", "--pattern", "\\x7fELF"), + ) + + assert rc == 0 + assert out.count(b"\n") > 10 + + +class TestLinuxVmayarascanYaraRule: + def test_linux_specific_vmayarascan_yara_rule(self, volatility, python): + image = LinuxSamples.LINUX_GENERIC.value.path + yara_rule_01 = r""" + rule fullvmayarascan + { + strings: + $s1 = "_nss_files_parse_grent" + $s2 = "/lib64/ld-linux-x86-64.so.2" + $s3 = "(bufferend - (char *) 0) % sizeof (char *) == 0" + condition: + all of them + } + """ + + # FIXME: When the minimum Python version includes 3.12, replace the following with: + # with tempfile.NamedTemporaryFile(delete_on_close=False) as fd: ... + fd, filename = tempfile.mkstemp(suffix=".yar") + try: + with os.fdopen(fd, "w") as f: + f.write(yara_rule_01) + + rc, out, _err = test_volatility.runvol_plugin( + "linux.vmayarascan.VmaYaraScan", + image, + volatility, + python, + pluginargs=("--pid", "8600", "--yara-file", filename), + ) + finally: + with contextlib.suppress(FileNotFoundError): + os.remove(filename) + + assert rc == 0 + assert out.count(b"\n") > 4 + + +class TestLinuxVmayarascanYaraString: + def test_linux_generic_vmayarascan_yara_string(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.vmayarascan.VmaYaraScan", + image, + volatility, + python, + pluginargs=("--pid", "1", "--yara-string", "ELF"), + ) + + assert rc == 0 + assert out.count(b"\n") > 10 + + +class TestLinuxPageCacheFiles: + def test_linux_specific_page_cache_files(self, volatility, python): + image = LinuxSamples.LINUX_GENERIC.value.path + rc, out, _err = test_volatility.runvol_plugin( + "linux.pagecache.Files", + image, + volatility, + python, + pluginargs=("--find", "/etc/passwd"), + ) + + assert rc == 0 + assert out.count(b"\n") > 4 + + # inode_num inode_addr ... file_path + assert re.search( + rb"146829\s0x88001ab5c270.*?/etc/passwd", + out, + ) + + +class TestLinuxPageCacheInodepages: + def test_linux_specific_page_cache_inodepages(self, volatility, python): + image = LinuxSamples.LINUX_GENERIC.value.path + inode_address = hex(0x88001AB5C270) + inode_dump_filename = f"inode_{inode_address}.dmp" + + rc, out, _err = test_volatility.runvol_plugin( + "linux.pagecache.InodePages", + image, + volatility, + python, + pluginargs=("--inode", inode_address), + ) + + assert rc == 0 + assert out.count(b"\n") > 4 + + # PageVAddr PagePAddr MappingAddr .. DumpSafe + assert re.search( + rb"0xea000054c5f8\s0x18389000\s0x88001ab5c3b0.*?True", + out, + ) + + try: + rc, out, _err = test_volatility.runvol_plugin( + "linux.pagecache.InodePages", + image, + volatility, + python, + pluginargs=("--inode", inode_address, "--dump"), + ) + + assert rc == 0 + assert out.count(b"\n") >= 4 + + assert os.path.exists(inode_dump_filename) + with open(inode_dump_filename, "rb") as fp: + inode_contents = fp.read() + assert inode_contents.count(b"\n") > 30 + assert inode_contents.count(b"root:x:0:0:root:/root:/bin/bash") > 0 + finally: + with contextlib.suppress(FileNotFoundError): + os.remove(inode_dump_filename) + + +class TestLinuxCheckAfinfo: + def test_linux_generic_check_afinfo(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.check_afinfo.Check_afinfo", image, volatility, python + ) + + # linux-sample-1.bin has no suspicious results. + # This validates that plugin requirements are met and exceptions are not raised. + assert rc == 0 + assert out.count(b"\n") >= 4 + + +class TestLinuxCheckModules: + def test_linux_generic_check_modules(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.check_modules.Check_modules", image, volatility, python + ) + + # linux-sample-1.bin has no suspicious results. + # This validates that plugin requirements are met and exceptions are not raised. + assert rc == 0 + assert out.count(b"\n") >= 4 + + +class TestLinuxEbpf: + def test_linux_generic_ebpf_progs(self, image, volatility, python): + rc, out, err = test_volatility.runvol_plugin( + "linux.ebpf.EBPF", + image, + volatility, + python, + globalargs=("-vvv",), + ) + + if rc != 0 and err.count(b"Unsupported kernel") > 0: + # The linux-sample-1.bin kernel implementation isn't supported. + # However, we can still check that the plugin requirements are met. + return None + + assert rc == 0 + assert out.count(b"\n") > 4 + + +class TestLinuxIomem: + def test_linux_generic_iomem(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.iomem.IOMem", image, volatility, python + ) + + assert rc == 0 + assert out.count(b"\n") > 100 + + +class TestLinuxKeyboardNotifiers: + def test_linux_generic_keyboard_notifiers(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.keyboard_notifiers.Keyboard_notifiers", image, volatility, python + ) + + # linux-sample-1.bin has no suspicious results for this plugin. + # This validates that plugin requirements are met and exceptions are not raised. + assert rc == 0 + assert out.count(b"\n") >= 4 + + +class TestLinuxKmesg: + def test_linux_generic_kmesg(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.kmsg.Kmsg", image, volatility, python + ) + + assert rc == 0 + assert out.count(b"\n") > 100 + + +class TestLinuxNetfilter: + def test_linux_generic_netfilter(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.netfilter.Netfilter", image, volatility, python + ) + + # linux-sample-1.bin has no suspicious results for this plugin. + # This validates that plugin requirements are met and exceptions are not raised. + assert rc == 0 + assert out.count(b"\n") >= 4 + + +class TestLinuxPsscan: + def test_linux_generic__psscan(self, image, volatility, python): + rc, out, _err = test_volatility.runvol_plugin( + "linux.psscan.PsScan", image, volatility, python + ) + + assert rc == 0 + assert out.count(b"\n") > 100 + + +class TestLinuxHiddenModules: + def test_linux_specific_hidden_modules(self, volatility, python): + # TODO: this check should be specific, against a distinct infected sample + image = LinuxSamples.LINUX_GENERIC.value.path + rc, out, _err = test_volatility.runvol_plugin( + "linux.hidden_modules.Hidden_modules", image, volatility, python + ) + + # linux-sample-1.bin has no hidden modules. + # This validates that plugin requirements are met and exceptions are not raised. + assert rc == 0 + assert out.count(b"\n") >= 4 + + +class TestLinuxIpAddr: + def test_linux_specific_ip_addr(self, volatility, python): + image = LinuxSamples.LINUX_GENERIC.value.path + rc, out, err = test_volatility.runvol_plugin( + "linux.ip.Addr", image, volatility, python + ) + + assert re.search( + rb"2\s+eth0\s+00:0c:29:8f:ed:ca\s+False\s+192.168.201.161\s+24\s+global\s+UP", + out, + ) + assert re.search( + rb"2\s+eth0\s+00:0c:29:8f:ed:ca\s+False\s+fe80::20c:29ff:fe8f:edca\s+64\s+link\s+UP", + out, + ) + assert out.count(b"\n") >= 8 + assert rc == 0 + + +class TestLinuxIpLink: + def test_linux_specific_ip_link(self, volatility, python): + image = LinuxSamples.LINUX_GENERIC.value.path + rc, out, err = test_volatility.runvol_plugin( + "linux.ip.Link", image, volatility, python + ) + + assert re.search( + rb"-\s+lo\s+00:00:00:00:00:00\s+UNKNOWN\s+16436\s+noqueue\s+0\s+LOOPBACK,LOWER_UP,UP", + out, + ) + assert re.search( + rb"-\s+eth0\s+00:0c:29:8f:ed:ca\s+UP\s+1500\s+pfifo_fast\s+1000\s+BROADCAST,LOWER_UP,MULTICAST,UP", + out, + ) + assert out.count(b"\n") >= 6 + assert rc == 0 + + +class TestLinuxKallsyms: + def test_linux_specific_kallsyms(self, volatility, python): + image = LinuxSamples.LINUX_GENERIC.value.path + rc, out, _err = test_volatility.runvol_plugin( + "linux.kallsyms.Kallsyms", + image, + volatility, + python, + pluginargs=("--modules",), + ) + # linux-sample-1.bin has no hidden modules. + # This validates that plugin requirements are met and exceptions are not raised. + assert rc == 0 + assert out.count(b"\n") > 1000 + + # Addr Type Size Exported SubSystem ModuleName SymbolName Description + # 0xffffa009eba9 t 28 False module usbcore usb_mon_register Symbol is in the text (code) section + assert re.search( + rb"0xffffa009eba9\s+t\s+28\s+False\s+module\s+usbcore\s+usb_mon_register\s+Symbol is in the text \(code\) section", + out, + ) + + +class TestLinuxPscallstack: + def test_linux_specific_pscallstack(self, volatility, python): + image = LinuxSamples.LINUX_GENERIC.value.path + rc, out, _err = test_volatility.runvol_plugin( + "linux.pscallstack.PsCallStack", + image, + volatility, + python, + pluginargs=("--pid", "1"), + ) + + assert rc == 0 + assert out.count(b"\n") > 30 + + # TID Comm Position Address Value Name Type Module + # 1 init 39 0x88001f999a40 0xffff81109039 do_select T kernel + assert re.search( + rb"1\s+init\s+39\s+0x88001f999a40.*?0xffff81109039\s+do_select\s+T\s+kernel", + out, + ) diff --git a/test/plugins/windows/windows.py b/test/plugins/windows/windows.py new file mode 100644 index 000000000..4d8bb3e54 --- /dev/null +++ b/test/plugins/windows/windows.py @@ -0,0 +1,326 @@ +import json +import hashlib +import shutil +import contextlib +import tempfile +import os +from test import test_volatility, WindowsSamples + + +class TestWindowsVolshell: + def test_windows_volshell(self, image, volatility, python): + out = test_volatility.basic_volshell_test( + image, volatility, python, globalargs=("-w",) + ) + assert out.count(b" 40 + + +class TestWindowsPslist: + def test_windows_generic_pslist(self, volatility, python, image): + rc, out, _err = test_volatility.runvol_plugin( + "windows.pslist.PsList", + image, + volatility, + python, + # Notice that this is needed to hit lru_cache when "specific" will run + globalargs=("-r", "json"), + ) + assert rc == 0 + out = out.lower() + assert out.find(b"system") != -1 + assert out.find(b"csrss.exe") != -1 + assert out.find(b"svchost.exe") != -1 + assert out.count(b"\n") > 10 + + def test_windows_specific_pslist(self, volatility, python): + image = WindowsSamples.WINDOWSXP_GENERIC.value.path + rc, out, _err = test_volatility.runvol_plugin( + "windows.pslist.PsList", + image, + volatility, + python, + globalargs=("-r", "json"), + ) + assert rc == 0 + expected_row = { + "CreateTime": None, + "ExitTime": None, + "File output": "Disabled", + "Handles": 1140, + "ImageFileName": "System", + "Offset(V)": 2185004992, + "PID": 4, + "PPID": 0, + "SessionId": None, + "Threads": 61, + "Wow64": False, + "__children": [], + } + assert test_volatility.match_output_row(json.loads(out), expected_row) + + +class TestWindowsPsscan: + def test_windows_generic_psscan(self, volatility, python, image): + rc, out, _err = test_volatility.runvol_plugin( + "windows.psscan.PsScan", image, volatility, python + ) + assert rc == 0 + out = out.lower() + assert out.find(b"system") != -1 + assert out.find(b"csrss.exe") != -1 + assert out.find(b"svchost.exe") != -1 + assert out.count(b"\n") > 10 + + +class TestWindowsDlllist: + def test_windows_generic_dlllist(self, volatility, python, image): + rc, out, _err = test_volatility.runvol_plugin( + "windows.dlllist.DllList", image, volatility, python + ) + assert rc == 0 + out = out.lower() + assert out.count(b"\n") > 10 + + +class TestWindowsModules: + def test_windows_generic_modules(self, volatility, python, image): + rc, out, _err = test_volatility.runvol_plugin( + "windows.modules.Modules", image, volatility, python + ) + assert rc == 0 + out = out.lower() + assert out.count(b"\n") > 10 + + +class TestWindowsHivelist: + def test_windows_generic_hivelist(self, volatility, python, image): + rc, out, _err = test_volatility.runvol_plugin( + "windows.registry.hivelist.HiveList", image, volatility, python + ) + assert rc == 0 + out = out.lower() + + not_xp = out.find(b"\\systemroot\\system32\\config\\software") + if not_xp == -1: + assert ( + out.find( + b"\\device\\harddiskvolume1\\windows\\system32\\config\\software" + ) + != -1 + ) + assert out.count(b"\n") > 10 + + +class TestWindowsDumpfiles: + def test_windows_specific_dumpfiles(self, volatility, python): + image = WindowsSamples.WINDOWSXP_GENERIC.value.path + with open("./test/known_files.json") as json_file: + known_files = json.load(json_file) + + failed_chksms = 0 + file_name = os.path.basename(image) + + try: + for addr in known_files["windows_dumpfiles"][file_name]: + path = tempfile.mkdtemp() + + rc, _out, _err = test_volatility.runvol_plugin( + "windows.dumpfiles.DumpFiles", + image, + volatility, + python, + globalargs=("-o", path), + pluginargs=("--virtaddr", addr), + ) + + for file in os.listdir(path): + with open(os.path.join(path, file), "rb") as fp: + if ( + hashlib.md5(fp.read()).hexdigest() + not in known_files["windows_dumpfiles"][file_name][addr] + ): + failed_chksms += 1 + + shutil.rmtree(path) + json_file.close() + + assert failed_chksms == 0 + assert rc == 0 + except Exception as e: + json_file.close() + print("Key Error raised on " + str(e)) + assert False + + +class TestWindowsHandles: + def test_windows_generic_handles(self, volatility, python, image): + rc, out, _err = test_volatility.runvol_plugin( + "windows.handles.Handles", + image, + volatility, + python, + pluginargs=("--pid", "4"), + ) + assert rc == 0 + assert out.find(b"System Pid 4") != -1 + assert ( + out.find( + b"MACHINE\\SYSTEM\\CONTROLSET001\\CONTROL\\SESSION MANAGER\\MEMORY MANAGEMENT\\PREFETCHPARAMETERS" + ) + != -1 + ) + assert out.find(b"MACHINE\\SYSTEM\\SETUP") != -1 + assert out.count(b"\n") > 500 + + +class TestWindowsSvcscan: + def test_windows_generic_svcscan(self, volatility, python, image): + rc, out, _err = test_volatility.runvol_plugin( + "windows.svcscan.SvcScan", image, volatility, python + ) + assert rc == 0 + assert out.find(b"Microsoft ACPI Driver") != -1 + assert out.count(b"\n") > 250 + + +class TestWindowsThrdscan: + def test_windows_generic_thrdscan(self, volatility, python, image): + rc, out, _err = test_volatility.runvol_plugin( + "windows.thrdscan.ThrdScan", image, volatility, python + ) + assert rc == 0 + assert out.find(b"\t4\t8") != -1 + assert out.find(b"\t4\t12") != -1 + assert out.find(b"\t4\t16") != -1 + + +class TestWindowsPrivileges: + def test_windows_generic_privileges(self, volatility, python, image): + rc, out, _err = test_volatility.runvol_plugin( + "windows.privileges.Privs", + image, + volatility, + python, + pluginargs=("--pid", "4"), + ) + assert rc == 0 + assert out.find(b"SeCreateTokenPrivilege") != -1 + assert out.find(b"SeCreateGlobalPrivilege") != -1 + assert out.find(b"SeAssignPrimaryTokenPrivilege") != -1 + assert out.count(b"\n") > 20 + + +class TestWindowsGetsids: + def test_windows_generic_getsids(self, volatility, python, image): + rc, out, _err = test_volatility.runvol_plugin( + "windows.getsids.GetSIDs", + image, + volatility, + python, + pluginargs=("--pid", "4"), + ) + assert rc == 0 + assert out.find(b"Local System") != -1 + assert out.find(b"Administrators") != -1 + assert out.find(b"Everyone") != -1 + assert out.find(b"Authenticated Users") != -1 + + +class TestWindowsEnvars: + def test_windows_generic_envars(self, volatility, python, image): + rc, out, _err = test_volatility.runvol_plugin( + "windows.envars.Envars", image, volatility, python + ) + assert rc == 0 + assert out.find(b"PATH") != -1 + assert out.find(b"PROCESSOR_ARCHITECTURE") != -1 + assert out.find(b"USERNAME") != -1 + assert out.find(b"SystemRoot") != -1 + assert out.find(b"CommonProgramFiles") != -1 + assert out.count(b"\n") > 500 + + +class TestWindowsCallbacks: + def test_windows_generic_callbacks(self, volatility, python, image): + rc, out, _err = test_volatility.runvol_plugin( + "windows.callbacks.Callbacks", image, volatility, python + ) + assert rc == 0 + assert out.find(b"PspCreateProcessNotifyRoutine") != -1 + assert out.find(b"KeBugCheckCallbackListHead") != -1 + assert out.find(b"KeBugCheckReasonCallbackListHead") != -1 + assert out.count(b"KeBugCheckReasonCallbackListHead ") > 5 + + +class TestWindowsVadwalk: + def test_windows_generic_vadwalk(self, volatility, python, image): + rc, out, _err = test_volatility.runvol_plugin( + "windows.vadwalk.VadWalk", image, volatility, python + ) + assert rc == 0 + assert out.find(b"Vad") != -1 + assert out.find(b"VadS") != -1 + assert out.find(b"Vadl") != -1 + assert out.find(b"VadF") != -1 + assert out.find(b"0x0") != -1 + + +class TestWindowsDevicetree: + def test_windows_generic_devicetree(self, volatility, python, image): + rc, out, _err = test_volatility.runvol_plugin( + "windows.devicetree.DeviceTree", image, volatility, python + ) + assert rc == 0 + assert out.find(b"DEV") != -1 + assert out.find(b"DRV") != -1 + assert out.find(b"ATT") != -1 + assert out.find(b"FILE_DEVICE_CONTROLLER") != -1 + assert out.find(b"FILE_DEVICE_DISK") != -1 + assert out.find(b"FILE_DEVICE_DISK_FILE_SYSTEM") != -1 + + +class TestWindowsVadyarascan: + def test_windows_specific_vadyarascan_yara_rule(self, volatility, python): + image = WindowsSamples.WINDOWSXP_GENERIC.value.path + yara_rule_01 = r""" + rule fullvadyarascan + { + strings: + $s1 = "!This program cannot be run in DOS mode." + $s2 = "Qw))Pw" + $s3 = "W_wD)Pw" + $s4 = "1Xw+2Xw" + $s5 = "xd`wh``w" + $s6 = "0g`w0g`w8g`w8g`w@g`w@g`wHg`wHg`wPg`wPg`wXg`wXg`w`g`w`g`whg`whg`wpg`wpg`wxg`wxg`w" + condition: + all of them + } + """ + fd, filename = tempfile.mkstemp(suffix=".yar") + try: + with os.fdopen(fd, "w") as f: + f.write(yara_rule_01) + rc, out, _err = test_volatility.runvol_plugin( + "windows.vadyarascan.VadYaraScan", + image, + volatility, + python, + pluginargs=("--pid", "4012", "--yara-file", filename), + ) + finally: + with contextlib.suppress(FileNotFoundError): + os.remove(filename) + assert rc == 0 + assert out.count(b"\n") > 4 + + def test_windows_specific_vadyarascan_yara_string(self, volatility, python): + image = WindowsSamples.WINDOWSXP_GENERIC.value.path + rc, out, _err = test_volatility.runvol_plugin( + "windows.vadyarascan.VadYaraScan", + image, + volatility, + python, + pluginargs=("--pid", "4012", "--yara-string", "MZ"), + ) + assert rc == 0 + assert out.count(b"\n") > 10 diff --git a/test/test_volatility.py b/test/test_volatility.py index 9cc9c3304..c376d3ccc 100644 --- a/test/test_volatility.py +++ b/test/test_volatility.py @@ -133,806 +133,8 @@ def basic_volshell_test(image, volatility, python, globalargs): return out -# WINDOWS - - -def test_windows_volshell(image, volatility, python): - out = basic_volshell_test(image, volatility, python, globalargs=["-w"]) - assert out.count(b" 40 - - -def test_windows_pslist(image, volatility, python): - rc, out, _err = runvol_plugin("windows.pslist.PsList", image, volatility, python) - out = out.lower() - assert out.find(b"system") != -1 - assert out.find(b"csrss.exe") != -1 - assert out.find(b"svchost.exe") != -1 - assert out.count(b"\n") > 10 - assert rc == 0 - - rc, out, _err = runvol_plugin( - "windows.pslist.PsList", image, volatility, python, pluginargs=["--pid", "4"] - ) - out = out.lower() - assert out.find(b"system") != -1 - assert out.count(b"\n") < 10 - assert rc == 0 - - -def test_windows_psscan(image, volatility, python): - rc, out, _err = runvol_plugin("windows.psscan.PsScan", image, volatility, python) - out = out.lower() - assert out.find(b"system") != -1 - assert out.find(b"csrss.exe") != -1 - assert out.find(b"svchost.exe") != -1 - assert out.count(b"\n") > 10 - assert rc == 0 - - -def test_windows_dlllist(image, volatility, python): - rc, out, _err = runvol_plugin("windows.dlllist.DllList", image, volatility, python) - out = out.lower() - assert out.count(b"\n") > 10 - assert rc == 0 - - -def test_windows_modules(image, volatility, python): - rc, out, _err = runvol_plugin("windows.modules.Modules", image, volatility, python) - out = out.lower() - assert out.count(b"\n") > 10 - assert rc == 0 - - -def test_windows_hivelist(image, volatility, python): - rc, out, _err = runvol_plugin( - "windows.registry.hivelist.HiveList", image, volatility, python - ) - out = out.lower() - - not_xp = out.find(b"\\systemroot\\system32\\config\\software") - if not_xp == -1: - assert ( - out.find(b"\\device\\harddiskvolume1\\windows\\system32\\config\\software") - != -1 - ) - - assert out.count(b"\n") > 10 - assert rc == 0 - - -def test_windows_dumpfiles(image, volatility, python): - - with open("./test/known_files.json") as json_file: - known_files = json.load(json_file) - - failed_chksms = 0 - file_name = os.path.basename(image) - - try: - for addr in known_files["windows_dumpfiles"][file_name]: - - path = tempfile.mkdtemp() - - rc, _out, _err = runvol_plugin( - "windows.dumpfiles.DumpFiles", - image, - volatility, - python, - globalargs=["-o", path], - pluginargs=["--virtaddr", addr], - ) - - for file in os.listdir(path): - with open(os.path.join(path, file), "rb") as fp: - if ( - hashlib.md5(fp.read()).hexdigest() - not in known_files["windows_dumpfiles"][file_name][addr] - ): - failed_chksms += 1 - - shutil.rmtree(path) - - json_file.close() - - assert failed_chksms == 0 - assert rc == 0 - except Exception as e: - json_file.close() - print("Key Error raised on " + str(e)) - assert False - - -def test_windows_handles(image, volatility, python): - rc, out, _err = runvol_plugin( - "windows.handles.Handles", image, volatility, python, pluginargs=["--pid", "4"] - ) - - assert out.find(b"System Pid 4") != -1 - assert ( - out.find( - b"MACHINE\\SYSTEM\\CONTROLSET001\\CONTROL\\SESSION MANAGER\\MEMORY MANAGEMENT\\PREFETCHPARAMETERS" - ) - != -1 - ) - assert out.find(b"MACHINE\\SYSTEM\\SETUP") != -1 - assert out.count(b"\n") > 500 - assert rc == 0 - - -def test_windows_svcscan(image, volatility, python): - rc, out, _err = runvol_plugin("windows.svcscan.SvcScan", image, volatility, python) - - assert out.find(b"Microsoft ACPI Driver") != -1 - assert out.count(b"\n") > 250 - assert rc == 0 - - -def test_windows_thrdscan(image, volatility, python): - rc, out, _err = runvol_plugin( - "windows.thrdscan.ThrdScan", image, volatility, python - ) - # find pid 4 (of system process) which starts with lowest tids - assert out.find(b"\t4\t8") != -1 - assert out.find(b"\t4\t12") != -1 - assert out.find(b"\t4\t16") != -1 - # assert out.find(b"this raieses AssertionError") != -1 - assert rc == 0 - - -def test_windows_privileges(image, volatility, python): - rc, out, _err = runvol_plugin( - "windows.privileges.Privs", image, volatility, python, pluginargs=["--pid", "4"] - ) - - assert out.find(b"SeCreateTokenPrivilege") != -1 - assert out.find(b"SeCreateGlobalPrivilege") != -1 - assert out.find(b"SeAssignPrimaryTokenPrivilege") != -1 - assert out.count(b"\n") > 20 - assert rc == 0 - - -def test_windows_getsids(image, volatility, python): - rc, out, _err = runvol_plugin( - "windows.getsids.GetSIDs", image, volatility, python, pluginargs=["--pid", "4"] - ) - - assert out.find(b"Local System") != -1 - assert out.find(b"Administrators") != -1 - assert out.find(b"Everyone") != -1 - assert out.find(b"Authenticated Users") != -1 - assert rc == 0 - - -def test_windows_envars(image, volatility, python): - rc, out, _err = runvol_plugin("windows.envars.Envars", image, volatility, python) - - assert out.find(b"PATH") != -1 - assert out.find(b"PROCESSOR_ARCHITECTURE") != -1 - assert out.find(b"USERNAME") != -1 - assert out.find(b"SystemRoot") != -1 - assert out.find(b"CommonProgramFiles") != -1 - assert out.count(b"\n") > 500 - assert rc == 0 - - -def test_windows_callbacks(image, volatility, python): - rc, out, _err = runvol_plugin( - "windows.callbacks.Callbacks", image, volatility, python - ) - - assert out.find(b"PspCreateProcessNotifyRoutine") != -1 - assert out.find(b"KeBugCheckCallbackListHead") != -1 - assert out.find(b"KeBugCheckReasonCallbackListHead") != -1 - assert out.count(b"KeBugCheckReasonCallbackListHead ") > 5 - assert rc == 0 - - -def test_windows_vadwalk(image, volatility, python): - rc, out, _err = runvol_plugin("windows.vadwalk.VadWalk", image, volatility, python) - - assert out.find(b"Vad") != -1 - assert out.find(b"VadS") != -1 - assert out.find(b"Vadl") != -1 - assert out.find(b"VadF") != -1 - assert out.find(b"0x0") != -1 - assert rc == 0 - - -def test_windows_devicetree(image, volatility, python): - rc, out, _err = runvol_plugin( - "windows.devicetree.DeviceTree", image, volatility, python - ) - - assert out.find(b"DEV") != -1 - assert out.find(b"DRV") != -1 - assert out.find(b"ATT") != -1 - assert out.find(b"FILE_DEVICE_CONTROLLER") != -1 - assert out.find(b"FILE_DEVICE_DISK") != -1 - assert out.find(b"FILE_DEVICE_DISK_FILE_SYSTEM") != -1 - assert rc == 0 - - -def test_windows_vadyarascan_yara_rule(image, volatility, python): - yara_rule_01 = r""" - rule fullvadyarascan - { - strings: - $s1 = "!This program cannot be run in DOS mode." - $s2 = "Qw))Pw" - $s3 = "W_wD)Pw" - $s4 = "1Xw+2Xw" - $s5 = "xd`wh``w" - $s6 = "0g`w0g`w8g`w8g`w@g`w@g`wHg`wHg`wPg`wPg`wXg`wXg`w`g`w`g`whg`whg`wpg`wpg`wxg`wxg`w" - condition: - all of them - } - """ - - # FIXME: When the minimum Python version includes 3.12, replace the following with: - # with tempfile.NamedTemporaryFile(delete_on_close=False) as fd: ... - fd, filename = tempfile.mkstemp(suffix=".yar") - try: - with os.fdopen(fd, "w") as f: - f.write(yara_rule_01) - - rc, out, _err = runvol_plugin( - "windows.vadyarascan.VadYaraScan", - image, - volatility, - python, - pluginargs=["--pid", "4012", "--yara-file", filename], - ) - finally: - with contextlib.suppress(FileNotFoundError): - os.remove(filename) - - out = out.lower() - assert out.count(b"\n") > 4 - assert rc == 0 - - -def test_windows_vadyarascan_yara_string(image, volatility, python): - rc, out, _err = runvol_plugin( - "windows.vadyarascan.VadYaraScan", - image, - volatility, - python, - pluginargs=["--pid", "4012", "--yara-string", "MZ"], - ) - out = out.lower() - - assert out.count(b"\n") > 10 - assert rc == 0 - - -# LINUX - - -def test_linux_volshell(image, volatility, python): - out = basic_volshell_test(image, volatility, python, globalargs=["-l"]) - assert out.count(b" 100 - - -def test_linux_pslist(image, volatility, python): - rc, out, _err = runvol_plugin("linux.pslist.PsList", image, volatility, python) - - assert rc == 0 - out = out.lower() - assert (out.find(b"init") != -1) or (out.find(b"systemd") != -1) - assert out.find(b"watchdog") != -1 - assert out.count(b"\n") > 10 - - -def test_linux_check_idt(image, volatility, python): - rc, out, _err = runvol_plugin( - "linux.check_idt.Check_idt", image, volatility, python - ) - - assert rc == 0 - out = out.lower() - assert out.count(b"__kernel__") >= 10 - assert out.count(b"\n") > 10 - - -def test_linux_check_syscall(image, volatility, python): - rc, out, _err = runvol_plugin( - "linux.check_syscall.Check_syscall", image, volatility, python - ) - - assert rc == 0 - out = out.lower() - assert out.find(b"sys_close") != -1 - assert out.find(b"sys_open") != -1 - assert out.count(b"\n") > 100 - - -def test_linux_lsmod(image, volatility, python): - rc, out, _err = runvol_plugin("linux.lsmod.Lsmod", image, volatility, python) - - assert rc == 0 - out = out.lower() - assert out.count(b"\n") > 10 - - -def test_linux_lsof(image, volatility, python): - rc, out, _err = runvol_plugin("linux.lsof.Lsof", image, volatility, python) - - assert rc == 0 - out = out.lower() - assert out.count(b"socket:") >= 10 - assert out.count(b"\n") > 35 - - -def test_linux_proc_maps(image, volatility, python): - rc, out, _err = runvol_plugin("linux.proc.Maps", image, volatility, python) - - assert rc == 0 - out = out.lower() - assert out.count(b"anonymous mapping") >= 10 - assert out.count(b"\n") > 100 - - -def test_linux_tty_check(image, volatility, python): - rc, out, _err = runvol_plugin( - "linux.tty_check.tty_check", image, volatility, python - ) - - assert rc == 0 - out = out.lower() - assert out.find(b"__kernel__") != -1 - assert out.count(b"\n") >= 5 - - -def test_linux_sockstat(image, volatility, python): - rc, out, _err = runvol_plugin("linux.sockstat.Sockstat", image, volatility, python) - - assert rc == 0 - assert out.count(b"AF_UNIX") >= 354 - assert out.count(b"AF_BLUETOOTH") >= 5 - assert out.count(b"AF_INET") >= 32 - assert out.count(b"AF_INET6") >= 20 - assert out.count(b"AF_PACKET") >= 1 - assert out.count(b"AF_NETLINK") >= 43 - - -def test_linux_library_list(image, volatility, python): - rc, out, _err = runvol_plugin( - "linux.library_list.LibraryList", - image, - volatility, - python, - pluginargs=["--pids", "2363"], - ) - - assert rc == 0 - assert re.search( - rb"NetworkManager\s2363\s0x7f52cdda0000\s/lib/x86_64-linux-gnu/libnss_files.so.2", - out, - ) - - assert out.count(b"\n") > 10 - - -def test_linux_pstree(image, volatility, python): - rc, out, _err = runvol_plugin("linux.pstree.PsTree", image, volatility, python) - - assert rc == 0 - out = out.lower() - assert (out.find(b"init") != -1) or (out.find(b"systemd") != -1) - assert out.count(b"\n") > 10 - - -def test_linux_pidhashtable(image, volatility, python): - rc, out, _err = runvol_plugin( - "linux.pidhashtable.PIDHashTable", image, volatility, python - ) - - assert rc == 0 - out = out.lower() - assert (out.find(b"init") != -1) or (out.find(b"systemd") != -1) - assert out.count(b"\n") > 10 - - -def test_linux_bash(image, volatility, python): - rc, out, _err = runvol_plugin("linux.bash.Bash", image, volatility, python) - - assert rc == 0 - assert out.count(b"\n") > 10 - - -def test_linux_boottime(image, volatility, python): - rc, out, _err = runvol_plugin("linux.boottime.Boottime", image, volatility, python) - - assert rc == 0 - out = out.lower() - assert out.count(b"utc") >= 1 - - -def test_linux_capabilities(image, volatility, python): - rc, out, err = runvol_plugin( - "linux.capabilities.Capabilities", - image, - volatility, - python, - globalargs=["-vvv"], - ) - - if rc != 0 and err.count(b"Unsupported kernel capabilities implementation") > 0: - # The linux-sample-1.bin kernel implementation isn't supported. - # However, we can still check that the plugin requirements are met. - return None - - assert rc == 0 - assert out.count(b"\n") > 10 - - -def test_linux_check_creds(image, volatility, python): - rc, out, _err = runvol_plugin( - "linux.check_creds.Check_creds", image, volatility, python - ) - - # linux-sample-1.bin has no processes sharing credentials. - # This validates that plugin requirements are met and exceptions are not raised. - assert rc == 0 - assert out.count(b"\n") >= 4 - - -def test_linux_elfs(image, volatility, python): - rc, out, _err = runvol_plugin("linux.elfs.Elfs", image, volatility, python) - - assert rc == 0 - assert out.count(b"\n") > 10 - - -def test_linux_envars(image, volatility, python): - rc, out, _err = runvol_plugin("linux.envars.Envars", image, volatility, python) - - assert rc == 0 - assert out.count(b"\n") > 10 - - -def test_linux_kthreads(image, volatility, python): - rc, out, err = runvol_plugin( - "linux.kthreads.Kthreads", - image, - volatility, - python, - globalargs=["-vvv"], - ) - - if rc != 0 and err.count(b"Unsupported kthread implementation") > 0: - # The linux-sample-1.bin kernel implementation isn't supported. - # However, we can still check that the plugin requirements are met. - return None - - assert rc == 0 - assert out.count(b"\n") >= 4 - - -def test_linux_malfind(image, volatility, python): - rc, out, _err = runvol_plugin("linux.malfind.Malfind", image, volatility, python) - - # linux-sample-1.bin has no process memory ranges with potential injected code. - # This validates that plugin requirements are met and exceptions are not raised. - assert rc == 0 - assert out.count(b"\n") >= 4 - - -def test_linux_mountinfo(image, volatility, python): - rc, out, _err = runvol_plugin( - "linux.mountinfo.MountInfo", image, volatility, python - ) - - assert rc == 0 - assert out.count(b"\n") > 10 - - -def test_linux_psaux(image, volatility, python): - rc, out, _err = runvol_plugin("linux.psaux.PsAux", image, volatility, python) - - assert rc == 0 - assert out.count(b"\n") > 50 - - -def test_linux_ptrace(image, volatility, python): - rc, out, _err = runvol_plugin("linux.ptrace.Ptrace", image, volatility, python) - - # linux-sample-1.bin has no processes being ptraced. - # This validates that plugin requirements are met and exceptions are not raised. - assert rc == 0 - assert out.count(b"\n") >= 4 - - -def test_linux_vmaregexscan(image, volatility, python): - rc, out, _err = runvol_plugin( - "linux.vmaregexscan.VmaRegExScan", - image, - volatility, - python, - pluginargs=["--pid", "1", "--pattern", "\\x7fELF"], - ) - - assert rc == 0 - assert out.count(b"\n") > 10 - - -def test_linux_vmayarascan_yara_rule(image, volatility, python): - yara_rule_01 = r""" - rule fullvmayarascan - { - strings: - $s1 = "_nss_files_parse_grent" - $s2 = "/lib64/ld-linux-x86-64.so.2" - $s3 = "(bufferend - (char *) 0) % sizeof (char *) == 0" - condition: - all of them - } - """ - - # FIXME: When the minimum Python version includes 3.12, replace the following with: - # with tempfile.NamedTemporaryFile(delete_on_close=False) as fd: ... - fd, filename = tempfile.mkstemp(suffix=".yar") - try: - with os.fdopen(fd, "w") as f: - f.write(yara_rule_01) - - rc, out, _err = runvol_plugin( - "linux.vmayarascan.VmaYaraScan", - image, - volatility, - python, - pluginargs=["--pid", "8600", "--yara-file", filename], - ) - finally: - with contextlib.suppress(FileNotFoundError): - os.remove(filename) - - assert rc == 0 - assert out.count(b"\n") > 4 - - -def test_linux_vmayarascan_yara_string(image, volatility, python): - rc, out, _err = runvol_plugin( - "linux.vmayarascan.VmaYaraScan", - image, - volatility, - python, - pluginargs=["--pid", "1", "--yara-string", "ELF"], - ) - - assert rc == 0 - assert out.count(b"\n") > 10 - - -def test_linux_page_cache_files(image, volatility, python): - rc, out, _err = runvol_plugin( - "linux.pagecache.Files", - image, - volatility, - python, - pluginargs=["--find", "/etc/passwd"], - ) - - assert rc == 0 - assert out.count(b"\n") > 4 - - # inode_num inode_addr ... file_path - assert re.search( - rb"146829\s0x88001ab5c270.*?/etc/passwd", - out, - ) - - -def test_linux_page_cache_inodepages(image, volatility, python): - - inode_address = hex(0x88001AB5C270) - inode_dump_filename = f"inode_{inode_address}.dmp" - - rc, out, _err = runvol_plugin( - "linux.pagecache.InodePages", - image, - volatility, - python, - pluginargs=["--inode", inode_address], - ) - - assert rc == 0 - assert out.count(b"\n") > 4 - - # PageVAddr PagePAddr MappingAddr .. DumpSafe - assert re.search( - rb"0xea000054c5f8\s0x18389000\s0x88001ab5c3b0.*?True", - out, - ) - - try: - rc, out, _err = runvol_plugin( - "linux.pagecache.InodePages", - image, - volatility, - python, - pluginargs=["--inode", inode_address, "--dump"], - ) - - assert rc == 0 - assert out.count(b"\n") >= 4 - - assert os.path.exists(inode_dump_filename) - with open(inode_dump_filename, "rb") as fp: - inode_contents = fp.read() - assert inode_contents.count(b"\n") > 30 - assert inode_contents.count(b"root:x:0:0:root:/root:/bin/bash") > 0 - finally: - with contextlib.suppress(FileNotFoundError): - os.remove(inode_dump_filename) - - -def test_linux_check_afinfo(image, volatility, python): - rc, out, _err = runvol_plugin( - "linux.check_afinfo.Check_afinfo", image, volatility, python - ) - - # linux-sample-1.bin has no suspicious results. - # This validates that plugin requirements are met and exceptions are not raised. - assert rc == 0 - assert out.count(b"\n") >= 4 - - -def test_linux_check_modules(image, volatility, python): - rc, out, _err = runvol_plugin( - "linux.check_modules.Check_modules", image, volatility, python - ) - - # linux-sample-1.bin has no suspicious results. - # This validates that plugin requirements are met and exceptions are not raised. - assert rc == 0 - assert out.count(b"\n") >= 4 - - -def test_linux_ebpf_progs(image, volatility, python): - rc, out, err = runvol_plugin( - "linux.ebpf.EBPF", - image, - volatility, - python, - globalargs=["-vvv"], - ) - - if rc != 0 and err.count(b"Unsupported kernel") > 0: - # The linux-sample-1.bin kernel implementation isn't supported. - # However, we can still check that the plugin requirements are met. - return None - - assert rc == 0 - assert out.count(b"\n") > 4 - - -def test_linux_iomem(image, volatility, python): - rc, out, _err = runvol_plugin("linux.iomem.IOMem", image, volatility, python) - - assert rc == 0 - assert out.count(b"\n") > 100 - - -def test_linux_keyboard_notifiers(image, volatility, python): - rc, out, _err = runvol_plugin( - "linux.keyboard_notifiers.Keyboard_notifiers", image, volatility, python - ) - - # linux-sample-1.bin has no suspicious results for this plugin. - # This validates that plugin requirements are met and exceptions are not raised. - assert rc == 0 - assert out.count(b"\n") >= 4 - - -def test_linux_kmesg(image, volatility, python): - rc, out, _err = runvol_plugin("linux.kmsg.Kmsg", image, volatility, python) - - assert rc == 0 - assert out.count(b"\n") > 100 - - -def test_linux_netfilter(image, volatility, python): - rc, out, _err = runvol_plugin( - "linux.netfilter.Netfilter", image, volatility, python - ) - - # linux-sample-1.bin has no suspicious results for this plugin. - # This validates that plugin requirements are met and exceptions are not raised. - assert rc == 0 - assert out.count(b"\n") >= 4 - - -def test_linux_psscan(image, volatility, python): - rc, out, _err = runvol_plugin("linux.psscan.PsScan", image, volatility, python) - - assert rc == 0 - assert out.count(b"\n") > 100 - - -def test_linux_hidden_modules(image, volatility, python): - rc, out, _err = runvol_plugin( - "linux.hidden_modules.Hidden_modules", image, volatility, python - ) - - # linux-sample-1.bin has no hidden modules. - # This validates that plugin requirements are met and exceptions are not raised. - assert rc == 0 - assert out.count(b"\n") >= 4 - - -def test_linux_ip_addr(image, volatility, python): - rc, out, err = runvol_plugin("linux.ip.Addr", image, volatility, python) - - assert re.search( - rb"2\s+eth0\s+00:0c:29:8f:ed:ca\s+False\s+192.168.201.161\s+24\s+global\s+UP", - out, - ) - assert re.search( - rb"2\s+eth0\s+00:0c:29:8f:ed:ca\s+False\s+fe80::20c:29ff:fe8f:edca\s+64\s+link\s+UP", - out, - ) - assert out.count(b"\n") >= 8 - assert rc == 0 - - -def test_linux_ip_link(image, volatility, python): - rc, out, err = runvol_plugin("linux.ip.Link", image, volatility, python) - - assert re.search( - rb"-\s+lo\s+00:00:00:00:00:00\s+UNKNOWN\s+16436\s+noqueue\s+0\s+LOOPBACK,LOWER_UP,UP", - out, - ) - assert re.search( - rb"-\s+eth0\s+00:0c:29:8f:ed:ca\s+UP\s+1500\s+pfifo_fast\s+1000\s+BROADCAST,LOWER_UP,MULTICAST,UP", - out, - ) - assert out.count(b"\n") >= 6 - assert rc == 0 - - -def test_linux_kallsyms(image, volatility, python): - rc, out, _err = runvol_plugin( - "linux.kallsyms.Kallsyms", - image, - volatility, - python, - pluginargs=["--modules"], - ) - # linux-sample-1.bin has no hidden modules. - # This validates that plugin requirements are met and exceptions are not raised. - assert rc == 0 - assert out.count(b"\n") > 1000 - - # Addr Type Size Exported SubSystem ModuleName SymbolName Description - # 0xffffa009eba9 t 28 False module usbcore usb_mon_register Symbol is in the text (code) section - assert re.search( - rb"0xffffa009eba9\s+t\s+28\s+False\s+module\s+usbcore\s+usb_mon_register\s+Symbol is in the text \(code\) section", - out, - ) - - -def test_linux_pscallstack(image, volatility, python): - rc, out, _err = runvol_plugin( - "linux.pscallstack.PsCallStack", - image, - volatility, - python, - pluginargs=["--pid", "1"], - ) - - assert rc == 0 - assert out.count(b"\n") > 30 - - # TID Comm Position Address Value Name Type Module - # 1 init 39 0x88001f999a40 0xffff81109039 do_select T kernel - assert re.search( - rb"1\s+init\s+39\s+0x88001f999a40.*?0xffff81109039\s+do_select\s+T\s+kernel", - out, - ) - - # MAC +# TODO: Migrate and integrate in testing (once analysis is fixed ?) def test_mac_volshell(image, volatility, python):