C++ 获取 PE 文件导出表
2023-09-11 14:14:01 时间
// 内存偏移转文件偏移
int rva_to_raw(PIMAGE_SECTION_HEADER pSection,int nSectionNum,int nRva)
{
int nRet = 0;
// 遍历节区
for (int i=0;i<nSectionNum;i++){
// 导出表地址在这个节区内
if (pSection[i].VirtualAddress <= nRva && nRva < pSection[i+1].VirtualAddress){
// 文件偏移 = 该段的 PointerToRawData + (内存偏移 - 该段起始的RVA(VirtualAddress))
nRet = nRva - pSection[i].VirtualAddress + pSection[i].PointerToRawData;
break;
}
}
return nRet;
}
void printExpTable(const string& strFilePath)
{
// 二进制方式读文件
fstream cFile(strFilePath, ios::binary | ios::in);
if (!cFile){cout << "打开文件失败" << endl; return;}
// 读 dos 头
IMAGE_DOS_HEADER dosHeader;
cFile.read((char*)&dosHeader,sizeof(IMAGE_DOS_HEADER));
// 读 nt 头(64位)
IMAGE_NT_HEADERS64 ntHeader;
cFile.seekg(dosHeader.e_lfanew, ios::beg);
cFile.read((char*)&ntHeader, sizeof(IMAGE_NT_HEADERS64));
if (!ntHeader.OptionalHeader.DataDirectory[0].VirtualAddress){
cout << "文件没有导出函数" << endl;
cFile.close(); return;
}
// 读节区头
int nSectionNum = ntHeader.FileHeader.NumberOfSections;
shared_ptr<IMAGE_SECTION_HEADER> pShareSection(new IMAGE_SECTION_HEADER[nSectionNum]);
PIMAGE_SECTION_HEADER pSection = pShareSection.get();
cFile.read((char*)pSection, sizeof(IMAGE_SECTION_HEADER)*nSectionNum);
// 计算导出表 RAW
IMAGE_EXPORT_DIRECTORY expDir;
int nExportOffset = rva_to_raw(pSection,nSectionNum,ntHeader.OptionalHeader.DataDirectory[0].VirtualAddress);
if (!nExportOffset){
cout << "RAW 获取失败" << endl;
cFile.close(); return;
}
// 读导出表
cFile.seekg(nExportOffset, ios::beg);
cFile.read((char*)&expDir, sizeof(IMAGE_EXPORT_DIRECTORY));
// 读导出表头
cFile.seekg(rva_to_raw(pSection, nSectionNum, expDir.Name), ios::beg);
char szExportName[50];
cFile.get(szExportName,50);
cout << "IMAGE_EXPORT_DIRECTORY.Name = " << szExportName << endl;
// 获取到处函数个数
int nAddressNum = expDir.NumberOfFunctions;
// 获取导出表函数名
shared_ptr<int> pShareName(new int[nAddressNum]);
int* pName = pShareName.get();
cFile.seekg(rva_to_raw(pSection, nSectionNum, expDir.AddressOfNames), ios::beg);
cFile.read((char*)pName, sizeof(int)*nAddressNum);
// 获取导出表函数序号
shared_ptr<short> pShareOrder(new short[nAddressNum]);
short* pOrder = pShareOrder.get();
cFile.seekg(rva_to_raw(pSection, nSectionNum, expDir.AddressOfNameOrdinals), ios::beg);
cFile.read((char*)pOrder, sizeof(short)*nAddressNum);
// 获取导出表函数地址
shared_ptr<int> pShareFunc(new int[nAddressNum]);
int* pFunc = pShareFunc.get();
cFile.seekg(rva_to_raw(pSection, nSectionNum, expDir.AddressOfFunctions), ios::beg);
cFile.read((char*)pFunc, sizeof(int)*nAddressNum);
// 遍历导出表
char szFuncName[50];
for (int i=0;i<nAddressNum;i++){
cFile.seekg(rva_to_raw(pSection, nSectionNum, pName[i]), ios::beg);
cFile.get(szFuncName, 50);
cout << "[Index:" << dec << i << "]\t"
<< "[ID:" << hex << pOrder[i] << "]\t"
<< "[RVA:" << pFunc[i] << "]\t"
<< "[Name:" << szFuncName << "]\t"
<< endl;
}
cFile.close();
}
效果图:
相关文章
- C++问题-无法打开包括文件:“GLES2/gl2.h”
- C++ stringstream与getline()
- c++读取文件到vector
- 机器学习笔记 - 在QT/PyTorch/C++ 中加载 TORCHSCRIPT 模型
- 【转】C++调用Matlab的.m文件
- C++设计模式:装饰器模式
- 从C、C++、Java到Python,编程入门到底学什么语言好?
- [h5棋牌项目]-17-C++读取json文件
- c++冒泡排序
- 【华为OD机试 2023最新 】 查找重复代码(C++ 100%)
- 【 华为OD机试 2023】 最大连续文件之和 / 区块链文件转储系统(C++ Java JavaScript Python)
- 在Qt程序中使用C++11线程std::thread处理耗时操作
- C++ 中的文件 IO 流
- C++ 读取文件所有内容的方法
- VC++ 从 CString类型的文件路径中获取文件名和扩展名
- C++/Qt:TXT文件读写
- ChatGPT上线了!我在2023年1月2日这一天用上了它!请使用c++写一个bert模型结构?
- C++打开的文件一定要用close()方法关闭
- VC++一文带你搞懂如何操作文件对话框(附源码)
- VC++调用PostThreadMessage给线程发消息,实现线程间的通信(附源码)
- PAT 1142 C++版
- C/C++编程日常踩到的那些坑。。。
- C++输入输出问题
- C++使用技巧(八):输入输出读写文件
- C++软件开发值得推荐的十大高效软件分析工具
- C/C++编程中容易犯的10种初级编程错误