3.4 DLL注入:全局消息钩子注入

dll,注入,全局,消息,钩子 · 浏览次数 : 39

小编点评

**SetWindowHookEx 函数** SetWindowHookEx 函数是一个 Windows 系统函数,可用于让应用程序安装全局钩子。 **安装全局钩子的步骤:** 1. **获取钩子类型:** `idHook` 应指定要监视的事件类型,例如 `WH_CBT` 表示系统回调函数。 2. **获取钩子函数地址:** `lpfn` 指向要安装的钩子的地址。 3. **获取应用程序句柄:** `hMod` 指向包含钩子代码的 DLL 模块的句柄。 4. **设置钩子:** 调用 `SetWindowsHookEx` 函数将钩子注册到应用程序的窗口句柄。 5. **取消钩子:** 调用 `UnHookWindowsHookEx` 函数取消先前注册的钩子。 **判断当前进程是否是需要注入的进程:** 1. **调用 `GetFristModuleName()` 函数获取应用程序的父进程名称。 2. **比较父进程名称和目标进程名称:** 如果它们相等,则说明当前进程是需要注入的进程。 **示例代码:** ```cpp #include #include HHOOK global_Hook; LRESULT CALLBACK MyProc(int nCode, WPARAM wParam, LPARAM lParam) { // 处理钩子事件 return CallNextHookEx(global_Hook, nCode, wParam, lParam); } void SetHook() { global_Hook = SetWindowsHookEx(WH_CBT, MyProc, GetModuleHandleA("hook.dll"), 0); } void UnHook() { if (global_Hook) { UnhookWindowsHookEx(global_Hook); } } int main() { // 加载 DLL 模块 HMODULE hMod = LoadLibrary("hook.dll"); // 获取 SetHook 函数的地址 pSetHook SetHook = (pSetHook)GetProcAddress(hMod, "SetHook"); // 设置钩子 SetHook(); // 监听事件 while (true) { Sleep(1000); } // 卸载钩子 UnHook(); // 释放 DLL 模块 FreeLibrary(hMod); return 0; } ``` **注意:** * 安装全局钩子可能对所有进程造成影响,因此需要进行仔细的分析和测试。 * 钩子函数必须在应用程序退出时释放。 * 本代码仅供参考,可能需要根据实际情况进行修改。

正文

SetWindowHookEx 是Windows系统的一个函数,可用于让一个应用程序安装全局钩子,但读者需要格外注意该方法安装的钩子会由操作系统注入到所有可执行进程内,虽然该注入方式可以用于绕过游戏保护实现注入,但由于其属于全局注入所以所有的进程都会受到影响,而如果想要解决这个问题,则需要在DllMain()也就是动态链接库开头位置进行判断,如果是我们所需操作的进程则执行该DLL模块内的功能,如果不是则自动跳过不执行任何操作即可实现指定进程的注入方式。

首先我们先来看一下该函数的原型定义;

HHOOK SetWindowsHookEx(
  int       idHook,
  HOOKPROC  lpfn,
  HINSTANCE hMod,
  DWORD     dwThreadId
);

参数说明如下:

  • idHook:钩子类型,标识了钩子函数要监视哪种事件。可以是整数值或预定义的常量值(如WH_MOUSE、WH_KEYBOARD、WH_SHELL等)。
  • lpfn:钩子函数的地址。
  • hMod:把钩子函数插入挂钩链中的应用程序的句柄,该参数通常被设置为包含钩子函数代码的DLL模块的句柄。
  • dwThreadId:要设置钩子的线程标识符或进程标识符,如果为 0,则钩子通常与所有线程的输入消息联系起来。

在安装全局消息钩子时,读者需要在DLL中对外暴漏两个接口,其中SetHook()用于设置钩子,UnHook()则用于取消钩子,在DLL入口处,通过调用GetFristModuleName()我们可以判断当前进程是否为我们所需操作的进程,如果是则执行进程内的流程,如果不是则跳过执行,这个流程可以描述为如下样子,读者可自行将如下代码编译为DLL文件。

#include <iostream>
#include <TlHelp32.h>
#include <windows.h>
#include <tchar.h>

// 指定全局变量
HHOOK global_Hook;

// 判断是否是需要注入的进程
BOOL GetFristModuleName(DWORD Pid, LPCTSTR ExeName)
{
  MODULEENTRY32 me32 = { 0 };
  me32.dwSize = sizeof(MODULEENTRY32);
  HANDLE hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, Pid);

  if (INVALID_HANDLE_VALUE != hModuleSnap)
  {
    // 先拿到自身进程名称
    BOOL bRet = Module32First(hModuleSnap, &me32);

    // 对比如果是需要注入进程,则返回真
    if (!_tcsicmp(ExeName, (LPCTSTR)me32.szModule))
    {
      CloseHandle(hModuleSnap);
      return TRUE;
    }
    CloseHandle(hModuleSnap);
    return FALSE;
  }
  CloseHandle(hModuleSnap);
  return FALSE;
}

// 获取自身DLL名称
char* GetMyDllName()
{
  char szFileFullPath[MAX_PATH], szProcessName[MAX_PATH];

  // 获取文件路径
  GetModuleFileNameA(NULL, szFileFullPath, MAX_PATH);
  
  int length = strlen(szFileFullPath);

  // 从路径后面开始找\,即倒着找右斜杠
  for (int i = length - 1; i >= 0; i--)
  {
    // 找到第一个\就可以马上获取进程名称了
    if (szFileFullPath[i] == '\\')
    {
      i++;
      // 结束符\0不能少 即i=length
      for (int j = 0; i <= length; j++)
      {
        szProcessName[j] = szFileFullPath[i++];
      }
      break;
    }
  }
  return szProcessName;
}

// 设置全局消息回调函数
LRESULT CALLBACK MyProc(int nCode, WPARAM wParam, LPARAM lParam)
{
  return CallNextHookEx(global_Hook, nCode, wParam, lParam);
}

// 安装全局钩子 此处的 GetMyDllName()函数 可以是外部其他DLL,可将任意DLL进行注入
extern "C" __declspec(dllexport) void SetHook()
{
  global_Hook = SetWindowsHookEx(WH_CBT, MyProc, GetModuleHandleA(GetMyDllName()), 0);
}

// 卸载全局钩子
extern "C" __declspec(dllexport) void UnHook()
{
  if (global_Hook)
  {
    UnhookWindowsHookEx(global_Hook);
  }
}

// DLL 主函数
BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
  switch (ul_reason_for_call)
  {
    case DLL_PROCESS_ATTACH:
    {
      // 当DLL被加载时触发,判断当前自身父进程是否为 lyshark.exe 
      BOOL flag = GetFristModuleName(GetCurrentProcessId(), TEXT("lyshark.exe"));
      if (flag == TRUE)
      {
        MessageBoxA(0, "hello lyshark", 0, 0);
      }
      break;
    }
    case DLL_THREAD_ATTACH:
    {
      break;
    }
    case DLL_THREAD_DETACH:
    {
      break;
    }
    case DLL_PROCESS_DETACH:
    {
      // DLL卸载时自动清理
      UnHook();
      break;
    }
    default:
      break;
  }
  return TRUE;
}

接着我们需要编写一个专门用来加载该DLL的程序,在调用DLL之前,我们需要通过LoadLibrary()将此模块加载到内存中,并通过GetProcAddress(hMod, "SetHook")获取到该模块的中SetHook函数的内存地址,最后直接调用SetHook()安装一个全局钩子,实现安装的代码流程如下所示;

#include <iostream>
#include <windows.h>

int main(int argc, char* argv[])
{
    HMODULE hMod = LoadLibrary(TEXT("d://hook.dll"));

    // 挂钩
    typedef void(*pSetHook)(void);
    pSetHook SetHook = (pSetHook)GetProcAddress(hMod, "SetHook");
    SetHook();

    while (1)
    {
        Sleep(1000);
    }

    // 卸载钩子
    typedef BOOL(*pUnSetHook)(HHOOK);
    pUnSetHook UnsetHook = (pUnSetHook)GetProcAddress(hMod, "UnHook");
    pUnSetHook();

    FreeLibrary(hMod);
    return 0;
}

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

与3.4 DLL注入:全局消息钩子注入相似的内容:

3.4 DLL注入:全局消息钩子注入

SetWindowHookEx 是`Windows`系统的一个函数,可用于让一个应用程序安装全局钩子,但读者需要格外注意该方法安装的钩子会由操作系统注入到所有可执行进程内,虽然该注入方式可以用于绕过游戏保护实现注入,但由于其属于全局注入所以所有的进程都会受到影响,而如果想要解决这个问题,则需要在`DllMain()`也就是动态链接库开头位置进行判断,如果是我们所需操作的进程则执行该DLL模块内的功

4.3 IAT Hook 挂钩技术

IAT(Import Address Table)Hook是一种针对Windows操作系统的API Hooking 技术,用于修改应用程序对动态链接库(DLL)中导入函数的调用。IAT是一个数据结构,其中包含了应用程序在运行时使用的导入函数的地址。IAT Hook的原理是通过修改IAT中的函数指针,将原本要调用的函数指向另一个自定义的函数。这样,在应用程序执行时,当调用被钩子的函数时,实际上会执行

cmake构建32位应用程序

1. 背景介绍 2. 工具介绍 3. 环境搭建 4. MinGW编译器版本 1. 背景介绍 最近需要使用第三方动态库文件G33DDCAPI.dll进行二次开发。由于这个动态库文件生成的时间比较早,且只提供了32位的版本,并没有提供源代码。如果希望利用这个动态库进行开发,有两种解决方法: 编译64位应

深入理解 Python 虚拟机:协程初探——不过是生成器而已

在 Python 3.4 Python 引入了一个非常有用的特性——协程,在本篇文章当中我们将详细介绍一下 Python 协程的原理以及虚拟机具体的实现协程的方式。

[转帖]BASH编写入门与实例

1 2 3 4 5 6 7 8 9 10 怎么写shell脚本: 。使用任何编辑工具编写shell脚本 例如vi -#!/bin/bash #在第一行放置头格式说明 -#!/usr/bin/gawk //awk需要添加的头格式,让系统知道用什么方式去解析此文件 -#!/usr/local/bin/p

.NET周报 【3月第4期 2023-03-24】

国内文章 .NET应用系统的国际化-多语言翻译服务 https://www.cnblogs.com/tianqing/p/17232559.html 本文重点介绍了多语言翻译服务的设计和实现。文章描述了如何通过多语言翻译服务,将临时存储在数据库中的多语言词条,按支持的语言翻译成多语言词条。作者设计了

1.创建一个类,类A中定义了一个方法,该方法能接受3个参数根据参数判断是做加法还是减法并返回计算结果;

class A: def cal(self,x,y,z): if z=='+': return x+y if z=='-': return x-y else: print('error') a=A() b=a.cal(3,4,'+') print(b) 运行结果: 2.延伸:创建一个类,类B继承A类

[转帖].dockerignore

https://www.cnblogs.com/panpanwelcome/p/12603658.html 1 2 3 4 删除git 缓存 git rm -r --cached . git add . git commit -m 'update .gitignore' .dockerignore

[转帖]Oracle中有大量的sniped会话

https://www.cnblogs.com/abclife/p/15699959.html 1 2 3 4 5 6 7 SQL> select status ,count(*) from gv$session group by status; STATUS COUNT(*) KILLED 2 S

Ceph存储池管理

目录Ceph存储池1. Ceph的存储流程1. 数据写入2. 数据读取2. 资源池的配置2.1 资源池创建pgp是什么 (Placement Group for Placement purpose)2.2 绑定池类型关闭3. 对象的管理3.1 上传对象3.2 查看对象3.3 下载对象3.4 删除对象