逆向笔记——PE输出导出表

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\n", 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\n",pNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress);
	printf("导出表的大小:%x\n",pNtHeaders->OptionalHeader.DataDirectory[0].Size);

	DWORD pExportTbOffset = RVA2Offset(pNtHeaders, pNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress); //注意这个VirtualAddress是VA
	pExportTable = (PIMAGE_EXPORT_DIRECTORY)(pExportTbOffset+fileBuffer);
	printf("函数地址:%x\n",pExportTable->AddressOfFunctions);
	printf("函数名序号地址:%x\n",pExportTable->AddressOfNameOrdinals);
	printf("函数名地址:%x\n",pExportTable->AddressOfNames);
	printf("函数序号基址:%x\n",pExportTable->Base);
	printf("特征值:%x\n",pExportTable->Characteristics);
	printf("函数名:%s\n",RVA2Offset(pNtHeaders, pExportTable->Name)+fileBuffer); //指向导出表的文件字符串
	printf("函数函数数量:%x\n",pExportTable->NumberOfFunctions);
	printf("函数名数量:%d\n",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\n", 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;
}

posted @ 2020-03-30 22:33  程序媛墨禾  阅读(512)  评论(0)    收藏  举报