Low-level physical memory access via Linpmem kernel driver
Project description
LinPyMem
Read physical memory from user-space using a kernel-mode driver (linpmem.ko) and virtual-to-physical address translation with CR3 walking.
🔍 What is LinPyMem?
LinPyMem is a Python wrapper around the linpmem kernel module, enabling:
- Translation of virtual memory addresses to physical addresses
- Reading raw physical memory (primitives, vectors, strings)
- Inspecting memory mapped regions of another Linux process
⚠️ Requirements
- Linux system with root privileges
linpmem.kobuilt from source- Module must be signed and enrolled via MOK if Secure Boot is enabled
- Python 3.7+
- Dependencies:
psutil,ctypes,fcntl,struct,subprocess
🔧 Installation
pip install linpymem
🔐 Secure Boot Considerations
If Secure Boot is enabled:
Sign the linpmem.ko using your own key:
/usr/src/linux-headers-$(uname -r)/scripts/sign-file sha256 MOK.key MOK.crt linpmem.ko
Enroll the public key:
sudo mokutil --import MOK.crt
Reboot and follow the on-screen instructions
✅ Usage with context manager (auto-loads and removes driver)
from linpymem import LinPyMem
some_offset = 0xcafebabe
with LinPyMem(ko_module_path="/path/to/linpmem.ko", process_name="firefox", vm_pathname="/usr/lib/x86_64-linux-gnu/libc.so.6") as reader:
print(f"[+] pid: {reader.pid} vm_range: {hex(reader.process_vm_start_addr)}-{hex(reader.process_vm_end_addr)} size: {hex(reader.process_vm_size)} cr3: {hex(reader.cr3)}")
regions = reader.pathname_vm_regions
for base_addr, size in regions:
data = reader.read_ptr(base_addr + some_offset)
⚙️ Manual Usage (driver is already loaded and should remain loaded)
from linpymem import LinPyMem, PhysAccessMode
some_offset = 0xcafebabe
reader = LinPyMem(process_name="firefox", vm_pathname="/usr/lib/x86_64-linux-gnu/libc.so.6")
print(f"[+] pid: {reader.pid} vm_range: {hex(reader.process_vm_start_addr)}-{hex(reader.process_vm_end_addr)} size: {hex(reader.process_vm_size)} cr3: {hex(reader.cr3)}")
for base_addr, size in regions:
# using conveinience function
data = reader.read_bytes(base_addr + some_offset, 0x1337)
# or equivalently
physical_address, pte_virt_addr = reader.virtual_to_physical(base_addr + some_offset, reader.cr3)
data, num_bytes_read, num_expected_bytes = reader.read_physical_memory(physical_address, PhysAccessMode.PHYS_BUFFER_READ, 0x1337)
🧭 Available class properties and functions
reader = LinPyMem(...)
reader.pid
reader.process_vm_start_addr
reader.process_vm_end_addr
reader.process_vm_size
reader.pathname_vm_regions
reader.cr3
# optional driver setup/teardown helpers
def insert_kernel_module(self, module_path: str):
def get_driver_major_number(self, driver_name: str) -> int:
def create_device_node(self, major_number: int, device_path: str):
def setup_driver(self, module_path: str, device_path: str):
def remove_driver(self, device_path: str):
# process inspection helpers
def get_pid_by_process_name(self, process_name: str) -> int:
def get_process_virtual_memory_bounds(self, pid: int) -> tuple[int, int, int]:
def get_pathname_virtual_address_range(self, pid: int, pathname: str) -> list[tuple[int, int]]:
# linpmem kernel IOCTL calls
def read_physical_memory(self, phys_addr: int, mode: PhysAccessMode, readbuffer_size: int = 0) -> tuple:
def virtual_to_physical(self, virt_addr: int, cr3: int = 0) -> tuple[int, int]:
def get_cr3_for_process(self, pid: int) -> int:
# convenince functions (constructed with IOCTL primitaves above)
def read_bytes(self, addr: int, size: int) -> bytes:
def read_ptr(self, addr: int) -> int:
def read_short(self, addr: int) -> int:
def read_int(self, addr: int) -> int:
def read_float(self, addr: int) -> float:
def read_double(self, addr: int) -> float:
def read_vec3_float(self, addr: int) -> tuple[float, float, float]:
def read_vec3_double(self, addr: int) -> tuple[float, float, float]:
def read_utf_string(self, addr: int, max_len: int = 1024) -> str:
def view_memory_region(self, start_address: int, size: int, row_size: int = 16):
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file linpymem-0.3.0.tar.gz.
File metadata
- Download URL: linpymem-0.3.0.tar.gz
- Upload date:
- Size: 12.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.0.1 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7bf5b41992ca59b5d857328a1d30d6b05f2b89aad2f014d9931b68c51c208641
|
|
| MD5 |
bbfa8ff514dc462115f6eb715e725ba4
|
|
| BLAKE2b-256 |
e08ec18736166805c7227528d8b0f7235621bda046fc7d47db9bd46c9c4c7a50
|
File details
Details for the file linpymem-0.3.0-py3-none-any.whl.
File metadata
- Download URL: linpymem-0.3.0-py3-none-any.whl
- Upload date:
- Size: 11.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.0.1 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
155af1c82924806758e967a59cd2b5dab310474667f91623249ae078b7da3717
|
|
| MD5 |
1e996672d64fa86ed920ab3530dd15f7
|
|
| BLAKE2b-256 |
79ce3d99cc5c9f23d86af04bfd6911420bec515a10ec5745f13e3e5e6e59a0e7
|