[Hook] MinHook 빌드 및 사용 방법
Hooking을 쉽게 구현할수 있는 MinHook이라는 라이브러리가 존재하는데, 아래의 github 레포에서 다운받아 빌드하여 사용할 수 있음
https://github.com/TsudaKageyu/minhook/releases/tag/v1.3.4
Release v1.3.4 · TsudaKageyu/minhook
Improved error handling for enumerating and suspending threads. Visual Studio 2022 support. CMake support. Fixed compilation with Clang. Fixed compilation as C++ code.
github.com
링크에 접근한 후 Release / v1.3.4의 Source code를 다운받음
다운받은 Source code를 압축 해제하면 minhook-1.3.4\build\VC17 경로에 MinHookVC17.sln 파일이 존재하는데 해당 파일을 더블클릭하여 Visual Studio를 실행함
Visual Studio의 솔루션 탐색기를 확인해보면 2개의 프로젝트가 존재하는데 MinHook을 사용하기 위해서는 libMinHook을 Release로 빌드하여 사용하면됨
빌드 전에 프로젝트를 설정해야 하는 값이 존재하는데 아래와 같이 런타임 라이브러리를 다중 스레드 DLL로 설정함
Rlease로 빌드를 수행하면 아래와 같이 libMinHook.x64.lib 라이브러리가 빌드 되는 것을 확인할 수 있음
이제 해당 라이브러리와 MinHook.h 헤더 파일을 활용하여 손 쉽게 Hooking 코드를 구현할 수 있음
예를 들어 ForegroundWindow API를 주기적으로 호출하는 프로그램이 존재한다면 아래와 같이 ForegroundWindow의 return 값을 Null로 설정하여 항상 Null 값을 반환되게 후킹할 수 있음
주의사항으로는 MinHook 라이브러리 빌드 시 Release로 빌드하였다면 Hook 구현 코드도 Release로 빌드 해야함
#include "pch.h"
#if defined _M_X64
#pragma comment(lib, "libMinHook.x64.lib")
#elif defined _M_IX86
#pragma comment(lib, "libMinHook.x86.lib")
#endif
typedef HWND(WINAPI* GetForegroundWindow_t)();
GetForegroundWindow_t fpGetForegroundWindow = nullptr;
// 후킹 함수 정의: 항상 NULL 반환
HWND WINAPI HookedGetForegroundWindow() {
return NULL;
}
// 후킹 초기화 함수
DWORD WINAPI InitHook(LPVOID) {
// MinHook 초기화
if (MH_Initialize() != MH_OK) {
return 1;
}
// user32.dll에서 GetForegroundWindow 함수 주소 가져오기
HMODULE hUser32 = GetModuleHandleA("user32.dll");
if (!hUser32) {
return 1;
}
void* pTarget = GetProcAddress(hUser32, "GetForegroundWindow");
if (!pTarget) {
return 1;
}
// 후킹 생성
if (MH_CreateHook(pTarget, &HookedGetForegroundWindow, reinterpret_cast<void**>(&fpGetForegroundWindow)) != MH_OK) {
return 1;
}
// 후킹 활성화
if (MH_EnableHook(pTarget) != MH_OK) {
return 1;
}
return 0;
}
// DllMain 엔트리포인트
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hModule);
CreateThread(NULL, 0, InitHook, NULL, 0, NULL);
break;
case DLL_PROCESS_DETACH:
MH_DisableHook(MH_ALL_HOOKS);
MH_Uninitialize();
break;
}
return TRUE;
}
dllmain.cpp
#ifndef PCH_H
#define PCH_H
// 여기에 미리 컴파일하려는 헤더 추가
#include "framework.h"
#include <MinHook.h>
#include <Windows.h>
#endif //PCH_H
pch.h
#include <windows.h>
#include <iostream>
#include <thread>
#include <chrono>
void monitorForegroundWindow() {
while (true) {
HWND hWnd = GetForegroundWindow();
if (hWnd == NULL) {
std::cout << "[*] No foreground window" << std::endl;
}
else {
char title[256] = { 0 };
if (GetWindowTextA(hWnd, title, sizeof(title))) {
std::cout << "[*] Foreground window title: " << title << std::endl;
}
else {
std::cout << "[!] Failed to get window title." << std::endl;
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
}
int main() {
std::cout << "[*] Starting foreground window monitor..." << std::endl;
monitorForegroundWindow();
return 0;
}
target.cpp
해당 예제 코드를 빌드하기 위해서는 아래와 같이 별도의 프로젝트 설정을 통해 기존에 빌드하였던 MinHook의 라이브러리, 헤더 파일 링크가 필요함
C:\Windows\System32\mavinject.exe 프로그램을 사용하여 Injection을 수행하면 Hooking에 성공한 시점부터는 window를 찾지 못하는 것을 확인할 수 있음
mavinject.exe <Target PID> /INJECTRUNNING <HookDLL Path>
참고
https://ferretsecu.tistory.com/1
MinHook으로 API 후킹 간단하게 하기[1]
후킹하는 방법은 구글에서 검색하면 많이 찾을 수 있다.(대표적으로 http://reversecore.com/) 그런데 실제로 하기 어렵기도 하고, 64bit일 경우 안되는 경우가 있는데, 이럴 때 간편하게 할 수 있는 라이
ferretsecu.tistory.com