当前位置 博文首页 > KOOKNUT的博客:PE文件学习--导出表
IMAGE_OPTIONAL_HEADER32.DataDirectory数组中的第一成员是导出表,今天来看看导出表的相关知识点。
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory
导出表,顾名思义,就是本文件向外部导出的一张表,而这张表中存放一些什么东西呢?里面存放的是一些导出函数,方便代码的重用,一般来说,导出表的概念会和动态链接库联系在一起。相当于动态库告诉外部加载者,我的哪些函数是可以被你调用的。
我们先来看看导出表中数据存放是如何存放的:
typedef struct _IMAGE_EXPORT_DIRECTORY
{
DWORD Characteristics;//标志位 未用
DWORD TimeDateStamp; //时间戳
WORD MajorVersion; //0
WORD MinorVersion; //0
DWORD Name; //导出表所在文件的文件名
DWORD Base; //导出函数的起始序号
DWORD NumberOfFunctions; //所有导出函数的个数
DWORD NumberOfNames; //以函数名称导出的函数个数
DWORD AddressOfFunctions; //导出函数地址表RVA
DWORD AddressOfNames; //函数名称地址表RVA
DWORD AddressOfNameOrdinals; //函数序号地址表RVA
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
接下来说一些对于32位的PE文件导出表进行遍历时候,所用到的一些重要API函数实现:
//定位第一个IMAGE_SECTION_HEADER
#define IMAGE_FIRST_SECTION( NtHeader ) \
((PIMAGE_SECTION_HEADER) ((ULONG_PTR)(NtHeader) + \
FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) + \
((NtHeader))->FileHeader.SizeOfOptionalHeader))
PVOID
NTAPI
RtlImageRvaToVa(
PIMAGE_NT_HEADERS NtHeader,
PVOID BaseAddress,
ULONG Rva,
PIMAGE_SECTION_HEADER *SectionHeader)
{
PIMAGE_SECTION_HEADER Section = NULL;
if (SectionHeader)
Section = *SectionHeader;
if ((Section == NULL) ||
(Rva < SWAPD(Section->VirtualAddress)) ||
(Rva >= SWAPD(Section->VirtualAddress) + SWAPD(Section->SizeOfRawData)))
{
//将当前虚拟地址所在的节区定位出来
Section = RtlImageRvaToSection(NtHeader, BaseAddress, Rva);
if (Section == NULL)
return NULL;
if (SectionHeader)
*SectionHeader = Section;//用于返出值
}
/*此处就是进行内存地址和文件地址的转换,其思想为:
当前所要定位到当前打开文件的基地址(ImageBase)+在节区的相对偏移(RVA-Section->VirtualAddress)+节区在文件中的偏移地址,,得到当前查询数据在文件中的地址
*/
return (PVOID)((ULONG_PTR)BaseAddress + Rva +
(ULONG_PTR)SWAPD(Section->PointerToRawData) -
(ULONG_PTR)SWAPD(Section->VirtualAddress));
}
///RtlImageRvaToSection的实现,实现RVA的所在节区定位
PIMAGE_SECTION_HEADER
NTAPI
RtlImageRvaToSection(
PIMAGE_NT_HEADERS NtHeader,
PVOID BaseAddress,
ULONG Rva)
{
PIMAGE_SECTION_HEADER Section;
ULONG Va;
ULONG Count;
//节区总数
Count = SWAPW(NtHeader->FileHeader.NumberOfSections);
//第一个IMAGE_SECTION_HEADER的定位
Section = IMAGE_FIRST_SECTION(NtHeader);
while (Count--)
{
Va = SWAPD(Section->VirtualAddress);
if ((Va <= Rva) && (Rva < Va + SWAPD(Section->SizeOfRawData)))
return Section;
Section++;
}
return NULL;
}
“假令风歇时下来,犹能簸却沧溟水。”–李白
参考书籍:
《Windows PE权威指南》