手工解析PE(节表)

手工解析PE(节表),第1张

上一篇文章解析了PE的前两个部分DOS头和NT头,这篇文章继续解析NT头的下一个部分 节表

首先我们需要算出第一个节表的地址,可以从PE标志开始算,

1.节表地址:PE标记[4字节]+标准PE头[20字节]+可选PE头[p_sizeofoptionalheader]

其中PE标记是固定的4字节,标准PE头是固定的20字节,可选PE头的大小不确定,但是在标准PE头中sizeofoptionalheader可以取到,所以最后还要加上sizeofoptionalheader的值

2.节表的个数:在标准PE头中numberofsections记录着

3.每个节表的大小:根据PE结构图可以看到,一个节表是40个字节

有了节表个数就可以确定循环次数了,每次循环结束后,节表的地址要增加40 到下一个节表地址

#include 
#include 
#include 
//获取文件大小
int get_file_size(char* filename)
{
	FILE* fp = fopen(filename,"r");
	int size;
	if( fp == NULL )
	{
		printf("open fail \n");
		return -1;
	}
	fseek(fp,0,SEEK_END);
	size=ftell(fp);
	fclose(fp);
	return size;
}
 
int main()
{
	char* filename="D:\\T\\zx.exe"; 
	int file_size=get_file_size(filename);

	//申请空间
	char* ptr;
	ptr = (char*) malloc(file_size);
	if( ptr == NULL)
	{
		printf("空间不足\n");
		return 0;
	}
	memset(ptr,0,file_size);
	printf("ptr:%x \n",ptr);
	//将文件内容 读取到内存
	FILE* fp = fopen(filename,"rb+");
	fread(ptr,file_size,1,fp);
	fclose(fp);
	

	//找到PE偏移
	int* p_e_lfanew=(int*)ptr+15; 
	printf("PE偏移:\t\t\t%x	\n",*p_e_lfanew);
	//PE标志
	char* p_signature = ptr+(*p_e_lfanew);				
	//标准PE头中的 节数量
	short* p_numberofsections=(short*)(p_signature+6);	
	printf("节数量:\t\t\t%x  \n",*p_numberofsections);
	//可选PE头大小
	short* p_sizeofoptionalheader=(short*)(p_signature+20);	
	printf("可选PE头大小:\t\t%x -> %d	\n",*p_sizeofoptionalheader,*p_sizeofoptionalheader);
	//内存镜像基址
	int* p_imagebase=(int*)(p_signature+52);				
	printf("内存镜像基址:\t\t%x \n",*p_imagebase);
	//内存对齐字节数
	int* p_sectionalignment=(int*)(p_signature+56);	
	printf("内存对齐字节数:\t\t%x  \n",*p_sectionalignment);
	//文件对齐字节数
	int* p_filealignment=(int*)(p_signature+60);	
	printf("文件对齐字节数:\t\t%x \n",*p_filealignment);
 
	//节表地址:DOS头[64字节]+PE标记[4字节]+标准PE头[20字节]+可选PE头[p_sizeofoptionalheader] =312=0x138
	int varsize=*p_sizeofoptionalheader;
	//char* image_section_header_base=ptr+64+4+20+(*p_sizeofoptionalheader);
	char* image_section_header_base=p_signature+4+20+(*p_sizeofoptionalheader);
	printf("节表地址:\t\t%x \n",image_section_header_base);
	
	/*
	每个节表40个字节
	char name[8]																	8字节
	int* misc 					节在文件中没有对齐时的真实大小						4字节
	int* p_virtualaddress		节在内存中的偏移(拉伸后,使用时需要+imagebase)		4字节	
	int* p_sizeofrawdata		节在文件中对齐后的大小								4字节		
	int* p_pointertorawdata		节在文件中的偏移									4字节
	int* p_pointertorelocations														4字节
	int* p_pointertolinenumbers														4字节
	short* p_numberofrelocations													2字节
	short* p_numberoflinenumbers													2字节
	int* p_characteristics		节的属性											4字节
	*/

	int i=1;
	for(i;i<=*p_numberofsections;i++)
	{
		printf("第 %d 个节:\n",i);
		//printf("image_section_header_base:%x \n",image_section_header_base);
		char name[9];
		memcpy(name,image_section_header_base,8);
		name[8]='
'; int *pmisc=(int*)(image_section_header_base+8); int *pvirtualaddress=(int*)(image_section_header_base+12); int *psizeofrawdata=(int*)(image_section_header_base+16); int *ppointertorawdata=(int*)(image_section_header_base+20); int *ppointertorelocations=(int*)(image_section_header_base+24); int *ppointertolinenumbers=(int*)(image_section_header_base+28); short *pnumberofrelocations=(short*)(image_section_header_base+32); short *pnumberoflinenumbers=(short*)(image_section_header_base+34); int *pcharacteristics=(int*)(image_section_header_base+36); printf("\t name:%s \n",name); printf("\t misc:%x \n",*pmisc); printf("\t virtualaddress:%x \n",*pvirtualaddress); printf("\t sizeofrawdata:%x \n",*psizeofrawdata); printf("\t pointertorawdata:%x \n",*ppointertorawdata); printf("\t pointertorelocations:%x \n",*ppointertorelocations); printf("\t pointertolinenumbers:%x \n",*ppointertolinenumbers); printf("\t numberofrelocations:%x \n",*pnumberofrelocations); printf("\t numberoflinenumbers:%x \n",*pnumberoflinenumbers); printf("\t characteristics:%x \n",*pcharacteristics); image_section_header_base=image_section_header_base+40; } //释放内存 free(ptr); ptr=NULL; return 0; }

执行结果如图

拿PE程序解析一下  结果没有差异

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/1324333.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-06-12
下一篇2022-06-12

发表评论

登录后才能评论

评论列表(0条)

    保存