PE文件结构分析

来源:互联网 发布:mac有自带画图吗 编辑:程序博客网 时间:2024/04/29 00:33

 PE文件格式(Portable Executable File Format)是windows下的可执行文件的格式, 从某种意义上讲,它反映了windows操作系统的工作方式, 对于它的了解, 可以帮助我们更加了解windows操作系统,对于windows下的编程,好处也是大大的。

在本文中, 我并不打算大讲特讲PE文件的构成是什么,每个字段是什么意思, 这些资料可以说在网上是浩瀚如海,到处都是的, 用google一搜,打开一看, 基本讲解的都是大同小异。 由于pe文件的结构比较庞大, 结构中套结构, 有的结构多达30多个字段, 光看这些字段都让人够晕的,在加上有的字段是一个32位的DWORD值, 而每一位都有其特殊的含义,这样, 光把每个字段的含义看一遍过来, 估计也得2个小时。 而实际上,这里面很多字段, 我们都不需要去了解, 也不需要去关注, 掌握那些关键字段就行了。

我觉得讲清楚一种技术, 最好的方法是例子,通过例子, 先从感性上去感受一下,然后有了这种感性的认识,然后再深入理论, 这才是比较好的办法。所以, 我这里给大家提供一个例子,这个例子是用VC6写的, 是一个C语言的控制台程序, 它要求提供一个PE文件名或者路径的参数, 然后分析这个文件的结构,并且把关键字段打印出来。你可以一边看网上的关于PE文件结构的讲解, 一边对照本程序, 我相信, 通过理论和实践的结合,你能很快的掌握PE文件的主要构成。 好了, 废话少说, 源码奉上:

// ShowPE.c

// Show The Main Structures Of the PE file

// Author: thinker

// Date: 11/28/2008

// E-Mail: cnhnyu@gmail.com

// QQ: 94483026


/*********************************************************

      PE File Format
  ------------------------------- <--+
  |     MZ  MS-DOS Header       |    |
  -------------------------------    |  Dos Headers
  |     MS DOS Stub             |    |
  ------------------------------- <--+
  |        PE00                 |    |
  -------------------------------    |
  |                             |    |
  |  IMAGE_FILE_HEADER          |    | IMAGE_NT_HEADERS32
  -------------------------------    |
  |                             |    |
  |  IMAGE_OPTIONAL_HEADER32    |    |
  |                             |    |
  ------------------------------- <--+   
  |   Section Header 1          |    |
  |-----------------------------|    |
  |   Section Header 2          |    |
  -------------------------------    |  Section Headers
  |     ..............          |    |
  |-----------------------------|    |
  |   Section Header N          |    |
  ------------------------------- <--+
  |   Section Data 1            |    |
  |-----------------------------|    |
  |   Section Data 2            |    |
  -------------------------------    |  Section Datas
  |     ...............         |    |
  -------------------------------    |
  |   Section Data N            |    |
  ------------------------------- <--+

**********************************************************/


#include <stdio.h>
#include <windows.h>
#include <time.h>

// Data Directory Description

char szDataDirectory[16][64] = {
    "Export Directory",
    "Import Directory",
    "Resource Directory",
    "Exception Directory",
    "Security Directory",
    "Base Relocation Table",
    "Debug Directory",
    "Architecture Specific Data",
    "RVA of GP",
    "TLS Directory",
    "Load Configuration Directory",
    "Bound Import Directory in headers",
    "Import Address Table",
    "Delay Load Import Descriptors",
    "COM Runtime descriptor"
};

HANDLE hFile = NULL;
HANDLE hFileMapping = NULL;
void* pFileBase = NULL;
IMAGE_DOS_HEADER *pDosHeader = NULL;
IMAGE_NT_HEADERS *pNTHeader = NULL;
IMAGE_SECTION_HEADER *pSectionHeader = NULL;


DWORD RVA2FileOffset(DWORD dwRVA);

int main(int argc, char **argv)
{
    struct tm* ptm;
    DWORD dwIndex;

    IMAGE_IMPORT_DESCRIPTOR *pImportDescriptor = NULL;
    IMAGE_THUNK_DATA *pThunkData = NULL;
    IMAGE_IMPORT_BY_NAME *pImportByName = NULL;

    IMAGE_EXPORT_DIRECTORY *pExportDirectory = NULL;

    DWORD *pdw;
    WORD *pw;

    if ( argc != 2 )
    {
        printf("Usage:/n/t%s PEFile/n", argv[0]);
        return -1;
    }


    /*********************** Map the file to memory *************************/
    hFile = CreateFile(argv[1], GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL);
    if ( hFile == INVALID_HANDLE_VALUE )
    {
        printf("Open File Error./n");
        return -1;
    }
    hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
    if ( !hFileMapping )
    {
        CloseHandle(hFile);
        printf("Create File Mapping Error./n");
        return -1;
    }

    pFileBase = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
    if ( !pFileBase )
    {
        CloseHandle(hFileMapping);
        CloseHandle(hFile);
        printf("Map View Of File Error./n");
        return -1;
    }
    /*********************** Map end *****************************************/

    // get the dos heaader pointer

    pDosHeader = (IMAGE_DOS_HEADER*)pFileBase;
    if ( pDosHeader->e_magic != IMAGE_DOS_SIGNATURE )
    {
        printf("Unknow File Format./n");
        goto End;
    }
    printf("%-35s%s/n/n", "FileName:", argv[1]);
    printf("%-35s%#010x/n", "Dos Stub Size:", pDosHeader->e_lfanew - sizeof(IMAGE_DOS_HEADER));
    printf("%-35s%#010x/n", "NT File RVA:", pDosHeader->e_lfanew);

    // get the nt header pointer

    pNTHeader = (IMAGE_NT_HEADERS*)((char*)pFileBase + pDosHeader->e_lfanew);
    if ( pNTHeader->Signature != IMAGE_NT_SIGNATURE )
    {
        printf("Not NT File./n");
        goto End;
    }

    // get the section header pointer

    pSectionHeader = (IMAGE_SECTION_HEADER*)((char*)pNTHeader + sizeof(IMAGE_NT_HEADERS));

    printf("/n%-35s%s/n", "nRun Platform:", (pNTHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386) ? "Intel 386" : "Other" );
    printf("%-35s%d/n", "NumOfSections:", pNTHeader->FileHeader.NumberOfSections);
    ptm = localtime(&pNTHeader->FileHeader.TimeDateStamp);

    printf("%-35s%02d/%02d/%04d %02d:%02d:%02d/n", "FileCreateTime:", ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_year + 1900,
         ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
    //printf("%.19s/n", asctime(ptm));

    printf("%-35s%#010x/n", "SizeofOptionHdr:", pNTHeader->FileHeader.SizeOfOptionalHeader);
    printf("%-35s%s/n", "File Type:", (pNTHeader->FileHeader.Characteristics & IMAGE_FILE_DLL) ? "DLL" : "EXE");


    printf("/n%-35s%s/n", "Image Type:", (pNTHeader->OptionalHeader.Magic == 0x10B) ? "Exe Image" : "Other");
    printf("%-35s%d.%d/n", "Linker Version:", pNTHeader->OptionalHeader.MajorLinkerVersion, pNTHeader->OptionalHeader.MinorLinkerVersion);
    printf("%-35s%#010x/n", "SizeofCode:", pNTHeader->OptionalHeader.SizeOfCode);
    printf("%-35s%#010x/n", "AddressOfEntryPoint:", pNTHeader->OptionalHeader.AddressOfEntryPoint);
    printf("%-35s%#010x/n", "DefaultLoadAddress:", pNTHeader->OptionalHeader.ImageBase);
    printf("%-35s%#010x/n", "SectionAlignment:", pNTHeader->OptionalHeader.SectionAlignment);
    printf("%-35s%#010x/n", "FileAlignment:", pNTHeader->OptionalHeader.FileAlignment);
    printf("%-35s%d.%d/n", "OS SystemVersion:", pNTHeader->OptionalHeader.MajorOperatingSystemVersion,
         pNTHeader->OptionalHeader.MinorOperatingSystemVersion);
    printf("%-35s%d.%d/n", "ImageVersion:", pNTHeader->OptionalHeader.MajorImageVersion,
         pNTHeader->OptionalHeader.MinorImageVersion);
    printf("%-35s%d.%d/n", "SubSystemVersion:", pNTHeader->OptionalHeader.MajorSubsystemVersion,
         pNTHeader->OptionalHeader.MinorSubsystemVersion);
    printf("%-35s%#010d/n", "SizeOfIamge:", pNTHeader->OptionalHeader.SizeOfImage);
    printf("%-35s%#010d/n", "SizeOfHeaders:", pNTHeader->OptionalHeader.SizeOfHeaders);
    if ( pNTHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI )
        printf("%-35s%s/n", "GUI System:", "Windows GUI");
    else if ( pNTHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
        printf("%-35s%s/n", "GUI System:", "Windows Console");
    else
        printf("%-35s%s/n", "GUI System:", "Other");

    printf("/n-----------------------------Data Directory----------------------------------/n");
    printf("#Index/t#Virtual Address/t#Size/t/t#%-32s/n", "Directory Name");
    for (dwIndex = 0; dwIndex < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; dwIndex++ )
    {
        printf("0x%02x/t0x%08x/t0x%08x/t%-50s/n", dwIndex,
            pNTHeader->OptionalHeader.DataDirectory[dwIndex].VirtualAddress,
            pNTHeader->OptionalHeader.DataDirectory[dwIndex].Size, szDataDirectory[dwIndex]);
    }
    printf("/n/n-----------------------------Section Headers----------------------------------/n");
    printf("#VirtualAddress/t#VirtualSize/t#PointerToRawData/t#SizeOfRawData/t#Name/n");
    for ( dwIndex = 0; dwIndex < pNTHeader->FileHeader.NumberOfSections; dwIndex++ )
    {
        printf("0x%08x/t0x%08x/t0x%08x/t/t0x%08x/t%-10s/n", pSectionHeader[dwIndex].VirtualAddress,
            pSectionHeader[dwIndex].Misc.VirtualSize, pSectionHeader[dwIndex].PointerToRawData,
            pSectionHeader[dwIndex].SizeOfRawData, pSectionHeader[dwIndex].Name);
    }

    // Import Table

    printf("/n/n-------------------------Import Table-------------------------------------/n");
    pImportDescriptor = (IMAGE_IMPORT_DESCRIPTOR*)((char*)pFileBase + RVA2FileOffset(pNTHeader->OptionalHeader.DataDirectory[1].VirtualAddress));
    for ( ; *(char*)pImportDescriptor ; pImportDescriptor++ )
    {
        printf("Import Lib: %s/n", (char*)(RVA2FileOffset(pImportDescriptor->Name) + (char*)pFileBase));
        pThunkData = (IMAGE_THUNK_DATA*)(RVA2FileOffset(pImportDescriptor->OriginalFirstThunk) + (char*)pFileBase);
        for ( ; pThunkData->u1.AddressOfData; pThunkData++ )
        {
            if ( pThunkData->u1.Ordinal & IMAGE_ORDINAL_FLAG32 ) // import by index

            {
                printf("/t0x%04x/n", pThunkData->u1.Ordinal & 0xffff);
            }
            else // import by name

            {
                pImportByName = (IMAGE_IMPORT_BY_NAME*)(RVA2FileOffset(pThunkData->u1.Ordinal) + (char*)pFileBase);
                printf("/t0x%04x/t%s/n", pImportByName->Hint, pImportByName->Name);
            }
        }
        printf("/n");
    }

    if ( pNTHeader->OptionalHeader.DataDirectory[0].Size == 0 ) // Export Table Not Exist

        goto End;

    // Export Table

    printf("/n/n------------------------Export Table---------------------------------/n");
    
    pExportDirectory = (IMAGE_EXPORT_DIRECTORY*)(RVA2FileOffset(pNTHeader->OptionalHeader.DataDirectory[0].VirtualAddress) + (char*)pFileBase);
    printf("Export Lib: /t%s/n", (char*)(RVA2FileOffset(pExportDirectory->Name) + (char*)pFileBase));
    printf("/tIndex/tName/t/t/n");
    printf("/t------------------------------/n");
    for ( dwIndex = 0; dwIndex < pExportDirectory->NumberOfNames; dwIndex++ )
    {
        pdw = (DWORD*)(RVA2FileOffset(pExportDirectory->AddressOfNames) + (char*)pFileBase);
        pw = (WORD*)(RVA2FileOffset(pExportDirectory->AddressOfFunctions) + (char*)pFileBase);
        printf("/t0x%04x/t%-20s/n", dwIndex, (char*)(RVA2FileOffset(pdw[dwIndex]) + (char*)pFileBase), pw[dwIndex]);
    }


End:
    UnmapViewOfFile(pFileBase);
    CloseHandle(hFileMapping);
    CloseHandle(hFile);

    return 0;
}

/*
   Convert RVA To File Offset
*/

DWORD RVA2FileOffset(DWORD dwRVA)
{
    DWORD dwNum, dwIndex;

    if ( pNTHeader == NULL )
        return 0;
    if ( pSectionHeader == NULL )
        return 0;
    dwNum = pNTHeader->FileHeader.NumberOfSections;
    for ( dwIndex = 0; dwIndex < dwNum; dwIndex++ )
    {
        if ( dwRVA >= pSectionHeader[dwIndex].VirtualAddress &&
             dwRVA <= pSectionHeader[dwIndex].VirtualAddress + pSectionHeader[dwIndex].SizeOfRawData)
        {
            return dwRVA - pSectionHeader[dwIndex].VirtualAddress + pSectionHeader[dwIndex].PointerToRawData;
        }
    }
    return 0;
}

<script type="text/javascript"><!-- google_ad_client = "pub-8062742131839416";/* 728x90, created 7/12/09 */google_ad_slot = "4877331128";google_ad_width = 728;google_ad_height = 90;// --></script><script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script>

原创粉丝点击