逆向笔记——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  程序媛墨禾  阅读(453)  评论(0编辑  收藏  举报