# PyMemoryEditor
A Python library developed with [ctypes](https://docs.python.org/3/library/ctypes.html) to manipulate Windows and Linux processes (32 bits and 64 bits), <br>
reading, writing and searching values in the process memory.
[![Python Package](https://github.com/JeanExtreme002/PyMemoryEditor/actions/workflows/python-package.yml/badge.svg)](https://github.com/JeanExtreme002/PyMemoryEditor/actions/workflows/python-package.yml)
[![Pypi](https://img.shields.io/pypi/v/PyMemoryEditor)](https://pypi.org/project/PyMemoryEditor/)
[![License](https://img.shields.io/pypi/l/PyMemoryEditor)](https://pypi.org/project/PyMemoryEditor/)
[![Platforms](https://img.shields.io/badge/platforms-Windows%20%7C%20Linux-8A2BE2)](https://pypi.org/project/PyMemoryEditor/)
[![Python Version](https://img.shields.io/badge/python-3.6%20%7C...%7C%203.11%20%7C%203.12-blue)](https://pypi.org/project/PyMemoryEditor/)
[![Downloads](https://static.pepy.tech/personalized-badge/pymemoryeditor?period=total&units=international_system&left_color=grey&right_color=orange&left_text=Downloads)](https://pypi.org/project/PyMemoryEditor/)
# Installing PyMemoryEditor:
```
pip install PyMemoryEditor
```
### Tkinter application sample:
Type `pymemoryeditor` at the CLI to run a tkinter app — similar to the [Cheat Engine](https://en.wikipedia.org/wiki/Cheat_Engine) — to scan a process.
# Basic Usage:
Import `PyMemoryEditor` and open a process using the `OpenProcess` class, passing a window title, process name <br>
or PID as an argument. You can use the context manager for doing it.
```py
from PyMemoryEditor import OpenProcess
with OpenProcess(process_name = "example.exe") as process:
# Do something...
```
After that, use the methods `read_process_memory` and `write_process_memory` to manipulate the process <br>
memory, passing in the function call the memory address, data type and its size. See the example below:
```py
from PyMemoryEditor import OpenProcess
title = "Window title of an example program"
address = 0x0005000C
with OpenProcess(window_title = title) as process:
# Getting value from the process memory.
value = process.read_process_memory(address, int, 4)
# Writing to the process memory.
process.write_process_memory(address, int, 4, value + 7)
```
# Getting memory addresses by a target value:
You can look up a value in memory and get the address of all matches, like this:
```py
for address in process.search_by_value(int, 4, target_value):
print("Found address:", address)
```
## Choosing the comparison method used for scanning:
There are many options to scan the memory. Check all available options in [`ScanTypesEnum`](https://github.com/JeanExtreme002/PyMemoryEditor/blob/master/PyMemoryEditor/win32/enums/scan_types.py).
The default option is `EXACT_VALUE`, but you can change it at `scan_type` parameter:
```py
for address in process.search_by_value(int, 4, target_value, scan_type = ScanTypesEnum.BIGGER_THAN):
print("Found address:", address)
```
**Note:** The scan types `EXACT_VALUE` and `NOT_EXACT_VALUE` uses [KMP (Knuth–Morris–Pratt) Algorithm](https://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm), that has completixy O(n + m) — `n` is the size of the memory page and `m` is the value length — to speed up the search process. The other scan types use the [brute force algorithm](https://en.wikipedia.org/wiki/Brute-force_search), which is O(n * m), so the search may be slower depending on the length of the target value.
You can also search for a value within a range:
```py
for address in process.search_by_value_between(int, 4, min_value, max_value, ...):
print("Found address:", address)
```
All methods described above work even for strings, including the method `search_by_value_between` — however, `bytes` comparison may work differently than `str` comparison, depending on the `byteorder` of your system.
## Progress information on searching:
These methods has the `progress_information` parameter that returns a dictionary containing the search progress information.
```py
for address, info in process.search_by_value(..., progress_information = True):
template = "Address: 0x{:<10X} | Progress: {:.1f}%"
progress = info["progress"] * 100
print(template.format(address, progress))
```
# Reading multiple addresses efficiently:
If you have a large number of addresses where their values need to be read from memory, using the `search_by_addresses` method is much more efficient than reading the value of each address one by one.
```py
for address, value in process.search_by_addresses(int, 4, addresses_list):
print(f"Address", address, "holds the value", value)
```
The key advantage of this method is that it reads a memory page just once, obtaining the values of the addresses within the page. This approach reduces the frequency of system calls.
## Getting memory regions:
Use the method `get_memory_regions()` to get the base address, size and more information of all memory regions used by the process.
```py
for memory_region in process.get_memory_regions():
base_address = memory_region["address"]
size = memory_region["size"]
information = memory_region["struct"]
```
Raw data
{
"_id": null,
"home_page": null,
"name": "PyMemoryEditor",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.6",
"maintainer_email": null,
"keywords": "address, api, cheat, ctypes, debug, editor, linux, memory, override, pointer, process, ptrace, reader, readprocessmemory, scanner, track, virtual, win32, writeprocessmemory, writer",
"author": null,
"author_email": "Jean Loui Bernard Silva de Jesus <jeanextreme002@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/da/65/28b4d050e7ef790011aaa5fa6938dc8078a99c67a68ddc8b13911fc242b3/pymemoryeditor-1.5.22.tar.gz",
"platform": null,
"description": "# PyMemoryEditor\nA Python library developed with [ctypes](https://docs.python.org/3/library/ctypes.html) to manipulate Windows and Linux processes (32 bits and 64 bits), <br>\nreading, writing and searching values in the process memory.\n\n[![Python Package](https://github.com/JeanExtreme002/PyMemoryEditor/actions/workflows/python-package.yml/badge.svg)](https://github.com/JeanExtreme002/PyMemoryEditor/actions/workflows/python-package.yml)\n[![Pypi](https://img.shields.io/pypi/v/PyMemoryEditor)](https://pypi.org/project/PyMemoryEditor/)\n[![License](https://img.shields.io/pypi/l/PyMemoryEditor)](https://pypi.org/project/PyMemoryEditor/)\n[![Platforms](https://img.shields.io/badge/platforms-Windows%20%7C%20Linux-8A2BE2)](https://pypi.org/project/PyMemoryEditor/)\n[![Python Version](https://img.shields.io/badge/python-3.6%20%7C...%7C%203.11%20%7C%203.12-blue)](https://pypi.org/project/PyMemoryEditor/)\n[![Downloads](https://static.pepy.tech/personalized-badge/pymemoryeditor?period=total&units=international_system&left_color=grey&right_color=orange&left_text=Downloads)](https://pypi.org/project/PyMemoryEditor/)\n\n# Installing PyMemoryEditor:\n```\npip install PyMemoryEditor\n```\n\n### Tkinter application sample:\nType `pymemoryeditor` at the CLI to run a tkinter app \u2014 similar to the [Cheat Engine](https://en.wikipedia.org/wiki/Cheat_Engine) \u2014 to scan a process.\n\n# Basic Usage:\nImport `PyMemoryEditor` and open a process using the `OpenProcess` class, passing a window title, process name <br>\nor PID as an argument. You can use the context manager for doing it.\n```py\nfrom PyMemoryEditor import OpenProcess\n\nwith OpenProcess(process_name = \"example.exe\") as process:\n # Do something...\n```\n\nAfter that, use the methods `read_process_memory` and `write_process_memory` to manipulate the process <br>\nmemory, passing in the function call the memory address, data type and its size. See the example below:\n```py\nfrom PyMemoryEditor import OpenProcess\n\ntitle = \"Window title of an example program\"\naddress = 0x0005000C\n\nwith OpenProcess(window_title = title) as process:\n\n # Getting value from the process memory.\n value = process.read_process_memory(address, int, 4)\n\n # Writing to the process memory.\n process.write_process_memory(address, int, 4, value + 7)\n```\n\n# Getting memory addresses by a target value:\nYou can look up a value in memory and get the address of all matches, like this:\n```py\nfor address in process.search_by_value(int, 4, target_value):\n print(\"Found address:\", address)\n```\n\n## Choosing the comparison method used for scanning:\nThere are many options to scan the memory. Check all available options in [`ScanTypesEnum`](https://github.com/JeanExtreme002/PyMemoryEditor/blob/master/PyMemoryEditor/win32/enums/scan_types.py).\n\nThe default option is `EXACT_VALUE`, but you can change it at `scan_type` parameter:\n```py\nfor address in process.search_by_value(int, 4, target_value, scan_type = ScanTypesEnum.BIGGER_THAN):\n print(\"Found address:\", address)\n```\n\n**Note:** The scan types `EXACT_VALUE` and `NOT_EXACT_VALUE` uses [KMP (Knuth\u2013Morris\u2013Pratt) Algorithm](https://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm), that has completixy O(n + m) \u2014 `n` is the size of the memory page and `m` is the value length \u2014 to speed up the search process. The other scan types use the [brute force algorithm](https://en.wikipedia.org/wiki/Brute-force_search), which is O(n * m), so the search may be slower depending on the length of the target value.\n\nYou can also search for a value within a range:\n```py\nfor address in process.search_by_value_between(int, 4, min_value, max_value, ...):\n print(\"Found address:\", address)\n```\n\nAll methods described above work even for strings, including the method `search_by_value_between` \u2014 however, `bytes` comparison may work differently than `str` comparison, depending on the `byteorder` of your system.\n\n## Progress information on searching:\nThese methods has the `progress_information` parameter that returns a dictionary containing the search progress information.\n```py\nfor address, info in process.search_by_value(..., progress_information = True):\n template = \"Address: 0x{:<10X} | Progress: {:.1f}%\"\n progress = info[\"progress\"] * 100\n \n print(template.format(address, progress))\n```\n\n# Reading multiple addresses efficiently:\nIf you have a large number of addresses where their values need to be read from memory, using the `search_by_addresses` method is much more efficient than reading the value of each address one by one.\n```py\nfor address, value in process.search_by_addresses(int, 4, addresses_list):\n print(f\"Address\", address, \"holds the value\", value)\n```\nThe key advantage of this method is that it reads a memory page just once, obtaining the values of the addresses within the page. This approach reduces the frequency of system calls.\n\n## Getting memory regions:\nUse the method `get_memory_regions()` to get the base address, size and more information of all memory regions used by the process.\n\n```py\nfor memory_region in process.get_memory_regions():\n base_address = memory_region[\"address\"]\n size = memory_region[\"size\"]\n information = memory_region[\"struct\"]\n```\n",
"bugtrack_url": null,
"license": null,
"summary": "Multi-platform library developed with ctypes for reading, writing and searching at process memory, in a simple and friendly way with Python 3.",
"version": "1.5.22",
"project_urls": {
"Homepage": "https://github.com/JeanExtreme002/PyMemoryEditor"
},
"split_keywords": [
"address",
" api",
" cheat",
" ctypes",
" debug",
" editor",
" linux",
" memory",
" override",
" pointer",
" process",
" ptrace",
" reader",
" readprocessmemory",
" scanner",
" track",
" virtual",
" win32",
" writeprocessmemory",
" writer"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "0b1b0a025f76f743724a6605ba53e6d099f1af7d426670a51a757920e3b38605",
"md5": "e95dfd4e13e9257233b622ef5c69bc46",
"sha256": "9ff1c046a0b78090fe97bf2320ae641220d0033f9547377b1c5a6d208be7f65c"
},
"downloads": -1,
"filename": "pymemoryeditor-1.5.22-py3-none-any.whl",
"has_sig": false,
"md5_digest": "e95dfd4e13e9257233b622ef5c69bc46",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.6",
"size": 39410,
"upload_time": "2024-05-29T21:09:26",
"upload_time_iso_8601": "2024-05-29T21:09:26.138917Z",
"url": "https://files.pythonhosted.org/packages/0b/1b/0a025f76f743724a6605ba53e6d099f1af7d426670a51a757920e3b38605/pymemoryeditor-1.5.22-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "da6528b4d050e7ef790011aaa5fa6938dc8078a99c67a68ddc8b13911fc242b3",
"md5": "089d1125d1862dedf37c4f643b6f0b21",
"sha256": "e19bcce5ba63f89c6fe6b2930ab379a1f02de355d05593611e1a2d32ad578b98"
},
"downloads": -1,
"filename": "pymemoryeditor-1.5.22.tar.gz",
"has_sig": false,
"md5_digest": "089d1125d1862dedf37c4f643b6f0b21",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.6",
"size": 29389,
"upload_time": "2024-05-29T21:09:28",
"upload_time_iso_8601": "2024-05-29T21:09:28.086457Z",
"url": "https://files.pythonhosted.org/packages/da/65/28b4d050e7ef790011aaa5fa6938dc8078a99c67a68ddc8b13911fc242b3/pymemoryeditor-1.5.22.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-05-29 21:09:28",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "JeanExtreme002",
"github_project": "PyMemoryEditor",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [],
"lcname": "pymemoryeditor"
}