-1

I tried to call a function-pointer from a dll that hooks the WM_LBUTONDOWN or WM_TOUCH message on all windows displayed at screen.

I have the following dll source code:

typedef void (*PtrFonct)(int nCode, WPARAM wParam, LPARAM lParam);
PtrFonct pf;
HHOOK global;

extern "C" __declspec(dllexport) LRESULT WINAPI procedure(int nCode, WPARAM wParam,LPARAM lParam)
{
    if (nCode == HC_ACTION){
        MSG* pMSG = (MSG*)lParam;
        if (pMSG->message == WM_LBUTTONDOWN){
            pf(nCode, wParam, lParam);
        }
    }
    return CallNextHookEx(global, nCode, wParam, lParam);
} 

extern "C" __declspec(dllexport) BOOL setCallback(void ((*callbackFunc)(int, WPARAM, LPARAM))){
    pf = callbackFunc;
    if (pf)
        return TRUE;
    return FALSE;
}

and my listener source code is the following one:

    MSG message;
    HMODULE lib = LoadLibrary(L"C:/HookTouch.dll");
    if (lib) {
        HOOKPROC procedure = (HOOKPROC)GetProcAddress(lib, "_procedure@12");
        dllFunct fonctionCallback = (dllFunct)GetProcAddress(lib, "setCallback");
        if (fonctionCallback)
            fonctionCallback(MyCallback);
        if (procedure)
            hook = SetWindowsHookEx(WH_GETMESSAGE, procedure, lib, 0);
    }
    else
        printf("Can't find dll!\n");

    while (GetMessage(&message, NULL, 0, 0))
    {
        TranslateMessage(&message);
        DispatchMessage(&message);
    }
    FreeLibrary(lib);
    UnhookWindowsHookEx(hook);

My own callback to display "Hello click" is this one:

void MyCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
    printf("Hello Click\n");
}

I know my hook is working because I can display a message on click by using a message box instead of pf(nCode, wParam, lParam) but when I use this function-pointer, MyCallback is not triggered. I checked if my function was well affected to the pf function-pointer and all seems to be ok.

Do you know why the call of pf(nCode, wParam, lParam) don't trigger the MyCallback function of the listener?

Timisorean
  • 1,388
  • 7
  • 20
  • 30
CyrilleH
  • 3
  • 3
  • How have you verified, that your callback isn't called? For `printf` to output anything requires that the target process has a console attached to it. This is usually not the case for applications that process mouse and touch input. Also note that different instances of a DLL do not share global data. – IInspectable Jun 25 '19 at 14:45
  • My listener is a console application so I can see my printf logs. I also check with breakpoints in VS that `setCallback` of Dll is called and I see pf filled correctly. If I put a breakpoint in `MyCallback` function, nothing happens. – CyrilleH Jun 25 '19 at 15:03
  • You are installing a **global** hook. Your code runs inside the target process. Your launcher process is just one of many 32-bit target processes your DLL gets injected into. – IInspectable Jun 25 '19 at 15:05
  • 1
    Ok I didn't see things from this angle :-). That means that I can't alert my application like that. Do you know a way to do that ? – CyrilleH Jun 25 '19 at 15:21

2 Answers2

0

This approach will not work.

A message hook runs in the context of each thread that is being hooked. Each hooked process will get its own copy of your DLL injected into it. As such, only the copy that originally installed the hook will have a valid function pointer set. Besides, you can't call your callback function across process boundaries anyway.

You need to use a different IPC mechanism to let your injected hooks communicate back to your main app process.

For instance, you could create a hidden HWND and store it in a block of global shared memory and then each injected hook can send window messages to it, like WM_COPYDATA. Or, your main app can open a named pipe that each injected hook can then connect to and send data to.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
0

You are calling setCallback only for the dll that's loaded in your process. The dll's that will be injected by SetWindowsHookEx in all the other process will not have the callback set. On top of that, MyCallback is only defined in your own process; the Dll's injected in other processes have no trivial way of accessing it.

Since you cannot know which processes Windows has injected for you, you will need the Dll to broadcast its 'location' to you, via Inter-Process communcation, eg. Named Pipes. Once you have the process ID of each of the DLL's that were injected, you can use CreateRemoteThread to call a function inside the Dll, like setCallback.. there's still some work to be done so that the Dll can directly call you callback: You will need to give the Dll the exact offset of your callback from the module base, and the Dll will then need to use CreateRemoteThread itself to issue the call. This all quickly becomes too tedious, and you would be wise to just use Named Pipe communication instead of issuing direct function calls.

Tip: An easy way to log things from other processes is using OutputDebugString. Alternatively, write to a file.

kundrata
  • 651
  • 3
  • 12
  • 24
  • Output from `OutputDebugString` can only be observed, if a debugger is attached to the process calling `OutputDebugString`. That debugger need not be Visual Studio, though. [DebugView](https://learn.microsoft.com/en-us/sysinternals/downloads/debugview) is perfectly fine. – IInspectable Jun 25 '19 at 15:27