如果您知道地址,您可以访问另一个程序的 stack/heap 吗?
Can you access another program's stack/heap if you know the address?
只是一个杂项问题。
我有一个 C++ 程序:
#include <stdio.h>
int main()
{
while (1) {
int value1 = 1;
printf("%p\n", (void *)&value1);
void* address = (void *)&value1;
int value2 = *(int*)address;
printf("%d\n",value2);
}
return 0;
}
这样做是获取value1的地址,存入address,然后获取address中的变量,存入value2。
这工作得很好,但是,我想从另一个 C++ 程序访问变量。我已经试过了(这个文件中有两种方法):
#include<iostream>
#include <cstdint>
int main() {
std::cout << "before seg fault" << std::flush;
uintptr_t p = <address>;
int value = *reinterpret_cast<int *>(p);
int value2 = *(int*)<address>;
std::cout << "after seg fault"<< std::flush;
std::cout << value;
return 0;
}
这会在尝试访问该值时导致分段错误,这可能是因为 OS 不希望我访问该值或者因为它在该实例中不存在。
无论这看起来多么不切实际和愚蠢,有没有办法克服这个问题?或者这是不可能的?作为旁注,我为什么应该/为什么不应该这样做?
编辑:我同意 Chris 的回答,因为当您 运行 在 linux 上使用 root 时它工作得很好。要求也适用于 Mac 和 Windows 的东西会不会太过分了?我已经尝试 运行 在 Mac 系统上运行 poke 程序,但它给出了错误:无法访问 pid 26112:: 没有这样的文件或目录,由行调用:
fprintf(stderr, "usage: %s pid address value\n", av[0]);
This causes a segmentation fault when trying to access the value, which is probably because the OS doesn't want me accessing this value or because it doesn't exist in this instance.
后者。一个进程的虚拟内存地址对另一个进程没有意义。除非试图读取任意地址的进程偶然在同一个虚拟地址中分配了内存,否则操作系统会注意到它正在做无意义的事情,并终止它以防止进程做可能有不好的无意义的事情后果。
Can you access another program's stack/heap if you know the address?
在 C++ 中没有执行此操作的标准方法。该语言缺少多进程的概念。
进程通信的一种合作方式是使用共享内存。在 C++ 中没有分配共享内存的标准方法。
在没有合作的情况下读取另一个进程的内存也是可能的,尽管操作系统通常出于明显的原因默认阻止普通用户这样做 - 除非进程属于同一组。在 C++ 中也没有执行此操作的标准方法。
Why should / why shouldn't I do this?
协作共享内存对于进程间通信很有用。请注意,还有其他替代方案,例如管道和套接字(但 none 的替代方案是在标准 C++ 中)。
另一个进程的非合作读取在用户 space 程序中很少有用。我认为执行此操作的调试器是此类罕见用例之一。
每个进程都有自己的地址 space,程序中的地址引用该地址 space,独立于任何其他地址 space 中的地址。因此,当您将一个显式值放入这样的指针并使用它时,您将获得该进程中该地址的任何内容(这可能是无效的,因此您会收到 SEGFAULT 或类似错误),而不是访问其他进程.
在大多数操作系统上,可以通过权限访问另一个进程的地址 space。例如,在 Linux 上,这个 poke
程序可以修改另一个进程的地址 space:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int main(int ac, char **av) {
char name[64];
int fd;
if (ac != 4) {
fprintf(stderr, "usage: %s pid address value\n", av[0]);
exit(1); }
sprintf(name, "/proc/%.10s/mem", av[1]);
if ((fd = open(name, O_WRONLY)) < 0) {
fprintf(stderr, "Can't access pid %s", av[1]);
perror(":");
exit(1); }
lseek(fd, strtol(av[2], 0, 0), SEEK_SET);
if (write(fd, av[3], strlen(av[3]) + 1) < 0)
perror("write");
return 0;
}
如果你 运行 这个程序:
#include <stdio.h>
#include <unistd.h>
int main() {
char data[16] = "test";
while (1) {
printf("pid = %d, &data = %p, data = %s\n", getpid(), &data, data);
sleep(2);
}
}
它将打印如下所示的行:
pid = 6376, &data = 0x7ffe255f3190, data = test
pid = 6376, &data = 0x7ffe255f3190, data = test
如果你在另一个window/terminal运行./poke 6376 0x7ffe255f3190 Hello
,它会变成
pid = 6376, &data = 0x7ffe255f3190, data = Hello
pid = 6376, &data = 0x7ffe255f3190, data = Hello
This causes a segmentation fault when trying to access the value, which is probably because the OS doesn't want me accessing this value or because it doesn't exist in this instance.
两者兼而有之:它不存在于您进程的地址中 space 因为 OS 不希望您访问其他进程的内存, 因此指示内存硬件不要将其映射到您的进程地址 space.
在一些旧的单用户操作系统中,您可以访问所有内存,因为没有进程隔离、用户或虚拟内存硬件的真正概念强制执行任何分离。
不再这样做的原因是它确实 扩展性很差。一旦你有一些后台任务,如果没有定期安排它们(或者如果它们让出处理器花费太长时间),事情就会开始中断。一旦你有了几个进程,如果它们不小心破坏了彼此的内存,事情就会开始崩溃。
所以现在我们有独立的进程,它们只能通过相互协议进行通信(例如通过映射一些共享内存),但是不能践踏彼此的变量。
However unpractical and stupid this may seem, is there a way to overcome this? Or is it impossible? As a side note, Why should / why shouldn't I do this?
出于与 OS 阻止您的相同原因,您不应该这样做(也就是说,正是您所要求的):它会导致无法诊断的错误和随机部分的安全漏洞你的系统。
如果要在进程之间共享内存,可以使用共享内存。它非常特定于平台,因此您需要查找特定平台的 API,或使用 Boost.Interprocess.
但是请注意,在使用它的每个进程中,相同的内存可能会映射到不同的地址,因此您不能在其中有用地存储指针(但偏移量是可以的),并且实现诸如共享内存中基于节点的容器(但 Boost.Interprocess 有一些你可以使用)。
只是一个杂项问题。 我有一个 C++ 程序:
#include <stdio.h>
int main()
{
while (1) {
int value1 = 1;
printf("%p\n", (void *)&value1);
void* address = (void *)&value1;
int value2 = *(int*)address;
printf("%d\n",value2);
}
return 0;
}
这样做是获取value1的地址,存入address,然后获取address中的变量,存入value2。 这工作得很好,但是,我想从另一个 C++ 程序访问变量。我已经试过了(这个文件中有两种方法):
#include<iostream>
#include <cstdint>
int main() {
std::cout << "before seg fault" << std::flush;
uintptr_t p = <address>;
int value = *reinterpret_cast<int *>(p);
int value2 = *(int*)<address>;
std::cout << "after seg fault"<< std::flush;
std::cout << value;
return 0;
}
这会在尝试访问该值时导致分段错误,这可能是因为 OS 不希望我访问该值或者因为它在该实例中不存在。
无论这看起来多么不切实际和愚蠢,有没有办法克服这个问题?或者这是不可能的?作为旁注,我为什么应该/为什么不应该这样做?
编辑:我同意 Chris 的回答,因为当您 运行 在 linux 上使用 root 时它工作得很好。要求也适用于 Mac 和 Windows 的东西会不会太过分了?我已经尝试 运行 在 Mac 系统上运行 poke 程序,但它给出了错误:无法访问 pid 26112:: 没有这样的文件或目录,由行调用:
fprintf(stderr, "usage: %s pid address value\n", av[0]);
This causes a segmentation fault when trying to access the value, which is probably because the OS doesn't want me accessing this value or because it doesn't exist in this instance.
后者。一个进程的虚拟内存地址对另一个进程没有意义。除非试图读取任意地址的进程偶然在同一个虚拟地址中分配了内存,否则操作系统会注意到它正在做无意义的事情,并终止它以防止进程做可能有不好的无意义的事情后果。
Can you access another program's stack/heap if you know the address?
在 C++ 中没有执行此操作的标准方法。该语言缺少多进程的概念。
进程通信的一种合作方式是使用共享内存。在 C++ 中没有分配共享内存的标准方法。
在没有合作的情况下读取另一个进程的内存也是可能的,尽管操作系统通常出于明显的原因默认阻止普通用户这样做 - 除非进程属于同一组。在 C++ 中也没有执行此操作的标准方法。
Why should / why shouldn't I do this?
协作共享内存对于进程间通信很有用。请注意,还有其他替代方案,例如管道和套接字(但 none 的替代方案是在标准 C++ 中)。
另一个进程的非合作读取在用户 space 程序中很少有用。我认为执行此操作的调试器是此类罕见用例之一。
每个进程都有自己的地址 space,程序中的地址引用该地址 space,独立于任何其他地址 space 中的地址。因此,当您将一个显式值放入这样的指针并使用它时,您将获得该进程中该地址的任何内容(这可能是无效的,因此您会收到 SEGFAULT 或类似错误),而不是访问其他进程.
在大多数操作系统上,可以通过权限访问另一个进程的地址 space。例如,在 Linux 上,这个 poke
程序可以修改另一个进程的地址 space:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int main(int ac, char **av) {
char name[64];
int fd;
if (ac != 4) {
fprintf(stderr, "usage: %s pid address value\n", av[0]);
exit(1); }
sprintf(name, "/proc/%.10s/mem", av[1]);
if ((fd = open(name, O_WRONLY)) < 0) {
fprintf(stderr, "Can't access pid %s", av[1]);
perror(":");
exit(1); }
lseek(fd, strtol(av[2], 0, 0), SEEK_SET);
if (write(fd, av[3], strlen(av[3]) + 1) < 0)
perror("write");
return 0;
}
如果你 运行 这个程序:
#include <stdio.h>
#include <unistd.h>
int main() {
char data[16] = "test";
while (1) {
printf("pid = %d, &data = %p, data = %s\n", getpid(), &data, data);
sleep(2);
}
}
它将打印如下所示的行:
pid = 6376, &data = 0x7ffe255f3190, data = test
pid = 6376, &data = 0x7ffe255f3190, data = test
如果你在另一个window/terminal运行./poke 6376 0x7ffe255f3190 Hello
,它会变成
pid = 6376, &data = 0x7ffe255f3190, data = Hello
pid = 6376, &data = 0x7ffe255f3190, data = Hello
This causes a segmentation fault when trying to access the value, which is probably because the OS doesn't want me accessing this value or because it doesn't exist in this instance.
两者兼而有之:它不存在于您进程的地址中 space 因为 OS 不希望您访问其他进程的内存, 因此指示内存硬件不要将其映射到您的进程地址 space.
在一些旧的单用户操作系统中,您可以访问所有内存,因为没有进程隔离、用户或虚拟内存硬件的真正概念强制执行任何分离。
不再这样做的原因是它确实 扩展性很差。一旦你有一些后台任务,如果没有定期安排它们(或者如果它们让出处理器花费太长时间),事情就会开始中断。一旦你有了几个进程,如果它们不小心破坏了彼此的内存,事情就会开始崩溃。
所以现在我们有独立的进程,它们只能通过相互协议进行通信(例如通过映射一些共享内存),但是不能践踏彼此的变量。
However unpractical and stupid this may seem, is there a way to overcome this? Or is it impossible? As a side note, Why should / why shouldn't I do this?
出于与 OS 阻止您的相同原因,您不应该这样做(也就是说,正是您所要求的):它会导致无法诊断的错误和随机部分的安全漏洞你的系统。
如果要在进程之间共享内存,可以使用共享内存。它非常特定于平台,因此您需要查找特定平台的 API,或使用 Boost.Interprocess.
但是请注意,在使用它的每个进程中,相同的内存可能会映射到不同的地址,因此您不能在其中有用地存储指针(但偏移量是可以的),并且实现诸如共享内存中基于节点的容器(但 Boost.Interprocess 有一些你可以使用)。