• 
    

    
    

      99热精品在线国产_美女午夜性视频免费_国产精品国产高清国产av_av欧美777_自拍偷自拍亚洲精品老妇_亚洲熟女精品中文字幕_www日本黄色视频网_国产精品野战在线观看 ?

      利用Windows加載PE文件和外殼的導(dǎo)入表

      2015-09-09 05:59:17張鐘
      電腦知識(shí)與技術(shù) 2015年16期
      關(guān)鍵詞:外殼

      摘要:根據(jù)PE文件導(dǎo)入表的結(jié)構(gòu)及系統(tǒng)加載導(dǎo)入表的原理,在外殼中自定義了導(dǎo)入表,將外殼中的導(dǎo)入表與PE文件的導(dǎo)入表合并,并用Win32匯編編程實(shí)現(xiàn)。利用Windows加載PE文件時(shí),將PE文件和外殼的導(dǎo)入表初始化,從而實(shí)現(xiàn)了在PE文件和外殼中正常調(diào)用API函數(shù)。

      關(guān)鍵詞:PE文件;外殼;導(dǎo)入表;合并導(dǎo)入表

      中圖分類號(hào):TP309 文獻(xiàn)標(biāo)識(shí)碼:A 文章編號(hào):1009-3044(2015)03-0117-04

      The Use of Windows to Load the Import Table of the PE File and Shell

      ZHANG Zhong

      (Chongqing University of Technology, Chongqing 400054,China)

      Abstract: Based on the import table structure of the PE file and the principle of system loading the import table,it is defined in the shell. the import table of the shell and that of the PE file are combined in one by using Win32 assembly program. Which is initialized while windows loads PE file, so as to realize normal calling API functions in the PE file and shell.

      Key words: PE file; shell; import table; merging import table

      PE文件(EXE)經(jīng)加殼后,由于程序功能上的需要,在外殼中或多或少地會(huì)用到API函數(shù),而要調(diào)用API函數(shù)就需要知道API函數(shù)的地址。由于外殼代碼是附加在編譯鏈接好的PE文件上,因此,外殼中調(diào)用的API函數(shù)地址只能自己想法解決。在外殼中獲得API函數(shù)地址常用的方法有二種:一種方法是在PE文件被加載的進(jìn)程中由外殼中的代碼自己動(dòng)態(tài)的獲取API函數(shù)的地址;另一種方法是在外殼中自定義一個(gè)所用API函數(shù)的導(dǎo)入表,利用Windows加載PE文件時(shí),由系統(tǒng)加載外殼的導(dǎo)入表,從而獲得API函數(shù)的地址。而PE文件的導(dǎo)入表就用外殼中的相關(guān)代碼來(lái)初始化或外殼中的相關(guān)代碼為PE文件重新構(gòu)造還原一個(gè)導(dǎo)入表并初始化。那么有沒(méi)有方法讓系統(tǒng)加載PE文件時(shí)同時(shí)完成對(duì)PE文件和外殼自定義的導(dǎo)入表進(jìn)行初始化呢?這就是本文所要討論的問(wèn)題。

      1 PE文件8導(dǎo)入表和外殼導(dǎo)入表合并的基本思路

      1.1 PE文件導(dǎo)入表的結(jié)構(gòu)

      圖1 PE文件磁盤映像中的導(dǎo)入表結(jié)構(gòu)(部分)

      要自定義導(dǎo)入表和實(shí)現(xiàn)導(dǎo)入表的合并,首先要了解熟悉導(dǎo)入表的基本結(jié)構(gòu)組成。PE文件的導(dǎo)入表是由一系列的IMAGE_IMPORT_DESCRIPTOR結(jié)構(gòu)組成的數(shù)組,每一個(gè)IMAGE_IMPORT_DESCRIPTOR結(jié)構(gòu)對(duì)應(yīng)一個(gè)DLL,導(dǎo)入表的最后由一個(gè)內(nèi)容全為0 的IMAGE_IMPORT_DESCRIPTOR結(jié)構(gòu)結(jié)束。該結(jié)構(gòu)的定義如下:

      IMAGE_IMPORT_DESCRIPTOR STRUCT

      union

      Characteristics dd ?

      OriginalFirstThunk dd ? ;指向?qū)朊Q表(INT)的RVA

      ends

      TimeDateStamp dd ?

      ForwarderChain dd ?

      Name1 dd ? ;指向DLL名稱(ANSI字符串,以0結(jié)尾)的RVA

      FirstThunk dd ? ;指向?qū)氲刂繁恚↖AT)的RVA

      IMAGE_IMPORT_DESCRIPTOR ENDS

      字段OriginalFirstThunk所指的導(dǎo)入名稱表(Import Name Table,簡(jiǎn)稱INT)由若干個(gè)IMAGE_THUNK_DATA結(jié)構(gòu)組成的數(shù)組,每一個(gè)IMAGE_THUNK_DATA結(jié)構(gòu)對(duì)應(yīng)一個(gè)API導(dǎo)入函數(shù),數(shù)組的最后由一個(gè)內(nèi)容全為0的IMAGE_THUNK_DATA結(jié)構(gòu)結(jié)束。該結(jié)構(gòu)的定義如下:

      IMAGE_THUNK_DATA STRUCT

      union u1

      ForwarderString dd ?

      Function dd ? ;導(dǎo)入函數(shù)的入口地址

      Ordinal dd ? ;導(dǎo)入API的序號(hào)

      AddressOfData dd ? ;指向IMAGE_IMPORT_BY_NAME的RVA

      ends

      IMAGE_THUNK_DATA ENDS

      從這個(gè)結(jié)構(gòu)的定義可看到,該結(jié)構(gòu)是一個(gè)共用體,實(shí)際上就是一個(gè)雙字。當(dāng)雙字的最高位是1時(shí),表示函數(shù)是以序號(hào)導(dǎo)入的,低31位就是函數(shù)的序號(hào)值;當(dāng)最高位是0時(shí),表示函數(shù)是以函數(shù)名稱(ANSI字符串,以0結(jié)尾)導(dǎo)入的,雙字表示是一個(gè)RVA,此時(shí)指向一個(gè)IMAGE_IMPORT_BY_NAME結(jié)構(gòu)。IMAGE_IMPORT_BY_NAME結(jié)構(gòu)定義如下所示。

      IMAGE_IMPORT_BY_NAME STRUCT

      Hint dw ? ;指示API函數(shù)在DLL導(dǎo)出表中的序號(hào),有些編譯器設(shè)為0

      Name1 db ? ;導(dǎo)入函數(shù)的函數(shù)名(ANSI字符串,以0結(jié)尾)

      IMAGE_IMPORT_BY_NAME ENDS

      Windows在裝入PE文件時(shí),其工作之一是定位到導(dǎo)入表,根據(jù)導(dǎo)入表中說(shuō)明的DLL,將DLL裝入內(nèi)存,在DLL中搜索導(dǎo)入表記錄的API函數(shù),找到后將對(duì)應(yīng)的函數(shù)地址(指針)寫入IAT,以方便程序正確調(diào)用API函數(shù)。

      1.2 外殼中自定義的導(dǎo)入表(示例)

      根據(jù)前面所敘的PE文件導(dǎo)入表結(jié)構(gòu),外殼中自定義的導(dǎo)入表如下(部分):

      APPEND_CODE equ this byte ;外殼開始

      ImportTableHeader label dword

      ;-----IMAGE_IMPORT_DESCRIPTOR結(jié)構(gòu)數(shù)組-----

      ImportTable dd _MessageBox-ImportTable ;OriginalFirstThunk

      dd 0,0

      dd DllUser32-ImportTable ;Name1

      dd _MessageBox-ImportTable ;FirstThunk

      dd 0,0,0,0,0 ;導(dǎo)入表結(jié)束符

      ;-------DLL名稱字符串---------

      DllUser32 db 'user32.dll'

      dw 0

      ;---------IMAGE_THUNK_DATA結(jié)構(gòu)數(shù)組------- _MessageBox dd Func1-ImportTable ;IMAGE_THUNK_DATA

      _DialogBoxIndirectParam dd Func2-ImportTable

      _EndDialog dd Func3-ImportTable

      _GetDlgItemText dd Func4-ImportTable

      _SetWindowText dd Func5-ImportTable

      _SendDlgItemMessage dd Func6-ImportTable

      _LoadIcon dd Func7-ImportTable

      _SendMessage dd Func8-ImportTable

      dd 0 ;結(jié)束符

      ;------IMAGE_IMPORT_BY_NAME結(jié)構(gòu)數(shù)組------

      Func1 dw 0

      db 'MessageBoxA',0

      Func2 dw 0

      db 'DialogBoxIndirectParamA',0

      Func3 dw 0

      db 'EndDialog',0

      Func4 dw 0

      db 'GetDlgItemTextA',0

      Func5 dw 0

      db 'SetWindowTextA',0

      Func6 dw 0

      db 'SendDlgItemMessageA',0

      Func7 dw 0

      db 'LoadIconW',0

      Func8 dw 0

      db 'SendMessageW',0

      …………

      ImportTableEnd label dword

      1.3 PE文件的導(dǎo)入表和外殼的導(dǎo)入表的合并思路

      為了讓W(xué)indows加載PE文件和外殼中的導(dǎo)入表,首先在外殼中要嚴(yán)格按照PE文件的導(dǎo)入表格式定義,然后將PE文件和外殼的導(dǎo)入表合并成一個(gè)IMAGE_IMPORT_DESCRIPTOR數(shù)組。由于在PE文件中的.idata節(jié)或.rdata節(jié)中空隙空間有限,不一定能裝下外殼中的整個(gè)導(dǎo)入表,所以在這里是將PE文件的導(dǎo)入表移動(dòng)到PE文件的原來(lái)最后一個(gè)節(jié)區(qū)的末尾處(新增加的.zzcode節(jié)區(qū)的開始處),然后再接上外殼的導(dǎo)入表,這樣就合并成了一個(gè)完整的導(dǎo)入表。這又有二種拼接方法:(a)PE文件的導(dǎo)入表放在前面,外殼的導(dǎo)入表放在后面;(b)外殼導(dǎo)入表放在前面,PE文件的導(dǎo)入表放在后面。如下圖2所示:

      (a) (b)

      圖2 PE文件導(dǎo)入表與外殼導(dǎo)入表合并后的磁盤映像

      2 利用Windows加載PE文件和外殼的導(dǎo)入表的程序?qū)崿F(xiàn)

      2.1 合并PE文件和外殼的導(dǎo)入表

      這里用圖2(a)中所示的導(dǎo)入表合并方案來(lái)說(shuō)明如何編程實(shí)現(xiàn)導(dǎo)入表的合并。

      1)首先由API函數(shù)CreateFile、CreateFileMapping、MapViewOfFile創(chuàng)建PE文件的內(nèi)存映像,從PE開頭定位到NT映像頭IMAGE_NT_HEADERS,這里用ebx指向IMAGE_NT_HEADERS結(jié)構(gòu),由字段OptionalHeader、DataDirectory通過(guò)變量VirtualAddress,也就是 [ebx].OptionalHeader.DataDirectory[8].VirtualAddress定位到PE文件的導(dǎo)入表,然后用如下代碼片段計(jì)算出導(dǎo)入表的字節(jié)長(zhǎng)度。

      xor ecx,ecx

      assume esi:ptr IMAGE_IMPORT_DESCRIPTOR

      .while [esi].OriginalFirstThunk || [esi].TimeDateStamp || \

      [esi].ForwarderChain || [esi].Name1 || [esi].FirstThunk

      inc ecx

      add esi,sizeof IMAGE_IMPORT_DESCRIPTOR

      .endw

      mov eax,sizeof IMAGE_IMPORT_DESCRIPTOR

      mul ecx

      mov @IIDlength,eax

      2)在PE文件中新增加一個(gè)節(jié)區(qū)如.zzcode,將PE文件的導(dǎo)入表寫入該文件的新增加節(jié)區(qū)的開頭處,然后將整個(gè)外殼(注意:要求外殼的導(dǎo)入表要放在外殼的最前面)寫在緊接PE文件的導(dǎo)入表的后面,這樣就實(shí)現(xiàn)了PE文件的導(dǎo)入表和外殼導(dǎo)入表的合并。其后就可用任意字節(jié)代碼履蓋掉PE文件原來(lái)位置的導(dǎo)入表。

      3)修改PE文件導(dǎo)入表的指針使其指向合并后的導(dǎo)入表頭部,同時(shí)修改合并導(dǎo)入表的大小,以確保系統(tǒng)加載PE文件時(shí)初始化合并后的導(dǎo)入表。代碼片段如下:

      mov eax,[ebx].VirtualAddress ;ebx指向PE文件新增加的節(jié)區(qū)

      mov [edi].OptionalHeader.DataDirectory[8].VirtualAddress,eax

      mov ecx,offset ImportTableEnd - offset ImportTableHeader

      add ecx,@IIDlength

      mov [edi].OptionalHeader.DataDirectory[8].isize,ecx

      4)將外殼自定義的整個(gè)導(dǎo)入表讀入由函數(shù)GlobalAlloc申請(qǐng)的內(nèi)存塊中,然后對(duì)導(dǎo)入表IMAGE_IMPORT_DESCRIPTOR結(jié)構(gòu)中的OriginalFirstThunk、Name1、FirstThunk字段的雙字地址進(jìn)行修改,同時(shí)對(duì)IMAGE_THUNK_DATA結(jié)構(gòu)中共用體u1中的AddressOfData字段的地址進(jìn)行修改,將字段中的相對(duì)于外殼導(dǎo)入表頭部的偏移offset轉(zhuǎn)換為RVA。這樣,當(dāng)Windows加載外殼導(dǎo)入表時(shí),通過(guò)內(nèi)存PE文件的映像基地址+字段的RVA,就能準(zhǔn)確定位需要查找DLL中的函數(shù),并將函數(shù)地址填寫入IAT,從而保證外殼中調(diào)用API函數(shù)時(shí)找到所對(duì)應(yīng)的函數(shù)地址。偏移地址修改為RVA完成后,再將內(nèi)存塊中的整個(gè)導(dǎo)入表寫回原來(lái)位置將原來(lái)的外殼導(dǎo)入表覆蓋掉,至此,合并導(dǎo)入表的工作就完成了。進(jìn)行這個(gè)地址轉(zhuǎn)換的程序代碼如下:

      ;修正外殼自定義導(dǎo)入表RVA子程序

      DisposeImportTab proc _lphFile,_dwAddCodeFile,_dwAddCodeVirt

      ;_lphFile——文件句柄,_dwAddCodeFile——被加殼PE文件添加代碼的位置,_dwAddCodeVirt——內(nèi)存中添加代碼的位置

      local @lpAlloc1,@dwReadByte,@ImpTablength

      pushad

      mov esi,offset ImportTableEnd-offset ImportTableHeader

      mov @ImpTablength,esi

      invoke GlobalAlloc,GPTR,@ImpTablength

      mov @lpAlloc1,eax

      mov edi,eax ;指向自定義的導(dǎo)入表頭部

      mov ecx,_dwAddCodeFile

      invoke SetFilePointer,_lphFile,ecx,NULL,F(xiàn)ILE_BEGIN

      invoke ReadFile,_lphFile,edi,esi,addr @dwReadByte,NULL

      .if @dwReadByte

      ;在此修正導(dǎo)入表RVA地址的代碼

      assume edi:ptr IMAGE_IMPORT_DESCRIPTOR

      mov eax,_dwAddCodeVirt

      .while [edi].FirstThunk

      add [edi].OriginalFirstThunk,eax

      mov esi,@lpAlloc1

      add esi,[edi].FirstThunk

      add [edi].FirstThunk,eax

      add [edi].Name1,eax

      assume esi: ptr IMAGE_THUNK_DATA

      .while [esi].u1.AddressOfData

      add [esi].u1.Ordinal,eax

      add esi,4

      .endw

      add edi,14h

      .endw

      assume edi:nothing,esi:nothing

      mov ecx,_dwAddCodeFile

      mov ebx,offset ImportTableEnd-offset ImportTableHeader

      invoke SetFilePointer,_lphFile,ecx,NULL,F(xiàn)ILE_BEGIN

      invoke WriteFile,_lphFile,@lpAlloc1,ebx,addr @dwReadByte,NULL

      invoke GlobalFree,@lpAlloc1

      popad

      mov eax,1

      .else

      invoke MessageBox,NULL,addr szImportTabErr,addr szCaptionTip,MB_OK

      popad

      mov eax,0

      .endif

      ret

      DisposeImportTab endp

      2.2 合并導(dǎo)入表的測(cè)試與分析

      1)在Windos 7 和Windows XP SP2環(huán)境下,對(duì)示例PE文件和多個(gè)PE文件進(jìn)行了加殼,對(duì)合并后的導(dǎo)入表進(jìn)行了測(cè)試,程序原有各項(xiàng)功能運(yùn)行正常,這說(shuō)明PE文件的API函數(shù)調(diào)用,外殼中API函數(shù)調(diào)用工作正常,合并導(dǎo)入表達(dá)到預(yù)期目的。

      2)用導(dǎo)入表查看工具軟件查看加殼后的示例PE文件導(dǎo)入表,如圖3所示是PE文件導(dǎo)入表(部分)磁盤映像,導(dǎo)入表字段OriginalFirstThunk指向INT,字段FirstThunk指向IAT;圖4所示是外殼導(dǎo)入表(部分)磁盤映像,導(dǎo)入表字段OriginalFirstThunk和字段FirstThunk指向同一個(gè)IMAGE_THUNK_DATA,當(dāng)被系統(tǒng)載入內(nèi)存后它就轉(zhuǎn)變成IAT了。

      3 結(jié)束語(yǔ)

      1)本文示例中外殼中的導(dǎo)入表和PE文件的導(dǎo)入表合并后放在外殼的最前面,其實(shí)合并后的導(dǎo)入表還可放置在外殼的最后面或外殼中的任意位置,只是這樣編程實(shí)現(xiàn)時(shí)要復(fù)雜一些。

      2)測(cè)試和分析表明:除了可把PE文件的導(dǎo)入表IMAGE_IMPORT_DESCRIPTOR結(jié)構(gòu)數(shù)組移動(dòng)到外殼中,實(shí)際上還可以把IMAGE_THUNK_DATA結(jié)構(gòu)也移動(dòng)到外殼中,不過(guò)這里就需要修正IMAGE_IMPORT_DESCRIPTOR結(jié)構(gòu)中字段OriginalFirstThunk、FirstThunk的RVA值,以便正確的指向IMAGE_THUNK_DATA結(jié)構(gòu)數(shù)組,保證Windows加載PE文件導(dǎo)入表時(shí)正確尋址找到INT和IAT,但I(xiàn)MAGE_THUNK_DATA結(jié)構(gòu)中的共用體u1中的字段AddressOfData不必修正,因?yàn)镮MAGE_IMPORT_BY_NAME結(jié)構(gòu)的位置沒(méi)有變動(dòng)。同樣,PE文件的導(dǎo)入表IMAGE_IMPORT_DESCRIPTOR結(jié)構(gòu)數(shù)組雖然移動(dòng)到外殼中,但由于IMAGE_THUNK_DATA結(jié)構(gòu)數(shù)組的位置沒(méi)有變化,所以不必修改其中的字段OriginalFirstThunk、FirstThunk的RVA值。

      3)將PE文件的導(dǎo)入表IMAGE_IMPORT_DESCRIPTOR結(jié)構(gòu)數(shù)組移動(dòng)到外殼中,而將IMAGE_THUNK_DATA結(jié)構(gòu)和IMAGE_IMPORT_BY_NAME結(jié)構(gòu)留在PE文件中,也就是把整個(gè)導(dǎo)入表分割成了二部分,這樣可以加強(qiáng)外殼與原程序的聯(lián)系,如果簡(jiǎn)單地把PE文件的外殼脫去會(huì)導(dǎo)致系統(tǒng)初始化PE文件的導(dǎo)入表失敗,從而使PE文件不能正常調(diào)用API函數(shù)而引發(fā)異常。

      參考文獻(xiàn):

      [1] 段鋼. 加密與解密[M]. 3版. 北京: 電子工業(yè)出版社, 2008.

      [2] 羅云彬. Windows環(huán)境下32位匯編語(yǔ)言程序設(shè)計(jì)[M]. 2版. 北京: 電子工業(yè)出版社, 2006.

      [3] 張鐘. 在遠(yuǎn)程進(jìn)程中注入DLL鉤掛IAT的方法[J]. 計(jì)算機(jī)與現(xiàn)代化, 2014(4).

      [4] 戚利. WindowsPE權(quán)威指南[M]. 北京: 機(jī)械工業(yè)出版社, 2012.

      猜你喜歡
      外殼
      正壓外殼型防爆電機(jī)的防爆原理及相關(guān)試驗(yàn)
      外殼層最近鄰交換相互作用對(duì)Blume-Capel模型相變行為的影響
      U盾外殼組件注塑模具設(shè)計(jì)
      塑料外殼注射模設(shè)計(jì)
      模具制造(2019年7期)2019-09-25 07:30:00
      電動(dòng)機(jī)外殼的消失模鑄造工藝研究
      3E 汽車外殼(金屬)破碎回收生產(chǎn)線
      資源再生(2017年3期)2017-06-01 12:20:58
      隔爆外殼水壓試驗(yàn)工藝探討
      音響外殼模內(nèi)裝飾注塑模具設(shè)計(jì)
      濾清器外殼拉伸經(jīng)濟(jì)效益分析
      冷藏室門外殼沖壓模具設(shè)計(jì)與優(yōu)化
      杨浦区| 鄯善县| 平顺县| 九江市| 肃南| 武汉市| 浦县| 兖州市| 犍为县| 图片| 云南省| 利川市| 泰兴市| 政和县| 通榆县| 孟连| 宁晋县| 中山市| 罗江县| 旺苍县| 东光县| 同心县| 平乐县| 新巴尔虎右旗| 二连浩特市| 罗江县| 洛隆县| 宾阳县| 夏邑县| 临泽县| 廉江市| 临桂县| 郑州市| 昌黎县| 栾川县| 馆陶县| 西平县| 巫溪县| 宁陕县| 尉犁县| 始兴县|