【Windows系统编程】06.HotFixHook与进程通信(详解HotFixHook)

上一讲讲到的InlineHook,每次Hook的时候,都要读写两次内存(先Hook,再还原)这种Hook方式,性能比较低,今天我们讲的这种Hook方式,可以说是InlineHook的升级版本

HotFix(热补丁)

我们先来讲讲原理:

我们继续来看看目标程序反汇编:

770A8E19 | CC                       | int3                                    |
770A8E1A | CC                       | int3                                    |
770A8E1B | CC                       | int3                                    |
770A8E1C | CC                       | int3                                    |
770A8E1D | CC                       | int3                                    |
770A8E1E | CC                       | int3                                    |
770A8E1F | CC                       | int3                                    |
770A8E20 | 8BFF                     | mov edi,edi                             |
770A8E22 | 55                       | push ebp                                |
770A8E23 | 8BEC                     | mov ebp,esp                             |
770A8E25 | 833D 8C8C0D77 00         | cmp dword ptr ds:[770D8C8C],0           |
770A8E2C | 74 22                    | je user32.770A8E50                      |
770A8E2E | 64:A1 18000000           | mov eax,dword ptr fs:[18]               |
770A8E34 | BA 18930D77              | mov edx,user32.770D9318                 | edx:"榍\f"
770A8E39 | 8B48 24                  | mov ecx,dword ptr ds:[eax+24]           | ecx:"榍\f"
770A8E3C | 33C0                     | xor eax,eax                             |
770A8E3E | F0:0FB10A                | lock cmpxchg dword ptr ds:[edx],ecx     | edx:"榍\f", ecx:"榍\f"
770A8E42 | 85C0                     | test eax,eax                            |
770A8E44 | 75 0A                    | jne user32.770A8E50                     |
770A8E46 | C705 288D0D77 01000000   | mov dword ptr ds:[770D8D28],1           |
770A8E50 | 6A FF                    | push FFFFFFFF                           |
770A8E52 | 6A 00                    | push 0                                  |
770A8E54 | FF75 14                  | push dword ptr ss:[ebp+14]              |
770A8E57 | FF75 10                  | push dword ptr ss:[ebp+10]              |
770A8E5A | FF75 0C                  | push dword ptr ss:[ebp+C]               |
770A8E5D | FF75 08                  | push dword ptr ss:[ebp+8]               |
770A8E60 | E8 0BFEFFFF              | call <user32.MessageBoxTimeoutW>        |
770A8E65 | 5D                       | pop ebp                                 |
770A8E66 | C2 1000                  | ret 10                                  |

我们发现呢,在MessageBox API之前,还有一堆int3,而这些int3是没用的,我们是否能用这点空余的内存,来构造一个jmp指令,来跳转到我们HOOK的函数?

很明显,jmp(E9)指令占一个字节,32位环境下,地址也占4个字节,而这里int3的数目,足够让我们来构造一个指令了

  • 思路:

    MessageBox函数第一句指令,mov edi,edi 实际上在32位环境下并没有什么意义,我们利用这个指令的两个字节,跳转到他上面的5个字节,构造跳转到我们自己的函数地址

    这样的话,我们就要修改7个字节的数据

  • 实操演示:

    我们还是利用动态库,注入的方式完成Hook:

    dll:

    // dllmain.cpp : 定义 DLL 应用程序的入口点。
    #include "pch.h"BOOL hotFixHook(const WCHAR* pszModuleName, const char* pszFuncName, PROC pHookFunc) {//构造段跳转指令:BYTE ShortJmp[2] = { 0xEB,0xF9 };//替换5个int3的jmp指令:BYTE JmpCode[5] = { 0xE9,0, };HMODULE hModule = GetModuleHandle(pszModuleName);if (hModule == INVALID_HANDLE_VALUE) {MessageBox(NULL, L"打开进程失败", L"错误", NULL);return FALSE;}//获取函数地址FARPROC pFuncAddr = GetProcAddress(hModule, pszFuncName);//修改内存属性DWORD dwOldProcAddrProtect = 0;VirtualProtectEx(GetCurrentProcess(), (LPVOID)((DWORD)pFuncAddr - 5), 7, PAGE_EXECUTE_READWRITE, &dwOldProcAddrProtect);DWORD JmpAddr = (DWORD)pHookFunc - (DWORD)pFuncAddr;*(DWORD*)(JmpCode + 1) = JmpAddr;//修改内存memcpy((LPVOID)((DWORD)pFuncAddr - 5), JmpCode, 5);memcpy(pFuncAddr, ShortJmp, 2);//改回内存属性VirtualProtectEx(GetCurrentProcess(), pFuncAddr, 7, dwOldProcAddrProtect, &dwOldProcAddrProtect);return TRUE;
    }BOOL UnHook(const WCHAR* pszModuleName, const char* pszFuncName) {//构造段跳转指令:BYTE ShortJmp[2] = { 0x8B,0xFF };//替换5个int3的jmp指令:BYTE JmpCode[5] = { 0x90,0x90,0x90,0x90,0x90 };HMODULE hModule = GetModuleHandle(pszModuleName);if (hModule == INVALID_HANDLE_VALUE) {MessageBox(NULL, L"打开进程失败", L"错误", NULL);return FALSE;}//获取函数地址FARPROC pFuncAddr = GetProcAddress(hModule, pszFuncName);//修改内存属性DWORD dwOldProcAddrProtect = 0;VirtualProtectEx(GetCurrentProcess(), (LPVOID)((DWORD)pFuncAddr - 5), 7, PAGE_READWRITE, &dwOldProcAddrProtect);//修改内存memcpy((LPVOID)((DWORD)pFuncAddr - 7), JmpCode, 5);memcpy(pFuncAddr, ShortJmp, 2);//改回内存属性VirtualProtectEx(GetCurrentProcess(), pFuncAddr, 7, dwOldProcAddrProtect, &dwOldProcAddrProtect);return TRUE;
    }typedef int
    (WINAPI*fnMyMessageBox)(_In_opt_ HWND hWnd,_In_opt_ LPCWSTR lpText,_In_opt_ LPCWSTR lpCaption,_In_ UINT uType);int WINAPI
    MyMessageBox(_In_opt_ HWND hWnd,_In_opt_ LPCWSTR lpText,_In_opt_ LPCWSTR lpCaption,_In_ UINT uType) {//如果我们还是通过正常流程调用MessageBOx,就会进入死循环,这里通过函数指针的方式调用,跳过前两字节(我们构造的短跳转指令)fnMyMessageBox Func = (fnMyMessageBox)((DWORD)MessageBox + 2);int nRet = Func(NULL, L"Hook", L"Hook", NULL);return nRet;
    }BOOL APIENTRY DllMain( HMODULE hModule,DWORD  ul_reason_for_call,LPVOID lpReserved)
    {switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:hotFixHook(L"User32.dll", "MessageBoxW", (PROC)MyMessageBox);break;case DLL_THREAD_ATTACH:break;case DLL_THREAD_DETACH:break;case DLL_PROCESS_DETACH:break;}return TRUE;
    }

Hook测试:

运行目标程序:

运行目标程序

注入dll:

注入dll

Hook成功:

Hook成功

进程通信

1.文件映射

进程一:

// Process1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//#include <iostream>
#include <Windows.h>#define BUF_SIZE 256
TCHAR szName[] = L"WdigObject";int main()
{//为指定文件创建或打开命名或未命名的文件映射对象HANDLE hFileMap = CreateFileMapping(INVALID_HANDLE_VALUE,      //要从中创建文件映射对象的句柄NULL,                      //安全属性PAGE_READWRITE,    //指定文件映射对象的页面保护0,                      //文件映射对象的最大大小的高阶 DWORD BUF_SIZE,                  //文件映射对象最大大小的低序 DWORDszName                     //文件映射对象的名称);//将文件映射的驶入映射到调用进程的地址空间LPVOID lpMapAddr = MapViewOfFile(hFileMap,        //文件映射对象的句柄FILE_MAP_ALL_ACCESS,   //对文件映射对象的访问类型,用于确定页面的页面保护0,               //视图开始位置的文件偏移量的高顺序 DWORD 0,        //要开始视图的文件偏移量低序 DWORDBUF_SIZE             //要映射到视图的文件映射的字节数);CopyMemory(lpMapAddr, L"Hello FileMap", (wcslen(L"Hello FileMap")+1)*2);getchar();//从调用进程的地址空间中取消映射文件的映射视图。UnmapViewOfFile(lpMapAddr);CloseHandle(hFileMap);
}

进程二:

// Process2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//#include <iostream>
#include <Windows.h>#define BUF_SIZE 256
TCHAR szName[] = L"WdigObject";int main()
{//打开文件映射HANDLE hFileMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, szName);LPVOID lpBuffer = MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, BUF_SIZE);MessageBox(NULL, (LPCWSTR)lpBuffer, L"success", NULL);UnmapViewOfFile(lpBuffer);CloseHandle(hFileMap);
}

通信测试:

先运行进程一,在运行进程二:

通信成功:

通信成功

我们来看看文件映射完成进程通信的原理:

就是生成一个文件映射,两个进程都能访问这些内存,就完成了进程通信

2.命名管道

进程一:

// Process1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//#include <iostream>
#include <Windows.h>int main()
{//创建命名管道的实例,并返回后续管道操作的句柄HANDLE hPipe = CreateNamedPipe(L"\\\\.\\pipe\\Communication",          //管道的唯一名称PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,//打开模式PIPE_TYPE_BYTE,                        //管道模式1,                                     //可为此管道创建的最大实例数1024,                                  //要为输出缓冲区保留的字节数1024,                                  //要为输入缓冲区保留的字节数0,                                     //NULL                                   //安全属性);//创建一个事件HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);//使命名管道服务进程能够等待客户端进程连接到命名管道的实例OVERLAPPED ovlap;ZeroMemory(&ovlap, sizeof(ovlap));ovlap.hEvent = hEvent;if (!ConnectNamedPipe(hPipe, &ovlap)) {//这里需要注意,如果成功,也会报错if (GetLastError() != ERROR_IO_PENDING) {std::cout << "ConnectNamedPipe Failed Code:" << GetLastError() << std::endl;CloseHandle(hPipe);CloseHandle(hEvent);return -1;}}if (WaitForSingleObject(hEvent, INFINITE) == WAIT_FAILED) {std::cout << "WaitForSingleObject Error" << GetLastError() << std::endl;CloseHandle(hPipe);CloseHandle(hEvent);return -1;}CloseHandle(hEvent);char szBuffer[0x100] = { 0 };DWORD dwReadSize = 0;ReadFile(hPipe, szBuffer, 0x100, &dwReadSize, NULL);std::cout << szBuffer << std::endl;char WriteBuffer[] = "Hello";DWORD dwWriteSize = 0;WriteFile(hPipe, WriteBuffer, strlen(WriteBuffer) + 1, &dwWriteSize, NULL);system("pause");return 0;
}

进程二:

// Process2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//#include <iostream>
#include <Windows.h>int main()
{//等待命名管道if (!WaitNamedPipe(L"\\\\.\\pipe\\Communication",    //命名管道的名称NMPWAIT_WAIT_FOREVER             //函数等待命名管道实例可用的毫秒数)) {std::cout << "WaitNamedPipe Failed Code:" << GetLastError() << std::endl;return -1;}//创建或打开文件或 I/O 设备HANDLE hFile = CreateFile(L"\\\\.\\pipe\\Communication",     //要创建或打开的文件或设备的名称GENERIC_READ | GENERIC_WRITE,     //请求对文件或设备的访问权限NULL,                             //请求的文件或设备的共享模式NULL,                             //安全属性OPEN_EXISTING,                    //要对存在或不存在的文件或设备执行的操作FILE_ATTRIBUTE_NORMAL,            //文件或设备属性和标志NULL);char WriteBuffer[] = "Hello";DWORD dwWrittenByte = 0;WriteFile(hFile, WriteBuffer, strlen(WriteBuffer) + 1, &dwWrittenByte, NULL);char lpBuffer[0x100] = { 0 };DWORD dwReadBytes = 0;ReadFile(hFile, lpBuffer, 0x100, &dwReadBytes, NULL);std::cout << lpBuffer << std::endl;system("pause");return 0;}

通信测试:

先运行进程一,在运行进程二

通信成功:

通信成功

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

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

相关文章

Android3:布局

一。线性布局 创建项目Linear Layout Example activity_main.xml <?xml version"1.0" encoding"utf-8"?><LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"an…

‘VB6EXT.OLB’ could not be registered

打开VB6提示&#xff1a;‘VB6EXT.OLB’ could not be registered 解决办法&#xff1a; 用管理员打开。 实测可行。 参考&#xff1a;VB6 Error please help-VBForums

uni-app引入sortable列表拖拽,兼容App和H5,拖拽排序。

效果: 拖拽排序 背景&#xff1a; 作为一名前端开发人员&#xff0c;在工作中难免会遇到拖拽功能&#xff0c;分享一个github上一个不错的拖拽js库&#xff0c;能满足我们在项目开发中的需要&#xff0c;下面是我在uniapp中使用SortableJS的使用详细流程&#xff1b; vue开发…

TCP定制协议,序列化和反序列化

目录 前言 1.理解协议 2.网络版本计算器 2.1设计思路 2.2接口设计 2.3代码实现&#xff1a; 2.4编译测试 总结 前言 在之前的文章中&#xff0c;我们说TCP是面向字节流的&#xff0c;但是可能对于面向字节流这个概念&#xff0c;其实并不理解的&#xff0c;今天我们要介…

派森 #P122. 峰值查找

描述 给定一个长度为n的列表nums&#xff0c;请你找到峰值并返回其索引。数组可能包含多个峰值&#xff0c;在这种情况下&#xff0c;返回任何一个所在位置即可。 &#xff08;1&#xff09;峰值元素是指其值严格大于左右相邻值的元素。严格大于即不能有等于&#xff1b; &…

docker的资源控制及数据管理

docker的资源控制及docker数据管理 一.docker的资源控制 1.CPU 资源控制 1.1 资源控制工具 cgroups&#xff0c;是一个非常强大的linux内核工具&#xff0c;他不仅可以限制被 namespace 隔离起来的资源&#xff0c; 还可以为资源设置权重、计算使用量、操控进程启停等等。 …

kafka晋升之路-理论+场景

kafka晋升之路 一&#xff1a;故事背景二&#xff1a;核心概念2.1 系统架构2.2 生产者&#xff08;Producer&#xff09;2.2.1 生产者分区2.2.2 生产者分区策略 2.3 经纪人&#xff08;Broker&#xff09;2.3.1 主题&#xff08;Topic&#xff09;2.3.2 分区&#xff08;Partit…

07 - 查看、创建、切换和删除分支

查看所有文章链接&#xff1a;&#xff08;更新中&#xff09;GIT常用场景- 目录 文章目录 1. 查看分支2. 创建和切换分支3. 删除分支 1. 查看分支 git branch -va2. 创建和切换分支 第一种&#xff1a; 创建分支&#xff1a; git branch new_branch切换分支&#xff1a; …

代码生成综述

代码生成大模型属于LLM模型的一个子类&#xff0c;理论来讲也是属于语言模型的一种特例。代码本身其实也是一种特殊的语言表示&#xff0c;所以代码模型的实现应该是具备通用自然语言和代码两部分的能力。实际的代码模型也是有两条路径来实现&#xff0c;让训练好的NLP LLM模型…

【2023年11月第四版教材】《第5章-信息系统工程之软件工程(第二部分)》

《第5章-信息系统工程之软件工程&#xff08;第二部分&#xff09;》 1.3 软件设计1.4 软件实现&#xff3b;补充第三版教材内容&#xff3d; 1.5 部署交付 1.3 软件设计 1、结构化设计SD是一种面向数据流的方法&#xff0c;它以SRS和SA阶段所产生的DFD和数据字 典等文档为基础…

无人机精细化巡检方案制定:提高效率与准确性的关键

在当前技术日新月异的时代&#xff0c;无人机在多个领域的应用已成为行业标配。但如何制定出一套有效、细致的无人机巡检方案&#xff0c;确保其最大效能&#xff0c;成为许多组织与公司的核心议题。其中&#xff0c;复亚智能在此领域已展现出了卓越的实力与深入的见解。 1. 精…

TCP中窗口和滑动窗口的含义以及流量控制

一.窗口 在TCP中由于要保证可靠性&#xff0c;所以每发送一条数据后&#xff0c;都需要接收方返回一条应答报文&#xff0c;要是我们每发送一条数据&#xff0c;发送方就等待接收应答报文&#xff0c;收到之后再去发送下一条数据&#xff0c;这样我们就会花费大量的时间在等待应…

一文预览 | 8 月 16 日 NVIDIA 在 WAVE SUMMIT深度学习开发者大会 2023精彩亮点抢先看!

由深度学习技术及应用国家工程研究中心主办&#xff0c;百度飞桨和文心大模型承办的 WAVE SUMMIT深度学习开发者大会2023&#xff0c;将于 8 月 16 日在北京与大家见面。NVIDIA 作为技术合作伙伴&#xff0c;将携手百度飞桨参与这场技术盛会。 在这次大会中&#xff0c;NVIDIA…

【从零开始的rust web开发之路 二】axum中间件和共享状态使用

系列文章目录 第一章 axum学习使用 第二章 axum中间件使用 文章目录 系列文章目录前言一、中间件是什么二、中间件使用常用中间件使用中间件使用TraceLayer中间件实现请求日志打印自定义中间件 共享状态 前言 上篇文件讲了路由和参数相应相关的。axum还有个关键的地方是中间件…

微信小程序 游戏水平评估系统的设计与实现_pzbe0

近年来&#xff0c;随着互联网的蓬勃发展&#xff0c;游戏公司对信息的管理提出了更高的要求。传统的管理方式已无法满足现代人们的需求。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;随着各行业的不断发展&#xff0c;使命召…

【C++习题集】-- 堆

&#xff08;用于复习&#xff09; 目录 树概念及结构 名词概念 二叉树概念及结构 特殊的二叉树 满二叉树 完全二叉树 运算性质 二叉树存储结构 顺序存储 链式存储 堆 - 顺序存储 堆的性质 堆的实现 堆的应用 堆排序 直接建堆法 树概念及结构 概念&#xff1a…

【目标检测中对IoU的改进】GIoU,DIoU,CIoU的详细介绍

文章目录 1、IoU2、GIoU(Generalized Intersection over Union)3、DIoU4、CIoU 1、IoU IoU为交并比&#xff0c;即对于pred和Ground Truth&#xff1a;交集/并集 1、IoU可以作为评价指标使用&#xff0c;也可以用于构建IoU loss 1 - IoU 缺点&#xff1a; 2、对于pred和GT相…

[MySQL]主从服务器布置

配置主服务器 配置文件 /etc/my.cnf 在[mysqld]下进行配置 log_binON //启动二进制日志 log-bin mysql-bin //启用二进制日志&#xff0c;用于记录主服务器的更新操作 server-id 1 // 用来表示mysql服务id,保证集成环境中的唯一性 , 范围 [1,2^32) read-only0 // 1表示只…

ChatGLM-6B微调记录

目录 GLM-130B和ChatGLM-6BChatGLM-6B直接部署基于PEFT的LoRA微调ChatGLM-6B GLM-130B和ChatGLM-6B 对于三类主要预训练框架&#xff1a; autoregressive&#xff08;无条件生成&#xff09;&#xff0c;GPT的训练目标是从左到右的文本生成。autoencoding&#xff08;语言理解…

如何在windows电脑安装多个tomcat服务器和乱码问题

前提条件安装jdk 以17版本为例&#xff0c;将jdk8卸载干净 1.首先进入tomcat官网下载 tomcat网址 这里下载tomcat10为例子 1.1 这里选择方式一 下载解压版 2.解压后拷贝三份 分别命名为 8081、 8082、 8083 3.分别对每个tomcat执行以下操作 3.1 找到tomcat所在webapps文…