Linux下訪問記憶體實體地址

2021-06-05 17:38:01 字數 4323 閱讀 4086

原文

linux核心裡提供的/dev/mem驅動,為我們讀寫記憶體實體地址,提供了乙個渠道。下面講述2種利用mem裝置檔案進行實體地址讀寫的方法,一種是裝置驅動的方法,另一種是系統呼叫的方法。

首先我們看下mem這個裝置檔案,/dev/mem是linux下的乙個字元裝置,原始檔是~/drivers/char/mem.c,這個裝置檔案是專門用來讀寫實體地址用的。裡面的內容是所有物理記憶體的位址以及內容資訊。通常只有root使用者對其有讀寫許可權。

1.裝置驅動的方法

下面是mem.c檔案裡定義的file_operations結構,提供了llseek,read,write,mmap以及open等方法。

static struct file_operations mem_fops =

;

因此我們可以通過一般驅動的使用方法,將記憶體完全當作乙個裝置來對對待。應用程式如下:

#include

#include

int main(void)

read(fd,rdbuf,10);

for(i = 0;i < 10;i++)

lseek(fd,5,0);

write(fd,wrbuf,10);

lseek(fd,0,0);//move f_ops to the front

read(fd,rdbuf,10);

for(i = 0;i < 10;i++)

return 0;

}

執行結果如下:將記憶體最開始10個位元組的內容進行替換。

old mem[0]:b

old mem[1]:u

old mem[2]:t

old mem[3]:t

old mem[4]:e

old mem[5]:r

old mem[6]:f

old mem[7]:l

old mem[8]:y

old mem[9]:!

new mem[0]:b

new mem[1]:u

new mem[2]:t

new mem[3]:t

new mem[4]:e

new mem[5]:b

new mem[6]:u

new mem[7]:t

new mem[8]:t

new mem[9]:e

2.系統呼叫的方法

細心的你可能會發現,既然你前面說了這個檔案裡存放的就是記憶體的位址及內容資訊,那我可不可以直接檢視到呢,答案是:可以的。linux核心的開發者為我們提供了乙個命令hexedit,通過它就可以將/dev/mem的內容顯示出來(如果你使用cat /dev/mem將會看到亂碼),執行hexedit /dev/mem的結果如下:

00000000   62 75 74 74  65 62 75 74  74 65 72 66  6c 79 21 20  butterfly!

00000010   20 20 20 20  20 20 20 20  20 20 20 20  20 20 20 20

00000020   20 20 20 20  20 20 20 20  20 20 20 20  20 20 20 20

00000030   6f ef 00 f0  6f ef 00 f0  57 ef 00 f0  6f ef 00 f0  o...o...w...o...

00000040   02 11 00 c0  4d f8 00 f0  41 f8 00 f0  34 85 00 f0  ....m...a...4...

00000050   39 e7 00 f0  59 f8 00 f0  2e e8 00 f0  d2 ef 00 f0  9...y...........

00000060   a4 e7 00 f0  f2 e6 00 f0  6e fe 00 f0  53 ff 00 f0  ........n...s...

00000070   53 ff 00 f0  a4 f0 00 f0  c7 ef 00 f0  1c 42 00 c0  s............b..

從上圖可見,最左邊顯示的是位址,接下來24列顯示的是各記憶體位元組單元內容的ascii碼資訊,最右邊顯示的是對應的字元資訊。讓人欣慰的是,這個檔案可以直接修改,按下tab鍵進入修改模式,修改過程中修改內容會以粗體顯示,按下f2儲存後粗體消失。上面的butterfly就是通過這種方式修改的。

既然記憶體的位址以及內容資訊全部被儲存在mem這個裝置檔案裡,那麼我們可以想到通過另外一種方式來實現對實體地址的讀寫了。那就是將mem裝置檔案和mmap系統呼叫結合起來使用,將檔案裡的物理記憶體位址對映到程序的位址空間,從而實現對記憶體實體地址的讀寫。下面談一下mmap系統呼叫。

mmap的函式原型為:void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offset),該函式定義在/usr/include/sys/mman.h中,使用時要包含:#include,mmap()用來將某個檔案中的內容對映到程序的位址空間,對該空間的訪問即是對該檔案內容的讀寫。引數說明如下:

start:指向欲對映到的位址空間的起始位址,通常設為null或者0.表示讓系統融自動選定位址,對映成功後該位址會返回。

length:表示對映的檔案內容的大小,以位元組為單位。

prot:表示對映區域的保護方式,有如下四種組合:

--prot_exec 對映區域可執行 ,

--prot_read 對映區域可讀 ,

--prot_write 對映區域可寫,

--prot_none 對映區域不能被訪問

flags:對映區域的一些特性,主要有:

--map_fixed 如果對映不成功則出錯返回,

--map_shared 對對映區域的寫入資料會寫回到原來的檔案

--map_private 對對映區域的寫入資料不會寫回原來的檔案

--map_anonymous

--map_denywrite 只允許對對映區域的寫入操作,其他對檔案直接寫入的操作將被拒絕

--map_locked 鎖定對映區域

在呼叫mmap()時,必須要指定map_shared或map_private。

fd:open()返回的檔案描述符。

offset:為被對映檔案的偏移量,表示從檔案的哪個地方開始對映,一般設定為0,表示從檔案的最開始位置開始對映。offset必須是分頁大小(4096位元組)的整數倍。

應用程式如下:

#include

#include

#include //mmap head file

int main (void)

//map physical memory 0-10 bytes

start = (char *)mmap(0, 10, prot_read | prot_write, map_shared, fd, 0);

if(start < 0)

//read old value

for (i = 0; i < 10; i++)

//write memory

memcpy(start, buf, 10);

//read new value

for (i = 0;i < 10;i++)

munmap(start, 10); //destroy map memory

close(fd);  //close file

return 0;

}

程式執行結果如下:

old mem[0]:b

old mem[1]:u

old mem[2]:t

old mem[3]:t

old mem[4]:e

old mem[5]:b

old mem[6]:u

old mem[7]:t

old mem[8]:t

old mem[9]:e

new mem[0]:b

new mem[1]:u

new mem[2]:t

new mem[3]:t

new mem[4]:e

new mem[5]:r

new mem[6]:f

new mem[7]:l

new mem[8]:y

new mem[9]:!

「/dev/mem是個很好玩的東西,你竟然可以直接訪問物理記憶體。這在linux下簡直是太神奇了,這種感覺象乙個小偷打算偷乙個銀行,可是這個銀行戒備森嚴,正當這個小偷苦無對策時,突然發現在乙個不起眼的地方有個後門,這個後門可以直接到銀行的金庫。」

Linux下訪問記憶體實體地址

linux核心裡提供的 dev mem驅動,為我們讀寫記憶體實體地址,提供了乙個渠道。下面講述2種利用mem裝置檔案進行實體地址讀寫的方法,一種是裝置驅動的方法,另一種是系統呼叫的方法。首先我們看下mem這個裝置檔案,dev mem是linux下的乙個字元裝置,原始檔是 drivers char m...

記憶體實體地址

cpu訪問記憶體時要給出記憶體單元的位址 記憶體位址 每個記憶體單元都有乙個唯一的位址,稱之為實體地址。首先給出乙個公式 實體地址 段位址x16 偏移位址 實體地址指的是cpu訪問記憶體資料的記憶體位址,段位址指的是8086cpu的16位的位址匯流排,偏移位址也指的是16位的位址匯流排。什麼是段位址...

Linux 下面對實體地址的訪問

linux核心提供了 dev mem驅動,提供了一種直接訪問記憶體實體地址的方法,具體實施有兩種方法,一是裝置驅動,二是系統呼叫的方法。dev mem驅動的原始檔在drivers char mem.c中。這個檔案還生成了一些常用的字元裝置驅動,表現為 dev zero,dev null等一些特殊的字...