PE文件格式”1.9版 完整译文(三)

正如你所见,我计划只用2个节,一个用于代码,一个用于所有剩余的东西(数据、常量和输入目录等)。没有重定位和象资源之类其它东西。我也不用BSS节并将变量“written”放入已初始化数据。文件和RAM中的节对齐都是一样的(32字节);这将有助于使任务简单,否则我就得来回地计算RVA很多次。

现在我们设置数据目录,开始于0xb8字节,有0x80字节长:

地址 大小
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_EXPORT(0)
???????? ???????? ;IMAGE_DIRECTORY_ENTRY_IMPORT(1)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_RESOURCE(2)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_EXCEPTION(3)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_SECURITY(4)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_BASERELOC(5)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_DEBUG(6)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_COPYRIGHT(7)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_GLOBALPTR(8)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_TLS(9)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG(10)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT(11)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_IAT(12)
00000000 00000000 ;13
00000000 00000000 ;14
00000000 00000000 ;15

仅使用输入目录。

下一个使节头。首先我们做代码节的,代码节将包含前面所编的汇编语句。它有32字节长,所以代码节也就是这么长。节头从0x138处开始,有0x28字节长: Name 2e636f6465000000 ;".code"的ASCII码值
VirtualSize 00000000 ;未用
VirtualAddress ???????? ;待定
SizeOfRawData 20000000 ;代码的大小
PointerToRawData ???????? ;待定
PointerToRelocations00000000 ;未用
PointerToLinenumbers00000000 ;未用
NumberOfRelocations 0000 ;未用
NumberOfLinenumbers 0000 ;未用
Characteristics 20000060 ;代码节,可执行,可读

第二节将包含数据。节头开始于0x160处,有0x28字节长:

Name 2e64617461000000 ;".data"的ASCII码值
VirtualSize 00000000 ;未用
VirtualAddress ???????? ;待定
SizeOfRawData ???????? ;待定
PointerToRawData ???????? ;待定
PointerToRelocations00000000 ;未用
PointerToLinenumbers00000000 ;未用
NumberOfRelocations 0000 ;未用
NumberOfLinenumbers 0000 ;未用
Characteristics 400000c0 ;已初始化的,可读,可写

下一个字节位于0x188处,但节需要按32字节(的倍数)对齐(因为我是这样选择的),所以我们需要添一些(0)字节直到0x1a0处:

000000000000 ;填充的
000000000000
000000000000
000000000000

现在第一节,就是上面所汇编的代码节,“到”了。它开始于0x1a0处,有0x20字节长:

6A00 ;push 0x00000000
68???????? ;push offset_written
6A0D ;push 0x0000000d
68???????? ;push offsethello_string
6AF5 ;push 0xfffffff5
2EFF15???????? ;call dwordptrcs:__imp__GetStdHandle@4
50 ;push eax
2EFF15???????? ;call dwordptrcs:__imp__WriteConsoleA@20
C3 ;ret

因为这一节的长度(刚好32字节),在下一节(数据节)前我们不需要填充任何字节。下一节到了,从0x1c0处开始:

68656C6C6F2C20776F726C640A ;"hello,world "的ASCII码值
000000 ;填充几个0以和_written对齐
00000000 ;_written

现在剩下的只有输入目录了。本文件将从"kernel32.dll"库中输入2个函数,输入目录将从本节的变量后面立即开始。首先我们先将上面的数据按32字节对齐:

000000000000000000000000 ;填充的

在0x1e0处开始输入描述(IMAGE_IMPORT_DESCRIPTOR):

OriginalFirstThunk ???????? ;待定
TimeDateStamp 00000000 ;未绑定
ForwarderChain ffffffff ;无中转
Name ???????? ;待定
FirstThunk ???????? ;待定

我们需要用一个0字节项来结束输入目录(我们现在位于0x1f4):

OriginalFirstThunk 00000000 ;结束符号
TimeDateStamp 00000000 ;
ForwarderChain 00000000 ;
Name 00000000 ;
FirstThunk 00000000 ;

现在只剩下DLL名字,还有2个换长,以及换长数据和函数名字了。但现在我们真的很快就要完成了。

DLL名字,以0结尾,开始于0x208处:

6b65726e656c33322e646c6c00 ;"kernel32.dll"的ASCII码值
000000 ;填充到32位边界

原始第一个换长,开始于0x218处:

AddressOfData ???????? ;"WriteConsoleA"函数名的RVA
AddressOfData ???????? ;"GetStdHandle"函数名的RVA
00000000 ;结束符号

第一个换长就是同样的列表,开始于0x224处:

(__imp__WriteConsoleA@20,at0x224)
AddressOfData ???????? ;"WriteConsoleA"函数名的RVA
(__imp__GetStdHandle@4,at0x228)
AddressOfData ???????? ;"GetStdHandle"函数名的RVA
00000000 ;结束符号

现在剩下的只有输入名字(IMAGE_IMPORT_BY_NAME)形式的两个函数名了。我们现处于0x230字节。

0100 ;序数,不需要正确
5772697465436f6e736f6c654100 ;"WriteConsoleA"的ASCII码值
0200 ;序数,不需要正确
47657453746448616e646c6500 ;"GetStdHandle"的ASCII码值

Ok,这就全部结束了。下一个字节,我们并不真正需要,是0x24f。我们必须将节填充到0x260处:

00000000000000000000000000000000;填充的
00

------------

我们已经完成了。因为我们已经知道了所有的字节偏移量,我们可以应用我们的修正到所有原先被用“??”符号标为“未知”的地址和大小了。

我将不强迫你一步一步地去读它(很好懂的),只直接给出结果来:

------------

DOS-头,开始于0x0:

00|4d5a0000000000000000000000000000
10|00000000000000000000000000000000
20|00000000000000000000000000000000
30|00000000000000000000000040000000

签名,开始于0x40:

50450000

文件头,开始于0x44:

Machine 4c01 ;i386
NumberOfSections 0200 ;代码和数据
TimeDateStamp 00000000;谁管它?
PointerToSymbolTable 00000000;未用
NumberOfSymbols 00000000;未用
SizeOfOptionalHeader e000 ;常量
Characteristics 0201 ;可执行于32位机器上

可选头,开始于0x58:

Magic 0b01 ;常量
MajorLinkerVersion 00 ;我是0.0版:-)
MinorLinkerVersion 00 ;
SizeOfCode 20000000;32字节代码
SizeOfInitializedData a0000000;数据节大小
SizeOfUninitializedData 00000000;我们没有BSS节
AddressOfEntryPoint a0010000;代码节的开始处
BaseOfCode a0010000;代码节的RVA
BaseOfData c0010000;数据节的RVA
ImageBase 00001000;1MB,任意选择
SectionAlignment 20000000;32字节对齐
FileAlignment 20000000;32字节对齐
MajorOperatingSystemVersion 0400 ;NT4.0
MinorOperatingSystemVersion 0000 ;
MajorImageVersion 0000 ;0.0版本
MinorImageVersion 0000 ;
MajorSubsystemVersion 0400 ;Win324.0
MinorSubsystemVersion 0000 ;
Win32VersionValue 00000000;未用?
SizeOfImage c0000000;所有节大小的总数
SizeOfHeaders a0010000;第一节的偏移量
CheckSum 00000000;非驱动程序不须用
Subsystem 0300 ;Win32控制台程序
DllCharacteristics 0000 ;未用(不是一个DLL)
SizeOfStackReserve 00001000;1MB栈
SizeOfStackCommit 00100000;开始时4KB
SizeOfHeapReserve 00001000;1MB堆
SizeOfHeapCommit 00100000;开始时4KB
LoaderFlags 00000000;未知
NumberOfRvaAndSizes 10000000;常量

数据目录,开始于0xb8:

地址 大小
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_EXPORT(0)
e0010000 6f000000 ;IMAGE_DIRECTORY_ENTRY_IMPORT(1)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_RESOURCE(2)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_EXCEPTION(3)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_SECURITY(4)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_BASERELOC(5)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_DEBUG(6)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_COPYRIGHT(7)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_GLOBALPTR(8)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_TLS(9)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG(10)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT(11)
00000000 00000000 ;IMAGE_DIRECTORY_ENTRY_IAT(12)
00000000 00000000 ;13
00000000 00000000 ;14
00000000 00000000 ;15

节头(代码节),开始于0x138:

Name 2e636f6465000000 ;".code"
VirtualSize 00000000 ;未用
VirtualAddress a0010000 ;代码节的RVA
SizeOfRawData 20000000 ;代码的大小
PointerToRawData a0010000 ;代码节的文件偏移量
PointerToRelocations00000000 ;未用
PointerToLinenumbers00000000 ;未用
NumberOfRelocations 0000 ;未用
NumberOfLinenumbers 0000 ;未用
Characteristics 20000060 ;代码节,可执行,可读

节头(数据节),开始于0x160:

Name 2e64617461000000 ;".data"
VirtualSize 00000000 ;未用
VirtualAddress c0010000 ;数据节的RVA
SizeOfRawData a0000000 ;数据节的大小
PointerToRawData c0010000 ;数据节的文件偏移量
PointerToRelocations00000000 ;未用
PointerToLinenumbers00000000 ;未用
NumberOfRelocations 0000 ;未用
NumberOfLinenumbers 0000 ;未用
Characteristics 400000c0 ;已初始化,可读,可写
(填充)
000000000000 ;填充的
000000000000
000000000000
000000000000

代码节,开始于0x1a0:

6A00 ;push 0x00000000
68d0011000 ;push offset_written
6A0D ;push 0x0000000d
68c0011000 ;push offsethello_string
6AF5 ;push 0xfffffff5
2EFF1528021000 ;call dwordptrcs:__imp__GetStdHandle@4
50 ;push eax
2EFF1524021000 ;call dwordptrcs:__imp__WriteConsoleA@20
C3 ;ret

数据节,开始于0x1c0:

68656C6C6F2C20776F726C640A ;"hello,world "
000000 ;填充到和_written对齐
00000000 ;_written

填充:

000000000000000000000000 ;填充的

输入描述(IMAGE_IMPORT_DESCRIPTOR),开始于0x1e0:

OriginalFirstThunk 18020000 ;原始第一个换长的RVA
TimeDateStamp 00000000 ;未绑定
ForwarderChain ffffffff ;-1,无中转
Name 08020000 ;DLL名字的RVA
FirstThunk 24020000 ;第一个换长的RVA

结束标志(0x1f4):

OriginalFirstThunk 00000000 ;结束标志
TimeDateStamp 00000000 ;
ForwarderChain 00000000 ;
Name 00000000 ;
FirstThunk 00000000 ;

DLL名字,开始于0x208:

6b65726e656c33322e646c6c00 ;"kernel32.dll"
000000 ;填充到32位边界

原始第一个换长,开始于0x218:

AddressOfData 30020000 ;函数名"WriteConsoleA"的RVA
AddressOfData 40020000 ;函数名"GetStdHandle"的RVA
00000000 ;结束标志

第一个换长,开始于0x224:

AddressOfData 30020000 ;函数名"WriteConsoleA"的RVA
AddressOfData 40020000 ;函数名"GetStdHandle"的RVA
00000000 ;结束标志

输入函数名称(IMAGE_IMPORT_BY_NAME),开始于0x230:

IMAGE_IMPORT_BY_NAME,开始于0x240:

0200 ;序数,不需要正确
47657453746448616e646c6500 ;"GetStdHandle"的ASCII码值
(填充)
00000000000000000000000000000000;填充的
00

第一个未使用字节开始于:0x260

--------------

噢,这个文件能在NT上却不能在windows95上运行。windows95不能运行按32字节节对齐的应用程序,它要求节对齐为4KB;并且很明显的,文件对齐也应为512字节。因此要想在windows95上运行,你得插入很多的0字节(为了对齐)并调整RVA。感谢D.Binette在windows95上的(运行)试验。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值