SetWindowsHookEx succeed but callback function is never called - c++

dll code:
LRESULT CALLBACK CBTNewProc(int nCode, WPARAM wParam, LPARAM lParam)
{
std::ofstream file;
file.open("E:\\enter.txt", std::ios::out);
file << nCode;
file.close();
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
extern "C" __declspec(dllexport) void installHook()
{
if (g_hHook != NULL){
UnhookWindowsHookEx(g_hHook);
g_hHook = NULL;
}
HINSTANCE hInstance = GetModuleHandle(NULL);
g_hHook = SetWindowsHookEx(WH_CBT, CBTNewProc, NULL, GetCurrentThreadId());
if (g_hHook == NULL)
{
MessageBox(NULL, L"fail!", L"caption", MB_OK);
}
else
{
MessageBox(NULL, L"install success!", L"caption", MB_OK);
}
}
I wrote another program to load this dll and called installHook. The message box "install success" is showed but the callback function was never called, enter.txt is not found under drive E.
I'm using Win7 + VS2013.

For a hook to be set in other processes, you must pass the hInstance of the DLL which contains the hook proc to SetWindowsHookEx.
You should also pass zero as the thread ID.

Related

Hook WH_GETMESSAGE message

I'm trying to hook WH_GETMESSAGE from my class to determine the moment when specific window is resizing. However, looks like the hook isn't set.
Class from where I try to hook:
class WindowDisplayHelper : // public ...
{
public:
// some other public methods here
void SetMsgHook();
protected:
LRESULT CALLBACK GetMsgProcHook(int code, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK MsgPoc(int code, WPARAM wParam, LPARAM lParam);
private:
// some other private members there
HWND m_windowHandle;
bool m_isWindowResizing = false;
static HHOOK m_msgHook;
static WindowsDisplayHelperMasterWindow* m_pThis;
};
.cpp file:
WindowDisplayHelper* WindowDisplayHelper ::m_pThis = nullptr;
HHOOK WindowDisplayHelper ::m_msgHook = NULL;
void WindowDisplayHelper ::SetMsgHook()
{
m_pThis = this;
m_msgHook = SetWindowsHookEx(WH_GETMESSAGE, MsgPoc, NULL, 0);
}
LRESULT CALLBACK WindowDisplayHelper::MsgPoc(int code, WPARAM wParam, LPARAM lParam)
{
if (m_pThis != nullptr)
{
return m_pThis->GetMsgProcHook(code, wParam, lParam);
}
return CallNextHookEx(0, code, wParam, lParam);
}
LRESULT CALLBACK WindowDisplayHelper::GetMsgProcHook(int code, WPARAM wParam, LPARAM lParam)
{
DUMPER_INFO("Hooked");
if (code < 0)
{
return CallNextHookEx(0, code, wParam, lParam);
}
MSG* lpmsg = (MSG*)lParam;
DUMPER_INFO("Hooked for HWND: %p. Current window %p", lpmsg->hwnd, m_windowHandle);
if (lpmsg->hwnd != m_windowHandle)
{
return CallNextHookEx(0, code, wParam, lParam);
}
if (lpmsg->message == WM_ENTERSIZEMOVE && !m_isWindowResizing)
{
DUMPER_INFO("Start window resizing");
m_isWindowResizing = true;
}
else if (lpmsg->message == WM_EXITSIZEMOVE && m_isWindowResizing)
{
DUMPER_INFO("Stop window resizing");
m_isWindowResizing = false;
}
return CallNextHookEx(0, code, wParam, lParam);
}
Here is how I create WindowDisplayHelper object:
bool DisplayManager::CreateWindowDisplay(TDisplayId displayId, void * windowHandle)
{
auto helper = boost::make_shared<WindowDisplayHelper>(windowHandle);
helper->SetMsgHook();
AddDisplayHelper(displayId, helper);
return true;
}
Though I call SetMsgHook() after the object is created, looks like hook isn't set, because I don't see any debug outputs in my log file and m_isWindowResizing variable always == false. So the question is why my hook doesn't work?
Thanks.
m_msgHook = SetWindowsHookEx(WH_GETMESSAGE, MsgPoc, NULL, 0);
This line produce a ERROR_HOOK_NEEDS_HMOD (1428) system error. It means that Cannot set nonlocal hook without a module handle. If you set dwThreadId parameter to zero, the hook procedure is associated with all existing threads running in the same desktop as the calling thread. It is a nonload hook you need specified a valid hmod parameter. You need put the hook code in a DLL as #Remy Lebeau pointed out.
Or set a valid dwThreadId parameter using GetCurrentThreadId() as #rudolfninja pointed out.
I test based on a Windows Desktop Application Template with the following code. It works. You can have a try.
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
// ...
HHOOK m_msgHook = SetWindowsHookEx(WH_GETMESSAGE, MsgPoc, NULL, GetCurrentThreadId());
DWORD errCode = GetLastError();
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
LRESULT CALLBACK MsgPoc(int code, WPARAM wParam, LPARAM lParam)
{
OutputDebugString(L"Hooked");
if (code < 0)
{
return CallNextHookEx(0, code, wParam, lParam);
}
MSG* lpmsg = (MSG*)lParam;
//OutputDebugString("Hooked for HWND: %p. Current window %p", lpmsg->hwnd, m_windowHandle);
if (lpmsg->hwnd != m_windowHandle)
{
return CallNextHookEx(0, code, wParam, lParam);
}
if (lpmsg->message == WM_ENTERSIZEMOVE && !m_isWindowResizing)
{
OutputDebugString(L"Start window resizing");
m_isWindowResizing = true;
}
else if (lpmsg->message == WM_EXITSIZEMOVE && m_isWindowResizing)
{
OutputDebugString(L"Stop window resizing");
m_isWindowResizing = false;
}
return CallNextHookEx(0, code, wParam, lParam);
}

Dll process hook is not working

I want to hook my KeyboardProc from dll into my created window using dll injection. I want to see message boxes when pressing keys with focused injected window, but my code is not working properly.
Injected window code:
#include <windows.h>
#include <iostream>
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (lParam)
{
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArgs, int nCmdShow)
{
HWND hwnd;
LPCTSTR className = L"WNDCLASS";
LPCTSTR windowName = L"Window";
WNDCLASSEX wcex;
memset(&wcex, 0, sizeof(wcex));
wcex.cbSize = sizeof(wcex);
wcex.hInstance = hInstance;
wcex.lpszClassName = className;
wcex.style = CS_DBLCLKS;
wcex.lpfnWndProc = WndProc;
wcex.hbrBackground = CreateSolidBrush(RGB(255, 255, 255));
if (!RegisterClassEx(&wcex))
{
return -1;
}
hwnd = CreateWindowEx(NULL, className, windowName, WS_OVERLAPPEDWINDOW, 0, 0, 500, 500, NULL, NULL, hInstance, NULL);
if (!hwnd)
{
return -2;
}
MSG msg;
ShowWindow(hwnd, SW_NORMAL);
UpdateWindow(hwnd);
while (GetMessage(&msg, hwnd, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return
msg.lParam;
}
dll code:
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
#include <tchar.h>
HHOOK hhkKb;
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (wParam == WM_KEYDOWN)
{
MessageBox(0, L"DOWN", L"keyboard key down in dll", MB_ICONINFORMATION);
}
else if (wParam == WM_KEYUP)
{
MessageBox(0, L"UP", L"keyboard key up in dll", MB_ICONINFORMATION);
}
return
CallNextHookEx(hhkKb, nCode, wParam, lParam);
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
HWND windowHandle = FindWindow(NULL, L"Window");
if (windowHandle == NULL)
{
MessageBox(NULL, L"Error", L"Handle is null", MB_ICONERROR);
return TRUE;
}
DWORD threadId = GetWindowThreadProcessId(windowHandle, NULL);
hhkKb = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, hModule, threadId);
MessageBox(NULL, L"Success", L"Sucessfully injected dll", MB_ICONINFORMATION); //shows that message
break;
}
case DLL_PROCESS_DETACH:
{
UnhookWindowsHookEx(hhkKb);
break;
}
}
return TRUE;
}
I see "Sucessfully injected dll" message, but when I'm pressing keys into injected window, the KeyboardProc is not called, what I'm doing wrong?
using dll injection
unclear how you do this dll injection, but based on your previous question can assume that you manually inject your dll by CreateRemoteThread to LoadLibraryA. and in any case call SetWindowsHookEx from dll entry point is error by sense.
formally if thread, which call SetWindowsHookEx, exit - hooks will be automatically removed. so can say that on exit thread indirect call UnhookWindowsHookEx. don't sure are this clear documented, but can be view in next simply test
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
DbgPrint("%x>KeyboardProc(%x)\n", GetCurrentThreadId(), wParam);
return CallNextHookEx(0, nCode, wParam, lParam);
}
ULONG HookThread(PVOID threadId)
{
DbgPrint("%x>HookThread(%x)\n", GetCurrentThreadId(), (ULONG)(ULONG_PTR)threadId);
if (HHOOK hhk = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, (HINSTANCE)&__ImageBase, (ULONG)(ULONG_PTR)threadId))
{
Sleep(10000);//10 sec
//MessageBoxW(0,0,L"Close Me", MB_ICONWARNING);
}
return 0;
}
void test()
{
if (HANDLE hThread = CreateThread(0, 0, HookThread, (PVOID)(ULONG_PTR)GetCurrentThreadId(), 0,0))
{
CloseHandle(hThread);
MessageBoxW(0,0,L"Press Buttons here", MB_ICONINFORMATION);
}
}
first several seconds (or until you close MessageBoxW L"Close Me" if chose this variant) you can view dbgprint from KeyboardProc when you press buttons on first messagebox. after HookThread exit - no more KeyboardProc will be called.
so if you inject dll via CreateRemoteThread - this thread call LoadLibrary, then SetWindowsHookEx will be called in this thread, and finally thread just exit - and this remove effect of call SetWindowsHookEx - hook will be remove.
however if we use SetWindowsHookEx we not need manually inject dll to process. visa versa - this api special design for automatically inject dll to remote process. and of course you must not call SetWindowsHookEx from dll entry point - this is nonsense. you need call SetWindowsHookEx from remote process - as result your dll and will be injected to target process. reread Installing and Releasing Hook Procedures

Global CBT hook is never called

I'm trying to make an application that gets informed on creation and destruction of top-level windows, system-wide. I've made a code to exploit a CBT hook. The solution contains two projects, DLL and EXE. EXE project has a reference to the DLL project. The hook is being set from a DLL. There is a message loop in EXE project. The problem is that CBT hook is not working. With the help of VS debugger, I've found out that hook callback is never called, while return code from SetWindowsHookEx is non-zero, implying the hook was set. What's a mistake? How do I fix it?
Here's a minimal example. DLL, main.cpp:
#include <windows.h>
typedef void(*DECODERPROC)(int code, WPARAM wParam, LPARAM lParam);
HINSTANCE hInst = nullptr;
HHOOK hHook = nullptr;
DECODERPROC fpDecoder = nullptr;
LRESULT CALLBACK cbtProc(int code, WPARAM wParam, LPARAM lParam) {
// FIXME: never called
if (code > 0 && fpDecoder) {
fpDecoder(code, wParam, lParam);
}
return CallNextHookEx(hHook, code, wParam, lParam);
}
__declspec(dllexport) bool InstallHook(DECODERPROC decoder) {
if (hHook) return false;
fpDecoder = decoder;
return (hHook = SetWindowsHookEx(WH_CBT, cbtProc, hInst, 0)) != NULL;
}
__declspec(dllexport) bool UninstallHook() {
if (!hHook) return false;
bool res = UnhookWindowsHookEx(hHook) != NULL;
if (res) hHook = NULL;
return res;
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
hInst = reinterpret_cast<HINSTANCE>(hModule);
return TRUE;
}
EXE, main.cpp
#include <iostream>
#include <locale>
#include <windows.h>
#include <fcntl.h>
#include <io.h>
using namespace std;
typedef void(*DECODERPROC)(int code, WPARAM wParam, LPARAM lParam);
__declspec(dllimport) bool InstallHook(DECODERPROC);
__declspec(dllimport) bool UninstallHook();
int main() {
_setmode(_fileno(stdout), _O_U8TEXT);
WNDCLASS windowClass = {};
windowClass.lpfnWndProc = [](HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -> LRESULT {
if (message == WM_DESTROY)
UninstallHook();
return DefWindowProc(hWnd, message, wParam, lParam);
};
LPCWSTR windowClassName = L"Foobar";
windowClass.lpszClassName = windowClassName;
if (!RegisterClass(&windowClass)) {
wcerr << L"Failed to register window class" << endl;
return 1;
}
HWND messageWindow = CreateWindow(windowClassName, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, 0, 0);
if (!messageWindow) {
wcerr << L"Failed to create message-only window" << endl;
return 1;
}
InstallHook([](int code, WPARAM wParam, LPARAM lParam) {
wcout << L"Never called" << endl;
});
MSG msg;
while (GetMessage(&msg, 0, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
If you are running on Windows 64-bit, you need both 32-bit and 64-bit versions of the DLL in order to hook every running process. A 32-bit DLL cannot hook a 64-bit process, and vice versa. So you need to call SetWindowsHookEx() from a 32-bit process to hook 32-bit processes, and from a 64-bit process to hook 64-bit processes.
More importantly than that, a separate instance of your DLL gets injected into every running process, so your fpDecoder callback pointer is NULL in every instance of the DLL except for the one that your EXE is calling InstallHook() on. So you need to redesign your hook to use inter-process communication (window message, named pipe, mailslot, socket, etc) to communicate with your main EXE, you can't use a function pointer.
Depending on which process you are actually debugging, you might not see cbtProc() getting called. If you are debugging your main EXE process, your code is not doing anything to trigger any CBT activity within your EXE's process once the hook has been installed, and the debugger would not show you any CBT activity occurring in other processes that it is not debugging.
Depending on what you are actually looking for in your hook, you might consider using SetWinEventHook() instead, as it can be used with or without a DLL, and it has more flexible filtering capabilities than SetWindowsHookEx().

SetWindowsHookEx not calling my callback?

Well I tried different solution to my problem but It just doesn't work.
I call SetWindowsHookExA and then when I press a key the messagebox is not shown. What to do?
this is my code (this is a DLL which is loaded by another DLL which is loaded by the program):
#include <Windows.h>
HINSTANCE gl_hThisInstance = NULL;
HHOOK hHook = NULL;
LRESULT CALLBACK KeyHit(int code,WPARAM wParam,LPARAM lParam);
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
gl_hThisInstance = (HINSTANCE)hModule;
hHook = SetWindowsHookExA(
WH_KEYBOARD,
KeyHit,
//(HWND)gl_hThisInstance//not working
0,//not working
//(DWORD)gl_hThisInstance//not working
//GetCurrentThreadId()//even not working with this
0//not working
);
break;
}
return TRUE;
}
LRESULT CALLBACK KeyHit(int code,WPARAM wParam,LPARAM lParam)
{
MessageBox(0,"PRESSED","PRESSED",0);
return CallNextHookEx(hHook,code,wParam,lParam);
}
I got issues with the hooking before. Not really an issue, but the way I did it was not supposed to.
First of all, you should have 2 exported functions from the DLL, SetHook and RemoveHook. The SetHook function will call the SetWindowsHookEx() from there. If you ever try to call the SetWindowsHookEx() from within a thread or DLLMain of your DLL, the function returns no errors, but the callback function will never be called. It took me sometimes to figure it out.
Posted here is my working code to catch WH_GETMESSAGE, you can reference from here.
Here is my working exported SetHook() function from the DLL.
bool __declspec(dllexport) __stdcall SetHook(DWORD myWnd)
{
mySavedHook = SetWindowsHookEx(WH_GETMESSAGE,
GetMsgProc,
infoContainer.DllHModule,
myWnd);
int errorID = GetLastError();
if (errorID != 0)
{
MessageBoxA(NULL, "Failed to implement hook", "Failed", 0);
MessageBoxA(NULL, to_string(errorID).c_str(), "Error ID", 0);
return false;
}
else
{
return true;
}
}
infoContainer.DllHModule: instance of the DLL, which is the first parameter of DllMain().
myWnd: is my Thread ID (not Process ID) - Get it from GetWindowThreadProcessId(window_handle, NULL). To implement global hook, use 0 as myWnd.
And here is my callback function.
LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode >= 0)
{
LPMSG msg = (LPMSG)lParam;
if (msg->message == WM_CALLFUNCTION)
{
MessageBoxA(NULL, "Receive WM_CALLFUNTION", "Good news", 0);
}
}
//Doesn't matter, just call this function and return it.
return CallNextHookEx(_hook, nCode, wParam, lParam);
}
The callback function must have the CALLBACK keyword to work.
From the external application, call the SetHook() from the DLL and use the Thread ID as its param.

Crashes during UnhookWindowsHookEx()

I made hook for calculator and want to get messages which calculator receives. To do that, I set my own window procedure, but during unhooking if I use SetWindowLong(..) to recover the old window procedure program crushes.
DLL code:
#define EXPORT_API extern "C" __declspec(dllexport)
EXPORT_API void InstallHook();
EXPORT_API void UninstallHook();
#pragma data_seg("Shared")
HHOOK g_hHook = NULL;
WNDPROC g_OldWndProc = NULL;
#pragma data_seg()
#pragma comment(linker, "/section:Shared,rws")
HWND GetTargetWindowHwnd()
{
return ::FindWindowA(0, "Calculator");
}
// my new wnd procedure to catch messages
LRESULT CALLBACK NewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT lResult = 0;
switch(uMsg)
{
case WM_CLOSE:
{
MessageBoxA(0, "Here we are!", "", 0);
}
break;
default:
lResult = CallWindowProc(g_OldWndProc, hwnd, uMsg, wParam, lParam);
break;
}
lResult = CallWindowProc(g_OldWndProc, hwnd, uMsg, wParam, lParam);
return lResult;
}
// hook procedure
LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
MSG *pMsg = (MSG *)lParam;
HWND hWnd = GetTargetWindowHwnd();
bool flagIn = false;
if( hWnd == pMsg->hwnd )
{// if messege was sent to my target window
if(g_OldWndProc == NULL)
{
// save the adress of old wnd procedure to recover it later
g_OldWndProc = (WNDPROC)GetWindowLong(hWnd, GWL_WNDPROC);
// set my wnd procedure
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)NewWndProc);
}
}
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
EXPORT_API void InstallHook()
{
try
{
g_hHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, g_hInstance, 0);
}
catch(...)
{
MessageBoxA(0, "Hook error", "Error", 0);
}
}
EXPORT_API void UninstallHook()
{
if(g_OldWndProc)
{
// recovering old wnd proc
HWND hWnd = GetTargetWindowHwnd();
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)g_OldWndProc);
g_OldWndProc = NULL;
}
if (g_hHook)
{
UnhookWindowsHookEx(g_hHook);
g_hHook = NULL;
}
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
g_hInstance = (HINSTANCE) hModule;
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
EXE CODE:
void CHookTestDlg::OnBnClickedBtnInstall()
{
InstallHook();
}
void CHookTestDlg::OnBnClickedBtnUninstall()
{
UninstallHook();
}
If I don't use my wnd procedure it works normal. If I use SetWindowLong(..) to recover the old window procedure program crushes during unhook. What is wrong?
The problem is that you are setting the window proc on the target window from within the target process (calc), and in that case, it is succeeding. But when you call UninstallHook, that code runs in your own exe's process; and in that case, SetWindowLong will fail.
(Putting the hook values in shared memory won't help; SetWindowLong will still refuse to change the window proc across a process boundary - see MSDN for details.)
To get this to work, you would need to communicate to the hooked instance of the DLL and ask it to reset the wndproc from within that target process, and once that is done, then unhook the hook.
(atzz's advice on unhooking is also valid. Hooking windows that you don't own is generally best avoided.)
When unsubclassing, always check that the window was not subclassed by someone else after you. I.e. before restoring WindowProc, you should read it again and compare against expected value (NewWndProc). If it is different, you must not unload the DLL, because another subclasser has a pointer to your DLL code stored, and this pointer will become dangling as soon as your DLL is unloaded.