文件和内存的直观不同
开始位置不一样
中间的0块大小不一样
数据基本一样
.dll,.sys,.exe都是4D5A(MZ)开头
.txt,.doc自己没法运行,是exe把它打开的
为什么要分节
节省硬盘空间 硬盘间隙小,内存间隙大,相同数据硬盘废的空间小
空隙也能一样(硬盘对齐=内存对齐,就不用拉伸了,节省时间,之前硬盘对齐小是因为硬盘贵,书的页,为了增加读写速度),拉伸(FileBuffer到ImageBuffer),但都是分节了
任何exe都有自己的虚拟的4GB空间(寻址范围232),高2G低2G,与内存条无关
多开(大号小号),节省内存
共用一些节
DOS头 PE头 可选PE头
e_magic e_lfanew 从文件开始算,过E8个字节,真正PE文件开始的地方,从e_lfanew到真正开始的地方DOS stub 可以写些无关的数据如编译器放进去的cannot run in DOS model,该区域也在内存中,也有地址,意味着可以塞shellcode然后执行
NT头 包含了标准PE头和可选PE头
NT头
1.50 45 00 00 DWORD SIGNATURE PE
2.接着是标准PE头
DOS头,标准PE头大小确定,DOS 64字节,PE 20字节
可选PE不确定,由标准PE头的一个成员规定
3.接着是可选PE头
SizeOfHeaders是文件对齐后,不是SectionAlignment
一个exe可以包含多个PE文件
AddressOfEntryPoint+ImageBase = 在内存里运行时的OEP(类似Main)
FileBuffer开始的位置 = 0
ImageBase = ImageBuffer的开始位置
节表 一个40字节 判断节是否是代码节不应该用名字区分,而应该用节属性
找节表的起始 DOS DOS Stub PE标记 标准PE 可选PE后
节表个数:标准PE头 NumberOfSections
Name名字8字节.text .data等,Misc可以不准确的意思是可以改动
VirtualAddress是距离imagebase的距离,应该是对齐的整数倍,文件中的偏移也是一样
若节的属性为60000020h = 20000000(可执行)+40000000(可读)+20(有可执行代码)
FileBuffer & ImageBuffer
MISC存的是在内存中真正分配的值,所以会存在大于SizeOfRawData
拷到哪:VirtualAddress
拷多大:SizeOfRawData (Misc也行,不太好)
x在imagebuffer里位置是401234,找它在文件里的位置,假设内存对齐不一样:
401234 - imagebase = 1234
1234 - 该节对应的VirtualAddress(循环看节表的各VirtualAddress,应该<1234) = 234
该节的PointerToRawData + 1234 = 它在文件里的位置
一个应用程序是由一堆PE文件组成,exe不一定等于进程,单exe,贴exe后贴dll,然后重定位之类,可以自己写dll贴在空的地方然后自己重定位dll注入
FOA 文件中的偏移
RVA = VisualAddress
VA = ImageBase + RVA
代码节空白区添加自己的shellcode
将OEP改为call shellcode这句指令的地址,执行
call shellcode
jmp 原OEP
call 硬编码E8
jmp硬编码E9
导出表(dll能供使用的函数)
可选PE的最后一个项(96字节之后),16个数组中的第一个,size可改,VitualAddress是表在内存的偏移,所以会存在转为文件的转换
导入表
可选PE的最后一个项,16个数组中的第2个
这个表不止一个,因为不止用一个dll
IAT表
所以调用的地址不在自己的进程空间而在dll的进程空间,把dll放到自己的进程空间里
4070DC(是在exe里)在文件偏移70DC处
运行前后寸的值不一样。77D5050B不在exe里,是dll,不会在编译的时候就写死messagebox的地址,所以要相对寻址下,是在dll全部贴完重定位了以后改的。Dll地址写死了不一定能占到想要的位置,占不到位置做的修改就是重定位,如果占到了重定位表没啥用