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

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

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 许可协议。转载请注明出处!

目录
相关文章
|
6月前
|
Java Spring
创建名为 'authFilterRegistration' 的bean时,该bean依赖于一个未满足的依赖关系
创建名为 'authFilterRegistration' 的bean时,该bean依赖于一个未满足的依赖关系
35 1
|
1月前
thinkphp5.1全局异常类封装
thinkphp5.1全局异常类封装
27 0
thinkphp5.1全局异常类封装
|
2月前
|
数据库
报错注入
报错注入
12 1
|
2月前
|
数据库
13、报错注入(Get)
13、报错注入(Get)
15 0
|
7月前
|
安全 API Windows
3.1 DLL注入:常规远程线程注入
动态链接库注入技术是一种特殊的技术,它允许在运行的进程中注入DLL动态链接库,从而改变目标进程的行为。DLL注入的实现方式有许多,典型的实现方式为远程线程注入,该注入方式的注入原理是利用了`Windows`系统中提供的`CreateRemoteThread()`这个API函数,该函数第四个参数是准备运行的线程,我们将`LoadLibrary()`函数填入其中,这样就可以执行远程进程中的`LoadLibrary()`函数,进而将我们自己准备的DLL加载到远程进程空间中执行,DLL在被装载后则会自动执行初始化部分。
73 0
|
3月前
|
C++
c++将一个类的回调函数注入到另一个类中的方法
c++将一个类的回调函数注入到另一个类中的方法
|
4月前
|
Python
关于SSTI模块注入的常见绕过方法
关于SSTI模块注入的常见绕过方法
75 0
|
7月前
|
Windows
3.2 DLL注入:远程APC异步注入
APC(Asynchronous Procedure Call)异步过程调用是一种`Windows`操作系统的核心机制,它允许在进程上下文中执行用户定义的函数,而无需创建线程或等待OS执行完成。该机制适用于一些频繁的、短暂的或非常细微的操作,例如改变线程优先级或通知线程处理任务。在`APC机制`中,当某些事件发生时(例如文件IO,网络IO或定时器触发),这些事件将被操作系统添加到一个`APC队列`中,该队列绑定到执行线程。在下一次发生`ALERTABLE`的事件时(例如调用SleepEx或SignalObjectAndWait时),OS将弹出`APC函数`并在执行线程上下文中调用该函数,并在执
56 0
|
7月前
|
安全 UED Windows
3.3 DLL注入:突破会话0强力注入
Session是`Windows`系统的一个安全特性,该特性引入了针对用户体验提高的安全机制,即拆分Session 0和用户会话,这种拆分`Session 0`和`Session 1`的机制对于提高安全性非常有用,这是因为将桌面服务进程,驱动程序以及其他系统级服务取消了与用户会话的关联,从而限制了攻击者可用的攻击面。
48 0
|
Shell 数据安全/隐私保护 iOS开发
代码注入(11)
代码注入(11)
123 0