Concept of Export Table
The export table describes which functions the current PE file provides. The PE file is like a restaurant, and the menu is the export table. The export table is generally used in DLL files, but EXE files can also have export tables, as they are both PE files and can have export tables. The functions exported by DLL are recorded in the export table, in the first item of the data directory, with an index of 0.
1. How to locate the export table:
The first structure in the data directory is the export table.

typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
VirtualAddress Export Table RVA Size Export Table Size (the Size field may not be the actual size)
2. Export Table Structure
This structure merely indicates where the export table is located and its size, but it is not the actual export table. How to find this structure in FileBuffer? The RVA is stored in VirtualAddress. If you want to locate in FileBuffer, you must first convert the RVA to FOA.The actual export table structure is as follows:
NAME: Pointer (Rva), pointing to the export table file name string. xx.dll
AddressOfFunctions description:
This address stores the entry addresses of all exported functions of dll or EXE.
The element width of this table is 4 bytes. This table stores the addresses of all exported functions. The number of this table is determined by NumberOfFunctions. The value in this table item is RVA, which needs to be added to ImageBase to get the actual address of the function. Location: The RVA stored in IMAGE_EXPORT_DIRECTORY->AddressOfFunctions is the RVA of this table and needs to be converted to FOA first.
AddressOfNames description:
This address stores the addresses of all exported function names of dll or EXE.
The element width of this table is 4 bytes. This table stores the RVAs of all exported functions with names. The value in this table item is RVA, pointing to the actual name of the function.
AddressOfNameOrdinals
This address stores the sequence numbers of all exported functions of dll or EXE.
Summary:
Why are they divided into 3 tables? 1. The number of function exports may not be the same as the number of function names. Therefore, the function address table and function name table should be separated. 2. Is the function address table always greater than the function name table? Not necessarily, a single function address may have multiple different names. 3. How to obtain the address of a function based on the function name?
4. How to obtain the address of a function based on the export sequence number of the function?
To further consolidate, let's take another real example and go through it according to the above rules.
.dll export functions are exported from the following def file, with visible sequence numbers 2, 3, 5, 6.
EXPORTS
Plus @2
Sub @5 NONAME
Mul @3
Div @6
Practice:
1. Write a program to print all export table information.
VOID PutExportTable();
{
PVOID pFileBuffer;
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
PIMAGE_EXPORT_DIRECTORY pExportTable = NULL;
DWORD AddressOfNameFOA = NULL;
DWORD AddressOfNameOrdinalsFOA = NULL;
DWORD AddressOfFunctions = NULL;
WORD Ordinal = NULL;
BOOL isOk = FALSE;
DWORD size = 0;
ReadPEFile(file_path, &pFileBuffer);
if (!pFileBuffer)
{
printf("Read file failed");
return;
{}
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew) + 4);
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)(((DWORD)pFileBuffer + pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)(((DWORD)pFileBuffer + pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER + pPEHeader->SizeOfOptionalHeader);
pExportTable = (PIMAGE_EXPORT_DIRECTORY)((DWORD)pFileBuffer+ RvaToOffset(pOptionHeader->DataDirectory[0].VirtualAddress ,pFileBuffer));
printf("DIRECTORY_ENTRY_EXPORT ViltualAddress:%X\n", pOptionHeader->DataDirectory[0].VirtualAddress);
printf("Characteristics: %#x\n", pExportTable->Characteristics)
printf("TimeDateStamp: %#x\n", pExportTable->TimeDateStamp);
printf("MajorVersion: %#x\n", pExportTable->MajorVersion);
printf("MinorVersion: %#x\n", pExportTable->MinorVersion);
printf("Name: %s\n", (PVOID)((DWORD)pFileBuffer + RvaToOffset(pExportTable->Name, pFileBuffer)));//(PVOID)((DWORD)pFileBuffer + RvaToOffset(pExportTable->Name,pFileBuffer))
printf("Base: %#x\n", pExportTable->Base);
printf("NumberOfFunctions: %#x\n", pExportTable->NumberOfFunctions);
printf("NumberOfNames: %#x\n", pExportTable->NumberOfNames);
printf("AddressOfFunctions: %#x\n", pExportTable->AddressOfFunctions);
printf("AddressOfNames: %#x\n", pExportTable->AddressOfNames);
printf("AddressOfNameOrdinals: %#x\n", pExportTable->AddressOfNameOrdinals);//52590
{}
2. Write the function GetFunctionAddrByName (FileBuffer pointer, function name pointer)
DWORD GetFunctionAddressByName(LPVOID pFileBuffer, LPCSTR Name)
{
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
PIMAGE_NT_HEADERS32 pNtHeader = (PIMAGE_NT_HEADERS32)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pFileBuffer + pDosHeader->e_lfanew + 4);
PIMAGE_OPTIONAL_HEADER pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileBuffer + pDosHeader->e_lfanew + 4 + IMAGE_SIZEOF_FILE_HEADER);
PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pFileBuffer + pDosHeader->e_lfanew + 4 + IMAGE_SIZEOF_FILE_HEADER + pFileHeader->SizeOfOptionalHeader);
PIMAGE_DATA_DIRECTORY pDirectory = (PIMAGE_DATA_DIRECTORY)pOptionalHeader->DataDirectory;
PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((DWORD)pFileBuffer + Rva_To_FOA(pFileBuffer, pDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress));
if (!pExportTable)
{
printf("No export table");
free(pFileBuffer);
return 0;
{}
//Convert Rva value to Foa
PDWORD AddressOfNames = (PDWORD)((DWORD)pFileBuffer + Rva_To_FOA(pFileBuffer, pExportTable->AddressOfNames));
PDWORD AddressOfFunctions = (PDWORD)((DWORD)pFileBuffer + Rva_To_FOA(pFileBuffer, pExportTable->AddressOfFunctions));
PWORD AddressOfNameOrdinals = (PWORD)((DWORD)pFileBuffer + Rva_To_FOA(pFileBuffer, pExportTable->AddressOfNameOrdinals));
for (int i = 0; i < pExportTable->NumberOfNames; i++)
{
if (!strcmp((LPCSTR)((DWORD)pFileBuffer + Rva_To_FOA(pFileBuffer, AddressOfNames[i])), Name))
{
return AddressOfFunctions[AddressOfNameOrdinals[i]];
{}
{}
return 0;
{}
3. Write the function GetFunctionAddrByOrdinals (FileBuffer pointer, function export ordinal number)
DWORD GetFunctionAddressByOrdinals(LPVOID pFileBuffer, DWORD Ordinals)
{
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
PIMAGE_NT_HEADERS32 pNtHeader = (PIMAGE_NT_HEADERS32)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pFileBuffer + pDosHeader->e_lfanew + 4);
PIMAGE_OPTIONAL_HEADER pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileBuffer + pDosHeader->e_lfanew + 4 + IMAGE_SIZEOF_FILE_HEADER);
PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pFileBuffer + pDosHeader->e_lfanew + 4 + IMAGE_SIZEOF_FILE_HEADER + pFileHeader->SizeOfOptionalHeader);
PIMAGE_DATA_DIRECTORY pDirectory = (PIMAGE_DATA_DIRECTORY)pOptionalHeader->DataDirectory;
PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((DWORD)pFileBuffer + Rva_To_FOA(pFileBuffer, pDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress));
if (!pExportTable)
{
printf("No export table");
free(pFileBuffer);
return 0;
{}
//Convert Rva value to Foa
PDWORD AddressOfNames = (PDWORD)((DWORD)pFileBuffer + Rva_To_FOA(pFileBuffer, pExportTable->AddressOfNames));
PDWORD AddressOfFunctions = (PDWORD)((DWORD)pFileBuffer + Rva_To_FOA(pFileBuffer, pExportTable->AddressOfFunctions));
PWORD AddressOfNameOrdinals = (PWORD)((DWORD)pFileBuffer + Rva_To_FOA(pFileBuffer, pExportTable->AddressOfNameOrdinals));
return AddressOfFunctions[Ordinals-pExportTable->Base];
{}

评论已关闭