TImor 发表于 2018-8-22 20:29

PE结构中导出表分析

本帖最后由 TImor 于 2018-8-22 20:31 编辑

说好的导出表晚了一点更新

导出表结构分析:


typedef struct _IMAGE_EXPORT_DIRECTORY {                  
    DWORD   Characteristics;             // 未使用   
    DWORD   TimeDateStamp;               // 时间戳   
    WORD    MajorVersion;               // 未使用   
    WORD    MinorVersion;               // 未使用   
    DWORD   Name;                // 指向该导出表文件名字符串      
    DWORD   Base;                // 导出函数起始序号      
    DWORD   NumberOfFunctions;               // 所有导出函数的个数      
    DWORD   NumberOfNames;               // 以函数名字导出的函数个数      
    DWORD   AddressOfFunctions;   // 导出函数地址表RVA                     
    DWORD   AddressOfNames;         // 导出函数名称表RVA                     
    DWORD   AddressOfNameOrdinals;// 导出函数序号表RVA                  
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;         

有用的就后边的这几个,本文解析的只是后三个,由于是RVA需要先转换为FOA;
原理:1、先判断属于哪个节通过数据目录项的virtualaddress跟每个节的Virtualaddress+misc.virtualsize判断

         2、判断属于哪个节了以后减去该节的VirtuallAddress
         3、将减完成的差值加上PointerToRawData就是相对于文件的偏移,也就是物理地址;
先贴上自写的RVAToFOA代码:
DWORD RVATOFOA(IN DWORD RVA,OUT DWORD FOA,IN LPVOID pFileBuffer){

    PIMAGE_DOS_HEADER pDosHeader = NULL;
    PIMAGE_NT_HEADERS pNtHeaders = NULL;
    PIMAGE_FILE_HEADER pFileHeader = NULL;
    PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;
    PIMAGE_SECTION_HEADER pSectionHeader = NULL;

    pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
    pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
    pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNtHeaders + 4);
    pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
    pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);

    size_t count = 0;
    //先判断在哪个节里边
    for (count = 1; RVA > (pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize); count++, pSectionHeader++);

    FOA = RVA - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;

    return FOA;
}
有了这个以后再解析导出表的信息:
VOID ExportDirectoryPrintf(){
    //定义PE头部指针变量
    PIMAGE_DOS_HEADER pDosHeader = NULL;
    PIMAGE_NT_HEADERS pNtHeaders = NULL;
    PIMAGE_FILE_HEADER pFileHeader = NULL;
    PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;
    PIMAGE_DATA_DIRECTORY pDataDirectory = NULL;
    PIMAGE_EXPORT_DIRECTORY pExportDirectory = NULL;
    PIMAGE_SECTION_HEADER pSectionHeader = NULL;

   
    DWORD ExportFOA = 0;
    DWORD FcFOA = 0;
    DWORD NameFOA = 0;
    DWORD NameOrdinalsFOA = 0;
    PDWORD pFunction = NULL;
    PDWORD pName = NULL;
    PDWORD pNameOrdinals = NULL;

    LPVOID pFileBuffer = NULL;


    ReadPEFile(INDLLPATH, &pFileBuffer);
   
    if (!pFileBuffer){
      printf("文件(dll)打开失败!\n");
      free(pFileBuffer);
    }
   
    pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
    pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
    pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNtHeaders + 4);
    pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
    pDataDirectory = (PIMAGE_DATA_DIRECTORY)((DWORD)pOptionalHeader + 96);
    pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
   
    printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
    printf("导出表RVA:%x\n",pDataDirectory->VirtualAddress);
    ExportFOA=RVATOFOA(pDataDirectory->VirtualAddress,ExportFOA,pFileBuffer);
   
    //这个地方需要把导出表的virtualAddress转换为FOA
    printf("导出表的FOA:%x\n",ExportFOA);
    //转换完成以后用directory指针加上就到导出表的地址了 (文件中地址)

    pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((DWORD)pFileBuffer + ExportFOA);


    FcFOA = RVATOFOA(pExportDirectory->AddressOfFunctions, FcFOA, pFileBuffer);

    NameOrdinalsFOA = RVATOFOA(pExportDirectory->AddressOfNameOrdinals, NameOrdinalsFOA, pFileBuffer);

    NameFOA = RVATOFOA(pExportDirectory->AddressOfNames, NameFOA, pFileBuffer);
    printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
    //先打印函数地址表
    pFunction =(PDWORD)((DWORD)pFileBuffer + FcFOA);

    printf(" 导出函数地址表RVA:%x\n", pExportDirectory->AddressOfFunctions);

    printf(" 导出函数地址表FOA:%x\n", FcFOA);

    for (size_t i = 0; i < pExportDirectory->NumberOfFunctions; i++, pFunction++)
    {
      printf("函数地址%d:%x\n", i, pFunction);
    }
    printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
    //打印函数名称表
    pName = (PDWORD)((DWORD)pFileBuffer + NameFOA);

    printf(" 导出函数名称表RVA:%x\n", pExportDirectory->AddressOfNames);
   
    printf(" 导出函数名称表FOA:%x\n", NameFOA);

    for (size_t i = 0; i < pExportDirectory->NumberOfNames; i++, pName++)
    {
      printf("函数名称表%d:%x\n", i, pName);
    }
    printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
    //打印导出函数序号表
    pNameOrdinals = (PDWORD)((DWORD)pFileBuffer + NameOrdinalsFOA);

    printf(" 导出函数序号表RVA:%x\n", pExportDirectory->AddressOfNameOrdinals);

    printf(" 导出函数序号表FOA:%x\n", NameOrdinalsFOA);

    for (size_t i = 0; i < pExportDirectory->NumberOfNames; i++, pNameOrdinals++)
    {
      printf("函数序号表第%d个:%x\n", i, pNameOrdinals);
    }
    printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
   
}
这个地方使用的是自己写的DLL里边一共四个函数运行结果为:




山梦 发表于 2018-8-23 14:04

谢谢楼主分享

pinkgun 发表于 2019-6-11 19:09

感谢楼主正遇到一个pe结构的软件
页: [1]
查看完整版本: PE结构中导出表分析