PE-导出表

导出表概念

导出表一般用于DLL文件,DLL导出了什么函数都记录在导出表上,在数据目录的第1项,下标为0

1.如何定位导出表:

数据目录项的第一个结构,就是导出表.

 typedef struct _IMAGE_DATA_DIRECTORY {  
    DWORD   VirtualAddress;   
    DWORD   Size;     
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;  
​

VirtualAddress 导出表的RVA ​ Size 导出表大小 ( Size 字段不一定是真实的)

2.导出表结构

上面的结构,只是说明导出表在哪里,有多大,并不是真正的导出表. ​ 如何在FileBuffer中找到这个结构呢?在VirtualAddress中存储的是RVA,如果想在FileBuffer中定位 ​ 必须要先将该RVA转换成FOA. ​ 真正的导出表结构如下:

AddressOfNameOrdinals;

NAME:指针(Rva),指向导出表文件名字 字符串. xx.dll

AddressOfFunctions说明:

该地址存着dll或EXE所有导出函数的入口地址

该表中元素宽度为4个字节 ​ 该表中存储所有导出函数的地址 ​ 该表中个数由NumberOfFunctions决定 ​ 该表项中的值是RVA, 加上ImageBase才是函数真正的地址 ​ 定位: ​ IMAGE_EXPORT_DIRECTORY->AddressOfFunctions 中存储的是该表的RVA 需要先转换成FOA

AddressOfNames说明:

该地址存着dll或EXE所有导出函数名字的地址

该表中元素宽度为4个字节 该表中存储所有以名字导出函数的名字的RVA 该表项中的值是RVA, 指向函数真正的名称

AddressOfNameOrdinals

该地址存着dll或EXE所有导出函数的序号

总结:

为什么要分成3张表? ​

1、函数导出的个数与函数名的个数未必一样.所以要将函数地址表和函数名称表分开. ​

2、函数地址表是不是一定大于函数名称表? ​ 未必,一个相同的函数地址,可能有多个不同的名字. ​

3、如何根据函数的名字获取一个函数的地址?

4、如何根据函数的导出序号获取一个函数的地址?

为了再巩固一下,这里再举一个真实的例子,根据上面的规则自己走一遍。

.dll 导出函数由以下def 文件导出,可见序号为 2 3 5 6

EXPORTS 
    
Plus    @2
Sub     @5 NONAME
Mul     @3
Div     @6

由上述 def 生成.dll ,查看导出表的结果是:

img

练习:

1、编写程序打印所有的导出表信息

2、编写函数 GetFunctionAddrByName ( FileBuffer指针,函数名指针)

3、编写函数 GetFunctionAddrByOrdinals ( FileBuffer指针,函数名导出序号)

VOID PutExportTable()
{
    PVOID pFileBuffer;
    PIMAGE_DOS_HEADER pDosHeader = NULL;
    PIMAGE_FILE_HEADER pPEHeader = NULL;
    PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
    PIMAGE_SECTION_HEADER pSectionHeader = NULL;
    PIMAGE_EXPORT_DIRECTORY pExportTable = NULL;
​
    DWORD AddressOfNameFOA = NULL;
    DWORD AddressOfNameOrdinalsFOA = NULL;
    DWORD AddressOfFunctions = NULL;
    WORD Ordinal = NULL;
​
    BOOL isOk = FALSE;
    DWORD size = 0;
    ReadPEFile(file_path, &pFileBuffer);
    if (!pFileBuffer)
    {
        printf("读取文件失败");
        return;
    }
    pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
    pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew) + 4);
    pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)(((DWORD)pFileBuffer + pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER);
    pSectionHeader = (PIMAGE_SECTION_HEADER)(((DWORD)pFileBuffer + pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER + pPEHeader->SizeOfOptionalHeader);
​
    pExportTable = (PIMAGE_EXPORT_DIRECTORY)((DWORD)pFileBuffer+ RvaToOffset(pOptionHeader->DataDirectory[0].VirtualAddress ,pFileBuffer));
    printf("DIRECTORY_ENTRY_EXPORT ViltualAddress:%X\n", pOptionHeader->DataDirectory[0].VirtualAddress);
​
    printf("Characteristics: %#x\n", pExportTable->Characteristics);
    printf("TimeDateStamp: %#x\n", pExportTable->TimeDateStamp);
    printf("MajorVersion: %#x\n", pExportTable->MajorVersion);
    printf("MinorVersion: %#x\n", pExportTable->MinorVersion);
    printf("Name: %s\n", (PVOID)((DWORD)pFileBuffer + RvaToOffset(pExportTable->Name, pFileBuffer)));//(PVOID)((DWORD)pFileBuffer + RvaToOffset(pExportTable->Name,pFileBuffer))
    printf("Base: %#x\n", pExportTable->Base);
    printf("NumberOfFunctions: %#x\n", pExportTable->NumberOfFunctions);
    printf("NumberOfNames: %#x\n", pExportTable->NumberOfNames);
    printf("AddressOfFunctions: %#x\n", pExportTable->AddressOfFunctions);
    printf("AddressOfNames: %#x\n", pExportTable->AddressOfNames);
    printf("AddressOfNameOrdinals: %#x\n", pExportTable->AddressOfNameOrdinals);//52590
​
    
    
    
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值