• PE结构学习02-导出表


    导出表:

    • 上篇文章,我们学习了各种头,Dos,NT,节表头,我们知道,OptionalHeader指向的DataDirectory[]数组一共有16个:

    • 我们接下来要学习的有:
    1. IMAGE_DIRECTORY_ENTRY_IMPORT 导入表
    2. IMAGE_DIRECTORY_ENTRY_BASERELOC 基址重定位表
    3. IMAGE_DIRECTORY_ENTRY_EXPORT 导出表
    4. IMAGE_DIRECTORY_ENTRY_RESOURCE 资源表
    • 今天我们学习导出表:
    1. 我们知道dll文件,是动态链接库,里面有许多函数给别人调用,但是别人怎么知道里面有什么函数呢?就需要导出表清单给人家看,就如同你去餐厅点餐,却不知道餐厅有什么菜,这时服务生会拿出菜单来,这个菜单就如同导出表。
    2. 所有PE文件都可以有导出表,只是大部分情况下,exe不提供导出表而已。
    • 我们知道OptionalHeader指向的DataDirectory[]数组一共有16个,每个都是一样的结构:
    1. VirtualAddress  虚拟偏移地址
    2. size  大小
    • NtHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT ],这个数据目录表VirtualAddress指向的是导出表的地址:
    typedef struct _IMAGE_EXPORT_DIRECTORY 
    {
    DWORD Characteristics;//未使用,总是定义为0
    DWORD TimeDateStamp;//文件生成时间
    WORD MajorVersion;//未使用,总是定义为0
    WORD MinorVersion;//未使用,总是定义为0
    DWORD Name; //模块的真实名称的RVA
    DWORD Base; //基数,加上序数就是函数地址数组的索引值
    DWORD NumberOfFunctions;//导出函数的总数
    DWORD NumberOfNames; //以名称方式导出的函数的总数
    DWORD AddressOfFunctions; // RVA from base of image指向输出函数地址的RVA
    DWORD AddressOfNames; // RVA from base of image指向输出函数名字的RVA
    DWORD AddressOfNameOrdinals; // RVA from base of image向输出函数序号的RVA

    } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY
    1. Characteristics:现在没有用到,一般为0。
    2. TimeDateStamp:导出表生成的时间戳,由连接器生成。
    3. MajorVersion,MinorVersion:看名字是版本,实际貌似没有用,都是0。
    4. Name:模块的名字,就是dll的名称。
    5. Base:序号的基数,按序号导出函数的序号值从Base开始递增。
    6. NumberOfFunctions:所有导出函数的数量。
    7. NumberOfNames:按名字导出函数的数量。
    8. AddressOfFunctions:一个RVA,指向一个DWORD数组,数组中的每一项是一个导出函数的RVA,顺序与导出序号相同。
    9. AddressOfNames:一个RVA,依然指向一个DWORD数组,数组中的每一项仍然是一个RVA,指向一个表示函数名字。
    10. AddressOfNameOrdinals:一个RVA,还是指向一个WORD数组,数组中的每一项与AddressOfNames中的每一项对应,表示该名字的函数在AddressOfFunctions中的序号。
    typedef struct _IMAGE_IMPORT_BY_NAME 
    {
    WORD Hint;
    CHAR Name[1];
    } IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

    • AddressOfFunctions 指向所有函数的地址。
    • AddressOfNames 指向名字的地址。
    • AddressOfNameOrdinals 指向一个序号。
    • 查找导出表代码(c/c++):
    int main(int argc, char *argv[])
    {
     PIMAGE_DOS_HEADER Pdos = (PIMAGE_DOS_HEADER)GetModuleHandle(L"user32.dll");
    
    
     PIMAGE_NT_HEADERS Pnt = (PIMAGE_NT_HEADERS)((int)Pdos->e_lfanew + (int)Pdos);
    
     IMAGE_OPTIONAL_HEADER32 Popt = Pnt->OptionalHeader;
    
     IMAGE_EXPORT_DIRECTORY * Export;
     Export = (IMAGE_EXPORT_DIRECTORY*)(Popt.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + (ULONG_PTR)Pdos);
    
     DWORD * AllAddress;
     DWORD * AllName;
     USHORT * AllOrg;
    
     AllAddress = (DWORD*)((int)Export->AddressOfFunctions + (int)Pdos);//函数地址数组
     AllName = (DWORD*)((int)Export->AddressOfNames + (int)Pdos);//函数名称数组
     AllOrg = (USHORT *)((int)Export->AddressOfNameOrdinals + (int)Pdos);//序号数组
    
    
     int OneAddress;
     char * OneName;
     USHORT OneOrg;
     char * Buf = new char[500];
     int ListId = NULL;
    
     for (int i = 0; i < (int)Export->NumberOfNames; i++)
     {
    
     OneName = (char*)((BYTE*)Pdos + AllName[i]);
     OneOrg = (USHORT)AllOrg[i];
     OneAddress = (int)((int)Pdos + AllAddress[OneOrg]);
    
     printf("Name: %s, Org :%d,Address :%x
    ", OneName, OneOrg, OneAddress);
     }
    
     return 0;
    }

  • 相关阅读:
    7-1 N个数求和
    3662. 最大上升子序列和
    树状数组
    堆优化Dijkstra java模板
    皮亚诺曲线距离
    最长公共子序列(计数问题)
    最小路径覆盖
    极角排序
    2619. 询问
    Hessian矩阵与局部极小值
  • 原文地址:https://www.cnblogs.com/DeeLMind/p/6837021.html
Copyright © 2020-2023  润新知