-
-
PE结构导出表信息读取
-
发表于:
2018-8-22 20:16
5368
-
导出表结构分析:
咳咳,这两天舍友回来天天青春献给小酒桌了,忘了更新了,今晚才想起来;
导出表结构分析:
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics; // 未使用
DWORD TimeDateStamp; // 时间戳
WORD MajorVersion; // 未使用
WORD MinorVersion; // 未使用
DWORD Name; // 指向该导出表文件名字符串
DWORD Base; // 导出函数起始序号
DWORD NumberOfFunctions; // 所有导出函数的个数
DWORD NumberOfNames; // 以函数名字导出的函数个数
DWORD AddressOfFunctions; // 导出函数地址表RVA
DWORD AddressOfNames; // 导出函数名称表RVA
DWORD AddressOfNameOrdinals; // 导出函数序号表RVA
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
有用的就后边的这几个,本文解析的只是后三个,由于是RVA需要先转换为FOA;
原理:1、先判断属于哪个节通过数据目录项的virtualaddress 跟每个节的Virtualaddress+misc.virtualsize判断
2、判断属于哪个节了以后减去该节的VirtuallAddress
3、将减完成的差值加上PointerToRawData就是相对于文件的偏移,也就是物理地址;
先贴上自写的RVAToFOA代码:
DWORD RVATOFOA(IN DWORD RVA,OUT DWORD FOA,IN LPVOID pFileBuffer){
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNtHeaders = NULL;
PIMAGE_FILE_HEADER pFileHeader = NULL;
PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNtHeaders + 4);
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
size_t count = 0;
//先判断在哪个节里边
for (count = 1; RVA > (pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize); count++, pSectionHeader++);
FOA = RVA - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
return FOA;
}
有了这个以后再解析导出表的信息:
VOID ExportDirectoryPrintf(){
//定义PE头部指针变量
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNtHeaders = NULL;
PIMAGE_FILE_HEADER pFileHeader = NULL;
PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;
PIMAGE_DATA_DIRECTORY pDataDirectory = NULL;
PIMAGE_EXPORT_DIRECTORY pExportDirectory = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
DWORD ExportFOA = 0;
DWORD FcFOA = 0;
DWORD NameFOA = 0;
DWORD NameOrdinalsFOA = 0;
PDWORD pFunction = NULL;
PDWORD pName = NULL;
PDWORD pNameOrdinals = NULL;
LPVOID pFileBuffer = NULL;
ReadPEFile(INDLLPATH, &pFileBuffer);
if (!pFileBuffer){
printf("文件(dll)打开失败!\n");
free(pFileBuffer);
}
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNtHeaders + 4);
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
pDataDirectory = (PIMAGE_DATA_DIRECTORY)((DWORD)pOptionalHeader + 96);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
printf("导出表RVA:%x\n",pDataDirectory->VirtualAddress);
ExportFOA=RVATOFOA(pDataDirectory->VirtualAddress,ExportFOA,pFileBuffer);
//这个地方需要把导出表的virtualAddress转换为FOA
printf("导出表的FOA:%x\n",ExportFOA);
//转换完成以后用directory指针加上就到导出表的地址了 (文件中地址)
pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((DWORD)pFileBuffer + ExportFOA);
FcFOA = RVATOFOA(pExportDirectory->AddressOfFunctions, FcFOA, pFileBuffer);
NameOrdinalsFOA = RVATOFOA(pExportDirectory->AddressOfNameOrdinals, NameOrdinalsFOA, pFileBuffer);
NameFOA = RVATOFOA(pExportDirectory->AddressOfNames, NameFOA, pFileBuffer);
printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
//先打印函数地址表
pFunction =(PDWORD)((DWORD)pFileBuffer + FcFOA);
printf(" 导出函数地址表RVA:%x\n", pExportDirectory->AddressOfFunctions);
printf(" 导出函数地址表FOA:%x\n", FcFOA);
for (size_t i = 0; i < pExportDirectory->NumberOfFunctions; i++, pFunction++)
{
printf("函数地址%d:%x\n", i, pFunction);
}
printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
//打印函数名称表
pName = (PDWORD)((DWORD)pFileBuffer + NameFOA);
printf(" 导出函数名称表RVA:%x\n", pExportDirectory->AddressOfNames);
printf(" 导出函数名称表FOA:%x\n", NameFOA);
for (size_t i = 0; i < pExportDirectory->NumberOfNames; i++, pName++)
{
printf("函数名称表%d:%x\n", i, pName);
}
printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
//打印导出函数序号表
pNameOrdinals = (PDWORD)((DWORD)pFileBuffer + NameOrdinalsFOA);
printf(" 导出函数序号表RVA:%x\n", pExportDirectory->AddressOfNameOrdinals);
printf(" 导出函数序号表FOA:%x\n", NameOrdinalsFOA);
for (size_t i = 0; i < pExportDirectory->NumberOfNames; i++, pNameOrdinals++)
{
printf("函数序号表第%d个:%x\n", i, pNameOrdinals);
}
printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
}
这个地方使用的是自己写的DLL里边一共四个函数运行结果为:
好啦,还是一片代码为主的文章,如果有什么错误希望大家指正。
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics; // 未使用
DWORD TimeDateStamp; // 时间戳
WORD MajorVersion; // 未使用
WORD MinorVersion; // 未使用
DWORD Name; // 指向该导出表文件名字符串
DWORD Base; // 导出函数起始序号
DWORD NumberOfFunctions; // 所有导出函数的个数
DWORD NumberOfNames; // 以函数名字导出的函数个数
DWORD AddressOfFunctions; // 导出函数地址表RVA
DWORD AddressOfNames; // 导出函数名称表RVA
DWORD AddressOfNameOrdinals; // 导出函数序号表RVA
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
有用的就后边的这几个,本文解析的只是后三个,由于是RVA需要先转换为FOA;
原理:1、先判断属于哪个节通过数据目录项的virtualaddress 跟每个节的Virtualaddress+misc.virtualsize判断
2、判断属于哪个节了以后减去该节的VirtuallAddress
3、将减完成的差值加上PointerToRawData就是相对于文件的偏移,也就是物理地址;
先贴上自写的RVAToFOA代码:
DWORD RVATOFOA(IN DWORD RVA,OUT DWORD FOA,IN LPVOID pFileBuffer){
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNtHeaders = NULL;
PIMAGE_FILE_HEADER pFileHeader = NULL;
PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNtHeaders + 4);
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
size_t count = 0;
//先判断在哪个节里边
for (count = 1; RVA > (pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize); count++, pSectionHeader++);
FOA = RVA - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
return FOA;
}
有了这个以后再解析导出表的信息:
VOID ExportDirectoryPrintf(){
//定义PE头部指针变量
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNtHeaders = NULL;
PIMAGE_FILE_HEADER pFileHeader = NULL;
PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;
PIMAGE_DATA_DIRECTORY pDataDirectory = NULL;
PIMAGE_EXPORT_DIRECTORY pExportDirectory = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
DWORD ExportFOA = 0;
DWORD FcFOA = 0;
DWORD NameFOA = 0;
DWORD NameOrdinalsFOA = 0;
PDWORD pFunction = NULL;
PDWORD pName = NULL;
PDWORD pNameOrdinals = NULL;
LPVOID pFileBuffer = NULL;
ReadPEFile(INDLLPATH, &pFileBuffer);
if (!pFileBuffer){
printf("文件(dll)打开失败!\n");
free(pFileBuffer);
}
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNtHeaders + 4);
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
pDataDirectory = (PIMAGE_DATA_DIRECTORY)((DWORD)pOptionalHeader + 96);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
printf("导出表RVA:%x\n",pDataDirectory->VirtualAddress);
ExportFOA=RVATOFOA(pDataDirectory->VirtualAddress,ExportFOA,pFileBuffer);
//这个地方需要把导出表的virtualAddress转换为FOA
printf("导出表的FOA:%x\n",ExportFOA);
//转换完成以后用directory指针加上就到导出表的地址了 (文件中地址)
pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((DWORD)pFileBuffer + ExportFOA);
FcFOA = RVATOFOA(pExportDirectory->AddressOfFunctions, FcFOA, pFileBuffer);
NameOrdinalsFOA = RVATOFOA(pExportDirectory->AddressOfNameOrdinals, NameOrdinalsFOA, pFileBuffer);
NameFOA = RVATOFOA(pExportDirectory->AddressOfNames, NameFOA, pFileBuffer);
printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
//先打印函数地址表
pFunction =(PDWORD)((DWORD)pFileBuffer + FcFOA);
printf(" 导出函数地址表RVA:%x\n", pExportDirectory->AddressOfFunctions);
printf(" 导出函数地址表FOA:%x\n", FcFOA);
for (size_t i = 0; i < pExportDirectory->NumberOfFunctions; i++, pFunction++)
{
printf("函数地址%d:%x\n", i, pFunction);
}
printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
//打印函数名称表
pName = (PDWORD)((DWORD)pFileBuffer + NameFOA);
printf(" 导出函数名称表RVA:%x\n", pExportDirectory->AddressOfNames);
printf(" 导出函数名称表FOA:%x\n", NameFOA);
for (size_t i = 0; i < pExportDirectory->NumberOfNames; i++, pName++)
{
printf("函数名称表%d:%x\n", i, pName);
}
printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
//打印导出函数序号表
pNameOrdinals = (PDWORD)((DWORD)pFileBuffer + NameOrdinalsFOA);
printf(" 导出函数序号表RVA:%x\n", pExportDirectory->AddressOfNameOrdinals);
printf(" 导出函数序号表FOA:%x\n", NameOrdinalsFOA);
for (size_t i = 0; i < pExportDirectory->NumberOfNames; i++, pNameOrdinals++)
{
printf("函数序号表第%d个:%x\n", i, pNameOrdinals);
}
printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
}
这个地方使用的是自己写的DLL里边一共四个函数运行结果为:
好啦,还是一片代码为主的文章,如果有什么错误希望大家指正。
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics; // 未使用
DWORD TimeDateStamp; // 时间戳
WORD MajorVersion; // 未使用
WORD MinorVersion; // 未使用
DWORD Name; // 指向该导出表文件名字符串
DWORD Base; // 导出函数起始序号
DWORD NumberOfFunctions; // 所有导出函数的个数
DWORD NumberOfNames; // 以函数名字导出的函数个数
DWORD AddressOfFunctions; // 导出函数地址表RVA
DWORD AddressOfNames; // 导出函数名称表RVA
DWORD AddressOfNameOrdinals; // 导出函数序号表RVA
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
有用的就后边的这几个,本文解析的只是后三个,由于是RVA需要先转换为FOA;
原理:1、先判断属于哪个节通过数据目录项的virtualaddress 跟每个节的Virtualaddress+misc.virtualsize判断
2、判断属于哪个节了以后减去该节的VirtuallAddress
3、将减完成的差值加上PointerToRawData就是相对于文件的偏移,也就是物理地址;
先贴上自写的RVAToFOA代码:
DWORD RVATOFOA(IN DWORD RVA,OUT DWORD FOA,IN LPVOID pFileBuffer){
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNtHeaders = NULL;
PIMAGE_FILE_HEADER pFileHeader = NULL;
PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNtHeaders + 4);
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
size_t count = 0;
//先判断在哪个节里边
for (count = 1; RVA > (pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize); count++, pSectionHeader++);
FOA = RVA - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
return FOA;
}
有了这个以后再解析导出表的信息:
VOID ExportDirectoryPrintf(){
//定义PE头部指针变量
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNtHeaders = NULL;
PIMAGE_FILE_HEADER pFileHeader = NULL;
PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;
PIMAGE_DATA_DIRECTORY pDataDirectory = NULL;
PIMAGE_EXPORT_DIRECTORY pExportDirectory = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
DWORD ExportFOA = 0;
DWORD FcFOA = 0;
DWORD NameFOA = 0;
DWORD NameOrdinalsFOA = 0;
PDWORD pFunction = NULL;
PDWORD pName = NULL;
PDWORD pNameOrdinals = NULL;
LPVOID pFileBuffer = NULL;
ReadPEFile(INDLLPATH, &pFileBuffer);
if (!pFileBuffer){
printf("文件(dll)打开失败!\n");
free(pFileBuffer);
}
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNtHeaders + 4);
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
pDataDirectory = (PIMAGE_DATA_DIRECTORY)((DWORD)pOptionalHeader + 96);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
printf("导出表RVA:%x\n",pDataDirectory->VirtualAddress);
ExportFOA=RVATOFOA(pDataDirectory->VirtualAddress,ExportFOA,pFileBuffer);
//这个地方需要把导出表的virtualAddress转换为FOA
printf("导出表的FOA:%x\n",ExportFOA);
//转换完成以后用directory指针加上就到导出表的地址了 (文件中地址)
pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((DWORD)pFileBuffer + ExportFOA);
FcFOA = RVATOFOA(pExportDirectory->AddressOfFunctions, FcFOA, pFileBuffer);
NameOrdinalsFOA = RVATOFOA(pExportDirectory->AddressOfNameOrdinals, NameOrdinalsFOA, pFileBuffer);
NameFOA = RVATOFOA(pExportDirectory->AddressOfNames, NameFOA, pFileBuffer);
printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
//先打印函数地址表
pFunction =(PDWORD)((DWORD)pFileBuffer + FcFOA);
printf(" 导出函数地址表RVA:%x\n", pExportDirectory->AddressOfFunctions);
printf(" 导出函数地址表FOA:%x\n", FcFOA);
for (size_t i = 0; i < pExportDirectory->NumberOfFunctions; i++, pFunction++)
{
printf("函数地址%d:%x\n", i, pFunction);
}
printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
//打印函数名称表
pName = (PDWORD)((DWORD)pFileBuffer + NameFOA);
printf(" 导出函数名称表RVA:%x\n", pExportDirectory->AddressOfNames);
printf(" 导出函数名称表FOA:%x\n", NameFOA);
for (size_t i = 0; i < pExportDirectory->NumberOfNames; i++, pName++)
{
printf("函数名称表%d:%x\n", i, pName);
}
printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
//打印导出函数序号表
pNameOrdinals = (PDWORD)((DWORD)pFileBuffer + NameOrdinalsFOA);
printf(" 导出函数序号表RVA:%x\n", pExportDirectory->AddressOfNameOrdinals);
printf(" 导出函数序号表FOA:%x\n", NameOrdinalsFOA);
for (size_t i = 0; i < pExportDirectory->NumberOfNames; i++, pNameOrdinals++)
{
printf("函数序号表第%d个:%x\n", i, pNameOrdinals);
}
printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
}
这个地方使用的是自己写的DLL里边一共四个函数运行结果为:
好啦,还是一片代码为主的文章,如果有什么错误希望大家指正。
DWORD RVATOFOA(IN DWORD RVA,OUT DWORD FOA,IN LPVOID pFileBuffer){
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNtHeaders = NULL;
PIMAGE_FILE_HEADER pFileHeader = NULL;
PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNtHeaders + 4);
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
size_t count = 0;
//先判断在哪个节里边
for (count = 1; RVA > (pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize); count++, pSectionHeader++);
FOA = RVA - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
return FOA;
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)