Warning: Parameter 1 to wp_default_scripts() expected to be a reference, value given in /home/vhosts/lagon.eu5.org/wp-includes/plugin.php on line 571

Warning: Parameter 1 to wp_default_styles() expected to be a reference, value given in /home/vhosts/lagon.eu5.org/wp-includes/plugin.php on line 571
PE文件格式:导入表&IAT——手工重组 返回顶部

PE文件格式:导入表&IAT——手工重组

062014
PE文件格式:导入表&IAT——手工重组

最近学了导入表和IAT之后,有了动手实践一番的想法。于是乎,又是一个大半个晚上的折腾。。。。。不过终于成功了。

因为第一次尝试,途中错误不断所以截图可能有误,但描述应该无误(除非有的地方错了,不影响运行)。


下面是一个锁定任务栏程序(来自《PE权威指南》中的例子),和一个简单的Helloworld程序

 

		.386
		.model flat,stdcall
		option casemap :none
include 	windows.inc
include		user32.inc
includelib	user32.lib
include		kernel32.inc
includelib	kernel32.lib

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		.data
sz1	db	"Shell_TrayWnd",0
hTray	dd	?
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		.code
start:		
	invoke FindWindow,addr sz1,0
	mov	hTray,eax
	invoke	ShowWindow,hTray,SW_HIDE
	invoke	EnableWindow,hTray,FALSE
	invoke	MessageBox,NULL,addr sz1,NULL,0

	invoke	ShowWindow,hTray,SW_SHOW
	invoke	EnableWindow,hTray,TRUE
	invoke	ExitProcess,0
end start

helloWorld程序

    .386
    .model flat,stdcall
    option casemap:none

include    windows.inc
include    user32.inc
includelib user32.lib
include    kernel32.inc
includelib kernel32.lib
    .data
szText     db  'HelloWorld',0
    .code
start:
    invoke MessageBox,NULL,offset szText,NULL,MB_OK
    invoke ExitProcess,NULL
    end start

节的名称  未对齐前真实长度  内存中的偏移(对齐后的) 文件中对齐后的长度 文件中的偏移  节的属性

———————————————————————————————

.text 00000024   00001000  00000200   00000400 60000020

.rdata 00000092  00002000 00000200   00000600  40000040

.data 0000000b   00003000  00000200  00000800  c0000040

 

我们需要加入下面的代码:

Invoke      FindWindowA,addr szTrayWnd, 0

Mov          hTray,eax

Invoke      ShowWindow,hTray,SW_HIDE ;        //SW_HIDE==0

Invoke      EndbleWindow,hTray,FALSE;

……………………….

Invoke      ShowWindow,hTray,SW_SHOW;      //SW_SHOW==5

Invoke      EndbleWindow,hTray,TRUE;

 

每一个Invoke都可以分解三部分:

1、  Push 参数

2、  Call  XXXXXXXX

3、  Jmp   WORD ptr DS:[XXXXXXXX]  //指向IAT相应数据 的VA

 

完整的代码见下面的第三部分.data 段的修改

先修改.Data段

.data段文件偏移是800H,那在十六进制编辑器中打开helloworld.exe看到800H处。修改前如图:

我们需要添加以下几个数据:

szTrayWnd       db     “Shell_TrayWnd”,0

hTray                 dd     ?

修改后如下图红色部分,最后四个字节的00是为了标示hTray。

修改后.data段的size=0000000bH变大了12H,所以需要将PE文件头中的IMAGE_SECTION_HEADER(.data).VirtualSize (文件偏移为200H处)修改为1DH。

修改完成后helloworld仍然可以运行。

接下来修改.rdata段:

这是最难的一部分,这也是我写这篇文章的主要目的,手工重组IAT。.rdata段文件偏移是600H,看到600H处。修改前如图:

 

.rdata段中总共有两种数据,一种是IAT,另外一种是导入表数据结构。IAT的描述信息在IMAGE_NT_HEADERS.DataDirectory[12].VirtualAddress(相对于IMAGE_NT_HEADERS的偏移是D8H)。另一个导入表数据结构在IMAGE_NT_HEADERS.DataDirectory[1].VirtualAddress (相对于IMAGE_NT_HEADERS的偏移是80H)。正如成员名,VirtualAddress都是RVA

导入表数据结构存放着IMAGE_IMPORT_DESCRIPTOR结构,每个结构占14H个字节空间,最后以一个空的IMAGE_IMPORT_DESCRIPTOR结构作为结尾。

typedefstruct _IMAGE_IMPORT_DESCRIPTOR {

    union {

        ULONG  Characteristics;

        ULONG  OriginalFirstThunk;         // RVA

};

    ULONG  TimeDateStamp;

    ULONG  ForwarderChain;                 //-1 if no forwarders

    ULONG  Name;                                                            //RVA导入动态链接库(DLL)名

    ULONG  FirstThunk;                     //RVA

}IMAGE_IMPORT_DESCRIPTOR;

IMAGE_IMPORT_DESCRIPTOR结构中的OriginalFirstThunk和FirstThunk(指向IAT的RVA)分别当其最高位为零时,指向(RVA)一个不同的存储着相同数据的IMAGE_THUNK_DATA结构,每个结构占4个字节,最后以一个空的结构作为结尾。最高位为1时,导入符号为名称

typedefstruct _IMAGE_THUNK_DATA32 {

    union {

        ULONG ForwarderString;      // PUCHAR

        ULONG Function;             // PULONG

        ULONG Ordinal;

        ULONG AddressOfData;        // PIMAGE_IMPORT_BY_NAME

    } u1;

}IMAGE_THUNK_DATA32;

AddressOfData指向(RVA)一个(大小未定的)IMAGE_IMPORT_BY_NAME结构

typedefstruct _IMAGE_IMPORT_BY_NAME {

    USHORT Hint;                 //导入函数在DLL中的编号

    UCHAR  Name[1];        //长度不定,以‘\0’结束的函数名

}IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

在文件中找到IMAGE_NT_HEADERS.DataDirectory[1](文件偏移为130H)和IMAGE_NT_HEADERS.DataDirectory[12](文件偏移为188H):

 

得到IAT RVA=2000H 导入数据 RVA=2010H。然后转换成文件偏移地址就是600H和610H

如下图:

 

IAT放在前面,所以先计算IAT所需空间,IAT中存放着IMAGE_THUNK_DATA结构,大小为4字节。一个导入函数需要一个该结构,共有5个函数,user32.dll中有四个,加上结尾的空结构,需要4*4+4=14H,kernel32.dll中有一个函数,需要4*1+4=8H,总共是14h+8H=1CH。.rdata文件中偏移位600H,所以将600H~61BH预留给IAT。

从61CH开始编辑导入数据(就是DataDirectory[1]所指数据)。即IMAGE_IMPORT_DESCRIPTOR结构。总共有两个动态链接库(user32.dll和kernel32.dll)加上作为结尾标示的空结构,共3*14H=3CH字节空间。

即从61CH~657H之间。然后后面紧接着是originalFirstThunk所指向(RVA)的INT。大小与IAT相同。即658H~673H。再然后从674H开始就是存放着dll名和函数编号+函数名。那先对dll名和函数编号+函数名进行修改。如图:

在函数名之前有两个字节的函数编号!

然后就可以得到下表

名称                                                        文件偏移                            RVA

user32.dll                                               6AC                              000020AC

00B2EnableWindow                           69D                              0000209D

00d0FindWindowA                            68F                               0000208F

01B1MessageBoxA                                     681                              00002081

0248ShowWindow                              674                              00002074

kernel32.dll                                           6C5                              000020C5

0080ExitProcess                                 6B7                              000020B7

接下来编辑61CH~657H,即导入表数据区域。先是user32.dll

OriginalFirstThunk文件偏移为 660H  RVA=00002060H

TimeDataStamp       忽略,全零

ForWardChain          全零

Name                 RVA指向“user32.dll”,为000020AC

FirstThunk                  IAT 文件偏移为608H,RVA为00002008H

然后是kernel32.dll

OriginalFirstThunk指向(INT)658H的RVA即00002058H

TimeDataStamp       忽略,全零

ForWardChain          全零

Name                 RVA指向“kernel32.dll”,为000020C5H

FirstThunk                  IAT 文件偏移为600H,RVA为00002000H

接着是全为零的14H个字节。修改后如图:

 

然后修改IAT600H~61BH,IAT存放着IMAGE_THUNK_DATA。另外注意一点,IAT中总是按照函数编号或者函数名进行升序排序。

先处理kernel32.dll指向的IAT部分,只有Exitprocess一个函数。所以填入其RVA在加上一个空的IMAGE_THUNK_DATA。User32.dll紧随其后,按函数名升序排列。

因为INT(文件偏移658H)在文件中和IAT一样,所以直接拷贝相同长度数据即可。如图。

然后所有的调用API的jmp  dword ptr ds:[VA]都是取得IAT的值。

那么ExitProcess 的文件偏移是600H,则VA是00402000H,一样的道理,剩下的API则是:

         EnableWindow  614H             00402014H

         FindWindowA    610h              00402010H

         MessageBoxA   60CH            0040200CH

         ShowWindow     608H             00402008H

这些数据会在.data段修改时用到

修改完上面的东西后还没有完成.rdata段的修改。还要修改

IMAGE_SECTION_HEADER(.data).VirtualSize(文件偏移1D8H)=D2H

DataDirectory[1].VitualAddress=0000201C             (RVA文件偏移为61CH)

DataDirectory[1].isize=   3CH                              不变

DataDirectory[12].VitualAddress=00002000           (RVA文件偏移为600H,不变)

DataDirectory[12].isize= 1CH

最后就是修改.text段

.text段文件偏移是400H。

需要加入的代码如下:(OD反汇编得到的)

为了省事从OD反汇编来的,所以代码中的地址全部要修改。

00401000>/$  6A 00         push 0x0                                 ;/Title = NULL

                   //当确定push 1个字节的内容时用6A

00401002  |.  6800304000   push LockTray.00403000      ; |Class = “Shell_TrayWnd”

                   //68 0B304000

00401007  |.  E856000000   call<jmp.&user32.FindWindowA>; \FindWindowA

                   //E8

0040100C  |.  A30E304000   mov dword ptrds:[0x40300E],eax

                   // A3 19304000

00401011  |.  6A00         push 0x0                                      ; /ShowState = SW_HIDE

00401013  |. FF35 0E304000 push dword ptr ds:[0x40300E]    ; |hWnd

                   //FF3519304000

00401019  |.  E850000000   call<jmp.&user32.ShowWindow> ; \ShowWindow

                   //E8

0040101E  |.  6A00         push 0x0                    ; /Enable = FALSE

00401020  |. FF35 0E304000 push dword ptr ds:[0x40300E]    ; |hWnd = NULL

                   //FF35 19304000

00401026  |.  E831000000   call<jmp.&user32.EnableWindow> ; \EnableWindow

                   //E8

;        MessgaeBox 部分

;

0040103B  |.  6A05         push 0x5                     ; /ShowState = SW_SHOW

0040103D  |. FF35 0E304000 push dword ptr ds:[0x40300E]    ; |hWnd = NULL

                   //FF35 19304000

00401043  |.  E826000000   call<jmp.&user32.ShowWindow>  ;\ShowWindow

                   //E8

00401048  |.  6A01         push 0x1                     ; /Enable = TRUE

0040104A  |. FF35 0E304000 push dword ptr ds:[0x40300E]    ; |hWnd = NULL

                   //FF35 19304000

00401050  |.  E807000000   call <jmp.&user32.EnableWindow>; \EnableWindow                //E8

                   ;ExitProcess部分

;所有jmp部分 这里用到.rdata得到的jmp的VA

0040105C      FF25 14204000        jmp    dword ptr ds:[<&user32.EnableWindow>]

//      FF2514204000

00401062      FF25 10204000        jmp    dword ptr ds:[<&user32.FindWindowA>]

                   //      FF25 10204000

00401068      FF25 0C204000        jmp    dword ptr ds:[<&user32.MessageBoxA>]

                                     //      FF25 0C204000

0040106E      FF25 08204000        jmp    dword ptr ds:[<&user32.ShowWindow>]

                                     //      FF25 08204000

00401074      FF25 00204000        jmp    dword ptr ds:[<&kernel32.ExitProcess>]

                  //不变

完整16进制代码如下:

6A 00 680B 30 40 00 E8 57 00 00 00 A3 19 30 40

00 6A 00FF 35 19 30 40 00 E8 51 00 00 00 6A 00

FF 35 1930 40 00 E8 32 00 00 00 6A 00 6A 00 68

00 30 4000 6A 00 E8 2E 00 00 00 6A 05 FF 35 19

30 40 00E8 27 00 00 00 6A 01 FF 35 19 30 40 00

E8 08 0000 00 6A 01 E8 19 00 00 00 CC FF 25 14

20 40 00FF 25 10 20 40 00 FF 25 0C 20 40 00 FF

25 08 2040 00 FF 25 00 20 40 00

完整指令如下:

地址        十六进制数据            指令          注释

00401000      6A 00                push 0   ;  WindowName = NULL

00401002      68 0B304000          push    offset HelloWorld.0040300B

 ; ClassName = “Shell_TrayWnd”

00401007      E857000000          call<jmp.&user32.FindWindowA>

; USER32.FindWindowA

0040100C      A3 19304000          mov     dword ptr ds:[HelloWorld.403019], eax

00401011      6A 00                push    0

00401013      FF35 19304000        push   dword ptr ds:[HelloWorld.403019]

00401019      E8 51000000          call    <jmp.&user32.ShowWindow>

; 跳转至 user32.ShowWindow

0040101E      6A 00                push    0  ; Enable = FALSE

00401020      FF35 19304000        push   dword ptr ds:[HelloWorld.403019]

 ;  hWnd= NULL

00401026      E8 32000000          call    <jmp.&user32.EnableWindow>

; USER32.EnableWindow

0040102B      6A 00                push    0

0040102D      6A 00                push    0

0040102F      68 00304000          push    offset HelloWorld.00403000

; ASCII “HelloWorld”

00401034      6A 00                push    0

00401036      E8 2E000000          call    <jmp.&user32.MessageBoxA>

; 跳转至user32.MessageBoxA

0040103B      6A 05                push    5

0040103D      FF35 19304000        push   dword ptr ds:[HelloWorld.403019]

00401043      E8 27000000          call    <jmp.&user32.ShowWindow>

 ; 跳转至user32.ShowWindow

00401048      6A 01                push    1   ; Enable = TRUE

0040104A      FF35 19304000        push   dword ptr ds:[HelloWorld.403019]

; hWnd = NULL

00401050      E8 08000000          call    <jmp.&user32.EnableWindow>

; USER32.EnableWindow

00401055      6A 01                push    1 ; ExitCode = 1

00401057      E8 19000000          call    <jmp.&kernel32.ExitProcess>

 ;  KERNEL32.ExitProcess

0040105C      CC                   int3

0040105D      FF25 14204000        jmp    dword ptr ds:[<&user32.EnableWindow>]

00401063      FF25 10204000        jmp    dword ptrds:[<&user32.FindWindowA>]

00401069      FF25 0C204000        jmp    dword ptr ds:[<&user32.MessageBoxA>]

0040106F      FF25 08204000        jmp    dword ptr ds:[<&user32.ShowWindow>]

00401075      FF25 00204000        jmp    dword ptr ds:[<&kernel32.ExitProcess>]

修改之后截图如下:

      

然后修改IMAGE_SECTION_HEADER(.text).VirtualSize(文件偏移1B0H)=7BH

再然后,就修改成功了,可以双击运行了。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

 
Free Web Hosting