




已阅读5页,还剩7页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
关于PE可执行文件的修改 在windows9x、NT、2000下,所有的可执行文件都是基于Microsoft设计的一种新的文件格式PortableExecutableFileFormat(可移植的执行体),即PE格式。有一些时候,我们需要对这些可执行文件进行修改,下面文字试图详细的描述PE文件的格式及对PE格式文件的修改。1、 PE文件框架构成DOSMZheaderDOSstubPEheaderSectiontableSection1Section2Section.Sectionn上表是PE文件结构的总体层次分布。所有PE文件(甚至32位的DLLs)必须以一个简单的DOSMZheader开始,在偏移0处有DOS下可执行文件的“MZ标志”,有了它,一旦程序在DOS下执行,DOS就能识别出这是有效的执行体,然后运行紧随MZheader之后的DOSstub。DOSstub实际上是个有效的EXE,在不支持PE文件格式的操作系统中,它将简单显示一个错误提示,类似于字符串ThisprogramcannotruninDOSmode或者程序员可根据自己的意图实现完整的DOS代码。通常DOSstub由汇编器/编译器自动生成,对我们的用处不是很大,它简单调用中断21h服务9来显示字符串ThisprogramcannotruninDOSmode。紧接着DOSstub的是PEheader。PEheader是PE相关结构IMAGE_NT_HEADERS的简称,其中包含了许多PE装载器用到的重要域。可执行文件在支持PE文件结构的操作系统中执行时,PE装载器将从DOSMZheader的偏移3CH处找到PEheader的起始偏移量。因而跳过了DOSstub直接定位到真正的文件头PEheader。PE文件的真正内容划分成块,称之为sections(节)。每节是一块拥有共同属性的数据,比如“.text”节等,那么,每一节的内容都是什么呢?实际上PE格式的文件把具有相同属性的内容放入同一个节中,而不必关心类似“.text”、“.data”的命名,其命名只是为了便于识别,所有,我们如果对PE格式的文件进行修改,理论上讲可以写入任何一个节内,并调整此节的属性就可以了。PEheader接下来的数组结构sectiontable(节表)。每个结构包含对应节的属性、文件偏移量、虚拟偏移量等。如果PE文件里有5个节,那么此结构数组内就有5个成员。以上就是PE文件格式的物理分布,下面将总结一下装载一PE文件的主要步骤:1、PE文件被执行,PE装载器检查DOSMZheader里的PEheader偏移量。如果找到,则跳转到PEheader。2、PE装载器检查PEheader的有效性。如果有效,就跳转到PEheader的尾部。3、紧跟PEheader的是节表。PE装载器读取其中的节信息,并采用文件映射方法将这些节映射到内存,同时付上节表里指定的节属性。4、PE文件映射入内存后,PE装载器将处理PE文件中类似importtable(引入表)逻辑部分。上述步骤是一些前辈分析的结果简述。2、 PE文件头概述 我们可以在winnt.h这个文件中找到关于PE文件头的定义: typedefstruct_IMAGE_NT_HEADERS DWORDSignature; /PE文件头标志:“PE00”。在开始DOSheader的偏移3CH处所指向的地址开始 IMAGE_FILE_HEADERFileHeader;/PE文件物理分布的信息 IMAGE_OPTIONAL_HEADER32OptionalHeader;/PE文件逻辑分布的信息 IMAGE_NT_HEADERS32,*PIMAGE_NT_HEADERS32; typedefstruct_IMAGE_FILE_HEADER WORDMachine;/该文件运行所需要的CPU,对于Intel平台是14Ch WORDNumberOfSections;/文件的节数目 DWORDTimeDateStamp;/文件创建日期和时间 DWORDPointerToSymbolTable;/用于调试 DWORDNumberOfSymbols;/符号表中符号个数 WORDSizeOfOptionalHeader;/OptionalHeader结构大小 WORDCharacteristics;/文件信息标记,区分文件是exe还是dll IMAGE_FILE_HEADER,*PIMAGE_FILE_HEADER; typedefstruct_IMAGE_OPTIONAL_HEADER WORDMagic;/标志字(总是010bh) BYTEMajorLinkerVersion;/连接器版本号 BYTEMinorLinkerVersion;/ DWORDSizeOfCode;/代码段大小 DWORDSizeOfInitializedData;/已初始化数据块大小 DWORDSizeOfUninitializedData;/未初始化数据块大小 DWORDAddressOfEntryPoint;/PE装载器准备运行的PE文件的第一个指令的RVA,若要改变整个执行的流程,可以将该值指定到新的RVA,这样新RVA处的指令首先被执行。(许多文章都有介绍RVA,请去了解) DWORDBaseOfCode;/代码段起始RVA DWORDBaseOfData;/数据段起始RVA DWORDImageBase;/PE文件的装载地址 DWORDSectionAlignment;/块对齐 DWORDFileAlignment;/文件块对齐 WORDMajorOperatingSystemVersion;/所需操作系统版本号 WORDMinorOperatingSystemVersion;/ WORDMajorImageVersion;/用户自定义版本号 WORDMinorImageVersion;/ WORDMajorSubsystemVersion;/win32子系统版本。若PE文件是专门为Win32设计的 WORDMinorSubsystemVersion;/该子系统版本必定是4.0否则对话框不会有3维立体感 DWORDWin32VersionValue;/保留 DWORDSizeOfImage;/内存中整个PE映像体的尺寸 DWORDSizeOfHeaders;/所有头+节表的大小 DWORDCheckSum;/校验和 WORDSubsystem;/NT用来识别PE文件属于哪个子系统 WORDDllCharacteristics;/ DWORDSizeOfStackReserve;/ DWORDSizeOfStackCommit;/ DWORDSizeOfHeapReserve;/ DWORDSizeOfHeapCommit;/ DWORDLoaderFlags;/ DWORDNumberOfRvaAndSizes;/ IMAGE_DATA_DIRECTORYDataDirectoryIMAGE_NUMBEROF_DIRECTORY_ENTRIES; /IMAGE_DATA_DIRECTORY结构数组。每个结构给出一个重要数据结构的RVA,比如引入地址表等 IMAGE_OPTIONAL_HEADER32,*PIMAGE_OPTIONAL_HEADER32; typedefstruct_IMAGE_DATA_DIRECTORY DWORDVirtualAddress;/表的RVA地址 DWORDSize;/大小 IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY; PE文件头后是节表,在winnt.h下如下定义 typedefstruct_IMAGE_SECTION_HEADER BYTENameIMAGE_SIZEOF_SHORT_NAME;/节表名称,如“.text” union DWORDPhysicalAddress;/物理地址 DWORDVirtualSize;/真实长度 Misc; DWORDVirtualAddress;/RVA DWORDSizeOfRawData;/物理长度 DWORDPointerToRawData;/节基于文件的偏移量 DWORDPointerToRelocations;/重定位的偏移 DWORDPointerToLinenumbers;/行号表的偏移 WORDNumberOfRelocations;/重定位项数目 WORDNumberOfLinenumbers;/行号表的数目 DWORDCharacteristics;/节属性 IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER; 以上结构就是在winnt.h中关于PE文件头的定义,如何我们用C/C+来进行PE可执行文件操作,就要用到上面的所有结构,它详细的描述了PE文件头的结构。 3、修改PE可执行文件 现在让我们把一段代码写入任何一个PE格式的可执行文件,代码如下: -test.asm- .386p .modelflat,stdcall optioncasemap:none includemasm32includewindows.inc includemasm32includeuser32.inc includelibmasm32libuser32.lib .code start: INVOKEMessageBoxA,0,0,0,MB_ICONINFORMATIONorMB_OK ret endstart 以上代码只显示一个MessageBox框,编译后得到二进制代码如下: unsignedcharwriteline18= 0x6a,0x40,0x6a,0x0,0x6a,0x0,0x6a,0x0,0xe8,0x01,0x0,0x0,0x0,0xe9,0x0,0x0,0x0,0x0 ; 好,现在让我们看看该把这些代码写到那。现在用Tdump.exe显示一个PE格式得可执行文件信息,可以发现如下描述: Objecttable: #NameVirtSizeRVAPhysSizePhysoffFlags - 01.text0000CCC0000010000000CE000000060060000020CER 02.data000046280000E00000002C000000D400C0000040IRW 03.rsrc000003C800013000000004000001000040000040IR Keytosectionflags: C-containscode E-executable I-containsinitializeddata R-readable W-writeable 上面描述此文件中存在3个段及每个段得信息,实际上我们的代码可以写入任何一个段,这里我选择“.text”段。用如下代码得到一个PE格式可执行文件的头信息: /writePE.cpp #include #include #include #include #include #include unsignedcharwriteline18= 0x6a,0x40,0x6a,0x0,0x6a,0x0,0x6a,0x0,0xe8,0x01,0x0,0x0,0x0,0xe9,0x0,0x0,0x0,0x0 ; DWORDspace; DWORDentryaddress; DWORDentrywrite; DWORDprogRAV; DWORDoldentryaddress; DWORDnewentryaddress; DWORDcodeoffset; DWORDpeaddress; DWORDflagaddress; DWORDflags; DWORDvirtsize; DWORDphysaddress; DWORDphyssize; DWORDMessageBoxAadaddress; intmain(intargc,char*argv) HANDLEhFile,hMapping; void*basepointer; FILETIME*Createtime; FILETIME*Accesstime; FILETIME*Writetime; Createtime=newFILETIME; Accesstime=newFILETIME; Writetime=newFILETIME; if(hFile=CreateFile(argv1,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,0,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,0)=INVALID_HANDLE_VALUE)/打开要修改的文件 puts(couldnotopen); returnEXIT_FAILURE; if(!GetFileTime(hFile,Createtime,Accesstime,Writetime) printf(nerrorgetfiletime:%dn,GetLastError(); /得到要修改文件的创建、修改等时间 if(!(hMapping=CreateFileMapping(hFile,0,PAGE_READONLY|SEC_COMMIT,0,0,0) puts(mappingfailed); CloseHandle(hFile); returnEXIT_FAILURE; if(!(basepointer=MapViewOfFile(hMapping,FILE_MAP_READ,0,0,0) puts(viewfailed); CloseHandle(hMapping); CloseHandle(hFile); returnEXIT_FAILURE; /把文件头映象存入baseointer CloseHandle(hMapping); CloseHandle(hFile); map_exe(basepointer);/得到相关地址 UnmapViewOfFile(basepointer); printaddress(); printf(nn); if(space50) printf(n空隙太小,数据不能写入.n); else writefile();/写文件 if(hFile=CreateFile(argv1,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,0,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,0)=INVALID_HANDLE_VALUE) puts(couldnotopen); returnEXIT_FAILURE; if(!SetFileTime(hFile,Createtime,Accesstime,Writetime) printf(errorsettime:%dn,GetLastError(); /恢复修改后文件的建立时间等 deleteCreatetime; deleteAccesstime; deleteWritetime; CloseHandle(hFile); return0; voidmap_exe(constvoid*base) IMAGE_DOS_HEADER*dos_head; dos_head=(IMAGE_DOS_HEADER*)base; #include typedefstructPE_HEADER_MAP DWORDsignature; IMAGE_FILE_HEADER_head; IMAGE_OPTIONAL_HEADERopt_head; IMAGE_SECTION_HEADERsection_header; peHeader; #include if(dos_head-e_magic!=IMAGE_DOS_SIGNATURE) puts(unknowntypeoffile); return; peHeader*header; header=(peHeader*)(char*)dos_head+dos_head-e_lfanew);/得到PE文件头 if(IsBadReadPtr(header,sizeof(*header) puts(noPEheader,probablyDOSexecutable); return; DWORDmods; chartmpstr4=0; DWORDtmpaddress; DWORDtmpaddress1; if(strstr(constchar*)header-section_header0.Name,.text)!=NULL) virtsize=header-section_header0.Misc.VirtualSize; /此段的真实长度 physaddress=header-section_header0.PointerToRawData; /此段的物理偏移 physsize=header-section_header0.SizeOfRawData; /此段的物理长度 peaddress=dos_head-e_lfanew; /得到PE文件头的开始偏移 peHeaderpeH; tmpaddress=(unsignedlong)&peH; /得到结构的偏移 tmpaddress1=(unsignedlong)&(peH.section_header0.Characteristics); /得到变量的偏移 flagaddress=tmpaddress1-tmpaddress+2; /得到属性的相对偏移 flags=0x8000;/一般情况下,“.text”段是不可读写的,如果我们要把数据写入这个段需要改变其属性,实际上这个程序并没有把数据写入“.text”段,所以并不需要更改,但如果你实现复杂的功能,肯定需要数据,肯定需要更改这个值, space=physsize-virtsize; /得到代码段的可用空间,用以判断可不可以写入我们的代码 /用此段的物理长度减去此段的真实长度就可以得到 progRAV=header-opt_head.ImageBase; /得到程序的装载地址,一般为400000 codeoffset=header-opt_head.BaseOfCode-physaddress; /得到代码偏移,用代码段起始RVA减去此段的物理偏移 /应为程序的入口计算公式是一个相对的偏移地址,计算公式为: /代码的写入地址codeoffset entrywrite=header-section_header0.PointerToRawData+header-section_header0.Misc.VirtualSize; /代码写入的物理偏移 mods=entrywrite%16; /对齐边界 if(mods!=0) entrywrite+=(16-mods); oldentryaddress=header-opt_head.AddressOfEntryPoint; /保存旧的程序入口地址 newentryaddress=entrywrite+codeoffset; /计算新的程序入口地址 return; voidprintaddress() HINSTANCEgLibMsg=NULL; DWORDfunaddress; gLibMsg=LoadLibrary(user32.dll); funaddress=(DWORD)GetProcAddress(gLibMsg,MessageBoxA); MessageBoxAadaddress=funaddress; gLibAMsg=LoadLibrary(kernel32.dll); /得到MessageBox在内存中的地址,以便我们使用 voidwritefile() intret; longretf; DWORDaddress; inttmp; unsignedcharwaddress4=0; ret=_open(filename,_O_RDWR|_O_CREAT|_O_BINARY,_S_IREAD|_S_IWRITE); if(!ret) printf(erroropenn); return; retf=_lseek(ret,(long)peaddress+40,SEEK_SET); /程序的入口地址在PE文件头开始的40处 if(retf=-1) printf(errorseekn); return; address=newentryaddress; tmp=address24; waddress3=tmp; tmp=address24; waddress2=tmp; tmp=address24; waddress1=tmp; tmp=address24; waddress0=tmp; retf=_write(ret,waddress,4); /把新的入口地址写入文件 if(retf=-1) printf(errorwrite:%dn,GetLastError(); return; retf=_lseek(ret,(long)entrywrite,SEEK_SET); if(retf=-1) printf(errorseekn); return; retf=_write(ret,writeline,18); if(retf=-1) printf(errorwrite:%dn,GetLastError(); return; /把writeline写入我们计算出的空间 retf=_lseek(ret,(long)entrywrite+9,SEEK_SET); /更改MessageBox函数
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 开展国际交流学习借鉴先进经验
- 2025年小升初名校试题及答案
- 消防安全生产知识考试试题和答案
- 大学测绘考试试题及答案
- 贵州省专业技术人员公需科目创新能力学习测试卷及答案
- 注册测绘师考试真题及答案
- 2025年民事诉讼法考试试卷及答案
- 2025年注册测绘师考试测绘工程环境保护试题库及答案
- 2025年化学基础知识考试试题及答案
- 2025年民事法学自考试题及答案
- 数字化种植牙技术
- 2025年秋招:财务岗笔试真题及答案
- 2025年全国教育系统师德师风知识测试题及答案
- 糖尿病性视网膜病变
- 2025年平面设计笔试题库及答案
- 2025年反洗钱知识竞赛考试题库(含答案)
- 2025建筑电工考试题库及答案
- 【答案】《计算空气动力学》(国防科技大学)章节作业慕课答案
- 西藏代建管理办法
- 动火警示教育
- 淮北一中招生数学试卷
评论
0/150
提交评论