From dad718d293585239ea17d79421e120b52e99259a Mon Sep 17 00:00:00 2001 From: JeanExtreme002 Date: Thu, 16 Nov 2023 14:08:17 -0300 Subject: [PATCH] added writeable_only param --- PyMemoryEditor/__init__.py | 2 +- PyMemoryEditor/linux/functions.py | 4 ++++ PyMemoryEditor/linux/process.py | 8 ++++++-- PyMemoryEditor/linux/types.py | 7 +++++++ PyMemoryEditor/win32/enums/memory_protections.py | 3 +++ PyMemoryEditor/win32/functions.py | 4 ++++ PyMemoryEditor/win32/process.py | 8 ++++++-- 7 files changed, 31 insertions(+), 5 deletions(-) diff --git a/PyMemoryEditor/__init__.py b/PyMemoryEditor/__init__.py index 8fbc095..0d4ce0f 100644 --- a/PyMemoryEditor/__init__.py +++ b/PyMemoryEditor/__init__.py @@ -6,7 +6,7 @@ """ __author__ = "Jean Loui Bernard Silva de Jesus" -__version__ = "1.5.4" +__version__ = "1.5.5" from .enums import ScanTypesEnum diff --git a/PyMemoryEditor/linux/functions.py b/PyMemoryEditor/linux/functions.py index 352b29e..037c4b2 100644 --- a/PyMemoryEditor/linux/functions.py +++ b/PyMemoryEditor/linux/functions.py @@ -77,6 +77,7 @@ def search_all_memory( value: Union[bool, int, float, str, bytes, tuple], scan_type: ScanTypesEnum = ScanTypesEnum.EXACT_VALUE, progress_information: bool = False, + writeable_only: bool = False, ) -> Generator[Union[int, Tuple[int, dict]], None, None]: """ Search the whole memory space, accessible to the process, @@ -109,6 +110,9 @@ def search_all_memory( # Only readable memory pages. if not b"r" in region["struct"].Privileges: continue + # If writeable_only is True, checks if the memory page is writeable. + if writeable_only and not b"w" in region["struct"].Privileges: continue + memory_total += region["size"] regions.append(region) diff --git a/PyMemoryEditor/linux/process.py b/PyMemoryEditor/linux/process.py index a701a9c..bb02318 100644 --- a/PyMemoryEditor/linux/process.py +++ b/PyMemoryEditor/linux/process.py @@ -66,6 +66,7 @@ def search_by_value( scan_type: ScanTypesEnum = ScanTypesEnum.EXACT_VALUE, *, progress_information: bool = False, + writeable_only: bool = False, ) -> Generator[Union[int, Tuple[int, dict]], None, None]: """ Search the whole memory space, accessible to the process, @@ -76,13 +77,14 @@ def search_by_value( :param value: value to be queried (bool, int, float, str or bytes). :param scan_type: the way to compare the values. :param progress_information: if True, a dictionary with the progress information will be return. + :param writeable_only: if True, search only at writeable memory regions. """ if self.__closed: raise ClosedProcess() if scan_type in [ScanTypesEnum.VALUE_BETWEEN, ScanTypesEnum.NOT_VALUE_BETWEEN]: raise ValueError("Use the method search_by_value_between(...) to search within a range of values.") - return search_all_memory(self.pid, pytype, bufflength, value, scan_type, progress_information) + return search_all_memory(self.pid, pytype, bufflength, value, scan_type, progress_information, writeable_only) def search_by_value_between( self, @@ -93,6 +95,7 @@ def search_by_value_between( *, not_between: bool = False, progress_information: bool = False, + writeable_only: bool = False, ) -> Generator[Union[int, Tuple[int, dict]], None, None]: """ Search the whole memory space, accessible to the process, @@ -104,11 +107,12 @@ def search_by_value_between( :param end: maximum inclusive value to be queried (bool, int, float, str or bytes). :param not_between: if True, return only addresses of values that are NOT within the range. :param progress_information: if True, a dictionary with the progress information will be return. + :param writeable_only: if True, search only at writeable memory regions. """ if self.__closed: raise ClosedProcess() scan_type = ScanTypesEnum.NOT_VALUE_BETWEEN if not_between else ScanTypesEnum.VALUE_BETWEEN - return search_all_memory(self.pid, pytype, bufflength, (start, end), scan_type, progress_information) + return search_all_memory(self.pid, pytype, bufflength, (start, end), scan_type, progress_information, writeable_only) def write_process_memory( self, diff --git a/PyMemoryEditor/linux/types.py b/PyMemoryEditor/linux/types.py index 3f4796c..fcbdbfa 100644 --- a/PyMemoryEditor/linux/types.py +++ b/PyMemoryEditor/linux/types.py @@ -1,4 +1,11 @@ # -*- coding: utf-8 -*- + +# Read more about proc and memory mapping here: +# https://man7.org/linux/man-pages/man5/proc.5.html + +# Read more about iovec here: +# https://man7.org/linux/man-pages/man3/iovec.3type.html + from ctypes import Structure, c_char_p, c_size_t, c_uint, c_void_p diff --git a/PyMemoryEditor/win32/enums/memory_protections.py b/PyMemoryEditor/win32/enums/memory_protections.py index 0aebbbc..6ee82ae 100644 --- a/PyMemoryEditor/win32/enums/memory_protections.py +++ b/PyMemoryEditor/win32/enums/memory_protections.py @@ -59,6 +59,9 @@ class MemoryProtectionsEnum(Enum): # Indicates memory page is readable. (Custom constant) PAGE_READABLE = PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_READWRITE + # Indicates memory page is readable and writeable. (Custom constant) + PAGE_READWRITEABLE = PAGE_EXECUTE_READWRITE | PAGE_READWRITE + # Sets all locations in the pages as invalid targets for CFG. Used along with any execute page protection like # PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE and PAGE_EXECUTE_WRITECOPY. Any indirect call to locations # in those pages will fail CFG checks and the process will be terminated. The default behavior for executable pages diff --git a/PyMemoryEditor/win32/functions.py b/PyMemoryEditor/win32/functions.py index b570eef..6eff41b 100644 --- a/PyMemoryEditor/win32/functions.py +++ b/PyMemoryEditor/win32/functions.py @@ -137,6 +137,7 @@ def SearchAllMemory( value: Union[bool, int, float, str, bytes, tuple], scan_type: ScanTypesEnum = ScanTypesEnum.EXACT_VALUE, progress_information: bool = False, + writeable_only: bool = False, ) -> Generator[Union[int, Tuple[int, dict]], None, None]: """ Search the whole memory space, accessible to the process, @@ -171,6 +172,9 @@ def SearchAllMemory( if region["struct"].Type != MemoryTypesEnum.MEM_PRIVATE.value: continue if region["struct"].Protect & MemoryProtectionsEnum.PAGE_READABLE.value == 0: continue + # If writeable_only is True, checks if the memory page is writeable. + if writeable_only and region["struct"].Protect & MemoryProtectionsEnum.PAGE_READWRITEABLE.value == 0: continue + memory_total += region["size"] regions.append(region) diff --git a/PyMemoryEditor/win32/process.py b/PyMemoryEditor/win32/process.py index 6adb924..da978b7 100644 --- a/PyMemoryEditor/win32/process.py +++ b/PyMemoryEditor/win32/process.py @@ -66,6 +66,7 @@ def search_by_value( scan_type: ScanTypesEnum = ScanTypesEnum.EXACT_VALUE, *, progress_information: bool = False, + writeable_only: bool = False, ) -> Generator[Union[int, Tuple[int, dict]], None, None]: """ Search the whole memory space, accessible to the process, @@ -76,6 +77,7 @@ def search_by_value( :param value: value to be queried (bool, int, float, str or bytes). :param scan_type: the way to compare the values. :param progress_information: if True, a dictionary with the progress information will be return. + :param writeable_only: if True, search only at writeable memory regions. """ if self.__closed: raise ClosedProcess() @@ -89,7 +91,7 @@ def search_by_value( if scan_type in [ScanTypesEnum.VALUE_BETWEEN, ScanTypesEnum.NOT_VALUE_BETWEEN]: raise ValueError("Use the method search_by_value_between(...) to search within a range of values.") - return SearchAllMemory(self.__process_handle, pytype, bufflength, value, scan_type, progress_information) + return SearchAllMemory(self.__process_handle, pytype, bufflength, value, scan_type, progress_information, writeable_only) def search_by_value_between( self, @@ -100,6 +102,7 @@ def search_by_value_between( *, not_between: bool = False, progress_information: bool = False, + writeable_only: bool = False, ) -> Generator[Union[int, Tuple[int, dict]], None, None]: """ Search the whole memory space, accessible to the process, @@ -111,6 +114,7 @@ def search_by_value_between( :param end: maximum inclusive value to be queried (bool, int, float, str or bytes). :param not_between: if True, return only addresses of values that are NOT within the range. :param progress_information: if True, a dictionary with the progress information will be return. + :param writeable_only: if True, search only at writeable memory regions. """ if self.__closed: raise ClosedProcess() @@ -122,7 +126,7 @@ def search_by_value_between( raise PermissionError("The handle does not have permission to read the process memory.") scan_type = ScanTypesEnum.NOT_VALUE_BETWEEN if not_between else ScanTypesEnum.VALUE_BETWEEN - return SearchAllMemory(self.__process_handle, pytype, bufflength, (start, end), scan_type, progress_information) + return SearchAllMemory(self.__process_handle, pytype, bufflength, (start, end), scan_type, progress_information, writeable_only) def read_process_memory( self,