2014-09-01 92 views
5

我得到一臺新電腦,所以一個朋友和我決定我們想用我們電腦的內存玩俄羅斯輪盤賭。總的前提是我們隨機在內存中佔據一個位置,並將其分配給一個隨機值,並查看哪個計算機發生故障/崩潰最快或最差。我所做的一切都不是想成爲一個好主意,所以不安全的做法被接受,甚至在此鼓勵。如何編輯隨機存儲器?

這是我到目前爲止有:

#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++中不安全內存管理的複雜性。

有誰知道我該怎麼做?任何幫助,將不勝感激。

+11

操作系統不會讓您的程序訪問未分配給您的程序的內存 – 2014-09-01 06:08:19

+3

這不是現代操作系統或現代計算機體系結構在「正常」情況下的工作方式。閱讀[虛擬內存](https://en.wikipedia.org/wiki/Virtual_memory),瞭解爲什麼隨機嘗試翻轉某些隨機內存位置中的某些位不會導致其他程序出現故障。基本上,每個正在運行的程序都有自己的地址空間,所以一個程序的指針值不一定指向另一個程序的內存。由於操作系統對進程的內存使用情況保持非常接近的選項卡,因此最終所做的幾乎肯定會使自己的進程崩潰。 – 2014-09-01 06:10:02

+0

答案取決於你的操作系統。 Linux上的root用戶可以通過'/ dev/mem'訪問隨機存儲位置,而Windows有一些特權的API調用,它們會給你類似的訪問權限。 – cdhowie 2014-09-01 06:10:28

回答

5

你不能用你的代碼做到這一點:在x86-64系統上,你會得到一個訪問衝突,每個地址都與你的可執行地址空間無關。

操作系統負責決定哪些地址屬於給定的進程(它們經歷最終決定該地址是否與進程有關的MMU轉換過程),以防它通知處理器並且根據操作系統,您可能會遇到訪問衝突或分段錯誤。

在linux系統上,您通常會編輯另一個進程的內存,如ptrace來調試另一個進程。另一種可能性是編輯/dev/mem。對於這兩者你都需要root權限。

在Windows系統上,而不是你可以使用ReadProcessMemoryWriteProcessMemory的或直接注入代碼爲您生成(CreateRemoteThread的),其地址的目標。

反正記住最主要的原因,你不能用你當前的代碼完成它:現代操作系統在分頁環境中運行你的應用程序,即它們提供一定的(通常唐虛擬地址空間't)映射到物理地址。 你要做的是錯誤的,因爲這些地址不會映射到物理位置。如果你真的想這樣做,你將不得不禁用或繞過分割機制,ring3/0保護,分頁,涉及MMU的翻譯,並可能處理大量有關保留地址和MMIO註冊時間間隔的其他問題。

+0

這不完全正確;這很難做到,但這是可能的。即使只是寫一個設備驅動程序來獲得必要的訪問權限。 – ash 2014-09-01 06:12:40

+0

隨着OP的代碼,它是不可能的,完全不可靠 – 2014-09-01 06:13:10

+1

「你不能這樣做」,你的意思是歐普不能用C++代碼做到這一點嗎?也許我誤解了你的回答。 – ash 2014-09-01 06:15:44

1

對於指針,只需使用「int *」即可。

這樣說,程序試圖訪問的內存只是它自己的內存。爲了訪問所有的計算機RAM(甚至不是所有的虛擬內存),它需要一些特定於操作系統的技巧以及管理權限來訪問程序本身以外的內存。

2

由於虛擬內存機制,你試圖做的事情不可能像你試圖做的那樣。您的進程中的內存地址是,由操作系統的虛擬內存管理器(VMM)將映射到實際的物理內存位置。如果您嘗試讀取或寫入VMM未分配給您的進程的地址,則只會導致您自己的進程崩潰(Windows上的訪問衝突,Linux上的分段錯誤等)。

在Linux上,如果您的進程具有root權限,您可以以不同的方式完成此操作;只需打開/dev/mem節點作爲文件並尋找一個隨機位置,然後寫入隨機值或零值。 (實際上,您在代碼中執行的操作與使用文件I/O操作時相同 - 查找和寫入操作 - 而不是取消引用指針)。

4

所有現代桌面操作系統都使用虛擬進程地址空間。這意味着你的進程看到4GB內存(在32位操作系統上;更多在64位系統上),它擁有所有內存本身,並且看不到其他進程或操作系統內核擁有的內存。虛擬地址空間如何映射到物理內存和交換空間取決於操作系統,並隨着內存交換進入和退出而隨着時間而改變。

因此,從實驗中可以預料到的最糟糕的情況是崩潰您編寫的程序。要做其他事情,你需要進入內核空間。

+0

在內核模式下,更準確地 – sehe 2014-09-01 07:35:03

+0

注意區分內核模式/用戶模式與內核空間/用戶空間嗎? – Tom 2014-09-01 07:43:58

+0

空間是指內存尋址空間。 _mode_是處理器所處的實際模式(與地址映射存在更多差異的具體不同模式) – sehe 2014-09-01 07:50:56

0

那麼,在Windows 95之後,所有更大的操作系統都使用了內置於CPU中的安全功能。在x86系列上,這被稱爲「保護模式」。有幾種不同的技術,但最廣泛使用的技術使用「分頁」。

尋呼意味着在頁面分割內存空間(4K通常情況下),在那裏你有代碼的一個子集,另一個用於數據等,如果你嘗試寫你允許的一組數據頁的​​東西之外,你會導致一個異常(稱爲「陷阱」),這將被操作系統攔截。 95後的生活更無聊了。

尋呼的一個優點是所謂的「交換」。這意味着操作系統可以通過將頁面放置在磁盤上來卸載RAM,然後在讀取/寫入它們時攔截並將其重新調用到RAM中。