Mach O在記憶體中符號表位址 字串表位址的計算

2021-09-27 11:26:27 字數 2610 閱讀 6145

kscrash 是乙個用於 ios 平台的崩潰捕捉框架,最近讀了其部分原始碼,在 ksdynamiclinker 檔案中有乙個函式,**如下:

/** get the segment base address of the specified image.

*const uintptr_t segmentbase = segmentbaseofimageindex(idx) + imagevmaddrslide;

0 迷惑現場

乙個 image 中會有多個 segment,引數 idx 傳遞的是 image 的索引,如果返回的是 segment base, 那麼是哪個 segment?

有人會說,注釋裡不是說返回非 0 的話,就表示的是 image base。可是從原理上講 vmaddr - fileoff 根本得不到 image base(後文有解釋)。

而在被呼叫處,加上由 aslr 引起的偏移,賦值給了 segmentbase。

在 fishhook 中,有這麼一行**:

uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff;

暫不考慮由 aslr 造成的 slide,那麼又是上邊提到的 vmaddr - fileoff,這裡的變數命名是 linkedit_base。

kscrash 中的所謂的 segmentbase 和 fishhook 中所謂的 linkedit_base,到底指的是什麼?如果指的是 __linkedit 端在記憶體中的真實位址那應該是 vmaddr + aslr偏移 才對。

在查詢資料的過程中,讀了大量的部落格、資料,對於這一塊的解釋,要麼沒提,要麼一帶而過,要麼是錯的。有的認為這個值是__linkedit 段在記憶體中的基址,有的認為是當前 image 在記憶體中的基址。

1 揭開面紗

1.1 前置知識

在理解這個值到底是什麼之前,我們需要一些前置知識。

mach-o 檔案的結構

虛擬記憶體

aslr

下邊我們簡單的說一下 mach-o 檔案。

mach-o

我們知道,程序是可執行檔案在記憶體中載入得到的結果,而 mach-o 就是一種 macos 平台的可執行檔案格式。

mach-o 檔案分為三個區域 header、load commands、data。其中 load commands 區的指令指導如何設定並載入二進位制資料。下邊列出 32 位平台下我們關心的幾個:

指令 對應的資料結構 描述

lc_segment segment_command 定義了這個檔案中的乙個 segment,在 mach-o 檔案被載入到時,這個 segment 會被對映到對應的位址空間。需要留意,segment_command 中有乙個 segname,可通過 segname 來查詢指定的 segment。

lc_symtab symtab_command 指定了這個檔案的符號表。symtab_command 中包含符號表在檔案中的偏移、符號數量、字串表在檔案中的偏移、字串表的大小。

segment_command **如下:

struct segment_command ;

對於每乙個 segment 而言,設定程序虛擬記憶體的過程就是將相應的內容載入到記憶體中,也就是從 mach-o 檔案的 fileoff 初載入 filesize 位元組到虛擬記憶體位址的 vmaddr 處,占用 vmsize 位元組。需要留意,對某些 segment 來說,vmsize 可能會大於 filesize,如__data、__linkedit。

在後邊的討論中,我們需要關心的是 segname 為 __linkedit 的段。__linkedit 段由 dyld 使用,包含符號表、字串表以及其他資料。

symtab_command **如下:

struct symtab_command ;

在 symtab_command 中,symoff 為符號表在 mach-o 檔案中的偏移、stroff 為字串表在 mach-o 檔案中的偏移。

1.2 揭秘

我們可以使用 machoview 來開啟乙個 mach-o 檔案,觀察 lc_segment(__linkedit)、lc_symtab。限於篇幅,這裡就不截圖觀察了。但是你應當留意到符號表、字串表在 mach-o 檔案的位置,位於 __linkedit 段中,這也驗證了上邊對 __linkedit 段的介紹。

我們從符號表在虛擬記憶體中的位址來倒推上邊那個所謂的 segmentbase、linkedit_base,看一張圖(不是很準確,但可以幫助我們搞明白這個問題)。

mach-o map

我們先忽略 aslr,圖中的深灰色背景表示是虛擬記憶體,__text 段、__data 段我們不關心,圖中沒有體現。

sym_vmaddr 是指的是符號表在虛擬記憶體中位址,而在虛擬記憶體中符號表在 __linkedit 段中偏移,即 sym_vmaddr - vmaddr,與其在 macho 檔案中的偏移,即 symoff - fileoff 相等。

也就是sym_vmaddr - vmaddr = symoff - fileoff,

vmaddr 移到右邊,即 sym_vmaddr = symoff - fileoff + vmaddr

深圳**建設www.sz886.com

核心符號表中位址都為0??

00000000 t stext 00000000 t sinittext 00000000 t stext 00000000 t init begin 00000000 t create page tables 00000000 t enable mmu loc 00000000 t fixup ...

未解決符號表,匯出符號表和位址重定向表

讓我們總結一下 編譯器把乙個cpp編譯為目標檔案的時候,除了要在目標檔案裡寫入cpp裡包含的資料和 還要至少提供3個表 未解決符號表,匯出符號表和位址重定向表。未解決符號表提供了所有在該編譯單元裡引用但是定義並不在本編譯單元裡的符號及其出現的位址。匯出符號表提供了本編譯單元具有定義,並且願意提供給其...

筆記 C 有符號數無符號數在記憶體中取值機制

符號位 0正1負 正數 原碼 反碼 補碼 負數 反碼 原碼基礎上符號位不變取反 補碼 反碼基礎上 1 例子 假設用short a 3 原碼 1000 0000 0000 0011 反碼 1111 1111 1111 1100 補碼 1111 1111 1111 1101include intmain...