OpenProcess (process API)

OpenProcess is the unified entry point. Depending on the host OS, it resolves to:

PlatformConcrete class
πŸͺŸ WindowsPyMemoryEditor.win32.process.WindowsProcess
🐧 LinuxPyMemoryEditor.linux.process.LinuxProcess
🍎 macOSPyMemoryEditor.macos.process.MacProcess

All three subclass AbstractProcess and share the API documented below.

class AbstractProcess

The cross-platform base class every backend implements. OpenProcess returns one of its subclasses; the methods documented on this page are the shared, public surface.

Construction

class OpenProcess(*, process_name=None, pid=None, permission=<platform default>, case_sensitive=<platform default>, exact_match=True)

Open a target process. OpenProcess resolves to the concrete backend for the host OS, so the permission and case_sensitive defaults are platform-specific (see below): on Windows permission defaults to the read+write mask and case_sensitive to False; on Linux/macOS permission defaults to None (ignored) and case_sensitive to True.

Parameters:
  • process_name (str) – name of the target process.

  • pid (int) – process ID. Takes precedence over process_name.

  • permission – Windows only. A ProcessOperationsEnum value (or integer). Defaults to read+write (PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION). On Linux and macOS this argument is accepted for API parity but ignored; passing a non-None value emits UserWarning.

  • case_sensitive (bool) – when False, process_name matching ignores case. Default is False on Windows, True elsewhere.

  • exact_match (bool) – when False, process_name matches as a substring ("chrome" matches "chrome.exe").

Raises:

Examples

# By name
with OpenProcess(process_name="game.exe") as process:
    ...

# By PID
with OpenProcess(pid=1234) as process:
    ...

# Partial, case-insensitive name match (Windows-friendly)
with OpenProcess(process_name="chrome", case_sensitive=False, exact_match=False) as process:
    ...

# Read-only handle (Windows only)
from PyMemoryEditor import ProcessOperationsEnum

with OpenProcess(
    process_name="game.exe",
    permission=ProcessOperationsEnum.PROCESS_VM_READ | ProcessOperationsEnum.PROCESS_QUERY_INFORMATION,
) as process:
    ...

Attributes

pid: int

The PID of the target process.

main_thread: ThreadInfo | None

The conventional β€œmain thread” of the target β€” by convention, the thread with the smallest tid. Returns None if the process has no listable threads (rare).

Methods

Read / write

read_process_memory(address, pytype, bufflength=None)

Read a value from memory.

Parameters:
  • address (int) – target memory address.

  • pytype (Type) – bool, int, float, str or bytes.

  • bufflength (int) – value size in bytes (optional for numeric types).

Returns:

the decoded value.

write_process_memory(address, pytype, bufflength=None, value=...)

Write a value to memory.

Parameters:
  • address (int) – target memory address.

  • pytype (Type) – one of the five supported types.

  • bufflength (int) – value size in bytes. Optional (defaults to None): numeric types fall back to their default width and str / bytes write the whole value. For str / bytes an explicit value is a maximum width that truncates the value and never pads β€” str counts characters (applied before UTF-8 encoding, so multibyte characters are never split), bytes counts bytes. Because it is optional, pass value by keyword when omitting it (write_process_memory(addr, int, value=9999)).

  • value – the value to write.

Returns:

the written value.

Typed shortcuts

Convenience read_* / write_* pairs with the size and signedness baked into the name β€” see :doc:../guide/read-write for examples. Widths are fixed and identical on every platform.

read_char(address)

Read / write a signed 8-bit integer (1 byte). Pair: write_char(address, value).

read_short(address)

Signed 16-bit integer (2 bytes). Pair: write_short.

read_int(address)

Signed 32-bit integer (4 bytes). Pair: write_int.

read_long(address)

Signed 32-bit integer (4 bytes, Win32 LONG). Pair: write_long.

read_longlong(address)

Signed 64-bit integer (8 bytes). Pair: write_longlong.

read_uchar(address)

Unsigned variants of the above: read_uchar / read_ushort / read_uint / read_ulong / read_ulonglong (1 / 2 / 4 / 4 / 8 bytes), each with a matching write_*.

read_float(address)

32-bit float (4 bytes). Pair: write_float.

read_double(address)

64-bit double (8 bytes). Pair: write_double.

read_bool(address)

Boolean (1 byte). Pair: write_bool.

read_string(address, byte_count)

Read exactly byte_count bytes (a short read raises OSError), decode UTF-8, and return the text up to the first NUL β€” so byte_count is the field width to read, not an upper bound. Pair: write_string(address, text, *, null_terminator=False).

read_bytes(address, length)

Read length raw bytes. Pair: write_bytes(address, data).

Searching

search_by_value(pytype, bufflength=None, value=..., scan_type=ScanTypesEnum.EXACT_VALUE, *, progress_information=False, writeable_only=False, memory_regions=None)

Yield every address holding value (compared per scan_type). bufflength is optional (numeric types use their default width; str / bytes infer it from value) β€” pass value by keyword when omitting it. See Searching memory for a full walkthrough.

search_by_value_between(pytype, bufflength=None, start=..., end=..., *, not_between=False, progress_information=False, writeable_only=False, memory_regions=None)

Yield every address whose value is in [start, end] (or outside, with not_between=True).

search_by_addresses(pytype, bufflength=None, addresses=..., *, raise_error=False, memory_regions=None)

Read each address in addresses once, yielding (address, value). Far faster than looping over read_process_memory(). bufflength is optional for numeric types; str / bytes still need an explicit size (no value to infer from) β€” pass addresses by keyword when omitting it.

search_by_pattern(pattern, *, byte_length=0, progress_information=False, memory_regions=None)

Scan memory for a byte pattern β€” IDA-style hex, raw bytes regex, or a compiled re.Pattern. See Pattern scan (AOB / regex).

Memory regions

get_memory_regions()

Yield a MemoryRegion per region β€” an immutable dataclass with address, size, is_readable, is_writable, is_executable, is_shared, path and the platform-specific struct.

snapshot_memory_regions()

Materialize the region list once as a MemoryRegionSnapshot (pre-sorted by base address), for reuse across iterative scans.

Modules and threads

get_modules()

Yield a ModuleInfo for every loaded module.

get_threads()

Yield a ThreadInfo for every thread inside the target.

Pointers

resolve_pointer_chain(base_address, offsets, *, ptr_size=None)

Walk a multi-level pointer chain and return the final address.

get_pointer(base_address, offsets=None, *, pytype=int, bufflength=None, ptr_size=None)

Build a RemotePointer bound to this process β€” a live, re-resolving handle. See Pointers.

scan_pointer_paths(target_address, *, max_depth=5, max_offset=0x400, ptr_size=None, aligned=True, writable_only=True, static_ranges=None, max_results=None, memory_regions=None, progress_callback=None)

Reverse pointer scan β€” yield PointerPath recipes that resolve to target_address. See Pointer scan (reverse).

save_pointer_paths(paths, file)

Save pointer paths to a JSON file.

load_pointer_paths(file)

Load pointer paths previously saved with save_pointer_paths().

rescan_pointer_paths(paths, target_address)

Keep only the paths that still resolve to target_address.

compare_pointer_scans(*sources)

Intersect several saved scans β€” return the paths present in every one.

Allocation

allocate_memory(size, *, permission=None)

Reserve size bytes inside the target. Windows and macOS only.

free_memory(address, size=0)

Release a previously allocated region.

Lifecycle

close()

Close the process handle. Subsequent calls raise ClosedProcess.

__enter__()
__exit__(exc_type, exc_value, exc_traceback)

The process is also a context manager β€” prefer the with block.