国产日韩欧美一区二区三区三州_亚洲少妇熟女av_久久久久亚洲av国产精品_波多野结衣网站一区二区_亚洲欧美色片在线91_国产亚洲精品精品国产优播av_日本一区二区三区波多野结衣 _久久国产av不卡

?

利用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)代碼來初始化或外殼中的相關(guān)代碼為PE文件重新構(gòu)造還原一個(gè)導(dǎo)入表并初始化。那么有沒有方法讓系統(tǒng)加載PE文件時(shí)同時(shí)完成對(duì)PE文件和外殼自定義的導(dǎo)入表進(jì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)入表中說明的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文件的原來最后一個(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)入表合并方案來說明如何編程實(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通過變量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文件原來位置的導(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í),通過內(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)入表寫回原來位置將原來的外殼導(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)行正常,這說明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é)束語

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)到外殼中,不過這里就需要修正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)的位置沒有變動(dòng)。同樣,PE文件的導(dǎo)入表IMAGE_IMPORT_DESCRIPTOR結(jié)構(gòu)數(shù)組雖然移動(dòng)到外殼中,但由于IMAGE_THUNK_DATA結(jié)構(gòu)數(shù)組的位置沒有變化,所以不必修改其中的字段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位匯編語言程序設(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ì)
中國塑料(2016年4期)2016-06-27 06:34:00
濾清器外殼拉伸經(jīng)濟(jì)效益分析
冷藏室門外殼沖壓模具設(shè)計(jì)與優(yōu)化
师宗县| 尚志市| 叙永县| 甘孜县| 宿迁市| 华亭县| 高要市| 兰州市| 连云港市| 民乐县| 三门峡市| 拉萨市| 阿拉善左旗| 保德县| 建宁县| 南宁市| 岐山县| 尼玛县| 平昌县| 恩平市| 安达市| 克什克腾旗| 将乐县| 手机| 新化县| 图们市| 安西县| 宁化县| 南充市| 抚顺县| 绵竹市| 莫力| 安陆市| 玛多县| 海兴县| 太仆寺旗| 九江县| 新密市| 文登市| 平度市| 沂水县|