PE文件结构分析

 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"> </script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值