上一篇文章解析了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 <stdio.h>
#include <malloc.h>
#include <string.h>
//获取文件大小
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]='\0';
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程序解析一下 结果没有差异