1. 程式人生 > >Linux/Unix平臺可執行檔案格式分析

Linux/Unix平臺可執行檔案格式分析

本文討論了 UNIX/LINUX 平臺下三種主要的可執行檔案格式:a.out(assembler and link editor output 彙編器和連結編輯器的輸出)、COFF(Common Object File Format 通用物件檔案格式)、ELF(Executable and Linking Format 可執行和連結格式)。首先是對可執行檔案格式的一個綜述,並通過描述 ELF 檔案載入過程以揭示可執行檔案內容與載入執行操作之間的關係。隨後依此討論了此三種檔案格式,並著重討論 ELF 檔案的動態連線機制,其間也穿插了對各種檔案格式優缺點的評價。最後對三種可執行檔案格式有一個簡單總結,並提出作者對可檔案格式評價的一些感想。

  可執行檔案格式綜述

  相對於其它檔案型別,可執行檔案可能是一個作業系統中最重要的檔案型別,因為它們是完成操作的真正執行者。可執行檔案的大小、執行速度、資源佔用情況以及可擴充套件性、可移植性等與檔案格式的定義和檔案載入過程緊密相關。研究可執行檔案的格式對編寫高效能程式和一些黑客技術的運用都是非常有意義的。

  不管何種可執行檔案格式,一些基本的要素是必須的,顯而易見的,檔案中應包含程式碼和資料。因為檔案可能引用外部檔案定義的符號(變數和函式),因此重定位資訊和符號資訊也是需要的。一些輔助資訊是可選的,如除錯資訊、硬體資訊等。基本上任意一種可執行檔案格式都是按區間儲存上述資訊,稱為段(Segment)或節(Section)。不同的檔案格式中段和節的含義可能有細微區別,但根據上下文關係可以很清楚的理解,這不是關鍵問題。最後,可執行檔案通常都有一個檔案頭部以描述本檔案的總體結構。

  相對可執行檔案有三個重要的概念:編譯(compile)、連線(link,也可稱為連結、聯接)、載入(load)。源程式檔案被編譯成目標檔案,多個目標檔案被連線成一個最終的可執行檔案,可執行檔案被載入到記憶體中執行。因為本文重點是討論可執行檔案格式,因此載入過程也相對重點討論。下面是LINUX平臺下ELF檔案載入過程的一個簡單描述。

  1:核心首先讀ELF檔案的頭部,然後根據頭部的資料指示分別讀入各種資料結構,找到標記為可載入(loadable)的段,並呼叫函式 mmap()把段內容載入到記憶體中。在載入之前,核心把段的標記直接傳遞給 mmap(),段的標記指示該段在記憶體中是否可讀、可寫,可執行。顯然,文字段是隻讀可執行,而資料段是可讀可寫。這種方式是利用了現代作業系統和處理器對記憶體的保護功能。著名的Shellcode(參考資料 17)的編寫技巧則是突破此保護功能的一個實際例子。

  2:核心分析出ELF檔案標記為 PT_INTERP 的段中所對應的動態聯結器名稱,並載入動態聯結器。現代 LINUX 系統的動態聯結器通常是 /lib/ld-linux.so.2,相關細節在後面有詳細描述。

  3:核心在新程序的堆疊中設定一些標記-值對,以指示動態聯結器的相關操作。

  4:核心把控制傳遞給動態聯結器。

  5:動態聯結器檢查程式對外部檔案(共享庫)的依賴性,並在需要時對其進行載入。

  6:動態聯結器對程式的外部引用進行重定位,通俗的講,就是告訴程式其引用的外部變數/函式的地址,此地址位於共享庫被載入在記憶體的區間內。動態連線還有一個延遲(Lazy)定位的特性,即只在"真正"需要引用符號時才重定位,這對提高程式執行效率有極大幫助。

  7:動態聯結器執行在ELF檔案中標記為 .init 的節的程式碼,進行程式執行的初始化。在早期系統中,初始化程式碼對應函式 _init(void)(函式名強制固定),在現代系統中,則對應形式為

雙擊程式碼全選
1 2 3 4 5 6 void __attribute((constructor)) init_function(void) { …… }

  其中函式名為任意。

  8:動態聯結器把控制傳遞給程式,從 ELF 檔案頭部中定義的程式進入點開始執行。在 a.out 格式和ELF格式中,程式進入點的值是顯式存在的,在 COFF 格式中則是由規範隱含定義。

  從上面的描述可以看出,載入檔案最重要的是完成兩件事情:載入程式段和資料段到記憶體;進行外部定義符號的重定位。重定位是程式連線中一個重要概念。我們知道,一個可執行程式通常是由一個含有 main() 的主程式檔案、若干目標檔案、若干共享庫(Shared Libraries)組成。(注:採用一些特別的技巧,也可編寫沒有 main 函式的程式,請參閱參考資料 2)一個 C 程式可能引用共享庫定義的變數或函式,換句話說就是程式執行時必須知道這些變數/函式的地址。在靜態連線中,程式所有需要使用的外部定義都完全包含在可執行程式中,而動態連線則只在可執行檔案中設定相關外部定義的一些引用資訊,真正的重定位是在程式執行之時。靜態連線方式有兩個大問題:如果庫中變數或函式有任何變化都必須重新編譯連線程式;如果多個程式引用同樣的變數/函式,則此變數/函式會在檔案/記憶體中出現多次,浪費硬碟/記憶體空間。比較兩種連線方式生成的可執行檔案的大小,可以看出有明顯的區別。

a.out 檔案格式分析

  a.out 格式在不同的機器平臺和不同的 UNIX 作業系統上有輕微的不同,例如在 MC680x0 平臺上有 6 個 section。下面我們討論的是最"標準"的格式。

  a.out 檔案包含 7 個 section,格式如下:

  exec header(執行頭部,也可理解為檔案頭部)

  text segment(文字段)

  data segment(資料段)

  text relocations(文字重定位段)

  data relocations(資料重定位段)

  symbol table(符號表)

  string table(字串表)

  執行頭部的資料結構:

雙擊程式碼全選
1 2 3 4 5 6 7 8 9 10 struct exec {     unsigned long  a_midmag;  /* 魔數和其它資訊 */     unsigned long  a_text;   /* 文字段的長度 */     unsigned long  a_data;   /* 資料段的長度 */     unsigned long  a_bss;    /* BSS段的長度 */     unsigned long  a_syms;   /* 符號表的長度 */     unsigned long  a_entry;   /* 程式進入點 */     unsigned long  a_trsize;  /* 文字重定位表的長度 */     unsigned long  a_drsize;  /* 資料重定位表的長度 */ };

  檔案頭部主要描述了各個 section 的長度,比較重要的欄位是 a_entry(程式進入點),代表了系統在載入程式並初試化各種環境後開始執行程式程式碼的入口。這個欄位在後面討論的 ELF 檔案頭部中也有出現。由 a.out 格式和頭部資料結構我們可以看出,a.out 的格式非常緊湊,只包含了程式執行所必須的資訊(文字、資料、BSS),而且每個 section 的順序是固定的。這種結構缺乏擴充套件性,如不能包含"現代"可執行檔案中常見的除錯資訊,最初的 UNIX 黑客對 a.out 檔案除錯使用的工具是 adb,而 adb 是一種機器語言偵錯程式!

  a.out 檔案中包含符號表和兩個重定位表,這三個表的內容在連線目標檔案以生成可執行檔案時起作用。在最終可執行的 a.out 檔案中,這三個表的長度都為 0。a.out 檔案在連線時就把所有外部定義包含在可執行程式中,如果從程式設計的角度來看,這是一種硬編碼方式,或者可稱為模組之間是強藕和的。在後面的討論中,我們將會具體看到ELF格式和動態連線機制是如何對此進行改進的。

  a.out 是早期UNIX系統使用的可執行檔案格式,由 AT&T 設計,現在基本上已被 ELF 檔案格式代替。a.out 的設計比較簡單,但其設計思想明顯的被後續的可執行檔案格式所繼承和發揚。可以參閱參考資料 16 和閱讀參考資料 15 原始碼加深對 a.out 格式的理解。參考資料 12 討論瞭如何在"現代"的紅帽LINUX執行 a.out 格式檔案。

  COFF 檔案格式分析

  COFF 格式比 a.out 格式要複雜一些,最重要的是包含一個節段表(section table),因此除了 .text,.data,和 .bss 區段以外,還可以包含其它的區段。另外也多了一個可選的頭部,不同的作業系統可一對此頭部做特定的定義。

  COFF 檔案格式如下:

雙擊程式碼全選
1 2 3 4 5 6 7 8 9 10 11 12 13 File Header(檔案頭部) Optional Header(可選檔案頭部)

相關推薦

Linux/Unix平臺執行檔案格式分析

本文討論了 UNIX/LINUX 平臺下三種主要的可執行檔案格式:a.out(assembler and link editor output 彙編器和連結編輯器的輸出)、COFF(Common Object File Format 通用物件檔案格式)、ELF(Exe

UNIX/LINUX 平臺執行檔案格式分析

    本文討論了 UNIX/LINUX 平臺下三種主要的可執行檔案格式:a.out(assembler and link editor output 彙編器和連結編輯器的輸出)、COFF(Common Object File Format 通用物件檔案格式)、ELF(Executable and Linki

Linux執行檔案格式詳解

Linux下面,目標檔案、共享物件檔案、可執行檔案都是使用ELF檔案格式來儲存的。程式經過編譯之後會輸出目標檔案,然後經過連結可以產生可執行檔案或者共享物件檔案。Linux下面使用的ELF檔案和Windows作業系統使用的PE檔案都是從Unix系統的COFF檔案格式演化來的

軟體素材---linux C語言:linux下獲取執行檔案的絕對路徑--getcwd函式

      //標頭檔案:#include <unistd.h>     //定義函式:char * getcwd(char * buf, size_t size);    

Linux C的執行檔案結構以及程序結構

(公共部分):程式碼區,BSS區,資料區. 1.程式碼區:存放可執行的指令.順便規劃局部變數的相關資訊(??).   獨有性:一份指令在記憶體(不管虛擬記憶體還是實際)中只要有一份就可以的   只讀性:彙編指令包含 操作碼+運算元;一般操作碼是不可變的,但是運算元可

Linux下檢視執行檔案、動態庫的ELF頭等資訊

      用法: readelf <option(s)> elf-file(s)       作用: 和Windows下的PE檔案類似,ELF檔案是linux系統下可執行檔案、動態庫檔案、靜態庫檔案的標準格式。有時候我們需要檢視ELF檔案的頭資訊,或者動態庫檔

Linux】查詢執行檔案

一,whereis:檢視檔案的位置   用法:whereis [-bmsu] 檔案或者目錄名稱   引數說 明:  -b : 只找二進位制檔案  -m: 只找在說明檔案manual路徑下的檔案  -s : 只找source原始檔  -u : 沒有說明文件的檔案 

Linux which --檢視執行檔案的位置

我們經常在linux要查詢某個檔案,但不知道放在哪裡了,可以使用下面的一些命令來搜尋:        which  檢視可執行檔案的位置。       whereis 檢視檔案的位置。        locate   配合資料庫檢視檔案位置。       find   實際搜尋硬碟查詢檔名稱。 which命

MAC系統中執行檔案格式(Mach-O)的學習 (一)

  可以用otool -s __TEXT __text AppPath來觀察段內容,二進位制資料,這是看真的內容,上面的是看定義。就是轉到真的fileOffset處再讀資料。 (__TEXT,__text) section 0000000100001060 55 48 89 e5 48 8

linux下touch的運用以及在linux下建立執行的.sh檔案

linux的touch命令不常用,一般在使用make的時候可能會用到,用來修改檔案時間戳,或者新建一個不存在的檔案。 1.命令格式: touch [選項]... 檔案... 2.命令引數: -a   或--t

Linux逆向---執行檔案程式碼靜態注入小實驗

分析完節頭之後,我最大的收穫就是,這麼多的01,並不是所有的都是用來執行我寫的那段輸出helloworld的程式的,而且程式碼段中有很大一段空閒空間,這就給我們一個向可執行檔案中注入自己程式碼,然後通過修改程式邏輯達到讓它去執行我們自己寫的的部分的程式碼的邏輯的機會。 這裡我們的原始碼是

Linux ELF檔案格式分析---objcopy命令的使用

本文轉自:https://blog.csdn.net/xj178926426/article/details/73777611  Linux ELF檔案格式分析—objcopy命令的使用 最近在看《程式設計師的自我修養—連結、裝載與庫》一書,對書中提到的一個小問題,自己做了

linux 查詢執行檔案

轉自:https://www.cnblogs.com/binyue/p/4707948.htmlLinux下的可執行檔案Linux下如何查詢可執行檔案,作為一個Linux小菜剛剛有了這個問題,在windows中,可以通過後綴名判斷是否是可執行檔案,比如.exe,.bat等是可

Python 中使用 pyrex 生成 Linux 執行檔案

 這個問題是相當有意義的,如果有了比較好的方法,Python 完全可以用來開發商業軟體,而不用擔心原始碼洩露。     前兩天我在網上看了看,有很多的人在問這個問題。大部分的人都在用 py2exe,這是個對 Python 程式打包的東東,實際上只是在 Python 程式中找

Linux:原始碼到執行檔案(CRF++ python安裝)

這一過程又稱為編譯軟體原始碼。編譯是將原始碼(程式語言描述)翻譯成計算機處理器能識別的語言的過程。一 語言發展phase1:機器語言(數值程式碼,二進位制指令。)phase2:組合語言(有一些人理解的符號)phase3:高階程式語言(我們現在使用的語言)二 編譯程式語言(1)

4.執行檔案格式(ELF格式)詳解

下一講介紹可執行程式的裝載,也就是為可執行檔案建立記憶體映像。在這之前我們要先了解可執行檔案的格式,在Windows下可執行檔案的格式一般為PE,而在Linux下可執行檔案的格式為ELF。ELF檔案的全稱是Executable and Linkable Format,意為可

Linux執行執行檔案提示No such file or directory的解決方法

最近在使用Linux作業系統執行一個可執行檔案,結果出現了No such file or directory的提示,表示很疑惑。 ./tshrf bash: ./tshref: No such file or directory 檢視檔案資訊,可以看到

Linux下安裝pyinstaller用於將py檔案打包生成一個執行檔案

(2)cd pyinstaller-2.1 執行 python setup.py install 4. 拷貝py檔案 將需打包的py檔案如test.py 拷貝到當前目錄 5. 生成可執行檔案 cd到pyinstaller目錄, 執行  python pyinstaller.py test.py可能遇到的問題1

linux下把python檔案打包成執行檔案步驟

1.安裝PyInstaller    pip install pyinstaller    pyinstaller --version2.使用PyInstaller打包python檔案  在和myscript.py同目錄下執行命令:pyinstaller mycript.py

linux下將Python指令碼打包為執行檔案

一. 下載pyinstaller 連結 二. 解壓 無需安裝,解壓即可使用 三. 輸入命令,進行打包 命令格式: pyinstaller_path/pyinstaller.py -F s