PE结构之导入表

 流程图:

文件中\样式

加载到进程中时
 
加载到进程中时的过程,一张图不够放
 

续图
 

整个流程
 

 补充导入表结构IMAGE_IMPORT_DESCRIPTOR 中的ForwarderChain字段, 该解释为
"某个导入模块涉及转发(即该模块的某些函数从其他模块转发过来),那么 ForwarderChain 字段会包含一个索引,指向这个导入描述符中与第一个转发函数相关的表条目  ,通常情况下,ForwarderChain 被设为 -1(或 0xFFFFFFFF),表示该导入描述符中没有转发函数"
关于函数转发,请查看PE结构之导出表-CSDN博客 中的内容>

这篇中介绍到kernel32.dll中包含了转发函数但是我们可以查看记事本的 exe .

 可以看到 这个成员 依然是用-1 来表达的.即使他有转发函数的情况下

 64位程序注意事项

考虑到 PE32+ 可执行文件(64 位),每个 ILT (导入名称表) 条目总结为:

  • 如果设置了高位(位 63,也称为“序号标志”),则底部 63 位(0 到 62)被视为序号函数号。
  • 如果未设置高位 (即序号标志为 false) ,则整个条目是 Hint/Name 表的 RVA。

导入表的遍历

//打印导入表
BOOL PrintImport(__in char* m_fileName)
{char* Filebuffer = NULL;if (!GetFileBuffer(m_fileName, &Filebuffer)) return FALSE;PIMAGE_DOS_HEADER LPdosHeader = NULL;PIMAGE_NT_HEADERS LPntHeader = NULL;LPdosHeader = (PIMAGE_DOS_HEADER)Filebuffer;LPntHeader = (PIMAGE_NT_HEADERS)((CHAR*)LPdosHeader + LPdosHeader->e_lfanew);//如果是32位程序if (LPntHeader->OptionalHeader.Magic == 0x10b){PIMAGE_NT_HEADERS32 LPntHeader32 = LPntHeader;LPntHeader = NULL;DWORD Characteristics = 0;//定位到导入表PIMAGE_IMPORT_DESCRIPTOR LPimport = (PIMAGE_IMPORT_DESCRIPTOR)((CHAR*)LPdosHeader+ RVAToFOAEX(LPdosHeader, LPntHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, &Characteristics));PIMAGE_IMPORT_DESCRIPTOR LPcurrentImport = LPimport;int i = 0;while (LPcurrentImport->OriginalFirstThunk!=0 && LPcurrentImport->FirstThunk!=0){printf("[%d]IMAGE_IMPORT_DESCRIPTOR结构\n",i++);printf("OriginalFirstThunk:0X%X\nTimeDateStamp:0X%X\nName:%s\nFirstThunk:0X%X\n",LPcurrentImport->OriginalFirstThunk,LPcurrentImport->TimeDateStamp,((CHAR*)LPdosHeader+RVAToFOA(LPdosHeader,LPcurrentImport->Name)),LPcurrentImport->FirstThunk);//导入查找表或者叫导入名称表PIMAGE_THUNK_DATA32 INTtable = (PIMAGE_THUNK_DATA32)((CHAR*)LPdosHeader + RVAToFOA(LPdosHeader, LPcurrentImport->OriginalFirstThunk));int j = 0;while (INTtable->u1.AddressOfData != 0){if ((INTtable->u1.AddressOfData & 0x80000000)==0){PIMAGE_IMPORT_BY_NAME hintName=(PIMAGE_IMPORT_BY_NAME) ((CHAR*)LPdosHeader + RVAToFOA(LPdosHeader, INTtable->u1.AddressOfData));printf("\t[%d] 按名称导入  hint:[0x%x] Name:%s\n",j, hintName->Hint, hintName->Name);}else{printf("\t[j] 按序号导入 0x%x\n", INTtable->u1.AddressOfData & (~0x80000000));}INTtable++;j++;}//导入地址表PIMAGE_THUNK_DATA32 IATtable = (PIMAGE_THUNK_DATA32)((CHAR*)LPdosHeader + RVAToFOA(LPdosHeader, LPcurrentImport->FirstThunk));int k = 0;while (IATtable->u1.AddressOfData != 0){if (LPcurrentImport->TimeDateStamp == 0){if ((INTtable->u1.AddressOfData & 0x80000000 )== 0){PIMAGE_IMPORT_BY_NAME hintName = (PIMAGE_IMPORT_BY_NAME)((CHAR*)LPdosHeader + RVAToFOA(LPdosHeader, INTtable->u1.AddressOfData));printf("\t[%d] 按名称导入  hint:[0x%x] Name:%s\n", k, hintName->Hint, hintName->Name);}else{printf("\t[k] 按序号导入 0x%x\n", INTtable->u1.AddressOfData & (~0x80000000));}}else{printf("\t函数绝对地址 0x%x\n", IATtable->u1.Function);}IATtable++; k++;}LPcurrentImport++;}}else{//64位程序PIMAGE_NT_HEADERS64 LPntHeader64 = LPntHeader;LPntHeader = NULL;DWORD Characteristics = 0;//定位到导入表PIMAGE_IMPORT_DESCRIPTOR LPimport = (PIMAGE_IMPORT_DESCRIPTOR)((CHAR*)LPdosHeader + RVAToFOAEX(LPdosHeader, LPntHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, &Characteristics));PIMAGE_IMPORT_DESCRIPTOR LPcurrentImport = LPimport;int i = 0;while (LPcurrentImport->OriginalFirstThunk != 0 && LPcurrentImport->FirstThunk != 0){printf("[%d]IMAGE_IMPORT_DESCRIPTOR结构\n", i++);printf("OriginalFirstThunk:0X%X\nTimeDateStamp:0X%X\nName:%s\nFirstThunk:0X%X\n", LPcurrentImport->OriginalFirstThunk, LPcurrentImport->TimeDateStamp,((CHAR*)LPdosHeader + RVAToFOA(LPdosHeader, LPcurrentImport->Name)), LPcurrentImport->FirstThunk);//导入查找表或者叫导入名称表PIMAGE_THUNK_DATA64 INTtable64 = (PIMAGE_THUNK_DATA32)((CHAR*)LPdosHeader + RVAToFOA(LPdosHeader, LPcurrentImport->OriginalFirstThunk));int j = 0;while (INTtable64->u1.AddressOfData != 0){if ((INTtable64->u1.AddressOfData & 0x8000000000000000) == 0){PIMAGE_IMPORT_BY_NAME hintName = (PIMAGE_IMPORT_BY_NAME)((CHAR*)LPdosHeader + RVAToFOA(LPdosHeader, INTtable64->u1.AddressOfData));printf("\t[%d] 按名称导入  hint:[0x%x] Name:%s\n", j, hintName->Hint, hintName->Name);}else{printf("\t[j] 按序号导入 0x%llx\n", INTtable64->u1.AddressOfData & (~0x8000000000000000));}INTtable64++;j++;}//导入地址表PIMAGE_THUNK_DATA64 IATtable64 = (PIMAGE_THUNK_DATA32)((CHAR*)LPdosHeader + RVAToFOA(LPdosHeader, LPcurrentImport->FirstThunk));int k = 0;while (IATtable64->u1.AddressOfData != 0){if (LPcurrentImport->TimeDateStamp == 0){if ((IATtable64->u1.AddressOfData & 0x8000000000000000) == 0){PIMAGE_IMPORT_BY_NAME hintName = (PIMAGE_IMPORT_BY_NAME)((CHAR*)LPdosHeader + RVAToFOA(LPdosHeader, IATtable64->u1.AddressOfData));printf("\t[%d] 按名称导入  hint:[0x%x] Name:%s\n", k, hintName->Hint, hintName->Name);}else{printf("\t[k] 按序号导入 0x%llx\n", IATtable64->u1.AddressOfData & (~0x8000000000000000));}}else{printf("\t函数绝对地址 0x%llx\n", IATtable64->u1.Function);}IATtable64++;k++;}LPcurrentImport++;}}
}

 如果某个导入表的时间戳==-1 ,请查看PE结构之绑定导入表-CSDN博客

导入表注入 (包括创建新的节区,移除Dostub 添加新的节表)

原理:在需要注册的程序中的导入表后添加 需要注入的dll的信息

将导入表移动带新节区
新的节区 属性请务必 给与可读可写的属性.否则你将 遭遇到
Exception Processing Message 0xC0000005 - Unexpected parameters
因为 系统在加载该dll时,将修改IAT表中的内容为函数的rva .如果不给可写属性,那么将遭遇如下的问题. 

 
我在 填写节属性时,复制了导入表的属性,导致无法运行程序

//导入表 HOOK  包含移动导入表 ,修改目录项的RVA ,添加新的导入表
BOOL IATHook(__in char* m_fileName, __in char* m_DllName , __in char* m_savePath)
{char* Filebuffer = NULL;if (!GetFileBuffer(m_fileName, &Filebuffer)) return FALSE;PIMAGE_DOS_HEADER LPdosHeader = NULL;PIMAGE_NT_HEADERS LPntHeader = NULL;LPdosHeader = (PIMAGE_DOS_HEADER)Filebuffer;LPntHeader = (PIMAGE_NT_HEADERS)((CHAR*)LPdosHeader + LPdosHeader->e_lfanew);//如果是32位程序if (LPntHeader->OptionalHeader.Magic == 0x10b){PIMAGE_NT_HEADERS32 LPntHeader32 = LPntHeader;LPntHeader = NULL;//定位到导入表DWORD Characteristics = 0;//原来的节表的属性 /*	DWORD Characteristics = 0xC0000000; //请给可读可写节区属性,否则你会后悔*/PIMAGE_IMPORT_DESCRIPTOR LPoriginalFirstImport = (PIMAGE_IMPORT_DESCRIPTOR)((CHAR*)LPdosHeader + RVAToFOAEX(LPdosHeader, LPntHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, &Characteristics));PIMAGE_IMPORT_DESCRIPTOR LPoriginalCurrentImport = LPoriginalFirstImport;//计算原来的所有导入表的大小DWORD sizeofOrinigal = 0;while (LPoriginalCurrentImport->OriginalFirstThunk != 0 && LPoriginalCurrentImport->FirstThunk != 0){sizeofOrinigal += sizeof(IMAGE_IMPORT_DESCRIPTOR);LPoriginalCurrentImport++;}//计算新添加的大小DWORD sizeofNew = 0;sizeofNew += sizeof(IMAGE_IMPORT_DESCRIPTOR)*2;//新增一个导入表结构,和空白区,sizeofNew += sizeof(IMAGE_THUNK_DATA32) * 2;//新增一个INT表和全0结束大小sizeofNew += sizeof(IMAGE_THUNK_DATA32) * 2;//新增一个IAT表和全0结束大小sizeofNew += sizeof(IMAGE_IMPORT_BY_NAME);//添加一个Hint/Name 表sizeofNew += strlen(m_DllName);//再加上一个字符串的小NewSecInfo info = { 0 };info.Characteristics = Characteristics;info.sizeofNewData = sizeofOrinigal + sizeofNew;//要往节中添加多少数据if (!AddSection(Filebuffer, &info)){free(Filebuffer);return FALSE;}//PULONG_PTR pCurrentPoint = NULL;//用于记录当前指针的位置DWORD currentRVA = 0;currentRVA = info.NewSectionVirtualAddress;pCurrentPoint = info.NewSectionBegionPointer;memcpy(pCurrentPoint, LPoriginalFirstImport, sizeofOrinigal);//将原来的节表赋值到新的节区//修改目录项中的导入表的RVAPIMAGE_NT_HEADERS32 LPnewNtHeader32 = (PIMAGE_NT_HEADERS32)(((PIMAGE_DOS_HEADER)info.newFileBuffer)->e_lfanew + (CHAR*)info.newFileBuffer);LPnewNtHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = currentRVA;//移动指针和RVA到原来的导入表结束位置pCurrentPoint = (char*)pCurrentPoint + sizeofOrinigal ;//移动指currentRVA += sizeofOrinigal;//移动RVA//记录要加的导入表指针PIMAGE_IMPORT_DESCRIPTOR pnewIDTpoint = (PIMAGE_IMPORT_DESCRIPTOR)pCurrentPoint;再次移动指针和RVA 留出要添加 导入表和空白位置pCurrentPoint = (char*)pCurrentPoint + sizeof(IMAGE_IMPORT_DESCRIPTOR)*2;currentRVA += sizeof(IMAGE_IMPORT_DESCRIPTOR) * 2;//添加Hint/Name 表((PIMAGE_IMPORT_BY_NAME)pCurrentPoint)->Hint = 0;memcpy(((PIMAGE_IMPORT_BY_NAME)pCurrentPoint)->Name, "add", strlen("add")+1);DWORD HintNameRVA = currentRVA;//移动指针和RVApCurrentPoint = (char*)pCurrentPoint + strlen("add") + 1 + sizeof(WORD);currentRVA += strlen("add") + 1 + sizeof(WORD);//添加INT表((PIMAGE_THUNK_DATA32)pCurrentPoint)->u1.Ordinal = HintNameRVA;//RVA不可能超越 0x80000000这个值(表示按序号导入),用户空间的代码在32位时最高地址为7FFF FFFF DWORD INTRVA = currentRVA;//移动指针和RVApCurrentPoint = (char*)pCurrentPoint + sizeof(IMAGE_THUNK_DATA32) * 2;//留空白结尾currentRVA+= sizeof(IMAGE_THUNK_DATA32) * 2;//添加IAT表((PIMAGE_THUNK_DATA32)pCurrentPoint)->u1.Ordinal = HintNameRVA;//RVA不可能超越 0x80000000这个值(表示按序号导入),用户空间的代码在32位时最高地址为7FFF FFFF DWORD IATRVA = currentRVA;//移动指针和RVApCurrentPoint = (char*)pCurrentPoint + sizeof(IMAGE_THUNK_DATA32) * 2;//留空白结尾currentRVA += sizeof(IMAGE_THUNK_DATA32) * 2;//添加DLL的名字memcpy(pCurrentPoint, m_DllName, strlen(m_DllName) + 1);DWORD dllNameRVA = currentRVA;pnewIDTpoint->OriginalFirstThunk = INTRVA;pnewIDTpoint->FirstThunk = IATRVA;pnewIDTpoint->Name = dllNameRVA;pnewIDTpoint->TimeDateStamp = 0;pnewIDTpoint->ForwarderChain = -1;//只有dll中有转发,加链接的过程中,连接器怎么知道这个dll有转发函数,并将导入表的这个位置写入值呢StoringFile(m_savePath, info.newFileBuffer, info.NewFileBufferSize);}else{}}

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

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

相关文章

windows安装deepspeed setup.py 207行找不到文件

一直报莫名奇妙的错误,查了半天也没查到 去看了一下源码,需要安装git,我没有安装 git命令获得信息也没啥用 直接注释掉 成功运行

YOLO11改进|注意力机制篇|引入轴向注意力Axial Attention

目录 一、【Axial Attention】注意力机制1.1【Axial Attention】注意力介绍1.2【Axial Attention】核心代码二、添加【Axial Attention】注意力机制2.1STEP12.2STEP22.3STEP32.4STEP4三、yaml文件与运行3.1yaml文件3.2运行成功截图一、【Axial Attention】注意力机制 1.1【Axi…

【JPCS独立出版,EI检索稳定】第三届能源互联网及电力系统国际学术会议(ICEIPS 2024)

第三届能源互联网及电力系统国际学术会议(ICEIPS 2024) 2024 3rd International Conference on Energy Internet and Power Systems ICEIPS 2024已成功申请JPCS - Journal of Physics: Conference Series (ISSN:1742-6596) ICEIPS 2024独立出版&…

TCP——Socket

应用进程只借助Socket API发和收但是不关心他是怎么进行传和收的 数据结构 图示Socket连接 捆绑属于隐式捆绑

200Kg大载重多旋无人机价格高昂技术分析

200Kg大载重多旋无人机作为一种高度专业化的航空工具,其价格相较于普通无人机显著较高,这主要是由于其在技术设计和生产过程中所需的高要求所致。以下是对其价格高昂的技术分析: 一、高性能材料与结构设计 1. 高强度轻量化材料:…

Python,Swift,Haskell三种语言在使用正则表达式上的方法对比

这里插入图片描述](https://i-blog.csdnimg.cn/direct/fea1494d0d0c4c9880881493929a8b91.png)在讨论 Python、Swift 和 Haskell 在正则表达式处理字符串方面的优缺点时,可以从它们对正则表达式的支持、灵活性和性能进行比较。以下通过具体的正则表达式字符串匹配例…

【前端】如何制作一个自己的代码(10)

接上文。 颜色名称 将color的属性值,设置成颜色的英文名就能显示对应的颜色。 比如,这里的red表示红色,这种设置颜色的方式是最简单的。 但是不同的浏览器,对颜色的解析可能存在差异,实际开发中不建议使用颜色名称来…

VUE基础(2)

一.分析脚手架 1.1.脚手架文件结构 ├── node_modules ├── public │ ├── favicon.ico: 页签图标 │ └── index.html: 主页面 ├── src │ ├── assets: 存放静态资源 │ │ └── logo.png │ │── component: 存放组件 │ │ └── He…

内网wordpress更换IP后无法访问的解决办法

一、现象 一台装有wordpress的台式机,从一个校区移到了另一个校区,更换了IP地址,导致无法正常访问。 二、分析 安装wordpress的时候里面的ip(或域名)都已固定。安装好后,内网通过IP访问&am…

2024年10月份实时获取地图边界数据方法,省市区县街道多级联动【附实时geoJson数据下载】

首先,来看下效果图 在线体验地址:https://geojson.hxkj.vip,并提供实时geoJson数据文件下载 可下载的数据包含省级geojson行政边界数据、市级geojson行政边界数据、区/县级geojson行政边界数据、省市区县街道行政编码四级联动数据&#xff0…

7、Vue2(二) vueRouter3+axios+Vuex3

14.vue-router 3.x 路由安装的时候不是必须的,可以等到使用的时候再装,如果之前没有安装的话,可以再单独安装。之前的终端命令行不要关闭,再重新开一个,还需要再package.json文件的依赖中添加。 如果忘记之前是否有安…

ESP32移植Openharmony设备开发---(4)Timer定时器

Timer内核定时器 官方文档:OpenAtom OpenHarmony 所需头文件:los_swtmr.h 头文件所在位置: 基本概念: 软件定时器 软件定时器,是基于系统Tick时钟中断且由软件来模拟的定时器,当经过设定的Tick时钟计数…

猫分鱼干 -算法题解

题目 假如有一群猫排成一行,要分配鱼干,每一只猫都有一个等级值。你作为管理员有很多鱼干但是需要按下边的分配制度分配: 1. 每一只猫至少要分配一斤鱼干,鱼干分配最小单位是斤,必须保证是整数。 2. 猫比他们邻居有更高…

大语言模型训练

大语言模型训练 1.两大问题2.并行训练2.1数据并行2.2模型并行2.3张量并行2.4混合并行 3.权重计算3.1浮点数3.2混合精度训练3.3deepspeed(微软)3.3.1 ZeRO3.3.2ZeRO-offload 3.3总结 4.PEFT4.1Prompt TuningPrefix-tuning4.2P-tuning & P-tuning v2 5…

数字图像处理:图像去噪

图像去噪–总变差去噪(TV) 引用资料: 1.全变分图像去噪算法(TV) 2.TV去噪的理解 总变差去噪 (Total Variation Denoising) 是一种经典的图像去噪方法,能够有效减少噪声,同时保留图像的边缘细节…

10.15.2024刷华为OD C题型(二)

10.15.2024刷华为OD C题型(二) 密码输入检测智能成绩表 如果是目标院校150分能过,而且这道题是两百分的话我就阿弥陀佛了。 这类简单类型的字符串处理题目一看就有思路,起码能做,遇到那种稍微加点数学的,感…

【STM32 HAL库】MPU6050姿态解算 卡尔曼滤波

【STM32 HAL库】MPU6050姿态解算 卡尔曼滤波 前言MPU6050寄存器代码详解mpu6050.cmpu6050.h 使用说明 前言 本篇文章基于卡尔曼滤波的原理详解与公式推导,来详细的解释下如何使用卡尔曼滤波来解算MPU6050的姿态 参考资料:Github_mpu6050 MPU6050寄存器…

C语言中的文件操作:从基础到深入底层原理

文件操作是几乎所有应用程序的重要组成部分,特别是在系统级编程中。C语言因其高效、灵活以及接近硬件的特点,成为了文件操作的理想选择。本文将全面深入地探讨C语言中的文件操作,从文件系统的概念到具体的文件操作函数,再到底层的…

外包干了2年,技术原地踏步。。。。。

先说一下自己的情况,本科生,19年通过校招进入南京某软件公司,干了接近2年的功能测试,今年年初,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了2年的功能测试&…

020 elasticsearch7.10.2 elasticsearch-head kibana安装

文章目录 全文检索流程ElasticSearch介绍ElasticSearch应用场景elasticsearch安装允许远程访问设置vm.max_map_count 的值 elasticsearch-head允许跨域 kibana 商品数量超千万,数据库无法使用索引 如何使用全文检索: 使用lucene,在java中唯一…