4.5 MinHook 挂钩技术

MinHook是一个轻量级的Hooking库,可以在运行时劫持函数调用。它支持钩子API函数和普通函数,并且可以运行在32位和64位Windows操作系统上。其特点包括易于使用、高性能和低内存占用。MinHook使用纯汇编语言实现,在安装和卸载钩子时只需要短暂地锁定目标线程,因此对目标线程的影响非常小。

读者可自行下载对应的库文件,本节所使用的是MinHook_133_lib版本,并配置好对应的包含文件以及库目录,如下图所示;

实现修改弹窗提示

如下一段代码其作用是hook MessageBoxA函数,当程序调用MessageBoxA时,会调用MyMessageBoxA函数代替原来的MessageBoxA函数进行处理,而MyMessageBoxA函数会将调用信息改成Hook Inject

示例中的SetHook函数用于创建并启用hook,使用MH_Initialize进行MinHook库初始化,然后使用MH_CreateHook创建钩子并保存MessageBoxA原函数指针到fpMessageBoxA中,最后使用MH_EnableHook启用hook。而UnHook函数用于禁用和释放hook,使用MH_DisableHook禁用钩子,然后使用MH_Uninitialize释放MinHook库资源。

DllMain函数中,如果是DLL进程附加事件,则执行SetHook函数,如果是DLL进程分离事件,则执行UnHook函数禁用和释放钩子。

c 复制代码
#include <Windows.h>
#include <MinHook.h>

#pragma comment(lib,"libMinHook-x86-v120-md.lib")

typedef int (WINAPI *OldMessageBox)(HWND, LPCSTR, LPCSTR, UINT);

OldMessageBox fpMessageBoxA = NULL;

// 自定义弹窗
int WINAPI MyMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
{
  int ret = fpMessageBoxA(hWnd, "Hook Inject hello lyshark", lpCaption, uType);
  return ret;
}

// 安装钩子
void SetHook()
{
  if (MH_Initialize() == MB_OK)
  {
    MH_CreateHook(&MessageBoxA, &MyMessageBoxA, reinterpret_cast<void**>(&fpMessageBoxA));
    MH_EnableHook(&MessageBoxA);
  }
}

// 卸载钩子
void UnHook()
{
  if (MH_DisableHook(&MessageBoxA) == MB_OK)
  {
    MH_Uninitialize();
  }
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
  switch (ul_reason_for_call)
  {
  case DLL_PROCESS_ATTACH:
    SetHook();
    break;
  case DLL_PROCESS_DETACH:
    UnHook();
    break;
  }
  return TRUE;
}

编译上述代码,使用注入器将hook.dll注入到特定进程内,此时点击弹窗提示会发现弹窗内容已经被替代了,如下图所示;

实现修改窗口标题

一般来说程序中的修改标题功能都是调用SetWindowTextA来实现的,我们可以Hook这个函数对其进行处理后返回新标题即可,当然也可以钩挂住GetWindowTextA函数,同样可以实现标题的修改。

如下代码通过对SetWindowTextA函数进行挂钩,当读者点击设置标题是则触发自定义fpSetWindowTextA函数,该函数内部通过调用自定义标题修改函数实现了将当前软件标题替换为破解版本,并返回给用户。

c 复制代码
#include <Windows.h>
#include <MinHook.h>

#pragma comment(lib,"libMinHook-x86-v120-md.lib")

typedef BOOL(WINAPI *OldSetWindowTextA)(HWND, LPCSTR);

OldSetWindowTextA fpSetWindowTextA = NULL;

BOOL WINAPI MySetWindowTextA(HWND hWnd, LPCSTR lpString)
{
  BOOL ret = fpSetWindowTextA(hWnd, "破解版本");
  return ret;
}

void SetHook()
{
  if (MH_Initialize() == MB_OK)
  {
    MH_CreateHook(&SetWindowTextA, &MySetWindowTextA, reinterpret_cast<void**>(&fpSetWindowTextA));
    MH_EnableHook(&SetWindowTextA);
  }
}

void UnHook()
{
  if (MH_DisableHook(&SetWindowTextA) == MB_OK)
  {
    MH_Uninitialize();
  }
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
  switch (ul_reason_for_call)
  {
  case DLL_PROCESS_ATTACH:
    SetHook();
    break;
  case DLL_PROCESS_DETACH:
    UnHook();
    break;
  }
  return TRUE;
}

当读者将hook.dll注入到程序中后,我们再次点击设置标题按钮,此时标题将被修改为破解版本,如下图所示;

实现监控进程创建

要实现监控进程创建,我们可以通过MinHook库来钩住explorer.exe程序,通过劫持程序内的CreateProcessW函数,在Windows操作系统中,大部分进程都是由 explorer.exe 进程派生出来的。explorer.exe 是Windows资源管理器的主进程,负责启动和管理用户界面、任务栏、桌面等。

当用户登录到系统后,explorer.exe 进程会自动启动,并成为用户交互的主要界面。在用户打开应用程序、文件夹或执行其他操作时,explorer.exe 进程会根据用户的请求创建新的进程来运行相应的应用程序或执行相应的任务。

通过对该进程进行挂钩,即可实现监控应用层其他进程创建或销毁的目的,读者可自行使用64位库编译下方代码,并注入到explorer.exe进程中,即可实现监控进程的创建功能。

c 复制代码
#include <Windows.h>
#include <MinHook.h>

#pragma comment(lib,"libMinHook-x64-v120-md.lib")

typedef int (WINAPI *OldCreateProcessW)(LPCWSTR, LPWSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL,
  DWORD, LPVOID, LPCWSTR, LPSTARTUPINFOW, LPPROCESS_INFORMATION);

OldCreateProcessW fpCreateProcessW = NULL;

int WINAPI MyCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,
  LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment,
  LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
{
  MessageBoxW(0, lpApplicationName, 0, 0);

  int nRetn = fpCreateProcessW(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes,
    bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
  return nRetn;
}

void SetHook()
{
  if (MH_Initialize() == MB_OK)
  {
    // 参数一: 函数名称
    // 参数二: 自定义函数
    // 参数三: 原始函数指针
    MH_CreateHook(&CreateProcessW, &MyCreateProcessW, reinterpret_cast<void**>(&fpCreateProcessW));
    MH_EnableHook(&CreateProcessW);
  }
}

void UnHook()
{
  if (MH_DisableHook(&CreateProcessW) == MB_OK)
  {
    MH_Uninitialize();
  }
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
  switch (ul_reason_for_call)
  {
  case DLL_PROCESS_ATTACH:
    SetHook();
    break;
  case DLL_PROCESS_DETACH:
    UnHook();
    break;
  }
  return TRUE;
}

读者可使用x64模式编译上方代码,并将其注入到explorer.exe文件中,至此当有新进程被加载时则会弹出该进程的详细路径信息,如下图所示;

相关推荐
追逐时光者10 小时前
推荐 12 款开源美观、简单易用的 WPF UI 控件库,让 WPF 应用界面焕然一新!
后端·.net
Jagger_10 小时前
敏捷开发流程-精简版
前端·后端
苏打水com10 小时前
数据库进阶实战:从性能优化到分布式架构的核心突破
数据库·后端
间彧11 小时前
Spring Cloud Gateway与Kong或Nginx等API网关相比有哪些优劣势?
后端
间彧11 小时前
如何基于Spring Cloud Gateway实现灰度发布的具体配置示例?
后端
间彧11 小时前
在实际项目中如何设计一个高可用的Spring Cloud Gateway集群?
后端
间彧12 小时前
如何为Spring Cloud Gateway配置具体的负载均衡策略?
后端
间彧12 小时前
Spring Cloud Gateway详解与应用实战
后端
EnCi Zheng13 小时前
SpringBoot 配置文件完全指南-从入门到精通
java·spring boot·后端
烙印60113 小时前
Spring容器的心脏:深度解析refresh()方法(上)
java·后端·spring