吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 11429|回复: 13
收起左侧

[分享] PE结构学习

  [复制链接]
枫笑九洲 发表于 2018-2-6 10:08
参考资料:
滴水逆向2015-03-16期。
1、PE结构简介
本论坛PE的解析的帖子以及教程非常多,我这里只是介绍一下学习的过程与思路,具体的内容还是需要自己去记忆与理解。结合PEtool或者其他的PE解析工具以及下载链接中的PDF文件,首先将pe的每个字段所在位置,整体分布,由一个宏观的把握。PE字段的命名有一定的规律,了解了文件偏移,虚拟地址,相对虚拟地址这些概念之后,一部分字段就可以猜测出含义,部分没有规律的,可以百度。
PE文件总览 https://pan.baidu.com/s/1oAkP0TG  密码: smxa

2、滴水逆向2015-03-16期课后做业
模拟一个PE文件在内存中的加载过程
1)、把一个PE文件读入内存缓冲区File->FileBuffer
2)、PE文件的拉伸,FileBuffer->ImageBuffer
3)、PE文件的还原,开辟另一块空间,把ImageBuffer重新还原成文件刚加载进内存时的样子
4)、PE文件的转存,把3得到的结果转存为文件,看看是否可以运行

3、大体思路如下:
1)、把一个PE文件读入内存缓冲区File->FileBuffer
首先读取文件大小,根据文件大小开辟缓冲区,把缓冲区初始化0,然后把PE文件代码写入缓冲区,具体函数如下:
ReadPEFile
[C++] 纯文本查看 复制代码
LPVOID ReadPEFile(LPSTR lpszFile)
{
	FILE *pFile =NULL;
	//DWORD fileSize=0;
	LPVOID pFileBuffer=NULL;
	//打开文件
	pFile=fopen(lpszFile,"rb");
	if (!pFile)
	{
		printf("无法打开EXE文件!");
		return NULL;
	}
	//读取文件大小
	fseek(pFile,0,SEEK_END);
	fileSize=ftell(pFile);
	fseek(pFile,0,SEEK_SET);
	//分配缓冲区
	pFileBuffer=malloc(fileSize);
	if (!pFileBuffer)
	{
		printf("分配空间失败!");
		fclose(pFile);
		return NULL;
	}
	//将文件数据读取到缓冲区
	size_t n=fread(pFileBuffer,fileSize,1,pFile);
	if(!n)
	{
		printf("读取数据失败!");
		free(pFileBuffer);
		fclose(pFile);
		return NULL;
	}
	//关闭文件
	fclose(pFile);
	return pFileBuffer;
}

返回指向缓冲区的指针

2)、PE文件的拉伸
拉伸前我们首先需要对PE文件的节表有一点的了解,PE文件的节表为一个结构体,具体如下:
typedef struct _IMAGE_SECTION_HEADER {
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];
    union {
            DWORD   PhysicalAddress;
            DWORD   VirtualSize;
    } Misc;
    DWORD   VirtualAddress;    //内存中偏移地址
    DWORD   SizeOfRawData;    //PE文件中对其之后的大小
    DWORD   PointerToRawData;//为PE块区在PE文件中偏移
    DWORD   PointerToRelocations;
    DWORD   PointerToLinenumbers;
    WORD    NumberOfRelocations;
    WORD    NumberOfLinenumbers;
    DWORD   Characteristics;    //块区的属性:可读、可写..
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

首先我们要开辟一个新空间,大小为可选PE头中的SizeOfImage这个参数的值,然后一个节一个节的copy过去,FileBuffer中的PointerToRawData对应ImageBuffer中的VirtualAddress,copy的大小为SizeOfRawData,具体函数如下:
CopyFileBufferToImageBuffer
[C++] 纯文本查看 复制代码
LPVOID CopyFileBufferToImageBuffer()
{
	LPVOID pFileBuffer=NULL;
	LPVOID pImageBuffer=NULL;
	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;
	pFileBuffer =ReadPEFile(FILEPATH);
	if(!pFileBuffer)
	{
		printf("文件读取失败\n");
		return 0;
	}
	//判断是否是有效的MZ标志
	if(*((PWORD)pFileBuffer)!=IMAGE_DOS_SIGNATURE)
	{
		printf("不是有效的MZ标志\n");
		free(pFileBuffer);
		return 0;
	}
	pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;

	if(*((PDWORD)((DWORD)pFileBuffer+pDosHeader->e_lfanew))!=IMAGE_NT_SIGNATURE)
	{
		printf("不是有效的PE标志\n");
		free(pFileBuffer);
		return 0;
	}
	pNTHeader=(PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew);
	
	pPEHeader=(PIMAGE_FILE_HEADER)(((DWORD)pNTHeader)+4);
	
	//可选PE头
	pOptionHeader=(PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
	pImageBuffer=malloc(pOptionHeader->SizeOfImage);
	//初始化新空间
	memset(pImageBuffer,0,pOptionHeader->SizeOfImage);
	//copy头文件到新空间
	memcpy(pImageBuffer,pFileBuffer,pOptionHeader->SizeOfHeaders);
	pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader+pPEHeader->SizeOfOptionalHeader);

	//copy节
	for (int i=0;i<pPEHeader->NumberOfSections;i++,pSectionHeader++)
	{
		memcpy((void*)((DWORD)pImageBuffer+pSectionHeader->VirtualAddress),
			(void*)((DWORD)pDosHeader+pSectionHeader->PointerToRawData),pSectionHeader->SizeOfRawData);
	
	}
	//返回pImageBuffer
	return pImageBuffer;
}


3)、PE文件的还原和保存
这一个没什么好说的,第二步的逆过程,直接上代码
CopyImageBufferToNewBuffer
[C++] 纯文本查看 复制代码
LPVOID CopyImageBufferToNewBuffer()
{
	LPVOID pImageBuffer=NULL;
	LPVOID pNewBuffer=NULL;
	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;
	FILE *pFile =NULL;
	char *FILEPATH1="c:\\NOTEPAD1.EXE";

	pImageBuffer =CopyFileBufferToImageBuffer();
	pNewBuffer=malloc(fileSize);
	//初始化NewBuffer
	memset(pNewBuffer,0,fileSize);

	pDosHeader=(PIMAGE_DOS_HEADER)pImageBuffer;
	pNTHeader=(PIMAGE_NT_HEADERS)((DWORD)pDosHeader+pDosHeader->e_lfanew );
	pPEHeader=(PIMAGE_FILE_HEADER)(((DWORD)pNTHeader)+4);
	pOptionHeader=(PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
	memcpy(pNewBuffer,pImageBuffer,pOptionHeader->SizeOfHeaders);
	pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader+pPEHeader->SizeOfOptionalHeader);
	//copy 节
	for(int i=0;i<pPEHeader->NumberOfSections;i++,pSectionHeader++)
	{
		memcpy((void*)((DWORD)pNewBuffer+pSectionHeader->PointerToRawData),
			(void*)((DWORD)pImageBuffer+pSectionHeader->VirtualAddress),pSectionHeader->SizeOfRawData);
	}
	pFile=fopen(FILEPATH1,"wb");
	fwrite(pNewBuffer,fileSize,1,pFile);

	fclose(pFile);
	return 0;
}


免费评分

参与人数 5吾爱币 +4 热心值 +4 收起 理由
雪狱苍龙 + 1 谢谢@Thanks!
邪术 + 1 谢谢@Thanks!
本物天下霸唱 + 1 + 1 用心讨论,共获提升!
?﹏從此沉默 + 1 + 1 我很赞同!
董秘书 + 1 + 1 鼓励转贴优秀软件安全工具和文档!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

董秘书 发表于 2018-2-6 10:12
感谢分享精神!
丶提莫 发表于 2018-2-6 10:22
ycfnxwl 发表于 2018-2-6 10:40
qn542231788 发表于 2018-2-6 11:20
非常感谢分享精神
li6574833 发表于 2018-2-6 12:05
不错的学习资料 谢谢
藤原拓海. 发表于 2018-2-6 14:58
谢谢楼主
181842 发表于 2018-2-6 16:38
非常感谢分享精神
tangfangxi 发表于 2018-2-7 13:15
感谢分享精神!
92013 发表于 2018-11-24 16:51
感谢分享,完全不懂…
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-19 15:21

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表