【PE】inline hook的实现

news2024/11/17 23:52:48

【PE】inline hook的实现

hook思路

最基本的5字节的hook思路如下,有了这个思路,可以用更多的方式进行hook

  1. 通过修改目标函数开头的5个字节为jmp …,劫持程序执行流
  2. 跳转过去之后,再把API开头5字节改回来(UnHook)
  3. 然后调用这个API(这个时候栈帧还是原来的样子)
  4. API执行完毕后,返回到我们自己的函数上
  5. 根据需求修改API执行的结果
  6. 然后再进行Hook(将开头5字节改回来)
  7. 最后返回到最初函数调用的地方,等待下次调用

hook方式

1.five bytes hook

在x86的ms库中,大部分的库函数的前5字节是可有可无的数据

USER32.dll:77280C10 mov     edi, edi
USER32.dll:77280C12 push    ebp
USER32.dll:77280C13 mov     ebp, esp

这里用vs编译一个最简单的MessageBoxA来调试

#include<Windows.h>

int main() {
	MessageBoxA(NULL, "woodwhale", "Title", S_OK);
	return 0;
}

call MessageBoxA的位置下个断点,然后F7步入,可以看到如下的汇编

image-20230422231648595

mov edi, edi这种汇编纯纯的没用

push ebp; mov ebp, esp;,抬栈操作,往上抬一个新的执行空间

从第5个字节开始,才是MessageBoxA这个函数真正有效的执行流。

如果我们将上面的5字节给patch成jmp ....跳转到某个函数,那么就成功hook了

计算jmp偏移

注意,jmp有三种跳转形式:

  1. 短跳转(Short Jmp,只能跳转到256字节的范围内),对应机器码:EB

  2. 近跳转(Near Jmp,可跳至同一段范围内的地址),对应机器码:E9

  3. 远跳转(Far Jmp,可跳至任意地址),对应机器码: EA

其中,短跳转和近跳转都是eip的相对偏移

由于新写入的jmp指令一共5字节,所以执行完这条指令后,eip会加上5,然后再加上jmp的操作数,前往目的地址

被hook函数地址 + 5 + jmp偏移 = 目的函数地址

所以jmp的偏移量为目的函数地址 - 被hook函数地址 - 5

写内存

由于要修改的代码位于PE文件的代码段,而PE文件载入内存时默认代码段的权限为RX(可读可执行),所以得用VirtualProtect来改代码端的权限(和linux中的mprotect异曲同工)

来看看函数原型

BOOL VirtualProtect(  
  LPVOID lpAddress,  //基地址:内存起始位置,也就是要修改代码的地址
  DWORD dwSize,  //    长度  :要修改多少个字节的属性,此处为一条jmp指令的长度5字节
  DWORD flNewProtect,  //    新保护属性  :修改后的内存保护属性,此处为64代表“可执行可写”。
  PDWORD lpflOldProtect  //    旧保护属性:原始的内存保护属性
);   

将5字节的权限改为RWX(可读可写可执行),然后将jmp指令给写进去,写完之后再把权限改回来

实现

#include<Windows.h>
#include<stdio.h>

FARPROC MsgBoxAddr;
BYTE PatchCode[7] = { 0xe9,0 };
BYTE OldCode[7] = { 0 };
DWORD OldState;

void hook();
int WINAPI backdoor(HWND hWnd,
	LPCSTR lpText,
	LPCSTR lpCaption,
	UINT uType);
void main();

void hook() {
	// 获取user32.dll中的MessageBoxA函数地址
	MsgBoxAddr = GetProcAddress(GetModuleHandle(L"user32.dll"), "MessageBoxA");
	// 计算需要hook到的函数地址
	DWORD targetAddr = DWORD(&backdoor) - DWORD(MsgBoxAddr) - 5;
	memcpy(&(*(PatchCode + 1)), &targetAddr, 4);
	printf("jmp to %x\n", *((ULONG*)(PatchCode + 1)));
	// 读取原本的5字节数据
	ReadProcessMemory(GetCurrentProcess(), MsgBoxAddr, OldCode, 5, nullptr);
	for (int i = 0; i < 5; i++) {
		printf("%x ", OldCode[i]);
		if (i == 4) {
			printf("\n");
		}
	}
	// 申请写的权限,写入需要patch的字节数据
	VirtualProtect(MsgBoxAddr, 6, PAGE_EXECUTE_READWRITE, &OldState);
	WriteProcessMemory(GetCurrentProcess(), MsgBoxAddr, PatchCode, 5, nullptr);
	// 恢复权限
	VirtualProtect(MsgBoxAddr, 6, OldState, &OldState);
}

int WINAPI backdoor(
	HWND hWnd,
	LPCSTR lpText,
	LPCSTR lpCaption,
	UINT uType
) {
	puts("Successful Hook!");
	// 写入oldCode,暂时恢复MessageBoxA函数
	for (int i = 0; i < 5; i++) {
		printf("%x ", OldCode[i]);
		if (i == 4) {
			printf("\n");
		}
	}
	WriteProcessMemory(GetCurrentProcess(), MsgBoxAddr, OldCode, 5, nullptr);
	MessageBoxA(NULL, "Hook", "Successful", MB_OK);
	// 恢复hook
	WriteProcessMemory(GetCurrentProcess(), MsgBoxAddr, PatchCode, 5, nullptr);
	return 0;
}

void main() {
	hook();	// inline_hook
	MessageBoxA(NULL, "woodwhale", "Title", S_OK);
}

效果

image-20230423011703841

使用IDA动调看看关键部分,成功写入jmp backdoor

image-20230423012039195

2.six bytes hook

6字节的hook原理同上,将jmp ... 的指令改写为push ...; ret;的方式

但是由于上述MessageBox这种函数上方只有5字节的地址可以写,所以得针对热补丁的形式进行hook。

热补丁的函数上方有较多的nopint 3,将这些无关紧要的字节给hook成push ...; ret;的方式

3.seven bytes hook

原理同上,只不过使用mov eax, addr; jmp eax;的方式。

这种hook的方式会占用一个寄存器的存储空间。

总结

上述提及的代码以及hook方式都是基于x86架构下的,针对x64架构,其实也有对应的inline hook

x86 InlineHookretjmp regjmp offset
影响字节数6 字节7 字节5 字节
影响寄存器影响一个寄存器的值
通用性通用通用通用
x64 InlineHookretjmp regjmp offset
影响字节数14 字节12 字节6 字节
影响寄存器影响一个寄存器的值
通用性通用通用寻址范围低

通常情况下 x64 使用 ret 方式,x86 使用 jmp offset 方式即可

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

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

相关文章

Servlet 入门到精通(六)

上一篇博客的传送门&#xff1a;Servlet 入门到精通&#xff08;五&#xff09; Servlet Filter 又称 Servlet 过滤器&#xff0c;它是在 Servlet 2.3 规范中定义的&#xff0c;是 Servlet 中的一个组件&#xff0c;是设计模式中责任链模式的一种经典实现。能够对 Servlet 容器…

SpringBoot启动自动执行sql脚本

在开发当中我们每次发布服务都需要手动执行脚本&#xff0c;然后重启服务&#xff0c;而SpringBoot有服务启动自动执行sql脚本的功能的&#xff0c;可以为我们省去手动执行脚本的这一步&#xff0c;只需要部署新的服务即可。 这个功能是SpringBoot自带的不需要引入额外的依赖&a…

Spring Boot 提取内存密码

访问 /actuator/heapdump 下载内存&#xff0c;提取密码 select * from java.util.LinkedHashMap$Entry x WHERE (toString(x.key).contains("password"))

学习系统编程No.21【进程间通信之共享内存】

引言&#xff1a; 北京时间&#xff1a;2023/4/16/21:53&#xff0c;刚刚把新文章发出去&#xff0c;开完班会回来&#xff0c;本来上篇博客在昨天就能发的&#xff0c;昨天下午打了一下午的羽毛球之后&#xff0c;饭都没吃&#xff0c;躺在床上&#xff0c;准备睡觉&#xff…

Spring五大类注解 || Bean的更简单存储

目录 前言&#xff1a; 五大类注解 Controller Service Repository Component Configuration JavaEE标准分层 阿里分层结构 BeanName命名规则 方法注解 Bean 注入方式取Bean 属性注入 Setter注入 构造方法注入 Resource 前言&#xff1a; 使用Spring容器&…

Linux-驱动开发-基础温习

一、裸机开发和驱动开发的区别&#xff1a; 裸机开发&#xff1a;底层&#xff08;相对于linux来说&#xff09;&#xff0c;库 二、linux驱动开发-根据各种框架进行开发 1、 外设比较多&#xff0c;资源多&#xff0c;资料非常少&#xff0c;官方的SDK;直接操作寄存器不显示…

Python 基础(十):元组

❤️ 博客主页&#xff1a;水滴技术 &#x1f338; 订阅专栏&#xff1a;Python 入门核心技术 &#x1f680; 支持水滴&#xff1a;点赞&#x1f44d; 收藏⭐ 留言&#x1f4ac; 文章目录 一、声明元组二、访问元组三、修改元组变量四、遍历元组五、切片六、常用函数和方法6.…

SpringBoot实现导出Excel功能

1 问题背景 需求要做一个导出excel的功能 2 前言 本篇着重阐述后端怎么实现&#xff0c;前端实现的部分只会粗略阐述。该实现方案是经过生产环境考验的&#xff0c;不是那些拿来练手的小demo。本文阐述的方案可以借鉴用来做毕设或者加到自己玩的项目中去。 3 实现思路 后端查询…

103. 二叉树的锯齿形层序遍历【191】

难度等级&#xff1a;中等 上一篇算法&#xff1a; 104. 二叉树的最大深度【75】 力扣此题地址&#xff1a; 103. 二叉树的锯齿形层序遍历 - 力扣&#xff08;Leetcode&#xff09; 1.题目&#xff1a;103. 二叉树的锯齿形层序遍历 给你二叉树的根节点 root &#xff0c;返回其…

p65 内网安全-域环境工作组局域网探针方案

数据来源 基本概念 DMZ区域&#xff1a;称为“隔离区”&#xff0c;也称‘’非军事化区/停火区” 工作组&#xff08;Work Group&#xff09;是局域网中的一个概念。它是最常见最简单最普通的资源管理模式&#xff0c;就是将不同的电脑按功能分别列入不同的组中&#xff0c;以…

完美解决丨except NameError:

示例如下&#xff1a; try: print(xx) except: print(xx is not defined) print(continue) 解决办法 第一种解决办法&#xff1a; try: print(xx) except NameError: print(xx is not defined) print(continue) 第二种解决办法&#xff1a; print(xx) if xx in locals() e…

camunda工作流user task如何使用

在Camunda中使用User Task通常需要以下步骤&#xff1a; 1、创建User Task&#xff1a;使用BPMN 2.0图形化设计器&#xff08;如Camunda Modeler&#xff09;&#xff0c;将User Task元素拖到流程图中&#xff0c;并为任务命名&#xff0c;指定参与者&#xff08;用户或用户组…

第二章 Maven 核心程序解压和配置

第一节 Maven核心程序解压与配置 1、Maven 官网地址 首页&#xff1a; Maven – Welcome to Apache Maven(opens new window) 下载页面&#xff1a; Maven – Download Apache Maven(opens new window) 下载链接&#xff1a; 具体下载地址&#xff1a;https://dlcdn.apac…

算法:(力扣)(牛客)打印螺旋矩阵题

手撕螺旋矩阵 题目思路解题 题目 描述&#xff1a;给定一个m x n大小的矩阵&#xff08;m行&#xff0c;n列&#xff09;&#xff0c;按螺旋的顺序返回矩阵中的所有元素。数据范围&#xff1a;0 \le n,m \le 100≤n,m≤10&#xff0c;矩阵中任意元素都满足 |val| \le 100∣val…

makefile 规则的覆盖

makefile 中经常会使用规则的覆盖&#xff0c;同样一个target 可能有多个prerequisites&#xff0c;这种依赖关系可以放到一起&#xff0c;也可以分开指定。 例1&#xff1a; test1:echo "test111"test2:echo "test222"test3:echo "test333"he…

vsync-app 不稳定导致抖动

问题描述&#xff1a;跟对比机器对比uc 浏览器新闻页滑动场景&#xff0c;出现抖动 1、trace 看是没有丢帧&#xff0c;对比看送帧buffer 给到 SF 步调不够一致&#xff0c;从间隔较大的两个 送帧buffer看&#xff0c;发现vsync-app 时间比正常的要长3ms 左右&#xff0c;vsync…

网络交换机端口管理工具

如今&#xff0c;企业或组织级网络使用数百个交换机端口作为其 IT 基础架构的一部分来实现网络连接。这使得交换机端口管理成为日常网络管理任务的一部分。传统上&#xff0c;网络管理员必须依靠手动网络交换机端口管理技术来跟踪交换机及其端口连接状态。这种手动任务弊大于利…

基于斯坦福大学开源,从零搭建chatGPT

下载地址&#xff1a; https://huggingface.co/datasets/togethercomputer/RedPajama-Data-1T 预处理仓库&#xff1a;https://github.com/togethercomputer/RedPajama-Data 复刻ChatGPT&#xff01;斯坦福等开启红睡衣计划&#xff0c;开源1.2万亿token训练集 【新智元导读…

JAVA队列(Queue)用法附实例讲解

队列是什么 队列用于模拟队列这种数据结构&#xff0c;队列通常是指“先进先出”的容器。新元素插入&#xff08;offer&#xff09;到队列的尾部&#xff0c;访问元素&#xff08;poll&#xff09;操作会返回队列头部的元素。通常&#xff0c;队列不允许随机访问队列中的元素 …

【JavaWeb】Servlet(崔老师版)

文章目录 1.概述1.1 JavaWeb三大组件1.2 Servlet作用 2.ServletConfig接口3.Servlet接口3.1 实现Servlet的方式3.2 Servlet生命周期 4.HttpServlet抽象类6.ServletContext5.1 概述5.2 获取ServletContext5.3 JavaWeb四大域对象5.4 获取应用初始化参数5.5 ServletContext获取资源…