2.10 PE结构:重建重定位表结构

Relocation(重定位)是一种将程序中的一些地址修正为运行时可用的实际地址的机制。在程序编译过程中,由于程序中使用了各种全局变量和函数,这些变量和函数的地址还没有确定,因此它们的地址只能暂时使用一个相对地址。当程序被加载到内存中运行时,这些相对地址需要被修正为实际的绝对地址,这个过程就是重定位。

在Windows操作系统中,程序被加载到内存中运行时,需要将程序中的各种内存地址进行重定位,以使程序能够正确地运行。Windows系统使用PE(Portable Executable)文件格式来存储可执行程序,其中包括重定位信息。当程序被加载到内存中时,系统会解析这些重定位信息,并将程序中的各种内存地址进行重定位。

重定位表一般出现在DLL中,因为DLL都是动态加载,所以地址不固定,DLL的入口点在整个执行过程中至少要执行2次,一次是在开始时执行初始化工作,一次则是在结束时做最后的收尾工作,重定位表则是解决DLL的地址问题,为了能找到重定位表首先我们需要使用PeView工具查询DataDirectory数据目录表,在其中找到Base relocation字段,里面的0x00001800则是重定位表基地址;

我们通过使用WinHex工具定位到0x00001800即可看到重定位表信息,如下图中的1000代表的是重定位RVA地址,绿色的0104代表的则是重定位块的长度,后面则是每两个字节代表一个重定位块,0A是重定位地址,30则是重定位的类型,以此顺序向下排列。

重定位表也是分页排列的,每一页大小都是1000字节,通过使用FixRelocPage命令即可查询到当前程序中的重定位块信息,并以第一个为例,查询一下起始地址RVA为1000的页上,有哪些重定位结构,如下图所示;

其中的重定位RVA地址0000100A是用标黄色的1000加上标蓝色的0xA得到的。而修正RVA地址00003000加上模块基地址63FF0000+3000得到的则是第一个被修正的内存地址,读者可使用x64dbg跳转到该程序内自行确认。

重定位表的修复原理与IAT修复完全一致,我们需要分别读入脱壳前与脱壳后的两个程序,接着通过循环正确的重定位表信息,并依次覆盖到脱壳后的程序内,以此实现对重定位表的修复功能,实现代码如下所示;

#include <windows.h>
#include <stdio.h>struct TypeOffset
{WORD Offset : 12;       // 低12位代表重定位地址WORD Type : 4;          // 高4位代表重定位类型
};DWORD FileSize = 0;  // 定义文件大小
DWORD FileBase = 0;  // 保存文件的基地址// 定义全局变量,来存储DOS,NT,Section头
PIMAGE_DOS_HEADER DosHeader = nullptr;
PIMAGE_NT_HEADERS NtHeader = nullptr;
PIMAGE_FILE_HEADER FileHead = nullptr;// 将RVA转换为FOA的函数
DWORD RVAtoFOA(DWORD rva)
{auto SectionTables = IMAGE_FIRST_SECTION(NtHeader);    // 获取区段表WORD Count = NtHeader->FileHeader.NumberOfSections;    // 获取区段数量for (int i = 0; i < Count; ++i){// 判断是否存在于区段中DWORD Section_Start = SectionTables[i].VirtualAddress;DWORD Section_Ends = SectionTables[i].VirtualAddress + SectionTables[i].SizeOfRawData;if (rva >= Section_Start && rva < Section_Ends){// 找到之后计算位置并返回值return rva - SectionTables[i].VirtualAddress + SectionTables[i].PointerToRawData;}}return -1;
}// 打开PE文件
bool OpenPeFile(LPCSTR FileName)
{// 打开文件HANDLE Handle = CreateFileA(FileName, GENERIC_READ, NULL,NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if (Handle == INVALID_HANDLE_VALUE)return false;// 获取文件大小FileSize = GetFileSize(Handle, NULL);// 读取文件数据DWORD OperSize = 0;FileBase = (DWORD)new BYTE[FileSize];ReadFile(Handle, (LPVOID)FileBase, FileSize, &OperSize, NULL);// 获取DOS头并判断是不是一个有效的DOS文件DosHeader = (PIMAGE_DOS_HEADER)FileBase;if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE)return false;// 获取 NT 头并判断是不是一个有效的PE文件NtHeader = (PIMAGE_NT_HEADERS)(FileBase + DosHeader->e_lfanew);if (NtHeader->Signature != IMAGE_NT_SIGNATURE)return false;// 判断是不是一个32位文件if (NtHeader->OptionalHeader.Magic != 0x010B)return false;CloseHandle(Handle);return true;
}// 修复重定位表
void RepairFixReloc(char new_file[])
{DWORD base = NtHeader->OptionalHeader.ImageBase;// 1. 获取重定位表的 rvaDWORD RelocRVA = NtHeader->OptionalHeader.DataDirectory[5].VirtualAddress;// 2. 获取重定位表auto Reloc = (PIMAGE_BASE_RELOCATION)(FileBase + RVAtoFOA(RelocRVA));// 3. 遍历重定位表中的重定位块,以0结尾while (Reloc->SizeOfBlock != 0){// 3.1 输出分页基址printf("[↓] 分页基址: 0x%08X \n\n", Reloc->VirtualAddress);// 3.2 找到重定位项auto Offset = (TypeOffset*)(Reloc + 1);// 3.3 计算重定位项的个数// Reloc->SizeOfBlock 保存的是整个重定位块的大小 结构体 + 重定位项数组// Reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION) 得到单个数组大小// 上面的结果 \ 2 = 重定位项的个数,原因是重定位项的大小为两个字节DWORD Size = (Reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / 2;// 3.4 遍历所有的重定位项for (DWORD i = 0; i < Size; ++i){DWORD Type = Offset[i].Type;                  // 获取重定位类型,只关心为3的类型DWORD pianyi = Offset[i].Offset;              // 获取重定位的偏移值DWORD rva = pianyi + Reloc->VirtualAddress;   // 获取要重定位的地址所在的RVADWORD foa = RVAtoFOA(rva);                    // 获取要重定位的地址所在的FOADWORD fa = foa + FileBase;                    // 获取要重定位的地址所在的faDWORD addr = *(DWORD*)fa;                     // 获取要重定位的地址DWORD new_addr = addr - base + 0x1500000;     // 计算重定位后的数据: addr - oldbase + newbase// 将重定位后的数据写回缓冲区(文件)if (Offset[i].Type == 3)*(DWORD*)fa = new_addr;printf("\t [->] 重定位RVA: 0x%08X | 重定位FOA: 0x%08X | 重定位地址: 0x%08X | 修正地址: 0x%08X \n", rva, foa, addr, new_addr);}// 找到下一个重定位块Reloc = (PIMAGE_BASE_RELOCATION)((DWORD)Reloc + Reloc->SizeOfBlock);}// 保存修正后的文件NtHeader->OptionalHeader.ImageBase = 0x1500000;// 打开一个新文件HANDLE new_handle = CreateFileA(new_file, GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);if (new_handle == INVALID_HANDLE_VALUE)return;DWORD OperSize = 0;// 保存修正好的程序BOOL ret = WriteFile(new_handle, (LPVOID)FileBase, FileSize, &OperSize, NULL);if (ret == TRUE){printf("\n\n");CloseHandle(new_handle);printf("[*] 修复 %s 文件 \t 写入基址: %08X \t 总长度: %d \t 写入长度: %d \n", new_file, FileBase, FileSize, OperSize);}
}void Banner()
{printf(" ____        _ _     _   ____      _            \n");printf("| __ ) _   _(_) | __| | |  _ \\ ___| | ___   ___ \n");printf("|  _ \\| | | | | |/ _` | | |_) / _ \\ |/ _ \\ / __|\n");printf("| |_) | |_| | | | (_| | |  _ <  __/ | (_) | (__ \n");printf("|____/ \\__,_|_|_|\\__,_| |_| \\_\\___|_|\\___/ \\___|\n");printf("                                                \n");printf("Reloc 重定位表快速修复工具 \t By: LyShark \n");printf("Usage: BuildFix [原文件位置] [修复后文件位置] \n\n\n");
}int main(int argc, char* argv[])
{Banner();if (argc == 3){bool flag = OpenPeFile(argv[1]);if (true == flag){RepairFixReloc(argv[2]);}}return 0;
}

运行上述程序,读者可自行传入脱壳前的程序与脱壳后的程序,此时则会实现自动替换,如下图所示;

本文作者: 王瑞
本文链接: https://www.lyshark.com/post/3c1b31b5.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

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

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

相关文章

虚幻动画系统概述

本文主要整理一下高层次的概述&#xff0c;方便后续查阅 1.动画流程 DCC产出动画文件 -> UE动画导入 -> 动画蓝图驱动&#xff08;类似unity的动画状态机&#xff09; ->动画后处理蓝图驱动&#xff08;例如修型骨&#xff0c;骨骼矫正等后期处理&#xff09; 2.动…

数据结构与算法:树

目录 树 定义 结构 二叉树 定义 结构 形式 满二叉树 完全二叉树 存储 链式存储结构 数组 孩子节点 父节点 应用 查找 维持相对顺序 遍历 深度优先遍历 前序遍历 中序遍历 后序遍历 广度优先遍历 层序遍历 二叉堆 定义 自我调整 操作 插入加点 删…

左神算法之中级提升班(9)

目录 【案例1】 【题目描述】 【思路解析】 【代码实现】 【案例2】 【题目描述】 【思路解析 平凡解技巧 从业务中分析终止条件 重点】 【代码实现】 【案例3】 【题目描述】 【思路解析】 【案例4】 【题目描述】 【思路解析】 【代码实现】 【动态规划代码】…

使用SSH地址拉取远程仓库代码报下面的错误

说明&#xff1a;配置了SSH秘钥后&#xff0c;使用SSH地址克隆代码&#xff0c;依旧无法拉取代码&#xff0c;提示下面这个信息。 Their offer&#xff1a;ssh-rsa&#xff0c;ssh-dss fatal&#xff1a;Could not read from remote repository. Please make sure you have the…

sqlserver2012性能优化配置:设置性能相关的服务器参数

前言 sqlserver2012 长时间运行的话会将服务器的内存占满 解决办法 通过界面设置 下图中设置最大服务器内存 通过执行脚本设置 需要先开发开启高级选项配置才能设置成功 设置完成之后将高级选择配置关闭&#xff0c;还原成跟之前一样 --可以配置高级选项 EXEC sp_conf…

开源库源码分析:Okhttp源码分析(一)

开源库源码分析&#xff1a;OkHttp源码分析 导言 接下来就要开始分析一些常用开源库的源码了&#xff0c;作为最常用的网络请求库&#xff0c;OkHttp以其强大的功能深受Android开发者的喜爱&#xff08;比如说我&#xff09;&#xff0c;还有对该库进行二次封装而成的热门库&a…

前端设计模式基础笔记

前端设计模式是指在前端开发中经常使用的一些解决问题的模式或思想。它们是经过实践证明的最佳实践&#xff0c;可以帮助我们更好地组织和管理我们的代码。 一、单例模式&#xff08;Singleton Pattern&#xff09; 单例模式是一种创建型模式&#xff0c;它保证一个类只有一个…

⑩ vue新特性

ref 或者reactive ref相当于data methods props和context props &#xff01;&#xff01;&#xff01;setup中没有this关键字&#xff0c;使用context&#xff08;简写&#xff1a;ctx&#xff09;就是this 在steup中使用生命周期函数 Provide / Inject 1、原来是 a传…

基于YOLOv2和传感器的多功能门禁系统

文章和项目源码已经归档至【Github仓库&#xff1a;https://github.com/timerring/face-recognition-door 】或者公众号【AIShareLab】回复 人脸识别门禁 也可获取。 文章目录 1.系统制作方案概述1.1系统设计的立意1.2系统的主要组成1.3系统的制作方案1.3.1制作方案框图1.3.2制…

python-xpath语法-爬取彼岸图4k高清动漫壁纸

安装 pip install lxml导入 from lxml import etreexpath使用路径表达式提取html文档中的元素或元素集&#xff0c;然后元素通过沿路径path或步steps来选取数据 XPath常用语法格式 表达式描述div选取div元素的所有子元素/div选取根元素divul//li选取ul元素下的所有li子元素…

大数据-玩转数据-oracel字符串分割转化为多列

一、建表 create table split_string_test(id integer primary key,test_string varchar2(500) );二、插入测试数据 insert into split_string_test values(1, 10,11,12,13,14,22); insert into split_string_test values(2, 22,23,24); insert into split_string_test valu…

TMS320F280049最小系统原理图

TMS320F280049最小系统原理图 1.概述2. 典型的 F2800x 系统方框图3. 最小系统原理图设计3.1 封装和器件决策3.2 电源及去耦电容3.3 晶振3.4 GPIO3.5 ADC模块3.6 JTAG 最近做了个新车规项目&#xff0c;第一次接触TMS320F280049&#xff0c;记录一下&#xff0c;最小系统原理图设…

PostgreSQL 事务并发锁

文章目录 PostgreSQL 事务大家都知道的 ACID事务的基本使用保存点 PostgreSQL 并发并发问题MVCC PostgreSQL 锁机制表锁行锁 总结 PostgreSQL 事务 大家都知道的 ACID 在日常操作中&#xff0c;对于一组相关操作&#xff0c;通常要求要么都成功&#xff0c;要么都失败。在关系…

Linux下运行Jmeter压测

一、在Linux服务器先安装SDK 1、先从官网下载jdk1.8.0_131.tar.gz&#xff0c;再从本地上传到Linux服务器 2、解压&#xff1a;tar -xzf jdk1.8.0_131.tar.gz&#xff0c;生成文件夹 jdk1.8.0_131 3、在/usr/目录下创建java文件夹&#xff0c;再将 jdk1.8.0_131目录移动到/u…

长胜证券:十大流通股东占比例高好还是低好?

近年来&#xff0c;跟着我国本钱商场的不断发展&#xff0c;越来越多的投资者开始了解和关注股东占比这个目标。而在股东占比中&#xff0c;十大流转股东的持股份额是一个重要的目标。可是&#xff0c;关于投资者来说&#xff0c;十大流转股东占比是高好还是低好&#xff1f;本…

微信小程序+echart实现点亮旅游地图

背景 最近看抖音有个很火的特效就是点亮地图&#xff0c;去过哪些地方&#xff0c;于是乎自己也想做一个&#xff0c;结合自己之前做的以家庭为单位的小程序&#xff0c;可以考虑做一个家庭一起点亮地图的功能。 效果图 过程 1&#xff0c;首先就是得去下微信小程序适配的ec…

牛客: BM4 合并两个排序的链表

牛客: BM4 合并两个排序的链表 文章目录 牛客: BM4 合并两个排序的链表题目描述题解思路题解代码 题目描述 题解思路 以链表一为主链表,遍历两条链表 若当前链表二的节点val小于当前链表一的下一个节点val,则将链表链表二的该节点连到链表一的节点的下一个,链表一的当前节点往…

智慧工地:实现作业区域安全管控

智慧工地是围绕工程现场人、机、料、法、环及施工过程中质量、安全、进度、成本等各项数据满足工地多角色、多视角的有效监管,实现工程建设管理的降本增效。 建设工程安全文明施工与质量提升,全方位的监测施工人员、各类器械设备、消防安全隐患&#xff0c;并提前对风险进行预警…

CANoe-Model Editor无法修改ARXML文件的问题、E2E在SOME/IP通信中的使用问题

1、Model Editor无法修改ARXML文件的问题 在CANoe 15软件版本中,Communication Setup导入arxml文件后,可以在model editor中打开arxml并修改配置。关闭model editor后再打开,可以看到修改的配置被保存了。 但是,当我把arxml文件从Communication Setup中移除后,再导入。此…

MacBook苹果电脑重装、降级系统

1、下载balenaEtcher镜像启动盘制作工具 https://tails.net/etcher/balenaEtcher-portable.exe 2、选择从文件烧录选择下载好的Mac 镜像文件 百度网盘 请输入提取码&#xff08;Mac OS 10.10-12版本镜像文件&#xff09; 第二步选择目标磁盘&#xff0c;这里需要准备一块1…