Skip to content

Latest commit

History

History
371 lines (262 loc) · 12.7 KB

File metadata and controls

371 lines (262 loc) · 12.7 KB

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.

.. py: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

.. py:class:: OpenProcess(*, name=None, pid=None, permission=<platform default>, case_sensitive=<platform default>, exact_match=True, strict_bitness=False)
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``.
:param str name: name of the target process.
:param int pid: process ID. Takes precedence over ``name``.
:param permission: **Windows only.** A
:py:class:`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``.
:param bool case_sensitive: when ``False``, ``name`` matching
ignores case. Default is ``False`` on Windows, ``True`` elsewhere.
:param bool exact_match: when ``False``, ``name`` matches as a
substring (``"chrome"`` matches ``"chrome.exe"``).
:param bool strict_bitness: when ``True``, :py:attr:`is_64bit` raises
:py:exc:`BitnessDetectionError` if the target's 32-/64-bit width
can't be read from its headers, instead of falling back to the host
word size. Use it when a wrong pointer-width default would be worse
than a hard failure.
:raises ProcessNotFoundError: no process matches ``name``.
:raises ProcessIDNotExistsError: ``pid`` doesn't exist.
:raises AmbiguousProcessNameError: more than one process matches.
:raises TypeError: neither ``name`` nor ``pid`` was provided.
:raises PermissionError: the OS denied access.

Examples

# By namewithOpenProcess(name="game.exe") asprocess:
...
# By PIDwithOpenProcess(pid=1234) asprocess:
...
# Partial, case-insensitive name match (Windows-friendly)withOpenProcess(name="chrome", case_sensitive=False, exact_match=False) asprocess:
...
# Read-only handle (Windows only)fromPyMemoryEditorimportProcessOperationsEnumwithOpenProcess(
name="game.exe",
permission=ProcessOperationsEnum.PROCESS_VM_READ|ProcessOperationsEnum.PROCESS_QUERY_INFORMATION,
) asprocess:
...

Attributes

.. py:attribute:: pid
:type: int
:no-index:
The PID of the target process.
.. py:attribute:: main_thread
:type: Optional[ThreadInfo]
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).
.. py:attribute:: is_64bit
:type: bool
``True`` if the target process is 64-bit, ``False`` if it is 32-bit.
Detected once on first access (via headers: ELF class on Linux, Mach-O
magic on macOS, ``IsWow64Process`` on Windows) and cached.
When the backend can't read the headers, the result depends on
``strict_bitness``: ``False`` (default) falls back to the host word size
and logs a WARNING; ``True`` raises
:py:exc:`BitnessDetectionError`.
.. py:attribute:: is_bitness_certain
:type: bool
``True`` if :py:attr:`is_64bit` was read from the target's own headers,
``False`` if it fell back to a guess of the host word size.
When ``False`` the automatic ``ptr_size`` default may be wrong for a
cross-bitness target — pass ``ptr_size`` explicitly to the pointer APIs.
.. py:attribute:: pointer_size
:type: int
Pointer width of the target process in bytes — ``8`` for a 64-bit target,
``4`` for a 32-bit one. Derived from :py:attr:`is_64bit`.

Methods

Read / write

.. py:method:: read_process_memory(address, pytype, bufflength=None)
Read a value from memory.
:param int address: target memory address.
:param Type pytype: ``bool``, ``int``, ``float``, ``str`` or ``bytes``.
:param int bufflength: value size in bytes (optional for numeric types).
:returns: the decoded value.
.. py:method:: write_process_memory(address, pytype, bufflength=None, value=...)
Write a value to memory.
:param int address: target memory address.
:param Type pytype: one of the five supported types.
:param int bufflength: 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)``).
:param value: the value to write.
:returns: the original ``value`` you passed in — **not** the truncated/encoded
form actually written (a capped ``str``/``bytes`` write returns the full
original value).
.. py:method:: read_process_memory_into(address, buffer)
Read ``len(buffer)`` raw bytes from ``address`` directly into a
pre-allocated, writable ``buffer`` (no intermediate allocation) — the
zero-copy counterpart of :py:meth:`read_process_memory` for tight
read-the-same-region loops. See :doc:`../guide/read-write` for examples.
:param int address: target memory address.
:param buffer: any writable, contiguous buffer-protocol object
(``bytearray``, ``ctypes`` array, writable ``memoryview``, ``numpy``
array, …). Its byte length sets how many bytes are read; the bytes land
verbatim (no decoding).
:returns: the number of bytes read (the buffer's byte length on success).
:raises TypeError: if ``buffer`` is not a writable buffer (e.g. ``bytes``).
:raises ValueError: if ``buffer`` is empty or not contiguous.
:raises OSError: if the read fails or returns fewer bytes than requested.

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.

.. py:method:: read_char(address)
:no-index:
Read / write a signed 8-bit integer (1 byte). Pair: ``write_char(address, value)``.
.. py:method:: read_short(address)
:no-index:
Signed 16-bit integer (2 bytes). Pair: ``write_short``.
.. py:method:: read_int(address)
:no-index:
Signed 32-bit integer (4 bytes). Pair: ``write_int``.
.. py:method:: read_long(address)
:no-index:
Signed 32-bit integer (4 bytes, Win32 ``LONG``). Pair: ``write_long``.
.. py:method:: read_longlong(address)
:no-index:
Signed 64-bit integer (8 bytes). Pair: ``write_longlong``.
.. py:method:: read_uchar(address)
:no-index:
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_*``.
.. py:method:: read_float(address)
:no-index:
32-bit float (4 bytes). Pair: ``write_float``.
.. py:method:: read_double(address)
:no-index:
64-bit double (8 bytes). Pair: ``write_double``.
.. py:method:: read_bool(address)
:no-index:
Boolean (1 byte). Pair: ``write_bool``.
.. py:method:: read_string(address, byte_count)
:no-index:
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)``.
.. py:method:: read_bytes(address, length)
:no-index:
Read ``length`` raw bytes. Pair: ``write_bytes(address, data)``.

Searching

.. py:method:: 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 :doc:`../guide/searching` for a full walkthrough.
.. py:method:: 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``).
.. py:method:: 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 :py:meth:`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.
.. py:method:: 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 :py:class:`re.Pattern`. See :doc:`../guide/pattern-scan`.

Memory regions

.. py:method:: get_memory_regions()
Yield a :py:class:`MemoryRegion` per region — an immutable dataclass with
``address``, ``size``, ``is_readable``, ``is_writable``, ``is_executable``,
``is_shared``, ``path`` and the platform-specific ``struct``.
.. py:method:: snapshot_memory_regions()
Materialize the region list once as a :py:class:`MemoryRegionSnapshot`
(pre-sorted by base address), for reuse across iterative scans.

Modules and threads

.. py:method:: get_modules()
Yield a :py:class:`ModuleInfo` for every loaded module.
.. py:method:: get_threads()
Yield a :py:class:`ThreadInfo` for every thread inside the target.

Pointers

.. py:method:: resolve_pointer_chain(base_address, offsets, *, ptr_size=None)
Walk a multi-level pointer chain and return the final address.
.. py:method:: get_pointer(base_address, offsets=None, *, pytype=int, bufflength=None, ptr_size=None)
Build a :py:class:`RemotePointer` bound to this process — a live,
re-resolving handle. See :doc:`../guide/pointers`.
.. py:method:: scan_pointer_paths(target_address, *, max_depth=3, 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 :py:class:`PointerPath` recipes that resolve
to ``target_address``. See :doc:`../guide/pointer-scan`.
.. py:method:: save_pointer_paths(paths, file)
Save pointer paths to a JSON file.
.. py:method:: load_pointer_paths(file)
Load pointer paths previously saved with :py:meth:`save_pointer_paths`.
.. py:method:: rescan_pointer_paths(paths, target_address)
Keep only the paths that still resolve to ``target_address``.
.. py:method:: compare_pointer_scans(*sources)
Intersect several saved scans — return the paths present in *every* one.

Allocation

.. py:method:: allocate_memory(size, *, permission=None)
Reserve ``size`` bytes inside the target. Windows and macOS only.
.. py:method:: free_memory(address, size=0)
Release a previously allocated region.

Lifecycle

.. py:method:: close()
Close the process handle. Subsequent calls raise :py:exc:`ClosedProcess`.
.. py:method:: __enter__()
.. py:method:: __exit__(exc_type, exc_value, exc_traceback)
The process is also a context manager — prefer the ``with`` block.
- [`ScanTypesEnum`](enums.md)
- [`MemoryRegion`](memory-region.md)
- [`RemotePointer`](remote-pointer.md)
- [`PointerPath`](pointer-path.md)
- [`ModuleInfo`](module-info.md)
- [`ThreadInfo`](thread-info.md)
- [Errors](errors.md)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
PyMemoryEditor/docs/api/openprocess.md at main · JeanExtreme002/PyMemoryEditor · GitHub
Skip to content

Latest commit

History

History
371 lines (262 loc) · 12.7 KB

File metadata and controls

371 lines (262 loc) · 12.7 KB

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.

.. py: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

.. py:class:: OpenProcess(*, name=None, pid=None, permission=<platform default>, case_sensitive=<platform default>, exact_match=True, strict_bitness=False)
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``.
:param str name: name of the target process.
:param int pid: process ID. Takes precedence over ``name``.
:param permission: **Windows only.** A
:py:class:`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``.
:param bool case_sensitive: when ``False``, ``name`` matching
ignores case. Default is ``False`` on Windows, ``True`` elsewhere.
:param bool exact_match: when ``False``, ``name`` matches as a
substring (``"chrome"`` matches ``"chrome.exe"``).
:param bool strict_bitness: when ``True``, :py:attr:`is_64bit` raises
:py:exc:`BitnessDetectionError` if the target's 32-/64-bit width
can't be read from its headers, instead of falling back to the host
word size. Use it when a wrong pointer-width default would be worse
than a hard failure.
:raises ProcessNotFoundError: no process matches ``name``.
:raises ProcessIDNotExistsError: ``pid`` doesn't exist.
:raises AmbiguousProcessNameError: more than one process matches.
:raises TypeError: neither ``name`` nor ``pid`` was provided.
:raises PermissionError: the OS denied access.

Examples

# By namewithOpenProcess(name="game.exe") asprocess:
...
# By PIDwithOpenProcess(pid=1234) asprocess:
...
# Partial, case-insensitive name match (Windows-friendly)withOpenProcess(name="chrome", case_sensitive=False, exact_match=False) asprocess:
...
# Read-only handle (Windows only)fromPyMemoryEditorimportProcessOperationsEnumwithOpenProcess(
name="game.exe",
permission=ProcessOperationsEnum.PROCESS_VM_READ|ProcessOperationsEnum.PROCESS_QUERY_INFORMATION,
) asprocess:
...

Attributes

.. py:attribute:: pid
:type: int
:no-index:
The PID of the target process.
.. py:attribute:: main_thread
:type: Optional[ThreadInfo]
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).
.. py:attribute:: is_64bit
:type: bool
``True`` if the target process is 64-bit, ``False`` if it is 32-bit.
Detected once on first access (via headers: ELF class on Linux, Mach-O
magic on macOS, ``IsWow64Process`` on Windows) and cached.
When the backend can't read the headers, the result depends on
``strict_bitness``: ``False`` (default) falls back to the host word size
and logs a WARNING; ``True`` raises
:py:exc:`BitnessDetectionError`.
.. py:attribute:: is_bitness_certain
:type: bool
``True`` if :py:attr:`is_64bit` was read from the target's own headers,
``False`` if it fell back to a guess of the host word size.
When ``False`` the automatic ``ptr_size`` default may be wrong for a
cross-bitness target — pass ``ptr_size`` explicitly to the pointer APIs.
.. py:attribute:: pointer_size
:type: int
Pointer width of the target process in bytes — ``8`` for a 64-bit target,
``4`` for a 32-bit one. Derived from :py:attr:`is_64bit`.

Methods

Read / write

.. py:method:: read_process_memory(address, pytype, bufflength=None)
Read a value from memory.
:param int address: target memory address.
:param Type pytype: ``bool``, ``int``, ``float``, ``str`` or ``bytes``.
:param int bufflength: value size in bytes (optional for numeric types).
:returns: the decoded value.
.. py:method:: write_process_memory(address, pytype, bufflength=None, value=...)
Write a value to memory.
:param int address: target memory address.
:param Type pytype: one of the five supported types.
:param int bufflength: 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)``).
:param value: the value to write.
:returns: the original ``value`` you passed in — **not** the truncated/encoded
form actually written (a capped ``str``/``bytes`` write returns the full
original value).
.. py:method:: read_process_memory_into(address, buffer)
Read ``len(buffer)`` raw bytes from ``address`` directly into a
pre-allocated, writable ``buffer`` (no intermediate allocation) — the
zero-copy counterpart of :py:meth:`read_process_memory` for tight
read-the-same-region loops. See :doc:`../guide/read-write` for examples.
:param int address: target memory address.
:param buffer: any writable, contiguous buffer-protocol object
(``bytearray``, ``ctypes`` array, writable ``memoryview``, ``numpy``
array, …). Its byte length sets how many bytes are read; the bytes land
verbatim (no decoding).
:returns: the number of bytes read (the buffer's byte length on success).
:raises TypeError: if ``buffer`` is not a writable buffer (e.g. ``bytes``).
:raises ValueError: if ``buffer`` is empty or not contiguous.
:raises OSError: if the read fails or returns fewer bytes than requested.

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.

.. py:method:: read_char(address)
:no-index:
Read / write a signed 8-bit integer (1 byte). Pair: ``write_char(address, value)``.
.. py:method:: read_short(address)
:no-index:
Signed 16-bit integer (2 bytes). Pair: ``write_short``.
.. py:method:: read_int(address)
:no-index:
Signed 32-bit integer (4 bytes). Pair: ``write_int``.
.. py:method:: read_long(address)
:no-index:
Signed 32-bit integer (4 bytes, Win32 ``LONG``). Pair: ``write_long``.
.. py:method:: read_longlong(address)
:no-index:
Signed 64-bit integer (8 bytes). Pair: ``write_longlong``.
.. py:method:: read_uchar(address)
:no-index:
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_*``.
.. py:method:: read_float(address)
:no-index:
32-bit float (4 bytes). Pair: ``write_float``.
.. py:method:: read_double(address)
:no-index:
64-bit double (8 bytes). Pair: ``write_double``.
.. py:method:: read_bool(address)
:no-index:
Boolean (1 byte). Pair: ``write_bool``.
.. py:method:: read_string(address, byte_count)
:no-index:
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)``.
.. py:method:: read_bytes(address, length)
:no-index:
Read ``length`` raw bytes. Pair: ``write_bytes(address, data)``.

Searching

.. py:method:: 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 :doc:`../guide/searching` for a full walkthrough.
.. py:method:: 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``).
.. py:method:: 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 :py:meth:`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.
.. py:method:: 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 :py:class:`re.Pattern`. See :doc:`../guide/pattern-scan`.

Memory regions

.. py:method:: get_memory_regions()
Yield a :py:class:`MemoryRegion` per region — an immutable dataclass with
``address``, ``size``, ``is_readable``, ``is_writable``, ``is_executable``,
``is_shared``, ``path`` and the platform-specific ``struct``.
.. py:method:: snapshot_memory_regions()
Materialize the region list once as a :py:class:`MemoryRegionSnapshot`
(pre-sorted by base address), for reuse across iterative scans.

Modules and threads

.. py:method:: get_modules()
Yield a :py:class:`ModuleInfo` for every loaded module.
.. py:method:: get_threads()
Yield a :py:class:`ThreadInfo` for every thread inside the target.

Pointers

.. py:method:: resolve_pointer_chain(base_address, offsets, *, ptr_size=None)
Walk a multi-level pointer chain and return the final address.
.. py:method:: get_pointer(base_address, offsets=None, *, pytype=int, bufflength=None, ptr_size=None)
Build a :py:class:`RemotePointer` bound to this process — a live,
re-resolving handle. See :doc:`../guide/pointers`.
.. py:method:: scan_pointer_paths(target_address, *, max_depth=3, 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 :py:class:`PointerPath` recipes that resolve
to ``target_address``. See :doc:`../guide/pointer-scan`.
.. py:method:: save_pointer_paths(paths, file)
Save pointer paths to a JSON file.
.. py:method:: load_pointer_paths(file)
Load pointer paths previously saved with :py:meth:`save_pointer_paths`.
.. py:method:: rescan_pointer_paths(paths, target_address)
Keep only the paths that still resolve to ``target_address``.
.. py:method:: compare_pointer_scans(*sources)
Intersect several saved scans — return the paths present in *every* one.

Allocation

.. py:method:: allocate_memory(size, *, permission=None)
Reserve ``size`` bytes inside the target. Windows and macOS only.
.. py:method:: free_memory(address, size=0)
Release a previously allocated region.

Lifecycle

.. py:method:: close()
Close the process handle. Subsequent calls raise :py:exc:`ClosedProcess`.
.. py:method:: __enter__()
.. py:method:: __exit__(exc_type, exc_value, exc_traceback)
The process is also a context manager — prefer the ``with`` block.
- [`ScanTypesEnum`](enums.md)
- [`MemoryRegion`](memory-region.md)
- [`RemotePointer`](remote-pointer.md)
- [`PointerPath`](pointer-path.md)
- [`ModuleInfo`](module-info.md)
- [`ThreadInfo`](thread-info.md)
- [Errors](errors.md)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' PyMemoryEditor/docs/api/openprocess.md at main · JeanExtreme002/PyMemoryEditor · GitHub
Skip to content

Latest commit

History

History
371 lines (262 loc) · 12.7 KB

File metadata and controls

371 lines (262 loc) · 12.7 KB

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.

.. py: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

.. py:class:: OpenProcess(*, name=None, pid=None, permission=<platform default>, case_sensitive=<platform default>, exact_match=True, strict_bitness=False)
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``.
:param str name: name of the target process.
:param int pid: process ID. Takes precedence over ``name``.
:param permission: **Windows only.** A
:py:class:`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``.
:param bool case_sensitive: when ``False``, ``name`` matching
ignores case. Default is ``False`` on Windows, ``True`` elsewhere.
:param bool exact_match: when ``False``, ``name`` matches as a
substring (``"chrome"`` matches ``"chrome.exe"``).
:param bool strict_bitness: when ``True``, :py:attr:`is_64bit` raises
:py:exc:`BitnessDetectionError` if the target's 32-/64-bit width
can't be read from its headers, instead of falling back to the host
word size. Use it when a wrong pointer-width default would be worse
than a hard failure.
:raises ProcessNotFoundError: no process matches ``name``.
:raises ProcessIDNotExistsError: ``pid`` doesn't exist.
:raises AmbiguousProcessNameError: more than one process matches.
:raises TypeError: neither ``name`` nor ``pid`` was provided.
:raises PermissionError: the OS denied access.

Examples

# By namewithOpenProcess(name="game.exe") asprocess:
...
# By PIDwithOpenProcess(pid=1234) asprocess:
...
# Partial, case-insensitive name match (Windows-friendly)withOpenProcess(name="chrome", case_sensitive=False, exact_match=False) asprocess:
...
# Read-only handle (Windows only)fromPyMemoryEditorimportProcessOperationsEnumwithOpenProcess(
name="game.exe",
permission=ProcessOperationsEnum.PROCESS_VM_READ|ProcessOperationsEnum.PROCESS_QUERY_INFORMATION,
) asprocess:
...

Attributes

.. py:attribute:: pid
:type: int
:no-index:
The PID of the target process.
.. py:attribute:: main_thread
:type: Optional[ThreadInfo]
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).
.. py:attribute:: is_64bit
:type: bool
``True`` if the target process is 64-bit, ``False`` if it is 32-bit.
Detected once on first access (via headers: ELF class on Linux, Mach-O
magic on macOS, ``IsWow64Process`` on Windows) and cached.
When the backend can't read the headers, the result depends on
``strict_bitness``: ``False`` (default) falls back to the host word size
and logs a WARNING; ``True`` raises
:py:exc:`BitnessDetectionError`.
.. py:attribute:: is_bitness_certain
:type: bool
``True`` if :py:attr:`is_64bit` was read from the target's own headers,
``False`` if it fell back to a guess of the host word size.
When ``False`` the automatic ``ptr_size`` default may be wrong for a
cross-bitness target — pass ``ptr_size`` explicitly to the pointer APIs.
.. py:attribute:: pointer_size
:type: int
Pointer width of the target process in bytes — ``8`` for a 64-bit target,
``4`` for a 32-bit one. Derived from :py:attr:`is_64bit`.

Methods

Read / write

.. py:method:: read_process_memory(address, pytype, bufflength=None)
Read a value from memory.
:param int address: target memory address.
:param Type pytype: ``bool``, ``int``, ``float``, ``str`` or ``bytes``.
:param int bufflength: value size in bytes (optional for numeric types).
:returns: the decoded value.
.. py:method:: write_process_memory(address, pytype, bufflength=None, value=...)
Write a value to memory.
:param int address: target memory address.
:param Type pytype: one of the five supported types.
:param int bufflength: 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)``).
:param value: the value to write.
:returns: the original ``value`` you passed in — **not** the truncated/encoded
form actually written (a capped ``str``/``bytes`` write returns the full
original value).
.. py:method:: read_process_memory_into(address, buffer)
Read ``len(buffer)`` raw bytes from ``address`` directly into a
pre-allocated, writable ``buffer`` (no intermediate allocation) — the
zero-copy counterpart of :py:meth:`read_process_memory` for tight
read-the-same-region loops. See :doc:`../guide/read-write` for examples.
:param int address: target memory address.
:param buffer: any writable, contiguous buffer-protocol object
(``bytearray``, ``ctypes`` array, writable ``memoryview``, ``numpy``
array, …). Its byte length sets how many bytes are read; the bytes land
verbatim (no decoding).
:returns: the number of bytes read (the buffer's byte length on success).
:raises TypeError: if ``buffer`` is not a writable buffer (e.g. ``bytes``).
:raises ValueError: if ``buffer`` is empty or not contiguous.
:raises OSError: if the read fails or returns fewer bytes than requested.

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.

.. py:method:: read_char(address)
:no-index:
Read / write a signed 8-bit integer (1 byte). Pair: ``write_char(address, value)``.
.. py:method:: read_short(address)
:no-index:
Signed 16-bit integer (2 bytes). Pair: ``write_short``.
.. py:method:: read_int(address)
:no-index:
Signed 32-bit integer (4 bytes). Pair: ``write_int``.
.. py:method:: read_long(address)
:no-index:
Signed 32-bit integer (4 bytes, Win32 ``LONG``). Pair: ``write_long``.
.. py:method:: read_longlong(address)
:no-index:
Signed 64-bit integer (8 bytes). Pair: ``write_longlong``.
.. py:method:: read_uchar(address)
:no-index:
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_*``.
.. py:method:: read_float(address)
:no-index:
32-bit float (4 bytes). Pair: ``write_float``.
.. py:method:: read_double(address)
:no-index:
64-bit double (8 bytes). Pair: ``write_double``.
.. py:method:: read_bool(address)
:no-index:
Boolean (1 byte). Pair: ``write_bool``.
.. py:method:: read_string(address, byte_count)
:no-index:
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)``.
.. py:method:: read_bytes(address, length)
:no-index:
Read ``length`` raw bytes. Pair: ``write_bytes(address, data)``.

Searching

.. py:method:: 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 :doc:`../guide/searching` for a full walkthrough.
.. py:method:: 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``).
.. py:method:: 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 :py:meth:`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.
.. py:method:: 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 :py:class:`re.Pattern`. See :doc:`../guide/pattern-scan`.

Memory regions

.. py:method:: get_memory_regions()
Yield a :py:class:`MemoryRegion` per region — an immutable dataclass with
``address``, ``size``, ``is_readable``, ``is_writable``, ``is_executable``,
``is_shared``, ``path`` and the platform-specific ``struct``.
.. py:method:: snapshot_memory_regions()
Materialize the region list once as a :py:class:`MemoryRegionSnapshot`
(pre-sorted by base address), for reuse across iterative scans.

Modules and threads

.. py:method:: get_modules()
Yield a :py:class:`ModuleInfo` for every loaded module.
.. py:method:: get_threads()
Yield a :py:class:`ThreadInfo` for every thread inside the target.

Pointers

.. py:method:: resolve_pointer_chain(base_address, offsets, *, ptr_size=None)
Walk a multi-level pointer chain and return the final address.
.. py:method:: get_pointer(base_address, offsets=None, *, pytype=int, bufflength=None, ptr_size=None)
Build a :py:class:`RemotePointer` bound to this process — a live,
re-resolving handle. See :doc:`../guide/pointers`.
.. py:method:: scan_pointer_paths(target_address, *, max_depth=3, 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 :py:class:`PointerPath` recipes that resolve
to ``target_address``. See :doc:`../guide/pointer-scan`.
.. py:method:: save_pointer_paths(paths, file)
Save pointer paths to a JSON file.
.. py:method:: load_pointer_paths(file)
Load pointer paths previously saved with :py:meth:`save_pointer_paths`.
.. py:method:: rescan_pointer_paths(paths, target_address)
Keep only the paths that still resolve to ``target_address``.
.. py:method:: compare_pointer_scans(*sources)
Intersect several saved scans — return the paths present in *every* one.

Allocation

.. py:method:: allocate_memory(size, *, permission=None)
Reserve ``size`` bytes inside the target. Windows and macOS only.
.. py:method:: free_memory(address, size=0)
Release a previously allocated region.

Lifecycle

.. py:method:: close()
Close the process handle. Subsequent calls raise :py:exc:`ClosedProcess`.
.. py:method:: __enter__()
.. py:method:: __exit__(exc_type, exc_value, exc_traceback)
The process is also a context manager — prefer the ``with`` block.
- [`ScanTypesEnum`](enums.md)
- [`MemoryRegion`](memory-region.md)
- [`RemotePointer`](remote-pointer.md)
- [`PointerPath`](pointer-path.md)
- [`ModuleInfo`](module-info.md)
- [`ThreadInfo`](thread-info.md)
- [Errors](errors.md)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' PyMemoryEditor/docs/api/openprocess.md at main · JeanExtreme002/PyMemoryEditor · GitHub
Skip to content

Latest commit

History

History
371 lines (262 loc) · 12.7 KB

File metadata and controls

371 lines (262 loc) · 12.7 KB

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.

.. py: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

.. py:class:: OpenProcess(*, name=None, pid=None, permission=<platform default>, case_sensitive=<platform default>, exact_match=True, strict_bitness=False)
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``.
:param str name: name of the target process.
:param int pid: process ID. Takes precedence over ``name``.
:param permission: **Windows only.** A
:py:class:`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``.
:param bool case_sensitive: when ``False``, ``name`` matching
ignores case. Default is ``False`` on Windows, ``True`` elsewhere.
:param bool exact_match: when ``False``, ``name`` matches as a
substring (``"chrome"`` matches ``"chrome.exe"``).
:param bool strict_bitness: when ``True``, :py:attr:`is_64bit` raises
:py:exc:`BitnessDetectionError` if the target's 32-/64-bit width
can't be read from its headers, instead of falling back to the host
word size. Use it when a wrong pointer-width default would be worse
than a hard failure.
:raises ProcessNotFoundError: no process matches ``name``.
:raises ProcessIDNotExistsError: ``pid`` doesn't exist.
:raises AmbiguousProcessNameError: more than one process matches.
:raises TypeError: neither ``name`` nor ``pid`` was provided.
:raises PermissionError: the OS denied access.

Examples

# By namewithOpenProcess(name="game.exe") asprocess:
...
# By PIDwithOpenProcess(pid=1234) asprocess:
...
# Partial, case-insensitive name match (Windows-friendly)withOpenProcess(name="chrome", case_sensitive=False, exact_match=False) asprocess:
...
# Read-only handle (Windows only)fromPyMemoryEditorimportProcessOperationsEnumwithOpenProcess(
name="game.exe",
permission=ProcessOperationsEnum.PROCESS_VM_READ|ProcessOperationsEnum.PROCESS_QUERY_INFORMATION,
) asprocess:
...

Attributes

.. py:attribute:: pid
:type: int
:no-index:
The PID of the target process.
.. py:attribute:: main_thread
:type: Optional[ThreadInfo]
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).
.. py:attribute:: is_64bit
:type: bool
``True`` if the target process is 64-bit, ``False`` if it is 32-bit.
Detected once on first access (via headers: ELF class on Linux, Mach-O
magic on macOS, ``IsWow64Process`` on Windows) and cached.
When the backend can't read the headers, the result depends on
``strict_bitness``: ``False`` (default) falls back to the host word size
and logs a WARNING; ``True`` raises
:py:exc:`BitnessDetectionError`.
.. py:attribute:: is_bitness_certain
:type: bool
``True`` if :py:attr:`is_64bit` was read from the target's own headers,
``False`` if it fell back to a guess of the host word size.
When ``False`` the automatic ``ptr_size`` default may be wrong for a
cross-bitness target — pass ``ptr_size`` explicitly to the pointer APIs.
.. py:attribute:: pointer_size
:type: int
Pointer width of the target process in bytes — ``8`` for a 64-bit target,
``4`` for a 32-bit one. Derived from :py:attr:`is_64bit`.

Methods

Read / write

.. py:method:: read_process_memory(address, pytype, bufflength=None)
Read a value from memory.
:param int address: target memory address.
:param Type pytype: ``bool``, ``int``, ``float``, ``str`` or ``bytes``.
:param int bufflength: value size in bytes (optional for numeric types).
:returns: the decoded value.
.. py:method:: write_process_memory(address, pytype, bufflength=None, value=...)
Write a value to memory.
:param int address: target memory address.
:param Type pytype: one of the five supported types.
:param int bufflength: 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)``).
:param value: the value to write.
:returns: the original ``value`` you passed in — **not** the truncated/encoded
form actually written (a capped ``str``/``bytes`` write returns the full
original value).
.. py:method:: read_process_memory_into(address, buffer)
Read ``len(buffer)`` raw bytes from ``address`` directly into a
pre-allocated, writable ``buffer`` (no intermediate allocation) — the
zero-copy counterpart of :py:meth:`read_process_memory` for tight
read-the-same-region loops. See :doc:`../guide/read-write` for examples.
:param int address: target memory address.
:param buffer: any writable, contiguous buffer-protocol object
(``bytearray``, ``ctypes`` array, writable ``memoryview``, ``numpy``
array, …). Its byte length sets how many bytes are read; the bytes land
verbatim (no decoding).
:returns: the number of bytes read (the buffer's byte length on success).
:raises TypeError: if ``buffer`` is not a writable buffer (e.g. ``bytes``).
:raises ValueError: if ``buffer`` is empty or not contiguous.
:raises OSError: if the read fails or returns fewer bytes than requested.

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.

.. py:method:: read_char(address)
:no-index:
Read / write a signed 8-bit integer (1 byte). Pair: ``write_char(address, value)``.
.. py:method:: read_short(address)
:no-index:
Signed 16-bit integer (2 bytes). Pair: ``write_short``.
.. py:method:: read_int(address)
:no-index:
Signed 32-bit integer (4 bytes). Pair: ``write_int``.
.. py:method:: read_long(address)
:no-index:
Signed 32-bit integer (4 bytes, Win32 ``LONG``). Pair: ``write_long``.
.. py:method:: read_longlong(address)
:no-index:
Signed 64-bit integer (8 bytes). Pair: ``write_longlong``.
.. py:method:: read_uchar(address)
:no-index:
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_*``.
.. py:method:: read_float(address)
:no-index:
32-bit float (4 bytes). Pair: ``write_float``.
.. py:method:: read_double(address)
:no-index:
64-bit double (8 bytes). Pair: ``write_double``.
.. py:method:: read_bool(address)
:no-index:
Boolean (1 byte). Pair: ``write_bool``.
.. py:method:: read_string(address, byte_count)
:no-index:
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)``.
.. py:method:: read_bytes(address, length)
:no-index:
Read ``length`` raw bytes. Pair: ``write_bytes(address, data)``.

Searching

.. py:method:: 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 :doc:`../guide/searching` for a full walkthrough.
.. py:method:: 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``).
.. py:method:: 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 :py:meth:`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.
.. py:method:: 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 :py:class:`re.Pattern`. See :doc:`../guide/pattern-scan`.

Memory regions

.. py:method:: get_memory_regions()
Yield a :py:class:`MemoryRegion` per region — an immutable dataclass with
``address``, ``size``, ``is_readable``, ``is_writable``, ``is_executable``,
``is_shared``, ``path`` and the platform-specific ``struct``.
.. py:method:: snapshot_memory_regions()
Materialize the region list once as a :py:class:`MemoryRegionSnapshot`
(pre-sorted by base address), for reuse across iterative scans.

Modules and threads

.. py:method:: get_modules()
Yield a :py:class:`ModuleInfo` for every loaded module.
.. py:method:: get_threads()
Yield a :py:class:`ThreadInfo` for every thread inside the target.

Pointers

.. py:method:: resolve_pointer_chain(base_address, offsets, *, ptr_size=None)
Walk a multi-level pointer chain and return the final address.
.. py:method:: get_pointer(base_address, offsets=None, *, pytype=int, bufflength=None, ptr_size=None)
Build a :py:class:`RemotePointer` bound to this process — a live,
re-resolving handle. See :doc:`../guide/pointers`.
.. py:method:: scan_pointer_paths(target_address, *, max_depth=3, 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 :py:class:`PointerPath` recipes that resolve
to ``target_address``. See :doc:`../guide/pointer-scan`.
.. py:method:: save_pointer_paths(paths, file)
Save pointer paths to a JSON file.
.. py:method:: load_pointer_paths(file)
Load pointer paths previously saved with :py:meth:`save_pointer_paths`.
.. py:method:: rescan_pointer_paths(paths, target_address)
Keep only the paths that still resolve to ``target_address``.
.. py:method:: compare_pointer_scans(*sources)
Intersect several saved scans — return the paths present in *every* one.

Allocation

.. py:method:: allocate_memory(size, *, permission=None)
Reserve ``size`` bytes inside the target. Windows and macOS only.
.. py:method:: free_memory(address, size=0)
Release a previously allocated region.

Lifecycle

.. py:method:: close()
Close the process handle. Subsequent calls raise :py:exc:`ClosedProcess`.
.. py:method:: __enter__()
.. py:method:: __exit__(exc_type, exc_value, exc_traceback)
The process is also a context manager — prefer the ``with`` block.
- [`ScanTypesEnum`](enums.md)
- [`MemoryRegion`](memory-region.md)
- [`RemotePointer`](remote-pointer.md)
- [`PointerPath`](pointer-path.md)
- [`ModuleInfo`](module-info.md)
- [`ThreadInfo`](thread-info.md)
- [Errors](errors.md)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' PyMemoryEditor/docs/api/openprocess.md at main · JeanExtreme002/PyMemoryEditor · GitHub
Skip to content

Latest commit

History

History
371 lines (262 loc) · 12.7 KB

File metadata and controls

371 lines (262 loc) · 12.7 KB

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.

.. py: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

.. py:class:: OpenProcess(*, name=None, pid=None, permission=<platform default>, case_sensitive=<platform default>, exact_match=True, strict_bitness=False)
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``.
:param str name: name of the target process.
:param int pid: process ID. Takes precedence over ``name``.
:param permission: **Windows only.** A
:py:class:`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``.
:param bool case_sensitive: when ``False``, ``name`` matching
ignores case. Default is ``False`` on Windows, ``True`` elsewhere.
:param bool exact_match: when ``False``, ``name`` matches as a
substring (``"chrome"`` matches ``"chrome.exe"``).
:param bool strict_bitness: when ``True``, :py:attr:`is_64bit` raises
:py:exc:`BitnessDetectionError` if the target's 32-/64-bit width
can't be read from its headers, instead of falling back to the host
word size. Use it when a wrong pointer-width default would be worse
than a hard failure.
:raises ProcessNotFoundError: no process matches ``name``.
:raises ProcessIDNotExistsError: ``pid`` doesn't exist.
:raises AmbiguousProcessNameError: more than one process matches.
:raises TypeError: neither ``name`` nor ``pid`` was provided.
:raises PermissionError: the OS denied access.

Examples

# By namewithOpenProcess(name="game.exe") asprocess:
...
# By PIDwithOpenProcess(pid=1234) asprocess:
...
# Partial, case-insensitive name match (Windows-friendly)withOpenProcess(name="chrome", case_sensitive=False, exact_match=False) asprocess:
...
# Read-only handle (Windows only)fromPyMemoryEditorimportProcessOperationsEnumwithOpenProcess(
name="game.exe",
permission=ProcessOperationsEnum.PROCESS_VM_READ|ProcessOperationsEnum.PROCESS_QUERY_INFORMATION,
) asprocess:
...

Attributes

.. py:attribute:: pid
:type: int
:no-index:
The PID of the target process.
.. py:attribute:: main_thread
:type: Optional[ThreadInfo]
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).
.. py:attribute:: is_64bit
:type: bool
``True`` if the target process is 64-bit, ``False`` if it is 32-bit.
Detected once on first access (via headers: ELF class on Linux, Mach-O
magic on macOS, ``IsWow64Process`` on Windows) and cached.
When the backend can't read the headers, the result depends on
``strict_bitness``: ``False`` (default) falls back to the host word size
and logs a WARNING; ``True`` raises
:py:exc:`BitnessDetectionError`.
.. py:attribute:: is_bitness_certain
:type: bool
``True`` if :py:attr:`is_64bit` was read from the target's own headers,
``False`` if it fell back to a guess of the host word size.
When ``False`` the automatic ``ptr_size`` default may be wrong for a
cross-bitness target — pass ``ptr_size`` explicitly to the pointer APIs.
.. py:attribute:: pointer_size
:type: int
Pointer width of the target process in bytes — ``8`` for a 64-bit target,
``4`` for a 32-bit one. Derived from :py:attr:`is_64bit`.

Methods

Read / write

.. py:method:: read_process_memory(address, pytype, bufflength=None)
Read a value from memory.
:param int address: target memory address.
:param Type pytype: ``bool``, ``int``, ``float``, ``str`` or ``bytes``.
:param int bufflength: value size in bytes (optional for numeric types).
:returns: the decoded value.
.. py:method:: write_process_memory(address, pytype, bufflength=None, value=...)
Write a value to memory.
:param int address: target memory address.
:param Type pytype: one of the five supported types.
:param int bufflength: 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)``).
:param value: the value to write.
:returns: the original ``value`` you passed in — **not** the truncated/encoded
form actually written (a capped ``str``/``bytes`` write returns the full
original value).
.. py:method:: read_process_memory_into(address, buffer)
Read ``len(buffer)`` raw bytes from ``address`` directly into a
pre-allocated, writable ``buffer`` (no intermediate allocation) — the
zero-copy counterpart of :py:meth:`read_process_memory` for tight
read-the-same-region loops. See :doc:`../guide/read-write` for examples.
:param int address: target memory address.
:param buffer: any writable, contiguous buffer-protocol object
(``bytearray``, ``ctypes`` array, writable ``memoryview``, ``numpy``
array, …). Its byte length sets how many bytes are read; the bytes land
verbatim (no decoding).
:returns: the number of bytes read (the buffer's byte length on success).
:raises TypeError: if ``buffer`` is not a writable buffer (e.g. ``bytes``).
:raises ValueError: if ``buffer`` is empty or not contiguous.
:raises OSError: if the read fails or returns fewer bytes than requested.

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.

.. py:method:: read_char(address)
:no-index:
Read / write a signed 8-bit integer (1 byte). Pair: ``write_char(address, value)``.
.. py:method:: read_short(address)
:no-index:
Signed 16-bit integer (2 bytes). Pair: ``write_short``.
.. py:method:: read_int(address)
:no-index:
Signed 32-bit integer (4 bytes). Pair: ``write_int``.
.. py:method:: read_long(address)
:no-index:
Signed 32-bit integer (4 bytes, Win32 ``LONG``). Pair: ``write_long``.
.. py:method:: read_longlong(address)
:no-index:
Signed 64-bit integer (8 bytes). Pair: ``write_longlong``.
.. py:method:: read_uchar(address)
:no-index:
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_*``.
.. py:method:: read_float(address)
:no-index:
32-bit float (4 bytes). Pair: ``write_float``.
.. py:method:: read_double(address)
:no-index:
64-bit double (8 bytes). Pair: ``write_double``.
.. py:method:: read_bool(address)
:no-index:
Boolean (1 byte). Pair: ``write_bool``.
.. py:method:: read_string(address, byte_count)
:no-index:
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)``.
.. py:method:: read_bytes(address, length)
:no-index:
Read ``length`` raw bytes. Pair: ``write_bytes(address, data)``.

Searching

.. py:method:: 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 :doc:`../guide/searching` for a full walkthrough.
.. py:method:: 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``).
.. py:method:: 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 :py:meth:`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.
.. py:method:: 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 :py:class:`re.Pattern`. See :doc:`../guide/pattern-scan`.

Memory regions

.. py:method:: get_memory_regions()
Yield a :py:class:`MemoryRegion` per region — an immutable dataclass with
``address``, ``size``, ``is_readable``, ``is_writable``, ``is_executable``,
``is_shared``, ``path`` and the platform-specific ``struct``.
.. py:method:: snapshot_memory_regions()
Materialize the region list once as a :py:class:`MemoryRegionSnapshot`
(pre-sorted by base address), for reuse across iterative scans.

Modules and threads

.. py:method:: get_modules()
Yield a :py:class:`ModuleInfo` for every loaded module.
.. py:method:: get_threads()
Yield a :py:class:`ThreadInfo` for every thread inside the target.

Pointers

.. py:method:: resolve_pointer_chain(base_address, offsets, *, ptr_size=None)
Walk a multi-level pointer chain and return the final address.
.. py:method:: get_pointer(base_address, offsets=None, *, pytype=int, bufflength=None, ptr_size=None)
Build a :py:class:`RemotePointer` bound to this process — a live,
re-resolving handle. See :doc:`../guide/pointers`.
.. py:method:: scan_pointer_paths(target_address, *, max_depth=3, 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 :py:class:`PointerPath` recipes that resolve
to ``target_address``. See :doc:`../guide/pointer-scan`.
.. py:method:: save_pointer_paths(paths, file)
Save pointer paths to a JSON file.
.. py:method:: load_pointer_paths(file)
Load pointer paths previously saved with :py:meth:`save_pointer_paths`.
.. py:method:: rescan_pointer_paths(paths, target_address)
Keep only the paths that still resolve to ``target_address``.
.. py:method:: compare_pointer_scans(*sources)
Intersect several saved scans — return the paths present in *every* one.

Allocation

.. py:method:: allocate_memory(size, *, permission=None)
Reserve ``size`` bytes inside the target. Windows and macOS only.
.. py:method:: free_memory(address, size=0)
Release a previously allocated region.

Lifecycle

.. py:method:: close()
Close the process handle. Subsequent calls raise :py:exc:`ClosedProcess`.
.. py:method:: __enter__()
.. py:method:: __exit__(exc_type, exc_value, exc_traceback)
The process is also a context manager — prefer the ``with`` block.
- [`ScanTypesEnum`](enums.md)
- [`MemoryRegion`](memory-region.md)
- [`RemotePointer`](remote-pointer.md)
- [`PointerPath`](pointer-path.md)
- [`ModuleInfo`](module-info.md)
- [`ThreadInfo`](thread-info.md)
- [Errors](errors.md)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' PyMemoryEditor/docs/api/openprocess.md at main · JeanExtreme002/PyMemoryEditor · GitHub
Skip to content

Latest commit

History

History
371 lines (262 loc) · 12.7 KB

File metadata and controls

371 lines (262 loc) · 12.7 KB

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.

.. py: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

.. py:class:: OpenProcess(*, name=None, pid=None, permission=<platform default>, case_sensitive=<platform default>, exact_match=True, strict_bitness=False)
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``.
:param str name: name of the target process.
:param int pid: process ID. Takes precedence over ``name``.
:param permission: **Windows only.** A
:py:class:`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``.
:param bool case_sensitive: when ``False``, ``name`` matching
ignores case. Default is ``False`` on Windows, ``True`` elsewhere.
:param bool exact_match: when ``False``, ``name`` matches as a
substring (``"chrome"`` matches ``"chrome.exe"``).
:param bool strict_bitness: when ``True``, :py:attr:`is_64bit` raises
:py:exc:`BitnessDetectionError` if the target's 32-/64-bit width
can't be read from its headers, instead of falling back to the host
word size. Use it when a wrong pointer-width default would be worse
than a hard failure.
:raises ProcessNotFoundError: no process matches ``name``.
:raises ProcessIDNotExistsError: ``pid`` doesn't exist.
:raises AmbiguousProcessNameError: more than one process matches.
:raises TypeError: neither ``name`` nor ``pid`` was provided.
:raises PermissionError: the OS denied access.

Examples

# By namewithOpenProcess(name="game.exe") asprocess:
...
# By PIDwithOpenProcess(pid=1234) asprocess:
...
# Partial, case-insensitive name match (Windows-friendly)withOpenProcess(name="chrome", case_sensitive=False, exact_match=False) asprocess:
...
# Read-only handle (Windows only)fromPyMemoryEditorimportProcessOperationsEnumwithOpenProcess(
name="game.exe",
permission=ProcessOperationsEnum.PROCESS_VM_READ|ProcessOperationsEnum.PROCESS_QUERY_INFORMATION,
) asprocess:
...

Attributes

.. py:attribute:: pid
:type: int
:no-index:
The PID of the target process.
.. py:attribute:: main_thread
:type: Optional[ThreadInfo]
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).
.. py:attribute:: is_64bit
:type: bool
``True`` if the target process is 64-bit, ``False`` if it is 32-bit.
Detected once on first access (via headers: ELF class on Linux, Mach-O
magic on macOS, ``IsWow64Process`` on Windows) and cached.
When the backend can't read the headers, the result depends on
``strict_bitness``: ``False`` (default) falls back to the host word size
and logs a WARNING; ``True`` raises
:py:exc:`BitnessDetectionError`.
.. py:attribute:: is_bitness_certain
:type: bool
``True`` if :py:attr:`is_64bit` was read from the target's own headers,
``False`` if it fell back to a guess of the host word size.
When ``False`` the automatic ``ptr_size`` default may be wrong for a
cross-bitness target — pass ``ptr_size`` explicitly to the pointer APIs.
.. py:attribute:: pointer_size
:type: int
Pointer width of the target process in bytes — ``8`` for a 64-bit target,
``4`` for a 32-bit one. Derived from :py:attr:`is_64bit`.

Methods

Read / write

.. py:method:: read_process_memory(address, pytype, bufflength=None)
Read a value from memory.
:param int address: target memory address.
:param Type pytype: ``bool``, ``int``, ``float``, ``str`` or ``bytes``.
:param int bufflength: value size in bytes (optional for numeric types).
:returns: the decoded value.
.. py:method:: write_process_memory(address, pytype, bufflength=None, value=...)
Write a value to memory.
:param int address: target memory address.
:param Type pytype: one of the five supported types.
:param int bufflength: 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)``).
:param value: the value to write.
:returns: the original ``value`` you passed in — **not** the truncated/encoded
form actually written (a capped ``str``/``bytes`` write returns the full
original value).
.. py:method:: read_process_memory_into(address, buffer)
Read ``len(buffer)`` raw bytes from ``address`` directly into a
pre-allocated, writable ``buffer`` (no intermediate allocation) — the
zero-copy counterpart of :py:meth:`read_process_memory` for tight
read-the-same-region loops. See :doc:`../guide/read-write` for examples.
:param int address: target memory address.
:param buffer: any writable, contiguous buffer-protocol object
(``bytearray``, ``ctypes`` array, writable ``memoryview``, ``numpy``
array, …). Its byte length sets how many bytes are read; the bytes land
verbatim (no decoding).
:returns: the number of bytes read (the buffer's byte length on success).
:raises TypeError: if ``buffer`` is not a writable buffer (e.g. ``bytes``).
:raises ValueError: if ``buffer`` is empty or not contiguous.
:raises OSError: if the read fails or returns fewer bytes than requested.

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.

.. py:method:: read_char(address)
:no-index:
Read / write a signed 8-bit integer (1 byte). Pair: ``write_char(address, value)``.
.. py:method:: read_short(address)
:no-index:
Signed 16-bit integer (2 bytes). Pair: ``write_short``.
.. py:method:: read_int(address)
:no-index:
Signed 32-bit integer (4 bytes). Pair: ``write_int``.
.. py:method:: read_long(address)
:no-index:
Signed 32-bit integer (4 bytes, Win32 ``LONG``). Pair: ``write_long``.
.. py:method:: read_longlong(address)
:no-index:
Signed 64-bit integer (8 bytes). Pair: ``write_longlong``.
.. py:method:: read_uchar(address)
:no-index:
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_*``.
.. py:method:: read_float(address)
:no-index:
32-bit float (4 bytes). Pair: ``write_float``.
.. py:method:: read_double(address)
:no-index:
64-bit double (8 bytes). Pair: ``write_double``.
.. py:method:: read_bool(address)
:no-index:
Boolean (1 byte). Pair: ``write_bool``.
.. py:method:: read_string(address, byte_count)
:no-index:
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)``.
.. py:method:: read_bytes(address, length)
:no-index:
Read ``length`` raw bytes. Pair: ``write_bytes(address, data)``.

Searching

.. py:method:: 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 :doc:`../guide/searching` for a full walkthrough.
.. py:method:: 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``).
.. py:method:: 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 :py:meth:`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.
.. py:method:: 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 :py:class:`re.Pattern`. See :doc:`../guide/pattern-scan`.

Memory regions

.. py:method:: get_memory_regions()
Yield a :py:class:`MemoryRegion` per region — an immutable dataclass with
``address``, ``size``, ``is_readable``, ``is_writable``, ``is_executable``,
``is_shared``, ``path`` and the platform-specific ``struct``.
.. py:method:: snapshot_memory_regions()
Materialize the region list once as a :py:class:`MemoryRegionSnapshot`
(pre-sorted by base address), for reuse across iterative scans.

Modules and threads

.. py:method:: get_modules()
Yield a :py:class:`ModuleInfo` for every loaded module.
.. py:method:: get_threads()
Yield a :py:class:`ThreadInfo` for every thread inside the target.

Pointers

.. py:method:: resolve_pointer_chain(base_address, offsets, *, ptr_size=None)
Walk a multi-level pointer chain and return the final address.
.. py:method:: get_pointer(base_address, offsets=None, *, pytype=int, bufflength=None, ptr_size=None)
Build a :py:class:`RemotePointer` bound to this process — a live,
re-resolving handle. See :doc:`../guide/pointers`.
.. py:method:: scan_pointer_paths(target_address, *, max_depth=3, 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 :py:class:`PointerPath` recipes that resolve
to ``target_address``. See :doc:`../guide/pointer-scan`.
.. py:method:: save_pointer_paths(paths, file)
Save pointer paths to a JSON file.
.. py:method:: load_pointer_paths(file)
Load pointer paths previously saved with :py:meth:`save_pointer_paths`.
.. py:method:: rescan_pointer_paths(paths, target_address)
Keep only the paths that still resolve to ``target_address``.
.. py:method:: compare_pointer_scans(*sources)
Intersect several saved scans — return the paths present in *every* one.

Allocation

.. py:method:: allocate_memory(size, *, permission=None)
Reserve ``size`` bytes inside the target. Windows and macOS only.
.. py:method:: free_memory(address, size=0)
Release a previously allocated region.

Lifecycle

.. py:method:: close()
Close the process handle. Subsequent calls raise :py:exc:`ClosedProcess`.
.. py:method:: __enter__()
.. py:method:: __exit__(exc_type, exc_value, exc_traceback)
The process is also a context manager — prefer the ``with`` block.
- [`ScanTypesEnum`](enums.md)
- [`MemoryRegion`](memory-region.md)
- [`RemotePointer`](remote-pointer.md)
- [`PointerPath`](pointer-path.md)
- [`ModuleInfo`](module-info.md)
- [`ThreadInfo`](thread-info.md)
- [Errors](errors.md)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' PyMemoryEditor/docs/api/openprocess.md at main · JeanExtreme002/PyMemoryEditor · GitHub
Skip to content

Latest commit

History

History
371 lines (262 loc) · 12.7 KB

File metadata and controls

371 lines (262 loc) · 12.7 KB

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.

.. py: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

.. py:class:: OpenProcess(*, name=None, pid=None, permission=<platform default>, case_sensitive=<platform default>, exact_match=True, strict_bitness=False)
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``.
:param str name: name of the target process.
:param int pid: process ID. Takes precedence over ``name``.
:param permission: **Windows only.** A
:py:class:`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``.
:param bool case_sensitive: when ``False``, ``name`` matching
ignores case. Default is ``False`` on Windows, ``True`` elsewhere.
:param bool exact_match: when ``False``, ``name`` matches as a
substring (``"chrome"`` matches ``"chrome.exe"``).
:param bool strict_bitness: when ``True``, :py:attr:`is_64bit` raises
:py:exc:`BitnessDetectionError` if the target's 32-/64-bit width
can't be read from its headers, instead of falling back to the host
word size. Use it when a wrong pointer-width default would be worse
than a hard failure.
:raises ProcessNotFoundError: no process matches ``name``.
:raises ProcessIDNotExistsError: ``pid`` doesn't exist.
:raises AmbiguousProcessNameError: more than one process matches.
:raises TypeError: neither ``name`` nor ``pid`` was provided.
:raises PermissionError: the OS denied access.

Examples

# By namewithOpenProcess(name="game.exe") asprocess:
...
# By PIDwithOpenProcess(pid=1234) asprocess:
...
# Partial, case-insensitive name match (Windows-friendly)withOpenProcess(name="chrome", case_sensitive=False, exact_match=False) asprocess:
...
# Read-only handle (Windows only)fromPyMemoryEditorimportProcessOperationsEnumwithOpenProcess(
name="game.exe",
permission=ProcessOperationsEnum.PROCESS_VM_READ|ProcessOperationsEnum.PROCESS_QUERY_INFORMATION,
) asprocess:
...

Attributes

.. py:attribute:: pid
:type: int
:no-index:
The PID of the target process.
.. py:attribute:: main_thread
:type: Optional[ThreadInfo]
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).
.. py:attribute:: is_64bit
:type: bool
``True`` if the target process is 64-bit, ``False`` if it is 32-bit.
Detected once on first access (via headers: ELF class on Linux, Mach-O
magic on macOS, ``IsWow64Process`` on Windows) and cached.
When the backend can't read the headers, the result depends on
``strict_bitness``: ``False`` (default) falls back to the host word size
and logs a WARNING; ``True`` raises
:py:exc:`BitnessDetectionError`.
.. py:attribute:: is_bitness_certain
:type: bool
``True`` if :py:attr:`is_64bit` was read from the target's own headers,
``False`` if it fell back to a guess of the host word size.
When ``False`` the automatic ``ptr_size`` default may be wrong for a
cross-bitness target — pass ``ptr_size`` explicitly to the pointer APIs.
.. py:attribute:: pointer_size
:type: int
Pointer width of the target process in bytes — ``8`` for a 64-bit target,
``4`` for a 32-bit one. Derived from :py:attr:`is_64bit`.

Methods

Read / write

.. py:method:: read_process_memory(address, pytype, bufflength=None)
Read a value from memory.
:param int address: target memory address.
:param Type pytype: ``bool``, ``int``, ``float``, ``str`` or ``bytes``.
:param int bufflength: value size in bytes (optional for numeric types).
:returns: the decoded value.
.. py:method:: write_process_memory(address, pytype, bufflength=None, value=...)
Write a value to memory.
:param int address: target memory address.
:param Type pytype: one of the five supported types.
:param int bufflength: 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)``).
:param value: the value to write.
:returns: the original ``value`` you passed in — **not** the truncated/encoded
form actually written (a capped ``str``/``bytes`` write returns the full
original value).
.. py:method:: read_process_memory_into(address, buffer)
Read ``len(buffer)`` raw bytes from ``address`` directly into a
pre-allocated, writable ``buffer`` (no intermediate allocation) — the
zero-copy counterpart of :py:meth:`read_process_memory` for tight
read-the-same-region loops. See :doc:`../guide/read-write` for examples.
:param int address: target memory address.
:param buffer: any writable, contiguous buffer-protocol object
(``bytearray``, ``ctypes`` array, writable ``memoryview``, ``numpy``
array, …). Its byte length sets how many bytes are read; the bytes land
verbatim (no decoding).
:returns: the number of bytes read (the buffer's byte length on success).
:raises TypeError: if ``buffer`` is not a writable buffer (e.g. ``bytes``).
:raises ValueError: if ``buffer`` is empty or not contiguous.
:raises OSError: if the read fails or returns fewer bytes than requested.

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.

.. py:method:: read_char(address)
:no-index:
Read / write a signed 8-bit integer (1 byte). Pair: ``write_char(address, value)``.
.. py:method:: read_short(address)
:no-index:
Signed 16-bit integer (2 bytes). Pair: ``write_short``.
.. py:method:: read_int(address)
:no-index:
Signed 32-bit integer (4 bytes). Pair: ``write_int``.
.. py:method:: read_long(address)
:no-index:
Signed 32-bit integer (4 bytes, Win32 ``LONG``). Pair: ``write_long``.
.. py:method:: read_longlong(address)
:no-index:
Signed 64-bit integer (8 bytes). Pair: ``write_longlong``.
.. py:method:: read_uchar(address)
:no-index:
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_*``.
.. py:method:: read_float(address)
:no-index:
32-bit float (4 bytes). Pair: ``write_float``.
.. py:method:: read_double(address)
:no-index:
64-bit double (8 bytes). Pair: ``write_double``.
.. py:method:: read_bool(address)
:no-index:
Boolean (1 byte). Pair: ``write_bool``.
.. py:method:: read_string(address, byte_count)
:no-index:
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)``.
.. py:method:: read_bytes(address, length)
:no-index:
Read ``length`` raw bytes. Pair: ``write_bytes(address, data)``.

Searching

.. py:method:: 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 :doc:`../guide/searching` for a full walkthrough.
.. py:method:: 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``).
.. py:method:: 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 :py:meth:`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.
.. py:method:: 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 :py:class:`re.Pattern`. See :doc:`../guide/pattern-scan`.

Memory regions

.. py:method:: get_memory_regions()
Yield a :py:class:`MemoryRegion` per region — an immutable dataclass with
``address``, ``size``, ``is_readable``, ``is_writable``, ``is_executable``,
``is_shared``, ``path`` and the platform-specific ``struct``.
.. py:method:: snapshot_memory_regions()
Materialize the region list once as a :py:class:`MemoryRegionSnapshot`
(pre-sorted by base address), for reuse across iterative scans.

Modules and threads

.. py:method:: get_modules()
Yield a :py:class:`ModuleInfo` for every loaded module.
.. py:method:: get_threads()
Yield a :py:class:`ThreadInfo` for every thread inside the target.

Pointers

.. py:method:: resolve_pointer_chain(base_address, offsets, *, ptr_size=None)
Walk a multi-level pointer chain and return the final address.
.. py:method:: get_pointer(base_address, offsets=None, *, pytype=int, bufflength=None, ptr_size=None)
Build a :py:class:`RemotePointer` bound to this process — a live,
re-resolving handle. See :doc:`../guide/pointers`.
.. py:method:: scan_pointer_paths(target_address, *, max_depth=3, 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 :py:class:`PointerPath` recipes that resolve
to ``target_address``. See :doc:`../guide/pointer-scan`.
.. py:method:: save_pointer_paths(paths, file)
Save pointer paths to a JSON file.
.. py:method:: load_pointer_paths(file)
Load pointer paths previously saved with :py:meth:`save_pointer_paths`.
.. py:method:: rescan_pointer_paths(paths, target_address)
Keep only the paths that still resolve to ``target_address``.
.. py:method:: compare_pointer_scans(*sources)
Intersect several saved scans — return the paths present in *every* one.

Allocation

.. py:method:: allocate_memory(size, *, permission=None)
Reserve ``size`` bytes inside the target. Windows and macOS only.
.. py:method:: free_memory(address, size=0)
Release a previously allocated region.

Lifecycle

.. py:method:: close()
Close the process handle. Subsequent calls raise :py:exc:`ClosedProcess`.
.. py:method:: __enter__()
.. py:method:: __exit__(exc_type, exc_value, exc_traceback)
The process is also a context manager — prefer the ``with`` block.
- [`ScanTypesEnum`](enums.md)
- [`MemoryRegion`](memory-region.md)
- [`RemotePointer`](remote-pointer.md)
- [`PointerPath`](pointer-path.md)
- [`ModuleInfo`](module-info.md)
- [`ThreadInfo`](thread-info.md)
- [Errors](errors.md)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); PyMemoryEditor/docs/api/openprocess.md at main · JeanExtreme002/PyMemoryEditor · GitHub
Skip to content

Latest commit

History

History
371 lines (262 loc) · 12.7 KB

File metadata and controls

371 lines (262 loc) · 12.7 KB

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.

.. py: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

.. py:class:: OpenProcess(*, name=None, pid=None, permission=<platform default>, case_sensitive=<platform default>, exact_match=True, strict_bitness=False)
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``.
:param str name: name of the target process.
:param int pid: process ID. Takes precedence over ``name``.
:param permission: **Windows only.** A
:py:class:`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``.
:param bool case_sensitive: when ``False``, ``name`` matching
ignores case. Default is ``False`` on Windows, ``True`` elsewhere.
:param bool exact_match: when ``False``, ``name`` matches as a
substring (``"chrome"`` matches ``"chrome.exe"``).
:param bool strict_bitness: when ``True``, :py:attr:`is_64bit` raises
:py:exc:`BitnessDetectionError` if the target's 32-/64-bit width
can't be read from its headers, instead of falling back to the host
word size. Use it when a wrong pointer-width default would be worse
than a hard failure.
:raises ProcessNotFoundError: no process matches ``name``.
:raises ProcessIDNotExistsError: ``pid`` doesn't exist.
:raises AmbiguousProcessNameError: more than one process matches.
:raises TypeError: neither ``name`` nor ``pid`` was provided.
:raises PermissionError: the OS denied access.

Examples

# By namewithOpenProcess(name="game.exe") asprocess:
...
# By PIDwithOpenProcess(pid=1234) asprocess:
...
# Partial, case-insensitive name match (Windows-friendly)withOpenProcess(name="chrome", case_sensitive=False, exact_match=False) asprocess:
...
# Read-only handle (Windows only)fromPyMemoryEditorimportProcessOperationsEnumwithOpenProcess(
name="game.exe",
permission=ProcessOperationsEnum.PROCESS_VM_READ|ProcessOperationsEnum.PROCESS_QUERY_INFORMATION,
) asprocess:
...

Attributes

.. py:attribute:: pid
:type: int
:no-index:
The PID of the target process.
.. py:attribute:: main_thread
:type: Optional[ThreadInfo]
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).
.. py:attribute:: is_64bit
:type: bool
``True`` if the target process is 64-bit, ``False`` if it is 32-bit.
Detected once on first access (via headers: ELF class on Linux, Mach-O
magic on macOS, ``IsWow64Process`` on Windows) and cached.
When the backend can't read the headers, the result depends on
``strict_bitness``: ``False`` (default) falls back to the host word size
and logs a WARNING; ``True`` raises
:py:exc:`BitnessDetectionError`.
.. py:attribute:: is_bitness_certain
:type: bool
``True`` if :py:attr:`is_64bit` was read from the target's own headers,
``False`` if it fell back to a guess of the host word size.
When ``False`` the automatic ``ptr_size`` default may be wrong for a
cross-bitness target — pass ``ptr_size`` explicitly to the pointer APIs.
.. py:attribute:: pointer_size
:type: int
Pointer width of the target process in bytes — ``8`` for a 64-bit target,
``4`` for a 32-bit one. Derived from :py:attr:`is_64bit`.

Methods

Read / write

.. py:method:: read_process_memory(address, pytype, bufflength=None)
Read a value from memory.
:param int address: target memory address.
:param Type pytype: ``bool``, ``int``, ``float``, ``str`` or ``bytes``.
:param int bufflength: value size in bytes (optional for numeric types).
:returns: the decoded value.
.. py:method:: write_process_memory(address, pytype, bufflength=None, value=...)
Write a value to memory.
:param int address: target memory address.
:param Type pytype: one of the five supported types.
:param int bufflength: 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)``).
:param value: the value to write.
:returns: the original ``value`` you passed in — **not** the truncated/encoded
form actually written (a capped ``str``/``bytes`` write returns the full
original value).
.. py:method:: read_process_memory_into(address, buffer)
Read ``len(buffer)`` raw bytes from ``address`` directly into a
pre-allocated, writable ``buffer`` (no intermediate allocation) — the
zero-copy counterpart of :py:meth:`read_process_memory` for tight
read-the-same-region loops. See :doc:`../guide/read-write` for examples.
:param int address: target memory address.
:param buffer: any writable, contiguous buffer-protocol object
(``bytearray``, ``ctypes`` array, writable ``memoryview``, ``numpy``
array, …). Its byte length sets how many bytes are read; the bytes land
verbatim (no decoding).
:returns: the number of bytes read (the buffer's byte length on success).
:raises TypeError: if ``buffer`` is not a writable buffer (e.g. ``bytes``).
:raises ValueError: if ``buffer`` is empty or not contiguous.
:raises OSError: if the read fails or returns fewer bytes than requested.

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.

.. py:method:: read_char(address)
:no-index:
Read / write a signed 8-bit integer (1 byte). Pair: ``write_char(address, value)``.
.. py:method:: read_short(address)
:no-index:
Signed 16-bit integer (2 bytes). Pair: ``write_short``.
.. py:method:: read_int(address)
:no-index:
Signed 32-bit integer (4 bytes). Pair: ``write_int``.
.. py:method:: read_long(address)
:no-index:
Signed 32-bit integer (4 bytes, Win32 ``LONG``). Pair: ``write_long``.
.. py:method:: read_longlong(address)
:no-index:
Signed 64-bit integer (8 bytes). Pair: ``write_longlong``.
.. py:method:: read_uchar(address)
:no-index:
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_*``.
.. py:method:: read_float(address)
:no-index:
32-bit float (4 bytes). Pair: ``write_float``.
.. py:method:: read_double(address)
:no-index:
64-bit double (8 bytes). Pair: ``write_double``.
.. py:method:: read_bool(address)
:no-index:
Boolean (1 byte). Pair: ``write_bool``.
.. py:method:: read_string(address, byte_count)
:no-index:
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)``.
.. py:method:: read_bytes(address, length)
:no-index:
Read ``length`` raw bytes. Pair: ``write_bytes(address, data)``.

Searching

.. py:method:: 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 :doc:`../guide/searching` for a full walkthrough.
.. py:method:: 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``).
.. py:method:: 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 :py:meth:`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.
.. py:method:: 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 :py:class:`re.Pattern`. See :doc:`../guide/pattern-scan`.

Memory regions

.. py:method:: get_memory_regions()
Yield a :py:class:`MemoryRegion` per region — an immutable dataclass with
``address``, ``size``, ``is_readable``, ``is_writable``, ``is_executable``,
``is_shared``, ``path`` and the platform-specific ``struct``.
.. py:method:: snapshot_memory_regions()
Materialize the region list once as a :py:class:`MemoryRegionSnapshot`
(pre-sorted by base address), for reuse across iterative scans.

Modules and threads

.. py:method:: get_modules()
Yield a :py:class:`ModuleInfo` for every loaded module.
.. py:method:: get_threads()
Yield a :py:class:`ThreadInfo` for every thread inside the target.

Pointers

.. py:method:: resolve_pointer_chain(base_address, offsets, *, ptr_size=None)
Walk a multi-level pointer chain and return the final address.
.. py:method:: get_pointer(base_address, offsets=None, *, pytype=int, bufflength=None, ptr_size=None)
Build a :py:class:`RemotePointer` bound to this process — a live,
re-resolving handle. See :doc:`../guide/pointers`.
.. py:method:: scan_pointer_paths(target_address, *, max_depth=3, 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 :py:class:`PointerPath` recipes that resolve
to ``target_address``. See :doc:`../guide/pointer-scan`.
.. py:method:: save_pointer_paths(paths, file)
Save pointer paths to a JSON file.
.. py:method:: load_pointer_paths(file)
Load pointer paths previously saved with :py:meth:`save_pointer_paths`.
.. py:method:: rescan_pointer_paths(paths, target_address)
Keep only the paths that still resolve to ``target_address``.
.. py:method:: compare_pointer_scans(*sources)
Intersect several saved scans — return the paths present in *every* one.

Allocation

.. py:method:: allocate_memory(size, *, permission=None)
Reserve ``size`` bytes inside the target. Windows and macOS only.
.. py:method:: free_memory(address, size=0)
Release a previously allocated region.

Lifecycle

.. py:method:: close()
Close the process handle. Subsequent calls raise :py:exc:`ClosedProcess`.
.. py:method:: __enter__()
.. py:method:: __exit__(exc_type, exc_value, exc_traceback)
The process is also a context manager — prefer the ``with`` block.
- [`ScanTypesEnum`](enums.md)
- [`MemoryRegion`](memory-region.md)
- [`RemotePointer`](remote-pointer.md)
- [`PointerPath`](pointer-path.md)
- [`ModuleInfo`](module-info.md)
- [`ThreadInfo`](thread-info.md)
- [Errors](errors.md)