Windows에서 후킹을 하기 위해서 제공하는 함수들이 있다. 이것들은 모두 DLL 환경에서 제작되어야 한다. 후킹을 위한 DLL 프로젝트와 테스트를 위한 MFC 프로젝트가 필요하다.
DLL 프로젝트
일전에는 후킹을 위한 함수를 만들 때에 모두 전역 변수와 전역 함수를 사용하였지만 관리하기가 쉽지 않았다. 검색하다 보니 싱글톤 클래스 형식으로 정리된 자료가 있어서 해당 방식으로 구현했다. 전역으로 작업하는 것이 간단하기는 하나 클래스 형식으로 하는 것이 관리가 더 편하다.
case DLL_PROCESS_ATTACH:
if (hook_mouse_callback::instance()->attach(hModule))
cout << "hook success!!" << endl;
else
cout << "hook failed!!" << endl;
break;
bool attach(__in HINSTANCE module)
{
_hook = SetWindowsHookEx(WH_MOUSE_LL, proxy_function, module, 0);
return _hook != nullptr;
}
우선 DLL에 진입하면 DllMain()에서 Hooking 할 항목에 대해서 Attach를 해야 한다. 이때 사용하는 함수가 SetWindowsHookEx()다. 마우스, 키보드 혹은 윈도에 대해서 후킹이 가능하다. 마우스를 후킹 할 예정이기 때문에 WH_MOUSE_LL을 지정하였다. 키보드의 경우에는 WH_KEYBOARD_LL을 사용하면 된다.
두 번째 항목은 proxy_function은 후킹 이벤트가 발생했을 때 동작하는 함수를 지정하는 것이다.
LRESULT hook_mouse_callback::new_function(__in int code, __in WPARAM wParam, __in LPARAM lParam)
{
if (code < HC_ACTION)
return ::CallNextHookEx(_hook, code, wParam, lParam);
MOUSEHOOKSTRUCT* mouse_param = (MOUSEHOOKSTRUCT *)lParam;
switch (wParam)
{
case WM_LBUTTONUP:
cout << "left mouse button up!!" << endl;
if(callbackHookFunc)
callbackHookFunc(WM_LBUTTONUP, wParam, lParam);
break;
case WM_MOUSEMOVE:
cout << "left mouse move!!" << endl;
if (callbackHookFunc)
callbackHookFunc(WM_MOUSEMOVE, wParam, lParam);
}
return ::CallNextHookEx(_hook, code, wParam, lParam);
}
간단하게 LBUTTONUP과 MOUSEMOVE에 대해서만 동작하도록 하였다. 그대로 전달하도록 만들었기 때문에 조금 더 간략하게 수정할 수 있다.
void callback(CALLBACK_HOOKFUNC func)
{
hook_mouse_callback::instance()->set_callback_func(func);
}
후킹 한 내용을 응용 프로그램에서 가져다 사용할 수 있도록 CALLBACK 함수를 만들어 두었다.
EXE 프로젝트
만들어진 DLL을 사용하기 위해서는 해당 DLL을 불러와야 한다. DLL을 묵시적으로 연결하기 위해서는 ATTACH를 DLL진입 시 동작하는 것이 아닌 Start/Stop 함수를 별도로 만들어 관리하면 된다. 해당 프로젝트는 DLL이 로딩되는 순간 후킹이 시작되므로 명시적으로 Load/Free Library로 Start/Stop을 관리한다.
HMODULE module = LoadLibrary(L"event_hooking.dll");
if (module)
{
using FUNC_CALLBACK = void(*)(CALLBACK_HOOKFUNC);
FUNC_CALLBACK pfunc = (FUNC_CALLBACK)GetProcAddress(module, "callback");
pfunc(OnHookingMessage);
}
후킹은 LoadLibaray() 함수로 로딩되면 바로 시작된다. 후킹을 시작하면 브레이크 포인트를 사용하기 불편하기 때문에 (엄청 느려짐) 조작에 대해서 고민할 필요는 있다. 라이브러리의 CALLBACK 함수를 EXE에도 설정한다.
using CALLBACK_HOOKFUNC = void(*)(UINT msg, WPARAM wParam, LPARAM lParam);
HMODULE g_hook_module = nullptr;
void OnHookingMessage(UINT msg, WPARAM wParam, LPARAM lParam)
{
AfxGetApp()->m_pMainWnd->SendMessage(msg, wParam, lParam);
}
LBUTTONPU 이벤트를 전달할 것이므로 해당 이벤트를 생성해서 메시지 박스를 설정해 둔다.
void ChookingTestDlg::OnLButtonUp(UINT nFlags, CPoint point)
{
AfxMessageBox(L"LMouseButtonUp!!");
CDialogEx::OnLButtonUp(nFlags, point);
}
이제 마우스를 어디에서 클릭해도 해당 메시지가 뜬다. 물론 닫을 순 없다. 클릭하는 순간 또 LBUTTONUP 이벤트가 발생하기 때문이다. 이 부분은 자신에 맞게 잘 사용하자.
'코드 > C++' 카테고리의 다른 글
libjpeg 사용하기 (0) | 2022.08.23 |
---|---|
[C++] string ↔ wstring 변환 (4) | 2022.02.24 |
[C++] XMLLite를 이용한 XML 파일 읽어오기 (0) | 2021.11.08 |
[C++] 3점을 지나는 외접원의 중심점 구하기 (0) | 2021.04.20 |
[C++] Char의 형 변환 (0) | 2021.04.20 |