appsion 发表于 2020-11-1 09:45

PE 文件解析3-数据目录[导出表]

本帖最后由 appsion 于 2020-11-1 11:28 编辑

PE 文件解析3-数据目录[导出表]
新手学习PE文件解析记录,持续更新. 部分参考来源于网络, 无法逐一标注, 如果侵权,请及时联系. 如有错误请指正,误喷.


上文链接: https://www.52pojie.cn/thread-1294381-1-1.html



结构体: IMAGE_EXPORT_DIRECTORY说明: 导出表信息头文件: winnt.h帮助文档: 仅存在于头文件, 没有帮助文档

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 image

    DWORD   AddressOfNames;                              // RVA from base of image

    DWORD   AddressOfNameOrdinals;                         // RVA from base of image

} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY

参数说明: 仅供参考, 详细说明请参考原文.
      Characteristics
                描述
      TimeDateStamp
                创建时间
      MajorVersion
                主版本号
      MinorVersion
                次版本号
      Name
                DLL库文件名的RVA.
      Base
                导出函数的起始序号.
      NumberOfFunctions
                导出函数的函数总数量.
      NumberOfNames
                按名称导出的函数数量
      AddressOfFunctions
                指向输出函数地址的RVA
      AddressOfNames
                指向输出函数名称的RVA
      AddressOfNameOrdinals
                指向输出函数序号的RVA


3.1 获取导出表信息

// 参数说明
//    DataBuff:文件指针
//    ExportRVA:导出表的RVA
void ExportDllInfo(char *DataBuff, DWORD ExportRVA)
{
      // 获取节表
      int SectionCount = 0;
      IMAGE_SECTION_HEADER *SectionHead = GetSectionHead(DataBuff, SectionCount);

      // 获取导出表FOA
      DWORD ExportFOA = RVAToRaw(SectionHead, SectionCount, ExportRVA);

      // 获取导出表
      IMAGE_EXPORT_DIRECTORY *Export = (IMAGE_EXPORT_DIRECTORY*)(DataBuff + ExportFOA);

      // 导出表名称RVA
      DWORD DllName_RVA = Export->Name;

      // 导出表名称FOA
      DWORD DllName_FOA = RVAToRaw(SectionHead, SectionCount, DllName_RVA);

      // 导出表名称
      char *DllName = (char *)(DataBuff + DllName_FOA);

      // 导出表创建时间
      // Export->TimeDateStamp

      // 导出表主版本
      // Export->MajorVersion
      
      // 导出表次版本
      // Export->MinorVersion

      // 导出函数起始序号
      // Export->Base

      // 导出函数总数量
      // Export->NumberOfFunctions

      // 按名称导出的函数数量
      // Export->NumberOfNames

      // 导出函数地址FOA
      DWORD ExportFunction_FOA = RVAToRaw(SectionHead, SectionCount, Export->AddressOfFunctions);

      // 导出函数名称FOA
      DWORD ExportName_FOA = RVAToRaw(SectionHead, SectionCount, Export->AddressOfNames);

      // 函数序号FOA
      DWORD ExportOrdinal_FOA = RVAToRaw(SectionHead, SectionCount, Export->AddressOfNameOrdinals);
}



3.2 获取导出函数信息, 方式有二种, 按名称导出, 按序号导出.
1. 按名称导出

for (size_t i = 0; i < Export->NumberOfNames; i++)
{
      // 名称RVA
      DWORD Name_RVA = ((DWORD*)(DataBuff + ExportName_FOA));

      // 序号
      WORD Ordinal = ((WORD*)(DataBuff + ExportOrdinal_FOA));
}


2. 按序号导出


// 获取导出函数名称RVA与序号
std::map<WORD, DWORD> NameOrdinal;
std::map<WORD, DWORD>::iterator Find_NameOrdinal;
for (size_t i = 0; i < Export->NumberOfNames; i++)
{
      WORD Ordinal = ((WORD*)(DataBuff + ExportOrdinal_FOA));
      DWORD Name_RVA = ((DWORD*)(DataBuff + ExportName_FOA));
      NameOrdinal.insert(std::pair<WORD, DWORD>(Ordinal, Name_RVA));
}

// 实际导出数量, 注: 部分 FunctionRVA 为0;
int RealFunctionCount = 0;
for (size_t i = 0; i < Export->NumberOfFunctions; i++)
{
      // FunctionRVA
      DWORD FunctionRVA = ((DWORD*)(DataBuff + ExportFunction_FOA));
      if (!FunctionRVA) continue;

      // FunctionID
      // 注:
                //1. Export->Base 为导出函数的起始序号
                //2. 函数序号不是按递增方式排列
      WORD Ordinal = Export->Base + i;

      Find_NameOrdinal = NameOrdinal.find(i);
      if (Find_NameOrdinal != NameOrdinal.end())
      {
                // 导出函数名称RVA
                DWORD Name_RVA = Find_NameOrdinal->second;

                // 导出函数名称FOA
                DWORD Name_FOA = RVAToRaw(SectionHead, SectionCount, Find_NameOrdinal->second);

                // 导出函数名称
                char *Name = DataBuff + Name_FOA;
      }
      RealFunctionCount++;
}


RVA 转 FOA

DWORD RVAToRaw(IMAGE_SECTION_HEADER *SectionHead, int SECTIONCount, DWORD m_RVA)
{
      // 遍历节表
      for (size_t i = 0; i < SECTIONCount; i++)
      {
                IMAGE_SECTION_HEADER section = ((IMAGE_SECTION_HEADER*)SectionHead);

                // 判断 RVA 所在的节表
                if (m_RVA >= section.VirtualAddress && m_RVA <= (section.VirtualAddress + section.SizeOfRawData))
                {
                        // 获取偏移差
                        m_RVA = m_RVA - section.VirtualAddress;
                        m_RVA = m_RVA + section.PointerToRawData;
                        return m_RVA;
                }
      }
      return 0;
}


霏映 发表于 2020-11-1 11:08

不错,下来试试

954464133 发表于 2020-11-2 10:39

不错嘛试试先

lvcaolhx 发表于 2020-11-2 10:59

内容太专业,我等小白看不懂。

wobzhidao 发表于 2020-11-3 08:19

这个软件确实不错的啊

雪痕 发表于 2020-11-3 12:54

学习学习{:1_893:}

rbj520 发表于 2020-11-3 20:14

謝謝樓主分享{:1_921:}

碎步流年 发表于 2020-11-5 13:52

看着不错,试试

miaoj29 发表于 2020-11-10 15:47

谢谢分享,,,,辛苦辛苦

tsecond 发表于 2020-11-13 09:12

看着熟悉的C代码就是舒服!
页: [1] 2
查看完整版本: PE 文件解析3-数据目录[导出表]