PointerPathο
A discovered static pointer path, returned by scan_pointer_paths.
from PyMemoryEditor import PointerPath
Resolving base_address and then walking offsets with
resolve_pointer_chain lands on the target. When the base sits inside a
known module, module / module_offset express it ASLR-independently so the
path survives a restart β feed it to rebase() in the next run.
Constructionο
- class PointerPath(base_address, offsets, module=None, module_offset=None, ptr_size=8)ο
- Parameters:
base_address (int) β absolute static base for this run (the slot whose pointer the chain dereferences first).
offsets (Tuple[int, ...]) β forward-order offsets, ready to hand to
resolve_pointer_chain().module (Optional[str]) β name of the module containing
base_address(Nonewhen the base falls in a caller-supplied static range with no known module).module_offset (Optional[int]) β
base_address - module.base_addressβ the portable, ASLR-independent part of the base.Nonewhenmoduleis.ptr_size (int) β pointer width β
8for 64-bit (default) or4for 32-bit.
PointerPath is a @dataclass(frozen=True) β instances are immutable and
hashable.
Attributesο
| Attribute | Type | Meaning |
|---|---|---|
base_address | int | Absolute static base for the run the path was found in. |
offsets | Tuple[int, ...] | Forward-order offsets. |
module | Optional[str] | Module owning base_address. |
module_offset | Optional[int] | base_address - module.base_address. |
ptr_size | int | Pointer width (4 or 8). |
Methodsο
Resolvingο
- resolve(process)ο
Walk this path in
processand return the final target address.- Parameters:
process (AbstractProcess) β the open process.
- Returns:
the target address (
int).
- to_pointer(process, *, pytype=int, bufflength=None)ο
Build a live
RemotePointerfor the value at the end of this path.- Returns:
a
RemotePointerre-resolving on every access.
Rebasing across runsο
- rebase(process)ο
Return a copy with
base_addressrecomputed from the live module base inprocessβ the call that makes a saved path valid again after a restart moved the module (ASLR).- Raises:
ValueError β this path has no associated module (its base came from a caller-supplied static range), so it cannot be rebased.
LookupError β the module is not loaded in
process.
Serializationο
- to_dict()ο
Serialise to a JSON-friendly dict (hex strings) for export. The ASLR-independent part β
module+module_offset+offsetsβ is what makes a saved path replayable in a later run viafrom_dict()+rebase().
- classmethod from_dict(data)ο
Rebuild a
PointerPathfromto_dict()output. Numeric fields accept either hex strings ("0x158") or plain ints.
Comparison & displayο
- recipe()ο
The ASLR-independent identity of this path:
(module, module_offset, offsets). Two paths from different runs describe the same pointer when their recipes are equal.
- __str__()ο
Cheat Engine-style textual representation, e.g.:
"game.exe"+0x10F4F4 -> [+0x0] -> +0x158
Example workflowsο
Saving and reloadingο
paths = list(process.scan_pointer_paths(address))
process.save_pointer_paths(paths, "pointers.json")
# Later, in a different run:
loaded = process.load_pointer_paths("pointers.json")
for path in loaded:
live = path.rebase(process)
print(live.resolve(process))
Building a live handle from a saved pathο
loaded = process.load_pointer_paths("pointers.json")
hp_ptr = loaded[0].rebase(process).to_pointer(process, pytype=int, bufflength=4)
hp_ptr.value = 9999
Intersecting independent scansο
stable = process.compare_pointer_scans(
"scan1.json", "scan2.json", "scan3.json",
)
print(f"{len(stable)} stable pointers")
See also