Windows PE权威指南(导入表)

知识体系接上一章: Windows PE权威指南总结(一)

上一章主要是理论知识,包括PE大致数据结构。本文知识点基于书中第四章(105页至144页)。
今天发现OD可以编辑二进制或者汇编代码并转储为新文件。
下面0x00与0x01使用的exe为reg.exe(下载),给出masm源码:

.386
.model flat,stdcall
option casemap:none

include windows.inc
include user32.inc
include kernel32.inc
includelib user32.lib
includelib kernel32.lib
include advapi32.inc
includelib advapi32.lib

.data
subKeyName db 'SOFTWARE',0
keyName db 'keyName',0
keyValue db 'zhou',0
hKey dd 0

.code
start:
    invoke RegCreateKeyA,HKEY_LOCAL_MACHINE, offset subKeyName, offset hKey
    invoke RegSetValueExA,hKey, offset keyName, 0, REG_SZ, offset keyValue, 4
    invoke RegCloseKey,hKey
end start

0x00 Import与IAT

在Image_Optional_Header32中有一个字段叫DataDirArray,长度一般固定为16。其展开后如下图所示:
DataDirArray

其中红框标出来的Import和ImportAddressTable(IAT)是与导入表相关的2个字段。展开后有2个字段:VirtualAddress和Size。VirtualAddress属于上一章的知识点,转换为FOA后即可定位到文件中偏移。

观察上图中Import和IAT中VirtualAddress和Size值可以发现,Import表是紧跟在IAT表之后的。IAT表VirtualSize是0x2000h。从SectionHeader(见下图)得知其FOA为600,大小为200h。其实真正没有用到这么多,首先200H是FIileAlignment常见值,其次分配的大有利于后期对exe文件的修改。
SectionHeader

0x01 导入表的双桥结构

根据Import表和IAT的VirtualAddress定位到文件中位置,其数据值如下(红框标出部分为IAT,其余为Import Table):
Import Table

Import表是由一个IMAGE_IMPORT_DESCRIPTOR数组组成,有多少个导入DLL就有多少个IMAGE_IMPORT_DESCRIPTOR结构体,每个结构体占20个字节,所以当遇到20个字节0时代表数组结束。

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;            // 0 for terminating null import descriptor
        DWORD   OriginalFirstThunk;         // 包含指向IMAGE_DATA(输入名称表)RVA 的结构数组
    };
    DWORD   TimeDateStamp;                  //当可执行文件不与被导入的DLL进行绑定时,此字段为0
    DWORD   ForwarderChain;                 //第一个被转向的API索引
    DWORD   Name;                           //指向被导入的DLL 名称
    DWORD   FirstThunk;                     //指向输入地址表(IAT)RVA,IAT是一个IMAGE_THUNK_DATA结构的数组
} IMAGE_IMPORT_DESCRIPTOR;

IMAGE_IMPORT_DESCRIPTOR中具体字段含义百度或者看书就行,讲的都很清楚。
这里要强调一下导入表的双桥结构。IMAGE_IMPORT_DESCRIPTOR结构体中有OriginalFirstThunk(称为桥1)和FirstThunk(称为桥2)。其实无论是桥1和桥2最终都是为了指向具体的导入函数。但是桥1和桥2侧重点不同。从上述结构体注释可以看出来桥2是先指向IAT表,由IAT表再指向真正函数信息(包括函数所在dll的Hint值以及函数名称)。桥1是直接指向函数信息。那么为什么需要桥2这种费力的存在呢?看下图:

双桥结构

OD加载reg.exe,注意下面数据区。内存地址0x00402000映射到文件中地址为0x600h,与上述0x01中第一张图中数值对比可以发现差异:exe在运行过程中会将IAT(桥2指向地址)中地址纠正为函数在内存中正确的地址。这样才可以通过jmp ds:00402008进行跳转。而桥1数据并不会发生改变,仍然指向函数的Hint值与函数名称。

0x02 手工重组导入表实践练习

当完全掌握上述导入表数据结构及双桥结构,我们就可以尝试为一个已有的exe添加新的功能。
现提供一个 tip.exe(下载)。

  1. tip.exe运行时会弹出一个MessageBox窗口,尝试修改其弹出窗口的内容,原来值为spring。
  2. 修改汇编代码,弹出spring窗口前再弹出一个MessageBox窗口。
  3. 上面0x00和0x01实践的reg.exe其功能为在注册表HKLM\Software下面添加一个值。源码和exe上面已经给出,尝试手动将汇编代码融合到 tip.exe中。
    下面给出我手工融合后的exe仅供参考: tip_new.exe(下载)

你可能感兴趣的:(Windows PE权威指南(导入表))