5、导出表

5、导出表

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;

这个导出表。他在可选PE头中的最后一个数组。

在可选PE头中是这样的

IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];

我们直接点进去

#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES    16

看到了这样的字眼,其实就可以确定了。这是一个固定的值是16

所以,我们继续下一步。我们找到可选PE头

这里带读者找一遍

image

首先起始位置是4D5A我们就去3C位置去看一下,NT头。的位置 ,4550是PE标记,没问题了。

然后标准PE头的大小是20 个字节,

image

这个E0是可选PE头的大小。我们就直接往下找。

image

标记上的就是可选PE头了。

从可选PE头的最后一个字节,往上数16个(8字节)数据。

image

也就是这个

其中00018F90就是导出表的数据。首先我们判断一下对不对。我们使用PEtools来判断一下。

image

这里要提一嘴,大小哪里来 的。看一下结构体就知道了

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

下面开始演示RvaToFoa

首先使用PETool打开

image

选择这个,我们0x00018F90再rdata区,

所以这个 减去内存偏移 + 文件偏移即可。

image

这样也就定位到了我们要的数据。

下面继续说我们的导出表。

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;

首先前12个字节全是废的 我们无需理会。直接从

image

也就是我标记的,从下面开始看 下面四个字节是一个Name数据,注意这里也是一个RVA

    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  导出函数序号表

好了。下面开始着重记录三张表

    DWORD   AddressOfFunctions;     // RVA from base of image  导出函数地址表

这里记录的是导出函数的地址,偏移量从序号表中获取

    DWORD   AddressOfNameOrdinals;  // RVA from base of image  导出函数序号表

也就是这个表。

    DWORD   AddressOfNames;         // RVA from base of image  导出函数名称表

这是一个名称表。要注意一点。导出序号表的序号是一个WORD不是DWORD类型的。

VOID PrintExpInfo(PCHAR pFileBuffer)
{if (!pFileBuffer){return;}PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pFileBuffer;PIMAGE_NT_HEADERS pNth = (PIMAGE_NT_HEADERS)(pFileBuffer + pDos->e_lfanew);if (pNth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == NULL){return;}// 定位到导出表DWORD dwExportFoa = RvaToFoa(pFileBuffer, pNth->OptionalHeader.DataDirectory[0].VirtualAddress);PIMAGE_EXPORT_DIRECTORY pExp = (PIMAGE_EXPORT_DIRECTORY)(pFileBuffer + dwExportFoa);// 输出基本内容printf("Name;                 [%s]   \n", pFileBuffer + RvaToFoa(pFileBuffer, pExp->Name));printf("Base;                 [0x%08x] \n", pExp->Base);printf("NumberOfFunctions;    [0x%08x] \n", pExp->NumberOfFunctions);printf("NumberOfNames;        [0x%08x] \n", pExp->NumberOfNames);printf("AddressOfFunctions;   [0x%08x] \n", pExp->AddressOfFunctions);printf("AddressOfNames;       [0x%08x] \n", pExp->AddressOfNames);printf("AddressOfNameOrdinals;[0x%08x] \n", pExp->AddressOfNameOrdinals);//导出函数名称表LPDWORD lpAddName = (LPDWORD)(pFileBuffer + RvaToFoa(pFileBuffer, pExp->AddressOfNames));for (size_t i = 0; i < pExp->NumberOfNames; i++){printf("%s \n", pFileBuffer + RvaToFoa(pFileBuffer, lpAddName[i]));}// 导出函数地址表LPDWORD lpAddfunction = (LPDWORD)(pFileBuffer + RvaToFoa(pFileBuffer, pExp->AddressOfFunctions));for (size_t i = 0; i < pExp->NumberOfFunctions; i++){printf("i :%d functionAddress[0x%p]\n",i, pFileBuffer + RvaToFoa(pFileBuffer,lpAddfunction[i]));}// 导出函数序号表LPWORD lpNameOrdinals = (LPWORD)(pFileBuffer + RvaToFoa(pFileBuffer, pExp->AddressOfNameOrdinals));for (size_t i = 0; i < pExp->NumberOfFunctions; i++){printf("i : %d NameOrdinals : %d\n", i, lpNameOrdinals[i]);}
}

RvaToFoa代码如下

DWORD RvaToFoa(PCHAR pBuffer, DWORD dwRva)
{if (pBuffer == NULL) return -1;PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuffer;PIMAGE_NT_HEADERS pNth = (PIMAGE_NT_HEADERS)(pBuffer + pDos->e_lfanew);PIMAGE_FILE_HEADER pFil = (PIMAGE_FILE_HEADER)((PCHAR)pNth + 4);PIMAGE_OPTIONAL_HEADER pOpt = (PIMAGE_OPTIONAL_HEADER)((PCHAR)pFil + IMAGE_SIZEOF_FILE_HEADER);PIMAGE_SECTION_HEADER pSec = (PIMAGE_SECTION_HEADER)((PCHAR)pOpt + pFil->SizeOfOptionalHeader);if (dwRva <= pOpt->SizeOfHeaders)	return dwRva;for (size_t i = 0; i < pFil->NumberOfSections; i++){if (dwRva >= pSec[i].VirtualAddress && (dwRva <= (pSec[i].VirtualAddress + pSec[i].Misc.VirtualSize))){return dwRva - pSec[i].VirtualAddress + pSec[i].PointerToRawData;}}return -1;
}

根据名称获取函数地址

PCHAR GetProcAddressByName(PCHAR pFileBuffer, PCHAR pFunName)
{// 定位导出表PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pFileBuffer;PIMAGE_NT_HEADERS pNth = (PIMAGE_NT_HEADERS)(pFileBuffer + pDos->e_lfanew);if (pNth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == NULL){return NULL;}DWORD dwExportFoa = RvaToFoa(pFileBuffer,pNth->OptionalHeader.DataDirectory[0].VirtualAddress);PIMAGE_EXPORT_DIRECTORY pExp = (PIMAGE_EXPORT_DIRECTORY)(pFileBuffer + dwExportFoa);//定位三张表LPDWORD pAddFunc = (LPDWORD)(pFileBuffer + RvaToFoa(pFileBuffer, pExp->AddressOfFunctions));LPDWORD pAddName = (LPDWORD)(pFileBuffer + RvaToFoa(pFileBuffer, pExp->AddressOfNames));LPWORD pAddOrder = (LPDWORD)(pFileBuffer + RvaToFoa(pFileBuffer, pExp->AddressOfNameOrdinals));// 判断然后输出即可for (size_t i = 0; i < pExp->NumberOfNames; i++){if (!strcmp(pFunName, pFileBuffer + RvaToFoa(pFileBuffer, pAddName[i]))){return pAddFunc[pAddOrder[i]];}}return NULL;
}

根据输出序号获取地址(这里的序号是+base之后的数据哈)

PCHAR GetProcAddressByOrid(PCHAR pFIleBuffer, DWORD dwOrid)
{// 定位导出表PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pFIleBuffer;PIMAGE_NT_HEADERS pNth = (PIMAGE_NT_HEADERS)(pFIleBuffer + pDos->e_lfanew);// 判断导出表是否存在if (pNth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == NULL){return NULL;}DWORD dwOffset = RvaToFoa(pFIleBuffer, pNth->OptionalHeader.DataDirectory[0].VirtualAddress);PIMAGE_EXPORT_DIRECTORY pExp = (PIMAGE_EXPORT_DIRECTORY)(pFIleBuffer + dwOffset);// 定位序号表,函数地址表LPDWORD dwFunc = (LPDWORD)(pFIleBuffer + RvaToFoa(pFIleBuffer, pExp->AddressOfFunctions));LPWORD wOrid = (LPWORD)(pFIleBuffer + RvaToFoa(pFIleBuffer, pExp->AddressOfNameOrdinals));return dwFunc[dwOrid - pExp->Base];
}

导出表结束

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/855564.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

4、文件与内存转换相关

4、文件与内存转换相关 FileBufferToImageBuffer 也是一样的长话短说。这里涉及了一点,就是内存对齐 PE头与节区之间 节区与节区时间会发生内存对齐。在文件中有一个文件对齐 ​​ 在可选PE头中有这两个进行标识,之前也写过这个内存对齐的博客,这里就不多说了 下面贴几个代…

1、PE 初识

1、PE 初识 概论 首先 PE头部分主要是学习PE结构的前半部分,每一个是做什么的,以及重点是什么,每一个是做什么用的。并使用Cpp代码来解析该PE头 注意这里用了一个Windows.h的头文件,后面再说。 PE是Windows系统 PE结构(Portable Executable),即可移植可执行文件格式,是…

交换空间swap

交换空间: 交换空间是硬盘上的一部分,被用作虚拟内存,当系统的物理内存(RAM)不足时,系统会使用交换空间来存储暂时不用的数据。1.关闭交换空间 1)关闭所有交换空间 swapoff -a2)关闭特定的交换空间 swapoff /dev/sdb12.开启交换空间 1)开启所有交换空间 swapon -a2…

2024 IDEA 2024.3 安装使用教程(附激活至2099年,以及常见问题处理)

IntelliJ IDEA简介 IntelliJ IDEA是一款非常强大的Java集成开发环境(IDE),由JetBrains公司开发。它提供了丰富的功能和工具,帮助开发者更高效地编写、调试和部署代码。 下面这种方式仅供交流学习,如果有能力还请支持正版 下载安装 下载 IDEA 2024.3 版本的安装包 为了方便,也…

第十六次作业

1、通过华为云沃土云创计划免费薅云服务器 打开链接:https://developer.huaweicloud.com/programs/dev-program.html 使能⽅向选择个⼈在这个 计划权益中申请优惠券免费购买成功2、复现windows、linux权限维持技巧 windows权限维持: 隐藏⽂件:利⽤⽂件属性 ⽂件右键属性,勾…

OpenCL 编程步骤 2. 获取设备

clGetDeviceIDs 查询支持OpenCL设备列表: cl_int clGetDeviceIDs(cl_platform_id platform ,cl_device_type device_type ,cl_uint num_entries ,cl_device_id *devices ,cl_uint *num_devices )与clGetPlatformIDs函数类似,第一次调用时,devic…

记录一下:小华半导体HC32F448建立MDK工程

1.先到官网上下载文件 a>下载驱动库:HC32F448_DDL_Rev1.1.0.zip 驱动库中是包括了例程的。 b>下载样例:HC32F448_Template_Rev1.0.1.zip 可以直接复制官方的样例,就不用自己创建工程了。 c>下载芯片支持包:HC32F448_IDE_Rev1.0.1.zip 下载后双击安装即可。否则KEI…

4大应用场景揭秘:AI视频监控在养老院中的智能化管理与安全保障

随着人口老龄化的加剧,养老院的管理面临着越来越多的挑战。传统的人工巡查方式不仅难以做到全天候监控,而且存在响应迟缓、效率低下等问题。为了解决这些问题,思通数科推出的AI视频监控系统,利用人工智能技术提供了一种高效、智能化的解决方案。尤其在养老院的老人体征监控…

考勤管理系统

实现对用户信息的添加,查看,删除 实现对部门信息的添加,查看 实现用户登录功能,修改密码功能。 页面与之前的大相径庭。 还是一样的框架总体感觉换汤不换药,目前就是熟练度问题

浏览器怎么渲染数据的

突然发现自己对于css的样式规则一直都没有完全明白,今天写文好好整明白 浏览器渲染原理 1. 浏览器向服务器请求html文件 2. html文件返回浏览器 3. 浏览器解读html文件<!DOCTYPE html>//告诉浏览器,这是html5文件// html树<html lang="en">//语言<h…

在宝塔里添加反向代理

安装OnlyOffice时,需要配置反向代理; 完成以上操作之后,访问时有可能出现504报错,也可能就可以正常访问了。如果报错可以修改上图反向代理中的目标URL的内容将域名改成127.0.0.1。我当时改成http://127.0.0.1:9633就可以了本文来自博客园,作者:飞龙在生,转载请注明原文链…