发信人: 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

|