Reading Living Process Memory Without Interrupting It

Reading living process memory without interrupting it

For process 1234 you can get its memory map by reading sequentially /proc/1234/maps (a textual pseudo-file) and read the virtual memory by e.g. read(2)-ing or mmap(2)-ing appropriate segments of the /proc/1234/mem sparse pseudo-file.

However, I believe you cannot avoid some kind of synchronization (perhaps with ptrace(2), as gdb does), since the process 1234 can (and does) alter its address space at any time (with mmap & related syscalls).

The situation is different if the monitored process 1234 is not arbitrary, but if you could improve it to communicate somehow with the monitoring process.

I'm not sure to understand why do you ask this. And gdb is able to watch some location without stopping the process.

Check Shared Memory(SHR) consumption for process

The S or share key is listed as obsolete, in the ps man page, so that doesn't seem to be possible:

https://www.man7.org/linux/man-pages/man1/ps.1.html

Your next best option may be something like this:

awk '{print $3}' < /proc/<PID>/statm

That's the number of resident shared pages (so multiple by the page size).

However, there's a big caveat: https://man7.org/linux/man-pages/man5/proc.5.html

       /proc/[pid]/statm
Provides information about memory usage, measured in
pages. The columns are:

size (1) total program size
(same as VmSize in /proc/[pid]/status)
resident (2) resident set size
(inaccurate; same as VmRSS in /proc/[pid]/status)
shared (3) number of resident shared pages
(i.e., backed by a file)
(inaccurate; same as RssFile+RssShmem in
/proc/[pid]/status)
text (4) text (code)
lib (5) library (unused since Linux 2.6; always 0)
data (6) data + stack
dt (7) dirty pages (unused since Linux 2.6; always 0)

Reading Memory Address from a process with a Static Address and Offsets in Python

I've figured out what I was missing. I've been interpreting the addresses wrong. They are pointers to the addresses and so, when using offsets I need to read them, and add them to one another to get access to the value I want to read. Also, I needed to use the base address of the program, for which I just needed to return the value of the module.

Here is the above script with the necessary changes to read a process' memory with offsets:

import win32api
import win32process
import win32con
import ctypes


def get_process_by_name(process_name):
"""Finds the process id of the given
process name and returns the process id and its base address."""

process_name = process_name.lower()

# Enumerate all processes
processes = win32process.EnumProcesses()

for process_id in processes:
# If process_id is the same as this program, skip it
if process_id == -1:
continue

# Try to read the process memory
try:
h_process = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION | win32con.PROCESS_VM_READ, True, process_id)

# Try to read the modules of the process
try:
# modules is an array of base addresses of each module
modules = win32process.EnumProcessModules(h_process)

for base_address in modules:
# Get the name of the module
name = str(win32process.GetModuleFileNameEx(h_process, base_address))

# Compare it to the name of your program
if name.lower().find(process_name) != -1:
return process_id, base_address
finally:
win32api.CloseHandle(h_process)
except:
pass


def read_process_memory(process_id, address, offsets=[]):
"""Read a process' memory based on its process id, address and offsets.
Returns the address without offsets and the value."""

# The handle to the program's process
# This will allow to use ReadProcessMemory
h_process = ctypes.windll.kernel32.OpenProcess(win32con.PROCESS_VM_READ, False, p_id)

# This is a pointer to the data you want to read
# Use `data.value` to get the value at this pointer
# In this case, this value is an Integer with 4 bytes
data = ctypes.c_uint(0)

# Size of the variable, it usually is 4 bytes
bytesRead = ctypes.c_uint(0)

# Starting address
current_address = address

if offsets:
# Append a new element to the offsets array
# This will allow you to get the value at the last offset
offsets.append(None)

for offset in offsets:
# Read the memory of current address using ReadProcessMemory
ctypes.windll.kernel32.ReadProcessMemory(h_process, current_address, ctypes.byref(data), ctypes.sizeof(data), ctypes.byref(bytesRead))

# If current offset is `None`, return the value of the last offset
if not offset:
return current_address, data.value
else:
# Replace the address with the new data address
current_address = data.value + offset

else:
# Just read the single memory address
ctypes.windll.kernel32.ReadProcessMemory(h_process, current_address, ctypes.byref(data), ctypes.sizeof(data), ctypes.byref(bytesRead))

# Close the handle to the process
ctypes.windll.kernel32.CloseHandle(h_process)

# Return a pointer to the value and the value
# The pointer will be used to write to the memory
return current_address, data.value


# Open the process
p_id, base_address = get_process_by_name("program.exe")

# The static address needs the program base_address
address = base_address + 0x00571160
offsets = [0xD84, 0x1B8, 0x38, 0x5C, 0x24, 0xF4, 0x1D08]
pointer_value, value = read_process_memory(p_id, address, offsets)
print(f"(Static Address) Value: {value}")

# Re-reading the memory with the last pointer
pointer_value, value = read_process_memory(p_id, pointer_value, None)
print(f"(Dynamic Address) Value: {value}")

Is it possible to determine if another process has read your memory?

In general no. I just had to dump the complete memory of a process some days ago, and the first thing I did, was to suspend the process that should be dumped. As the stopped process has no control over its own restart, there is no guarantee that it can continue afterwards, so there is no way that it could reliable check whether it was dumped or not.

There are several approaches that are used, esp in the copy-protection area, like crypting memory addresses, spawning several other process to guard the orignial process, and several other tricks but which are nothing more than that: tricks. As long as the hardware does not fully encrypt everything and does inside the cpu itself without anbybody else giving access to it the there is always a way to read the memory without letting the cpu know it (e.g. intels TPM is a first towards this direction).

E.g. one possible attack to get passwords in embedded devices is the following:
To get the password in the ram, the device is opened (while running), the dram chips are frozen and then connected to a different device (and the original is shut down). The frozen state allows the chips to retain their electric state some secs longer without refresh - enough time to connect them else where and read afterwards everything out. No program could detect such a thing. Only way around is the above mentioned: the content on the chips itself must be encoded.

How to get the memory usage of a process in linux without root permission

I'm not sure exactly what you are really looking for-- do you want to know the amount of memory that a process is currently using? If so, then look at /proc/<pid>/status and examine the VmRSS line. That's the number you want (in this case, RSS means "Resident Set Size" if you're curious). That line should be parse-able in a high-level language like PHP. However, for a lower-level language like C, it should be easier to parse /proc/<pid>/stat which has the same values but each is separated by a space and there are no labels.

If you don't have permission to read the file, that means that the server process is running under a different user than you are logged in as. You will need to work with the hosting provider to get that resolved, or figure out how to get the server process to query its own processes (PHP script?).

Does that answer your question? Or are you interested in knowing "max memory usage" as in, "the most amount of memory that a process may use before being killed by the kernel?" This is actually something of a touchy philosophical issue for Linux. You won't find any solid information about such a maximum because there is no hard limit. Read up on "Linux memory overcommit" for more details.

Dump memory of a process

Nah! Call ptrace() with PTRACE ATTACH. Then open /proc/<pid>/mem, seek to the region offset, and read the length of the region as given in /proc</pid>/maps.

Here's a program I wrote that does it in C. Here's a module I wrote that does it in Python (and the ptrace binding). For the finish, a program that dumps all regions of a process to files.

Enjoy!



Related Topics



Leave a reply



Submit