SetWindowsHookEx not calling my callback? - c++

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.

Related

SetWindowsHookEx succeed but callback function is never called

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.

Possible ways to control code in DLL

I am working on my university project and stuck with a problem.
My task is to write a program and .dll to intercept calls from WinAPI.
For example I launch my program and it should inject .dll using SetWindowsHookEx to any process by PID. I successfully made this task for function CreateFile, but I need to realise it for multiple functions and allow user to choose which function to intercept via command line arguments.
In my code, when installing hook I define callback function:
HINSTANCE hinst = LoadLibrary(L"ConsoleApplication1.dll");
HOOKPROC addr = (HOOKPROC)GetProcAddress(hinst, "meconnect");
HHOOK handle = SetWindowsHookEx(WH_KEYBOARD, addr, hinst, threadID);
But there are only three arguments in this callback function for launching CallNextHookEx(NULL, code, wParam, lParam) and it seem we can't change them.
The other problem is that when we inject our .dll to another process we are only able to run tasks from DLL_PROCESS_ATTACH section, so it doesn't link with our program, so we can't pass our arguments.
Maybe the solution is to create a temporary file and write arguments to it and then read it from .dll, but I hope you will help me with more elegant solution. I will appreciate any help.
You can use separate function for every hook for example.
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
SetWindowsHookEx(WH_CBT, CBTProc, (HINSTANCE) NULL, GetCurrentThreadId());
SetWindowsHookEx(WH_CALLWNDPROCRET, CallWndRetProc, (HINSTANCE) NULL, GetCurrentThreadId());
break;
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < 0)
return CallNextHookEx(___cbt_message_hookptr, nCode, wParam, lParam);
// your code here
return CallNextHookEx(___cbt_message_hookptr, nCode, wParam, lParam);
}
LRESULT CALLBACK CallWndRetProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < 0)
return CallNextHookEx(___callwndprocret_message_hookptr, nCode, wParam, lParam);
// your code here
return CallNextHookEx(___callwndprocret_message_hookptr, nCode, wParam, lParam);
}
For reference your DLL_PROCESS_ATTACH issue, it's common problem with communication between intercepted process and your process.
Best solution in my opinion is using Pipes as inter process communication mechanism, bcs it's simplest and most elegant solution.
My advice is you should start another thread from DLL_PROCESS_ATTACH which will be receiving commands via pipe from main application to hook certain functions and also it will be sending intercepted data over same pipe to main application where you will archive or display this data.
Example of sending message over pipe from intercepted process, assuming that you have something listening for this data on other side:
LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\payload_datapipe");
CHAR chReadBuf[1024];
DWORD cbRead = 0;
BOOL fResult;
fResult = CallNamedPipe(
lpszPipename, // pipe name
_Message, // message to server
strlen(_Message), // message length
chReadBuf, // buffer to receive reply
sizeof(chReadBuf), // size of read buffer
&cbRead, // number of bytes read
NMPWAIT_NOWAIT);//NMPWAIT_WAIT_FOREVER); // wait;-)
if (!fResult)
{
return;
}
More information's about Named Pipes you can find at relevant documentation pages. https://msdn.microsoft.com/en-us/library/windows/desktop/aa365592%28v=vs.85%29.aspx

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().

Global Keyboard Hook Spy?

I'm writing up a quick tool in C# thats meant to sort of be a virtual keyboard. At the moment I am using SendKeys. I want to know if keyloggers would capture the keys so I found this code but i don't have mfc installed so i cant compile nor run it
How might i key if SendKeys is being logged by keyloggers or how do I get the code (snippet below) running in a single exe to test my code with?
#include <Windows.h>
static UINT uMsg = 0;
static HWND hWndMain = 0;
static HHOOK hKeyHook = NULL ;
#pragma data_seg()
HINSTANCE hInstance = 0;
HOOKPROC lpfnHookProc = 0;
LRESULT __stdcall KeyboardFunc (int nCode, WPARAM wParam, LPARAM lParam)
{
BOOL bPassToChain;
char szDebug [100];
// Check for exception cases...
if (nCode < 0)
return (CallNextHookEx (hKeyHook, nCode, wParam, lParam));
if (nCode == HC_NOREMOVE)
return (CallNextHookEx (hKeyHook, nCode, wParam, lParam));
switch (wParam)
{
case VK_F2:
wsprintf (szDebug, "F2 key message, lparam = 0x%X\n", lParam);
OutputDebugString (szDebug);
// only send on keydown, not keyup (autorepeat)
if (HIWORD (lParam) & 0xC000)
{
OutputDebugString ("F2 Keyup\n");
}
else
{
wsprintf (szDebug, "Sending F2 keydown message %d to hwnd 0x%X\n",
uMsg, hWndMain);
OutputDebugString (szDebug);
PostMessage (hWndMain, uMsg, 0, 0);
}
bPassToChain = FALSE;
break;
default :
bPassToChain = TRUE ;
break ;
}
if (bPassToChain)
return (CallNextHookEx (hKeyHook, nCode, wParam, lParam));
else
return TRUE ; // We have processed this key
}
BOOL __stdcall InstallExampleKeyboardHook (HWND hWnd, UINT uMyMsg)
{
hWndMain = hWnd ;
uMsg = uMyMsg;
lpfnHookProc = (HOOKPROC) KeyboardFunc ;
hKeyHook = SetWindowsHookEx (WH_KEYBOARD, lpfnHookProc, hInstance, NULL);
if (hKeyHook)
return TRUE ;
else
return FALSE ;
}
It's nothing about MFC. Straight native c++ code. If you have Visual Studio, you should be able to make a quick console c++ app, copy and paste that code in, and compile and test. If not, go and get the free but big Windows SDK. Less friendly then VS, but there's a compiler, so should get you in the right direction.
Low level hooks are not quite debugger friendly, so you might need to trace or log out some helpful statements.
Edited: to get the module handle, you will need something like this:
HookModule = LoadLibrary(ModulePath);
HookProc HookFunction = GetProcAddress(HookModule, "GetMessageCallBack");
GetMessageHookHandle = SetWindowsHookEx(HookType.WH_GETMESSAGE, HookFunction, HookModule, 0);

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.