检查程序是否是PE文件

检查程序是否是PE文件

说明:

判断一个文件是否是PE文件。本例主要判断DOS头,NT头。利用两种方式进行判断,一种是WIN32的函数;另一种是MFC的方法。但是思路是一致的。

 

PE结构适用于windows系统的程序,即.exe。

PE(Portable Execute)文件是Windows下可执行文件的总称,常见的有DLL,EXE,OCX,SYS等,事实上,一个文件是否是PE文件与其扩展名无关,PE文件可以是任何扩展名。那Windows是怎么区分可执行文件和非可执行文件的呢?我们调用LoadLibrary传递了一个文件名,系统是如何判断这个文件是一个合法的动态库呢?这就涉及到PE文件结构了。

PE文件的结构一般来说如下图所示:从起始位置开始依次是DOS头,NT头,节表以及具体的节。

概念:

(1)DOS头是用来兼容MS-DOS操作系统的,目的是当这个文件在MS-DOS上运行时提示一段文字,大部分情况下是:This program cannot be run in DOS mode.还有一个目的,就是指明NT头在文件中的位置。(用记事本打开任何一个镜像文件,其头2个字节必为字符串“MZ”,这是Mark Zbikowski的姓名缩写,他是最初的MS-DOS设计者之一。)

(2)NT头包含windows PE文件的主要信息,其中包括一个‘PE’字样的签名,PE文件头(IMAGE_FILE_HEADER)和PE可选头(IMAGE_OPTIONAL_HEADER32),头部的详细结构以及其具体意义在PE文件头文章中详细描述。

(3)节表:是PE文件后续节的描述,windows根据节表的描述加载每个节。

(4)节:每个节实际上是一个容器,可以包含代码、数据等等,每个节可以有独立的内存权限,比如代码节默认有读/执行权限,节的名字和数量可以自己定义,未必是上图中的三个。

 

对于一个PE文件来说,最开始的位置就是一个DOS程序。DOS程序包含一个DOS头和一个DOS程序体。

DOS头部是由IMAGE_DOS_HEADER结构体来定义的。

该结构体定义如下:

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header

    WORD   e_magic;                     // Magic number

    WORD   e_cblp;                      // Bytes on last page of file

    WORD   e_cp;                        // Pages in file

    WORD   e_crlc;                      // Relocations

    WORD   e_cparhdr;                   // Size of header in paragraphs

    WORD   e_minalloc;                  // Minimum extra paragraphs needed

    WORD   e_maxalloc;                  // Maximum extra paragraphs needed

    WORD   e_ss;                        // Initial (relative) SS value

    WORD   e_sp;                        // Initial SP value

    WORD   e_csum;                      // Checksum

    WORD   e_ip;                        // Initial IP value

    WORD   e_cs;                        // Initial (relative) CS value

    WORD   e_lfarlc;                    // File address of relocation table

    WORD   e_ovno;                      // Overlay number

    WORD   e_res[4];                    // Reserved words

    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)

    WORD   e_oeminfo;                   // OEM information; e_oemid specific

    WORD   e_res2[10];                  // Reserved words

    LONG   e_lfanew;                    // File address of new exe header

  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

 

注意:

(1)该结构体中,有两个字段需要注意,分别是第一个字段 e_magic,和最后一个字段 e_lfanew字段。

(2)e_magic 字段是一个DOS可执行文件的标识符,该字段占用两个字节,该位置保存着的字符是“MZ”。

(3)e_lfanew字段是文件的新头部,即到了NT头。或称为偏移量。

 

步骤:

1.在对话框中,放置好如下图的控件。

 

2.在打开按钮中,编写文件对话框,选择要判断的程序。

CFileDialog filedlg(TRUE);

         if (filedlg.DoModal())

         {

                   strPath=filedlg.GetPathName();

                   SetDlgItemText(IDC_EDT_PATH, strPath);

         }

 

3.打开文件、读取文件内容

WIN32版:

打开文件

HANDLE hFile = CreateFile(strPath, GENERIC_READ, FILE_SHARE_READ, NULL,

                            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

读取文件内容,dosHeader可获取DOS头,dwReadSize获取DOS头大小

::ReadFile(hFile, &dosHeader, sizeof(IMAGE_DOS_HEADER), & &dwReadSize,, NULL);

 

FMC版:

dwSize = file.Read(&dosHeader, sizeof(IMAGE_DOS_HEADER));

同理,osHeader可获取DOS头,dwSize获取DOS头大小

 

4.此时已经取出DOS头的内容,判断与系统规定的DOS头是否一致。

dosHeader.e_magic != IMAGE_DOS_SIGNATURE;

IMAGE_DOS_SIGNATURE 宏定义。实质是“MZ”

 

5.移动文件内部的指针,将指针移动到NT头。

IMAGE_NT_HEADERS32 ntHeader;

SetFilePointer(hFile, dosHeader.e_lfanew, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)

注意:IMAGE_NT_HEADERS32 是32位系统。若64位系统用IMAGE_NT_HEADERS64

 

6.同理,取出NT头的内容和大小,再进行判断。

::ReadFile(hFile, &ntHeader, sizeof(IMAGE_NT_HEADERS32), &dwReadSize, NULL);

NT头判断

ntHeader.Signature != IMAGE_NT_SIGNATURE

 

7.最后,若DOS和NT头都与系统一致,属于PE结构;否则不属于。

打开按钮的源代码:
void CReadFilePEDlg::OnBnClickedBtnOpen()
{
    // TODO:  在此添加控件通知处理程序代码
    
    CFileDialog filedlg(TRUE);
    if (filedlg.DoModal())
    {
        strPath=filedlg.GetPathName();
        SetDlgItemText(IDC_EDT_PATH, strPath);
    }

}
WIN32检查PE结构的源代码:
void CReadFilePEDlg::OnBnClickedBtnPe()
{
    // TODO:  在此添加控件通知处理程序代码
    //MessageBox(L"ddd");
    CString strFlat;
    if (strPath.IsEmpty())
    {
        OnBnClickedBtnOpen();
    }
    HANDLE hFile = CreateFile(strPath, GENERIC_READ, FILE_SHARE_READ, NULL,
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (!hFile)
    {
        MessageBox(L"打开文件失败!");
        return ;
    }
    else
    {

        //判断dos部分是否一致
        IMAGE_DOS_HEADER dosHeader;
        DWORD dwReadSize;
        ::ReadFile(hFile, &dosHeader, sizeof(IMAGE_DOS_HEADER), &dwReadSize, NULL);
        
        if (dwReadSize != sizeof(IMAGE_DOS_HEADER))
        {
            MessageBox(L"DOS的长度不一致!");
            return;
        }
        //e_magic是DOS可执行文件的标识符,存放"MZ",
        if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE)
        {
            MessageBox(L"DOS的标识符不一致!不是PE结构");
            return;
        }

        //文件移位都NT结构,再判断NT部分是否一致
        IMAGE_NT_HEADERS32 ntHeader;
        if (SetFilePointer(hFile, dosHeader.e_lfanew, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
        {
            MessageBox(L"无法移动呢文件内部指针!");
            return;
        }
        ::ReadFile(hFile, &ntHeader, sizeof(IMAGE_NT_HEADERS32), &dwReadSize, NULL);
        if (dwReadSize != sizeof(IMAGE_NT_HEADERS32))
        {
            MessageBox(L"NT的长度不一致!");
            return;
        }
        if (ntHeader.Signature != IMAGE_NT_SIGNATURE)
        {
            MessageBox(L"NT的标识符不一致!不是PE结构");
            return;
        }    
        strFlat = L"属于PE结构";
    }
    ::CloseHandle(hFile);
    MessageBox(strFlat);
}
MFC检查PE结构的源代码:
void CReadFilePEDlg::OnBnClickedBtnPe2()
{
    // TODO:  在此添加控件通知处理程序代码
    CString strFlat;
    if (strPath.IsEmpty())
    {
        OnBnClickedBtnOpen();
    }
    CFile file;
    if (!file.Open(strPath, CFile::modeRead))
    {
        MessageBox(L"打开文件失败!");
    }
    else
    {
        IMAGE_DOS_HEADER dosHeader;
        DWORD dwSize;
        dwSize = file.Read(&dosHeader, sizeof(IMAGE_DOS_HEADER));
        if (dwSize != sizeof(IMAGE_DOS_HEADER))
        {
            MessageBox(L"DOS的长度不一致!");
            return;
        }
        if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE)
        {
            MessageBox(L"DOS的标识符不一致!不是PE结构");
            return;
        }

        IMAGE_NT_HEADERS32 ntHeader;
        if (!file.Seek(dosHeader.e_lfanew, CFile::begin))
        {
            MessageBox(L"无法移动呢文件内部指针!");
            return;
        }
        dwSize = file.Read(&ntHeader, sizeof(IMAGE_NT_HEADERS32));
        if (dwSize != sizeof(IMAGE_NT_HEADERS32))
        {
            MessageBox(L"NT的长度不一致!");
            return;
        }
        if (ntHeader.Signature != IMAGE_NT_SIGNATURE)
        {
            MessageBox(L"NT的标识符不一致!不是PE结构");
            return;
        }
        strFlat = L"属于PE结构!";
    }
    MessageBox(strFlat);
}

 

posted @ 2017-09-08 19:55  gd_沐辰  阅读(1279)  评论(0编辑  收藏  举报