PE文件中的IAT和IET
IAT
IAT中文名叫导入地址表
在IAT中存放的是导入的函数的RVA数组,每个元素对应一个函数的地址(RVA)
通过这个RVA即可找到导入函数的位置
所以说我们必须先知道IAT在哪
1.找到可选头结构体的最后一个成员
可选头结构体的最后一个成员是DataDirectory
它是一个结构体数组
typedef struct _IMAGE_OPTIONAL_HEADER {
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;
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;
它的每个元素是一个IMAGE_DATA_DIRECTORY(IDD)结构体
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
2.找DataDirectory数组的第二个成员
上图就是DataDirectory数组,每个元素就是上面说的IDD结构体
我们找到第二个元素IMPORT Table
可以得到它的RVA和Size(对应的就是IDD结构体的VirtualAddress和Size成员)
3.通过找到的RVA我们转到IMPORT Table的地址
这个地址也是一个结构体数组,每个元素都是一个IMAGE_IMPORT_DESCRIPTOR(IID)结构体
该结构体有20个字节大小
typedef struct _IMAGE_IMPORT_DESCRIPTOR{
union{
DWORD Characteristics;
DWORD OriginalFirstThunk; //INT的RVA
};
DWORD TimeDateStamp;
DWORD ForwarderChain;
DWORD Name; //导入的库的名称的RVA
DWORD FirstThunk; //IAT的RVA
}IMAGE_IMPORT_DESCRIPTOR;
通过该结构体的最后一个成员我们得到IAT的RVA
上图中蓝色部分即为IMPORT Table数组中的第一个元素
4.通过IID找IAT
找到IID后(这里我们选的是IMPORT Table数组中的第一个元素)
通过最后一个4字节成员0x1000(即IAT的RVA),找到IAT的地址
图中蓝色部分即为导入函数的RVA,
注意IAT是一个地址数组,数组元素全都是导入函数的RVA
这里,我们选第一个地址0xC1708,转到相应地址查看
可以看到导入函数的相应信息
注意:这里的相关信息是一个IMAGE_IMPORT_BY_NAME结构体(图中蓝色部分)
其实上面的IAT地址处是地址数组,也是IMAGE_IMPORT_BY_NAME结构体的指针数组
每个地址都是一个IMAGE_IMPORT_BY_NAME结构体的指针
IMAGE_IMPORT_BY_NAME结构体定义如下:
typedef struct _IMAGE_IMPORT_BY_NAME{
WORD Hint; //导入函数的源(就是一个标识)
BYTE Name[1]; //导入函数的名称
}IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
IET
IET简单理解就是一个应用程序或库需要给别的程序用的函数,即导出函数表
怎么找到IET的导出函数的地址?
1.找可选头最后一个成员DataDirectory
找到DataDirectory[0]
DataDirectory的第一个元素就是EXPORT Table
通过其RVA转到相应地址
2.找到IET倒数第三个成员
上图蓝色部分即为IET,可以发现:
IET地址处只有一个结构体(IED,40个字节),与IAT地址处相比较,IAT地址处是一个结构体数组,每个元素都是一个20字节的IID结构体
IET地址处的结构体为IMAGE_EXPORT_DIRECTORY(IED)
IED结构体定义如下:
typedef struct _IMAGE_EXPORT_DIRECTORY{
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Name; //库的名称地址(RVA)
DWORD Base;
DWORD NumberOfFunctions;
DWORD NumberOfNames;
DWORD AddressOfFunctions; //导出函数的起始地址(RVA)这个地址里面 是一个地址数组,每个地址就是一个导出函数的地址
DWORD AddressOfNames; //库中导出函数的名称地址(RVA)
DWORD AddressOfNameOrdinals;
}IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
找到AddressOfFunctions的RVA
3.通过找到的AddressOfFunctions转到相应地址
转到B5A0C
这里我们随便选一个地址看看,如第一个4EF9A(RVA),将其加上文件映射基址(我的环境下是77DE0000),得到77E2EF9A(VA)
77E2EF9A这个地址在OD中即可找到相应导出函数(但是我的环境下不知道为什么OD不显示…请大神指点)