1、如何定位导出表:
数据目录项的第一个结构,就是导出表.
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
VirtualAddress 导出表的RVA
Size 导出表大小
DWORD pExportTbOffset = RVA2Offset(pNtHeaders, pNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress); //注意这个VirtualAddress是VA
pExportTable = (PIMAGE_EXPORT_DIRECTORY)(pExportTbOffset+fileBuffer);
2、导出表结构
上面的结构,只是说明导出表在哪里,有多大,并不是真正的导出表.
如何在FileBuffer中找到这个结构呢?在VirtualAddress中存储的是RVA,如果想在FileBuffer中定位
必须要先将该RVA转换成FOA.
真正的导出表结构如下:
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;
DWORD* pdwFunctionAddress = (DWORD*)(RVA2Offset(pNtHeaders, (DWORD)pExportTable->AddressOfNames)+(DWORD)fileBuffer);
WORD* pwOrdinals = (WORD*)(RVA2Offset(pNtHeaders, (DWORD)pExportTable->AddressOfNameOrdinals)+(DWORD)fileBuffer);
DWORD* pdwNamesAddress = (DWORD*)((DWORD)fileBuffer + RVA2Offset(pNtHeaders, pExportTable->AddressOfNames));
int i = 0;
for(i;i<(int)pExportTable->NumberOfNames;i++)
{
DWORD dwFunctionAddress = pdwFunctionAddress[pwOrdinals[i]];
DWORD pdwFunNameOffset = (DWORD)fileBuffer + RVA2Offset(pNtHeaders, pdwNamesAddress[i]);
printf("导出函数序号: %d , 函数名: %s ,相对内存偏移: 0x%X
", pExportTable->Base + i, pdwFunNameOffset, dwFunctionAddress);
}
代码
#include <stdio.h>
#include <windows.h>
unsigned char* FileBuffer(const char* FileName);
void ImportTable();
unsigned char* RVAToFVA(unsigned char* fileBuffer,unsigned char* x);
DWORD RVA2Offset(PIMAGE_NT_HEADERS pNTHeader, DWORD dwRVA);
void main()
{
ImportTable();
}
void ImportTable()
{
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_NT_HEADERS pNtHeaders;
PIMAGE_EXPORT_DIRECTORY pExportTable;
unsigned char* fileBuffer = FileBuffer("OllyDBG.EXE");
pDosHeader = (PIMAGE_DOS_HEADER)fileBuffer;
pNtHeaders = (PIMAGE_NT_HEADERS)(fileBuffer+pDosHeader->e_lfanew);
printf("导出表的相对虚拟地址:%x
",pNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress);
printf("导出表的大小:%x
",pNtHeaders->OptionalHeader.DataDirectory[0].Size);
DWORD pExportTbOffset = RVA2Offset(pNtHeaders, pNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress); //注意这个VirtualAddress是VA
pExportTable = (PIMAGE_EXPORT_DIRECTORY)(pExportTbOffset+fileBuffer);
printf("函数地址:%x
",pExportTable->AddressOfFunctions);
printf("函数名序号地址:%x
",pExportTable->AddressOfNameOrdinals);
printf("函数名地址:%x
",pExportTable->AddressOfNames);
printf("函数序号基址:%x
",pExportTable->Base);
printf("特征值:%x
",pExportTable->Characteristics);
printf("函数名:%s
",RVA2Offset(pNtHeaders, pExportTable->Name)+fileBuffer); //指向导出表的文件字符串
printf("函数函数数量:%x
",pExportTable->NumberOfFunctions);
printf("函数名数量:%d
",pExportTable->NumberOfNames);
DWORD* pdwFunctionAddress = (DWORD*)(RVA2Offset(pNtHeaders, (DWORD)pExportTable->AddressOfNames)+(DWORD)fileBuffer);
WORD* pwOrdinals = (WORD*)(RVA2Offset(pNtHeaders, (DWORD)pExportTable->AddressOfNameOrdinals)+(DWORD)fileBuffer);
DWORD* pdwNamesAddress = (DWORD*)((DWORD)fileBuffer + RVA2Offset(pNtHeaders, pExportTable->AddressOfNames));
int i = 0;
for(i;i<(int)pExportTable->NumberOfNames;i++)
{
DWORD dwFunctionAddress = pdwFunctionAddress[pwOrdinals[i]];
DWORD pdwFunNameOffset = (DWORD)fileBuffer + RVA2Offset(pNtHeaders, pdwNamesAddress[i]);
printf("导出函数序号: %d , 函数名: %s ,相对内存偏移: 0x%X
", pExportTable->Base + i, pdwFunNameOffset, dwFunctionAddress);
}
}
//将PE文件读到FileBuffer
unsigned char* FileBuffer(const char* FileName)
{
unsigned char* Heap = NULL;
FILE* Stream;
//打开文件
Stream = fopen(FileName,"rb");
//计算文件大小
fseek(Stream,0,SEEK_END);
long FileSize = ftell(Stream);
fseek(Stream,0,SEEK_SET);
//分配堆空间
Heap = (unsigned char*)malloc(sizeof(char)*FileSize);
//将文件拷到堆
fread(Heap,sizeof(char),FileSize,Stream);
fclose(Stream);
return Heap;
}
DWORD RVA2Offset(PIMAGE_NT_HEADERS pNTHeader, DWORD dwRVA)
{
PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)((DWORD)pNTHeader + sizeof(IMAGE_NT_HEADERS));
for(int i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++)
{
if(dwRVA >= pSection[i].VirtualAddress && dwRVA < (pSection[i].VirtualAddress + pSection[i].SizeOfRawData))
{
return pSection[i].PointerToRawData + (dwRVA - pSection[i].VirtualAddress);
}
}
return 0;
}