macos 在 OS X 中读取其他进程的内存?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10668/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 05:52:32  来源:igfitidea点击:

Reading Other Process' Memory in OS X?

cmacosmemoryptrace

提问by Facebook Staff are Complicit

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 ptracewith PEEKDATAand such, however it doesn't have that option on BSD [man ptrace].

我一直试图了解如何在 Mac OS X 上读取其他进程的内存,但我运气不佳。我在网上看到了很多使用ptracewithPEEKDATA等的例子,但是它在 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?

如何在 Mac OS X 上读取和写入另一个进程的内存?

回答by Trance Diviner

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.

使用task_for_pid()或其他方法获取目标进程的任务端口。此后,您可以使用vm_read()vm_write()等直接操作进程的地址空间。

回答by Derek Park

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).

Matasano Chargen 不久前发表了一篇关于将一些调试代码移植到 OS X 的好文章,其中包括学习如何在另一个进程中读写内存(除其他外)。

It has to work, otherwise GDB wouldn't:

它必须工作,否则 GDB 不会

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_SETFPREGSin 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.

事实证明,苹果以其无限的智慧,已经内脏了ptrace()。OS X 手册页列出了以下请求代码:

  • PT_ATTACH— 选择要调试的进程
  • PT_DENY_ATTACH— 因此进程可以阻止自己被调试
    [...]

没有提到读取或写入内存或寄存器。假若该名男子页面没有还提到已经劝阻PT_GETREGSPT_SETREGSPT_GETFPREGS,和PT_SETFPREGS在错误代码部分。所以,我检查了ptrace.h. 在那里我发现:

  • PT_READ_I— 阅读说明词
  • PT_READ_D— 读取数据字
  • PT_READ_U— 如果您年纪大到可以记住 U 区是什么,则可以读取 U 区数据
    [...]

有一个问题解决了。我可以读取和写入断点的内存。但是我仍然无法访问寄存器,并且我需要能够弄乱 EIP。

回答by Jona

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

我知道这个帖子已经有 100 年的历史了,但是对于从搜索引擎来到这里的人来说:

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

xnumem完全符合您的要求,操作和读取进程间内存。

// 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();

回答by Scott Marcy

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.

如果您希望能够在进程之间共享内存块,您应该查看 shm_open(2) 和 mmap(2)。在一个进程中分配一块内存并将路径(对于 shm_open)传递给另一个进程非常容易,然后两者都可以一起发疯。这比 Chris Hanson 提到的在另一个进程的地址空间中闲逛要安全得多。当然,如果您无法控制这两个过程,这对您没有多大好处。

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

(请注意 shm_open 的最大路径长度似乎是 26 字节,尽管这似乎没有记录在任何地方。)

// 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()

回答by user2284570

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 bookwhich 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.

我很快就在本书中找到了您需要的东西,其中包含当今所有 UNIX 通用的所有 API(比我想象的要多得多)。你应该在未来购买它。这本书是一套(数百)印刷的手册页,很少安装在现代机器上。每个手册页都详细介绍了一个 C 函数。

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

我很快就找到了shmat() shmctl()shmdt()shmget()在其中。我没有广泛搜索,也许还有更多。

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

它看起来有点过时,但是:是的,现代 UNIX 操作系统的基本用户空间 API 可以追溯到 80 年代。

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.

更新:本书中描述的大多数函数都是 POSIX C 头文件的一部分,你不需要安装任何东西。很少有例外,例如原始库“curses”。

回答by user2284570

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

我确实找到了您需要的简短实现(只有一个源文件 (main.c))。它是专为 XNU 设计的。

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

它是在谷歌搜索的前十名与以下关键词的结果?转储进程内存 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)

但是从严格的虚拟地址空间点 de vue 来看,您应该对这个问题更感兴趣:OS X:在不关闭进程的情况下生成核心转储?(也看看这个

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

当您查看 gcore 源代码时,执行此操作非常复杂,因为您需要处理踏板及其状态...

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.

在大多数 Linux 发行版中,gcore 程序现在是 GDB 包的一部分。我认为 OSX 版本是随 xcode/开发工具一起安装的。

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.

更新:wxHexEditor 是一个可以编辑设备的编辑器。它也可以像编辑常规文件一样编辑进程内存。它适用于所有 UNIX 机器。

回答by fixermark

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.

通常,我建议您使用常规 open() 打开临时文件。一旦它在两个进程中打开,您就可以从文件系统 unlink() 它,并且您将像使用 shm_open 一样进行设置。该过程与 Scott Marcy 为 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.

这种方法的缺点是,如果执行 unlink() 的进程崩溃,您最终会得到一个未使用的文件,并且没有进程负责清理它。这个缺点与 shm_open 共享,因为如果没有 shm_unlink 一个给定的名称,该名称将保留在共享内存空间中,可供以后的进程 shm_opened 使用。

回答by Chris Hanson

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.

在背后操纵进程的内存是一件坏事,而且充满危险。这就是 Mac OS X(像任何 Unix 系统一样)保护内存并使进程彼此隔离的原因。

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.

当然可以做到:在明确合作的进程之间有共享内存的设施。还有一些方法可以操作其他进程的地址空间,只要这样做的进程有明确的权限(由安全框架授予)。但这对于编写调试工具的人来说是有用的。对于 Mac OS X 上的绝大多数开发来说,这不应该是正常的——甚至是罕见的——发生。