发信人: rufi (如飞), 信区: Arch_Compiler
标 题: 最短小的PE文件之破译
发信站: 日月光华 (2004年03月24日23:45:03 星期三), 站内信件
最短小的PE文件之破译
研究PE格式是从看到chsoft的说明档开始的:
chsoft (Get busy living or get busy dying) 共上站 2086 次 [狮子座]
上 次 在:[2004年03月24日10:54:22 星期三] 从 [10.100.118.60] 到本站一游。
目前在线:[讯息器:(打开) 呼叫器:(打开)] 表现值:[资深人士] 信箱:[ ]
文 章 数:[3549] 经 验 值:[# ] 生命力:[149]
目前 chsoft 状态如下:
品味文章 览新文章
史上最短小精悍的PE File完整版
00000000h: 4D 5A B8 EC 00 40 00 E9 B0 00 00 00 50 45 00 00 4C 01 01 00
00000014h: 75 73 65 72 33 32 2E 64 6C 6C 00 00 C8 00 03 01 0B 01 00 00
00000028h: 00 10 00 00 00 10 00 00 00 00 00 00 02 00 00 00 02 00 00 00
0000003Ch: 0C 00 00 00 00 00 40 00 00 10 00 00 00 02 00 00 02 01 00 00
00000050h: 00 00 00 00 04 00 00 00 00 00 00 00 00 20 00 00 00 02 00 00
00000064h: 00 00 00 00 02 00 00 00 00 00 10 00 00 20 00 00 00 00 10 00
00000078h: 00 10 00 00 00 00 00 00 0D 00 00 00 00 00 00 00 00 00 00 00
0000008Ch: 94 00 00 00 28 00 00 00 00 00 00 00 00 00 00 00 FF FF FF FF
000000A0h: 14 00 00 00 4C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
000000B4h: 00 00 00 00 00 00 00 00 6A 00 50 50 6A 00 FF 15 4C 00 40 00
000000C8h: C3 90 90 90 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
000000DCh: 00 00 00 00 00 00 00 00 94 00 00 00 28 00 00 00 48 65 6C 6C
000000F0h: 6F 21 00 00 00 10 00 00 00 10 00 00 00 00 00 00 00 00 00 00
00000104h: 4D 65 73 73 61 67 65 42 6F 78 41 00 60 00 00 E0
共276个字节,猜猜看运行结果是什么?
这个文件字节数不多,分析起来不是很难,分析一个标准的PE文件反而花了很多的时间.
搞清楚标准的PE格式之后,对这个文件的机理也就明白了.
下面是破译出来的源程序:
org 0x400000 ;ImageBase
origin:
DOS_MZ_header:
.e_magic db "MZ"
start:
use32
mov eax,Section_Table.Name ; ASCII "Hello!"
jmp main
PE_header:
.Signature db "PE",0,0
FileHeader:
.Machine dw 0x014C ;Machine = IMAGE_FILE_MACHINE_I386
(14Ch)
.NumberOfSections dw 0x01
.TimeDateStamp dd "user" ;db "user32.dll",0
.PointerToSymbolTable dd "32.d"
.NumberOfSymbols dd "ll"
.SizeOfOptionalHeader dw 0x00C8
.Characteristics dw 0x0103 ;exe or dll
OptionalHeader: ;OptionalHeader has 31 fields
.Magic dw 0x010B
.MajorLinkerVersion db 0
.MinerLinkerVersion db 0
.SizeOfCode dd 0x1000
.SizeOfInitializedData dd 0x1000
.SizeOfUnInitializedData dd 0
.AddressOfEntryPoint dd start-origin
.BaseOfCode dd start-origin
.BaseOfData dd PE_header-origin ;e_lfanew
.ImageBase dd origin
.SectionAlignment dd 0x1000
.FileAlignment dd 0x0200
messagebox:
.MajorOSVersion dw 0x0102 ;point to dword before "MessageBoxA"
.MinorOSVersion dw 0x0000
.MajorImageVersion dw 0
.MinorImageVersion dw 0
.MajorSubSystemVerion dw 4
.MinorSubSystemVerion dw 0
.Win32VersionValue dd 0
.SizeOfImage dd 0x2000
.SizeOfHeaders dd 0x0200
.CheckSum dd 0
.SubSystem dw 2
.DllCharacteristics dw 0
.SizeOfStackReserve dd 0x100000
.SizeOfStackCommit dd 0x2000
.SizeOfHeapReserve dd 0x100000
.SizeOfHeapRCommit dd 0x1000
.LoaderFlags dd 0
.NumberOfDataDirectories dd 0x0D ;13
Data_Directories:
.Export_Table dd 0,0 ; Rva,Size
.Import_Table dd 0x94,0x28 ; Rva,Size
.Resource_Table dd 0,0 ; Rva,Size
.Exception_Table dd 0xFFFFFFFF,0x14 ; Rva,Size
.Security_Table dd 0x4C,0 ; Rva,Size
.Relocation_Table dd 0,0 ; Rva,Size
.Debug dd 0,0 ; Rva,Size
;.Description dd 0x5050006A,0x15FF006A ; Rva,Size
;.Global_PTR dd 0x0040004C,0x909090C3 ; Rva,Size
main:
PUSH 0 ; /Style = MB_OK|M
PUSH EAX ; |Title
PUSH EAX ; |Text
PUSH 0 ; |hOwner = NULL
CALL DWORD [DS:messagebox] ; \MessageBoxA
RETN
NOP
NOP
NOP
.TLS_Table dd 0,0 ; Rva,Size
.Load_Config_Table dd 0,0 ; Rva,Size
.Bound_Import dd 0,0 ; Rva,Size
.ImportAddressTable dd 0x94,0x28 ; Rva,Size
Section_Table:
.Name db "Hello!",0,0
.VirtualSize dd 0x1000
.VirtaulAddress dd 0x1000
.SizeOfRawData dd 0
.PointerToRawData dd 0 ; after five dwords, appear
"user32.dll"
.PointerToRelocations dd "Mess" ; db "MessageBoxA",0
.PointerToLinenumbers dd "ageB"
.NumberOfRelocations dw "ox"
.NumberOfLinenumbers dw "A"
.Characteristics dd 0xE0000060
编译后就得到了那276个字节,运行的结果是显示一个标题和内容都要是"Hello!"的消息
框.
分析这个源程序就会发现:
1.程序的入口点在DOS header内,之后又跳转到Data_Directories的Debug之后,于是
Data_Directories的Description和Global_PTR中的内容为Code.
2.PE header的BaseOfData字段同时又是DOS header的
e_lfanew字段,指向PE header的位置.
3.NumberOfDataDirectories设为了13,而正常情况下为16.
4.Section_Table中只有一个节,而这个节内容分散在前面的数据中,以致于整个文件的he
ader
之后没有RawData.
5.PointerToRawData为0,这样从文件开头数过5个DWORD后,找到dll的文件名.
6.Import_Table的RVA是0x94,这样Ox94之后的第5个DWORD,相当于ImageImportDescripto
r的
FirstThunk,这个字段的内容为0x4C, 而Ox4C处的字段为MajorOSVersion,所这个地方的
内容(0x0102)
相当于ThunkValue,指向一个ImageImportByName结构,0x0102处的双字节为Hint,Hint之
后的则是
函数名MessageBoxA.
概括地说,这个文件的机理就把文件头不重要的平常没有用到的字节,填充为有用的数据
或代码.
然后一些关键字段的内容为指针时,巧妙指向那些数据或代码,于是文件可以被执行.
--
add life,coding
push limits
mov reality,ideas