当前位置: 首页 > news >正文

pe格式从入门到图形化显示(七)-导出表


文章目录

  • 前言
  • 一、什么是Windows PE格式中的导出表?
  • 二、解析导出表并显示
    • 1.导出表的结构
    • 2.解析导出表
    • 3.显示导出表


前言

通过分析和解析Windows PE格式,并使用qt进行图形化显示


一、什么是Windows PE格式中的导出表?

PE文件格式的导出表是PE文件中用于记录程序导出函数信息的数据结构。导出表位于数据目录表的第一项,索引值为0。导出表记录了当前文件对外开放的函数接口,使得其他程序可以通过这些接口调用该文件中的函数。

二、解析导出表并显示

1.导出表的结构

IMAGE_EXPORT_DIRECTORY结构体包含了导出表的特征、时间戳、版本号、导出函数数量、导出函数名称数量、导出函数地址表、导出函数名称表和导出函数序号表等信息。IMAGE_EXPORT_DIRECTORY的定义如下:

typedef struct _IMAGE_EXPORT_DIRECTORY {DWORD   Characteristics;DWORD   TimeDateStamp;WORD    MajorVersion;WORD    MinorVersion;DWORD   Name;DWORD   Base;DWORD   NumberOfFunctions;DWORD   NumberOfNames;DWORD   AddressOfFunctions;     // RVA from base of imageDWORD   AddressOfNames;         // RVA from base of imageDWORD   AddressOfNameOrdinals;  // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

IMAGE_EXPORT_DIRECTORY中的字段包括:
Characteristics:导出表的特征值,用于描述导出表的特性。
TimeDateStamp:时间戳,表示导出表创建或最后修改的时间。
MajorVersion和MinorVersion:导出表的主次版本号,用于标识导出表的版本信息。
Name:导出表的名称,通常为一个字符串,用于描述导出表的功能或用途。
Base:导出表中函数的起始序号,用于定位导出函数在文件中的位置。
NumberOfFunctions:导出表中导出的函数数量。
NumberOfNames:以名称导出的函数数量。
AddressOfFunctions:导出函数地址表在文件中的虚拟地址。
AddressOfNames:导出函数名称表在文件中的虚拟地址。
AddressOfNameOrdinals:导出函数序号表在文件中的虚拟地址。

2.解析导出表

bool PEParser::parserFileData(const QByteArray &fileData)
{//判断是否是MZ开头的文件if (fileData.left(2) != "MZ"){return false;}//解析DOS头parserDOSHeader(fileData.left(sizeof(IMAGE_DOS_HEADER)));//DOSStub数据m_dosStubData = fileData.mid(sizeof(IMAGE_DOS_HEADER), m_dosHeader.e_lfanew - sizeof(IMAGE_DOS_HEADER));long peAddress = m_dosHeader.e_lfanew;if (fileData.mid(peAddress, 2) != "PE"){return false;}m_fileData = fileData;//去除前4个字节的PE头标识long fileHeaderIndex = peAddress + 4;//记录文件头索引m_fileHeaderIndex = fileHeaderIndex;//解析标准PE文件头paserFileHeader(fileData.mid(fileHeaderIndex, sizeof(IMAGE_FILE_HEADER)));//解析扩展PE文件头long optionHeaderIndex = fileHeaderIndex + sizeof(IMAGE_FILE_HEADER);//记录扩展PE文件头索引m_optionHeaderIndex = optionHeaderIndex;//解析扩展PE文件头parserOptionHeader(fileData.mid(optionHeaderIndex, m_fileHeader.SizeOfOptionalHeader));//解析节表long sectionHeaderIndex = optionHeaderIndex + m_fileHeader.SizeOfOptionalHeader;//节表结构在文件中开始的偏移m_sectionHeaderIndex = sectionHeaderIndex;//解析节表parserSectionHeader(fileData.mid(sectionHeaderIndex,m_fileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)));//解析数据目录parserDataDirectory();//解析导出表parserExportTable();return true;
}void PEParser::parserExportTable()
{DWORD address = 0;if (m_x86Flag){address = m_optionalHeader32.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;}else{address = m_optionalHeader64.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;}if (address == 0){return;}//将虚拟地址转换为文件地址RVA2FOAInfo info = RVA2FOA(address);//获取导出表数据IMAGE_EXPORT_DIRECTORY exportTable;memcpy(&exportTable, m_fileData.data() + info.FOA, sizeof(IMAGE_EXPORT_DIRECTORY));QList<DWORD> functionAddressList;QList<WORD> functionOrdinalsList;//获取导出函数序号表数据info = RVA2FOA(exportTable.AddressOfNameOrdinals);QByteArray ordinalsTempData = m_fileData.mid(info.FOA, exportTable.NumberOfFunctions * sizeof(WORD));//获取导出函数地址表数据info = RVA2FOA(exportTable.AddressOfFunctions);QByteArray addrTempData = m_fileData.mid(info.FOA, exportTable.NumberOfFunctions * sizeof(DWORD));//遍历导出表中导出函数的数据for (int i = 0; i < exportTable.NumberOfFunctions; ++i){DWORD addr = 0;memcpy(&addr, addrTempData.data() + i * sizeof(DWORD), sizeof(DWORD));functionAddressList.append(addr);WORD ordinal = 0;memcpy(&ordinal, ordinalsTempData.data() + i * sizeof(WORD), sizeof(WORD));functionOrdinalsList.append(ordinal);}//获取导出函数名称表数据info = RVA2FOA(exportTable.AddressOfNames);QByteArray nameTempData = m_fileData.mid(info.FOA, exportTable.NumberOfFunctions * sizeof(DWORD));//遍历导出表中以名称导出的数据QList<ExportFunctionInfo> exportFunctionInfo;for (int i = 0; i < exportTable.NumberOfNames; ++i){DWORD nameRVA = 0;memcpy(&nameRVA, nameTempData.data() + i * sizeof(DWORD), sizeof(DWORD));DWORD nameFOA = RVA2FOA(nameRVA).FOA;int index = m_fileData.indexOf('\0', nameFOA);ExportFunctionInfo info;info.name = m_fileData.mid(nameFOA, index - nameFOA);info.address = functionAddressList[functionOrdinalsList[i]];info.ordinal = functionOrdinalsList[i];exportFunctionInfo.append(info);}//按序号排序std::sort(exportFunctionInfo.begin(), exportFunctionInfo.end(), [=](const ExportFunctionInfo &info1, const ExportFunctionInfo &info2) -> bool{return info1.ordinal < info2.ordinal;});emit sendExportTable(exportFunctionInfo);
}

3.显示导出表

void MainWindow::showExportTable(const QList<ExportFunctionInfo> &exportTable)
{ui->tableWidget_exportTable->clearContents();ui->tableWidget_exportTable->setRowCount(0);for (int i = 0; i < exportTable.size(); ++i){ui->tableWidget_exportTable->insertRow(i);ui->tableWidget_exportTable->setItem(i, 0, new QTableWidgetItem(exportTable[i].name));ui->tableWidget_exportTable->setItem(i, 1, new QTableWidgetItem(QString::asprintf("%08lX", exportTable[i].address)));ui->tableWidget_exportTable->setItem(i, 2, new QTableWidgetItem(QString::asprintf("%08lX", exportTable[i].ordinal)));}
}

http://www.lryc.cn/news/335185.html

相关文章:

  • 图片地址生成二维码(通过前端实现)
  • window安装maven和hadoop3.1.4
  • Redis系列之主从复制集群搭建
  • spring框架介绍
  • 如果在 Ubuntu 系统中两个设备出现两个相同的端口号解决方案
  • 随手分享的APP链接,可能会让你“大型社死”
  • 国内AI大模型已近80个,哪个最有前途?
  • 美团一面:说说synchronized的实现原理?问麻了。。。。
  • P1123 取数游戏(dfs算法)
  • 交叉验证(Cross-Validation)
  • 【kears】(01)keras使用介绍
  • 2. TypeScript 安装与环境配置指南
  • python pygame库的略学
  • 大模型日报2024-04-09
  • 抖音视频如何下载保存(方法分享)
  • MySQL-用户与权限管理:用户管理、权限管理、角色管理
  • Vue.js中如何使用Vue Router处理浏览器返回键的功能
  • QT drawPixmap和drawImage处理图片模糊问题
  • YOLOv9改进策略 :小目标 | 新颖的多尺度前馈网络(MSFN) | 2024年4月最新成果
  • 从零开始:一步步学习爬虫技术的实用指南(一)
  • Python面向对象详解
  • 思维题锻炼-最小数字
  • ubuntu20.04 运行 lio-sam 流程记录
  • P5356 [Ynoi2017] 由乃打扑克
  • 随机潮流应对不确定性?计及分布式发电的配电系统随机潮流计算程序代码!
  • Oracle表空间满清理方案汇总分享
  • 基于单片机数码管20V电压表仿真设计
  • SCI一区 | Matlab实现NGO-TCN-BiGRU-Attention北方苍鹰算法优化时间卷积双向门控循环单元融合注意力机制多变量时间序列预测
  • C++——优先级队列
  • docker部署jumpserver