PE文件导出表结构
typedef struct _IMAGE_EXPORT_DIRECTORY {
//保留。恒为0x00000000
DWORD Characteristics;
//导出表的创建时间(GMT)
DWORD TimeDateStamp;
//导出表的主版本号
WORD MajorVersion;
//导出表的子版本号
WORD MinorVersion;
//导出模块的名字
DWORD Name;
//API 索引基数
DWORD Base;
//EAT数量
DWORD NumberOfFunctions;
//ENT数量
DWORD NumberOfNames;
//EAT的RVA
DWORD AddressOfFunctions;
//ENT的RVA
DWORD AddressOfNames;
//导出序号表的RVA
DWORD AddressOfNameOrdinals;
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
导出表主要由名称表,函数表,序号表组成的,但是函数表和序号表是一定要有的,名称表是可选的。
解析过程中要注意RVA转Offset。
BOOL PEAnalyseSpace::PEAnalyse::ShowExport()
{
BOOL bRet = FALSE;//是否执行成功
PIMAGE_EXPORT_DIRECTORY pExport = NULL;//导出表指针
PDWORD pNames = NULL;//名称表指针
PWORD pOrders = NULL;//序号表指针
PDWORD pFuncs = NULL;//地址表指针
PCHAR pszName = NULL;//指向函数名字
DWORD dwIndex = 0;//索引
DWORD dwNum = 0;//导出函数的数量
do
{
//没有解析
if (m_lpBase == NULL)
{
break;
}
//导出表为空
if (m_pNt->OptionalHeader.DataDirectory->Size == NULL)
{
break;
}
//获取导出表
pExport = (PIMAGE_EXPORT_DIRECTORY)
(RVAtoOffset(m_pNt->OptionalHeader.DataDirectory->VirtualAddress)
+(DWORD)m_lpBase);
//获取导出函数的数量
dwNum = pExport->NumberOfFunctions;
//导出函数
pNames = (PDWORD)((PCHAR)RVAtoOffset(pExport->AddressOfNames) + (DWORD)m_lpBase);
//导出序号
pOrders = (PWORD)(RVAtoOffset(pExport->AddressOfNameOrdinals) + (DWORD)m_lpBase);
//导出地址
pFuncs = (PDWORD)(RVAtoOffset(pExport->AddressOfFunctions) + (DWORD)m_lpBase);
//输出导出模块的名称
cout << "Module Name Is: "
<< (PCHAR)(RVAtoOffset(pExport->Name) + (DWORD)m_lpBase)
<< endl;
for (; dwIndex < dwNum; dwIndex++)
{
//获取函数名
pszName = (PCHAR)(RVAtoOffset(pNames[dwIndex]) + (DWORD)m_lpBase);
cout << "ID: " << pOrders[dwIndex]
<< "\tFunctionName: " << pszName
<< "\tFunctionRVA: " << hex << "0x" << pFuncs[dwIndex]
<< endl;
}
bRet = TRUE;
} while (FALSE);
return bRet;
}
实际效果:
Github:PEAnalyse