主讲:林春蔷职称:讲师成都信息工程学院信息对抗教研室通过一个实例改变程序的执行流程,从而加深大家对PE文件格式的理解。WinhexLordPEOllyICE工具zzzzzzzzz为什么要重点学习这种文件格式?portableexecutable可移植可执行跨Win32平台的文件格式所有Win32执行体(exe、dll、kernelmodedrivers)1.PE文件格式总体结构2.MS-DOSMZ文件头+DOSStub3.PE文件头4.节表5.节MZ文件头:DOSMZHEADERDOS插桩程序:DOSStubIMAGE_SECTION_HEADERIMAGE_SECTION_HEADERIMAGE_SECTION_HEADERIMAGE_SECTION_HEADER.text.data.edata.reloc...COFF行号COFF符号表CodeView调试信息PE文件标志:“PE\0\0”映像文件头:IMAGE_FILE_HEADER可选映像头:IMAGE_OPTIONAL_HEADER32数据目录表:IMAGE_DATA_DIRECTORYDOS头PE文件头节表(SectionTable)节(Section)调试信息文件头文件尾hello-2.5.exe“PE00”2020年3月13日第8页MSDOSHeader所有MS-DOS兼容的可执行文件都将这个值设为0x5A4D(MZ)4字节文件偏移地址定位PE头部MS-DOS头部占据了PE文件的头64个字节(4*16=64)◦USHORTe_magic;//魔数=MZMZ文件格式创始人,微软资深工程师MarkZbikowski的缩写◦LONGe_lfanew;//e_lfanew成员用于定位PE头。该字段位于3CH处,该位置给出了PE文件头部的开始位置。在本例中,PE文件头部开始位置为0B0H。Signature一dword类型,值为50h,45h,00h,00h(PE\0\0)。本域为PE标记,我们可以此识别给定文件是否为有效PE文件。◦这个字串在文件中的位置(e_lfanew)可以在DOS程序头中找到它的指针,它占用四个字节,位于文件开始偏移3CH字节中。魔术数字定位PE头部PE文件标志“PE\0\0”“PE00”魔术数字魔术数字魔术数字该结构域包含了关于PE文件物理分布的信息,比如节数目、文件执行机器等。它实际上是结构IMAGE_FILE_HEADER的简称。2020年3月13日第14页WORDMachine;该程序要执行的环境及平台WORDNumberOfSections;文件中节的个数DWORDTimeDateStamp;文件建立的时间DWORDPointerToSymbolTable;COFF符号表的偏移DWORDNumberOfSymbols;符号数目WORDSizeOfOptionalHeader;可选头的长度WORDCharacteristics;文件属性标志集合PE头部1:映像文件头名字描述AddressOfEntryPoint*PE装载器准备运行的PE文件的第一个指令的RVA。若要改变整个执行的流程,可以将该值指定到新的RVA,这样新RVA处的指令首先被执行。(病毒感染中通用关键字段)ImageBasePE文件的优先装载地址。比如,如果该值是400000h,PE装载器将尝试把文件装到虚拟地址空间的400000h处。若该地址区域已被其他模块占用,那PE装载器会选用其他空闲地址。SectionAlignment内存中节对齐的粒度。FileAlignment文件中节对齐的粒度。名字描述MajorSubsystemVersionMinorSubsystemVersionwin32子系统版本。若PE文件是专门为Win32设计的,该子系统版本必定是4.0否则对话框不会有3维立体感。SizeOfImage内存中整个PE映像体的尺寸。SizeOfHeaders所有头+节表的大小。可以以此值作为PE文件第一节的文件偏移量。SubsystemNT用来识别PE文件属于哪个子系统。DataDirectory一个IMAGE_DATA_DIRECTORY结构数组。每个结构给出一个重要数据结构的RVA,比如引入地址表等。◦RVA:RelativeVirtualAddress,表示相对虚拟地址。它是相对内存中ImageBase的偏移位置。◦VA:VirtualAddress,表示虚拟地址,即装载到内存中之后的位置。(VA=ImageBase+RVA)◦举例说明,如果PE文件装入内存空间的400000h处,且进程从虚拟地址401000h开始执行,我们可以说进程执行起始地址在RVA1000h。每个RVA都是相对于模块的起始VA的。对齐◦内存中节对齐的粒度◦文件中节对齐的粒度问题1:桶的容量为100升,现有367升水,请问需要使用多少个桶?问题2:代码节的代码实际长度为0x46字节,文件中节对齐粒度为0x200,内存中节对齐粒度为0x1000字节,请问代码节在文件和内存中分别占用多少字节?◦为什么PE文件中有很多“00”字节?一个IMAGE_DATA_DIRECTORY数组,里面放的是这个可执行文件的一些重要部分的RVA和尺寸,目的是使可执行文件的装入更快,数组的项数由上一个域给出。IMAGE_DATA_DIRECTORY包含有两个域,如下:IMAGE_DATA_DIRECTORYVitualAddressDD?SizeDD?IMAGE_DATA_DIRECTORYENDS节表其实就是紧挨着PEheader的一结构数组。◦该数组成员的数目由Fileheader(IMAGE_FILE_HEADER)结构中NumberOfSections域的域值来决定。节表结构又命名为IMAGE_SECTION_HEADER(每个结构占用28H)。结构中放的是一个节的信息,如名字、地址、长度、属性等。2020年3月13日第25页节表UCHARName[8];//节名union{ULONGPhysicalAddress;//OBJ文件中表示本节物理地址ULONGVirtualSize;//EXE文件中表示节的实际字节数}Misc;ULONGVirtualAddress;//本节的RVAULONGSizeOfRawData;//本节在文件中的尺寸ULONGPointerToRawData;//本节在文件中的偏移地址ULONGPointerToRelocations;//OBJ文件中表示本节重定位信//息的偏移,EXE文件中无意义ULONGPointerToLinenumbers;//行号偏移USHORTNumberOfRelocations;//重定位项的数目USHORTNumberOfLinenumbers;//本节在行号表中的行号数目ULONGCharacteristics;//节属性代码SectionAlignmentFileAlignment2020年3月13日第27页如:80000000H就表示这段内存是可写的,40000000H就表示这段内存是可读的一个节可包含多个属性,对应位为1表示有此属性如果期望一个节的数据可读可写,则它的属性代码应该是:?节的属性节的属性代表了该节所在内存区块的权限,其中每一位都代表了一种权限或属性的启开和关闭:属性为:60000020H,请问是什么节?属性为:C0000040H,请问是什么节?请问病毒代码会为自己设置什么样的属性值?2020年3月13日第29页装载器如何把一个节映射到内存中?获取文件节的数目(NumberOfSections)定位节表(SizeOfHeaders)获得该节在磁盘上的存储位置及大小(PointerToRawData,SizeOfRawData)把该节映射进内存(VirtualAddress,ImageBase)设置该节的属性(Characteristics)“节(Section)”跟在节表之后,一般PE文件都有几个“节”。比较常见的有:代码节已初始化的数据节未初始化的数据节引入函数节引出函数节资源节代码节一般名为.text或CODE,该节含有程序的可执行代码。每个PE文件应该都有代码节这个节一般取名为.data或DATA已初始化的数据节中放的是在编译时刻就已确定的数据。如HelloWorld中的字符串“HelloWorld!”。这个节的名称一般叫.bbs。这个节里放有未初始化的全局变量和静态变量。◦例如staticintk;“该节的'PointerToRawData'为0,表明其内容不在文件内,特征位'IMAGE_SCN_CNT_UNINITIALIZED_DATA'指明所有内容必须在加载时间置0。这意味着有节头,但没有节在文件内,该节被加载器创建,并且包含全0字节。其长度是'SizeOfUninitializedData'.典型名字如'.bss','BSS'。这个节一般名为.rdata,也叫引入函数节。◦一个引入函数是被某模块调用的但又不在调用者模块中的函数◦它可以用来从其它(系统或第三方写的)DLL中引入函数,例如user32.dll、gdi32.dll等。一系列DWORD的数组◦在文件中时,每个双字中存放着对应引入函数的函数名字符串的RVA◦在内存中时,每个双字中存放着对应引入函数的地址。请问:ExitProcess函数的地址可能在不同的操作系统中各不相同,但为什么我们写的程序可以在不同的系统中正常运行?输入目录是一个IMAGE_IMPORT_DESCRIPTORs数组,每个DLL都使用一个元素,该列表中止于一个全0的数组元素。一个IMAGE_IMPORT_DESCRIPTOR是一个具有如下元素的结构:IMAGE_IMPORT_DESCRIPTORSTRUCTunionCharacteristicsdd?OriginalFirstThunkdd?//指向引入函数名列表或序号列表EndsTimeDateStampdd?ForwarderChaindd?Name1dd?//指向dll函数名FirstThunkdd?//指向IAT表IMAGE_IMPORT_DESCRIPTORENDSData最高位:为1时,表示通过序号引入函数为0时,表示通过函数名引入kernel32.dll为dll文件名◦8000为Hints,ExitProcess为引入函数名user32.dll为dll文件名◦6202为Hints,wsprintfA为引入函数名◦9D01为Hints,MessageBoxA为引入函数名IMAGE_IMPORT_DESCRIPTORIMAGE_IMPORT_BY_NAMEOriginalFirstThunkTimeDatestampForwardChainNameFirstThunkIMAGE_THUNK_DATAIMAGE_THUNK_DATA……01函数123函数2……IMAGE_THUNK_DATAIMAGE_THUNK_DATA……KERNEL32.DLLIMAGE_IMPORT_DESCRIPTORIMAGE_IMPORT_BY_NAMEOriginalFirstThunkTimeDatestampForwardChainNameFirstThunkIMAGE_THUNK_DATAIMAGE_THUNK_DATA……01函数123函数2……IMAGE_THUNK_DATAIMAGE_THUNK_DATA……KERNEL32.DLL函数1地址函数2地址……2020年3月13日第49页2020年3月13日第50页什么是引入函数?这些函数一般从哪里引入?为什么要设计引入函数节?目的何在?ExitProcess7081CDDAMessageBoxA77D504EAwsprintfA77D1A8AD引出函数节一般名为.edata,这是本文件向其他程序提供调用函数的列表所在的“索引”及具体代码实现。(这个节一般用在DLL中,EXE也