PE文件能够多小?? 一次一次的打破了我的想象, 网上有人发了133B的PE文件, 我就在想他是如何做到的? 分析了下. 相当的给力. 不知道还能不能够再小?

网上不少的手写PE文件的, 不过大多200B以上. 原来我自己也倒腾过PE文件, 不过都是按照套路一个一个字段的填写. 昨天偶然看了下人家写的. 那是多么的给力啊, IMAGE_DOS_HEADER和IMAGE_NT_HEADERS进行了重叠. 重叠还是小Case. 我们知道IMAGE_NT_HEADERS的IMAGE_OPTIONAL_HEADER32里面有非常多字段是用不到的, 所以即使IMAGE_NT_HEADERS和IMAGE_DOS_HEADER重叠也是节约不了多少空间的. 那么IMAGE_OPTIONAL_HEADER32头里面那些字段还应该怎么利用呢? 答案大牛已经给出了,把代码,和导入表, 字符串资源全部整合进去, 打造出来的PE文件就一个IMAGE_DOS_HEADER + IMAGE_NT_HEADERS的大小, 给力, 非常的给力.

特别是到最后这个地方, Exporot导出表居然只有一个字节?? 我倒. 以前还不知道导出表一个字节也可以跑. 因为原来是两个dword类型, 一个是偏移一个是大小, 他大小直接省略, 偏移用了一个字节. 可以吗? 这样可以吗? 事实证明这个程序确实是可以跑起来的. 只能够说明作者对PE文件, 和Windows的装载机制很了解了.

PE文件的代码是从njhhack的blog上down下来的, 不过是TASM的语法, 和Masm虽然差别不是很大, 不过我也懒得去倒腾Tasm了. 所以我修改成了Masm的语法, 我至今不知道Masm里面如何才能够生成一个没有任何东西的.exe文件, 最后我只能退而求其次了. 使用com文件, 这个好使. 你搞的是什么, 最后就是什么, 一点东西都不多. 原来Fasm一直有那么多的信仰者. 也是有道理的.. 有的时候用Masm做点规则之外的事情也是很麻烦. 比如像用Masm生成一个不带任何框架的函数, 也是很麻烦, C语言还有类似的关键字,或许Masm有这个语法. 不过也没有见人搞过. 有知道的一定告诉我哈. 不要和我说直接定义标号什么的, 我想生成一个不带框架的函数. 然后导出. 不知道怎么搞定. 扯远了, 还是看看这个PE文件吧!

参考: njhhack的专栏 绝影的blog

http://blog.csdn.net/njhhack/article/details/2120019

http://blog.csdn.net/hitetoshi/article/details/3296253

PE文件下载(直接点击里面的make.bat就可以生成一个133B的PE文件了):

MinPe.rar

看看大牛都是如何做的

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
;***************************************************************************
	;打造超小的win32 PE文件, 编译我已经都给出了, 只需要运行目录下的make.bat
	;就可以生成一个130K的PE文件, 灰常的给力啊. 
;***************************************************************************
	.386
	.model tiny
ImageBase	equ		400000h			;模块基址	
	.Code
DefineStart:
;===========================================================================
	;想要压缩PE文件首先要做的事情就是必须把Dos头和Pe头进行融合. 还有导入表,
	;好好的看了人家搞的MinPE, 真是佩服的五体投地啊, 
;===========================================================================
DosSignature		word		5a4dh           ;MZ 标志
					word		0ffffh
NtSignature			dword		4550h           ;PE 标志
Machine				word		014ch           ;Intel 80386
MumberOfSection		word		1		;节区数量
;===========================================================================
	;这里正好是IMAGE_FILE_HEADER的3个字段, 什么值都是无所谓的
;===========================================================================
User32				byte		"user32.dll", 0, 0ffh
;TimeDateStamp		dword		0		;FileHeader-->TimeDateStamp
;PointerToSymbolTable	dword		0		;FileHeader-->PointerToSymbolTable
;NumberOfSymbols	dword		0		;FileHeader-->NumberOfSymbols

SizeOfOptionalHeader	word		OptionHeaderSize;可选头大小
Characteristics		word		010fh		;属性标志(exe)
;===========================================================================
	;可选头
;===========================================================================
Magic				word		10bh		;普通可执行镜像10bh
LinkerVersion		word		0ffffh		;连接器版本, 随便
;===========================================================================
	;这里正好是IMAGE_OPTIONAL_HEADER的3个字段, 也是无所谓什么值的
;===========================================================================
SzMessageBoxA		byte		"MessageBoxA", 0
;SizeOfCode			dword		0		;OptionalHeader-->SizeOfCode
;SizeOfInitializedData	dword		0		;OptionalHeader-->SizeOfInitializedData
;SizeOfUninitializedData dword		0		;OptionalHeader-->SizeOfUninitializedData
AddressOfEntryPoint	dword		Start		;程序入口

;===========================================================================
	;这里又有2个字段是随便什么值的, 8字节不要浪费
;===========================================================================
;BaseOfCode		dword		0
;BaseOfData		dword		0
Next3:
			word		15ffh		;Call MessageBoxA
			dword		ImageBase + IAT1
	ret
			byte		0ffh
;===========================================================================			
_ImageBase			dword		ImageBase	;建议装载地址
SectionAlignment	dword		4		;内存对齐 DosHead-->e_lfanew
FileAlignment		dword		4		;文件对齐
;===========================================================================
	;这里又是可选头的2个字段什么值无所谓, 又可以填充8个字节的代码
;===========================================================================
;OperationSystemVersion	dword				;操作系统版本
;ImageVersion		dword				;用户自定义版本
Start:
	mov	eax, offset SzMessageBoxA + ImageBase
	jmp	Next1
			byte		0ffh		;补够8字节
;===========================================================================
	;这里2个字段8字节空间又可以填充一点代码	
;===========================================================================
;SubsystemVersion	dword		任意
;Win32VersionValue	dword		任意
			word		4
Next1:
	push	65
	push	eax
	push	eax
	jmp	Next2
;===========================================================================
SizeOfImage			dword		ImageSize	;任意数值,要求大于SizeOfHeaders
SizeOfHeaders		dword		FileHeaderSize	;文件头(Dos头, Pe头, 区表)大小
	OptionHeaderSize = $-Magic	
;===========================================================================
	;这里很多字段都是无所谓的, 一大片空间不能够浪费, 制造一个导入表,灰常给力
;===========================================================================
IAT:
CheckSum		dword		0		;OriginalFirstThunk(无所谓值我们有FirstThunk就够了)
Subsystem		word		2		;TimeDateStamp(无所谓值)
DllCharacteristics	word		0ffh		;
SizeOfStackReserve	dword		IAT1		;任意数值,(Virtual Size),   ForwarderChain
SizeOfStackCommit	dword		User32		;任意数值,(Virtual Address),Name1, dll名称
SizeOfHeapReserve       dword		IAT1            ;任意数值,(Raw Data Size),  FirstThunk IAT表
SizeOfHeapCommit        dword 		User32          ;任意数值,(Raw Data Offset) 
;===========================================================================
	;一个可选头就把代码和导入表全部包括进去了, 以前真是太浪费了..可耻啊
	;这里4个字节不要浪费, LoaderFlags没有什么用, 加4个字节代码
;===========================================================================
;LoaderFlags		dword		0		;调试标记, 无所谓值
Next2:
	push	0
	jmp	Next3				 	
NumberOfRvaAndSizes	dword 		2h              ;程序数据目录的项数
;===========================================================================
	;接下来的就是数据目录了
;===========================================================================
IAT1:
Ide00_Export		dword		SzMessageBoxA-2, 0;这个输出表应该没有什么意义, 占位置的
;===========================================================================
	;我倒, 5c刚好是IAT这个地方, 输出表只占用了一个字节也可以?太了解
	;windows装载了吧
;===========================================================================
Ide01_Import		byte		IAT - DefineStart
FileHeaderSize 		= $
ImageSize		= FileHeaderSize + 4
END

里面注释非常, 齐全了. 我就不多说了, 总之就是前面说的DOS头和NT头,重叠了, 然后导入表放在了可选头里面. 代码也在可选头里面, 我只是分析了下,

原作者贴了个代码, 什么也没有说, 估计他认为大家应该都是了解PE文件格式的..我就加了些注释, 应该有些帮助才是.

代码在网页上不好看, 建议直接去下载那个源代码然后分析, 条件不够啊, 我也不知道怎么倒腾WordPress, 怎么才能够搞个代码高亮舒服点的, 你要知道可要教教我!