日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux下ELF二进制文件加壳,pe/elf 文件加壳时的处理

發布時間:2023/12/20 linux 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux下ELF二进制文件加壳,pe/elf 文件加壳时的处理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

==Ph4nt0m Security Team==

Issue 0x02, Phile #0x0A of 0x0A

|=—————————————————————————=|

|=———————-=[ pe/elf 文件加殼時的處理 ]=———————-=|

|=—————————————————————————=|

|=—————————————————————————=|

|=————————–=[ By dummy ]=————————–=|

|=———————–=[ ]=———————-=|

|=—————————————————————————=|

前言:

最初的殼是在感染型的病毒技術上發展出來的,加殼目的一般是壓縮或加密。本文主要就x86平臺下win32 pe和linux elf 加殼程序的實現做簡單介紹和總結,以自己以前寫相關程序做線索敘述,其中程序源碼是開源的,有興趣的朋友可以繼續進行改進。

ps: 其中有些地方很久沒碰,可能有地方描述有誤,還請見諒:)

正文:

——————————————————-

slm x86 win32 r3 pe packer

mimisys x86 win32 r0 pe packer

elfp x86 linux r3 elf packer

——————————————————-

一、一個殼的組成

一個完整的殼程序主要由 2 個部分組成 packer 和 loader。它們具體的作用分別是:

(1) packer

負責將待加殼程序壓縮和加密處理、把loader寫到待加殼程序上。以slm的pakcer為例具體操作包括,pe有效性判斷、優化可壓縮數據、壓縮和加密、添加loader、存放加殼參數和待加殼程序原數據(oep等等)、改寫入口點等等。

(2) loader

主要工作是解壓或解密被加殼的程序,以slm的loader為例具體的操作包括:獲取自身位置、獲取加殼參數、進行解壓或解密、填充導入表、重定位、tls 初始化等等。

二、slm (x86 win32 r3 pe packer)

資料:

http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx

工具:

lordpe pe 文件格式查看編輯工具

dumpbin vc 自帶coff文件格式查看工具

ollydbg r3 調試工具

源碼結構:

./slm/cm 公共頭文件和模塊

./slm/pk packer 實現

./slm/sc loader 實現

在做這個時候對 pe 也是剛剛了解,所以 slm 很多地方現在看來有些問題:)。在第一節已經簡單描述 slm 的工作流程,下面主要就我當初做的時候遇到的問題做一些描述:

(1) 資源的處理

slm 的資源處理做的比較煩瑣,當初目的是為了把可壓縮資源數據歸并到一起,進行一次壓縮,不可壓縮單獨存放。下面簡單介紹一下資源的目錄數據格式,詳細還是看看微軟的文檔和相關源碼:)

從IMAGE_NT_HEADERS.IMAGE_DATA_DIRECTORY[IMAGE_DIRECTORY_ENTRY_RESOURCE]取出資源數據的地址res_rva,經過轉換后第一個結構體是IMAGE_RESOURCE_DIRECTORY

IMAGE_RESOURCE_DIRECTORY:

NumberOfIdEntries 目錄下 id 名稱入口項個數

NumberOfNamedEntries 目錄下 name 名稱入口項個數

緊跟著IMAGE_RESOURCE_DIRECTORY后面是IMAGE_RESOURCE_DIRECTORY_ENTRY結構數組,這個數組的元素個數是 NumberOfIdEntries + NumberOfNamedEntries。

IMAGE_RESOURCE_DIRECTORY_ENTRY:

Id 目錄id,只有NameIsString非真才有效

NameIsString 目錄名稱是否是字符串,如果為真NameOffset有效

NameOffset 目錄名稱串的偏移, 偏移是相對與res_rva*的。

DataIsDirectory 如果為真 OffsetToData 有效,否則OffsetToDirectory

有效

OffsetToData 指向資源數據,偏移類型rva

OffsetToDirectory 指向子目錄,偏移類型rva

如果目錄入口名稱是字符串,通過NameOffset獲取PIMAGE_RESOURCE_DIR_STRING_U的結構指針,目錄名是unicode格式,并且不是以零結尾的字符串。如果目錄名不是字符串而是id, 那么其值在winnt.h 定義。常見id有RT_ICON、RT_VERSION等等。

結構大致簡單描述完了,有點要注意OffsetToDirectory、OffsetToData修改時要進行 DWORD 對齊,否則會出現奇怪的現象。

(2) 導入表處理

從IMAGE_NT_HEADERS.IMAGE_DATA_DIRECTORY[IMAGE_DIRECTORY_ENTRY_IMPORT]取出導入表的地址imp_rva,經過轉換后第一個結構體是IMAGE_IMPORT_DESCRIPTOR。

IMAGE_IMPORT_DESCRIPTOR:

Name 指向導入 dll 的名稱,偏移類型 rva

FirstThunk 指向 IMAGE_THUNK_DATA 結構體,偏移類型 rva

OriginalFirstThunk 指向FirstThunk 的副本, 可以為空。偏移類型 rva

導入由IMAGE_IMPORT_DESCRIPTOR結構數組組成,數組長度由一個Name域為空的結構表明。

FirstThunk和OriginalFirstThunk都是指向以IMAGE_THUNK_DATA數組組成的數據結構,系統的加載器在進行導入表填充時,會把FirstThunk指向的結構修改掉。

(3) TLS 處理

這里說的tls是所謂的靜態tls(在pe文件結構上進行實現),關于什么是tls可以看看《windows 核心編程》線程那章。

1、tls 是怎樣的

比如要在vc中聲明一個tls變量需要這樣__declspec(thread) int x = 0;在鏈接時這個變量會被鏈接器放入.tls的節中。這個節從外邊看和其他的節沒有什么不同,唯一的區別在IMAGE_DATA_DIRECTORY[IMAGE_DIRECTORY_ENTRY_TLS]指向的一個結構會對此節進行描述,這個結構是IMAGE_TLS_DIRECTORY。

IMAGE_TLS_DIRECTORY:

StartAddressOfRawData tls數據開始地址類型va

EndAddressOfRawData tls數據結束地址類型va

AddressOfIndex; tls slot的地址,默認tls slot為0

AddressOfCallBacks 指向一個PIMAGE_TLS_CALLBACK的數組,這個數組

以0結尾,每個PIMAGE_TLS_CALLBACK都是va類型

SizeOfZeroFill 數據區需要進行清 0 數據的大小

Characteristics

2、系統加載器怎樣處理exe的tls

系統加載器在完成重定位和輸入表填充后,就開始處理tls。如果存在tls_dir,求出tls數據的大小EndAddressOfRawData – StartAddressOfRawData + SizeOfZeroFill, 按照大小分配一塊內存,地址存入(PDWORD)fs:[0x2c] + tls_slot, 接著拷貝StartAddressOfRawData -> EndAddressOfRawData之間的數據到新分配的內存中,然后使用SizeOfZeroFill 清零剩下的數據,然后進行循環回調AddressOfCallBacks中的函數,PIMAGE_TLS_CALLBACK函數和DllMain原型很像,只是沒有返回值。

3、系統加載器怎樣處理dll的tls

首先明確dll是可以使用tls的,唯一的不同是AddressOfCallBacks調用方式會有些區別。如果目標dll是被靜聽鏈接到其他文件上,在進程創建完成時即被加載,那么他的tls callback會觸發,而LoadLibrary方式加載不會觸發。

(4) rva & raw 轉換

pe 文件中許多結構域的指針類型是rva, rva是pe文件由系統加載后,方法相關數據的相對偏移量。而我們進行加殼處理時,是直接map的文件數據訪問都是使用文件指針,這就需要rva進行轉換。(每次做pe相關工具時,我都會習慣寫一個這樣的函數,現在不下10中版本,竟然沒有一個可以保證是正確的 – -)

下面這個是最新的rva2raw版本,不保證正確性。

三、mimisys (x86 win32 r0 pe packer)

資料:

Windows Research Kernel

wrk/base/ntos/mm/sysload.c:MmLoadSystemImage

工具:

syser 內核調試器,你也可以選擇其他的r0調試器

vmware 如果不想頻繁重啟,需要一個虛擬機

文件格式的一些處理參考slm, 這里主要就r0 pe和r3 pe區別做介紹:

(1) 節和頁

r0空間的內存常常很緊張,就導致sys section屬性有幾個特殊地方

1、可換出和禁止換出

在內存不足時,系統內存管理器,會枚舉已加載的section object, 如果存在pageout屬性,那么系統內存管理器就會換出這個節對應的頁(這個節經過系統頁對齊后換出內存)節對齊原則VirtualAddress向上、VirtualSize向下。禁止換出如名字所名這個節將永駐內存。

2、節對齊小于一頁

大多數sys的節對齊指數都是小于一頁,系統加載器在處理這類文件時相當很簡單。加載后文件和磁盤上的文件布局基本一致。當節對齊小于一頁時,SizeOfRawData必須大于等于VirtualSize,即不支持未初始化節。mimisys通過增加SizeOfImage在文件加載后分配一個未初始化的緩沖區,保證解壓過程。

(2) checksum校驗

一句話: 只有正確的checksum sys文件才允許被加載。

(3) win2k相關問題

win2k的系統加載器和其他nt系統有幾處不同,r3和r0都會有一些區別,比如r3 pe的必須要有導入表,否則拒絕加載,r0 pe必須要有重定位信息,否則也會拒絕加載。這種情況需要構造一個空的重定位目錄即可。

mimisys采取的是合并節,導致加殼后只剩下兩個節,第一個節是loader, 存放loader和各種加殼參數,第二個節是原程序優化壓縮后的數據(移動重定位,移動資源等等)。兩個節的屬性都是不允許換出的。

四、elfp (x86 linux r3 elf packer)

資料:

Tool Interface Standard (TIS) Executable and Linking Format

http://www.x86.org/ftp/manuals/tools/elf.pdf

毛德操 《漫談內核兼容》8,9 ELF映像的裝入

http://linux.insigma.com.cn/jszl.asp?docid=132762762

http://linux.insigma.com.cn/jszl.asp?docid=133617926

linux 內核源碼

linux/fs/binfmt_elf.c:load_elf_binary

工具:

objdump 進行elf文件格式的結構查看

http://www.gnu.org/software/binutils/binutils.html

ald 匯編級調試器,gdb無法調試沒有調試信息文件的。

http://ald.sourceforge.net/

elfp是在magiclinux完成的linux elf文件壓縮殼。

elf的格式是linux下主要的可執行文件格式,它也是在coff上基礎上設計的,所以它和pe文件的格式很相似,下面的敘述過程中會和 pe 文件以對比形式進行描述。

elf文件的第一個數據結構是以Elf32_Ehdr開始

typedef struct

{

unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */

Elf32_Half e_type; /* Object file type */

Elf32_Half e_machine; /* Architecture */

Elf32_Word e_version; /* Object file version */

Elf32_Addr e_entry; /* Entry point virtual address */

Elf32_Off e_phoff; /* Program header table file offset */

Elf32_Off e_shoff; /* Section header table file offset */

Elf32_Word e_flags; /* Processor-specific flags */

Elf32_Half e_ehsize; /* ELF header size in bytes */

Elf32_Half e_phentsize; /* Program header table entry size */

Elf32_Half e_phnum; /* Program header table entry count */

Elf32_Half e_shentsize; /* Section header table entry size */

Elf32_Half e_shnum; /* Section header table entry count */

Elf32_Half e_shstrndx; /* Section header string table index */

} Elf32_Ehdr;

e_ident 在 elf.h 中對應的 ELFMAG 宏,長度是四個字節

e_entry 入口點映像偏移(映像偏移即 pe 中所說的 rva)

e_phoff Elf32_Phdr 數組的文件偏移

e_shoff Elf32_Shdr 數組的文件偏移

e_ehsize Elf32_Ehdr 結構的大小

e_phentsize Elf32_Phdr 結構大小

e_phnum Elf32_Phdr 數組成員個數

e_shentsize Elf32_Shdr 結構大小

e_shnum Elf32_Shdr 數組成員個數

在Elf32_Ehdr之后即Elf32_Phdr數組,Elf32_Phdr的地址通過Elf32_Ehdr.e_ehsize來確定。Elf32_Ehdr數組(或叫段表),你可以把phdr看做pe的節表。

typedef struct

{

Elf32_Word p_type; /* Segment type */

Elf32_Off p_offset; /* Segment file offset */

Elf32_Addr p_vaddr; /* Segment virtual address */

Elf32_Addr p_paddr; /* Segment physical address */

Elf32_Word p_filesz; /* Segment size in file */

Elf32_Word p_memsz; /* Segment size in memory */

Elf32_Word p_flags; /* Segment flags */

Elf32_Word p_align; /* Segment alignment */

} Elf32_Phdr;

p_type 描述這個段的加載行為屬性

p_offset 段數據在文件中偏移,類似pe節中的PointerToRawData

p_vaddr 段數據加載后在映像中偏移, 類似pe節中的VirtualAddress

p_filesz 段數據在文件中大小,類型pe節中的SizeOfRawData

p_memsz 段數據加載后在映像中大小,類型pe節中的VirtualSize

p_flags 描述這個段的內存屬性,類似pe節中的節屬性

p_align 段對齊粒度

p_type主要的類型有

PT_LOAD 這個段需要裝載到內存中

PT_PHDR 這個段存放的是Elf32_Phdr數組

PT_INTERP 這個段存放一個解釋器名,請求系統加載器把映像裝載需求轉給這

個解釋器,關于elf的解釋器問題,可以理解為windows下ntdll裝載

pe文件,elf文件的解釋器主要負責重定位、導入表填充等操作

p_flags 主要類型有

PF_X 這個段可執行

PF_W 這個段可寫

PF_R 這個段可讀

在Elf32_Ehdr(段表)之后便是Elf32_Shdr數組(節表),你可能到這里很奇怪了,怎么這個叫節表?如果你熟悉pe應該知道節表對pe文件的重要性,但這個可不是pe中的那個節表,你應該把它看做nt header中data_dir[]結構,加載器或調試器等工具會通過節名確定節具體用途,比如存儲調試信息、版本信息、字符串表等等、elfp在加殼過程會丟棄節表。

下面簡單講講elfp的loader處理過程(加殼過程很簡單),在一個elf文件被加載后,它的入口點在執行之前,堆棧中會由系統加載器push的一些參數。

// 堆棧結構:

// +——————-+

// | return address | 返回地址

// +——————-+

// | argc | 參數個數

// +——————-+

// | argv[?], NULL | 參數表,以 NULL 結尾

// +——————-+

// | envp[?], NULL | 環境表,以 NULL 結尾

// +——————-+

// | auxv[?] | 中文不知道叫什么它,這個主要是給解釋器使用,

// +——————-+ 存放這個elf的相關信息如果被加殼程序需要解

釋器,你需要重寫正確填寫這個參數,讓解釋器可

以正確的找到相關數據的地址。

elfp殼loader的執行流程大致如下:

申請內存–>把每個段解壓到指定的地址上–>獲取被加殼程序原始信息–>檢查原始段表、重寫 auxv–>加載解釋器–>調用解釋器

關于 elf 的解釋器,可以參考資料鏈接上的文字,那里比我描述的完整。

五、附錄

-EOF-

總結

以上是生活随笔為你收集整理的Linux下ELF二进制文件加壳,pe/elf 文件加壳时的处理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。