出于安全原因,并非计算机中的所有进程都共享相同的memory space。当我谈论不同的内存空间时,我的意思是什么?考虑以下 2 个程序:
//program 1
int main(int argc, char** argv){
printf("%02x", *((uint8_t*)0xf00fba11));
return 0;
}
//program 2
int main(int argc, char** argv){
printf("%02x", *((uint8_t*)0xf00fba11));
return 0;
}
如果这些程序要同时运行(并假设它们没有段错误(他们几乎肯定会)),它们将打印不同的值。怎么会这样??他们都访问内存位置 0xf00fba11!... 还是他们?
为了了解这里发生了什么,我们首先需要了解当 cpu 从内存中加载一个值时发生了什么。为了从内存中加载一个值,cpu 向 RAM 发送一个请求,如下所示:
cpu
|-------------| |---------|
| read |-------address out to RAM (0xf00fba11)---->| RAM |
| | | |
| *0xf00fba11 |<---------data coming back to CPU----------| |
|-------------| |---------|
在cpu和ram之间有一个特殊的硬件,将地址从“虚拟地址”转换为“物理地址”,它被称为内存管理单元(简称MMU)。如果程序请求地址 0x1000 的值,MMU 可能会“重新映射”0x1000 到 0x8000。如果地址 0x1000 在所有读取和写入到达 RAM 之前总是被 0x8000 替换,这似乎是一个毫无意义的操作。该程序仍然以完全相同的方式运行......那么有什么大不了的?
重要的是现在程序 1 和 2 无法访问彼此的数据。 MMU 可以配置为不存在程序 1 可以读取的包含程序 2 变量之一的地址。这种“映射”对于每个进程(大部分)都是唯一的,并且由操作系统配置。
这是一个 MMU 可能如何影响我们的玩具“f00fba11”示例的示例。
Process 1
cpu
|-------------| |---------|
| read |---0xf00fba11---| MMU |--0x1000ba11------->| RAM |
| | | |
| *0xf00fba11 |<---------data coming back to CPU----------| |
|-------------| |---------|
Process 2
cpu
|-------------| |---------|
| read |---0xf00fba11---| MMU |--0x7000ba11------->| RAM |
| | | |
| *0xf00fba11 |<---------data coming back to CPU----------| |
|-------------| |---------|
进程 1 和进程 2 都请求存储在内存地址 0xf00fba11 的数据,但他们获得了 2 个完全不同的 RAM 单元!这个绝妙的发明被称为“虚拟记忆”。如果 MMU 以不同方式映射它们的内存,我们说 2 个进程具有不同的“地址空间”。操作系统决定这些映射并配置 MMU 以遵守它们,从而使进程彼此“隔离”。考虑 2 个进程和它们可能想要访问的内存地址。
Process 1
asks for | gets physical address
------------------------------------
0x0000 - 0x0fff | ERROR SEGFAULT
0x1000 - 0x1fff | 0x70000 - 0x70fff
0x2000 - 0x2fff | 0x30000 - 0x30fff
0x3000 - 0x3fff | 0xa7000 - 0xa7fff
etc.... | etc.....
Process 2
asks for | gets physical address
------------------------------------
0x0000 - 0x0fff | ERROR SEGFAULT
0x1000 - 0x1fff | 0xb1000 - 0xb1fff
0x2000 - 0x2fff | 0x40000 - 0x40fff
0x3000 - 0x3fff | 0x1c000 - 0x1cfff
etc.... | etc.....
因此,如果在进程 1 中将环境变量加载到内存地址 0x7ffe2a673d84,它可能会转换为物理地址 0x63002a673d84。此外,当进程 2 尝试访问 *0x7ff32a673d84 时,它将被映射到完全不同的地址,或者,在您的情况下,进程 2 可能未映射,导致 SEGFAULT.
所以坏消息是,我认为没有任何方法可以用代码“修复”这个问题。做你想做的事情会给你一个段错误或随机的无用数据。要获取您感兴趣的数据,您需要查看 MMU 配置设置并更改它们,除非您以提升的权限级别运行,否则不允许这样做。
在我们分开之前,值得注意的是,进程之间可能存在一些共享地址,以便在两个进程之间来回传递数据或访问共享软件库。也就是说,对于几个不同的进程,0x1000 将转换为 0x5000。
或者我不知道你在说什么。我并没有真正关注./getenv PATH ./fmt_vuln