diff --git a/PyMemoryEditor/__init__.py b/PyMemoryEditor/__init__.py index 0150815..803e208 100644 --- a/PyMemoryEditor/__init__.py +++ b/PyMemoryEditor/__init__.py @@ -1,12 +1,14 @@ # -*- coding: utf-8 -*- """ -A Python library developed with ctypes to manipulate Windows and Linux processes (32 bits and 64 bits), -reading and writing values in the process memory. +Multi-platform library developed with ctypes for reading, writing and +searching process memory, in a simple and friendly way with Python 3. + +The package supports Windows and Linux (32-bit and 64-bit). """ __author__ = "Jean Loui Bernard Silva de Jesus" -__version__ = "1.5.6" +__version__ = "1.5.7" from .enums import ScanTypesEnum @@ -21,4 +23,6 @@ # For Linux. else: from .linux.process import LinuxProcess + from .linux.ptrace import ptrace + from .linux.ptrace.enums import PtraceCommandsEnum OpenProcess = LinuxProcess diff --git a/PyMemoryEditor/linux/ptrace/__init__.py b/PyMemoryEditor/linux/ptrace/__init__.py index d17ec58..1a91614 100644 --- a/PyMemoryEditor/linux/ptrace/__init__.py +++ b/PyMemoryEditor/linux/ptrace/__init__.py @@ -5,7 +5,7 @@ # https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/baselib-ptrace-1.html # ... -from .enums import CommandsEnum +from .enums import PtraceCommandsEnum from ctypes.util import find_library import ctypes @@ -15,7 +15,7 @@ libc.ptrace.restype = ctypes.c_long -def ptrace(command: CommandsEnum, pid: int, *args: int) -> int: +def ptrace(command: PtraceCommandsEnum, pid: int, *args: int) -> int: """ Run ptrace() system call with the provided command, pid and arguments. """ diff --git a/PyMemoryEditor/linux/ptrace/enums.py b/PyMemoryEditor/linux/ptrace/enums.py index 3efb20f..b581809 100644 --- a/PyMemoryEditor/linux/ptrace/enums.py +++ b/PyMemoryEditor/linux/ptrace/enums.py @@ -3,7 +3,7 @@ from enum import Enum -class CommandsEnum(Enum): +class PtraceCommandsEnum(Enum): """ Enum with commands for ptrace() system call. diff --git a/PyMemoryEditor/process/__init__.py b/PyMemoryEditor/process/__init__.py index 89a5077..3c03667 100644 --- a/PyMemoryEditor/process/__init__.py +++ b/PyMemoryEditor/process/__init__.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- from abc import ABC, abstractmethod -from typing import Optional, Type, TypeVar, Union +from typing import Generator, Optional, Tuple, Type, TypeVar, Union +from ..enums import ScanTypesEnum from ..process.info import ProcessInfo @@ -52,6 +53,63 @@ def close(self) -> bool: """ raise NotImplementedError() + @abstractmethod + def get_memory_regions(self) -> Generator[dict, None, None]: + """ + Generates dictionaries with the address, size and other + information of each memory region used by the process. + """ + raise NotImplementedError() + + @abstractmethod + def search_by_value( + self, + pytype: Type[T], + bufflength: int, + value: Union[bool, int, float, str, bytes], + 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, + for the provided value, returning the found addresses. + + :param pytype: type of value to be queried (bool, int, float, str or bytes). + :param bufflength: value size in bytes (1, 2, 4, 8). + :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. + """ + raise NotImplementedError() + + def search_by_value_between( + self, + pytype: Type[T], + bufflength: int, + start: Union[bool, int, float, str, bytes], + end: Union[bool, int, float, str, bytes], + *, + 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, + for a value within the provided range, returning the found addresses. + + :param pytype: type of value to be queried (bool, int, float, str or bytes). + :param bufflength: value size in bytes (1, 2, 4, 8). + :param start: minimum inclusive value to be queried (bool, int, float, str or bytes). + :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. + """ + raise NotImplementedError() + @abstractmethod def read_process_memory( self, diff --git a/PyMemoryEditor/process/util.py b/PyMemoryEditor/process/util.py index afcc316..0dad91b 100644 --- a/PyMemoryEditor/process/util.py +++ b/PyMemoryEditor/process/util.py @@ -4,8 +4,7 @@ import sys if "win" in sys.platform: - from win32.win32gui import FindWindow - from win32.win32process import GetWindowThreadProcessId + from ..win32.functions import GetProcessIdByWindowTitle def get_process_id_by_process_name(process_name: str) -> int: @@ -24,8 +23,7 @@ def get_process_id_by_window_title(window_title: str) -> int: if "win" not in sys.platform: raise OSError("This function is compatible only with Windows OS.") - hwnd = FindWindow(None, window_title) - return GetWindowThreadProcessId(hwnd)[1] if hwnd else 0 + return GetProcessIdByWindowTitle(window_title) def pid_exists(pid: int) -> bool: diff --git a/pyproject.toml b/pyproject.toml index 39b1e9d..df78ecd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "PyMemoryEditor" dynamic = ["version"] -description = "A Python library to edit and track memory of Windows and Linux processes (32 bits and 64 bits)." +description = "Multi-platform library developed with ctypes for reading, writing and searching process memory, in a simple and friendly way with Python 3. The package supports Windows and Linux (32-bit and 64-bit)." authors = [ { name = "Jean Loui Bernard Silva de Jesus", email = "jeanextreme002@gmail.com" }, ] @@ -36,13 +36,14 @@ classifiers = [ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Topic :: Scientific/Engineering", "Topic :: Security", "Topic :: System :: Monitoring" ] exclude = ["tests"] requires-python = ">=3.6" -dependencies = ['pywin32 ; platform_system == "Windows"', "psutil"] +dependencies = ["psutil"] [project.optional-dependencies] tests = [ diff --git a/requirements.txt b/requirements.txt index d907143..c75b26b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,2 @@ -pywin32 ; sys_platform == 'win32' psutil pytest