memory-inspector is a Windows-only, interactive command-line tool for inspecting the memory of a running process you own or have permission to analyze. It scans for exact values, narrows them down as they change, finds pointers to an address, resolves multi-level pointer chains, runs array-of-bytes (AOB) pattern scans inside a module, and — only after an explicit confirmation — writes a value or NOPs out code bytes, keeping the original bytes for a one-step restore.
It is built on pymem and is not affiliated with WeMod or any game trainer platform. It does not evade, disable, or bypass any anti-cheat, DRM, or integrity check.
- Windows 10/11, 64-bit. Pointer-chain resolution is 64-bit only; a 32-bit target is not supported for chains in this version.
- Python 3.10 or higher.
- An elevated terminal (Run as Administrator). Reading and writing another process's memory requires it.
- A target process you own or have permission to analyze. The tool refuses to attach to its own process.
- Git, to clone the repository. The GitHub CLI (
gh) is optional, for setting the repository description and topics after pushing.
This package is not published to PyPI. Install it from source:
git clone https://github.com/enonymous1/memory-inspector.git
cd memory-inspector
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install .Verify the install:
memory-inspector --help
memory-inspector --versionOn Linux or macOS the command installs but refuses to run: it prints the banner and exits, because pymem needs the Win32 API. That platform guard is intentional, not a bug.
Attach by picking from a list, by PID, or by exact process name:
memory-inspector
memory-inspector --pid 1234
memory-inspector --process notepad.exe
memory-inspector --read-onlyA safe first run is against Notepad (or any other process you own),
with --read-only so writes and patches are disabled:
memory-inspector --process notepad.exe --read-onlyThe interactive inspector:
[1] New scan (find an exact value)
[2] Next scan (filter by a new value)
[3] Auto-filter (purge fluctuating values over time)
[4] Pointer scan (find what points to an address)
[5] Resolve pointer chain
[6] AOB pattern scan in a module
[7] Write value (modify an address)
[8] NOP bytes at an address
[9] Restore last NOP patch
[q] Quit inspector
Addresses and offsets accept decimal or 0x-prefixed hex. Value
types are i32, u32, i64, u64, f32, and f64. Scans and
filters never write. Options 7 and 8 always show the address, the
current value or bytes, and the new value, and ask for confirmation
first; --read-only disables them entirely.
from memory_inspector.process_manager import ProcessManager
from memory_inspector.memory_scanner import MemoryScanner
from memory_inspector.memory_writer import MemoryWriter
with ProcessManager(1234) as manager:
pm = manager.get_pymem_instance()
scanner = MemoryScanner(pm)
addresses = scanner.find_value(100, "i32")
addresses = scanner.filter_addresses(addresses, 90, "i32")
if addresses and MemoryWriter(pm).write_value(addresses[0], 90, "i32"):
print("Wrote 90 to", hex(addresses[0]))write_value returns False on a write failure and raises
ValueError for an out-of-range value before anything is written.
Core classes take a ProcessMemory protocol, not a concrete pymem
class, so they can be driven with a fake in tests (see below).
Set up a development install (Windows for live runs; Linux or macOS is fine for the mocked suite):
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install ".[dev]"Run every gate before committing. They must all pass:
ruff check src tests
ruff format --check src tests
mypy src
pytest -qTests stub pymem in tests/conftest.py and never touch a live
process, so the suite runs on any platform. That is a deliberate
trade-off, not full coverage: the live gate before any release is a
run on Windows, as Administrator, against a process you own — scan,
filter, resolve a pointer chain, write with confirmation, NOP a
whole instruction, and restore it.
To add a value kind, edit exactly one place:
src/memory_inspector/value_kinds.py (VALUE_KIND_SPECS). The
scanner and writer both derive their method names and struct format
from that table. To add an inspector action, add a branch in
interactive_inspector in src/memory_inspector/cli.py and a
driving test in tests/test_cli.py using the fake scanner/writer
doubles there.
There is no server, service, or hosted component to deploy. For users, "deployment" is installing from source on a Windows machine (see Installation) and running it elevated.
For maintainers, a release is a GitHub tag plus CI:
- Bump the version in
pyproject.toml,src/memory_inspector/__init__.py, andCHANGELOG.md. - Commit, push to
main, and confirm the Ubuntu + Windows CI matrix (Python 3.10–3.13) is green. - Tag the release, for example
git tag v2.1.0, and push the tag. - Confirm the live Windows gate above before announcing the release. CI alone does not prove the tool works against a real process, because pymem is stubbed in tests.
The package is not on PyPI. Publishing to PyPI would be a separate decision (distribution name, build, and upload credentials) and is not part of this release process.
cli.pyowns the interaction loop and confirmations only. It does not know pymem method names.process_manager.pyowns attaching by PID, exact-name resolution, and handle lifetime.memory_scanner.py,memory_writer.py,pointer_scanner.py, andcode_injector.pyprogram against theProcessMemoryprotocol inprotocols.py, so a pymem change touches the adapter surface, not every module.value_kinds.pyis the single registry for value types.code_injector.pychanges page protection withVirtualProtectEx, writes, restores protection, and flushes the instruction cache, so patched code is actually executed as patched.
- Use only on software you own or have permission to analyze.
- Writing to a process can crash it. NOPing a partial instruction corrupts code: only NOP whole instructions, and restore immediately if the target misbehaves.
- Online games with anti-cheat systems may ban accounts for memory modification. This tool offers no protection against that.
- Pointer chains are 64-bit only. Float scans use exact equality, so a decimal that does not round-trip to the same float bits will not match.
- Scans without a cap can return very many addresses for common
values such as 0. Library callers can pass
max_resultstofind_valueandfind_pointersto bound the result. - Antivirus software may flag any memory-manipulation tool. That is expected for this category and is not, by itself, evidence of malware.
- "Requires Windows" on Linux/macOS: expected. Run it on Windows.
- "Could not find process" / "Could not open process": the PID or name is wrong, the process exited, or the terminal is not elevated. Re-check the PID in Task Manager and re-run elevated.
- "Multiple processes named ...": use
--pidwith the exact PID from the picker instead of--process. - A scan finds nothing: check the value type (
i32vsu64, for example), that the value is actually in writable memory, and that the target has not reallocated the value elsewhere. - A NOP patch reports success but the target behaves unchanged: check that you NOPed whole instructions, and that the instruction-cache flush did not warn in the log.
- A write succeeds but the value changes back immediately: the target rewrote it. That is the program's normal behavior, not a failed write; the inspector's read-back verification shows the value right after the write.
MIT. See LICENSE and CHANGELOG.md.