Quick Start
Five minutes from pip install to overwriting a value in another process.
1. Install
pip install PyMemoryEditor
(See Installation for the GUI app or installing from source.)
2. Open a process
PyMemoryEditor exposes a single entry point: OpenProcess. You can target a
process by name or PID:
from PyMemoryEditor import OpenProcess
# By process name
process = OpenProcess(process_name="notepad.exe")
# Or by PID
process = OpenProcess(pid=1234)
The recommended pattern is a with block — it closes the handle automatically:
with OpenProcess(process_name="notepad.exe") as process:
...
By default, OpenProcess opens a read + write handle. No special permission
flag needed for the common case.
3. Read and write a value
The easiest way is the typed shortcuts — the size is baked into the method name, so there’s nothing to remember:
from PyMemoryEditor import OpenProcess
with OpenProcess(process_name="notepad.exe") as process:
address = 0x0005000C
value = process.read_int(address) # read a 4-byte int
print("Current:", value)
process.write_int(address, value + 7) # write it back
There’s a read_* / write_* pair for every common type — read_float,
read_bool, read_uint, read_string, and more:
name = process.read_string(address, 32) # up to 32 bytes, decoded as text
Prefer to spell out the type yourself? The generic read_process_memory /
write_process_memory cover every case too — see
Reading and writing memory.
4. Run your first scan
You rarely know the address of a value up front — you find it by scanning.
search_by_value yields every address holding a given value:
with OpenProcess(process_name="game.exe") as process:
for address in process.search_by_value(int, value=100):
print(f"Found at 0x{address:X}")
That’s the same operation Cheat Engine performs in its First Scan button. See the searching guide for all eight comparison modes and the refine workflow.
5. The Cheat Engine workflow
The classic loop is:
Scan for a value you can see (e.g. your health is
100) — you get back many candidate addresses.Let the value change in the target (you take damage →
95).Refine: keep only the addresses that now hold the new value. Repeat until one address remains — that’s your value.
Read, write or freeze it.
with OpenProcess(process_name="game.exe") as process:
# 1. First scan — every address currently holding 100.
candidates = list(process.search_by_value(int, value=100))
# 3. After the value drops to 95 in-game, keep only the matches that agree.
survivors = [
address
for address, value in process.search_by_addresses(int, addresses=candidates)
if value == 95
]
# 4. Overwrite the survivors back to a high value.
for address in survivors:
process.write_int(address, 9999)
For big targets, see the refine-scan workflow to cache the region map once.
6. Pointer scanning — make an address survive restarts
The address you just found is useless next launch. The OS loads everything
somewhere new every time (ASLR), so 0x1FA3C140 today is garbage tomorrow.
The fix is a static pointer path: a chain that starts at a fixed location
inside a loaded module and dereferences its way to your value — so the same
recipe keeps working across restarts.
PyMemoryEditor finds these for you. scan_pointer_paths is a reverse pointer
scan (Cheat Engine’s “Pointer scan”): give it the value’s address right now,
and it discovers the static paths that resolve to it.
with OpenProcess(process_name="game.exe") as process:
# The value lives here this run (e.g. from search_by_value above).
for path in process.scan_pointer_paths(0x1FA3C140, max_depth=4):
print(path)
# "game.exe"+0x10F4F4 -> [+0x0] -> +0x158
print(hex(path.resolve(process)))
Each result is a PointerPath carrying the module + offsets — the part that
survives a restart. Save the reliable ones and reuse them later:
with OpenProcess(process_name="game.exe") as process:
paths = list(process.scan_pointer_paths(0x1FA3C140, max_depth=4))
process.save_pointer_paths(paths, "health.json")
# ...next launch, the absolute address has changed but the path still works:
with OpenProcess(process_name="game.exe") as process:
survivors = process.rescan_pointer_paths("health.json", 0x2B7C0140)
pointer = survivors[0].rebase(process).to_pointer(process)
pointer.write(9999)
See the pointer scan guide for tuning the scan
(max_depth, max_offset), the multi-run refine workflow, and intersecting
independent scans with compare_pointer_scans.
Next steps
📖 User guide — every workflow, in depth.
🖥️ The bundled GUI app — same features, no code required.
📚 API reference — every public class and method.
🛟 Troubleshooting — common errors and how to fix them.
⚖️ Responsible use
PyMemoryEditor talks to other processes through OS-level APIs. Only point it at processes you own or have explicit permission to inspect.