pe格式研究1

小E qq592646022

PE(Portable Excute)格式,是微软Win32环境可执行文件的标准格式,PE文件使用的是一个平面地址空间,所有代码和数据都合并在一起,组成一个很大的结构。主要有:

  .text 是在编译或汇编结束时产生的一种块,它的内容全是指令代码

  .rdata 是运行期只读数据

  .data 是初始化的数据块

  .idata 包含其它外来DLL的函数及数据信息,即输入表

  .rsrc 包含模块的全部资源:如图标、菜单、位图等

  PE文件结构(简化):

  -----------------

  │1,DOS MZ header│

  -----------------

  │2,DOS stub │

  -----------------

  │3,PE header │

  -----------------

  │4,Section table│

  -----------------

  │5,Section 1 │

  -----------------

  │6,Section 2 │

  -----------------

  │6 Section ... │

  -----------------

  │n,Section n │

  -----------------

这些都可以在winnt.h头文件中查看到具体的结构体类型。我就不多说了,我们主要是通过编程来加深对pe格式的了解:

一、检测pe的有效性

主要通过检查dos头的MZ header和nt头也就是pe header的DWORD Signature是否位固定的值,分别为0x5A4D、0x00004550(用十六进制打开可以看到这个ascii为PE00),呵呵,我们用宏定义来替代这两个固定值。

#define IMAGE_DOS_SIGNATURE                 0x5A4D      // MZ
#define IMAGE_NT_SIGNATURE                  0x00004550 // PE00
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES    16    //这个下面会提到
typedef struct IMAGE_DOS_HEADER               //dos头的结构体定义  
{
       WORD e_magic;                                //这个就是要检测的位置是否为0x5A4D
       WORD e_cblp;
       WORD e_cp;
       WORD e_crlc;
       WORD e_cparhdr;
       WORD e_minalloc;
       WORD e_maxalloc;
       WORD e_ss;
       WORD e_sp;
       WORD e_csum;
       WORD e_ip;
       WORD e_cs;
       WORD e_lfarlc;
       WORD e_ovno;
       WORD e_res[4];
       WORD e_oemid;
       WORD e_oeminfo;
       WORD e_res2[10];
       DWORD e_lfanew;                                   //这个比较重要,指向下一个头开始的位置,也就是pe真正的开始,也就是nt头(nt_header)的开始
}IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
typedef struct IMAGE_NT_HEADERS            //nt头开始包括两个头(File头和optional头
{
       DWORD Signature;                                   //这个就是要检测的位置是否为0x00004550
       IMAGE_FILE_HEADER FileHeader;
       IMAGE_OPTIONAL_HEADER32 OptionalHeader;
}IMAGE_NT_HEADERS,*PIMAGE_NT_HEADERS;
typedef struct IMAGE_FILE_HEADER            //文件头
{
       WORD Machine;
       WORD NumberOfSections;                     //节的数量
       DWORD TimeDateStamp;
       DWORD PointerToSymbols;
       DWORD NumberOfSymbols;
       WORD SizeOfOptionalHeader;
       WORD Characteristics;
}IMAGE_FILE_HEADER,*PIMAGE_FILE_HEADER;
typedef struct IMAGE_OPTIONAL_HEADER32 //optional头,看到这么长是不是吓坏了,呵呵,其实,有的没怎么用的,都是一些类型值。比较重要的地方我标注了。
{
       WORD    Magic;                                       //幻数,听了很迷惑,呵呵,没事继续
       BYTE      MajorLinkerVersion;
       BYTE      MinorLinkerVersion;
       DWORD SizeOfCode;
       DWORD SizeOfInitializedData;                  
       DWORD SizeOfUnInitializedData;
       DWORD AddressOfEntryPoint;                         //程序入口地址
       DWORD BaseOfCode;                                      //代码基址
       DWORD BaseOfData;                                      //数据基址
       DWORD ImgaeBase;                                        //镜像基址
       DWORD SectionAlignment;                              //节对齐度也好像叫粒度
       DWORD FileAlignment;                             //文件对齐度
       WORD    MajorOperatingSystemVersion;
       WORD    MinorOperatingsystemversion;
       WORD    MajorImageVersion;
       WORD    MinorImageVersion;
       WORD    MajorSubsybtemVersion;
       WORD    MinorSubsybtemVersion;
       DWORD Win32VersionValue;
       DWORD SizeOfImage;                                     //镜像大小
       DWORD SizeoOfHeaders;
       DWORD CheckSum;
       WORD    Subsystem;
       WORD    DllCharacteristics;
       DWORD SizeOfStackReserve;
       DWORD SizeOfStackCommit;
       DWORD SizeOfHeapReserve;
       DWORD SizeOfHeapCommit;
       DWORD LoaderFlages;
       DWORD NumberOfRvaAndSizes;
       IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; //这个是DataDirectory结构体数组IMAGE_NUMBEROF_DIRECTORY_ENTRIES为宏定义值为 16
}IMAGE_OPTIONAL_HEADER32,*PIMAGE_OPTIONAL_HEADER32;


好了,我们可以开始写检测pe的有效性了,什么?你还以为还需要些什么,其实不用了,这些够我们检测pe有效性了,呵呵,开始吧。

写个主函数,会写吧,不要告诉我这个你都不会。

void main(int argc,char* argv[])
{
       IMAGE_DOS_HEADER dosheader; //定义dos头结构体变量
IMAGE_NT_HEADERS ntheader; //一样,只不过是放nt头的变量
       FILE* p;
       DWORD Sig;        / /这个放前面提到的nt头的DWORD Signature;
       //printf("%d %s",argc,argv[1]);
    //getchar();
       if(argc>1)
       {
              p=fopen(argv[1],"rb");
              if(p!=NULL)
              {    
                     fread(&dosheader,sizeof(dosheader),1,p);    //读头放到dosheader结构体变量
                     if(dosheader.e_magic==IMAGE_DOS_SIGNATURE)         //先检测dos头是否有效
                     {
                            PrintDosHeader(dosheader);
                            fseek(p,dosheader.e_lfanew,SEEK_SET);                   //定位到pe(nt头)头开始
                            fread(&Sig,sizeof(Sig),1,p);                                     //读取Signature值
                            if(Sig==IMAGE_NT_SIGNATURE)                          //检测是否有效
printf("是pe文件\n\n");                                           //有效是pe文件
                            
                     }
                     else
                            printf("无效文件\n");
                     fclose(p);
                    
              }
              else printf("Erro open file\n");
       }
       else
       {
              printf("参数不正确\n");
       }
      
}


好了,编译成功,在cmd输入 pe xxx.exe 回车看到没呵呵,pe是这个编译后的程序,xxx.exe是要检测的文件。其实也可以输出其它dos头的信息。写个函数就好了。

void PrintDosHeader(IMAGE_DOS_HEADER dosheader)
{
       printf("IMAGE_DOS_HEADER dump:\n");
       printf("e_magic        :%04x\n",dosheader.e_magic);
       printf("e_cblp    : %04x\n",dosheader.e_cblp);
       printf("e_cp      : %04x\n",dosheader.e_cp);
       printf("e_crlc    : %04x\n",dosheader.e_crlc);
       printf("e_cparhdr : %04x\n",dosheader.e_cparhdr);
       printf("e_minalloc: %04x\n",dosheader.e_minalloc);
       printf("e_maxalloc: %04x\n",dosheader.e_maxalloc);
       printf("e_ss      : %04x\n",dosheader.e_ss);

       printf("e_sp      : %04x\n",dosheader.e_sp);
       printf("e_csum    : %04x\n",dosheader.e_csum);
       printf("e_ip      : %04x\n",dosheader.e_ip);
       printf("e_cs      : %04x\n",dosheader.e_cs);
       printf("e_lfarlc : %04x\n",dosheader.e_lfarlc);
       printf("e_ovno    : %04x\n",dosheader.e_ovno);
       printf("e_res[0] : %04x\n",dosheader.e_res[0]);
       printf("e_oemid   : %04x\n",dosheader.e_oemid);
       printf("e_oeminfo : %04x\n",dosheader.e_oeminfo);
       printf("res2[0]   : %04x\n",dosheader.e_res2[0]);
       printf("lfanew    : %08x\n",dosheader.e_lfanew);
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值