pe结构学习心得(五)--获取导出表
// PEExportTable.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <windows.h>
#include <time.h>
#include <imagehlp.h>
#pragma comment (lib, "imagehlp.lib")
int _tmain(int argc, _TCHAR* argv[])
{
while (1) {
WCHAR cFile[256] = {0};
printf("Please enter the file name and path:");
wscanf(L"%s",cFile);
HANDLE hFile = NULL;
hFile = ::CreateFile((LPCWSTR)cFile,GENERIC_READ,0,NULL,OPEN_EXISTING,NULL,NULL);
if (hFile == INVALID_HANDLE_VALUE){
printf("Create file failed! (%d).\n\n", GetLastError());
system("pause");
return 0;
}
//创建文件映射
HANDLE hMap = NULL;
hMap = ::CreateFileMapping(hFile,NULL,PAGE_READONLY,0,0,0);
if (!hMap){
printf("Create file mapping failed! (%d).\n\n", GetLastError());
system("pause");
return 0;
}
//映射要自己进程的空间
LPVOID pMap = NULL;
pMap = ::MapViewOfFile(hMap,FILE_MAP_READ,0,0,0);
if (!pMap){
printf("Mapping file failed (%d).\n\n", GetLastError());
system("pause");
return 0;
}
//后面计算文件偏移的时候要用到的
ULONG dwImageBase = (ULONG)pMap;
//获得DOS头文件指针
PIMAGE_DOS_HEADER pDosHeader = NULL;//DOS头文件
pDosHeader = (PIMAGE_DOS_HEADER)pMap;
//判断DOS头标志 IMAGE_DOS_SIGNATURE 0x5A4D MZ
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE){
printf("Not DOS Header! (%d).\n\n", GetLastError());
system("pause");
return 0;
}
//获得PE头文件指针
PIMAGE_NT_HEADERS pPeHeaders = NULL;//PE头文件
pPeHeaders = (PIMAGE_NT_HEADERS)((LONG)pMap + pDosHeader->e_lfanew);
//判断PE头标志 IMAGE_NT_SIGNATURE 0x00004550 PE00
if (pPeHeaders->Signature != IMAGE_NT_SIGNATURE){
printf("Not PE Header! (%d).\n\n", GetLastError());
system("pause");
return 0;
}
//打印输出表
//获得输出表指针
if (!pPeHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) {
printf("Can't find export table!\n\n");
system("pause");
return 0;
}
PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)::ImageRvaToVa(pPeHeaders, pMap, pPeHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress, NULL);
//打印IMAGE_EXPORT_DIRECTORY各个域的值
printf("Image export table infomation:\n");
printf("-------------------------------------------------------------------\n");
printf("IMAGE_EXPORT_DESCRIPTOR\n\tCharacteristics:\t0x%08x\n\tTimeDateStamp:\t\t0x%08x\n\tMajorVersion:\t\t0x%08x\n\tMinorVersion:\t\t0x%08x\n\tName:\t\t\t0x%08x\tOffset:0x%08x\t%s\n\tBase:\t\t\t0x%08x\n\tNumberOfFunctions:\t0x%08x\t%d\n\tNumberOfNames:\t\t0x%08x\t%d\n\tAddressOfFunctions:\t0x%08x\tOffset:0x%08x\n\tAddressOfNames:\t\t0x%08x\tOffset:0x%08x\n\tAddressOfNameOrdinals:\t0x%08x\tOffset:0x%08x\n\n",
pExportTable->Characteristics,
pExportTable->TimeDateStamp,
pExportTable->MajorVersion,
pExportTable->MinorVersion,
pExportTable->Name, (ULONG)::ImageRvaToVa(pPeHeaders, pMap, pExportTable->Name, NULL) - dwImageBase, //RVA & Offset
::ImageRvaToVa(pPeHeaders, pMap, pExportTable->Name, NULL), //字符串
pExportTable->Base,
pExportTable->NumberOfFunctions,
pExportTable->NumberOfFunctions, //函数个数
pExportTable->NumberOfNames,
pExportTable->NumberOfNames, //有符号名称的函数个数
pExportTable->AddressOfFunctions, (ULONG)::ImageRvaToVa(pPeHeaders, pMap, pExportTable->AddressOfFunctions, NULL) - dwImageBase, //函数的地址表 RVA & Offset
pExportTable->AddressOfNames, (ULONG)::ImageRvaToVa(pPeHeaders, pMap, pExportTable->AddressOfNames, NULL) - dwImageBase, //函数的名称表 RVA & Offset
pExportTable->AddressOfNameOrdinals, (ULONG)::ImageRvaToVa(pPeHeaders, pMap, pExportTable->AddressOfNameOrdinals, NULL) - dwImageBase); //函数的序号表 RVA & Offset
//打印输出函数序号、偏移、符号名称
printf("\tOrdinal\t\t\tRVA(Offset)\t\tSymbol Name\n");
printf("\t-----------------------------------------------------------\n");
//一般情况下这样处理是没问题的,但是如果序号不是连贯的就有问题了
PDWORD pdwSymbolName = NULL;
PDWORD pdwFunction = NULL;
PWORD pdwOrdinal = NULL;
pdwOrdinal = (PWORD)::ImageRvaToVa(pPeHeaders,pMap,(ULONG)pExportTable->AddressOfNameOrdinals, NULL);
pdwFunction = (PDWORD)::ImageRvaToVa(pPeHeaders,pMap,(ULONG)pExportTable->AddressOfFunctions, NULL);
pdwSymbolName = (PDWORD)::ImageRvaToVa(pPeHeaders,pMap,(ULONG)pExportTable->AddressOfNames, NULL);
//打印出按名字导出的函数
for (UINT m = 0; m < (ULONG)pExportTable->AddressOfFunctions; m++) {
for (UINT n = 0; n < (ULONG)pExportTable->NumberOfNames; n++) {
if (m == pdwOrdinal[n]) {
printf("\t(%d)\t0x%08x\t0x%08x(0x%08x)\t0x%08x:(0x%08x)%s\n",
pdwOrdinal[n] + pExportTable->Base, //序号十进制
pdwOrdinal[n] + pExportTable->Base, //序号十六进制
pdwFunction[m], //函数入口地址(RVA)
(ULONG)::ImageRvaToVa(pPeHeaders, pMap, (ULONG)pdwFunction[m], NULL) - dwImageBase, //函数入口地址Offset)减去起始地址才是在文件中的偏移量
pdwSymbolName[n], //名字(RVA)
(ULONG)::ImageRvaToVa(pPeHeaders, pMap, (ULONG)pdwSymbolName[n], NULL) - dwImageBase, //名字(Offset)减去起始地址才是在文件中的偏移量
::ImageRvaToVa(pPeHeaders, pMap, (ULONG)pdwSymbolName[n], NULL));
}
}
}
//关闭打开的句柄,释放资源
::UnmapViewOfFile(pMap);
::CloseHandle(hMap);
::CloseHandle(hFile);
}
system("pause");
return 0;
}
