本帖最后由 appsion 于 2020-11-1 11:28 编辑
PE 文件解析3-数据目录[导出表]
新手学习PE文件解析记录, 持续更新. 部分参考来源于网络, 无法逐一标注, 如果侵权,请及时联系. 如有错误请指正,误喷.
上文链接: https://www.52pojie.cn/thread-1294381-1-1.html
结构体: IMAGE_EXPORT_DIRECTORY 说明: 导出表信息 头文件: winnt.h 帮助文档: 仅存在于头文件, 没有帮助文档
[Asm] 纯文本查看 复制代码
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Name;
DWORD Base;
DWORD NumberOfFunctions;
DWORD NumberOfNames;
DWORD AddressOfFunctions; // RVA from base of image
DWORD AddressOfNames; // RVA from base of image
DWORD AddressOfNameOrdinals; // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY
参数说明: 仅供参考, 详细说明请参考原文.
Characteristics
描述
TimeDateStamp
创建时间
MajorVersion
主版本号
MinorVersion
次版本号
Name
DLL库文件名的RVA.
Base
导出函数的起始序号.
NumberOfFunctions
导出函数的函数总数量.
NumberOfNames
按名称导出的函数数量
AddressOfFunctions
指向输出函数地址的RVA
AddressOfNames
指向输出函数名称的RVA
AddressOfNameOrdinals
指向输出函数序号的RVA
3.1 获取导出表信息
[Asm] 纯文本查看 复制代码
// 参数说明
// DataBuff:文件指针
// ExportRVA:导出表的RVA
void ExportDllInfo(char *DataBuff, DWORD ExportRVA)
{
// 获取节表
int SectionCount = 0;
IMAGE_SECTION_HEADER *SectionHead = GetSectionHead(DataBuff, SectionCount);
// 获取导出表FOA
DWORD ExportFOA = RVAToRaw(SectionHead, SectionCount, ExportRVA);
// 获取导出表
IMAGE_EXPORT_DIRECTORY *Export = (IMAGE_EXPORT_DIRECTORY*)(DataBuff + ExportFOA);
// 导出表名称RVA
DWORD DllName_RVA = Export->Name;
// 导出表名称FOA
DWORD DllName_FOA = RVAToRaw(SectionHead, SectionCount, DllName_RVA);
// 导出表名称
char *DllName = (char *)(DataBuff + DllName_FOA);
// 导出表创建时间
// Export->TimeDateStamp
// 导出表主版本
// Export->MajorVersion
// 导出表次版本
// Export->MinorVersion
// 导出函数起始序号
// Export->Base
// 导出函数总数量
// Export->NumberOfFunctions
// 按名称导出的函数数量
// Export->NumberOfNames
// 导出函数地址FOA
DWORD ExportFunction_FOA = RVAToRaw(SectionHead, SectionCount, Export->AddressOfFunctions);
// 导出函数名称FOA
DWORD ExportName_FOA = RVAToRaw(SectionHead, SectionCount, Export->AddressOfNames);
// 函数序号FOA
DWORD ExportOrdinal_FOA = RVAToRaw(SectionHead, SectionCount, Export->AddressOfNameOrdinals);
}
3.2 获取导出函数信息, 方式有二种, 按名称导出, 按序号导出.
1. 按名称导出
[Asm] 纯文本查看 复制代码
for (size_t i = 0; i < Export->NumberOfNames; i++)
{
// 名称RVA
DWORD Name_RVA = ((DWORD*)(DataBuff + ExportName_FOA))[i];
// 序号
WORD Ordinal = ((WORD*)(DataBuff + ExportOrdinal_FOA))[i];
}
2. 按序号导出
[Asm] 纯文本查看 复制代码
// 获取导出函数名称RVA与序号
std::map<WORD, DWORD> NameOrdinal;
std::map<WORD, DWORD>::iterator Find_NameOrdinal;
for (size_t i = 0; i < Export->NumberOfNames; i++)
{
WORD Ordinal = ((WORD*)(DataBuff + ExportOrdinal_FOA))[i];
DWORD Name_RVA = ((DWORD*)(DataBuff + ExportName_FOA))[i];
NameOrdinal.insert(std::pair<WORD, DWORD>(Ordinal, Name_RVA));
}
// 实际导出数量, 注: 部分 FunctionRVA 为0;
int RealFunctionCount = 0;
for (size_t i = 0; i < Export->NumberOfFunctions; i++)
{
// FunctionRVA
DWORD FunctionRVA = ((DWORD*)(DataBuff + ExportFunction_FOA))[i];
if (!FunctionRVA) continue;
// FunctionID
// 注:
//1. Export->Base 为导出函数的起始序号
//2. 函数序号不是按递增方式排列
WORD Ordinal = Export->Base + i;
Find_NameOrdinal = NameOrdinal.find(i);
if (Find_NameOrdinal != NameOrdinal.end())
{
// 导出函数名称RVA
DWORD Name_RVA = Find_NameOrdinal->second;
// 导出函数名称FOA
DWORD Name_FOA = RVAToRaw(SectionHead, SectionCount, Find_NameOrdinal->second);
// 导出函数名称
char *Name = DataBuff + Name_FOA;
}
RealFunctionCount++;
}
RVA 转 FOA
[Asm] 纯文本查看 复制代码
DWORD RVAToRaw(IMAGE_SECTION_HEADER *SectionHead, int SECTIONCount, DWORD m_RVA)
{
// 遍历节表
for (size_t i = 0; i < SECTIONCount; i++)
{
IMAGE_SECTION_HEADER section = ((IMAGE_SECTION_HEADER*)SectionHead)[i];
// 判断 RVA 所在的节表
if (m_RVA >= section.VirtualAddress && m_RVA <= (section.VirtualAddress + section.SizeOfRawData))
{
// 获取偏移差
m_RVA = m_RVA - section.VirtualAddress;
m_RVA = m_RVA + section.PointerToRawData;
return m_RVA;
}
}
return 0;
}
|