diff --git a/.gitignore b/.gitignore index 6ad846b..79a8109 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,4 @@ __pycache__ *.pyc *.egg-info/ -build/ dist/ diff --git a/MANIFEST.in b/MANIFEST.in index 2b8b271..c28ab72 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,2 @@ include README.md include LICENSE.md -include mem_edit/VERSION diff --git a/README.md b/README.md index 53789b7..71840ab 100644 --- a/README.md +++ b/README.md @@ -18,19 +18,19 @@ ## Installation **Dependencies:** -* python 3 (written and tested with 3.7) -* ctypes -* typing (for type annotations) +* python 3 (written and tested with 3.5) +* ctypes +* typing (for type annotations) Install with pip, from PyPI (preferred): ```bash -pip3 install mem_edit +pip install mem_edit ``` Install with pip from git repository ```bash -pip3 install git+https://mpxd.net/code/jan/mem_edit.git@release +pip install git+https://mpxd.net/code/jan/mem_edit.git@release ``` @@ -55,7 +55,7 @@ Increment a magic number (unsigned long 1234567890) found in 'magic.exe': pid = Process.get_pid_by_name('magic.exe') with Process.open_process(pid) as p: addrs = p.search_all_memory(magic_number) - + # We don't want to edit if there's more than one result... assert(len(addrs) == 1) @@ -104,7 +104,7 @@ Read and alter a structure: s = MyStruct() s.first_member = 1234567890 s.second_member = 0x1234 - + addrs = p.search_all_memory(s) print(addrs) diff --git a/mem_edit/VERSION b/mem_edit/VERSION deleted file mode 100644 index be58634..0000000 --- a/mem_edit/VERSION +++ /dev/null @@ -1 +0,0 @@ -0.3 diff --git a/mem_edit/__init__.py b/mem_edit/__init__.py index 8947638..9f3fbf9 100644 --- a/mem_edit/__init__.py +++ b/mem_edit/__init__.py @@ -12,17 +12,12 @@ To get started, try: """ import platform -import pathlib from .utils import MemEditError __author__ = 'Jan Petykiewicz' -with open(pathlib.Path(__file__).parent / 'VERSION', 'r') as f: - __version__ = f.read().strip() -version = __version__ - system = platform.system() if system == 'Windows': diff --git a/mem_edit/abstract.py b/mem_edit/abstract.py index fb463f7..e08740a 100644 --- a/mem_edit/abstract.py +++ b/mem_edit/abstract.py @@ -9,8 +9,7 @@ import copy import ctypes import logging -from . import utils -from .utils import ctypes_buffer_t +from .utils import ctypes_buffer_t, search_buffer, ctypes_equal logging.basicConfig(level=logging.INFO) @@ -241,7 +240,7 @@ class Process(metaclass=ABCMeta): values = [self.read_memory(base + offset, buffer) for offset, buffer in targets] return values - def search_addresses(self, addresses: List[int], needle_buffer: ctypes_buffer_t, verbatim: bool=True) -> List[int]: + def search_addresses(self, addresses: List[int], needle_buffer: ctypes_buffer_t) -> List[int]: """ Search for the provided value at each of the provided addresses, and return the addresses where it is found. @@ -250,26 +249,18 @@ class Process(metaclass=ABCMeta): :param needle_buffer: The value to search for. This should be a ctypes object of the same sorts as used by .read_memory(...), which will be compared to the contents of memory at each of the given addresses. - :param verbatim: If True, perform bitwise comparison when searching for needle_buffer. - If False, perform utils.ctypes_equal-based comparison. Default True. :return: List of addresses where the needle_buffer was found. """ found = [] read_buffer = copy.copy(needle_buffer) - if verbatim: - def compare(a, b): - return bytes(read_buffer) == bytes(needle_buffer) - else: - compare = utils.ctypes_equal - for address in addresses: - self.read_memory(address, read_buffer) - if compare(needle_buffer, read_buffer): + read = self.read_memory(address, read_buffer) + if ctypes_equal(needle_buffer, read): found.append(address) return found - def search_all_memory(self, needle_buffer: ctypes_buffer_t, writeable_only: bool=True, verbatim: bool=True) -> List[int]: + def search_all_memory(self, needle_buffer, writeable_only=True) -> List[int]: """ Search the entire memory space accessible to the process for the provided value. @@ -277,22 +268,14 @@ class Process(metaclass=ABCMeta): sorts as used by .read_memory(...), which will be compared to the contents of memory at each accessible address. :param writeable_only: If True, only search regions where the process has write access. - Default True. - :param verbatim: If True, perform bitwise comparison when searching for needle_buffer. - If False, perform utils.ctypes_equal-based comparison. Default True. :return: List of addresses where the needle_buffer was found. """ found = [] - if verbatim: - search = utils.search_buffer_verbatim - else: - search = utils.search_buffer - for start, stop in self.list_mapped_regions(writeable_only): try: region_buffer = (ctypes.c_byte * (stop - start))() self.read_memory(start, region_buffer) - found += [offset + start for offset in search(needle_buffer, region_buffer)] + found += [offset + start for offset in search_buffer(needle_buffer, region_buffer)] except OSError: logger.error('Failed to read in range 0x{} - 0x{}'.format(start, stop)) return found diff --git a/mem_edit/linux.py b/mem_edit/linux.py index ae8404d..4dafd1c 100644 --- a/mem_edit/linux.py +++ b/mem_edit/linux.py @@ -40,7 +40,7 @@ def ptrace(command: int, pid: int = 0, arg1: int = 0, arg2: int = 0) -> int: """ Call ptrace() with the provided pid and arguments. See the ```man ptrace```. """ - logger.debug('ptrace({}, {}, {}, {})'.format(command, pid, arg1, arg2)) + logger.debug('ptrace({}, {}, {}, {})'.format(command, pid, arg1, arg2)) result = _ptrace(command, pid, arg1, arg2) if result == -1: err_no = ctypes.get_errno() @@ -58,7 +58,7 @@ class Process(AbstractProcess): self.pid = process_id def close(self): - os.kill(self.pid, signal.SIGSTOP) + os.kill(self.pid, signal.SIGSTOP) ptrace(ptrace_commands['PTRACE_DETACH'], self.pid, 0, 0) self.pid = None @@ -78,7 +78,7 @@ class Process(AbstractProcess): with open('/proc/{}/cmdline', 'rb') as f: return f.read().decode().split('\x00')[0] except FileNotFoundError: - return '' + return '' @staticmethod def list_available_pids() -> List[int]: diff --git a/mem_edit/utils.py b/mem_edit/utils.py index fc15970..c2e691f 100644 --- a/mem_edit/utils.py +++ b/mem_edit/utils.py @@ -23,32 +23,9 @@ class MemEditError(Exception): pass -def search_buffer_verbatim(needle_buffer: ctypes_buffer_t, haystack_buffer: ctypes_buffer_t) -> List[int]: - """ - Search for a buffer inside another buffer, using a direct (bitwise) comparison - - :param needle_buffer: Buffer to search for. - :param haystack_buffer: Buffer to search in. - :return: List of offsets where the needle_buffer was found. - """ - found = [] - - haystack = bytes(haystack_buffer) - needle = bytes(needle_buffer) - - start = 0 - result = haystack.find(needle, start) - while start < len(haystack) and result != -1: - found.append(result) - start = result + 1 - result = haystack.find(needle, start) - return found - - def search_buffer(needle_buffer: ctypes_buffer_t, haystack_buffer: ctypes_buffer_t) -> List[int]: """ - Search for a buffer inside another buffer, using ctypes_equal for comparison. - Much slower than search_buffer_verbatim. + Search for a buffer inside another buffer. :param needle_buffer: Buffer to search for. :param haystack_buffer: Buffer to search in. @@ -69,7 +46,7 @@ def ctypes_equal(a: ctypes_buffer_t, b: ctypes_buffer_t) -> bool: """ if not type(a) == type(b): return False - + if isinstance(a, ctypes.Array): return a[:] == b[:] elif isinstance(a, ctypes.Structure) or isinstance(a, ctypes.Union): diff --git a/setup.py b/setup.py index 5b53ab7..46b51f6 100644 --- a/setup.py +++ b/setup.py @@ -1,18 +1,10 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python from setuptools import setup, find_packages -with open('README.md', 'r') as f: - long_description = f.read() - -with open('mem_edit/VERSION', 'r') as f: - version = f.read().strip() - setup(name='mem_edit', - version=version, + version='0.1', description='Multi-platform library for memory editing', - long_description=long_description, - long_description_content_type='text/markdown', author='Jan Petykiewicz', author_email='anewusername@gmail.com', url='https://mpxd.net/code/jan/mem_edit', @@ -34,6 +26,7 @@ setup(name='mem_edit', 'trainer', ], classifiers=[ + 'Programming Language :: Python', 'Programming Language :: Python :: 3', 'Development Status :: 4 - Beta', 'Environment :: Other Environment', @@ -49,10 +42,8 @@ setup(name='mem_edit', 'Topic :: Utilities', ], packages=find_packages(), - package_data={ - 'mem_edit': ['VERSION'] - }, install_requires=[ + 'ctypes', 'typing', ], extras_require={