一丶简介

  上一讲讲解了导出表. 也就是一个PE文件给别人使用的时候.导出的函数  函数的地址 函数名称 序号 等等.

  一个进程是一组PE文件构成的.  PE文件需要依赖那些模块.以及依赖这些模块中的那些函数.这个就是导入表需要做的.

确定PE依赖那个模块. 确定PE依赖的那个函数.  以及确定函数地址.

总共分为三部分讲解.

  导入表定位位置: 在扩展头中有一个数据目录结构体. 第二项保存的就是导入表的 RVA 以及大小.

如下图所示:

EXE文件.没有导出表.有一个导入表. RVA 是 0x1A1C0  位于节Text中. 虚拟地址位 0x11000  文件偏移为 0x400

转换为 FOA =  1A1C0 - 11000 + 400 = 0x95c0

我们发现在文件中定位导入表的时候都是0,原因是程序加载到内存中.需要用到的时候.操作系统才会往这个地方填写数据.

 二丶导入表结构

typedef struct _IMAGE_IMPORT_DESCRIPTOR {union {DWORD   Characteristics;            // 0 for terminating null import descriptorDWORD   OriginalFirstThunk;         // RVA to original unbound IAT (PIMAGE_THUNK_DATA) 指向IAT结构注释表明了
    } DUMMYUNIONNAME;DWORD   TimeDateStamp;                  // 时间戳.// -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 forwardersDWORD   Name;                //指向DLL名字的 RVADWORD   FirstThunk;                     // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;

导入表大小为十进制的20个字节.  16进制的 0x14. 如果以16进制为一行. 则是 一行零4个字节

导入表跟导出表不同.导出表只有一个.里面有子表记录. 而导入表你依赖一个模块.则有一个导入表存在.

导入表结束位置是20个字节的连续为0的数据为结束位置. 也就是导入表最后一项都为0的时候.说明导入表结束了.

对于导入表来说.我们只需要关心三个成员.上面都标红了.

会一一进行讲解.首先从最简单的成员开始.

  2.1 Name成员. 确定依赖的模块的名字是什么

我们说过.一个PE文件.依赖模块. 那么这个成员就是记录了.我要依赖的模块的名字是什么.是一个RVA属性. RVA指向了一个ASCII码字符串.以0结尾.

因为在文件中导入表并没有.所以我们直接在内存中查看.

根据数据目录 导入表位置 0x1A1C0  + ImageBase(0x400000) == 0x41AC0

在内存中的0x41AC0位置.则是导入表的位置. 我们看一下.

导入表大小总共一行零4个字节. 倒数第二个成员则是 Name的 RVA  0x1A4A6

我们可以加上ImageBase 去内存中查看.

可以通过RVA 属性.看到导入表依赖的模块名字就是 VCRUNTIME140D.dll   带有D结尾的.dll说明是调试DLL. 140是编译器版本.说明是

VS2015编译的 .VCRuntime 是运行库 .  说明我们这个程序是一个 Debug版本编译的程序. 并且使用编译器 140版本编译的.

我们查看的这个Name属性.描述的就是 VCRUNTIME140D.dll 这个模块的信息了.如果想看其它依赖的模块就需要查看下一张导入表.

下一张导入表在第一章导入表的下面.最后一项的导入表全部为0.  我们下一张导入表的 依赖模块的模块名称的 RVA 属性是 0x1A75A

VA = Imagebase + RVA = 41A75A

依次查看即可.

   2.2 确定依赖的函数的名称

上面我们讲了Name成员.确定了导入表依赖的DLL的名字.那么我们导入表怎么确定依赖了那些函数那?

这个主要讲解导入表的第一个成员跟最后一个成员.

如下图所示:

第一个成员指向了一个INT 表.最后一个成员指向了一个 IAT表.

INT :: 导入名称表  Improt Name Table

IAT::  导入地址表  Improt Address Table

Name成员直接指向一个 ASC 结尾的字符串.

根据上图所示. 两张表是一样的. 但是所在位置是不一样的名字也不一样.一个叫做 INT 一个叫做IAT

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 * PIMAGE_THUNK_DATA32;

结构体大小:  4个字节. 他是一个联合体.找最大的.

里面有4个成员.为当前的4个字节起了四个名字.  真正有用的是下面两个. 也就是说有的时候需要用第三个成员.

有的时候需要用第四个成员. 而第四个成员是指向一个  IMAGE_IMPORT_BY_NAME的结构的RVA

typedef struct _IMAGE_IMPORT_BY_NAME {WORD    Hint;                 //编译器决定,不是空的话,就是函数在导出表中的 函数地址表的导出索引.CHAR   Name[1];               //函数名称,0结尾.
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

无论是第一个成员还是最后一个成员.都能确定 我一来的当前模块的那个函数.

为什么需要两个表. 这个下面会将. 首先讲解的就是无论使用那个表.都能找到依赖当前模块的函数.

第一个成员找:

  INT表  INT表是4个字节.最后0结尾.  INT表有多大.就是说依赖这个模块的多少个函数.

  IAT 同上. 0结尾.

那么我们怎么去寻找?

  看这个表的4个字节.  最高位为1那么就是函数的导出序号. 去掉最高位.就是函数的序号. 也就是说我们看的是序号.

  如果最高位不是1,那么找的就是一个 RVA ,一个指向 IMAGE_IMPROT_BY_NAME的结构.

例如下图:

INT 或者 IAT表. 都可以通过最高位判断. 是函数的序号.还是函数的名字.

INT或者IAT就是两种情况, 高位为1, 那么去掉高位就是依赖的函数序号. 不是1, 那么就是一个RVA. 指向了一个  IMAGE_IMPROT_BY_NAME 结构.

以一个导入表为例

INT的 RVA 为 1A2A8 VA = 41A2A8

41A2A8是INT表开始. 每一个是4个字节,以0结尾. 观看第一项. 高位为0,所以 0x1A48E 是一个RVA. 一个指向 IMAGE_IMPROT_BY_NAME 的结构

VA = 41A48E

高位两个字节,是函数在导出表中的导出索引.  后面就是以0结尾的函数名称了.

总结来说: 不管是INT表还是 IAT表. 主要看其高位值,高位为1,那么去掉高位,就是函数的序号. 高位为0.指向一个结构.这个结构保存了函数的导出序号.以及函数名称.

在IMAGE_IMPROT_BY_NAME 结构中的 HINT 如果不是空,那么这个序号(索引) 就是导出表的函数地址表的索引. 我们可以直接拿着这个索引去导出表中获取函数地址.

     2.3 确定函数地址

如果我们使用DLL的函数.那么在程序中.调用这个DLL的函数.那么就会生成一个间接Call

比如我们程序调用MessageBoxA

反汇编

跳转过去之后.会看到内存中有一个地址

这个地址才是真正的MessageBox的地址

在我们导入表中,最后一个成员  IAT表.就是上面所说的表,保存了函数地址表.

那么这和我们说的结构是不一样的. IAT不是说跟INT是一样的吗?

PE加载前加载后的区别.

一样是一样的.但是需要分清 PE加载前.还有PE加载后.如果加载前,那么IAT跟INT一样.都可以找到依赖的函数名称.

如果是加载后.也就是在内存中的话.那么IAT表保存的就是函数的地址.

PE加载后如下图:

IAT表保存的就是函数地址了.

从导入表中找到IAT表.

IAT表的RVA 偏移为 0x1A098  VA == 41A098

IAT表中存储了函数地址,4个字节为单位.0x6AD79CF0 就是函数 __Vcrt_loadlibraryExW . INT表中存储的就是 依赖的函数名称.上面我们也看到了.

三丶知识总结

导入表大小为20个字节. 十六进制 0x14 ,一行零4个字节.

  1.导入表重要成员有三个.  INT表. Name表.  IAT表.

    PE加载前.

        INT 表 IAT表相同. 根据INT或者IAT表的高位,高位为1.去掉高位就是函数序号. 高位为0. 那么是一个RVA偏移. 指向函数名称表.

          函数名称表

            HINT  当前函数在导出函数地址表中的索引

            Name  当前函数的名称.

    PE加载后INT 表同上. IAT表变成了存储函数地址的地址表了.

  2. Name 民称表. 直接指向DLL名称文件名. 是一个RVA .注意是直接指向.

  3.INT IAT表.的RVA 都是定位INT IAT表位置. 定位的位置是INT IAT表.这个表存储的才是数据

转载于:https://www.cnblogs.com/gd-luojialin/p/11306208.html

PE知识复习之PE的导入表相关推荐

  1. PE知识复习之PE的各种头属性解析

    PE知识复习之PE的各种头属性解析 一丶DOS头结构体 typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header WORD e_magic; // M ...

  2. PE知识复习之PE的两种状态

    PE知识复习之PE的两种状态 一丶熟悉PE的整体结构 从下面依次网上看.可以得出PE结构 其中DOS头有DOS头结构 也就是 IMAGE_DOS_HEADER 关于结构体的各项属性.前边已经写过了.本 ...

  3. PE知识复习之PE的导出表

    一丶简介 在说明PE导出表之前.我们要理解.一个PE可执行程序.是由一个文件组成的吗. 答案: 不是.是由很多PE文件组成.DLL也是PE文件.如果我们PE文件运行.那么就需要依赖DLL.系统DLL就 ...

  4. Windows PE 第八章 延迟加载导入表

    延迟加载导入表 延迟加载导入表是PE中引入的专门用来描述与动态链接库延迟加载相关的数据,因为这些数据所引起的作用和结构与导入表数据基本一致,所以称为延迟加载导入表. 延迟加载导入表和导入表是相互分离的 ...

  5. PE文件结构详解(四)PE导入表

    PE文件结构详解(二)可执行文件头的最后展示了一个数组,PE文件结构详解(三)PE导出表中解释了其中第一项的格式,本篇文章来揭示这个数组中的第二项:IMAGE_DIRECTORY_ENTRY_IMPO ...

  6. PE文件学习笔记(五):导入表、IAT、绑定导入表解析

    1.导入表(Import Descriptor)结构解析: 导入表是记录PE文件中用到的动态连接库的集合,一个dll库在导入表中占用一个元素信息的位置,这个元素描述了该导入dll的具体信息.如dll的 ...

  7. PE结构学习(5)_导入表与导出表

    导出表与导入表 通常来讲exe文件只有导入表而没有导出表,而dll文件既有导入表也有导出表 导出表 什么是导出表 代码重用机制提供了重用代码的动态链接库, 它会向调用者说明库里的哪些函数是可以被别人使 ...

  8. 【逆向】PE结构分析和关于PE的一些问题及解决

    目录 前言: 开始需要大概了解一些名词: 程序的装入(地址的变换) 分页机制: 大概带着这些知识后,再来看PE的结构: 一些结构的定义 关于地址计算的一些问题 经典例题: 例题分析 ☆如何在PE中查找 ...

  9. 22. PE结构-PE详解之输入表(导入表)、屠龙刀W32Dasm(静态)、LordPE(动态)工具入门(查找dll、调用函数)

    我们知道PE 文件中的数据被载入内存后根据不同页面属性被划分成很多区块(节),并有区块表(节表)的数据来描述这些区块.这里我们需要注意的问题是:一个区块中的数据仅仅只是由于属性相同而放在一起,并不一定 ...

最新文章

  1. 主板和cpu搭配表_GTX1650显卡搭配知识:GTX1650配什么CPU和主板及多大电源?
  2. c++ builder 中的 XMLDocument 类详解(2) - 记要
  3. jdk入门_JDK 9 REPL:入门
  4. zplane函数怎么用m文件调用_matlab中一个m文件怎么调用另一个m文件的函数
  5. git关闭密码自动存储_项目在 git 里怎样合理的保存配置文件(服务器密码等敏感内容)...
  6. Note - Shader - 2
  7. 克服协作的五种障碍_如何克服社区管理的障碍
  8. 9.23 基础知识
  9. 以变制变——前端动态化代码保护方案探索
  10. 学习了1!+...10!
  11. 【交通标志识别】基于matlab GUI SIFT交通标志识别【含Matlab源码 864期】
  12. mapxtreme for java_在MapXtreme for Java 4.8.0 中公布新制造的电子地图
  13. 美国三大股指再创新高:纳指开盘上涨0.29%
  14. iphone邮件服务器 263,如何在iPhone和iPad中设置使用263企业邮箱?
  15. 第一届全国区块链和分布式记账技术标准化技术委员会 委员名单
  16. Qt的工程文件(.pro) -- 转
  17. Windows 8 引入新版的凭据管理器
  18. Android8.0 NotificationChannel修改铃声和振动的坑
  19. 做B端产品经理好还是做C端产品经理好?
  20. 客户贷款逾期预测[7] - 模型融合

热门文章

  1. ECshop sina
  2. 交流:Ghost版系统安装简单分析
  3. Maya中操作普通DG节点和Dag节点的区别
  4. java+yeild+sleep_java之yield(),sleep(),wait()区别详解-备忘笔记[转]
  5. VoltDB培训PPT一则
  6. Web1.0、Web2.0、Web3.0、Web4.0、Web5.0、Web6.0
  7. ASP.NET MVC——Entity Framework连接mysql及问题
  8. HTTP版本/层次/响应/状态之高屋建瓴
  9. 【java奇思妙想】一个能够改变字体颜色、字号大小、字体样式的html网页
  10. Scala学习之 java.net.BindException: 无法指定被请求的地址: Service 'sparkDriver' failed