





PE之代码解析导出表
1)导出表
导出表(ExportTable)是PE文件中描述导出函数的核心数据结构,位于.edata节区,用于定义DLL对外暴露的函数名称,序号及地址映射。其根结构为IMAGE_EXPORT_DIRECTORY,包含导出函数总数,名称表地址,地址表地址等关键信息,是系统加载DLL时解析导出符号的依据,决定了外部程序能否正确调用DLL中的函数。
需注意导出表的特殊场景,咱们来看下逆向破解中的典型场景:
导出函数隐藏/伪造:恶意软件常通过修改导出表隐藏真实函数,或伪造导出函数名称误导逆向分析者;
导出表修复:破解加壳程序时,需重建被破坏的导出表以恢复DLL的正常调用;
导出函数挂钩(Hook):通过修改导出表中的函数地址,实现对目标函数的拦截与篡改;
无导出表DLL分析:部分恶意DLL故意删除导出表,需通过动态调试或静态分析定位函数入口。
2)解析导出表
解析导出表需先定位IMAGE_EXPORT_DIRECTORY:通过PE头中的DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]获取其RVA,再转换为文件偏移。接着读取导出函数总数,遍历地址表(AddressOfFunctions)获取函数RVA,通过名称表(AddressOfNames)和序号表(AddressOfNameOrdinals)建立“名称-序号-地址映射,最终整理出所有导出函数的完整信息。
3)程序开发流程
前期基本流程和导入表基本大差不差哦,首先把要分析的EXE或DLL文件以二进制方式打开,将文件里所有内容读到内存里的一个临时区域(咱们叫它buf),接着把这个buf转换成能识别PE文件开头DOS头的格式,找到DOS头里的e_lfanew这个关键值,用它加上buf的起始位置定位到PE文件的核心NT头,再从NT头里的OptionalHeader.DataDirectory中找到对应导出表的索引(IMAGE_DIRECTORY_ENTRY_EXPORT),拿到导出表的地址;拿到导出表的地址(RVA)和大小后先做检查,若地址或大小为0则说明文件没有导出表,直接提示并返回,若导出表存在就用之前写的RVAToOffset函数把导出表的RVA转换成它在buf里的实际偏移量,找到真正的导出表结构体(IMAGE_EXPORT_DIRECTORY),之后打印导出表的基本信息,比如模块名称(Name),特性标志(Characteristics),时间戳(TimeDateStamp)等,重点关注Base(导出函数的起始序数),NumberOfFunctions(总共导出的函数数量),NumberOfNames(有名字的导出函数数量),AddressOfFunctions(EAT,存每个导出函数RVA的数组地址),AddressOfNames(ENT,存每个具名导出函数名称RVA的数组地址),AddressOfNameOrdinals(存与ENT中每个名称对应序号索引的数组地址)这些关键信息,再用同样方法把EAT,ENT和AddressOfNameOrdinals三个数组的RVA转换成buf里的偏移量以便直接访问,最后进入核心解析和打印环节,先循环遍历EAT数组(因其数量NumberOfFunctions代表所有导出函数总数),对每个条目获取函数RVA,计算实际序数(索引+Base),若RVA为0则标注(UnusedEntry),对于每个有效函数RVA,循环遍历AddressOfNameOrdinals数组,其每个值代表对应EAT数组位置的序号索引,将该索引与当前遍历的EAT索引比较,找到匹配项则说明EAT当前位置的函数有名字,用AddressOfNameOrdinals数组当前索引去ENT数组找到对应名称RVA,再转换成buf里的偏移量取出函数名字,若遍历完AddressOfNameOrdinals数组都无匹配项则标注为(Ordinal-onlyExport),最后把每个函数的序数,RVA和找到的名字打印出来,整个导出表的分析就完成啦哈哈哈。
4)代码示例
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
DWORD RvaToOffset(DWORD dwRva, char* buf)
{
// Validate input parameters (null buffer check)
if (buf == NULL)
{
return 0; // Return 0 as error indicator (RVA 0 is rarely valid in PE files)
}
// Cast buffer to DOS header (first structure in PE file)
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)buf;
// Validate DOS header signature (0x5A4D = "MZ")
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
{
return 0; // N

最低0.47元/天 解锁文章
495

被折叠的 条评论
为什么被折叠?



