从文件到Filebuffer再到ImageBuffer再到Newbuffer再到文件(低内聚,高耦合)

// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。

//



#include "stdafx.h"

#include "string.h"

#include <malloc.h>

#include <windows.h>



//函数声明



LPVOID ReadPEFile(LPSTR FilePath);

void PrintNTHeaders(LPVOID pfilebuf);

void ImageBufferToFileBuffer(LPVOID ImageBuffer);

int getFileSize(FILE* fileAdress);

FILE* openFile(char* filePath, char* type);

int ReadFileSize(char* FilePath);

//读取文件大小

int ReadFileSize(char* FilePath)

{

FILE* Pfile;//一般使用FILE*类型变量表示文件句柄,通过它来访问FILE结构体,对文件进行操作。

DWORD len;//定义文件长度;

Pfile = fopen(FilePath, "rb+");//pfile可以拿到文件句柄(指针),那样就可以操作了。fopen函数是打开一个文件,其调用的一般形式为:文件指针名=fopen(文件名,使用文件方式);

if (!Pfile)

{

printf("打开文件错误,错误码01");

return NULL;

}

fseek(Pfile, 0, SEEK_END);//把文件指针位置移动到最后面,用来读取大小。函数原形:int fseek(FILE *stream, long offset, int fromwhere);函数设置文件指针stream的位置。如果执行成功,stream将指向以fromwhere(偏移起始位置:文件头0(SEEK_SET),当前位置1(SEEK_CUR),文件尾2(SEEK_END))为基准,偏移offset(指针偏移量)个字节的位置。如果执行失败(比如offset超过文件自身大小),则不改变stream指向的位置。

len = ftell(Pfile); //用ftell函数拿到大小,ftell原型:long ftell(FILE *stream);函数 ftell 用于得到文件位置指针当前位置相对于文件首的偏移字节数。在随机方式存取文件时,由于文件位置频繁的前后移动,程序不容易确定文件的当前位置。

//printf("这个程序的大小为:%d个字节\n", len);//打印文件大小,单位字节。,读取成功66560个字节

return len;

}

//打开文件,并返回指针,LPVOID是暂时没有类型的指针

LPVOID ReadPEFile(char* FilePath)//LPSTR是一种字符串数据类型。LPSTR被定义成是一个指向以NULL(‘\0’)结尾的32位ANSI字符数组指针

{

FILE* Pfile;//一般使用FILE*类型变量表示文件句柄,通过它来访问FILE结构体,对文件进行操作。

LPVOID pfilebuffer; //定义文件缓冲区指针

DWORD len;//定义文件长度;

Pfile = fopen(FilePath, "rb+");//pfile可以拿到文件句柄(指针),那样就可以操作了。fopen函数是打开一个文件,其调用的一般形式为:文件指针名=fopen(文件名,使用文件方式);

if (!Pfile)

{

printf("打开文件错误,错误码01");

return NULL;

}

fseek(Pfile, 0, SEEK_END);//把文件指针位置移动到最后面,用来读取大小。函数原形:int fseek(FILE *stream, long offset, int fromwhere);函数设置文件指针stream的位置。如果执行成功,stream将指向以fromwhere(偏移起始位置:文件头0(SEEK_SET),当前位置1(SEEK_CUR),文件尾2(SEEK_END))为基准,偏移offset(指针偏移量)个字节的位置。如果执行失败(比如offset超过文件自身大小),则不改变stream指向的位置。

len = ftell(Pfile); //用ftell函数拿到大小,ftell原型:long ftell(FILE *stream);函数 ftell 用于得到文件位置指针当前位置相对于文件首的偏移字节数。在随机方式存取文件时,由于文件位置频繁的前后移动,程序不容易确定文件的当前位置。

//printf("这个程序的大小为:%d个字节\n", len);//打印文件大小,单位字节。,读取成功66560个字节

pfilebuffer = malloc(len);//知道大小了后,我们就把pfilebuffer文件缓冲区指针确定大小,用malloc动态分配

fseek(Pfile, 0, SEEK_SET);//然后把文件游标指针拿到最前面来。

if (!pfilebuffer) //判断pfilebuffer获取成功没

{

printf("分配文件缓冲区空间上失败,错误码02");

pfilebuffer = 0;

fclose(Pfile);

return NULL;

}

size_t filebuffer_count = fread(pfilebuffer, 1, len, Pfile); //把len个字节全部读取到pfilebuffer缓冲区中,这里返回的是一个文件字节大小,用于判断是否读取成功函数原型size_t fread(void *buffer, size_t size, size_t count, FILE *stream);//C99前,从给定输入流stream读取最多count个对象到数组buffer中(相当于以对每个对象调用size次fgetc),把buffer当作unsigned char数组并顺序保存结果。流的文件位置指示器前进读取的字节数。

if (!filebuffer_count)

{

printf("读取文件到缓冲区失败,错误码03");

pfilebuffer = 0;

fclose(Pfile);

return 0;

}

//走到这里就读取成功了,返回一个长度为len个字节(含文件数据流)的pfilebuffer缓冲区指针

fclose(Pfile);

return  pfilebuffer;

}





//定义一个打印整个PE头+节表目录信息的函数 ,//

void PrintNTHeaders(LPVOID pfilebuf)

{

LPVOID pfilebuffer;//用来接收 ReadPEFile()函数返回得pfilebuffer缓冲区指针;

PIMAGE_DOS_HEADER pDosHeader = NULL; //DOS头指针

PIMAGE_NT_HEADERS32 pNTHeader = NULL;//NT头指针

PIMAGE_FILE_HEADER pFileHeader = NULL;//标准头指针

PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = NULL;//可选头指针



pfilebuffer = pfilebuf;  //传入pfilebuffer缓冲区指针;

if (!pfilebuffer)

{

printf("传入pfilebuffer缓冲区指针失败,错误代码04");

free(pfilebuffer);

return;

}

//PWORD在DOS下(实模式)地址是分段的,每一段的长度为64K字节,刚好是16位(二进制的十六位)DOS头刚好64个字节。

if (*((PWORD)pfilebuffer) != IMAGE_DOS_SIGNATURE)

{

printf("EXE不是有效的程序,错误代码05");

free(pfilebuffer);

return;

}

printf("PIGAMGE_DOS_HEADER-DOS头指针大小:%d个字节\n", sizeof(PIMAGE_DOS_HEADER));

pDosHeader = (PIMAGE_DOS_HEADER)pfilebuffer;

printf("DOS头pDosHeader指针大小:%d个字节\n", sizeof(pDosHeader));

//开始打印DOS头

printf("\n=======即将打印DOS头=======\n");

printf("MZ标志:%x\n", pDosHeader->e_magic);

printf("PE头偏移:%x\n", pDosHeader->e_lfanew);//定位PE文件,PE头相对于文件的偏移量

   //开始判断PE标志

   //printf("IMAGE_NT_SIGNATURE值为:%x", *PWORD((DWORD)pfilebuffer + pDosHeader->e_lfanew));  其实这里就可以验证了

if ((*PWORD((DWORD)pfilebuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)//说明:pDosHeader->e_lfanew存的是DOS头开始到PE的偏移量,用(DWORD)pfilebuffer指针加上这个偏移量,那么就可以得到PE头的指针偏移量,就得到IMAGE_NT_SIGNATURE值

{

printf("没有找到PE头标志,错误代码06\n");

free(pfilebuffer);

return;

}

pNTHeader = (PIMAGE_NT_HEADERS32)((DWORD)pfilebuffer + pDosHeader->e_lfanew);

//测试打印下NT头

printf("NT头:%x\n", pNTHeader->Signature);



//拿到标准PE头指针

pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);

//打印PE标准头结构

printf("===============PE标准头结构===============\n\n\n");

printf("PE-Machine:%x\n", pFileHeader->Machine);

printf("PE结构中节的数量:%x\n", pFileHeader->NumberOfSections);

printf("PE可选PE结构体大小:%d字节\n\n", pFileHeader->SizeOfOptionalHeader);





//拿到可选PE头



pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + 20);

printf("===============PE可选头结构===============\n\n\n");

printf("PE可选头指针:%x\n", pOptionalHeader);

printf("PE-Magic:%x\n", pOptionalHeader->Magic);

printf("程序入口OEP地址:%x\n", pOptionalHeader->AddressOfEntryPoint);

printf("PE可选头-SizeOfHeader值:%xH\n那么节表里面的首节地址也应该是:%xH\n", pOptionalHeader->SizeOfHeaders, pOptionalHeader->SizeOfHeaders);



//拿到节表地址:

PIMAGE_SECTION_HEADER pSection = NULL;

pSection = PIMAGE_SECTION_HEADER((DWORD)pOptionalHeader + 224);

printf("pSection地址:%x\n", pSection);

printf("PE节表-第一个节PointerToRawData地址:%x\n", pSection->PointerToRawData);

printf("PE节区地址:%x\n", pSection->VirtualAddress);

printf("pe节区name:%s\n", pSection->Name);

//pSection = PIMAGE_SECTION_HEADER((DWORD)pSection + 40);

//printf("第二个pe节区name:%s\n", pSection->Name);

//======================================//



DWORD dwSection = pFileHeader->NumberOfSections;//定义节区描述文件个数这里有3个


for (DWORD i = 0; i < dwSection; i++, pSection++)


{

printf("\n================第%d个节区描述============\nName:", i + 1);

for (DWORD j = 0; j < IMAGE_SIZEOF_SHORT_NAME; j++)

{

printf("%c", pSection->Name[j]);

}

printf("\nMISC:%d个字节\n",pSection->Misc);//文件中节区实际含有数据的大小

printf("VirtualAddress:%x\n", pSection->VirtualAddress);//在内存中的地址,需要加上ImageBase;

printf("SizeOfRawData:%d个字节\n", pSection->SizeOfRawData);//文件中的节区大小

printf("PointToRawData:%d偏移字节\n", pSection->PointerToRawData);//文件中节区首地址的偏移

printf("Characteristics:%08x\n",pSection->Characteristics);//节属性

printf("\n================第%d个节区描述结束============\n", i + 1);

}

}



//复制FileBuffer到ImageBuffer的函数

//参数1:Filebuffer指针

LPVOID CopyFileBufferToImageBuffer(LPVOID pFileBuffer)

{

LPVOID TempiamgeBuffer = NULL;

PIMAGE_DOS_HEADER pDosHeader1=NULL;

PIMAGE_NT_HEADERS32 pNTHeader1 = NULL;

PIMAGE_FILE_HEADER pFileHeader1 = NULL;

PIMAGE_OPTIONAL_HEADER32 pOptionHeader1 = NULL;

PIMAGE_SECTION_HEADER pSectionHeader1 = NULL;

//临时指针;



if (!pFileBuffer)

{

printf("文件指针未获取到,请检查你的参数设置,错误代码07\n");

pFileBuffer = NULL;

return 0;

}



pDosHeader1 = (PIMAGE_DOS_HEADER)pFileBuffer;


if (*((PWORD)pDosHeader1) != IMAGE_DOS_SIGNATURE) //这里为什么要用(PWORD)呢,第一,pDosHeader1指针是4字节,IMAGE_DOS_SIGNATURE的值是两个字节。第二*的操作数必须是一个指针,所以用指向WORD的指针PWORD

{

printf("没有找到MZ标志,错误代码07\n");

pDosHeader1 = NULL;

pFileBuffer = NULL;

return 0 ;

}


//找到所有头

pNTHeader1 = PIMAGE_NT_HEADERS32((DWORD)pDosHeader1 + pDosHeader1->e_lfanew);



if (*(PDWORD)pNTHeader1 != IMAGE_NT_SIGNATURE)

{

printf("没有找到PE标志,错误代码08\n");

pNTHeader1 = NULL;

pFileBuffer = NULL;

return 0 ;

}



pFileHeader1 = PIMAGE_FILE_HEADER((DWORD)pNTHeader1 + 4);

pOptionHeader1 = PIMAGE_OPTIONAL_HEADER32((DWORD)pFileHeader1 + IMAGE_SIZEOF_FILE_HEADER);

pSectionHeader1 = PIMAGE_SECTION_HEADER((DWORD)pOptionHeader1 + pFileHeader1->SizeOfOptionalHeader);

printf("sizeofimage:%d\n", pOptionHeader1->SizeOfImage);

printf("sizeofHeader:%d\n", pOptionHeader1->SizeOfHeaders);

//申请一块动态内存,并用Tempimagebuffer指向他=======================



TempiamgeBuffer = malloc(pOptionHeader1->SizeOfImage + 0xe0);





printf("pOptionHeader1->ImageBase:%x\n", pOptionHeader1->ImageBase);

printf("pOptionHeader1->FileAlignment:%d\n", pOptionHeader1->FileAlignment);

printf("pOptionHeader1->SectionAlignment:%d\n", pOptionHeader1->SectionAlignment);




//判断是否申请成功

if (!TempiamgeBuffer)

{

printf("动态内存申请失败\n,错误代码09");

TempiamgeBuffer = NULL;

free(TempiamgeBuffer);

return 0;

}

//刷新清空这块内存里面的数据

memset(TempiamgeBuffer, 0, pOptionHeader1->SizeOfImage);//函数原型:void *memset(void *s, int ch, size_t n);将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。

//然后就可以复制了



//函数原型void *memcpy(void *destin, void *source, unsigned n);destin-- 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。从源source所指的内存地址的起始位置开始拷贝n个字节到目标destin所指的内存地址的起始位置中。

//destin-- 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。

//source-- 指向要复制的数据源,类型强制转换为 void* 指针。

//n-- 要被复制的字节数。



//复制整个PE头

memcpy(TempiamgeBuffer, pDosHeader1, pOptionHeader1->SizeOfHeaders); //函数原型void *memcpy(void *destin, void *source, unsigned n);destin-- 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。

//

DWORD dwSection = pFileHeader1->NumberOfSections;//节的个数

PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader1;

for (DWORD i = 0; i < dwSection; i++)

{

memcpy((void*)((DWORD)TempiamgeBuffer + (pTempSectionHeader->VirtualAddress)),((void*)((DWORD)pFileBuffer + pTempSectionHeader->PointerToRawData)), pTempSectionHeader->SizeOfRawData);

//pSectionHeader1 = (PIMAGE_SECTION_HEADER)(pSectionHeader1+sizeof(_IMAGE_SECTION_HEADER));

//PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader1;

if (i < 3)

{

pTempSectionHeader++;

}

}





printf("复制数据到ImageBuffer成功\n");

//memset(TempiamgeBuffer, 0, pOptionHeader1->SizeOfImage); //清空

//free(TempiamgeBuffer);//释放内存

//TempiamgeBuffer = NULL;

return TempiamgeBuffer;


}







//imagebuffer 到filebuffer





DWORD ImagebufferToFilebuffer(LPVOID imagebuffer) 

{

LPVOID TempFileBuffer = NULL;

PIMAGE_DOS_HEADER pDosHeader2 = NULL;

PIMAGE_NT_HEADERS32 pNTHeader2 = NULL;

PIMAGE_FILE_HEADER pFileHeader2 = NULL;

PIMAGE_OPTIONAL_HEADER32 pOptionHeader2 = NULL;

PIMAGE_SECTION_HEADER pSectionHeader2 = NULL;



if (!imagebuffer)

{

printf("ImagebufferToFilebuffer函数没有获取到imagebuffer指针,错误到吗20");

return 0;

}

if (*(PWORD)((PIMAGE_DOS_HEADER)imagebuffer) != IMAGE_DOS_SIGNATURE)

{

printf("imagebuffer不是有效的MZ");

return 0;

}

pDosHeader2=(PIMAGE_DOS_HEADER)imagebuffer;

pNTHeader2 = (PIMAGE_NT_HEADERS32)((DWORD)pDosHeader2 + pDosHeader2->e_lfanew);

pFileHeader2 = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader2 + 4);

pOptionHeader2 = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader2 + IMAGE_SIZEOF_FILE_HEADER);

pSectionHeader2 = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader2 + pFileHeader2->SizeOfOptionalHeader);

//先拿到文件buffer大小

int File_size = ReadFileSize("D:\\ipmsg.EXE");



//申请内存

TempFileBuffer = malloc(File_size);

//清空内存中的数据

memset(TempFileBuffer, 0, File_size);

//复制PE头

memcpy(TempFileBuffer, imagebuffer, pOptionHeader2->SizeOfHeaders);

//获得节个数

int DwSetion = pFileHeader2->NumberOfSections;

//申请一个节变量,用于自增

PIMAGE_SECTION_HEADER pSection = pSectionHeader2;

//开始复制节到文件内存里

for (int i = 0; i < DwSetion; i++)

{

memcpy((VOID*)((DWORD)TempFileBuffer + pSection->PointerToRawData), (void*)((DWORD)imagebuffer + pSection->VirtualAddress), pSection->SizeOfRawData);

pSection++;

}



printf("imagebuffer到FileBuffer成功了"); //好吧,真的成功了。接下来要存盘了。



//====================开始存盘,看看能不能用========================

char Save_exe[] = "D:\\ipmsg_pk.EXE";

FILE* Save_file = fopen(Save_exe, "wb+");

fwrite(TempFileBuffer,File_size,1,Save_file);

if (!Save_file)

{

printf("拷贝失败了,错误代码22\n");

fclose(Save_file);

return 0;

}



fclose(Save_file);

return 0;



}











//得到文件大小函数 返回文件大小

int getFileSize(FILE* fileAdress) 

{

int size;

//定位文件末尾

fseek(fileAdress, NULL, SEEK_END);

//得到文件流大小

size = ftell(fileAdress);

//重定位文件开头

fseek(fileAdress, NULL, SEEK_SET);

returnsize;

}



FILE* openFile(char* filePath, char* type) 

{

FILE* fileAdress;

//通过传入的文件地址以及读写类型打开文件创建文件流

if (!(fileAdress = fopen(filePath, type)))

{

printf("获取文件出错!\n");

return 0;

}

return fileAdress;

}







int main()

{

char FilePath[]  = "D:\\ipmsg.EXE";


LPVOID p=CopyFileBufferToImageBuffer(ReadPEFile(FilePath));



ImagebufferToFilebuffer(p);

getchar();

return 1;

}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值