Linux

為什麼某些庫和其他部分會在 gdb 的 linux 虛擬記憶體中重複?

  • October 14, 2018

在此處輸入圖像描述

這是在 gdb 中查看程序的虛擬記憶體的結果;我對此有一些疑問:

  1. 為什麼虛擬記憶體的某些部分是重複的?比如我們的程序(stack6)和libc庫重複4次;如果他們將它們分成不同的部分,那為什麼呢?為什麼不把它們放在一起呢?
  2. 最上面的路徑(/opt/pro…)是我們虛擬記憶體的指令部分(文本部分)並且只包含指令嗎?
  3. 為什麼4個libc的大小不同?偏移量是怎麼回事,如果我們已經有了大小和起始地址,那麼偏移量是什麼?
  4. 數據、bss、核心和堆部分在哪裡?為什麼上圖中的某些部分沒有關於它們的資訊?gdb 中是否有更好的選項可以實際顯示所有部分?
  5. 有沒有比 gdb 更好的程序可以更好地顯示我們程序的虛擬記憶體部分?我只想對實際的虛擬記憶體有一個很好的了解,哪個調試程序提供了最好的結果。

我提到的部分:

在此處輸入圖像描述

gdb‘輸出中缺少一項重要資訊:頁面的權限。(它們顯示在 Solaris 和 FreeBSD 上,但不在 Linux 上。)您可以通過查看/proc/<pid>/maps; 您的 Protostar 範例的地圖顯示

$ cat /proc/.../maps
08048000-08049000 r-xp 00000000 00:0f 2925       /opt/protostar/bin/stack6
08049000-0804a000 rwxp 00000000 00:0f 2925       /opt/protostar/bin/stack6
b7e96000-b7e97000 rwxp 00000000 00:00 0
b7e97000-b7fd5000 r-xp 00000000 00:0f 759        /lib/libc-2.11.2.so
b7fd5000-b7fd6000 ---p 0013e000 00:0f 759        /lib/libc-2.11.2.so
b7fd6000-b7fd8000 r-xp 0013e000 00:0f 759        /lib/libc-2.11.2.so
b7fd8000-b7fd9000 rwxp 00140000 00:0f 759        /lib/libc-2.11.2.so
b7fd9000-b7fdc000 rwxp 00000000 00:00 0
b7fe0000-b7fe2000 rwxp 00000000 00:00 0
b7fe2000-b7fe3000 r-xp 00000000 00:00 0          [vdso]
b7fe3000-b7ffe000 r-xp 00000000 00:0f 741        /lib/ld-2.11.2.so
b7ffe000-b7fff000 r-xp 0001a000 00:0f 741        /lib/ld-2.11.2.so
b7fff000-b8000000 rwxp 0001b000 00:0f 741        /lib/ld-2.11.2.so
bffeb000-c0000000 rwxp 00000000 00:0f 0          [stack]

(Protostar 範例在一個易於破解的 VM 中執行,大概是為了使練習易於處理:沒有 NX 保護,也沒有 ASLR。)

您將在上面看到,看似重複的映射gdb實際上對應於具有不同權限的不同映射。文本段被映射為只讀和可執行;數據段被映射為只讀;BSS 和堆被映射為讀寫。理想情況下,數據段、BSS 和堆是不可執行的,但此範例缺少 NX 支持,因此它們是可執行的。每個共享庫都有自己的文本段、數據段和 BSS 映射。第四個映射是一個不可讀、不可寫、不可執行的段,通常用於防止緩衝區溢出(儘管考慮到這裡使用的核心和 C 庫的年齡,這可能會有所不同)。

偏移量,當給出時,表示文件中數據的偏移量,它不一定與它在地址空間中的位置有很大關係。載入時,這會受到對齊約束;例如,libc-2.11.2.so的程序標頭檔指定了兩個“LOAD”標頭檔:

Type           Offset   VirtAddr   PhysAddr   FileSiz  MemSiz   Flg Align
LOAD           0x000000 0x00000000 0x00000000 0x13d2f4 0x13d2f4 R E 0x1000
LOAD           0x13e1cc 0x0013f1cc 0x0013f1cc 0x027b0  0x0577c  RW  0x1000

readelf -l用於查看此內容。)

如果映射到段的部分具有不同的保護標誌,則這些可能會導致具有不同虛擬地址的相同偏移量的多個映射。在stack6的情況下:

Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
LOAD           0x000000 0x08048000 0x08048000 0x00604 0x00604 R E 0x1000
LOAD           0x000604 0x08049604 0x08049604 0x00114 0x00128 RW  0x1000

(這也解釋了proc info mappingsfor顯示的小尺寸stack6:每個標頭請求小於 4KiB,對齊為 4KiB,因此它在不同地址獲得兩個具有相同偏移量的 4KiB 映射。)

空白映射對應匿名映射;詳情見man 5 proc。您需要闖入mmapgdb確定它們對應的內容。

您看不到核心映射(除了vsyscall某些架構上的遺留問題),因為從程序的角度來看它們並不重要(它們不可訪問)。

我不知道更好的gdb選擇,我總是使用/proc/$$/maps.

有關核心讀取的 ELF 格式的詳細資訊,以及它如何映射到記憶體分配,請參閱程序如何執行:ELF 二進製文件;它有指向更多參考資料的指針。

引用自:https://unix.stackexchange.com/questions/474028