一、PE加载的过程
1、根据SizeOfImage的大小,开辟一块缓冲区(ImageBuffer).
2、根据SizeOfHeader的大小,将头信息从FileBuffer拷贝到ImageBuffer
3、根据节表中的信息循环讲FileBuffer中的节拷贝到ImageBuffer中.
Q1、如何定位节表
可选PE头后面紧跟着的就是第一个节表.
Q2、如何确定节表个数
标准PE头里面的第二个成员:NumberOfSection 存储的就是一个有几个节表
二、FileBuffer和ImageBuffer结构
三、节表结构
typedef struct _IMAGE_SECTION_HEADER {
0x00 BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
union {
0x08 DWORD PhysicalAddress;
0x08 DWORD VirtualSize;
} Misc;
0x0c DWORD VirtualAddress;
0x10 DWORD SizeOfRawData;
0x14 DWORD PointerToRawData;
0x18 DWORD PointerToRelocations;
0x1c DWORD PointerToLinenumbers;
0x20 WORD NumberOfRelocations;
0x22 WORD NumberOfLinenumbers;
0x24 DWORD Characteristics;
};
四、编写程序打印节表中的信息.
#include "stdafx.h"
#include "string.h"
#include <malloc.h>
#include <windows.h>
WORD NumberOfSections = 0;
DWORD SizeOfHeaders = 0;
DWORD SizeOfImage = 0;
DWORD SectionAlignment = 0;
int info_Address[10] ;
int info_RawData[10] ;
int info_PointerToRawData[10];
FILE* file_open(char* file_path);
int compute_file_len(FILE* pfile);
char* allocate(int file_buf_size);
char* readfile2mem(FILE* file_address,char* pfile_buffer,int file_buf_size);
void read_PE_info(char* pfile_buffer);
void operate_pe()
{
FILE* fp2 = fopen("D:\\Lib\\test3.exe","wb");
// 打开文件
char file_path[] = "C:\\Windows\\System32\\notepad.exe";
FILE* file_address = file_open(file_path);
// 计算文件长度
int file_buf_size = compute_file_len(file_address);
printf("file_buf_size:%d\n",file_buf_size);
// 分配动态内存用于FILE_BUFFER
char* pfile_buffer = allocate(file_buf_size);
printf("===================分配FILE_BUFFER内存成功!内存地址开始:%x=========================\n",pfile_buffer);
// 将文件内容写入内存
pfile_buffer = readfile2mem(file_address,pfile_buffer,file_buf_size);
// 读取PE中的关键信息
read_PE_info(pfile_buffer);
// 重新分配一段内存用于IMAGE_BUFFER
char* pimage_buffer = allocate(SizeOfImage);
printf("===================分配IMAGE_BUFFER内存成功!内存地址开始:%x=========================\n",pfile_buffer);
// 往另一段内存中拷贝数据
//内存拷贝函数 将pfile_buffer指向的地址的内存拷贝SizeOfHeaders个字节到pimage_buffer指向的内存中去
memcpy(pimage_buffer,pfile_buffer,SizeOfHeaders);
printf("头部信息填充完毕!\n");
memset(pimage_buffer+SizeOfHeaders,0,SectionAlignment-SizeOfHeaders);
for(int j = 0;j<NumberOfSections;j++)
{ // 向新的内存中拷贝节表
memcpy(info_Address[j]+pimage_buffer,pfile_buffer+info_PointerToRawData[j],info_RawData[j]);
if(info_PointerToRawData[j]<SectionAlignment)
memset(pimage_buffer+SizeOfHeaders,0,SizeOfImage-SizeOfHeaders);
}
fwrite(pimage_buffer,SizeOfImage,1,fp2);
fclose(fp2);
free(pfile_buffer);
free(pimage_buffer);
}
FILE* file_open(char* file_path)
{
FILE* file_address = fopen(file_path,"rb");
if(!file_address)
{
printf("打开文件失败!\n");
return 0;
}
return file_address;
}
int compute_file_len(FILE* pfile)
{
int len = 0;
fseek(pfile,0,SEEK_END);
len = ftell(pfile);
fseek(pfile,0,SEEK_SET);
return len;
}
char* allocate(int buf_size)
{
char* buffer_address = (char*)malloc(buf_size);
if(!buffer_address)
{
printf("分配内存失败!\n");
return 0;
}
memset(buffer_address,0,buf_size);
return buffer_address;
}
char* readfile2mem(FILE* file_address,char* pfile_buffer,int file_buf_size)
{
if(!(fread(pfile_buffer,file_buf_size,1,file_address)))
{
printf("从文件向内存中读取数据失败!\n");
return 0;
}
return pfile_buffer;
}
void read_PE_info(char* pfile_buffer)
{
int info_01[10];
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;
pDosHeader = (PIMAGE_DOS_HEADER)pfile_buffer;
// 获取PE头部偏移
if(*((PDWORD)((DWORD)pDosHeader+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
{
printf("不是有效的PE标志!\n");
free(pfile_buffer);
return;
}
pNTHeader = PIMAGE_NT_HEADERS((DWORD)pfile_buffer+pDosHeader->e_lfanew);
printf("=====================开始查找NT头中信息=============================\n");
printf("pNTHeader:%X\n",pNTHeader);
//强制类型转化,指向标准PE头
pPEHeader = PIMAGE_FILE_HEADER((DWORD)pNTHeader+4);
printf("=====================开始查找标准PE头中信息=========================\n");
printf("pPEHeader:%X\n",pPEHeader);
printf("节的数量:%x\n",pPEHeader->NumberOfSections);
printf("SizeOfOptionalHeader(可选PE头的大小):%x\n",pPEHeader->SizeOfOptionalHeader);
NumberOfSections = pPEHeader->NumberOfSections;
// 强制类型转换,指向可选PE头
pOptionHeader = PIMAGE_OPTIONAL_HEADER32((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
printf("====================开始查找可选PE头中信息==========================\n");
printf("SizeOfImage:%x\n",pOptionHeader->SizeOfImage);
printf("SizeOfHeaders:%x\n",pOptionHeader->SizeOfHeaders);
printf("SectionAlignment:%x\n",pOptionHeader->SectionAlignment);
SizeOfHeaders = pOptionHeader->SizeOfHeaders;
SizeOfImage = pOptionHeader->SizeOfImage;
SectionAlignment = pOptionHeader->SectionAlignment;
// 强制类型转换,指向节表中的信息
printf("====================开始查找节表中信息==========================\n");
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader+pPEHeader->SizeOfOptionalHeader);
for(DWORD i = 0;i<NumberOfSections;i++,pSectionHeader++)
{
printf("VirtualAddress:%08X\n",pSectionHeader->VirtualAddress);
printf("SizeOfRawData:%08X\n",pSectionHeader->SizeOfRawData);
printf("PointerToRawData:%08X\n",pSectionHeader->PointerToRawData);
printf("==============================================\n");
info_Address[i] = pSectionHeader->VirtualAddress;
info_RawData[i] = pSectionHeader->SizeOfRawData;
info_PointerToRawData[i] = pSectionHeader->PointerToRawData;
}
printf("获得PE信息结束,准备开始向ImageBuffer存储!!\n");
}
int main()
{
operate_pe();
getchar();
return 0;
}