5、导出表
typedef struct _IMAGE_EXPORT_DIRECTORY {DWORD Characteristics;DWORD TimeDateStamp;WORD MajorVersion;WORD MinorVersion;DWORD Name; // 指向 导出表的文件名DWORD Base; // 导出函数的起始序号DWORD NumberOfFunctions; // 所有导出函数的个数(不准确)DWORD NumberOfNames; // 以函数名称导出函数的个数DWORD AddressOfFunctions; // RVA from base of image 导出函数地址表DWORD AddressOfNames; // RVA from base of image 导出函数名称表DWORD AddressOfNameOrdinals; // RVA from base of image 导出函数序号表
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
这个导出表。他在可选PE头中的最后一个数组。
在可选PE头中是这样的
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
我们直接点进去
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
看到了这样的字眼,其实就可以确定了。这是一个固定的值是16
所以,我们继续下一步。我们找到可选PE头
这里带读者找一遍
首先起始位置是4D5A我们就去3C位置去看一下,NT头。的位置 ,4550是PE标记,没问题了。
然后标准PE头的大小是20 个字节,
这个E0是可选PE头的大小。我们就直接往下找。
标记上的就是可选PE头了。
从可选PE头的最后一个字节,往上数16个(8字节)数据。
也就是这个
其中00018F90就是导出表的数据。首先我们判断一下对不对。我们使用PEtools来判断一下。
这里要提一嘴,大小哪里来 的。看一下结构体就知道了
typedef struct _IMAGE_DATA_DIRECTORY {DWORD VirtualAddress;DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
下面开始演示RvaToFoa
首先使用PETool打开
选择这个,我们0x00018F90再rdata区,
所以这个 减去内存偏移 + 文件偏移即可。
这样也就定位到了我们要的数据。
下面继续说我们的导出表。
typedef struct _IMAGE_EXPORT_DIRECTORY {DWORD Characteristics;DWORD TimeDateStamp;WORD MajorVersion;WORD MinorVersion;DWORD Name; // 指向 导出表的文件名DWORD Base; // 导出函数的起始序号DWORD NumberOfFunctions; // 所有导出函数的个数(不准确)DWORD NumberOfNames; // 以函数名称导出函数的个数DWORD AddressOfFunctions; // RVA from base of image 导出函数地址表DWORD AddressOfNames; // RVA from base of image 导出函数名称表DWORD AddressOfNameOrdinals; // RVA from base of image 导出函数序号表
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
首先前12个字节全是废的 我们无需理会。直接从
也就是我标记的,从下面开始看 下面四个字节是一个Name数据,注意这里也是一个RVA
DWORD Name; // 指向 导出表的文件名DWORD Base; // 导出函数的起始序号DWORD NumberOfFunctions; // 所有导出函数的个数(不准确)DWORD NumberOfNames; // 以函数名称导出函数的个数DWORD AddressOfFunctions; // RVA from base of image 导出函数地址表DWORD AddressOfNames; // RVA from base of image 导出函数名称表DWORD AddressOfNameOrdinals; // RVA from base of image 导出函数序号表
好了。下面开始着重记录三张表
DWORD AddressOfFunctions; // RVA from base of image 导出函数地址表
这里记录的是导出函数的地址,偏移量从序号表中获取
DWORD AddressOfNameOrdinals; // RVA from base of image 导出函数序号表
也就是这个表。
DWORD AddressOfNames; // RVA from base of image 导出函数名称表
这是一个名称表。要注意一点。导出序号表的序号是一个WORD不是DWORD类型的。
VOID PrintExpInfo(PCHAR pFileBuffer)
{if (!pFileBuffer){return;}PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pFileBuffer;PIMAGE_NT_HEADERS pNth = (PIMAGE_NT_HEADERS)(pFileBuffer + pDos->e_lfanew);if (pNth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == NULL){return;}// 定位到导出表DWORD dwExportFoa = RvaToFoa(pFileBuffer, pNth->OptionalHeader.DataDirectory[0].VirtualAddress);PIMAGE_EXPORT_DIRECTORY pExp = (PIMAGE_EXPORT_DIRECTORY)(pFileBuffer + dwExportFoa);// 输出基本内容printf("Name; [%s] \n", pFileBuffer + RvaToFoa(pFileBuffer, pExp->Name));printf("Base; [0x%08x] \n", pExp->Base);printf("NumberOfFunctions; [0x%08x] \n", pExp->NumberOfFunctions);printf("NumberOfNames; [0x%08x] \n", pExp->NumberOfNames);printf("AddressOfFunctions; [0x%08x] \n", pExp->AddressOfFunctions);printf("AddressOfNames; [0x%08x] \n", pExp->AddressOfNames);printf("AddressOfNameOrdinals;[0x%08x] \n", pExp->AddressOfNameOrdinals);//导出函数名称表LPDWORD lpAddName = (LPDWORD)(pFileBuffer + RvaToFoa(pFileBuffer, pExp->AddressOfNames));for (size_t i = 0; i < pExp->NumberOfNames; i++){printf("%s \n", pFileBuffer + RvaToFoa(pFileBuffer, lpAddName[i]));}// 导出函数地址表LPDWORD lpAddfunction = (LPDWORD)(pFileBuffer + RvaToFoa(pFileBuffer, pExp->AddressOfFunctions));for (size_t i = 0; i < pExp->NumberOfFunctions; i++){printf("i :%d functionAddress[0x%p]\n",i, pFileBuffer + RvaToFoa(pFileBuffer,lpAddfunction[i]));}// 导出函数序号表LPWORD lpNameOrdinals = (LPWORD)(pFileBuffer + RvaToFoa(pFileBuffer, pExp->AddressOfNameOrdinals));for (size_t i = 0; i < pExp->NumberOfFunctions; i++){printf("i : %d NameOrdinals : %d\n", i, lpNameOrdinals[i]);}
}
RvaToFoa代码如下
DWORD RvaToFoa(PCHAR pBuffer, DWORD dwRva)
{if (pBuffer == NULL) return -1;PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuffer;PIMAGE_NT_HEADERS pNth = (PIMAGE_NT_HEADERS)(pBuffer + pDos->e_lfanew);PIMAGE_FILE_HEADER pFil = (PIMAGE_FILE_HEADER)((PCHAR)pNth + 4);PIMAGE_OPTIONAL_HEADER pOpt = (PIMAGE_OPTIONAL_HEADER)((PCHAR)pFil + IMAGE_SIZEOF_FILE_HEADER);PIMAGE_SECTION_HEADER pSec = (PIMAGE_SECTION_HEADER)((PCHAR)pOpt + pFil->SizeOfOptionalHeader);if (dwRva <= pOpt->SizeOfHeaders) return dwRva;for (size_t i = 0; i < pFil->NumberOfSections; i++){if (dwRva >= pSec[i].VirtualAddress && (dwRva <= (pSec[i].VirtualAddress + pSec[i].Misc.VirtualSize))){return dwRva - pSec[i].VirtualAddress + pSec[i].PointerToRawData;}}return -1;
}
根据名称获取函数地址
PCHAR GetProcAddressByName(PCHAR pFileBuffer, PCHAR pFunName)
{// 定位导出表PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pFileBuffer;PIMAGE_NT_HEADERS pNth = (PIMAGE_NT_HEADERS)(pFileBuffer + pDos->e_lfanew);if (pNth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == NULL){return NULL;}DWORD dwExportFoa = RvaToFoa(pFileBuffer,pNth->OptionalHeader.DataDirectory[0].VirtualAddress);PIMAGE_EXPORT_DIRECTORY pExp = (PIMAGE_EXPORT_DIRECTORY)(pFileBuffer + dwExportFoa);//定位三张表LPDWORD pAddFunc = (LPDWORD)(pFileBuffer + RvaToFoa(pFileBuffer, pExp->AddressOfFunctions));LPDWORD pAddName = (LPDWORD)(pFileBuffer + RvaToFoa(pFileBuffer, pExp->AddressOfNames));LPWORD pAddOrder = (LPDWORD)(pFileBuffer + RvaToFoa(pFileBuffer, pExp->AddressOfNameOrdinals));// 判断然后输出即可for (size_t i = 0; i < pExp->NumberOfNames; i++){if (!strcmp(pFunName, pFileBuffer + RvaToFoa(pFileBuffer, pAddName[i]))){return pAddFunc[pAddOrder[i]];}}return NULL;
}
根据输出序号获取地址(这里的序号是+base之后的数据哈)
PCHAR GetProcAddressByOrid(PCHAR pFIleBuffer, DWORD dwOrid)
{// 定位导出表PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pFIleBuffer;PIMAGE_NT_HEADERS pNth = (PIMAGE_NT_HEADERS)(pFIleBuffer + pDos->e_lfanew);// 判断导出表是否存在if (pNth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == NULL){return NULL;}DWORD dwOffset = RvaToFoa(pFIleBuffer, pNth->OptionalHeader.DataDirectory[0].VirtualAddress);PIMAGE_EXPORT_DIRECTORY pExp = (PIMAGE_EXPORT_DIRECTORY)(pFIleBuffer + dwOffset);// 定位序号表,函数地址表LPDWORD dwFunc = (LPDWORD)(pFIleBuffer + RvaToFoa(pFIleBuffer, pExp->AddressOfFunctions));LPWORD wOrid = (LPWORD)(pFIleBuffer + RvaToFoa(pFIleBuffer, pExp->AddressOfNameOrdinals));return dwFunc[dwOrid - pExp->Base];
}
导出表结束