天天看點

Linux中通過/dev/mem操控實體位址

/dev/mem是實體記憶體的全映像,可以用來通路實體記憶體,用mmap來通路實體記憶體以及外設的IO資源,是實作使用者空間驅動的一種方法

我們先用hexedit來看下/dev/mem,hexedit /dev/mem 可以實體記憶體的資訊,當然肉眼是無法看的畢竟是16進制。

00000000   53 FF 00 F0 

53 FF 00 F0  53 FF 00 F0  53 FF 00 F0 

S...S...S...S...

00000010   53 FF 00 F0  53 FF 00 F0 

CC E9 00 F0  53 FF 00 F0  S...S.......S...

00000020   A5 FE 00 F0 

87 E9 00 F0  53 FF 00 F0  46 E7 00 F0 

........S...F...

00000030   46 E7 00 F0 

46 E7 00 F0  57 EF 00 F0  53 FF 00 F0 

F...F...W...S...

00000040   22 00 00 C0 

4D F8 00 F0 

41 F8 00 F0  FE E3 00 F0  "...M...A.......

00000050   39 E7 00 F0 

59 F8 00 F0  2E E8 00 F0  D4 EF 00 F0 

9...Y...........

00000060   A4 F0 00 F0 

F2 E6 00 F0  6E FE 00 F0  53 FF 00 F0 

........n...S...

00000070   ED EF 00 F0 

53 FF 00 F0  C7 EF 00 F0  EC 57 00 C0  ....S........W..

00000080   53 FF 00 F0 

00000090   53 FF 00 F0 

000000A0   53 FF 00 F0 

000000B0   53 FF 00 F0 

000000C0   53 FF 00 F0 

000000D0   53 FF 00 F0 

000000E0   53 FF 00

F0  53 FF 00 F0  53 FF 00 F0 

53 FF 00 F0  S...S...S...S...

000000F0  

不過可以用mmap将/dev/mem 映射出來,然後可以對其讀寫可以實作使用者空間的核心操作。先來說下mmap函數,

void *mmap(void *

addr

, size_t

length

int

prot

flags

fd

off_t

offset

);

共6個參數含義分别如下:

l  

addr如果為null,那麼有核心選擇一個映射的位址,如果不為null,那核心會把參數當做映射的提示(映射的位址就在所提示的附近,不會百分百確定的)

l   length表示映射長度

prot表示對映射的保護, 可以是可執行,可讀,可寫或不可通路,PROT_EXEC,PROT_READ,PROT_WRITE,PROT_NONE

flag表示是否對其他程序可見,MAP_SHARED表示其他程序可見。

fd需要映射的檔案描述符

offset指向fd的編譯

接下去我們用mmap來映射/dev/mem,編寫代碼如下:

#include<stdio.h>

#include<unistd.h>

#include<sys/mman.h>

#include<sys/types.h>

#include<sys/stat.h>

#include<fcntl.h>

main

()

{

  unsigned char *map_base;

  FILE *f;

  int n, fd;

  fd = open ("/dev/mem", O_RDWR |

O_SYNC);

  if (fd == -1)

    {

      printf ("open /dev/mem fail!\n");

      return (-1);

    }

  map_base =

    mmap (NULL, 0xff, PROT_READ |

PROT_WRITE, MAP_SHARED, fd, 0x20000);

  if (map_base ==

0)

      printf ("NULL

pointer!\n");

  else

      printf ("map Successfull!\n");

  unsigned long addr;

  unsigned char content;

  int i = 0;

  for (; i < 0xf; ++i)

      addr = (unsigned long) (map_base +

i);

      content = map_base[i];

      printf ("address:

0x%lx   value: 0x%x\t\t", addr,

              (unsigned int) content);

      map_base[i] = (unsigned char) i;

      printf ("address: 0x%lx   value: 0x%x\t\t", addr,

      map_base[i] = (unsigned char) i;

      printf ("address: 0x%lx   new value: 0x%x\n", addr,

  close (fd);

  munmap (map_base, 0xff);

  return (1);

}

編譯後,執行如下:

map

Successfull!

address:

0x7fbaafb5e000   value: 0x0         address:

0x7fbaafb5e000   new value: 0x0

0x7fbaafb5e001   value: 0x0         address:

0x7fbaafb5e001   new value: 0x1

0x7fbaafb5e002   value: 0x0         address:

0x7fbaafb5e002   new value: 0x2

0x7fbaafb5e003   value: 0x0         address:

0x7fbaafb5e003   new value: 0x3

0x7fbaafb5e004   value: 0x0         address:

0x7fbaafb5e004   new value: 0x4

0x7fbaafb5e005   value: 0x0         address:

0x7fbaafb5e005   new value: 0x5

0x7fbaafb5e006  

value: 0x0         address: 0x7fbaafb5e006  

new value: 0x6

0x7fbaafb5e007   value: 0x0         address:

0x7fbaafb5e007   new value: 0x7

0x7fbaafb5e008   value: 0x0         address:

0x7fbaafb5e008   new value: 0x8

0x7fbaafb5e009   value: 0x0         address: 0x7fbaafb5e009  

new value: 0x9

0x7fbaafb5e00a   value: 0x0         address:

0x7fbaafb5e00a   new value: 0xa

0x7fbaafb5e00b   value: 0x0         address:

0x7fbaafb5e00b   new value: 0xb

0x7fbaafb5e00c   value: 0x0         address: 0x7fbaafb5e00c   new

value: 0xc

0x7fbaafb5e00d   value: 0x0         address:

0x7fbaafb5e00d   new value: 0xd

0x7fbaafb5e00e   value: 0x0       address:

0x7fbaafb5e00e   new value: 0xe

例子将實體位址起始位址0x20000, 長度為0xf映射出來了,然後進行了讀寫操作。這裡0x7fbaafb5e000是mmap函數傳回的映射位址。第二次執行的時候,會發現記憶體中的值已經是上次修改過的值了并非全0.。

       大家可以把0x20000位址改成0x000位址(3G)位址,然後長度改成0xffffff,會出現段錯誤。系統的記憶體是段保護的,可以随便修改記憶體中的值系統是要崩潰的。

       /dev/mem還可以用來檢測系統甚至給系統打更新檔,為了防止/dev/mem被注入代碼,可以設定系統配置選項CONFIG_STRICT_DEVMEM=y。

此外還有port和kmem,/dev/port同/dev/mem,不過通路的是I/O端口。

/dev/kmem也同/dev/mem,不過其通路的是虛拟記憶體而不是實體記憶體。

繼續閱讀