• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            無我

            讓內心永遠燃燒著偉大的光明的精神之火!
            靈活的思考,嚴謹的實現
            豪邁的氣魄、頑強的意志和周全的思考

            【轉】pe/elf 文件加殼時的處理

            本文轉自http://huaidan.org/pstzine/0x02/html/PSTZine_0x02_0x0A.html

             ==Ph4nt0m Security Team==

                                   Issue 0x02, Phile #0x0A of 0x0A


            |=---------------------------------------------------------------------------=|
            |=----------------------=[  pe/elf 文件加殼時的處理  ]=----------------------=|
            |=---------------------------------------------------------------------------=|
            |=---------------------------------------------------------------------------=|
            |=--------------------------=[      By dummy     ]=--------------------------=|
            |=-----------------------=[  <dummy_at_ph4nt0m.org>  ]=----------------------=|
            |=---------------------------------------------------------------------------=|

                           
            前言:

                最初的殼是在感染型的病毒技術上發展出來的,加殼目的一般是壓縮或加密。本文主要
            就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 的解釋器,可以參考資料鏈接上的文字,那里比我描述的完整。

            五、附錄

            [1] 本文代碼
                ./pstzine_0A_01.zip

            -EOF-

            posted on 2012-06-27 17:21 Tim 閱讀(1784) 評論(0)  編輯 收藏 引用 所屬分類: 逆向工程

            <2012年6月>
            272829303112
            3456789
            10111213141516
            17181920212223
            24252627282930
            1234567

            導航

            統計

            公告

            本博客原創文章,歡迎轉載和交流。不過請注明以下信息:
            作者:TimWu
            郵箱:timfly@yeah.net
            來源:www.shnenglu.com/Tim
            感謝您對我的支持!

            留言簿(9)

            隨筆分類(173)

            IT

            Life

            搜索

            積分與排名

            最新隨筆

            最新評論

            閱讀排行榜

            亚洲一级Av无码毛片久久精品| 久久午夜伦鲁片免费无码| 国产欧美久久一区二区| 狠狠色丁香久久综合婷婷| 热99re久久国超精品首页| 久久人人超碰精品CAOPOREN| 久久久精品久久久久久| 国内高清久久久久久| 久久久国产精品网站| 中文字幕精品久久| 精品午夜久久福利大片| 亚洲精品WWW久久久久久| 久久精品亚洲一区二区三区浴池| 一本久久久久久久| 久久精品国产亚洲AV影院| 韩国无遮挡三级久久| 久久人人爽人人爽人人片AV东京热| 精品久久久久久国产潘金莲| 久久午夜福利电影| 久久精品国内一区二区三区| 99久久精品免费看国产一区二区三区 | 一级做a爰片久久毛片毛片| 久久精品国产亚洲av麻豆小说| 久久精品国产福利国产琪琪| 波多野结衣中文字幕久久| 欧美日韩中文字幕久久久不卡| 久久99精品国产麻豆宅宅| 精品综合久久久久久98| 亚洲国产天堂久久综合| 久久影视综合亚洲| 久久九色综合九色99伊人| 久久精品中文字幕久久| 久久综合久久综合久久综合| 国产精品久久午夜夜伦鲁鲁| 性欧美大战久久久久久久久 | 久久久九九有精品国产| 日韩精品久久无码人妻中文字幕| 老男人久久青草av高清| 亚洲欧美日韩精品久久亚洲区 | 久久精品国产91久久综合麻豆自制 | 久久久久久亚洲精品无码|