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函數禁用和釋放鉤子。

#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函數,該函數內部通過調用自定義標題修改函數實現了將當前軟件標題替換爲破解版本,並返回給用戶。

#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進程中,即可實現監控進程的創建功能。

#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文件中,至此當有新進程被加載時則會彈出該進程的詳細路徑信息,如下圖所示;

本文作者: 王瑞
本文鏈接: https://www.lyshark.com/post/c425464c.html
版權聲明: 本博客所有文章除特別聲明外,均採用 BY-NC-SA 許可協議。轉載請註明出處!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章