问题描述
我想以下列形式打印有关 IMAGE_EXPORT_DIRECTORY
的信息:
I want to print information about IMAGE_EXPORT_DIRECTORY
in the following form:
<Name1>,<Ordinal1>,<FileAddress1>
我知道这个 IMAGE 由 3 个数组组成:
I know that this IMAGE consists of 3 arrays:
- AddressOfFunctions -(导出地址表,每个元素都是一个 RVA)
- AddressOfNames -(导出名称指针表,每个元素也是一个 RVA - 有序?)
- AddressOfNameOrdinals(其中数组元素 - Base 代表 EAT 中的序数)
但是我如何访问这些表格以在一行中打印每个元素的信息?此外,当 NumberOfNames <时会发生什么?NumberOfFunctions ?
But how can i access those tables in order to print information for each element in one line? Also, what would happen when NumberOfNames < NumberOfFunctions ?
我已经知道如何前往 IMAGE_EXPORT_DIRECTORY
I already know how to get to the IMAGE_EXPORT_DIRECTORY
PIMAGE_DATA_DIRECTORY pFirstDir = &(pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]);
if (pFirstDir->Size > 0)
{
PIMAGE_EXPORT_DIRECTORY pExportDir = (PIMAGE_EXPORT_DIRECTORY)((BYTE *)pDosHeader + ConvertRvaToOffset(pFirstDir->VirtualAddress, pNTHeaders));
}
如果有人能解释这些数组的实际工作原理或如何访问它们的算法,我们将不胜感激.
If someone could explain how those arrays actually work or an algorithm of how to access them it would be greatly appreciated.
推荐答案
您可以使用以下伪 C 代码:
You can use the following pseudo-C-code:
UINT32 *export_addr_table = (UINT32 *) MAP(pExportDir->AddressOfFunctions);
UINT32 *export_nameptr_table = (UINT32 *) MAP(pExportDir->AddressOfNames);
UINT16 *export_ordinal_table = (UINT16 *) MAP(pExportDir->AddressOfNameOrdinals);
for (SIZE_T i = 0; i < pExportDir->NumberOfFunctions; i++)
{
UINT32 ordinal = pExportDir->Base + i;
UINT32 export_rva = export_addr_table[i];
if (is_forwarder_rva(export_rva))
{
// TODO: special care must be taken here - we cannot resolve directly to a VA unless target module is memory mapped
}
else
{
BOOL found_symname = FALSE;
char symname[MAX_SYMNAME_LEN];
// Loop through all exported names
for (SIZE_T j = 0; j < pExportDir->NumberOfNames; j++)
{
if (export_ordinal_table[j] == i)
{
UINT32 export_symname_rva = export_nameptr_table[j];
const char *export_symname = (const char *) MAP(export_symname_rva);
found_symname = TRUE;
// Copy export_symname into symname (i.e. using strncat or similar)
}
}
if (!found_symname)
{
snprintf(symname, MAX_SYMNAME_LEN, "#%"PRIu32, ordinal);
}
// Print symname, ordinal, address
}
}
这里,我使用 MAP()
表示将 RVA 解析为可取消引用的虚拟地址的操作(类似于您使用 ConvertRvaToOffset
所做的).
Here, I use MAP()
as representing the operation of resolving an RVA to a dereferencable virtual address (similar to what you did using ConvertRvaToOffset
).
说明:
导出地址表中存在所有导出的函数,但正如您已经指出的那样,导出名称指针表和导出序数表(它们是并行表)中仅存在命名函数.
All functions that are exported are present in the Export Address Table, but as you already have pointed out, only named functions are present in the Export Name Pointer Table and Export Ordinal Table (which are parallel tables).
导出名称指针表中的条目按词法排序,以便于从导出函数的符号名称快速解析为其无偏"序数(即导出地址表中的索引).因此,换一种方式,找到导出函数的导出名称(如果有),唯一的解决方案是遍历每个导出的名称并尝试匹配 RVA.
The entries in the Export Name Pointer Table are ordered lexically, to facilitate quick resolution from symbol names of exported functions to their "unbiased" ordinals (i.e. indexes into the Export Address Table). So to go the other way, and find the exported name (if any) for an exported function, the only solution is really to iterate through every exported name and try to match the RVA.
但是,导出地址表中的某些条目代表所谓的转发器 RVA"条目,它们将导出重定向到另一个 DLL 模块中的符号(请参阅 PE/COFF 6.3.2).这些不能真正以您想要的格式打印,所以我只是在上面的伪代码中添加了一个 //TODO
用于这种情况.
However, some entries in the Export Address Tables represent so called "forwarder RVA" entries, which redirect the export to a symbol in another DLL module (see PE/COFF 6.3.2). These cannot really be printed in the format you wanted, so I just added a // TODO
in the pseudo-code above for that case.
此外,请注意,对于每个导出函数(按名称导出和仅按序数导出),此函数的有效符号名称(用于解析导入查找表条目)是 #OrdinalNumber
,其中 OrdinalNumber
替换为实际的序号(请参阅 PE/COFF 6.3.2),所以这可能被列为导出函数的名称不是按名称导出的.
In addition, note that for every exported function (both exported by name, and by ordinal only), a valid symbol name (w.r.t to resolving Import Lookup Table entries) for this function is #OrdinalNumber
, where OrdinalNumber
is replaced with the actual ordinal (see the description for Forwarder RVA in PE/COFF 6.3.2), so this could make sense to list as the name of exported functions that are not exported by name.
这篇关于显示有关 IMAGE_EXPORT_DIRECTORY 的信息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!