我要买一台新电脑,所以我和一个朋友决定用电脑的内存玩俄罗斯轮盘赌。一般的前提是,我们随机地在内存中取一个位置,并将其分配给一个随机值,看看谁的计算机故障/崩溃最快或最严重。我所做的一切都不是一个好主意,所以这里接受甚至鼓励不安全的做法。
这就是我目前所拥有的:
#include <iostream>
#include <stdlib.h>
#include <time.h>
// use preprocessor to avoid losing this data during the running of the program
// 4GB RAM (4 * 2^32 bytes)
#define NUM_MEMORY_LOCATIONS 4294967296
int main()
{
// Intializes random number generator
time_t t;
srand((unsigned) time(&t));
while (true)
{
// 4GB RAM (2^32 bytes)
/** generate a 31-bit number between 0b0 (0) and 0b111 1111 1111 1111 1111 1111 1111 1111 (4294967295) **/
// generate a 15-bit number between 0b0 (0) and 0b111 1111 1111 1111 (32767)
unsigned long int hi = rand() % 32768;
// shift the bits
hi <<= 16;
// generate a 15-bit number between 0b0 (0) and 0b111 1111 1111 1111 (32767)
unsigned long int med = rand() % 32768;
// shift the bits
med <<= 1;
// generate a 1-bit number between 0b0 (0) and 0b1 (1)
unsigned long int lo = rand() % 2;
// combine to make final random number
unsigned long int randNum = hi + med + lo;
// select a random position in memory
void * randomPointer = 0;
randomPointer += randNum;
// Something like this here to break my computer:
//*randomPointer = 0;
}
}
我不知道如何设置这个值,甚至只设置为0。此外,我不确定应该使用什么指针类型。void指针似乎不起作用,但我可能只是不完全理解c++中不安全内存管理的复杂性。
有人知道我是怎么做到的吗?如有任何帮助,我们将不胜感激。
您的代码无法做到这一点:在x86-64系统上,您将对每个不属于可执行地址空间的地址进行访问。
操作系统负责决定哪些地址属于给定的进程(它们经过MMU转换过程,最终决定地址是否属于该进程),如果不属于,则会通知处理器,根据操作系统,您可能会遇到访问违规或分段故障。
在linux系统上,你通常会编辑另一个进程的内存,比如ptrace来调试另一个过程。另一种可能性是编辑/dev/mem。对于这两种情况,您都需要root访问权限。
相反,在Windows系统上,您可以使用ReadProcessMemory和WriteProcessMemory,或者直接将代码注入您生成地址的目标(CreateRemoteThread)。
无论如何,请记住当前代码无法实现这一目标的主要原因:现代操作系统在分页环境中运行应用程序,即它们提供了一个虚拟地址空间,不一定(通常也不)映射到物理地址因此,您试图做的是错误的,因为这些地址不会映射到物理位置。如果你真的想走这条路,你必须禁用或绕过分段机制、ring3/0保护、寻呼、涉及MMU的翻译,并可能处理大量其他关于保留地址和MMIO注册间隔的问题。
所有现代桌面操作系统都使用虚拟进程地址空间。这意味着您的进程看到4GB的内存(在32位操作系统上;在64位系统上更多),这些内存都属于自己,而看不到其他进程或操作系统内核拥有的内存。虚拟地址空间如何映射到物理内存和交换空间取决于操作系统,并随着内存的交换而变化。
因此,你可以从你的实验中得到的最糟糕的结果就是破坏你编写的程序。要做其他任何事情,您需要在内核空间中。
由于虚拟内存机制,您尝试执行的操作与尝试执行的方式不同。操作系统的虚拟内存管理器(VMM)会将进程中的内存地址映射到实际的物理内存位置。如果您试图读取或写入VMM尚未分配给您的进程的地址,您只会使自己的进程崩溃(Windows上的访问冲突、Linux上的分段故障等)
在Linux上,如果您的进程具有root权限,则可以通过不同的方式实现这一点;只需将/dev/mem
节点作为文件打开,并查找到一个随机位置,然后写入随机值或零值。(实际上,这与您在代码中所做的相同,只是使用文件I/O操作——查找和写入——而不是取消引用指针。)
对于指针,只需使用"int*"。
话虽如此,程序试图访问的内存只是它自己的内存。为了访问所有计算机的RAM(甚至不是所有的虚拟内存),需要一些特定于O/s的技巧以及管理权限才能访问程序本身之外的内存。
在Windows95之后,所有较大的操作系统都使用了内置在CPU中的安全功能。在x86系列中,这被称为"保护模式"。有几种不同的技术,但使用最广泛的一种是"分页"。
分页意味着将内存空间拆分为页面(通常为4k),其中有一个子集用于代码,另一个子集则用于数据等。如果你试图在允许的数据页面集之外写入任何内容,你会导致一个异常(称为"陷阱"),该异常将被操作系统拦截。95后的生活更加无聊。
分页的一个优点是所谓的"交换"。这意味着操作系统可以通过在磁盘上放置页面来卸载RAM,然后在读取/写入页面时拦截页面并将其召回RAM。