2009-06-07 88 views
6

對於我的學士論文,我希望可視化內存的數據剩餘量以及在重新引導系統後它如何持續存在。如何使用C獲取特定的內存地址C

我有一個簡單的想法將一張照片mmap到內存,關閉我的電腦,等待x秒鐘,啓動電腦,看看照片是否仍然存在。

 
int mmap_lena(void) 
{ 
    FILE *fd = NULL; 
    size_t lena_size; 
    void *addr = NULL; 

    fd = fopen("lena.png", "r"); 

    fseek(fd, 0, SEEK_END); 
    lena_size = ftell(fd); 

    addr = mmap((void *) 0x12345678, (size_t) lena_size, (int) PROT_READ, (int) MAP_SHARED, (int) fileno(fd), (off_t) 0); 
    fprintf(stdout, "Addr = %p\n", addr); 
    munmap((void *) addr, (size_t) lena_size); 
    fclose(fd); 
    fclose(fd_log); 
    return EXIT_SUCCESS; 
} 

我忽略了檢查返回值的緣故。

所以在mmap後,我試圖以某種方式獲取地址,但通常最終會出現分段錯誤,因爲我瞭解內存受操作系統保護。

 
int fetch_lena(void) 
{ 
    FILE *fd = NULL; 
    FILE *fd_out = NULL; 
    size_t lenna_size; 
    FILE *addr = (FILE *) 0x12346000; 

    fd = fopen("lena.png", "r"); 
    fd_out = fopen("lena_out.png", "rw"); 

    fseek(fd, 0, SEEK_END); 
    lenna_size = ftell(fd); 

    // Segfault 
    fwrite((FILE *) addr, (size_t) 1, (size_t) lenna_size, (FILE *) fd_out); 

    fclose(fd); 
    fclose(fd_out); 

    return 0; 

} 

還請注意,我硬編碼的不會忽略在這個例子中,所以只要您運行mmap_lena我在fetch_lena使用該值可以作爲操作系統採用的第一個參數只是針對mmap作爲一個提示是錯誤的(上我的系統總是默認爲0x12346000)。

如果有任何微不足道的編碼錯誤,我很抱歉,因爲我的C技能還沒有完全開發。

我想現在如果有任何方法可以獲得我想要的數據而不實現任何malloc掛鉤或內存分配器黑客。

由於提前, 大衛你有

+2

首先,一個標準的Linux進程無法訪問原始(物理)內存,因此您可以輕鬆地從進程中查看給定的物理內存地址(查看MMU,虛擬內存)。此外,Linux內核在將內存交給進程之前將內存清零(如在memset 0中)。 – ysdx 2015-09-30 11:14:05

回答

18

的一個問題是,你取回一個虛擬地址,不要在那裏駐留內存的物理地址。下次啓動時,映射可能不會相同。

這可以definitly在Linux的內核模塊中完成,但我不認爲這是在用戶空間中任何類型的API,你可以使用。

如果您有權限(我假設你可能是這臺機器,如果你重新啓動它的根),那麼你就可以從/ dev/MEM偷看看到實際phyiscal佈局。也許你應該嘗試抽樣值,重新啓動,並看看有多少這些值持續存在。

+0

謝謝,我不記得虛擬內存映射也是一個問題。 我在某種程度上不確定如何使用/ dev/mem來獲取我想要的信息,所以我想我將不得不編寫一個內核模塊。 – tr9sh 2009-06-07 17:24:45

+1

也許嘗試mmap/dev/mem然後尋找你想要查看的位置? – 2009-06-07 17:37:30

+4

我會同意克里斯:你將需要使用某種操作系統(或者根本不需要操作系統),它可以直接訪問內存。如果您重新啓動到Linux或其他具有受保護虛擬內存的操作系統,則無法保證您可以訪問相同的內存頁面。如果你想要一些易於使用的東西,那麼重新引導到舊版本的DOS中怎麼樣? – 2009-06-07 18:16:14

10

有一個similar project顯示冷啓動攻擊。 source code可用,也許你可以在那裏得到一些啓發。

然而,AFAIR他們讀出存儲器中,而第一,因此加載操作系統不必與操作系統內存保護一塌糊塗。也許你也應該嘗試這樣做,以避免啓動後內存被操作系統覆蓋或清除。

(同時檢查網站上的視頻,這是非常令人印象深刻;)

1

我不熟悉Linux,但你可能需要寫一個設備驅動程序。出於DMA目的,設備驅動程序必須有一些方法將虛擬內存地址轉換爲物理內存地址(DMA控制器僅處理物理內存地址)。您應該能夠使用這些接口直接處理物理內存。

2

測試代碼看起來很奇怪

FILE * ADDR =(FILE *)0x12346000; ((FILE *)fd_out,(size_t)1, (size_t)lenna_size,(FILE *)addr);

你不能只是將一個整數轉換爲一個FILE指針,並期望得到一個健全的東西。 您是否也將第一個和最後一個參數切換到fwrite?最後一個參數應該是要寫入的FILE *。

4

Direct Memory Access in Linux的問題中,我們找出了實現這一目標所需的大部分基本原理。請注意,mmap()並不是其他人所說的原因。你需要一個真正的地址,而不是虛擬的,你只能在內核中獲得地址(或者通過編寫一個驅動程序將一個地址傳遞給用戶空間)。

最簡單的方法是編寫一個可以讀取或寫入的字符設備驅動程序,使用ioctl爲您提供有效的開始或結束地址。同樣,如果你想讓內存管理函數的指針在內核中使用,請參閱我已經鏈接到的問題。大部分內容是在第一個(並且被接受的)答案的評論中得出的。

2

您可能希望儘可能少的操作系統爲此目的;您加載的軟件越多,覆蓋您想要檢查的內容的機會就越多。

DOS可能是一個不錯的選擇;它使用< 640k的內存。如果你不加載HIMEM,而是編寫你自己的(需要程序集)例程來跳轉到pmode,將一塊高內存複製到低內存中,然後跳回到實模式,你可以編寫一個主要是實模式的程序,可以轉儲出物理內存(不包括BIOS,DOS和您的應用程序)。它可以將其轉儲到閃存盤或其他東西。

當然,真正的問題可能是BIOS在POST期間清除內存。