您的位置:首页 > 编程语言 > C语言/C++

【C++源码】PE文件结构中导出表的解析

2016-08-31 19:39 411 查看
<pre name="code" class="cpp"><span style="font-size:18px;">#include<iostream>
#include<fstream>
#include<Windows.h>
#include<cstring>
#include"RVAToFOA.h"
using namespace std;
//函数声明
unsigned int GetFunctionAddressByName(char *functionName);
long GetFileSize(char *fileName);
unsigned int GetFunctionAddressByOrdinals(int n);
void PrintExportTable();

char* buffer;
long fileSize = GetFileSize("D:\\Notepad++\\plugins\\mimeTools.dll");

//获取各结构的地址
IMAGE_DOS_HEADER* pDOSHeader = (IMAGE_DOS_HEADER*)(buffer);
IMAGE_NT_HEADERS* pNTHeaders = (IMAGE_NT_HEADERS*)(&buffer[0] + pDOSHeader->e_lfanew);
IMAGE_FILE_HEADER* pFileHeader = (IMAGE_FILE_HEADER*)((int)(pNTHeaders)+4);
IMAGE_OPTIONAL_HEADER* pOptionalHeader = (IMAGE_OPTIONAL_HEADER*)((int)(pFileHeader)+sizeof(IMAGE_FILE_HEADER));
IMAGE_SECTION_HEADER* pSectionHeader[10];
IMAGE_EXPORT_DIRECTORY* pExportTable = (IMAGE_EXPORT_DIRECTORY*)
(&buffer[0] + RVAToFOA(buffer, pOptionalHeader->DataDirectory[0].VirtualAddress));

//导出函数名称表
unsigned char* addressOfNames[1000];
unsigned char** pAddressOfNames;//定义unsigned char** pAddressOfNames,利用pAddressOfNames来存贮导入函数名称表的地址

//导出函数地址表
unsigned int* addressOfFunctions[1000];
unsigned int** pAddressOfFunctions;//学会用二级指针

//导出函数序号表
unsigned short nameOrdinals[1000];
unsigned short* pNameOrdinals;

int main()
{
//先获取第一个节区头的地址
pSectionHeader[0] = (IMAGE_SECTION_HEADER*)((unsigned int)(pOptionalHeader)+sizeof(IMAGE_OPTIONAL_HEADER));
for (int i = 0;i < pFileHeader->NumberOfSections - 1;i++)
pSectionHeader[i + 1] = (IMAGE_SECTION_HEADER*)((unsigned int)(pSectionHeader[i]) + sizeof(IMAGE_SECTION_HEADER));

//给导出函数地址表赋值
for (int i = 0;i < pExportTable->NumberOfFunctions;i++)
{
pAddressOfFunctions = (unsigned int**)(buffer + RVAToFOA(buffer, pExportTable->AddressOfFunctions));
addressOfFunctions[i] = *(pAddressOfFunctions + i);
}

//给导出函数名称表赋值
for (int i = 0;i < pExportTable->NumberOfNames;i++)
{
pAddressOfNames = (unsigned char**)(buffer + RVAToFOA(buffer, pExportTable->AddressOfNames));
addressOfNames[i] = *(pAddressOfNames+i);
}

//给导出函数序号表赋值
for (int i = 0;i < pExportTable->NumberOfNames;i++)
{
pNameOrdinals = (unsigned short*)(buffer + RVAToFOA(buffer, pExportTable->AddressOfNameOrdinals));
nameOrdinals[i] = *(pNameOrdinals + i);
}

PrintExportTable();
}

unsigned int GetFunctionAddressByName(char *functionName)
{
int i;
for (i = 0;i < pExportTable->NumberOfNames;i++)//两字符串相等返回0
if (strcmp(functionName, (const char*)(buffer + RVAToFOA(buffer, (unsigned int)addressOfNames[i])))==0)
return (unsigned int)addressOfFunctions[nameOrdinals[i]]+pOptionalHeader->ImageBase;

if (i == pExportTable->NumberOfNames)
{
cout << "找不到此函数" << endl;
return 0;
}
}

unsigned int GetFunctionAddressByOrdinals(int n)
{
if(n<= pExportTable->Base+ pExportTable->NumberOfFunctions)
return (unsigned int)addressOfFunctions[n-pExportTable->Base] + pOptionalHeader->ImageBase;
else
{
cout << "无此函数" << endl;
return 0;
}
}

//获取文件大小
long GetFileSize(char *fileName)
{
filebuf *pbuf;
ifstream fileStr;
long size;
//采用二进制模式打开
fileStr.open(fileName, ios::binary);

//获取fileStr对应buffer对象的指针
pbuf = fileStr.rdbuf();

// 调用buffer对象方法获取文件大小
size = pbuf->pubseekoff(0, ios::end, ios::in);
pbuf->pubseekpos(0, ios::in);
// 分配内存空间
buffer = new char[size];
// 获取文件内容
pbuf->sgetn(buffer, size);
fileStr.close();

return size;
}

//打印导出表
void PrintExportTable()
{
cout << "Name:" << (char*)(buffer + RVAToFOA(buffer, pExportTable->Name)) << endl;
cout << "Base:" << hex << pExportTable->Base << endl;
cout << "NumberOfFunctions:" << hex << pExportTable->NumberOfFunctions << "<所有导出的函数的个数>" << endl;
cout << "NumberOfFunctions:" << hex << pExportTable->NumberOfFunctions << "<所有导出的函数的个数>" << endl;
cout << "NumberOfFunctions:" << hex << pExportTable->NumberOfNames << "<以函数名导出的函数的个数>" << endl;
cout << "AddressOfFunctions:" << hex << pExportTable->AddressOfFunctions << "<导出函数地址表偏移>" << endl;
cout << "AddressOfNameOrdinals:" << hex << pExportTable->AddressOfNameOrdinals << "<导出函数序号表偏移>" << endl;

cout << "****函数地址表****" << endl;
for (int i = 0;i < pExportTable->NumberOfFunctions;i++)
cout << "函数地址:" << hex << (unsigned int)(pAddressOfFunctions[i]) << endl;

cout << "****函数名称表****" << endl;
for (int i = 0;i < pExportTable->NumberOfNames;i++)
cout << "函数--" << hex << (unsigned int)(addressOfNames[i]) << endl
<< "函数名称:" << (char*)(buffer+RVAToFOA(buffer,(unsigned int)(addressOfNames[i]))) << endl;

cout << "****函数序号表****" << endl;
for (int i = 0;i < pExportTable->NumberOfNames;i++)
cout << "函数序号:" << hex << nameOrdinals[i] << endl;</span>
}




RVAToFOA.cpp的内容

<span style="font-size:18px;"><span style="font-size:18px;">#include<Windows.h>
#include"RVAToFOA.h"
unsigned int RVAToFOA(char* buffer, unsigned int address)
{
IMAGE_DOS_HEADER* pDOSHeader = (IMAGE_DOS_HEADER*)(buffer);
IMAGE_NT_HEADERS* pNTHeaders = (IMAGE_NT_HEADERS*)(&buffer[0] + pDOSHeader->e_lfanew);
IMAGE_FILE_HEADER* pFileHeader = (IMAGE_FILE_HEADER*)((int)(pNTHeaders)+4);
IMAGE_OPTIONAL_HEADER* pOptionalHeader = (IMAGE_OPTIONAL_HEADER*)((int)(pFileHeader)+sizeof(IMAGE_FILE_HEADER));
IMAGE_SECTION_HEADER* pSectionHeader[10];

pSectionHeader[0] = (IMAGE_SECTION_HEADER*)((int)(pOptionalHeader)+sizeof(IMAGE_OPTIONAL_HEADER));
for (int i = 0;i < pFileHeader->NumberOfSections - 1;i++)
{
pSectionHeader[i + 1] = (IMAGE_SECTION_HEADER*)((int)(pSectionHeader[i]) + sizeof(IMAGE_SECTION_HEADER));
}

//if(address<pSectionHeader[0]->VirtualAddress) return
for (int i = 0;i < pFileHeader->NumberOfSections - 1;i++)
{
if (address >= pSectionHeader[i]->VirtualAddress&&address <= pSectionHeader[i + 1]->VirtualAddress)
return address - pSectionHeader[i]->VirtualAddress + pSectionHeader[i]->PointerToRawData;
}
}</span></span>


以任意dll文件为例



解析结果与DIE分析出的相同



过程中主要学会的指针的灵活运用,其他表的解析后续学习中再贴上,欢迎私信交流,指导不足
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: