Reading Other Process' Memory in OS X?
Asked Answered
B

8

25

I've been trying to understand how to read the memory of other processes on Mac OS X, but I'm not having much luck. I've seen many examples online using ptrace with PEEKDATA and such, however it doesn't have that option on BSD [man ptrace].

int pid = fork();
if (pid > 0) {
    // mess around with child-process's memory
}

How is it possible to read from and write to the memory of another process on Mac OS X?

Burgher answered 14/8, 2008 at 4:31 Comment(6)
I am particularly interested in the case where I do not control the other process -- i.e. poking around inside somebody else's program to see what it's doing. (Presumably after disabling ASLR.)Burgher
I don't understand what part of the process you want to read. Do you to get the wall process address space as in core dump files? You need code to handle threads and (sometimes) shared libraries. You (mostly) don't need this code if it for just looking the program binary in ram for example.Tahr
@Tahr I'm interested in observing or manipulating the working memory of a process, not the executable code.Burgher
« manipulating the working memory » Your post just contain the « read » word. Do you mean you also need to write in the process address space? In that case you probably need an hex heditor. It work the same way for files, but you use a process as parameter. I'll try to see if it exist for XNU/darwin or bsd4.3 (since apple based their OS on this BSD)Tahr
@Tahr Writing in the process address space would be a very nice-to-have. I've heard of ways to access process memory on Linux before, but I wasn't sure if they applied to BSD, and more particularly I'm not sure how much has been removed from OS X that's available in other BSD distributions. Thanks for your suggestions.Burgher
virtual addressing is like files.When you look an at address in a file, it is not the same as the real address on the drive.The file can be fragmented,but the OS will make it look as in single piece. The program don't really care about allocation or size,the OS does all.It is the same virtual address in ram.If a library make system call it write a value in a special area were program shouldn't write: a page fault occurs.Register are in address space since they have address.See: upload.wikimedia.org/wikipedia/commons/3/32/…Tahr
M
16

Use task_for_pid() or other methods to obtain the target process’s task port. Thereafter, you can directly manipulate the process’s address space using vm_read(), vm_write(), and others.

Mirage answered 15/9, 2008 at 13:48 Comment(2)
There is also vm_remap which will allow you to map a foreign processes memory into your own VM.Rivas
after getting the process' task port, how do i get its address space? and how do i further search in the address space for a specific string ? can you give an example?Earpiercing
X
12

Matasano Chargen had a good post a while back on porting some debugging code to OS X, which included learning how to read and write memory in another process (among other things).

It has to work, otherwise GDB wouldn't:

It turns out Apple, in their infinite wisdom, had gutted ptrace(). The OS X man page lists the following request codes:

  • PT_ATTACH — to pick a process to debug
  • PT_DENY_ATTACH — so processes can stop themselves from being debugged
    [...]

No mention of reading or writing memory or registers. Which would have been discouraging if the man page had not also mentioned PT_GETREGS, PT_SETREGS, PT_GETFPREGS, and PT_SETFPREGS in the error codes section. So, I checked ptrace.h. There I found:

  • PT_READ_I — to read instruction words
  • PT_READ_D — to read data words
  • PT_READ_U — to read U area data if you’re old enough to remember what the U area is
    [...]

There’s one problem solved. I can read and write memory for breakpoints. But I still can’t get access to registers, and I need to be able to mess with EIP.

Xenia answered 14/8, 2008 at 4:46 Comment(0)
M
9

I know this thread is 100 years old, but for people coming here from a search engine:

xnumem does exactly what you are looking for, manipulate and read inter-process memory.

// Create new xnu_proc instance
xnu_proc *Process = new xnu_proc();

// Attach to pid (or process name)
Process->Attach(getpid());

// Manipulate memory
int i = 1337, i2 = 0;
i2 = process->memory().Read<int>((uintptr_t)&i);

// Detach from process
Process->Detach();
Matamoros answered 27/7, 2014 at 20:12 Comment(1)
That link's a 404. I think it's moved to github.com/gordio/xnumemRattray
E
6

It you're looking to be able to share chunks of memory between processes, you should check out shm_open(2) and mmap(2). It's pretty easy to allocate a chunk of memory in one process and pass the path (for shm_open) to another and both can then go crazy together. This is a lot safer than poking around in another process's address space as Chris Hanson mentions. Of course, if you don't have control over both processes, this won't do you much good.

(Be aware that the max path length for shm_open appears to be 26 bytes, although this doesn't seem to be documented anywhere.)

// Create shared memory block
void* sharedMemory = NULL;
size_t shmemSize = 123456;
const char* shmName = "mySharedMemPath";        
int shFD = shm_open(shmName, (O_CREAT | O_EXCL | O_RDWR), 0600);
if (shFD >= 0) {
    if (ftruncate(shFD, shmemSize) == 0) {
        sharedMemory = mmap(NULL, shmemSize, (PROT_READ | PROT_WRITE), MAP_SHARED, shFD, 0);
        if (sharedMemory != MAP_FAILED) {
            // Initialize shared memory if needed
            // Send 'shmemSize' & 'shmemSize' to other process(es)
        } else handle error
    } else handle error
    close(shFD);        // Note: sharedMemory still valid until munmap() called
} else handle error

...
Do stuff with shared memory
...

// Tear down shared memory
if (sharedMemory != NULL) munmap(sharedMemory, shmemSize);
if (shFD >= 0) shm_unlink(shmName);





// Get the shared memory block from another process
void* sharedMemory = NULL;
size_t shmemSize = 123456;              // Or fetched via some other form of IPC
const char* shmName = "mySharedMemPath";// Or fetched via some other form of IPC
int shFD = shm_open(shmName, (O_RDONLY), 0600); // Can be R/W if you want
if (shFD >= 0) {
    data = mmap(NULL, shmemSize, PROT_READ, MAP_SHARED, shFD, 0);
    if (data != MAP_FAILED) {
        // Check shared memory for validity
    } else handle error
    close(shFD);        // Note: sharedMemory still valid until munmap() called
} else handle error


...
Do stuff with shared memory
...

// Tear down shared memory
if (sharedMemory != NULL) munmap(sharedMemory, shmemSize);
// Only the creator should shm_unlink()
Eakins answered 15/9, 2008 at 16:8 Comment(2)
There are several restrictions on the use of shm_open; in addition to the path length issue mentioned, MacOSX ships with a kernel state setting that limits the size of a process's shared memory to 4MB. You can see this setting by executing sysctl -A on the command line and searching for 'kern.sysv.shmmax'.Errolerroll
not exactly, seems that the ~4MB limit is affected only the SYSTEM V IPC ftok/shmget/shmat funtions, if you are using the POSIX shm_open/ftruncate/mmap solution (mentioned above) the limit can be even about 16MB(!) (depending on the kernel probably) we are using 16MB blocks on OSX 10.5-10.9 (earlier even on 10.4) without problems.Dilatation
T
3

I have definitely found a short implementation of what you need (only one source file (main.c)). It is specially designed for XNU.

It is in the top ten result of Google search with the following keywords « dump process memory os x »

The source code is here

but from a strict point of virtual address space point de vue, you should be more interested with this question: OS X: Generate core dump without bringing down the process? (look also this)

When you look at gcore source code, it is quite complex to do this since you need to deal with treads and their state...

On most Linux distributions, the gcore program is now part of the GDB package. I think the OSX version is installed with xcode/the development tools.

UPDATE: wxHexEditor is an editor which can edit devices. IT CAN also edit process memory the same way it does for regular files. It work on all UNIX machines.

Tahr answered 7/10, 2013 at 23:45 Comment(1)
Interest stuff, I'll a look. Thanks.Burgher
T
2

You want to do Inter-Process-Communication with the shared memory method. For a summary of other commons method, see here

It didn't take me long to find what you need in this book which contains all the APIs which are common to all UNIXes today (which many more than I thought). You should buy it in the future. This book is a set of (several hundred) printed man pages which are rarely installed on modern machines. Each man page details a C function.

It didn't take me long to find shmat() shmctl(); shmdt() and shmget() in it. I didn't search extensively, maybe there's more.

It looked a bit outdated, but: YES, the base user-space API of modern UNIX OS back to the old 80's.

Update: most functions described in the book are part of the POSIX C headers, you don't need to install anything. There are few exceptions, like with "curses", the original library.

Tahr answered 14/8, 2008 at 4:31 Comment(4)
@JeremyBanks I need to write an another answer with your comment, but I have a few questions: Do you know in what consist virtual addressing from the user process point of vue (note:Wikipedia don't give real explanations about this)? Do you what is process isolation and how it deal with IPC? It is a base service of the OS to give memory space isolation: imagine a running process without administrator rights could read unencrypted passwords on an another process.Launching a driver in ring0 was the goal of pirates to achieve this.Tahr
@JeremyBanks : there is something which I forgot: Yes you could do it /dev/mem and /dev/kmem, but beginning with the x86 version of Mac OS X, apple removed those devices for many reasons including security. Linux did something similar with a config compile time option that most linux ditro enabled: it disable the full access of /dev/mem (even for root) and restrict it to only the addresses programs (like Xorg) uses.Tahr
I don't know enough about virtual memory to know the details of how this works in a modern operating system, but I understand that this violates memory isolation and if possible would require administrator rights. I was imaging the simplest case of, say, modifying a static int in a C program, which (maybe?) would be assigned to the same memory location, or which could be located in some way. I sort-of imagined that this was how some game bots which look into the game's state might operate. I was not entirely sure if it was possible.Burgher
@JeremyBanks: I found this utility source codeTahr
T
1

Manipulating a process's memory behind its back is a Bad Thing and is fraught with peril. That's why Mac OS X (like any Unix system) has protected memory, and keeps processes isolated from one another.

Of course it can be done: There are facilities for shared memory between processes that explicitly cooperate. There are also ways to manipulate other processes' address spaces as long as the process doing so has explicit right to do so (as granted by the security framework). But that's there for people who are writing debugging tools to use. It's not something that should be a normal — or even rare — occurrence for the vast majority of development on Mac OS X.

Taproot answered 14/8, 2008 at 9:19 Comment(2)
I guess you hear a lot of 'please take a seat...' type jokes, right? :PGemperle
I know this thread is old but, is what you're saying true even if the other process is a child process of one that I spawned? I haven't tried it yet but I hope it'll let me change memory without system protections disabled.Randeerandel
E
1

In general, I would recommend that you use regular open() to open a temporary file. Once it's open in both processes, you can unlink() it from the filesystem and you'll be set up much like you would be if you'd used shm_open. The procedure is extremely similar to the one specified by Scott Marcy for shm_open.

The disadvantage to this approach is that if the process that will be doing the unlink() crashes, you end up with an unused file and no process has the responsibility of cleaning it up. This disadvantage is shared with shm_open, because if nothing shm_unlinks a given name, the name remains in the shared memory space, available to be shm_opened by future processes.

Errolerroll answered 19/1, 2010 at 16:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.