From a187ad6768b841cfbe24398ad13d0dac30eb574a Mon Sep 17 00:00:00 2001 From: Nuno Alves Date: Tue, 9 Dec 2025 11:15:13 +0000 Subject: [PATCH 1/2] Fix dump memory (#2771) * analyzer/linux: improve memory map parse and fix error * lib/cuckoo: fix unknown memory protection flags This is a temporary fix because when processing the Linux memory dumps it fails with an undefined value. Current it is incorrectly parsing the dump, but this is useful to visualize the dumps. --- analyzer/linux/analyzer.py | 13 +++++++++---- lib/cuckoo/common/objects.py | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/analyzer/linux/analyzer.py b/analyzer/linux/analyzer.py index 28c78bf335c..1bc335de7c4 100644 --- a/analyzer/linux/analyzer.py +++ b/analyzer/linux/analyzer.py @@ -105,10 +105,15 @@ def dump_memory(pid): output_file = open(f"{MEM_PATH}/{pid}.dmp", "wb") for line in maps_file.readlines(): - m = re.match(r"([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r])(\S+)\s+\d+\s+\S+\s+\d+\s*(.*)?", line) - if m and m.group(3) == "r": + # Reference: https://man7.org/linux/man-pages/man5/proc_pid_maps.5.html + m = re.match(r"^([0-9a-f]+)-([0-9a-f]+) ([-rwxsp]{4}) ([0-9a-f]+) (\d\d:\d\d) (\d+) *(.*)$", line) + if not m: + log.error("Could not parse memory map line for pid %s: %s", pid, line) + continue + perms = m.group(3) + pathname = m.group(7) + if "r" in perms: # Testing: Uncomment to skip memory regions associated with dynamic libraries - # pathname = m.group(5) # if pathname and (pathname.endswith('.so') or 'lib' in pathname or '[' in pathname): # continue start = int(m.group(1), 16) @@ -118,7 +123,7 @@ def dump_memory(pid): chunk = mem_file.read(end - start) output_file.write(chunk) except (OSError, ValueError) as e: - log.error("Could not read memory range %s: {e}", f"{start:x}-{end:x}", str(e)) + log.error("Could not read memory range %x-%x (%s) (%s): %s", start, end, perms, pathname, e) maps_file.close() mem_file.close() output_file.close() diff --git a/lib/cuckoo/common/objects.py b/lib/cuckoo/common/objects.py index e31c3273556..7a5505232f5 100644 --- a/lib/cuckoo/common/objects.py +++ b/lib/cuckoo/common/objects.py @@ -796,7 +796,7 @@ def _prot_to_str(self, prot): if prot & PAGE_GUARD: return "G" prot &= 0xFF - return self.protmap[prot] + return self.protmap.get(prot, "UNKNOWN") def pretty_print(self): new_addr_space = copy.deepcopy(self.address_space) From 300b80c85c58ba7aefd26bf9aaa2940c538a9e3b Mon Sep 17 00:00:00 2001 From: Nuno Alves Date: Tue, 9 Dec 2025 11:15:27 +0000 Subject: [PATCH 2/2] analyzer/linux: Fix get_proc_status parsing (#2769) * analyzer/linux: Fix get_proc_status parsing When parsing the `/proc//status` file some field are empty which made the dict() conversion fail because the list length was 1. With this change, we are spliting on the ":" character and striping the key and the value so we can get the key without the ":" at the end and the value without any "\t" at the beginning or "\n" at the end. * analyzer/linux: convert parent process id (PPid) to int --- analyzer/linux/lib/api/process.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/analyzer/linux/lib/api/process.py b/analyzer/linux/lib/api/process.py index ba20ef05341..5a9fea3c3c7 100644 --- a/analyzer/linux/lib/api/process.py +++ b/analyzer/linux/lib/api/process.py @@ -25,18 +25,18 @@ def is_alive(self): status = self.get_proc_status() if not status: return False - if "zombie" in status.get("State:", ""): + if "zombie" in status.get("State", ""): return False return True def get_parent_pid(self): - return self.get_proc_status().get("PPid") + return int(self.get_proc_status().get("PPid")) def get_proc_status(self): try: with open(f"/proc/{self.pid}/status") as f: status = f.readlines() - status_values = dict([j.strip().split(maxsplit=1) for j in status]) + status_values = dict([tuple(map(str.strip, j.split(':',1))) for j in status]) return status_values except Exception: log.critical("Could not get process status for pid %s", self.pid)