From b04c196b99516dfbe43560200dbcf9142e0d4931 Mon Sep 17 00:00:00 2001 From: r1ngz3ro Date: Thu, 7 May 2026 19:38:26 +0100 Subject: [PATCH 1/4] added memory protections to segments in the minidump backend --- cle/backends/minidump/__init__.py | 34 ++++++++++++++---- cle/backends/minidump/regions.py | 60 +++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 cle/backends/minidump/regions.py diff --git a/cle/backends/minidump/__init__.py b/cle/backends/minidump/__init__.py index 31c578a06..4afe1043b 100644 --- a/cle/backends/minidump/__init__.py +++ b/cle/backends/minidump/__init__.py @@ -9,6 +9,7 @@ from cle.backends.backend import Backend, register_backend from cle.backends.region import Section, Segment +from .regions import DumpSection from cle.errors import CLEError, CLEInvalidBinaryError @@ -64,14 +65,30 @@ def __init__(self, *args, **kwargs): self.memory.add_backer(segment.start_virtual_address, data) for module in self._mdf.modules.modules: + # A module can span multiple segments + module_start = module.baseaddress + module_end = module.baseaddress + module.size + for segment in segments: - if segment.start_virtual_address == module.baseaddress: - break - else: - raise CLEInvalidBinaryError("Missing segment for loaded module: " + module.name) - section = Section(module.name, segment.start_file_address, module.baseaddress, module.size) - self.sections.append(section) - self.sections_map[ntpath.basename(section.name)] = section + seg_start = segment.start_virtual_address + seg_end = segment.start_virtual_address + segment.size + + # Check for overlap + overlap_start = max(module_start, seg_start) + overlap_end = min(module_end, seg_end) + + if overlap_start < overlap_end: + # find protection for this overlap + protect = 0 + if self._mdf.memory_info is not None: + for info in self._mdf.memory_info.infos: + if info.BaseAddress <= overlap_start < info.BaseAddress + info.RegionSize: + protect = info.Protect + break + + section = DumpSection(module, segment, protect, vaddr=overlap_start, size=overlap_end-overlap_start) + self.sections.append(section) + self.sections_map[ntpath.basename(section.name)] = section self._thread_data = {} @@ -83,6 +100,9 @@ def __init__(self, *args, **kwargs): self._binary_stream.seek(0) self._thread_data[tid] = (teb, data) + if self._mdf.exception is not None and self._mdf.exception.exception_records: + self._entry = self._mdf.exception.exception_records[0].ExceptionRecord.ExceptionAddress + def close(self): super().close() self._mdf.file_handle.close() diff --git a/cle/backends/minidump/regions.py b/cle/backends/minidump/regions.py new file mode 100644 index 000000000..7d2762588 --- /dev/null +++ b/cle/backends/minidump/regions.py @@ -0,0 +1,60 @@ +from __future__ import annotations + +from cle.backends.region import Section +from minidump.streams import MemoryInfoListStream + + +AP = MemoryInfoListStream.AllocationProtect + + +class DumpSection(Section): + """ + Represents a mapped memory section in a dump. + """ + + def __init__( + self, + module, + segment, + protect, + vaddr=None, + size=None, + ): + super().__init__( + module.name, + segment.start_file_address + (vaddr - segment.start_virtual_address) if vaddr else segment.start_file_address, + vaddr or module.baseaddress, + size or module.size + ) + self.protect = protect + + @property + def is_readable(self) -> bool: + readable = ( + AP.PAGE_READONLY.value + | AP.PAGE_READWRITE.value + | AP.PAGE_WRITECOPY.value + | AP.PAGE_EXECUTE_READ.value + | AP.PAGE_EXECUTE_READWRITE.value + | AP.PAGE_EXECUTE_WRITECOPY.value + ) + return bool(self.protect.value & readable) + + @property + def is_writable(self) -> bool: + writable = ( + AP.PAGE_READWRITE.value + | AP.PAGE_EXECUTE_READWRITE.value + ) + return bool(self.protect.value & writable) + + @property + def is_executable(self) -> bool: + executable = ( + AP.PAGE_EXECUTE.value + | AP.PAGE_EXECUTE_READ.value + | AP.PAGE_EXECUTE_READWRITE.value + | AP.PAGE_EXECUTE_WRITECOPY.value + ) + return bool(self.protect.value & executable) + From 0a904252cc32e50e6cf73658860abf951e7756d5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 18:56:13 +0000 Subject: [PATCH 2/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- cle/backends/minidump/__init__.py | 15 +++++++++------ cle/backends/minidump/regions.py | 16 ++++++++-------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/cle/backends/minidump/__init__.py b/cle/backends/minidump/__init__.py index 4afe1043b..37c85d38c 100644 --- a/cle/backends/minidump/__init__.py +++ b/cle/backends/minidump/__init__.py @@ -9,9 +9,10 @@ from cle.backends.backend import Backend, register_backend from cle.backends.region import Section, Segment -from .regions import DumpSection from cle.errors import CLEError, CLEInvalidBinaryError +from .regions import DumpSection + class MinidumpMissingStreamError(Exception): def __init__(self, stream, message=None): @@ -68,15 +69,15 @@ def __init__(self, *args, **kwargs): # A module can span multiple segments module_start = module.baseaddress module_end = module.baseaddress + module.size - + for segment in segments: seg_start = segment.start_virtual_address seg_end = segment.start_virtual_address + segment.size - + # Check for overlap overlap_start = max(module_start, seg_start) overlap_end = min(module_end, seg_end) - + if overlap_start < overlap_end: # find protection for this overlap protect = 0 @@ -85,8 +86,10 @@ def __init__(self, *args, **kwargs): if info.BaseAddress <= overlap_start < info.BaseAddress + info.RegionSize: protect = info.Protect break - - section = DumpSection(module, segment, protect, vaddr=overlap_start, size=overlap_end-overlap_start) + + section = DumpSection( + module, segment, protect, vaddr=overlap_start, size=overlap_end - overlap_start + ) self.sections.append(section) self.sections_map[ntpath.basename(section.name)] = section diff --git a/cle/backends/minidump/regions.py b/cle/backends/minidump/regions.py index 7d2762588..6fa8c27b5 100644 --- a/cle/backends/minidump/regions.py +++ b/cle/backends/minidump/regions.py @@ -1,8 +1,8 @@ from __future__ import annotations -from cle.backends.region import Section from minidump.streams import MemoryInfoListStream +from cle.backends.region import Section AP = MemoryInfoListStream.AllocationProtect @@ -22,9 +22,13 @@ def __init__( ): super().__init__( module.name, - segment.start_file_address + (vaddr - segment.start_virtual_address) if vaddr else segment.start_file_address, + ( + segment.start_file_address + (vaddr - segment.start_virtual_address) + if vaddr + else segment.start_file_address + ), vaddr or module.baseaddress, - size or module.size + size or module.size, ) self.protect = protect @@ -42,10 +46,7 @@ def is_readable(self) -> bool: @property def is_writable(self) -> bool: - writable = ( - AP.PAGE_READWRITE.value - | AP.PAGE_EXECUTE_READWRITE.value - ) + writable = AP.PAGE_READWRITE.value | AP.PAGE_EXECUTE_READWRITE.value return bool(self.protect.value & writable) @property @@ -57,4 +58,3 @@ def is_executable(self) -> bool: | AP.PAGE_EXECUTE_WRITECOPY.value ) return bool(self.protect.value & executable) - From 3493d220b3b60169aa63d48e99aec5977a3d3479 Mon Sep 17 00:00:00 2001 From: r1ngz3ro Date: Thu, 7 May 2026 20:20:13 +0100 Subject: [PATCH 3/4] deleted unused imports --- cle/backends/minidump/__init__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cle/backends/minidump/__init__.py b/cle/backends/minidump/__init__.py index 37c85d38c..07a92bd27 100644 --- a/cle/backends/minidump/__init__.py +++ b/cle/backends/minidump/__init__.py @@ -8,9 +8,8 @@ from minidump.streams import SystemInfoStream from cle.backends.backend import Backend, register_backend -from cle.backends.region import Section, Segment -from cle.errors import CLEError, CLEInvalidBinaryError - +from cle.backends.region import Segment +from cle.errors import CLEError from .regions import DumpSection From 0df01a259991dafab3a01e18b9395548495a7e21 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 19:21:04 +0000 Subject: [PATCH 4/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- cle/backends/minidump/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cle/backends/minidump/__init__.py b/cle/backends/minidump/__init__.py index 07a92bd27..5b44c9bec 100644 --- a/cle/backends/minidump/__init__.py +++ b/cle/backends/minidump/__init__.py @@ -10,6 +10,7 @@ from cle.backends.backend import Backend, register_backend from cle.backends.region import Segment from cle.errors import CLEError + from .regions import DumpSection