PE文件(四)FileBuffer-ImageBuffer作业

C语言实现如下功能

FileBuffer转ImageBuffer

1.根据Sizeofimage分配ImageBuffer空间

2.复制头 sizeofheader获取文件对齐后所有头和节表大小

3.利用循环,PointtoRaw获取节在FileBuffer中地址,利用SizeofRawData获取要复制的数据大小

ImageBuffer转NewBuffer

1.找到最后一个节的起始位置加上其对齐大小就是所需要的NewBuffer内存大小

2.复制所有的头到NewBuffer

#include<stdio.h>
#include<Windows.h>
#include<string.h>
DWORD ReadPEFileSize(const char* lpszFile) //将一个文件的硬盘内存数据读取到自定义的文件内存缓冲区
{
	FILE* pFile = NULL;
	pFile = fopen(lpszFile, "rb");
	DWORD FileSize = 0;
	if (!pFile)
	{
		printf("无法打开EXE文件");
		return 0;
	}
	fseek(pFile, 0, SEEK_END);
	FileSize = ftell(pFile);
	return FileSize;
}
char* ReadPEFile(const char* lpszFile)
{
	FILE* pFile = NULL;
	pFile = fopen(lpszFile, "rb");
	DWORD FileSize = ReadPEFileSize(lpszFile);
	fseek(pFile, 0, SEEK_SET);
	char* pFileBuffer = NULL;
	pFileBuffer = (char*)malloc(sizeof(char) * FileSize);
	if (!pFileBuffer)
	{
		printf("分配空间失败");
		fclose(pFile);
		return 0;
	}
	size_t i = fread(pFileBuffer, FileSize, 1, pFile);
	if (!i)
	{
		printf("读取数据失败!");
		free(pFileBuffer);
		fclose(pFile);
		return 0;
	}
	IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER*)pFileBuffer;
	IMAGE_NT_HEADERS* pNTHeader = (IMAGE_NT_HEADERS*)((char*)pFileBuffer + pDosHeader->e_lfanew); //(char*)pFileBuffer只有此处转换为了char*类型,之后加减是为char的大小为一个单位进行加减
	if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
	{
		printf("不是有效MZ标志,结束\n");
		free(pFileBuffer);
		fclose(pFile);
		return 0;
	}
	if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)
	{
		printf("不是有效的PE标志,打印结束\n");
		free(pFileBuffer);
		pFileBuffer = NULL;
		return 0;
	}
	fclose(pFile);
	return pFileBuffer;
}
void FileBufferToImageBufferToNewBuffer(const char* lpszFile)
{
	char* pFileBuffer = ReadPEFile(lpszFile); //获取自定义文件内存缓冲区指针
	if (pFileBuffer == NULL)
	{
		printf("缓冲区指针无效\n");
		return;
	}
	DWORD FileSize = ReadPEFileSize(lpszFile);//获取硬盘上文件大小
	IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER*)pFileBuffer; //获取自定义文件内存缓冲区DOS头指针
	IMAGE_NT_HEADERS* pNTHeader = (IMAGE_NT_HEADERS*)((char*)pFileBuffer + pDosHeader->e_lfanew); //获取NT头指针
	IMAGE_FILE_HEADER* pFileHeader = (IMAGE_FILE_HEADER*)((char*)pNTHeader + 4);//获取标准PE头指针
	IMAGE_OPTIONAL_HEADER* pOptionHeader = (IMAGE_OPTIONAL_HEADER*)((char*)pFileHeader + 20);//获取可选PE头指针
	IMAGE_SECTION_HEADER* pSecHeader = (IMAGE_SECTION_HEADER*)((char*)pOptionHeader + pFileHeader->SizeOfOptionalHeader); // 获取文件节表指针
	char* pSecBuffer = (char*)pDosHeader + pSecHeader->PointerToRawData; //获取第一个节的指针
	char* ImageBuffer = (char*)malloc(pOptionHeader->SizeOfImage); //开辟自定义的文件的虚拟内存大小
	if (ImageBuffer == NULL)
	{
		printf("申请虚拟内存失败\n");
		return;
	}
	memset(ImageBuffer, 0, pOptionHeader->SizeOfImage); //初始化虚拟内存
	memcpy(ImageBuffer, pFileBuffer, pOptionHeader->SizeOfHeaders); //将文件内存头字段数据复制到虚拟内存
	IMAGE_DOS_HEADER* iDosHeader = (IMAGE_DOS_HEADER*)ImageBuffer; //获取自定义虚拟内存内存缓冲区DOS头指针
	IMAGE_OPTIONAL_HEADER* iOptionHeader = (IMAGE_OPTIONAL_HEADER*)((char*)iDosHeader + iDosHeader->e_lfanew + 4 + 20);//获取可选PE头指针
	IMAGE_SECTION_HEADER* iSecHeader1 = (IMAGE_SECTION_HEADER*)pSecHeader; // 获取虚拟内存节表指针
	IMAGE_SECTION_HEADER* iSecHeader2 = iSecHeader1;后续内存转硬盘用
	char* iSecBuffer1 = (char*)iDosHeader + iSecHeader1->VirtualAddress; //保存第一个节的指针
	char* iSecBuffer2 = iSecBuffer1; //后续内存转硬盘用
	for (int i = 0; i < pFileHeader->NumberOfSections; i++)//循环将文件内存的节表数据复制到虚拟内存中
	{
		memcpy((char*)iDosHeader + iSecHeader1->VirtualAddress, (char*)pDosHeader + pSecHeader->PointerToRawData, pSecHeader->SizeOfRawData); //复制文件内存节表数据
		pSecHeader++; //指向硬盘下一个节表
		iSecHeader1++;//指向内存下一个节表
	}
	pFileBuffer = NULL;
	char* NewFileBuffer = (char*)malloc(FileSize); //申请新文件内存,此处开始内存转硬盘
	if (NewFileBuffer == NULL)
	{
		printf("申请虚拟内存失败\n");
		return;
	}
	memset(NewFileBuffer, 0, FileSize);
	memcpy(NewFileBuffer, ImageBuffer, iOptionHeader->SizeOfHeaders);
	IMAGE_DOS_HEADER* NewDosHeader = (IMAGE_DOS_HEADER*)NewFileBuffer;
	IMAGE_SECTION_HEADER* NewSecHeader = (IMAGE_SECTION_HEADER*)iSecHeader2;
		for (int i = 0; i < pFileHeader->NumberOfSections; i++)
		{
			memcpy((char*)NewDosHeader + NewSecHeader->PointerToRawData, (char*)iDosHeader + iSecHeader2->VirtualAddress, iSecHeader2->SizeOfRawData);
			iSecHeader2++;
			NewSecHeader++;
		}
	free(ImageBuffer);
	free(NewFileBuffer);
}

int main(int argc, char* argv[])
{
	const char* lpszFile = "C:\\Windows\\notepad.exe";
	FileBufferToImageBufferToNewBuffer(lpszFile);
	return 0;
}

2.编写一个函数,将RVA的值转换成FOA
将文件加载到内存时,已知一个数据在内存中的地址,将此地址转化成文件在上时的相对于文件起始地址的文件偏移地址。即将虚拟内存偏移地址转换成文件偏移地址。

由于FileBuffer到ImageBuffer中,节中会有数据被初始化,这里目前来说无法解决,所以就假设节中没有未被初始化的数据,或者拉伸后未被初始化数据不影响地址转化

#include<stdio.h>
#include<Windows.h>
#include<string.h>
DWORD ReadPEFileSize(const char* lpszFile) //将一个文件的硬盘内存数据读取到自定义的文件内存缓冲区
{
	FILE* pFile = NULL;
	pFile = fopen(lpszFile, "rb");
	DWORD FileSize = 0;
	if (!pFile)
	{
		printf("无法打开EXE文件");
		return NULL;
	}
	fseek(pFile, 0, SEEK_END);
	FileSize = ftell(pFile);
	return FileSize;
}
char* ReadPEFile(const char* lpszFile)
{
	FILE* pFile = NULL;
	pFile = fopen(lpszFile, "rb");
	DWORD FileSize = ReadPEFileSize(lpszFile);
	fseek(pFile, 0, SEEK_SET);
	char* pFileBuffer = NULL;
	pFileBuffer = (char*)malloc(sizeof(char) * FileSize);
	if (!pFileBuffer)
	{
		printf("分配空间失败");
		fclose(pFile);
		return NULL;
	}
	size_t i = fread(pFileBuffer, FileSize, 1, pFile);
	if (!i)
	{
		printf("读取数据失败!");
		free(pFileBuffer);
		fclose(pFile);
		return NULL;
	}
	IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER*)pFileBuffer;
	IMAGE_NT_HEADERS* pNTHeader = (IMAGE_NT_HEADERS*)((char*)pFileBuffer + pDosHeader->e_lfanew);
	if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
	{
		printf("不是有效MZ标志,结束\n");
		free(pFileBuffer);
		pFileBuffer = NULL;
		return FALSE;
	}
	if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)
	{
		printf("不是有效的PE标志,打印结束\n");
		free(pFileBuffer);
		pFileBuffer = NULL;
		return FALSE;
	}
	fclose(pFile);
	return pFileBuffer;
}
void RVAtoFOA(const char* lpszFile)
{
	char* pFileBuffer = ReadPEFile(lpszFile); //获取自定义文件内存缓冲区指针
	IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER*)pFileBuffer; //获取自定义文件内存缓冲区DOS头指针
	IMAGE_NT_HEADERS* pNTHeader = (IMAGE_NT_HEADERS*)((char*)pFileBuffer + pDosHeader->e_lfanew) ; //获取NT头指针
	IMAGE_FILE_HEADER* pFileHeader = (IMAGE_FILE_HEADER*)((char*)pNTHeader + 4);//获取标准PE头指针
	IMAGE_OPTIONAL_HEADER* pOptionHeader = (IMAGE_OPTIONAL_HEADER*)((char*)pFileHeader + 20);//获取可选PE头指针
	IMAGE_SECTION_HEADER* pSecHeader = (IMAGE_SECTION_HEADER*)((char*)pOptionHeader + pFileHeader->SizeOfOptionalHeader); // 获取文件节表指针
	IMAGE_SECTION_HEADER* pSecHeader2 = pSecHeader;
	char* pSecBuffer = (char*)pDosHeader + pSecHeader->PointerToRawData; //获取第一个节的指针
	char* ImageBuffer = (char*)malloc(pOptionHeader->SizeOfImage); //开辟自定义的文件的虚拟内存大小
	if (ImageBuffer == NULL)
	{
		printf("申请虚拟内存失败\n");
		exit(0);
	}
	memset(ImageBuffer, 0, pOptionHeader->SizeOfImage); //初始化虚拟内存
	memcpy(ImageBuffer, pFileBuffer, pOptionHeader->SizeOfHeaders); //将文件内存头字段数据复制到虚拟内存
	IMAGE_DOS_HEADER* iDosHeader = (IMAGE_DOS_HEADER*)ImageBuffer; //获取自定义虚拟内存内存缓冲区DOS头指针
	IMAGE_NT_HEADERS* iNTHeader = (IMAGE_NT_HEADERS*)((char*)ImageBuffer + iDosHeader->e_lfanew); //获取NT头指针
	IMAGE_FILE_HEADER* iFileHeader = (IMAGE_FILE_HEADER*)((char*)iNTHeader + 4);//获取标准PE头指针
	IMAGE_OPTIONAL_HEADER* iOptionHeader = (IMAGE_OPTIONAL_HEADER*)((char*)iFileHeader + 20);//获取可选PE头指针
	IMAGE_SECTION_HEADER* iSecHeader1 = (IMAGE_SECTION_HEADER*)((char*)iOptionHeader + pFileHeader->SizeOfOptionalHeader); // 获取虚拟内存节表指针
	IMAGE_SECTION_HEADER* iSecHeader2 = iSecHeader1;
	char* iSecBuffer1 = (char*)iDosHeader + iSecHeader1->VirtualAddress; //保存第一个节的指针
	char* iSecBuffer2 = iSecBuffer1;
	for (int i = 0; i < iFileHeader->NumberOfSections; i++)//循环将文件内存的节表数据复制到虚拟内存中
	{
		memcpy(iSecBuffer1, pSecBuffer, pSecHeader->SizeOfRawData); //复制文件内存节表数据
		pSecHeader++; //指向硬盘下一个节表
		iSecHeader1++;//指向内存下一个节表
		pSecBuffer = (char*)pDosHeader + pSecHeader->PointerToRawData; //指向硬盘下一个节
		iSecBuffer1 = (char*)iDosHeader + iSecHeader1->VirtualAddress; //指向内存下一个节
	}//此时文件内存转化为虚拟内存
	//以下开始虚拟内存节地址转换硬盘内存节地址
	DWORD RVA = 0;
	iSecHeader1--;// 使节表指针指向最后一个节表1q
	DWORD LastSecBuffer = (DWORD)ImageBuffer + iSecHeader1->VirtualAddress + iSecHeader1->SizeOfRawData;//最后一个节的有效内容末尾
	DWORD min = (DWORD)ImageBuffer + iSecHeader2->VirtualAddress;
	DWORD max = (DWORD)LastSecBuffer;
	printf("请选择你要转换的地址:");
	scanf("%d", &RVA);
	while(1)
	{
		if (RVA < min)
		{
            printf("输入地址过小,请重新输入");
		    scanf("%d", &RVA);
		}
		else if (RVA > max)
		{
		    printf("输入地址过大,请重新输入");
	    	scanf("%d", &RVA);
		}
		else
		{
	         printf("输入地址正确,开始转换地址");
			 break;
		}
	}
	DWORD offset1 = RVA - (DWORD)ImageBuffer; //获取转换地址在虚拟存中相对于DOS头的偏移量
	int nNumber = 0; //用于获取转换地址所在第几个节
	while(offset1)
	{
		if (offset1 >= (DWORD)iSecHeader2->VirtualAddress && offset1 <=(DWORD)iSecHeader2->VirtualAddress + iSecHeader2->Misc.VirtualSize)
		{
			break;
		}
		else
		{
			iSecHeader2++;
			nNumber++;
		}
	}
	DWORD offset2 = offset1 - iSecHeader2->VirtualAddress; //获取转换地址相对于目标节的偏移量
	pSecHeader2 += nNumber;
	char* pSecBufferPoint = (char*)pDosHeader + pSecHeader2->PointerToRawData + offset2;
	char* iSecBufferPoint = (char*)iDosHeader + iSecHeader2->VirtualAddress + offset2;
}



int main(int argc, char* argv[])
{
	const char* lpszFile = "C:\\Windows\\notepad.exe";
	RVAtoFOA(lpszFile);
	return 0;
}

上述代码本人经过多种测试能够正确运行,但本人并没有该作业的正确代码,所以无法保证代码绝对正确

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值