dong's profileThinking ...PhotosBlogLists Tools Help

Blog


    PE文件分析15

    导出函数节.edata
      导出函数节提供本文件中可以提供其他程序用的函数列表。一般用于DLL中,
     由两种实现方法,通过函数名导出或者通过序数导出。以此序数作为参数,可以通过GetProcAddress作为调用参数。
    导出节的开始,是一个IMAGE_EXPORT_DIRECTORY结构。来自Visual Studio 2005 中winnt.h
    // Export Format
    typedef struct _IMAGE_EXPORT_DIRECTORY {
        DWORD   Characteristics;
        DWORD   TimeDateStamp;
        WORD    MajorVersion;
        WORD    MinorVersion;
        DWORD   Name;
        DWORD   Base;
        DWORD   NumberOfFunctions;
        DWORD   NumberOfNames;
        DWORD   AddressOfFunctions;     // RVA from base of image
        DWORD   AddressOfNames;         // RVA from base of image
        DWORD   AddressOfNameOrdinals;  // RVA from base of image
    } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
    Name:是一个RVA,指向模块的真实名称,即指向DLL的名字
    Base :导出函数序号的起始值,将AddressOfFunctions字段指向的入口地址表的索引号加上这个起始值,就是对应的函数的导出号。
    NumberOfFunctions:模块导出的函数/符号总数
    NumberOfNames:通过名字导出的函数符号总数
    AddressOfFunctions 一个RVA是由NumberOfFunction个函数的入口地址组成的数组的地址
    指向模块中NumberOfNames个通过函数名字索引的函数入口地址组成的数组的地址
    AddressOfNameDrdinals:指向AddressOfNames数组中相关函数的序数组成的数组,数组的项目是文件名称地址表AddressOfFunctions的索引。

    如果已知导出函数名,获取函数地址的步骤如下
    1 定位到PEheader
    2从数据目录表读取名字导出表的虚拟地址
    3定位导出表获取名字数目(NumberOfNames)
    4 并行遍历AddressOfNames和AddressOfNameOrdinals指向的数组匹配名字,如果在AddressOfNames指向的数组中找到名字,从AddressOfNameOrdinals指向的数组中提取索引值。
    5 从AddressOfNameOrdinals数组提取的数值作为AddressOfFunctions数组的索引,这就找到了所需函数的RVA
    如果已知函数的序数,获取函数地址的一般步骤如下:
    1 定位到PEheader
    2 从数据目录表读出导出表的RVA
    3 定位导出表获取Base值
    4 减去Base值得到指向AddressOfFunction数组的索引,
    5 将该值与NumberOfFuctions值做比较,如果大于这个值则说明无效,
    6 通过索引轻松获取AddressOfFunctions数组中的RVA

    下一步我准备用C++做一个读取PE中信息的程序
    实在不行还是用C#吧

    PE文件分析14

    idata节的起始地址是A4400H,长度实际有3000H,对齐后有竟然只有2800H,不能理解,我又看了几个多于一个字节exe这种情况还不少
      转到A4400H
    下面分析IMAGE_IMPORT_DESCRIPTOR结构数组的元素
    typedef struct _IMAGE_IMPORT_DESCRIPTOR {
        union {
            DWORD   Characteristics;            // 0 for terminating null import descriptor
            DWORD   OriginalFirstThunk;         // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
               };
        DWORD   TimeDateStamp;       // 0 if not bound,
                           // -1 if bound, and real date\time stamp
           //    in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
            // O.W. date/time stamp of DLL bound to (Old BIND)
        DWORD   ForwarderChain;                 // -1 if no forwarders
        DWORD   Name;
        DWORD   FirstThunk;                     // RVA to IAT (if bound this IAT has actual addresses)
    } IMAGE_IMPORT_DESCRIPTOR;
    它只有20个字节,但这只是数组的一个元素而已
    这个数组结束的标志是最后一项全是0,因为很长,图上
    类型    名称    偏移    实例值    含义
    DWORD
    union    Characteristics/
    OriginalFirstThunk    00    B4300E00    见下面的解说
    DWORD    TimeDateStamp    04    0000 0000   
    DWORD    ForwarderChain    08    0000 0000   
    DWORD    Name    1C    243D 0E00   
    DWORD    FirstThunk    20    0431 OE00   
    看不到结尾
    这里比较复杂,FirstThunk和OriginalFirstThunk都是指向一个由一个联合体元素构成的数组的指针,,这个数组又指向另一个记录了dll中函数名的数组,这个联合体是DWORD型的,实际被调用的dll中的函数地址在结构体中,如果调用则存入FirstThunk所指的数组中,但是OriginalFirstThunk指向的数组的值不会改变。它们的关系图如下
    图:引自侯俊杰:PE文件格式学习,外加自己手绘

    他们各自的结构定义如下:
    typedef struct _IMAGE_THUNK_DATA32 {
        union {
            DWORD ForwarderString;      // PBYTE
            DWORD Function;             // PDWORD
            DWORD Ordinal;
            DWORD AddressOfData;        // PIMAGE_IMPORT_BY_NAME
        } u1;
    } IMAGE_THUNK_DATA32;
    typedef IMAGE_THUNK_DATA32              IMAGE_THUNK_DATA

    typedef struct _IMAGE_IMPORT_BY_NAME {
        WORD    Hint;
        BYTE    Name[1];
    } IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

    数组的个数就是导入的DLL的个数。
    列出某个PE文件所有导入函数的步骤
    1 校验文件是不是有效的PE文件
    2 从DOSHeader定位到PEheader
    3 获取OptionalHeader数据目录表地址
    4跳转致数据目录表的第二个成员-导入目录,提取其VirtualAddress的值
    5利用上值定位第一个IMAGE_IMPORT_DESCRIPTOR结构
    6
       检查OriginalFirstThunk的值,如果不是零,沿着OriginalFirstThunk里面的RVA转入其指向的RVA数组,若OriginalFirstThunk为零,就改用FirstThunk。
      对于每个数组元素比对元素值是否等于IMAGE_ORDINAL_FLAG32(80000000H)
    如果该元素值的最高二进制位为1,那么函数是由序数导入的,可以从该值的第字节提取序数。如果该元素值的最高二进制位为0,就可以将该值作为RVA转入IMAGE_IMPORT_BY_NAME数组,跳过Hint就得到函数名了。
    再跳到下一个数组元素提取函数名一直到数组的底部,(它以NULL结尾)这样就遍历完了一个DLL导入函数,接下去处理下一个DLL
    7 跳转到下一个IMAGE_IMPORT_DESCRIPTOR并处理之,如此循环直到数组的最后一个元素,它以全零结尾。

    PE文件中,所有DLL对应的导入地址数组在位置上排列在一起,全部这些数组的组合,称作导入地址表,FirstThunk指向导入地址表的起始地址。
    另外,在IMAGE_DTA_DIRECTORY中,第十三项也提供了这个信息

    PE文件实例分析12

    idata节的起始地址是A4400H,长度实际有3000H,对齐后有竟然只有2800H,不能理解,我又看了几个多于一个字节exe这种情况还不少

      转到A4400H

    PE文件实例分析11

    虽然节表中对于节的 个数是确定的,数组大小也是定制的,但是在节表的后面到真正的节之前仍有一块区域全是零,这在test.exe中就是220h400h之间的那一部分,

    节的起始位置在节表中已经明确给出,PointerToRawData记录了这个节开始的位置,节对齐后的尺寸。由UE可见,有非零数据的部分仅仅是400h41Eh这一小部分后面有一大部分0区,这是病毒藏身之所。

    .text 代码节,

    .idata导入函数节

    含有从其他DLLkernel32.dlluser32.dll中导入的函数地址。

    这个节的开始是一个IMAGE_IMPORT_DESCRIPTOR结构的数组,这就是导入地址表(IAT)即导入表。可惜test.exe中没有idata项。iceSword.exe中也没有,峰回路转,幸好我发现winrar安装文件中的WinRARr.exe中含有这个idata节,就那它来分析吧

    PE文件实例分析10

    Characteristics

    代码节一般是60000020H 可读写,可执行,节中包含代码

    数据节一般是:C0000040H 可读可写,包含已初始化数据

    节属性的定义:来自微软VisualStudio2005 winnt.h

    //

    // Section characteristics.

    //

    //      IMAGE_SCN_TYPE_REG                   0x00000000  // Reserved.

    //      IMAGE_SCN_TYPE_DSECT                 0x00000001  // Reserved.

    //      IMAGE_SCN_TYPE_NOLOAD                0x00000002  // Reserved.

    //      IMAGE_SCN_TYPE_GROUP                 0x00000004  // Reserved.

    #define IMAGE_SCN_TYPE_NO_PAD                0x00000008  // Reserved.

    //      IMAGE_SCN_TYPE_COPY                  0x00000010  // Reserved.

     

    #define IMAGE_SCN_CNT_CODE                   0x00000020  // Section contains code.

    #define IMAGE_SCN_CNT_INITIALIZED_DATA       0x00000040  // Section contains initialized data.

    #define IMAGE_SCN_CNT_UNINITIALIZED_DATA     0x00000080  // Section contains uninitialized data.

     

    #define IMAGE_SCN_LNK_OTHER                  0x00000100  // Reserved.

    #define IMAGE_SCN_LNK_INFO                   0x00000200  // Section contains comments or some other type of information.

    //      IMAGE_SCN_TYPE_OVER                  0x00000400  // Reserved.

    #define IMAGE_SCN_LNK_REMOVE                 0x00000800  // Section contents will not become part of image.

    #define IMAGE_SCN_LNK_COMDAT                 0x00001000  // Section contents comdat.

    //                                           0x00002000  // Reserved.

    //      IMAGE_SCN_MEM_PROTECTED - Obsolete   0x00004000

    #define IMAGE_SCN_NO_DEFER_SPEC_EXC          0x00004000  // Reset speculative exceptions handling bits in the TLB entries for this section.

    #define IMAGE_SCN_GPREL                      0x00008000  // Section content can be accessed relative to GP

    #define IMAGE_SCN_MEM_FARDATA                0x00008000

    //      IMAGE_SCN_MEM_SYSHEAP  - Obsolete    0x00010000

    #define IMAGE_SCN_MEM_PURGEABLE              0x00020000

    #define IMAGE_SCN_MEM_16BIT                  0x00020000

    #define IMAGE_SCN_MEM_LOCKED                 0x00040000

    #define IMAGE_SCN_MEM_PRELOAD                0x00080000

     

    #define IMAGE_SCN_ALIGN_1BYTES               0x00100000  //

    #define IMAGE_SCN_ALIGN_2BYTES               0x00200000  //

    #define IMAGE_SCN_ALIGN_4BYTES               0x00300000  //

    #define IMAGE_SCN_ALIGN_8BYTES               0x00400000  //

    #define IMAGE_SCN_ALIGN_16BYTES              0x00500000  // Default alignment if no others are specified.

    #define IMAGE_SCN_ALIGN_32BYTES              0x00600000  //

    #define IMAGE_SCN_ALIGN_64BYTES              0x00700000  //

    #define IMAGE_SCN_ALIGN_128BYTES             0x00800000  //

    #define IMAGE_SCN_ALIGN_256BYTES             0x00900000  //

    #define IMAGE_SCN_ALIGN_512BYTES             0x00A00000  //

    #define IMAGE_SCN_ALIGN_1024BYTES            0x00B00000  //

    #define IMAGE_SCN_ALIGN_2048BYTES            0x00C00000  //

    #define IMAGE_SCN_ALIGN_4096BYTES            0x00D00000  //

    #define IMAGE_SCN_ALIGN_8192BYTES            0x00E00000  //

    // Unused                                    0x00F00000

    #define IMAGE_SCN_ALIGN_MASK                 0x00F00000

     

    #define IMAGE_SCN_LNK_NRELOC_OVFL            0x01000000  // Section contains extended relocations.

    #define IMAGE_SCN_MEM_DISCARDABLE            0x02000000  // Section can be discarded.

    #define IMAGE_SCN_MEM_NOT_CACHED             0x04000000  // Section is not cachable.

    #define IMAGE_SCN_MEM_NOT_PAGED              0x08000000  // Section is not pageable.

    #define IMAGE_SCN_MEM_SHARED                 0x10000000  // Section is shareable.

    #define IMAGE_SCN_MEM_EXECUTE                0x20000000  // Section is executable.

    #define IMAGE_SCN_MEM_READ                   0x40000000  // Section is readable.

    #define IMAGE_SCN_MEM_WRITE                  0x80000000  // Section is writeable.

     

    Section Table的作用是给所有的节提供一个便于PE装载器查找装载用的索引

    下面讨论节

    PE文件实例分析9

    节表是一个数组,其元素个数由IMAGE_FILE_HEADER中的NumberOfSections的值决定在test.exe中是0300,即3

    其中内含 image 每一个sections 的信息

    以下是微软VisualStudio2005 winnt.h中的定义

    //

    // Section header format.

    //

     

    #define IMAGE_SIZEOF_SHORT_NAME              8

     

    typedef struct _IMAGE_SECTION_HEADER {

        BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];

        union {

                DWORD   PhysicalAddress;

                DWORD   VirtualSize;

                } Misc;

        DWORD   VirtualAddress;

        DWORD   SizeOfRawData;

        DWORD   PointerToRawData;

        DWORD   PointerToRelocations;

        DWORD   PointerToLinenumbers;

        WORD    NumberOfRelocations;

        WORD    NumberOfLinenumbers;

        DWORD   Characteristics;

    } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

     

    类型

    名称

    偏移

    含义

    test.exe中的值

    0

    1

    2

    BYTE×8

    Name[8]

    00

    节的名称

    .text

    .rdata

    .data

    DWORD

     Misc

    08

    本节的实际字节数

    1E00 0000

    5400 0000

    0C00 0000

    DWORD

    VirtualAddress

    1C

    本节的RVA

    0010 0000

    0020 0000

    0030 0000

    DWORD

    SizeOfRawData

    20

    本节文件经过对齐后的尺寸

    0002 0000

    0002 0000

    0002 0000

    DWORD

    PointerToRawData

    24

    本节原始数据在文件中的位置

    00 04 0000

    0006 0000

    0008 0000

    DWORD

    PointerToRelocations

    28

    OBJ文件表示本节重定位信息,exe无意义

    0000 0000

    0000 0000

    0000 0000

    DWORD

    PointerToLinenumbers

    2C

    行号偏移

    0000 0000

    0000 0000

    0000 0000

    WORD

    NumberOfRelocations

    30

    本节需要重定位数目

    0000

    0000

    0000

    WORD

    NumberOfLinenumbers

    32

    在行号表中的行号数目

    0000

    0000

    0000

    DWORD

    Characteristics

    34

    节属性

    2000 0060

    40000040

    400000C0

    VirtualSize:本节实际字节数,计算文件对齐后的节尺寸

    VirtualAddress PE装载器将该节映射到内存时会读取该值,地道内存中的位置

    SizeOfRawData 值是200H与(与FileAlignment吻合)显然大于Misc本节的实际字节数目E1h,所以病毒可以不增加文件长度来感染文件。

    PointerToRawData:节基于文件的偏移量,PE装载器通过本域值找到节数据在文件中的位置病毒应该在此创建新值,指向新创建的节

    PE文件实例分析8

    今天继续分析PE

    下面到节表了(Section Table

    DOS

    MZ文件头:DOS MZ header

    DOS插桩程序:DOS Stub

    PE文件头

    PE文件标志:“PE00

    映像文件头:IMAGE_FILE_HEADER

    可选映象头IMAGE_OPTIONAL_HEADER32

       数据目录表:IMAGE_DATA_DIRECTORY

    节表(Section table

    IMAGE_SECTION_TABLE

    IMAGE_SECTION_TABLE

    IMAGE_SECTION_TABLE

    IMAGE_SECTION_TABLE

    节(Section

    .txt

    .data

    .edata

    .reloc

    …….

    调试信息

    COFF 行号

    COFF 符号表

    CodeView调试信息

    由上表可见节表是紧跟着PE文件头的一个结构

    PE文件实例分析7

    AddresssOfEntryPoint 程序开始执行的地方,PE装载器准备运行的PE文件第一个指令的RVA,如果改变整个执行的流程,可以将该值指向新的RVA,新的RVA除的指令首选被执行,可以先保留原来的值,然后再跳转过来

     ImageBase: PE文件的首选装载地址如果此处被占用,则另选其他空闲地址这个的值是00040000H

    SectionAlignment:内存中节对其的标准位置,内存中每个节起始地址都必须是这个值的倍数此例是0010 00001000H比如第一节是402000H,大小必然小于1000H比如20个字节,那么下一个节的起始地址必然是403000H

    FileAlignment:文件中节对齐的标准位置。文件中每个节的起始地址必须是这个值的倍数。此例是0002 0000 00000200H,作用同上

    SiezeOfImage:内存中PE文件的影响体的尺寸,是所有头,节处理对齐后的大小

    SizeOfHeaders:所有的头,节表的和,SizeOfImage-文件中节的尺寸,这就是:PE文件第一节的偏移量了

    Subsystem:此PE文件是窗体程序还是Console app

    此一可执行文件用来作为使用者接口的子系统。WINNT.H 定义了下列常数:

    NATIVE=1 不需要子系统(例如驱动程序)

    WINDOWS_GUI=2 Windows GUI 子系统中执行

    WINDOWS_CUI=3 Windows 字符模式子系统中执行(也就是 console 应用程序)

    OS2_CUI=5 OS/2 字符模式子系统中执行(也就是 OS/2 1.x 应用程序)

    POSIZ_CUI=7 Posix 字符模式子系统中执行

     

    数据目录表

    以下是VisualStudio2005winnt.h中的定义

     

    //

    // Directory format.

    //

     

    typedef struct _IMAGE_DATA_DIRECTORY {

        DWORD   VirtualAddress;

        DWORD   Size;

    } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

     

    #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES    16

    它的体积就是4×2×16128个字节,在UE中占了8

    数据目录中各值的意义, 来自VisualStudio2005winnt.h

     

    // Directory Entries

     

    #define IMAGE_DIRECTORY_ENTRY_EXPORT          0   // Export Directory

    #define IMAGE_DIRECTORY_ENTRY_IMPORT          1   // Import Directory

    #define IMAGE_DIRECTORY_ENTRY_RESOURCE        2   // Resource Directory

    #define IMAGE_DIRECTORY_ENTRY_EXCEPTION       3   // Exception Directory

    #define IMAGE_DIRECTORY_ENTRY_SECURITY        4   // Security Directory

    #define IMAGE_DIRECTORY_ENTRY_BASERELOC       5   // Base Relocation Table

    #define IMAGE_DIRECTORY_ENTRY_DEBUG           6   // Debug Directory

    //      IMAGE_DIRECTORY_ENTRY_COPYRIGHT       7   // (X86 usage)

    #define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE    7   // Architecture Specific Data

    #define IMAGE_DIRECTORY_ENTRY_GLOBALPTR       8   // RVA of GP

    #define IMAGE_DIRECTORY_ENTRY_TLS             9   // TLS Directory

    #define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG    10   // Load Configuration Directory

    #define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT   11   // Bound Import Directory in headers

    #define IMAGE_DIRECTORY_ENTRY_IAT            12   // Import Address Table

    #define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   13   // Delay Load Import Descriptors

    #define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14   // COM Runtime descriptor

    虽然定义了16个数组元素但是给出明确意义的只有前15个,难道最后一个保留备用??

    通过各项的VirturalAddress获取地址

    test.exe中的值是从0128h1a8

    如导入地址表即第13个元素,它的VirtualAddress 0020 00002000h

    它的Size0800 00008h

    PE文件实例分析6

     

    类型

    名称

    偏移

    含义

    test.exe中的值

    WORD

    ImageBase

    18

    标志位一般010B

    0B01

    BYTE

    MajorLinkerVersion

    1A

    链接器主

    05

    BYTE

    MinorLinkerVersion

    1B

    次版本号

    0A

    DWORD

    SizeOfCode

    1C

    可执行代码长度

    0002 0000

    DWORD

    SizeOfInitializedData

    20

    初始化数据长

    0004 0000

    DWORD

    SizeOfUninitializedData

    24

    未初始化数据长

    0000 0000

    DWORD

    AddressOfEntryPoint

    28

    RVA地址程序从这里执行

    0010 0000

    DWORD

    BaseOfCode

    2C

    可执行代码起始处

    0010 0000

    DWORD

    BaseOfData

    30

    初始化数据起始位

    0020 0000

    DWORD

    ImageBase

    34

    载入程序首选RVA地址

    0000 4000

    DWORD

    SectionAlignment

    38

    加载后节在内存中的对齐方式

    0010 0000

    DWORD

    FileAlignment

    3C

    节在文件中的对齐方式

    0002 0000

    WORD   

    MajorOperatingSystemVersion

    40

    操作系统主

    0400

    WORD

    MinorOperatingSystemVersion

    42

    次版本号

    0000

    WORD

    MajorImageVersion

    44

    可执行文件主

    0000

    WORD

    MinorImageVersion

    46

    次版本号

    0000

    WORD

    MajorSubsystemVersion

    48

    子系统版本好(如console

    0400

    WORD

    MinorSubsystemVersion

    4A

     

    0000

    DWORD

    Win32VersionValue

    4C

    Win32版本号一般0

    0000 0000

    DWORD

    SizeOfImage

    50

    程序载入后占用内存大小

    0040 0000

    DWORD

    SizeOfHeaders

    54

    文件头长度之和

    0040 0000

    DWORD

    CheckSum

    58

    校验和

    0000 0000

    WORD

    Subsystem

    5C

    可执行文件的子系统

    0300

    WORD

    DllCharacteristics

    5E

    何时DllMain被调一般0

    0000

    DWORD

    SizeOfStackReserve

    60

    初始化线程时保留堆栈大小

    0000 1000

    DWORD

    SizeOfStackCommit

    64

    初始化线程时提交堆栈大小

    0010 0000

    DWORD

    SizeOfHeapReserve

    68

    进程初始化时保留的堆的大小

    0000 1000

    DWORD

    SizeOfHeapCommit

    6C

    进程初始化时提交的堆大小

    0010 0000

    DWORD

    LoaderFlags

    70

    装载标志,与调试相关

    0000 0000

    DWORD

    NumberOfRvaAndSizes

    74

    数据目录项数

    1000 0000

    IMAGE_DATA_DIRECTORY

    DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]

    78

    映像数据目录数组

     

     

     

    PE文件实例分析5

    映像文件头的大小:

    pe00开始的位置再偏移0x18个字节都是映像头的范围。

    这样就可以计算出节表的起始位置,一个节表28H个字节,就可以进一步确定最后一个界节表的末尾的地址,这样就能添加新节了!--》有想法了!!

     

    可选映像头:包含了PE文件的逻辑分布信息:

    以下是VisualStudio2005winnt.h中的定义

    typedef struct _IMAGE_OPTIONAL_HEADER {

        //

        // Standard fields.

        //

     

        WORD    Magic;

        BYTE    MajorLinkerVersion;

        BYTE    MinorLinkerVersion;

        DWORD   SizeOfCode;

        DWORD   SizeOfInitializedData;

        DWORD   SizeOfUninitializedData;

        DWORD   AddressOfEntryPoint;

        DWORD   BaseOfCode;

        DWORD   BaseOfData;

     

        //

        // NT additional fields.

        //

     

        DWORD   ImageBase;

        DWORD   SectionAlignment;

        DWORD   FileAlignment;

        WORD    MajorOperatingSystemVersion;

        WORD    MinorOperatingSystemVersion;

        WORD    MajorImageVersion;

        WORD    MinorImageVersion;

        WORD    MajorSubsystemVersion;

        WORD    MinorSubsystemVersion;

        DWORD   Win32VersionValue;

        DWORD   SizeOfImage;

        DWORD   SizeOfHeaders;

        DWORD   CheckSum;

        WORD    Subsystem;

        WORD    DllCharacteristics;

        DWORD   SizeOfStackReserve;

        DWORD   SizeOfStackCommit;

        DWORD   SizeOfHeapReserve;

        DWORD   SizeOfHeapCommit;

        DWORD   LoaderFlags;

        DWORD   NumberOfRvaAndSizes;

        IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];

    } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

     

    PE文件实例分析4

    PE文件头

    Pe文件头标志:结构体的末尾,long e_lfanew 一个long型的四个字节的数据:pe00分别是图中0b0h0b1h, ob2h,0b3h,

     

    映像文件头以下是来自在微软的VisualStudio2005winnt.h中的定义:

    typedef struct _IMAGE_FILE_HEADER {

        WORD    Machine;

        WORD    NumberOfSections;

        DWORD   TimeDateStamp;

        DWORD   PointerToSymbolTable;

        DWORD   NumberOfSymbols;

        WORD    SizeOfOptionalHeader;

        WORD    Characteristics;

    };

    对照UE中的数据:

    类型

    偏移(PE00)

    名称

    含义

    Test.exe的值

    WORD

    04

    Machine

    程序要执行的平台

    4C01(80386以上)

    WORD

    06

    NumberOfSections

    文件中节的个数

    0300

    DWORD

    08

    TimeDateStamp

    文件建立的时间

    764CB046(比对可知,后面是年,前面是时刻)

    DWORD

    0C

    PointerToSymbolTable

    COFF符号表的偏移

    00000000

    DWORD

    10

    NumberOfSymbols

    符号数目

    00000000

    WORD

    14

    SizeOfOptionalHeader

    可选的长度

    E000(可选头的长度)

    WORD

    16

    Characteristics

    标志集合

    0F01

    0000111100000001

     

    注意:WORD中的数字是反向存储的比如4C01,实际的表达的值是014C

    这些值有特殊的意义:

    机器类型Machine常见值:

    Machine

    计算机类型

    0x14c

    Intel 80386处理器以上

    0x014d

    Intel 80486处理器以上

    0x014e

    Intel Petium处理器以上

    0x0160

    P3000(MIPS)处理器,高位在前

    0x162

    R3000MIPS)处理器,低位在前

    0x166

    R4000(MIPS)处理器,低位在前

    0x168

    R10000(MIPS)处理器,低位在前

    0x184

    DEC Alpha AXP处理器

    0x1f0

    IBM PowerPC 低位在前

    如果我们要在文件中增加或者删除一个节,就要修改NumberOfSections

    利用SizeOfOptionalHeader就可以知道节表的起始位置。

    另一点要注意,这里的扎合理的文件创立的时间按并不是属性项里面的那个时间,而应该是PE文件被编译成的时间,因为文件被拷贝后,属性项里的时间会改变,这个时间是由磁盘文件表维护的。,但是文件中的时间信息并不改变

     

    Characteristics中的值实际是:010F

    它可以展开成0000000100001111从右到左依次称为bit0bin15各自含义如下

    1的含义

    Bit0

    文件中没有重定向信息

    Bit1

    文件是可执行文件

    Bit2

    没有行数信息,在可执行文件中没有用

    Bit3

    没有局部符号信息

    Bit8

    希望计算机为32位机

    Bit9

    没有调试信息

    Bit10

    该程序不能运行于可移动介质中

    Bit11

    程序不能在网上运行

    Bin12

    文件是一个系统文件,如驱动程序

    Bit13

    文件是一个动态链接库(DLL

    Bit14

    文件不能运行与多个处理器系统

    Bit15

    文件字节顺序需要交换

     

    PE文件实例分析3

     

     

    DOS

    MZ文件头:DOS MZ header

    DOS插桩程序:DOS Stub

    PE文件头

    PE文件标志:“PE00

    映像文件头:IMAGE_FILE_HEADER

    可选映象头IMAGE_OPTIONAL_HEADER32

       数据目录表:IMAGE_DATA_DIRECTORY

    节表(Section table

    IMAGE_SECTION_TABLE

    IMAGE_SECTION_TABLE

    IMAGE_SECTION_TABLE

    IMAGE_SECTION_TABLE

    节(Section

    .txt

    .data

    .edata

    .reloc

    …….

    调试信息

    COFF 行号

    COFF 符号表

    CodeView调试信息

     

    作成test.exe文件,然后对照pe文件的结构分析

    第一部分是DOS

    MZ文件头从0x000x3f共是 占了6410)个字节

    (注:四个字节等于一个双字,两个字节一个字,一个字节8bit UE中一行是16个半字节即八个字节。)前四行都是MZ文件头

    MS-DOS头是一个结构体,在微软的VisualStudio2005winnt.h中的定义

    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

      }

      WORD   e_magic  就是0x4D5A即我们在UE中看到的MZ两个字母的十六进制形式

     

       UE中的实际数据和结构体对照在一起看

    格式

    名称

    偏移字节数

    注解

    test.exe中的实际值

    (默认是十六进制)

    WORD

    e_magic

    00

    魔术数字

    4D 5A

    WORD

    e_cblp

    02

    文件最后页中字节数

    9000

    WORD

    e_cp

    04

    文件页数

    0300

    WORD

    e_crlc

    06

    重定向元素个数

    0000

    WORD

    e_cparhdr;

    08

    头部大小(以段为单位)

    0004

    WORD

    e_minalloc

    0A

    所需的最小附加段

    0000

    WORD

    e_maxalloc

    0C

    所需的最大附加段

    FFFF

    WORD

    e_ss

    0E

    初始的ss值(相对偏移量)

    0000

    WORD

    e_sp

    10

    初始的Sp(栈指针值吗?)

    B800

    WORD

    e_csum

    12

    校验和或者零

    0000

    WORD

    e_ip

    14

    初始的IP

    0000

    WORD

    e_cs

    16

    初始的CS值(相对偏移量)

    0000

    WORD

    e_lfarlc

    18

    重定向表文件地址

    4000

    WORD

    e_ovno

    1A

    覆盖号

    0000

    WORD

    e_res[4]

    1C

    保留字

    0000×4

    WORD

    e_oemid

    24

    OEM标志符

    0000

    WORD

    e_oeminfo

    26

    OEM信息

    0000

    WORD

    e_res2[10]

    28

    保留

    0000×10

    100000

    LONG=

    2×WORD

    e_lfanew

    3C

    PE头位置

    F800 0000

     

    观察对比多个程序发现插桩程序的字符出现位置是固定的,而pe00这个标志出现的位置不是固定的,固定的只是记录这个标志的变量的位置,

    注意:DWORD中的数字是反向存储的比如上面的F800 0000,实际的表达的值是

    0000 00F8,这就与UE中显示的PE00字符的出现位置对应起来了

    更典型的如果UE中显示某个DWORD1234 5678,那么实际的值是:7856  3412

    上面表格中的e_lfarlc 的值其实是00 40,这就是重定向表的地址了!

    学过汇编的人可能对此有点印象

     

    中间从0x3cpe头位置是一个dos插桩程序,其长度用e_lfanew-3f即可

    以上构成了DOS头,

     

    PE文件实例分析2

     

     

    DOS

    MZ文件头:DOS MZ header

    DOS插桩程序:DOS Stub

    PE文件头

    PE文件标志:“PE00

    映像文件头:IMAGE_FILE_HEADER

    可选映象头IMAGE_OPTIONAL_HEADER32

       数据目录表:IMAGE_DATA_DIRECTORY

    节表(Section table

    IMAGE_SECTION_TABLE

    IMAGE_SECTION_TABLE

    IMAGE_SECTION_TABLE

    IMAGE_SECTION_TABLE

    节(Section

    .txt

    .data

    .edata

    .reloc

    …….

    调试信息

    COFF 行号

    COFF 符号表

    CodeView调试信息

     

    作成test.exe文件,然后对照pe文件的结构分析  

    PE文件实例分析1

    今天开始分析pe文件

    虚地址VA=相对虚拟地址RVA+基地址Image Base

    基地址是可执行文件映射到内存中的基地址

    我先用汇编写成了一个很小的一个文件故意把它写的非常小,以便于分析,麻雀虽小,五脏俱全!

     

    .386

    .MODEL FLAT

    ExitProcess PROTO NEAR32 stdcall, dwExitCode:DWORD

    .DATA                  

    number1 DWORD   10

    number2 DWORD   100

    sum     DWORD   ?

    .CODE                         

    _start:               

            mov     eax, number1   

            add     eax, number2  

            mov    sum, eax      

            

            INVOKE  ExitProcess, 0

    PUBLIC _start                  

    END                            

    以下是这个程序的可执行文件的二进制信息

    装SUSE

    我敢说OPENSuSE 10.2是我装过的界面最好的linux版本,比Ubuntu还要好一点, 而且还有一个比Ubuntu好一点的地方,那就是SuSE自带很多工具,不用再去网上四处搜索下载了,而Ubuntu精简的没什么其他功能了 则一点对我们这种喜欢探索尝鲜的人是很没有吸引力的. 上个学期有一段时间也曾经试图装过,但是当时我是直接安装,结果显式器不支持,我只能进入一个控制台界面, 现在改变策略,用虚拟机安装的满是慢了点但是总比不能用好啊

    DDKBuild: 在Visual Studio中集成DDK

    初学驱动,搭建这个配置环境就让人无从着手,Google了几天后,终于找到一种可以在Visual Studio
    中集成DDK的方案。
    在Google中搜 ddkBuild,单击链接可以转到
    把DDKBuild.bat DDKBuild.cmd,DDKBuildWizard.exe还有一个PDF格式的帮助文档下载下来。
    仔细阅读那个罗里罗嗦的文档后就知道怎么做了