• 文件中pe到内存中pe


    前言

    学pe的时候被困扰了很久,终于在某处给我找到了,打算打出来读一读代码


    这边我们是从文件中的pe转到运行中的pe,然后再缩小存储到文件的pe
    这边我们需要知道内存中对齐是0x1000,文件对齐是0x200(这边是16进制的,误踩坑)

    我们第一步是先要把pe文件读出来,存储起来
    1、根据SizeOfImage的大小,开辟一块缓冲区(ImageBuffer).

    2、根据SizeOfHeader的大小,将头信息从FileBuffer拷贝到ImageBuffer

    3、根据节表中的信息循环讲FileBuffer中的节拷贝到ImageBuffer中.

    4、Misc.VirtualSize 和 SizeOfRawData谁大?

    5、FileBuffer与ImageBuffer谁大?

    0x01. exe->filebufeer,返回值为计算所得的文件大小

    DWORD ReadPEFile(char* file_path, PVOID* pFileBuffer)
    {
    	FILE* pfile = NULL;  // 文件指针
    	DWORD file_size = 0;
    	LPVOID pTempFilebuffer = NULL;
    
    	// 打开文件
    	pfile = fopen(file_path, "rb");  // 如果有新的指针,就要进行判断
    	if (!pfile)
    	{
    		printf("打开exe文件失败!
    ");//如果分配失败就要关闭文件、释放动态内存、指针指向NULL
    		return 0;
    	}
    	// 读取文件大小
    	fseek(pfile, 0, SEEK_END);
    	file_size = ftell(pfile);
    	fseek(pfile, 0, SEEK_SET);
    	// 分配空间
    	pTempFilebuffer = malloc(file_size);  // 如果有新的指针,就要进行判断
    	if (!pTempFilebuffer)
    	{
    		printf("分配空间失败!
    ");//如果分配失败就要关闭文件、释放动态内存、指针指向NULL
    		fclose(pfile);
    		return 0;
    	}
    	// 将数据读取到内存中
    	size_t n = fread(pTempFilebuffer, file_size, 1, pfile);
    	if (!n)
    	{
    		printf("数据读取到内存中失败!
    "); //如果分配失败就要关闭文件、释放动态内存、指针指向NULL
    		fclose(pfile);
    		free(pTempFilebuffer);
    		return 0;
    	}
    	// 关闭文件(已经读取到内存了)
    	*pFileBuffer = pTempFilebuffer;
    	pTempFilebuffer = NULL;
    	fclose(pfile);
    	return file_size;
    }
    

    1、dword是4字节类型,其实只是int的另外一种写法而已,里面有两个参数,一个是文件路径,一个是文件数据
    2、先是常规的读取文件步骤,文件指针,然后定义一个文件大小的变量,一个是临时存放pe文件的变量
    3、使用fopen打开文件,判断是否打开失败,其实判断的话也可以删掉,方便调试就留着
    4、使用fseek函数 第一个参数是文件指针,第二个是 0,第三个是宏,移动到末尾处,然后通过ftell函数得到文件的大小
    5、再把指针复位,也可以使用rewind(pFile);来复位,在通过刚刚获取到的变量file_size的值去开辟一个内存空间
    6、然后使用fread函数把文件读取出来,但是我们读取出来还要让计算机知道,所以赋值给了变量n
    7、变量n判断是否为为空,如果不为空,则进入下一步,把临时存储文件pTempFilebuffer变量的地址给了*pFileBuffer

    从这张图可以看出两者的区别,那就是pFileBuffer上面存储着地址

    这时候把刚刚那个变量清空,关闭文件,返回file_size

    0x02.filebuffer -> imagebuffer

    (1)

    然后把文件转到内存中的话需要注意一点(文件对其0x200,内存对其0x1000)
    这里也是个难点了,我们一段一段的分析

    DWORD CopyFileBufferToImageBuffer(PVOID pFileBuffer, PVOID* pImageBuffer)
    {
    
    }
    

    这边是有两个参数,一个是文件中的pe,另外一个是内存中的pe
    注意PVOID其实就是 void*PVOID* 也就是 void**

    (2)

    // 初始化PE头部结构体
    	PIMAGE_DOS_HEADER pDosHeader = NULL;
    	PIMAGE_NT_HEADERS pNTHeader = NULL;
    	PIMAGE_FILE_HEADER pPEHeader = NULL;
    	PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
    	PIMAGE_SECTION_HEADER pSectionHeader = NULL;
    	// 初始化IMAGE_BUFFER指针(temparay)
    	LPVOID pTempImagebuffer = NULL;
    
    	if (!pFileBuffer)
    	{
    		printf("(2pimagebuffer阶段)读取到内存的pfilebuffer无效!
    ");
    		return 0;
    	}
    	// 判断是否是可执行文件
    	if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)  // IMAGE_DOS_SIGNATURE是4字节,将pFileBuffer强制类型转换为4字节指针类型(PWORD)
    	{
    		printf("(2pimagebuffer阶段)不含MZ标志,不是exe文件!
    ");
    		return 0;
    	}
    	//强制结构体类型转换pDosHeader
    	pDosHeader = PIMAGE_DOS_HEADER(pFileBuffer);
    	//判断是否含有PE标志       
    	if (*((PDWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE) // 注意指针的加法是:去掉一个*后的类型相加。必须转换为DWORD类型再加减。
    	{																			  //相加后的和 强制类型转换为4字节指针类型(PWORD) IMAGE_NT_SIGNATURE 4BYTES
    		printf("(2pimagebuffer阶段)不是有效的PE标志!
    ");
    		return 0;
    	}
    


    通过这张图我们可以知道pe文件有dos头(PIMAGE_DOS_HEADER)nt头(PIMAGE_NT_HEADERS)、b
    再细细分,nt头中有PE签名、然后再PE头(PIMAGE_FILE_HEADER)PE可选头(PIMAGE_OPTIONAL_HEADER32)

    1、就先把我们所需要的结构体先初始化为0,然后再初始化一下临时存储内存中PE的变量 pTempImagebuff
    2、然后使用if判断读取到内存中的pfilebuffer有没有问题; 再判断是否可执行文件,IMAGE_DOS_SIGNATURE是个宏,里面是0x5A4D

    通过这张图知道 e_magic是word字节的,所以我们只需要word字节,由于这是指针,所以是PWORD
    (PWORD)pFileBuffer
    但是我们这是强转,告诉编译器我们需要的是内存中双字(word)的值的地址

    我们还需要再用一个*号来取值

    3、再把pFileBuffer中的dos头分出来,可能会有人好奇怎么分,我按照我想法和你说一下

    因为dos头也就这几个字节,所以把这个pe文件的前这几个字节分出来,基本就这样,其他的就不多细想了

    4、这时候再判断是否存在PE标志
    PIMAGE_DOS_HEADER之后的四个字节就是PE标志位了,我们上面得到了 pDosHeader ,所以我们在pFileBuffer+ 248

    (注意1:248是10进制的,需要换成16进制的
    注意2:pFileBuffer存储的是地址,地址上的内容是pe文件,所以先修改地址,再取值就是另外一个地方)

    (3)

    pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
    pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
    pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
    pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
    

    1、pFileBuffer 存储的是pe文件的首地址,首地址加上e_lfanew成员,就是nt头的第一个成员

    2、pe头:
    因为nt头的第一个成员固定是4字节,所以加上4,就是pe头的起始地址,在通过强转分开,填充进PIMAGE_FILE_HEADER结构体中,得到了pe头的内容

    3、OptionHeader 可选头:
    上面得到了pe头首地址,pe头大小为 IMAGE_SIZEOF_FILE_HEADER
    所以 pPEHeader + IMAGE_SIZEOF_FILE_HEADER 就得到了可选头的地址

    4、节表:
    由于可选头大小无法确定,但是PE头里面SizeOfOptionalHeader有可选头大小
    这是上面得到了OptionHeader首地址,首地址加上可选头大小,就是节表的首地址了

    总结:PE文件中每一块都是相连的

    (4)

          // 分配动态内存
    	pTempImagebuffer = malloc(pOptionHeader->SizeOfImage);
    	if (!pTempImagebuffer)
    	{
    		printf("分配动态内存失败!
    ");
    		free(pTempImagebuffer);
    		return 0;
    	}
    	// 初始化动态内存
    	memset(pTempImagebuffer, 0, pOptionHeader->SizeOfImage);
    	// 拷贝头部
    	memcpy(pTempImagebuffer, pDosHeader, pOptionHeader->SizeOfHeaders);
    

    1、sizeofimage是内存中整个PE文件的映射的尺寸,可以比实际的值大
    因为我们要从filebuffer转为imagebuffer,需要 内存中的pe + 基址 = 运行中的pe

    2、memset(pTempImagebuffer, 0, pOptionHeader->SizeOfImage);
    把刚刚开辟的内存全部初始化为0

    3、memcpy(pTempImagebuffer, pDosHeader, pOptionHeader->SizeOfHeaders);
    拷贝dos头
    destin-- 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。
    source-- 指向要复制的数据源,类型强制转换为 void* 指针。
    n-- 要被复制的字节数。

    (5)

    // 循环拷贝节表
    	PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
    	for (DWORD i = 0; i<pPEHeader->NumberOfSections; i++, pTempSectionHeader++)
    	{
    		memcpy((void*)((DWORD)pTempImagebuffer + pTempSectionHeader->VirtualAddress), (void*)((DWORD)pFileBuffer + pTempSectionHeader->PointerToRawData), pTempSectionHeader->SizeOfRawData);
    	}
    	// 返回数据
    	*pImageBuffer = pTempImagebuffer;
    	pTempImagebuffer = NULL;
    	return pOptionHeader->SizeOfImage;
    

    然后就开始拷贝节,使用for循环把节拷进去
    然后再把地址存储在*pImageBuffer,最后返回一下内存中的文件大小
    可能没有概念,内存对齐中的是0x1000,但是其他数据都是连在一起的,比如dos头,nt头,节表这三个连在一起,然后因为内存1000,就直接在后面全部为0,然后在下一个0x1000的地址再添上新数据

    源代码:

    DWORD CopyFileBufferToImageBuffer(PVOID pFileBuffer, PVOID* pImageBuffer)
    {
    	// 初始化PE头部结构体
    	PIMAGE_DOS_HEADER pDosHeader = NULL;
    	PIMAGE_NT_HEADERS pNTHeader = NULL;
    	PIMAGE_FILE_HEADER pPEHeader = NULL;
    	PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
    	PIMAGE_SECTION_HEADER pSectionHeader = NULL;
    	// 初始化IMAGE_BUFFER指针(temparay)
    	LPVOID pTempImagebuffer = NULL;
    
    	if (!pFileBuffer)
    	{
    		printf("(2pimagebuffer阶段)读取到内存的pfilebuffer无效!
    ");
    		return 0;
    	}
    	// 判断是否是可执行文件
    	if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)  // IMAGE_DOS_SIGNATURE是4字节,将pFileBuffer强制类型转换为4字节指针类型(PWORD)
    	{
    		printf("(2pimagebuffer阶段)不含MZ标志,不是exe文件!
    ");
    		return 0;
    	}
    	//强制结构体类型转换pDosHeader
    	pDosHeader = PIMAGE_DOS_HEADER(pFileBuffer);
    	//判断是否含有PE标志       
    	if (*((PDWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE) // 注意指针的加法是:去掉一个*后的类型相加。必须转换为DWORD类型再加减。
    	{																			  //相加后的和 强制类型转换为4字节指针类型(PWORD) IMAGE_NT_SIGNATURE 4BYTES
    		printf("(2pimagebuffer阶段)不是有效的PE标志!
    ");
    		return 0;
    	}
    	// 强制结构体类型转换
    	pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
    	pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
    	pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
    	pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
    
    	// 分配动态内存
    	pTempImagebuffer = malloc(pOptionHeader->SizeOfImage);
    	if (!pTempImagebuffer)
    	{
    		printf("分配动态内存失败!
    ");
    		free(pTempImagebuffer);
    		return 0;
    	}
    	// 初始化动态内存
    	memset(pTempImagebuffer, 0, pOptionHeader->SizeOfImage);
    	// 拷贝头部
    	memcpy(pTempImagebuffer, pDosHeader, pOptionHeader->SizeOfHeaders);
    	// 循环拷贝节表
    	PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
    	for (DWORD i = 0; i<pPEHeader->NumberOfSections; i++, pTempSectionHeader++)
    	{
    		memcpy((void*)((DWORD)pTempImagebuffer + pTempSectionHeader->VirtualAddress), (void*)((DWORD)pFileBuffer + pTempSectionHeader->PointerToRawData), pTempSectionHeader->SizeOfRawData);
    	}
    	// 返回数据
    	*pImageBuffer = pTempImagebuffer;
    	pTempImagebuffer = NULL;
    	return pOptionHeader->SizeOfImage;
    }DWORD CopyFileBufferToImageBuffer(PVOID pFileBuffer, PVOID* pImageBuffer)
    {
    	// 初始化PE头部结构体
    	PIMAGE_DOS_HEADER pDosHeader = NULL;
    	PIMAGE_NT_HEADERS pNTHeader = NULL;
    	PIMAGE_FILE_HEADER pPEHeader = NULL;
    	PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
    	PIMAGE_SECTION_HEADER pSectionHeader = NULL;
    	// 初始化IMAGE_BUFFER指针(temparay)
    	LPVOID pTempImagebuffer = NULL;
    
    	if (!pFileBuffer)
    	{
    		printf("(2pimagebuffer阶段)读取到内存的pfilebuffer无效!
    ");
    		return 0;
    	}
    	// 判断是否是可执行文件
    	if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)  // IMAGE_DOS_SIGNATURE是4字节,将pFileBuffer强制类型转换为4字节指针类型(PWORD)
    	{
    		printf("(2pimagebuffer阶段)不含MZ标志,不是exe文件!
    ");
    		return 0;
    	}
    	//强制结构体类型转换pDosHeader
    	pDosHeader = PIMAGE_DOS_HEADER(pFileBuffer);
    	//判断是否含有PE标志       
    	if (*((PDWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE) // 注意指针的加法是:去掉一个*后的类型相加。必须转换为DWORD类型再加减。
    	{																			  //相加后的和 强制类型转换为4字节指针类型(PWORD) IMAGE_NT_SIGNATURE 4BYTES
    		printf("(2pimagebuffer阶段)不是有效的PE标志!
    ");
    		return 0;
    	}
    	// 强制结构体类型转换
    	pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
    	pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
    	pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
    	pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
    
    	// 分配动态内存
    	pTempImagebuffer = malloc(pOptionHeader->SizeOfImage);
    	if (!pTempImagebuffer)
    	{
    		printf("分配动态内存失败!
    ");
    		free(pTempImagebuffer);
    		return 0;
    	}
    	// 初始化动态内存
    	memset(pTempImagebuffer, 0, pOptionHeader->SizeOfImage);
    	// 拷贝头部
    	memcpy(pTempImagebuffer, pDosHeader, pOptionHeader->SizeOfHeaders);
    	// 循环拷贝节表
    	PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
    	for (DWORD i = 0; i<pPEHeader->NumberOfSections; i++, pTempSectionHeader++)
    	{
    		memcpy((void*)((DWORD)pTempImagebuffer + pTempSectionHeader->VirtualAddress), (void*)((DWORD)pFileBuffer + pTempSectionHeader->PointerToRawData), pTempSectionHeader->SizeOfRawData);
    	}
    	// 返回数据
    	*pImageBuffer = pTempImagebuffer;
    	pTempImagebuffer = NULL;
    	return pOptionHeader->SizeOfImage;
    }
    

    0x03.imagebuffer -> newbuffer

    DWORD CopyImageBufferToNewBuffer(PVOID pImageBuffer, PVOID* pNewBuffer)
    {
    	// 初始化PE头部结构体
    	PIMAGE_DOS_HEADER pDosHeader = NULL;
    	PIMAGE_NT_HEADERS pNTHeader = NULL;
    	PIMAGE_FILE_HEADER pPEHeader = NULL;
    	PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
    	PIMAGE_SECTION_HEADER pSectionHeader = NULL;
    
    	// 初始化NEW_BUFFER指针(temparay)
    	LPVOID pTempNewbuffer = NULL;
    
    	// 判断pImageBuffer是否有效
    	if (!pImageBuffer)
    	{
    		printf("(2pnewbuffer阶段)读取到内存的pimagebuffer无效!
    ");
    		return 0;
    	}
    	//判断是不是exe文件
    	if (*((PWORD)pImageBuffer) != IMAGE_DOS_SIGNATURE)
    	{
    		printf("(2pnewbuffer阶段)不含MZ标志,不是exe文件!
    ");
    		return 0;
    	}
    	// 强制结构体类型转换
    	pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
    	if (*((PDWORD)((DWORD)pImageBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
    	{
    		printf("(2pnewbuffer阶段)不是有效的PE标志!
    ");
    		return 0;
    	}
    	// 强制结构体类型转换
    	pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageBuffer + pDosHeader->e_lfanew);
    	pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4); // 这里必须强制类型转换
    	pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
    	pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
    
    	//获取new_buffer的大小
    	int new_buffer_size = pOptionHeader->SizeOfHeaders;
    	for (DWORD i = 0; i<pPEHeader->NumberOfSections; i++)
    	{
    		new_buffer_size += pSectionHeader[i].SizeOfRawData;  // pSectionHeader[i]另一种加法
    	}
    	// 分配内存(newbuffer)
    	pTempNewbuffer = malloc(new_buffer_size);
    	if (!pTempNewbuffer)
    	{
    		printf("(2pnewbuffer阶段)分配Newbuffer失败!
    ");
    		return 0;
    	}
    	memset(pTempNewbuffer, 0, new_buffer_size);
    	// 拷贝头部
    	memcpy(pTempNewbuffer, pDosHeader, pOptionHeader->SizeOfHeaders);
    	// 循环拷贝节区
    	PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
    	for (DWORD j = 0; j<pPEHeader->NumberOfSections; j++, pTempSectionHeader++)
    	{	//PointerToRawData节区在文件中的偏移,VirtualAddress节区在内存中的偏移地址,SizeOfRawData节在文件中对齐后的尺寸
    		memcpy((PDWORD)((DWORD)pTempNewbuffer + pTempSectionHeader->PointerToRawData), (PDWORD)((DWORD)pImageBuffer + pTempSectionHeader->VirtualAddress), pTempSectionHeader->SizeOfRawData);
    	}
    	//返回数据
    	*pNewBuffer = pTempNewbuffer; //暂存的数据传给参数后释放
    	pTempNewbuffer = NULL;
    	return new_buffer_size;  // 返回计算得到的分配内存的大小
    }
    

    1、这边也是传入两个参数,一个是内存中的pe文件 pimagebuffer,一个新的pe文件

    PIMAGE_DOS_HEADER pDosHeader = NULL;
    	PIMAGE_NT_HEADERS pNTHeader = NULL;
    	PIMAGE_FILE_HEADER pPEHeader = NULL;
    	PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
    	PIMAGE_SECTION_HEADER pSectionHeader = NULL;
    
    	// 初始化NEW_BUFFER指针(temparay)
    	LPVOID pTempNewbuffer = NULL;
    

    也是初始化这些自定义好的结构体,然后初始化,创建一个临时存储数据的指针类型pTempNewbuffer

    // 判断pImageBuffer是否有效
    	if (!pImageBuffer)
    	{
    		printf("(2pnewbuffer阶段)读取到内存的pimagebuffer无效!
    ");
    		return 0;
    	}
    	//判断是不是exe文件
    	if (*((PWORD)pImageBuffer) != IMAGE_DOS_SIGNATURE)
    	{
    		printf("(2pnewbuffer阶段)不含MZ标志,不是exe文件!
    ");
    		return 0;
    	}
    	// 强制结构体类型转换
    	pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
    	if (*((PDWORD)((DWORD)pImageBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
    	{
    		printf("(2pnewbuffer阶段)不是有效的PE标志!
    ");
    		return 0;
    	}
    
    

    判断是否有读取到内存中imagebuffer
    if (*((PWORD)pImageBuffer) != IMAGE_DOS_SIGNATURE)
    然后这边强转pImageBuffer,意思就是把 pImageBuffer当成一个PWORD读出它指向的东西,然后再进行对比

    接下来就跟之前一样了

    newbuffer->写入exe

    int newbuffer_write2_exe(PVOID NewFileBuffer, DWORD FileSize, char* FilePath)
    {
    	FILE* fp1 = fopen(FilePath, "wb");
    	if (fp1 != NULL)
    	{
    		fwrite(NewFileBuffer, FileSize, 1, fp1);
    	}
    	fclose(fp1);
    	return 1;
    
    }
    

    最后就完成了,源代码如下

    
    #include <stdio.h>
    #include <malloc.h>
    #include <windows.h>
    
    
    // exe->filebuffer  返回值为计算所得文件大小
    int ReadPEFile(char* file_path, PVOID* pFileBuffer)
    {
    	FILE* pfile = NULL;  // 文件指针
    	DWORD file_size = 0;
    	LPVOID pTempFilebuffer = NULL;
    
    	// 打开文件
    	pfile = fopen(file_path, "rb");  // 如果有新的指针,就要进行判断
    	if (!pfile)
    	{
    		printf("打开exe文件失败!
    ");//如果分配失败就要关闭文件、释放动态内存、指针指向NULL
    		return 0;
    	}
    	// 读取文件大小
    	fseek(pfile, 0, SEEK_END);
    	file_size = ftell(pfile);
    	fseek(pfile, 0, SEEK_SET);
    	// 分配空间
    	pTempFilebuffer = malloc(file_size);  // 如果有新的指针,就要进行判断
    	if (!pTempFilebuffer)
    	{
    		printf("分配空间失败!
    ");//如果分配失败就要关闭文件、释放动态内存、指针指向NULL
    		fclose(pfile);
    		return 0;
    	}
    	// 将数据读取到内存中
    	size_t n = fread(pTempFilebuffer, file_size, 1, pfile);
    	if (!n)
    	{
    		printf("数据读取到内存中失败!
    "); //如果分配失败就要关闭文件、释放动态内存、指针指向NULL
    		fclose(pfile);
    		free(pTempFilebuffer);
    		return 0;
    	}
    	// 关闭文件(已经读取到内存了)
    	*pFileBuffer = pTempFilebuffer;
    	pTempFilebuffer = NULL;
    	fclose(pfile);
    	return file_size;
    }
    
    // filebuffer -> imagebuffer
    DWORD CopyFileBufferToImageBuffer(PVOID pFileBuffer, PVOID* pImageBuffer)
    {
    	// 初始化PE头部结构体
    	PIMAGE_DOS_HEADER pDosHeader = NULL;
    	PIMAGE_NT_HEADERS pNTHeader = NULL;
    	PIMAGE_FILE_HEADER pPEHeader = NULL;
    	PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
    	PIMAGE_SECTION_HEADER pSectionHeader = NULL;
    	// 初始化IMAGE_BUFFER指针(temparay)
    	LPVOID pTempImagebuffer = NULL;
    
    	if (!pFileBuffer)
    	{
    		printf("(2pimagebuffer阶段)读取到内存的pfilebuffer无效!
    ");
    		return 0;
    	}
    	// 判断是否是可执行文件
    	if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)  // IMAGE_DOS_SIGNATURE是4字节,将pFileBuffer强制类型转换为4字节指针类型(PWORD)
    	{
    		printf("(2pimagebuffer阶段)不含MZ标志,不是exe文件!
    ");
    		return 0;
    	}
    	//强制结构体类型转换pDosHeader
    	pDosHeader = PIMAGE_DOS_HEADER(pFileBuffer);
    	//判断是否含有PE标志       
    	if (*((PDWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE) // 注意指针的加法是:去掉一个*后的类型相加。必须转换为DWORD类型再加减。
    	{																			  //相加后的和 强制类型转换为4字节指针类型(PWORD) IMAGE_NT_SIGNATURE 4BYTES
    		printf("(2pimagebuffer阶段)不是有效的PE标志!
    ");
    		return 0;
    	}
    	// 强制结构体类型转换
    	pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
    	pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
    	pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
    	pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
    
    	// 分配动态内存
    	pTempImagebuffer = malloc(pOptionHeader->SizeOfImage);
    	if (!pTempImagebuffer)
    	{
    		printf("分配动态内存失败!
    ");
    		free(pTempImagebuffer);
    		return 0;
    	}
    	// 初始化动态内存
    	memset(pTempImagebuffer, 0, pOptionHeader->SizeOfImage);
    	// 拷贝头部
    	memcpy(pTempImagebuffer, pDosHeader, pOptionHeader->SizeOfHeaders);
    	// 循环拷贝节表
    	PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
    	for (DWORD i = 0; i<pPEHeader->NumberOfSections; i++, pTempSectionHeader++)
    	{
    		memcpy((void*)((DWORD)pTempImagebuffer + pTempSectionHeader->VirtualAddress), (void*)((DWORD)pFileBuffer + pTempSectionHeader->PointerToRawData), pTempSectionHeader->SizeOfRawData);
    	}
    	// 返回数据
    	*pImageBuffer = pTempImagebuffer;
    	pTempImagebuffer = NULL;
    	return pOptionHeader->SizeOfImage;
    }
    
    //imagebuffer->newbuffer
    DWORD CopyImageBufferToNewBuffer(PVOID pImageBuffer, PVOID* pNewBuffer)
    {
    	// 初始化PE头部结构体
    	PIMAGE_DOS_HEADER pDosHeader = NULL;
    	PIMAGE_NT_HEADERS pNTHeader = NULL;
    	PIMAGE_FILE_HEADER pPEHeader = NULL;
    	PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
    	PIMAGE_SECTION_HEADER pSectionHeader = NULL;
    
    	// 初始化NEW_BUFFER指针(temparay)
    	LPVOID pTempNewbuffer = NULL;
    
    	// 判断pImageBuffer是否有效
    	if (!pImageBuffer)
    	{
    		printf("(2pnewbuffer阶段)读取到内存的pimagebuffer无效!
    ");
    		return 0;
    	}
    	//判断是不是exe文件
    	if (*((PWORD)pImageBuffer) != IMAGE_DOS_SIGNATURE)
    	{
    		printf("(2pnewbuffer阶段)不含MZ标志,不是exe文件!
    ");
    		return 0;
    	}
    	// 强制结构体类型转换
    	pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
    	if (*((PDWORD)((DWORD)pImageBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
    	{
    		printf("(2pnewbuffer阶段)不是有效的PE标志!
    ");
    		return 0;
    	}
    	// 强制结构体类型转换
    	pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageBuffer + pDosHeader->e_lfanew);
    	pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4); // 这里必须强制类型转换
    	pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
    	pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
    
    	//获取new_buffer的大小
    	int new_buffer_size = pOptionHeader->SizeOfHeaders;
    	for (DWORD i = 0; i<pPEHeader->NumberOfSections; i++)
    	{
    		new_buffer_size += pSectionHeader[i].SizeOfRawData;  // pSectionHeader[i]另一种加法
    	}
    	// 分配内存(newbuffer)
    	pTempNewbuffer = malloc(new_buffer_size);
    	if (!pTempNewbuffer)
    	{
    		printf("(2pnewbuffer阶段)分配Newbuffer失败!
    ");
    		return 0;
    	}
    	memset(pTempNewbuffer, 0, new_buffer_size);
    	// 拷贝头部
    	memcpy(pTempNewbuffer, pDosHeader, pOptionHeader->SizeOfHeaders);
    	// 循环拷贝节区
    	PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
    	for (DWORD j = 0; j<pPEHeader->NumberOfSections; j++, pTempSectionHeader++)
    	{	//PointerToRawData节区在文件中的偏移,VirtualAddress节区在内存中的偏移地址,SizeOfRawData节在文件中对齐后的尺寸
    		memcpy((PDWORD)((DWORD)pTempNewbuffer + pTempSectionHeader->PointerToRawData), (PDWORD)((DWORD)pImageBuffer + pTempSectionHeader->VirtualAddress), pTempSectionHeader->SizeOfRawData);
    	}
    	//返回数据
    	*pNewBuffer = pTempNewbuffer; //暂存的数据传给参数后释放
    	pTempNewbuffer = NULL;
    	return new_buffer_size;  // 返回计算得到的分配内存的大小
    }
    
    //newbuffer->存盘
    int newbuffer_write2_exe(PVOID NewFileBuffer, DWORD FileSize, char* FilePath)
    {
    	FILE* fp1 = fopen(FilePath, "wb");
    	if (fp1 != NULL)
    	{
    		fwrite(NewFileBuffer, FileSize, 1, fp1);
    	}
    	fclose(fp1);
    	return 1;
    
    }
    
    void operate_pe()
    {   // 初始化操作
    	PVOID pFileBuffer = NULL;
    	PVOID pImageBuffer = NULL;
    	PVOID pNewFileBuffer = NULL;
    	DWORD NewFileBufferSize = 0;
    	//char file_path[] = "D:\Lib\IPMSG2007.exe";
    	char file_path[] = "C:/Users/86183/Desktop/PEtest.exe";
    	char write_file_path[] = "C:/Users/86183/Desktop/result.exe";
    
    	// exe->filebuffer
    	int ret1 = ReadPEFile(file_path, &pFileBuffer);  // &pFileBuffer(void**类型) 传递地址对其值可以进行修改
    	printf("exe->filebuffer  返回值为计算所得文件大小:%#x
    ", ret1);
    	// filebuffer -> imagebuffer
    	int ret2 = CopyFileBufferToImageBuffer(pFileBuffer, &pImageBuffer);
    	printf("filebuffer -> imagebuffer返回值为计算所得文件大小:%#x
    ", ret2);
    	//imagebuffer->newbuffer
    	int FileSize = CopyImageBufferToNewBuffer(pImageBuffer, &pNewFileBuffer);
    	printf("imagebuffer->newbuffer返回值为计算所得文件大小:%#x
    ", FileSize);
    	//newbuffer->存盘
    	int ret4 = newbuffer_write2_exe(pNewFileBuffer, FileSize, write_file_path);
    	printf("newbuffer->存盘返回值为:%d
    ", ret4);
    }
    
    
    int main()
    {
    	operate_pe();
    	getchar();
    	return 0;
    }
    
    	
    
  • 相关阅读:
    nginx 配置优化(简单)
    Nginx 安装
    Smokeping安装教程
    test [ ] 四类
    if语句中的判断条件(nginx)
    力扣 1431. 拥有最多糖果的孩子 python
    力扣 1672. 最富有客户的资产总量+1512. 好数对的数目 python
    力扣 剑指 Offer 58
    力扣 8. 字符串转换整数 (atoi)python--每日一题
    力扣 7. 整数反转python 每日一题
  • 原文地址:https://www.cnblogs.com/0x7e/p/13794164.html
Copyright © 2020-2023  润新知