YLLEN

要去看埃菲尔铁塔的顶

欢迎关注本人微博:t.cn/RGSLVUk

PE文件浅析

    额,这个貌似来晚了.......

    好了,开始PE文件浅析 , PE ( Portable Executable ) 是Windows下的可执行程序文件格式,

其采用的磁盘文件格式以及内存运行时格式具有“一致性”,具体信息请查询下其他资料。

32位系统下 为 PE,64位为PE+ ,其中扩充了部分字段,这里以PE32 为例子。


    大致格式:

|     DOS头      |            这里是为了兼容DOS系统

|     NT头         |            这才是真正的PE头

|     节区表头    |            这是PE节区描述信息 ,大致有.idata .data .text  .rsrc .reloc

|      节区          |            这里对应上面节区表中所描述的,


     

详细格式请翻看MSDN ,或者WinNt.H。

这里主要说一下 PE中导入\导出表。


导出表(模块向外界提供的API)

 

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;


        其中 

        NumberOfFunctions 是导出函数个数,

        Name 字段 是 所导出模块的 名称所在的 RVA ,

        AddressOfFunctions 是导出函数的 RVA ,

        AddressOfNames 是 导出函数的名称数组所在RVA

        AddressOfNameOrdinals是 导出函数的ID 编号,需加上 Base 来确定


  示例 输出 是这样的:

    YunDb.DLL

 [1] ,  DllCanUnloadNow  , 0xc66d4a1


 [2] ,  DllGetClassObject  , 0xffec8b55


 [3] ,  DllRegisterServer  , 0xd4b9016a


 [4] ,  DllUnregisterServer  , 0xd4b9016a



导入表(模块引入的外界API)


typedef struct _IMAGE_IMPORT_DESCRIPTOR {

    union {

     DWORD   Characteristics;      // 0 for terminating null import descriptor

DWORD   OriginalFirstThunk;    // RVA to original unbound IAT (PIMAGE_THUNK_DATA)

    } DUMMYUNIONNAME;

    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;



    导入表是个数组形式,每一个元素对应一个 IMAGE_IMPORT_DESCRIPTOR ,

就像 [ntdll.dll .....] [kernel32.dll ....] ... [gdi32.dll .....] 这样, 一个模块一个导入描述符

其中_IMAGE_IMPORT_DESCRIPTOR  的 

   union {

     DWORD   Characteristics;      

     DWORD   OriginalFirstThunk;  

    } DUMMYUNIONNAME;



中 OriginalFirstThunk 是指向一个IMAGE_THUNK_DATA结构的 RVA,

IMAGE_THUNK_DATA 的结构

typedef struct _IMAGE_THUNK_DATA32 {

    union {

        DWORD ForwarderString;      // PBYTE

        DWORD Function;             // PDWORD

        DWORD Ordinal;

        DWORD AddressOfData;        // PIMAGE_IMPORT_BY_NAME

    } u1;

} IMAGE_THUNK_DATA32;

     这个结构是一个与所在环境有关的一个DWORD类型联合结构体,其中Ordinal

是在确定导入表序号时 有意义,

AddressOfData是一个

struct {

    DWORD hint ;        这个是API编号

    byte name[1];        这个是API名称字符串的RVA

}*PIMAGE_IMPORT_BY_NAME ;


这里需要注意

    AddressOfData的值 若 最高位是 1 ,也即 AddressOfData>>31 == 1 则是 序号导入,就是导入了 模块中API 编号,用的时候 AddressOfData & 0x7FFF后按编号找, 若不是,则是 名称导入,那么这个值就是 API RVA了。



在文件结构中 FirstThunk 和 OriginalFirstThunk 所指向的地址相同,

也即是导入名称表, 在PE文件加载时 FirstThunk 会被 装载程序 填充为

API真实地址,

IAT 原理 :


addr1      call MessageBox   ;  实则为 call   addN 

..

..

addN    JMP     [ IAT表中对应API  VA ]


    HOOK IAT 也就是 修改了  "  IAT表中对应API  VA" 这个值

 劫持了程序流程。



 感觉能说的很少,是学的少了......


 今天就到这里、






评论

© YLLEN | Powered by LOFTER