C/C++ x64 Inline Hook 代码封装
Hook 技术常被叫做挂钩技术,挂钩技术其实早在DOS时代就已经存在了,该技术是Windows系统用于替代DOS中断机制的具体实现,钩子的含义就是在程序还没有调用系统函数之前,钩子捕获调用消息并获得控制权,在执行系统调用之前执行自身程序,简单来说就是函数劫持.
接着来研究一下64位程序的Hook,64位与32位系统之间无论从寻址方式,还是语法规则都与x32架构有着本质的不同,所以上面的使用技巧只适用于32位程序,注入32位进程使用,下面的内容则是64位下手动完成Hook挂钩的一些操作手法,由于64位编译器无法直接内嵌汇编代码,导致我们只能调用C库函数来实现Hook的中转.
该笔记是针对64位Hook的简易封装,自己留着也没什么意思,还是分享出来吧,转载请加出处,谢谢!
简单实现64位Hook去弹窗: 由于64位编译器无法直接内嵌汇编代码,所以在我们需要Hook时只能将跳转机器码以二进制字节方式写死在程序里,如下代码是一段简单的演示案例,主要实现了去弹窗的功能.
#include <stdio.h>
#include <Windows.h>
BYTE OldCode[12] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
BYTE HookCode[12] = { 0x48, 0xB8, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0xFF, 0xE0 };
DWORD_PTR base;
int WINAPI MyMessageBoxW(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
{
return 1;
}
int main(int argc,char * argv[])
{
HMODULE hwnd = GetModuleHandle(TEXT("user32.dll"));
DWORD_PTR base = (DWORD_PTR)GetProcAddress(hwnd, "MessageBoxW");
DWORD OldProtect;
if (VirtualProtect((LPVOID)base, 12, PAGE_EXECUTE_READWRITE, &OldProtect))
{
memcpy(OldCode, (LPVOID)base, 12); // 拷贝原始机器码指令
*(PINT64)(HookCode + 2) = (INT64)&MyMessageBoxW; // 填充90为指定跳转地址
}
memcpy((LPVOID)base, &HookCode, sizeof(HookCode)); // 拷贝Hook机器指令
MessageBoxW(NULL, L"hello lyshark", NULL, NULL);
return 0;
}
64位Hook代码完整版: 接着我们在上面代码的基础上,继续进行完善,添加恢复钩子的功能,该功能时必须要有的,因为我们还是需要调用原始的弹窗代码,所以要在调用时进行暂时恢复,调用结束后再继续Hook挂钩.
#include <stdio.h>
#include <Windows.h>
void Hook();
void UnHook();
BYTE Ori_Code[12] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
BYTE HookCode[12] = { 0x48, 0xB8, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0xFF, 0xE0 };
/* Hook 机器码的原理如下所示
MOV RAX, 0x9090909090909090
JMP RAX
*/
static int (WINAPI *OldMessageBoxW)(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType) = MessageBoxW;
int WINAPI MyMessageBoxW(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
{
UnHook(); // 恢复Hook
int ret = OldMessageBoxW(hWnd, TEXT("Hook Inject"), lpCaption, uType); // 调用原函数
Hook(); // 继续hook
return ret;
}
void Hook()
{
DWORD OldProtect;
if (VirtualProtect(OldMessageBoxW, 12, PAGE_EXECUTE_READWRITE, &OldProtect))
{
memcpy(Ori_Code, OldMessageBoxW, 12); // 拷贝原始机器码指令
*(PINT64)(HookCode + 2) = (INT64)&MyMessageBoxW; // 填充90为指定跳转地址
}
memcpy(OldMessageBoxW, &HookCode, sizeof(HookCode)); // 拷贝Hook机器指令
}
void UnHook()
{
memcpy(OldMessageBoxW, &Ori_Code, sizeof(Ori_Code)); // 恢复hook原始代码
}
int main(int argc, char *argv [])
{
Hook();
MessageBoxW(NULL, TEXT("hello lyshark"), TEXT("MsgBox"), MB_OK);
UnHook();
MessageBoxW(NULL, TEXT("hello lyshark"), TEXT("MsgBox"), MB_OK);
return 0;
}
完整版DLL注入钩子: 最后将上面所写的代码进行封装,实现一个完整的钩子处理程序,代码如下.
#include <stdio.h>
#include <Windows.h>
BYTE OldCode[12] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
BYTE HookCode[12] = { 0x48, 0xB8, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0xFF, 0xE0 };
void Hook(LPCWSTR lpModule, LPCSTR lpFuncName, LPVOID lpFunction)
{
DWORD_PTR FuncAddress = (UINT64)GetProcAddress(GetModuleHandle(lpModule), lpFuncName);
DWORD OldProtect = 0;
if (VirtualProtect((LPVOID)FuncAddress, 12, PAGE_EXECUTE_READWRITE, &OldProtect))
{
memcpy(OldCode, (LPVOID)FuncAddress, 12); // 拷贝原始机器码指令
*(PINT64)(HookCode + 2) = (UINT64)lpFunction; // 填充90为指定跳转地址
}
memcpy((LPVOID)FuncAddress, &HookCode, sizeof(HookCode)); // 拷贝Hook机器指令
VirtualProtect((LPVOID)FuncAddress, 12, OldProtect, &OldProtect);
}
void UnHook(LPCWSTR lpModule, LPCSTR lpFuncName)
{
DWORD OldProtect = 0;
UINT64 FuncAddress = (UINT64)GetProcAddress(GetModuleHandle(lpModule), lpFuncName);
if (VirtualProtect((LPVOID)FuncAddress, 12, PAGE_EXECUTE_READWRITE, &OldProtect))
{
memcpy((LPVOID)FuncAddress, OldCode, sizeof(OldCode));
}
VirtualProtect((LPVOID)FuncAddress, 12, OldProtect, &OldProtect);
}
int WINAPI MyMessageBoxW(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
{
// 首先恢复Hook代码
UnHook(L"user32.dll", "MessageBoxW");
int ret = MessageBoxW(0, L"hello lyshark", lpCaption, uType);
// 调用结束后,再次挂钩
Hook(L"user32.dll", "MessageBoxW", (PROC)MyMessageBoxW);
return ret;
}
bool APIENTRY DllMain(HANDLE handle, DWORD dword, LPVOID lpvoid)
{
switch (dword)
{
case DLL_PROCESS_ATTACH:
Hook(L"user32.dll", "MessageBoxW", (PROC)MyMessageBoxW);
break;
case DLL_PROCESS_DETACH:
UnHook(L"user32.dll", "MessageBoxW");
break;
}
return true;
}
针对Hook代码的封装: 上方的代码还是基于过程化的案例,为了能更加通用,我们将其封装成类,这样后期可以直接调用了.
// hook.h
#pragma once
#include <Windows.h>
#ifdef __cplusplus
extern "C"{
#endif
class MyHook
{
public:
FARPROC m_pfnOrig; // 保存函数地址
BYTE m_bOldBytes[12]; // 保存函数入口代码
BYTE m_bNewBytes[12]; // 保存Inlie Hook代码
public:
MyHook();
~MyHook();
BOOL Hook(LPCWSTR lpModule, LPCSTR lpFuncName, LPVOID lpFunction);
BOOL UnHook(LPCWSTR lpModule, LPCSTR lpFuncName);
};
#ifdef __cplusplus
}
#endif
// hook.cpp
#include "hook.h"
MyHook::MyHook()
{
BYTE OldCode[12] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
BYTE NewCode[12] = { 0x48, 0xB8, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0xFF, 0xE0 };
RtlMoveMemory(MyHook::m_bNewBytes, NewCode, 12);
memset(MyHook::m_bOldBytes, 0, 12);
m_pfnOrig = NULL;
}
MyHook::~MyHook()
{
m_pfnOrig = NULL;
ZeroMemory(MyHook::m_bNewBytes, 12);
ZeroMemory(MyHook::m_bOldBytes, 12);
}
BOOL MyHook::Hook(LPCWSTR lpModule, LPCSTR lpFuncName, LPVOID lpFunction)
{
DWORD_PTR FuncAddress = (UINT64)GetProcAddress(GetModuleHandle(lpModule), lpFuncName);
DWORD OldProtect = 0;
if (VirtualProtect((LPVOID)FuncAddress, 12, PAGE_EXECUTE_READWRITE, &OldProtect))
{
memcpy(m_bOldBytes, (LPVOID)FuncAddress, 12); // 拷贝原始机器码指令
*(PINT64)(MyHook::m_bNewBytes + 2) = (UINT64)lpFunction; // 填充90为指定跳转地址
}
memcpy((LPVOID)FuncAddress, &m_bNewBytes, sizeof(m_bNewBytes)); // 拷贝Hook机器指令
VirtualProtect((LPVOID)FuncAddress, 12, OldProtect, &OldProtect);
return TRUE;
}
BOOL MyHook::UnHook(LPCWSTR lpModule, LPCSTR lpFuncName)
{
DWORD OldProtect = 0;
UINT64 FuncAddress = (UINT64)GetProcAddress(GetModuleHandle(lpModule), lpFuncName);
if (VirtualProtect((LPVOID)FuncAddress, 12, PAGE_EXECUTE_READWRITE, &OldProtect))
{
memcpy((LPVOID)FuncAddress, m_bOldBytes, sizeof(m_bOldBytes));
}
VirtualProtect((LPVOID)FuncAddress, 12, OldProtect, &OldProtect);
return TRUE;
}
// main.cpp
#include <Windows.h>
#include "hook.h"
MyHook MsgHook;
int WINAPI MyMessageBoxW(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
{
// 首先恢复Hook代码
MsgHook.UnHook(L"user32.dll", "MessageBoxW");
int ret = MessageBoxW(0, L"Hook Inject", lpCaption, uType);
// 调用结束后,再次挂钩
MsgHook.Hook(L"user32.dll", "MessageBoxW", (PROC)MyMessageBoxW);
return ret;
}
int main(int argc, char * argv[])
{
// 开始Hook
MsgHook.Hook(L"user32.dll", "MessageBoxW", (PROC)MyMessageBoxW);
MessageBoxW(NULL, L"hello lyshark", L"Msg", MB_OK);
// 结束Hook
MsgHook.UnHook(L"user32.dll", "MessageBoxW");
return 0;
}
第二种封装方式: 接着我们将代码声明与实现合在一起,实现第二种封装方式.
// hook.h
#include <Windows.h>
class MyHook
{
public:
static UINT64 Hook(LPCWSTR lpModule, LPCSTR lpFuncName, LPVOID lpFunction)
{
UINT64 dwAddr = (UINT64)GetProcAddress(GetModuleHandle(lpModule), lpFuncName);
BYTE jmp[] =
{
0x48, 0xb8, // jmp
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, // address
0x50, 0xc3 // retn
};
ReadProcessMemory(GetCurrentProcess(), (LPVOID)dwAddr, MemoryAddress(), 12, 0);
UINT64 dwCalc = (UINT64)lpFunction;
memcpy(&jmp[2], &dwCalc, 8);
WriteProcessMemory(GetCurrentProcess(), (LPVOID)dwAddr, jmp, 12, nullptr);
return dwAddr;
}
static BOOL UnHook(LPCWSTR lpModule, LPCSTR lpFuncName)
{
UINT64 dwAddr = (UINT64)GetProcAddress(GetModuleHandle(lpModule), lpFuncName);
if (WriteProcessMemory(GetCurrentProcess(), (LPVOID)dwAddr, MemoryAddress(), 12, 0))
return TRUE;
return FALSE;
}
static BYTE* MemoryAddress()
{
static BYTE backup[12];
return backup;
}
};
// main.cpp
#include <windows.h>
#include "hook.h"
MyHook MsgHook;
static int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType)
{
MsgHook.UnHook(L"user32.dll", "MessageBoxW");
int ret = MessageBox(hWnd, L"Hook Inject", lpCaption, uType);
MsgHook.Hook(L"user32.dll", "MessageBoxW", (PROC)MyMessageBoxW);
return ret;
}
int main(int argc, char * argv[])
{
MsgHook.Hook(L"user32.dll", "MessageBoxW", (PROC)MyMessageBoxW);
MessageBoxW(NULL, L"hello lyshark", L"MsgBox", MB_OK);
MsgHook.UnHook(L"user32.dll", "MessageBoxW");
MessageBoxW(NULL, L"hello lyshark", L"MsgBox", MB_OK);
return 0;
}
C/C++ x64 Inline Hook 代码封装的更多相关文章
- 小试X64 inline HOOK,hook explorer.exe--->CreateProcessInternalW监视进程创建
原始函数是这样的 kernel32!CreateProcessInternalW: 00000000`7738e750 4c8bdc mov r11,rsp 00000000 ...
- x86平台inline hook原理和实现
概念 inline hook是一种通过修改机器码的方式来实现hook的技术. 原理 对于正常执行的程序,它的函数调用流程大概是这样的: 0x1000地址的call指令执行后跳转到0x3000地址处执行 ...
- Android Hook框架adbi的分析(3)---编译和inline Hook实践
本文博客地址:http://blog.csdn.net/qq1084283172/article/details/75200800 一.序言 在前面的博客中,已经分析过了Android Hook框架a ...
- Windows下x86和x64平台的Inline Hook介绍
前言 我在之前研究文明6的联网机制并试图用Hook技术来拦截socket函数的时候,熟悉了简单的Inline Hook方法,但是由于之前的方法存在缺陷,所以进行了深入的研究,总结出了一些有关Windo ...
- windows 32位以及64位的inline hook
Tips : 这篇文章的主题是x86及x64 windows系统下的inline hook实现部分. 32位inline hook 对于系统API的hook,windows 系统为了达成hotpatc ...
- Inline Hook NtQueryDirectoryFile
Inline Hook NtQueryDirectoryFile 首先声明这个是菜鸟—我的学习日记,不是什么高深文章,高手们慎看. 都总是发一些已经过时的文章真不好意思,几个月以来沉迷于游戏也是时候反 ...
- android inline hook
最近终于沉下心来对着书把hook跟注入方面的代码敲了一遍,打算写几个博客把它们记录下来. 第一次介绍一下我感觉难度最大的inline hook,实现代码参考了腾讯GAD的游戏安全入门. inline ...
- x64内核HOOK技术之拦截进程.拦截线程.拦截模块
x64内核HOOK技术之拦截进程.拦截线程.拦截模块 一丶为什么讲解HOOK技术. 在32系统下, 例如我们要HOOK SSDT表,那么直接讲CR0的内存保护属性去掉. 直接讲表的地址修改即可. 但是 ...
- 在已有软件加壳保护 下实现 Inline hook
如写的不好请见谅,本人水平有限. 个人简历及水平:. http://www.cnblogs.com/hackdragon/p/3662599.html 正常情况: 接到一个项目实现对屏幕输出内容的获取 ...
- Inline Hook
@author: dlive IAT Hook时如果要钩取的API不在IAT中(LoadLibrary后调用),则无法使用该技术.而Inline Hook不存在这个限制. 0x01 Inline Ho ...
随机推荐
- WebRTC 的现状和未来:专访 W3C WebRTC Chair Bernard Aboba
WebRTC 无疑推动和改变了互联网视频,而这仅仅是刚刚开始,除了大家熟悉的 WebRTC-PC.Simulcast 和 SVC,有太多的新技术和新架构出现在 WebRTC 新的标准中,比如 WebT ...
- 拥抱智能,AI 视频编码技术的新探索
随着视频与交互在日常生活中的作用日益突显,愈发多样的视频场景与不断提高的视觉追求对视频编码提出更高的挑战.相较于人们手工设计的多种视频编码技术,AI 编码可以从大数据中自我学习到更广泛的信号内在编码规 ...
- 关于 VS Code 用户自定义代码片段的官方 $ 命令记录
关于 VS Code 的定义用户代码片段的部分 $ 命令 TM_SELECTED_TEXT:当前选定的文本或空字符串: 注:选定后通过在命令窗口点选「插入代码片段」插入. TM_CURRENT_LIN ...
- java实现mysqlplus查询一个月之间的数据
先说需求使用mysqlplus查询一个月之内的数据,传入的参数是202108 要求就查8月份这个月的所有数据,oracle数据中数据记录的时间类型是Date类型 public static void ...
- d3条形图案例
- proxy配置多个代理
https://blog.csdn.net/h_hongai/article/details/109311786
- C#通过泛型实现对子窗体的不同操作
private void button1_Click(object sender, EventArgs e) { FormOperate<object>();//调用FormOperate ...
- 基于python+django的旅游信息网站-旅游景点门票管理系统设计与实现
该系统是基于python+django开发的旅游景点门票管理系统.是给师弟做的课程作业.大家学习过程中,遇到问题可以在github咨询作者 演示地址 前台地址: http://travel.gitap ...
- [转帖]ipv6相关内核参数配置的优化实践
https://zhuanlan.zhihu.com/p/605217713 调整ARP缓存大小 这个参数通常需要在高负载的访问服务器上增加.比如繁忙的网络(或网关/防火墙 Linux 服务器),再比 ...
- Kubeadm 安装支持IPV6 K8S1.28.x的简单过程
Kubeadm 安装支持IPV6 K8S的简单过程 背景 手贱 找了一个晚上想尝试安装一个K8S集群 并且可以支持IPV6 协议栈的 然后就开始各种百度. 各种处理 找到了一堆歪门邪道. 但是还不知道 ...