如何使用 C 转储 PE 导出函数名称?
How to dump PEs exports functions names with C?
我正在尝试使用 C 解析 PE 文件。导入解析很好,但导出解析有问题。这是我为解析导出而编写的代码:
void PrintExports(DWORD imageBase) {
// Get the export section.
PIMAGE_DOS_HEADER ptrDosHeader = (PIMAGE_DOS_HEADER)imageBase;
PIMAGE_NT_HEADERS32 ptrNtHeaders = (PIMAGE_NT_HEADERS32)(ptrDosHeader->e_lfanew + imageBase);
DWORD exportsStartRVA = ptrNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
DWORD exportsEndRVA = exportsStartRVA + ptrNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
PIMAGE_SECTION_HEADER ptrExportsHeader = GetSectionHeaderByRVA(exportsStartRVA, ptrNtHeaders);
// Check it's not null..
if (!ptrExportsHeader)
return;
PIMAGE_EXPORT_DIRECTORY ptrExportsDirectory = (PIMAGE_EXPORT_DIRECTORY)(imageBase + exportsStartRVA );
printf("Exports\n");
printf(" Exports.section: %s\n", ptrExportsHeader->Name);
printf(" Exports.ordinalBase: %x\n", ptrExportsDirectory->Base);
printf(" Exports.NumberOfFunctions: %x (hex)\n", ptrExportsDirectory->NumberOfFunctions);
printf(" Exports.NumberOfNames: %x (hex)\n", ptrExportsDirectory->NumberOfNames);
PDWORD ptrExportsFunctions = (PDWORD)((DWORD)ptrExportsDirectory->AddressOfFunctions + imageBase);
PDWORD ptrExportsNamesOrdinals = (PDWORD)((DWORD)ptrExportsDirectory->AddressOfNameOrdinals + imageBase);
PDWORD * ptrExportsNames = (PDWORD *)((DWORD)ptrExportsDirectory->AddressOfNames + imageBase);
printf(" Exports.functions:\n");
printf(" EntryPoint Ordinal Name\n");
for (int i = 0; i < ptrExportsDirectory->NumberOfFunctions; i++) {
if (ptrExportsFunctions[i] == 0)
continue;
printf(" %010x %07x", ptrExportsFunctions[i], i + ptrExportsDirectory->Base);
if ((ptrExportsFunctions[i] >= exportsStartRVA) && (ptrExportsFunctions[i] <= exportsEndRVA))
printf(" (forwarder -> %s)", ptrExportsFunctions[i] + imageBase);
printf("\n");
}
return;
}
作为 运行 这段代码的结果,我得到了导出的序号和地址。当我试图用下面的代码获取名称时,问题就开始了(这段代码应该在 "for" 循环内)。发生的事情是我收到访问冲突异常(我在此示例中尝试解析的 PE 是 shell32.dll):
for (int j = 0; j < ptrExportsDirectory->NumberOfNames; j++) {
if (ptrExportsNamesOrdinals[j] == i + ptrExportsDirectory->Base) {
printf(" %s", ptrExportsNames[j]);
}
}
此外,在某些情况下(例如,如果我尝试解析的 PE 是 user32.dll),ptrExportsNamesOrdinal[j] 具有永远无法解析的值等于 i + ptrExportsDirectory->Base。您可以看到下面的屏幕截图:
条件
(ptrExportsNamesOrdinals[j] == i + ptrExportsDirectory->Base)
用在if测试中是错误的。 Export Ordinal Table 实际上不包含序数,而是索引到 Export Address Table(这是 PE/COFF 规范中的错误 - 参见 )。
您应该使用的测试条件是
(ptrExportsNamesOrdinals[j] == i)
如此处示例所示:。
我做了什么来修复它:
PDWORD ptrExportsFunctions = (PDWORD)(imageBase + ptrExportsDirectory->AddressOfFunctions);
PDWORD ptrExportsNames = (PDWORD)(imageBase + ptrExportsDirectory->AddressOfNames);
PWORD ptrExportsNamesOrdinals = (PWORD)(imageBase + ptrExportsDirectory->AddressOfNameOrdinals);
并且比在循环中:
for (DWORD j = 0; j < ptrExportsDirectory->NumberOfNames; j++)
{
if(ptrExportsNamesOrdinals[j] == i){
printf("%s", (char*)imageBase + ptrExportsNames[j]);
}
}
现在一切正常。
我正在尝试使用 C 解析 PE 文件。导入解析很好,但导出解析有问题。这是我为解析导出而编写的代码:
void PrintExports(DWORD imageBase) {
// Get the export section.
PIMAGE_DOS_HEADER ptrDosHeader = (PIMAGE_DOS_HEADER)imageBase;
PIMAGE_NT_HEADERS32 ptrNtHeaders = (PIMAGE_NT_HEADERS32)(ptrDosHeader->e_lfanew + imageBase);
DWORD exportsStartRVA = ptrNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
DWORD exportsEndRVA = exportsStartRVA + ptrNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
PIMAGE_SECTION_HEADER ptrExportsHeader = GetSectionHeaderByRVA(exportsStartRVA, ptrNtHeaders);
// Check it's not null..
if (!ptrExportsHeader)
return;
PIMAGE_EXPORT_DIRECTORY ptrExportsDirectory = (PIMAGE_EXPORT_DIRECTORY)(imageBase + exportsStartRVA );
printf("Exports\n");
printf(" Exports.section: %s\n", ptrExportsHeader->Name);
printf(" Exports.ordinalBase: %x\n", ptrExportsDirectory->Base);
printf(" Exports.NumberOfFunctions: %x (hex)\n", ptrExportsDirectory->NumberOfFunctions);
printf(" Exports.NumberOfNames: %x (hex)\n", ptrExportsDirectory->NumberOfNames);
PDWORD ptrExportsFunctions = (PDWORD)((DWORD)ptrExportsDirectory->AddressOfFunctions + imageBase);
PDWORD ptrExportsNamesOrdinals = (PDWORD)((DWORD)ptrExportsDirectory->AddressOfNameOrdinals + imageBase);
PDWORD * ptrExportsNames = (PDWORD *)((DWORD)ptrExportsDirectory->AddressOfNames + imageBase);
printf(" Exports.functions:\n");
printf(" EntryPoint Ordinal Name\n");
for (int i = 0; i < ptrExportsDirectory->NumberOfFunctions; i++) {
if (ptrExportsFunctions[i] == 0)
continue;
printf(" %010x %07x", ptrExportsFunctions[i], i + ptrExportsDirectory->Base);
if ((ptrExportsFunctions[i] >= exportsStartRVA) && (ptrExportsFunctions[i] <= exportsEndRVA))
printf(" (forwarder -> %s)", ptrExportsFunctions[i] + imageBase);
printf("\n");
}
return;
}
作为 运行 这段代码的结果,我得到了导出的序号和地址。当我试图用下面的代码获取名称时,问题就开始了(这段代码应该在 "for" 循环内)。发生的事情是我收到访问冲突异常(我在此示例中尝试解析的 PE 是 shell32.dll):
for (int j = 0; j < ptrExportsDirectory->NumberOfNames; j++) {
if (ptrExportsNamesOrdinals[j] == i + ptrExportsDirectory->Base) {
printf(" %s", ptrExportsNames[j]);
}
}
此外,在某些情况下(例如,如果我尝试解析的 PE 是 user32.dll),ptrExportsNamesOrdinal[j] 具有永远无法解析的值等于 i + ptrExportsDirectory->Base。您可以看到下面的屏幕截图:
条件
(ptrExportsNamesOrdinals[j] == i + ptrExportsDirectory->Base)
用在if测试中是错误的。 Export Ordinal Table 实际上不包含序数,而是索引到 Export Address Table(这是 PE/COFF 规范中的错误 - 参见
您应该使用的测试条件是
(ptrExportsNamesOrdinals[j] == i)
如此处示例所示:
我做了什么来修复它:
PDWORD ptrExportsFunctions = (PDWORD)(imageBase + ptrExportsDirectory->AddressOfFunctions);
PDWORD ptrExportsNames = (PDWORD)(imageBase + ptrExportsDirectory->AddressOfNames);
PWORD ptrExportsNamesOrdinals = (PWORD)(imageBase + ptrExportsDirectory->AddressOfNameOrdinals);
并且比在循环中:
for (DWORD j = 0; j < ptrExportsDirectory->NumberOfNames; j++)
{
if(ptrExportsNamesOrdinals[j] == i){
printf("%s", (char*)imageBase + ptrExportsNames[j]);
}
}
现在一切正常。