作业要求我们在上一章已经说明了,还有不懂的可以去上一张看一下,这里直接给出源码,代码我们就不做解释了,自己写出来或着自己理解一遍或许对PE会有更好的理解。
编写一个程序,实现从FileBuffer拉升到ImageBuffer再转回FileBuffer并且完成存盘:
这是主函数部分:
#include <stdio.h> #include <windows.h> #include <stdlib.h> #include "Function.h" int main(int argc, char** argv) { char *File_Buffer,*Image_Buffer,*New_Buffer; char filepath[]="E:\\个人\\逆向\\练习.exe"; //打开文件,读取到File_Buffer File_Buffer=ReadToFile_Buffer(filepath); //将File_Buffer拉伸存到Image_Buffer Image_Buffer=FileBufferToImageBuffer(File_Buffer); //将Image_Buffer再存到New_Buffer New_Buffer=ImageBufferToNewBuffer(Image_Buffer); //将文件存盘 char newname[]="NewBuffer.exe"; save(newname,New_Buffer); //释放申请的内存 free(File_Buffer); free(Image_Buffer); free(New_Buffer); return 0; }
这是Function(函数说明部分):
//打开文件,将数据读取到Fiel_Buffer //该函数返回值为一个指针,指向File_Buffer char*ReadToFile_Buffer(char *filepath){ FILE *fp; char *File_Buffer=NULL; int length; //打开文件 if((fp=fopen(filepath,"rb"))==NULL){ printf("文件打开失败!\n"); exit(0); }else{ printf("打开文件成功。\n"); } //计算文件大小 fseek(fp,0,SEEK_END); length=ftell(fp); fseek(fp,0,SEEK_SET); //动态申请内存 File_Buffer=(char*)malloc(length) if(File_Buffer==NULL){ printf("申请内存失败!\n"); }else{ printf("申请内存成功。\n"); } //将文件数据读取到File_Buffer if(fread(File_Buffer,1,length,fp)){ printf("读取文件成功。\n"); }else{ printf("读取文件失败!\n"); } //关闭文件 if(fclose(fp)){ printf("关闭文件失败!\n"); exit(0); }else{ printf("关闭文件成功。\n"); } return File_Buffer; } //将Fiel_Buffer读取到Image_Buffer //该函数返回一个指针,指向Image_Buffer char *FileBufferToImageBuffer(char *File_Buffer){ char *Image_Buffer=NULL; IMAGE_DOS_HEADER *pDosHeader=(IMAGE_DOS_HEADER*)File_Buffer; IMAGE_FILE_HEADER *pFileHeader=(IMAGE_FILE_HEADER*)(File_Buffer+pDosHeader->e_lfanew+4); IMAGE_OPTIONAL_HEADER *pOptionalHeader=(IMAGE_OPTIONAL_HEADER*)((char*)pFileHeader+20); IMAGE_SECTION_HEADER *pSectionHeader=(IMAGE_SECTION_HEADER*)((char*)pOptionalHeader+pFileHeader->SizeOfOptionalHeader); //动态申请内存 Image_Buffer=(char*)malloc(pOptionalHeader->SizeOfImage); if(Image_Buffer==NULL){ printf("内存申请失败!\n"); }else{ printf("内存申请成功。\n"); } //初始化申请的内存 int i=0; while(i<=pOptionalHeader->SizeOfImage){ *(Image_Buffer + i)= 0x00; i++; } //读取数据到Image_Buffer //复制所有头 int j=0; for(j=0;j<pOptionalHeader->SizeOfHeaders;j++){ *(Image_Buffer + j)= *(File_Buffer + j); } //复制所有节信息 int k,x; for(k=0;k<pOptionalHeader->SizeOfHeaders;k++){ for(x=0;x<pSectionHeader->SizeOfRawData;x++){ *(Image_Buffer+pSectionHeader->VirtualAddress)=*(File_Buffer+pSectionHeader->PointerToRawData+x); } pSectionHeader++; } return Image_Buffer; } //将Image_Buffer存到New_Buffer //该函数需要一个指向File_Buffer的指针 //该函数返回一个指针,指向New_Buffer char *ImageBufferToNewBuffer(char *Image_Buffer){ char *New_Buffer; //定义PE头部结构体 IMAGE_DOS_HEADER *pDosHeader=(IMAGE_DOS_HEADER*)Image_Buffer; IMAGE_FILE_HEADER *pFileHeader=(IMAGE_FILE_HEADER*)(Image_Buffer+pDosHeader->e_lfanew+4); IMAGE_OPTIONAL_HEADER *pOptionalHeader=(IMAGE_OPTIONAL_HEADER*)((char*)pFileHeader+20); IMAGE_SECTION_HEADER *pSectionHeader=(IMAGE_SECTION_HEADER*)(pOptionalHeader+pFileHeader->SizeOfOptionalHeader); //计算所需内存大小 IMAGE_SECTION_HEADER *temp=pSectionHeader; temp=pSectionHeader+pFileHeader->NumberOfSections-1; int length=temp->PointerToRawData+temp->VirtualAddress; //申请内存 New_Buffer=(char*)malloc(length); //初始化申请的内存 int i; for(i=0;i<length;i++){ *(New_Buffer+i)=0x00; } //复制所有头 int j; for(j=0;j<pOptionalHeader->SizeOfHeaders;j++){ *(New_Buffer+j)=*(Image_Buffer+j); } //复制所有节 int k,x; for(k=0;k<pFileHeader->NumberOfSections;k++){ for(x=0;x<pSectionHeader->SizeOfRawData;x++){ *(New_Buffer+pSectionHeader->PointerToRawData+x)=*(Image_Buffer+pSectionHeader->PointerToRawData+x); } pSectionHeader++; } return New_Buffer; } void save(char *newname,char *New_Buffer){ //定义PE头部结构 IMAGE_DOS_HEADER *pDosHeader=(IMAGE_DOS_HEADER*)New_Buffer; IMAGE_FILE_HEADER *pFileHeader=(IMAGE_FILE_HEADER*)((char*)New_Buffer+pDosHeader->e_lfanew+4); IMAGE_OPTIONAL_HEADER *pOptionalHeader=(IMAGE_OPTIONAL_HEADER*)((char*)pFileHeader+0x20); IMAGE_SECTION_HEADER *pSectionHeader=(IMAGE_SECTION_HEADER*)(pOptionalHeader+pFileHeader->SizeOfOptionalHeader); //计算New_Buffer大小 IMAGE_SECTION_HEADER *temp=pSectionHeader; temp=pSectionHeader+pFileHeader->NumberOfSections-1; int length=temp->PointerToRawData+temp->VirtualAddress; //新建文件 FILE *fp; if((fp=fopen(newname,"wb"))==NULL){ printf("文件新建失败!\n"); }else{ printf("文件新建成功。\n"); } //将New_Buffer读写到文件中 if(fwrite(New_Buffer,length,1,fp)){ printf("存盘成功。\n"); }else{ printf("存盘失败!\n"); exit(0); } if(fclose(fp)){ printf("关闭文件成功。\n"); }else{ printf("关闭文件失败!\n"); } }
代码中还有很多可以优化的地方,或者是有一些错误的地方希望大家指出来,我会非常虚心地学习,也希望我们能够共同进步!
在博客中我还发现另一个很不错的源码:day30.1-FileBuffer-ImageBuffer
#include "stdafx.h" #include "stdlib.h" #define IMAGE_SIZEOF_SHORT_NAME 8 //******************************************************************************* #pragma pack(1) typedef struct DOS_HEADER{ //DOS头字段 short e_magic; short e_cblp; short e_cp; short e_crlc; short e_cparhdr; short e_minalloc; short e_maxalloc; short e_ss; short e_sp; short e_csum; short e_ip; short e_cs; short e_lfarlc; short e_ovno; short e_res[4]; short e_oemid; short e_oeminfo; short e_res2[10]; int e_lfanew; }Dos; #pragma pack() //别忘了中间还有一个PE签名 #pragma pack(1) typedef struct FILE_HEADER{ //标准PE头字段 short Machine; short NumberOfSections; int TimeDateStamp; int PointerToSymbolTable; int NumberOfSymbols; short SizeOfOptionalHeader; short Characteristics; }File; #pragma pack() #pragma pack(1) typedef struct OPTIONAL_HEADER{ //可选PE头字段 short Magic; char MajorLinkerVersion; char MinorLinkerVersion; int SizeOfCode; int SizeOfInitializedData; int SizeOfUninitializedData; int AddressOfEntryPoint; int BaseOfCode; int BaseOfData; int ImageBase; int SectionAlignment; int FileAlignment; short MajorOperatingSystemVersion; short MinorOperatingSystemVersion; short MajorImageVersion; short MinorImageVersion; short MajorSubsystemVersion; short MinorSubsystemVersion; int Win32VersionValue; int SizeOfImage; int SizeOfHeaders; int CheckSum; short Subsystem; short DllCharacteristics; int SizeOfStackReserve; int SizeOfStackCommit; int SizeOfHeapReserve; int SizeOfHeapCommit; int LoaderFlags; int NumberOfRvaAndSizes; //后面还有几个(16)个结构体,一个结构体8字节,我们先不研究,后面再说 }Op; #pragma pack() #pragma pack(1) typedef struct _IMAGE_SECTION_HEADER { char Name[IMAGE_SIZEOF_SHORT_NAME]; //宏定义使用 union{ int PhysicalAddress; int VirtualSize; }Misc; int VirtualAddress; int SizeOfRawData; int PointerToRawData; int PointerToRelocations; int PointerToLinenumbers; short NumberOfRelocations; short NumberOfLinenumbers; int Characteristics; }Sec; #pragma pack() //******************************************************************************* //将硬盘上的可执行文件数据复制一份存入FileBuffer中 char* readInFileBuffer(char* filePath){ FILE* fp = NULL; char* p = NULL; fp = fopen(filePath,"rb"); if(NULL == fp){ printf("文件打开失败\n"); fclose(fp); return NULL; } //计算文件长度 fseek(fp,0,2); int len = ftell(fp); fseek(fp,0,0); //动态申请FileBuffer内存空间 p = (char*)malloc(len); if(NULL == p){ printf("FileBuffer内存空间分配失败\n"); fclose(fp); return NULL; } //写入数据 int isSuccessed = fread(p,len,1,fp); if(!isSuccessed){ printf("写入FileBuffer失败\n"); fclose(fp); free(p); return NULL; } fclose(fp); return p; //将FileBuffer首地址返回 } //PE装载 char* fileBufferToImageBuffer(char* fileBufferp){ Dos* dosp = (Dos*)fileBufferp; //定义DOS结构体类型指针 File* filep = (File*)(fileBufferp + dosp->e_lfanew + 4);//定义File结构体类型指针 Op* opp = (Op*)((char*)filep + 20);//定义Op结构体类型指针 Sec* secp = (Sec*)((char*)opp + filep->SizeOfOptionalHeader);//定义Sec结构体类型指针 //动态申请ImageBuffer的内存空间 char* ip = NULL; ip = (char*)malloc(opp->SizeOfImage); if(NULL == ip){ printf("动态申请ImageBuffer内存失败\n"); return NULL; } for(int i = 0;i < opp->SizeOfImage;i++){ *(ip + i) = 0x00; } //复制所有头 for(int j = 0;j < opp->SizeOfHeaders;j++){ *(ip + j) = *(fileBufferp + j); } //复制所有节 for(int k = 0;k < filep->NumberOfSections;k++){ for(int x = 0;x < secp->SizeOfRawData;x++){ *(ip + secp->VirtualAddress + x) = *(fileBufferp + secp->PointerToRawData + x); } secp++; } return ip; //返回ImageBuffer的起始地址 } //ImageBuffer到NewBuffer char* imageBufferToNewBuffer(char* imageBufferp){ Dos* dosp = (Dos*)imageBufferp; //定义DOS结构体类型指针 File* filep = (File*)(imageBufferp + dosp->e_lfanew + 4);//定义File结构体类型指针 Op* opp = (Op*)((char*)filep + 20);//定义Op结构体类型指针 Sec* secp = (Sec*)((char*)opp + filep->SizeOfOptionalHeader);//定义Sec结构体类型指针 //计算newBuffer需要的大小 //使用最后一个节的文件偏移地址 + 最后一个节对齐后的大小 Sec* temp = secp; secp = secp + filep->NumberOfSections - 1; int len = secp->PointerToRawData + secp->SizeOfRawData; secp = temp; //动态分配NewBuffer内存 char* np = (char*)malloc(len); if(NULL == np){ printf("NewBuffer内存分配失败\n"); return NULL; } for(int i = 0;i < len;i++){ *(np + i) = 0x00; } //复制所有头 for(int j = 0;j < opp->SizeOfHeaders;j++){ *(np + j) = *(imageBufferp + j); } //复制所有节 for(int k = 0;k < filep->NumberOfSections;k++){ for(int x = 0;x < secp->SizeOfRawData;x++){ *(np + secp->PointerToRawData + x) = *(imageBufferp + secp->VirtualAddress + x); } secp++; } return np; //返回NewBuffer的首地址 } //将文件存盘 int save(char* savePath,char* newBufferp){ Dos* dosp = (Dos*)newBufferp; //定义DOS结构体类型指针 File* filep = (File*)(newBufferp + dosp->e_lfanew + 4);//定义File结构体类型指针 Op* opp = (Op*)((char*)filep + 20);//定义Op结构体类型指针 Sec* secp = (Sec*)((char*)opp + filep->SizeOfOptionalHeader);//定义Sec结构体类型指针 FILE* fp = fopen(savePath,"wb"); if(NULL == fp){ printf("文件打开失败\n"); fclose(fp); return 0; } secp = secp + filep->NumberOfSections - 1; int len = secp->PointerToRawData + secp->SizeOfRawData; //得到newBuffer的大小 int isSuccessed = fwrite(newBufferp,len,1,fp); if(!isSuccessed){ printf("存盘失败\n"); fclose(fp); return 0; } fclose(fp); printf("存盘成功\n"); return 1; } int main(int argc,char*argv[]){ //读入FileBuffer char filePath[] = "D:\\notepad.exe"; char* fileBuffer = readInFileBuffer(filePath); if(NULL == fileBuffer){ return 0; } //FileBuffer到ImageBuffer char* imageBuffer = fileBufferToImageBuffer(fileBuffer); if(NULL == imageBuffer){ printf("PE加载失败"); free(fileBuffer); fileBuffer = NULL; return 0; } //ImageBuffer到NewBuffer char* newBuffer = imageBufferToNewBuffer(imageBuffer); if(NULL == newBuffer){ free(fileBuffer); free(imageBuffer); fileBuffer = NULL; imageBuffer = NULL; return 0; } //存盘 char destFilePath[] = "D:\\notepad_new.exe"; int isSuccessed2 = save(destFilePath,newBuffer); if(!isSuccessed2){ printf("存盘失败\n"); } free(fileBuffer); free(imageBuffer); free(newBuffer); fileBuffer = NULL; imageBuffer = NULL; newBuffer = NULL; return 0; }