• PE手工分析导入表和导入函数地址表分析


    在上篇:PE手工分析-PE头 中我们了解了PE文件头内容,在此基础上我们来分析一下导入表和导入函数地址表的内容.

    还是使用上篇使用的PE文件来分析,上一篇中我们基本上已经定位出PE头的位置以及相应内容.

    PE扩展头中包含 IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];//数据目录表

    通过该数据目录表我们可以进一步对导入表和导入函数地址表进行详细的分析(其数据目录表分析也雷同)

    详细信息可以查看MSDN定义.

    数据目录表结构定义:

    typedef struct _IMAGE_DATA_DIRECTORY {
    
        DWORD   VirtualAddress;
    
        DWORD   Size;
    
    } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; 

    DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]数据目录表分析如下:

    索引

    数据目录表

    文件偏移地址

    偏移

    大小

    说明

    0

    导出表

    00000170h

    00 00 00 00 

    00 00 00 00

    没有导出

    1

    导入表

    00000178h

    00 E0 01 00

    64 00 00 00

    ...

     

     

     

    12

    导入地址表

    000001d0h

    A0 E2 01 00

    3C 02 00 00

     

     

     

     

     

    ...

     

     

     

     

    ...

     

     

     

     

    导入表RVA=01E000

    IAT RVA=01E2A0

    RVA的概念请参考:RVA,另外可以参考《加密解密ii》中的第二章介绍

    了解了RVA之后我们就明白了在获取导入表的RVA之后需要根据节地址转换成文件相对地址FOA

    所以为了获取导入表的文件相对地址需要对PE的节表进行分析

    首先需要知道节表所在的位置(紧跟数据目录表结尾)

    总共16个数据目录,导入地址函数表在第12(0开始)个位置

    节表起始位置=1d0+8+3×8=1F0

    节表结构如下:

    typedef struct _IMAGE_SECTION_HEADER {
    
        BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];// #define IMAGE_SIZEOF_SHORT_NAME 8
    
        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;

    从上面镜像头分析可以之后该PE中包含有7个节

    每个节包含40个字节

    总共占有空间:40×7=280(0x118)->01F0-20E

    可以看到每个节对应的内容如下:

    段名称   

    虚拟地址 

     虚拟大小  

    物理地址  

    物理大小 

      标志

    PointerToRawData

    .textbss

    1000

    0

    10000

    0

    2EE0

    .text

    11000

    897D

    00008A00

    60000020

    00000400

    .rdata

    1A000

    24B5

    2600

    40000040

    8E00

    .data

    01D000

    05F4

    2000

    C0000040

    B400

    .idata

    0001E000

    10C8

    1200

    C0000040

    B600

    .rsrc

    00020000

    0459

    0600

    40000040

    C800

    .reloc

    00021000

    06DA

    0800

    42000040

    CE00

    节表的分析完毕,然后我们需要针对导入表的RVA获取相应的FOA

    RVA:01E000=>PointerToRawData:B600

    指向导入表描述符

    typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    
        union {
    
            DWORD   Characteristics;            //
    
            DWORD   OriginalFirstThunk;         //
    
        } DUMMYUNIONNAME;         //0001e270=>B600+270=b870->01E4DC->_foo@4
    
        DWORD   TimeDateStamp;                  // 0                                          
    
        DWORD   ForwarderChain;                 //0
    
        DWORD   Name;                 //01E4E6=>B600+4E6=BAE6->dllExport.dll
    
        DWORD   FirstThunk;                     //01E4AC=>B600+4AC=BAAC->01E4DC->_foo@4
    
    } IMAGE_IMPORT_DESCRIPTOR;

    其文件内容如下:

    OriginalFirstThunk指向地址(RVA)01E4DC->(FOA)BADC

    FirstThunk指向地址(RVA)01E4AC->(FOA)BAAC对应结构为

    typedef struct _IMAGE_THUNK_DATA32 {
    
        union {
    
            DWORD ForwarderString;      // PBYTE
    
            DWORD Function;             // PDWORD
    
            DWORD Ordinal;
    
            DWORD AddressOfData;        // PIMAGE_IMPORT_BY_NAME
    
        } u1;
    
    } IMAGE_THUNK_DATA32;
    

    相应IMAGE_THUNK_DATA指向的内容为

    typedef struct _IMAGE_IMPORT_BY_NAME {
    
        WORD    Hint;            //00
    
        BYTE    Name[1];     //_foo@4
    
    } IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
    

    这里对应的导入表分析基本完成了 

    • 相应的IAT分析如下:

    RVA:01E2A0=>PointerToRawData:B600+(2A0)=B8A0在找到了IAT表的地址后让我们来看一下其中的内容

    可以看到这里的BAAC正好处理B8A0的区域中.

    所以很显然,FirstThunk属于IAT中的某一个地址区域

    相应PE文件内容如下

    Dll加载之前导入表结构

     

    DLL加载之后导入表中内容将被操作系统填充为函数的VA

    到这里基本上已经把IATINT绑定起来了,而在函数调用过程中将如何实现调用IAT的函数地址呢?

    程序中每个调用 API 函数的 CALL 指令所使用的地址都是相应函数登记在 IAT 表的地址

    源文档 <http://blog.csdn.net/misterliwei/article/details/840983>

    那么,IAT导入函数地址表,和导入表有什么联系呢??

    其实,所有的DLL的IMAGE_IMPORT_DESCRIPTOR结构的FirstThunk指向的是一片连续的内存空间,第一个DLL的IMAGE_IMPORT_DESCRIPTOR结构的FirstThunk的值,就是IAT表的起始地址!

    也就是说,导入表中的首个IMAGE_IMPORT_DESCRIPTOR的FirstThunk字段,在内存中,等同于IMAGE_NT_HEADER.OptionHeader.DataDirectory[12].VirtualAddress

    数据目录表第13项,索引值为12,就是IAT了。

    在RING3的API劫持中,很多人都会选择使用IAT劫持,也就是基于这个理论的。

    源文档 <http://tieba.baidu.com/f?kz=726947835>

    对于IAT和导入表之间的关系用如下图片作为结尾

    导入表中的FirstThunk指向IAT表中的某一项

     

    之前的理解有问题所以后面加以修改

  • 相关阅读:
    Java8新特性学习笔记(一) Lambda表达式
    android游戏动画特效的一些处理
    start from here
    感知机回归
    2020/2/21
    梯度下降
    凸优化
    批量归一化和残差网络
    Momentum
    词嵌入基础
  • 原文地址:https://www.cnblogs.com/SkyMouse/p/2493775.html
Copyright © 2020-2023  润新知