Modules and threads
Beyond memory regions, PyMemoryEditor exposes two more inspection APIs:
get_modules()— every executable and shared library loaded into the process.get_threads()— every thread currently running inside the process.
Both return immutable dataclass instances and are cross-platform.
Loaded modules
A module is a file mapped into the process — the main executable plus every
shared library it loaded (.exe/.dll on Windows, the binary and .so files
on Linux, the Mach-O image and .dylib files on macOS).
with OpenProcess(process_name="game.exe") as process:
for module in process.get_modules():
print(
module.name,
hex(module.base_address),
module.size,
module.path,
)
The ModuleInfo dataclass
- class ModuleInfo
- name: str
File name of the module — e.g.
"game.exe","libc.so.6".
- path: str
Full path of the backing file on disk. On Windows it falls back to
namewhen only the name is available; on macOSnamederives frompath, so an unresolvable image yields both as empty strings.
- base_address: int
Address where the module is loaded for this run. Combine it with a static offset (
base_address + offset) to reach a known location despite ASLR — the natural feed intoresolve_pointer_chain().
- size: int
Module size in bytes.
0when the backend cannot determine it. Platform-specific: full image on Windows/Linux;__TEXTsegment size on macOS.
- raw: Any
Underlying platform handle for advanced follow-up calls.
Finding a module by name
def find_module(process, name):
for module in process.get_modules():
if module.name == name:
return module
return None
with OpenProcess(pid=1234) as process:
main_module = find_module(process, "game.exe")
if main_module:
# Use module.base_address + static_offset as the base of a pointer chain.
hp_addr = process.resolve_pointer_chain(
main_module.base_address + 0x10F4F4, [0x0, 0x158],
)
Threads
get_threads() yields a ThreadInfo for every thread running inside the
target. It’s useful for introspection (“how many workers does it spawn?”,
“is the main thread still alive?”).
with OpenProcess(process_name="game.exe") as process:
for thread in process.get_threads():
print(thread.tid, thread.state, thread.priority)
print("Main thread:", process.main_thread.tid)
The ThreadInfo dataclass
- class ThreadInfo
- tid: int
Thread identifier. The meaning is platform-specific:
Linux — POSIX TID; same namespace as PID.
Windows — kernel-assigned DWORD thread id.
macOS — Mach thread port name.
- start_address: int | None
Reserved for the thread entry point — currently always ``None`` on every platform (no backend fetches it).
- state: str | None
Short human-readable state (e.g.
"R"/"S"on Linux).Noneon platforms that don’t surface it.
- priority: int | None
Scheduling priority as reported by the OS. Scale is platform-specific;
Nonewhen not exposed.
- raw: Any
Underlying platform handle (
THREADENTRY32on Windows, the TID path on Linux, a Mach port int on macOS). Useful for advanced follow-up calls.
The main_thread shortcut
The process.main_thread property is a convenience for the conventional “main
thread” — by convention, the thread with the smallest tid:
print(process.main_thread.tid)
It returns None if the target has no listable threads (rare; typically means
the process just exited).
Cross-platform tid semantics
Don’t mix tids with pids, and don’t compare tids across operating
systems. On Linux a TID and a PID share a namespace; on Windows and macOS they
don’t.
See also
Memory regions — list the process’s address space.
Pointers — use
module.base_address + offsetas a static base.