2
votes

I'm trying to make a simple globalhook that prints some text into a .txt file whenever someone presses a key on the keyboard. The problem is that when I execute my program and press on a key in a certain program, the program gets stuck and doesn't respond anymore. So I think the problem is that the hookprocedure doesn't work/return properly when called.

this is the code in my .exe file:

#include <Windows.h>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include <wingdi.h>
#include <string>

using namespace std;

typedef bool (*install)();
install instal;
HINSTANCE hinst;

int main()
{
hinst = LoadLibrary(TEXT("injectdll.dll"));
if(!hinst)
{
printf("The DLL could not be found.\n");
}

instal = (install) GetProcAddress(hinst, "install");
if(!instal) 
{
    printf("The function was not found.\n");
}

if(!instal())
{
    printf("func couldn't be executed");
}

printf("Program successfully hooked.\nPress enter to unhook the function and stop the program.\n");
getchar();
}

this is the code in my dll:

    #include <windows.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <fstream>
#include <string>
#include <Strsafe.h>

using namespace std;

#pragma data_seg(".shared")
HHOOK hook = 0;
#pragma data_seg()
#pragma comment(linker, "/SECTION:.shared,RWS")

HINSTANCE hinst;

LRESULT CALLBACK meconnect(int code, WPARAM wParam, LPARAM lParam) 
{
if (code < 0) 
{
    return CallNextHookEx(hook, code, wParam, lParam);
}
FILE *file;
fopen_s(&file, "function.txt", "a+");
fprintf(file, "Function keyboard_hook called.\n");
fclose(file);

return 0;
}

extern "C" __declspec(dllexport) bool install() 
{ 
hook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC) meconnect, hinst, 0);
return hook != NULL;
}

BOOL WINAPI DllMain(HINSTANCE hDLL, DWORD Reason, LPVOID Reserved) {

switch(Reason) {
case DLL_PROCESS_ATTACH:
            hinst = hDLL;
    break;
case DLL_PROCESS_DETACH:
    break;
case DLL_THREAD_ATTACH:
    break;
case DLL_THREAD_DETACH:
    break;
}

return TRUE;
}

the meconnect function returns 0, I don't know if this is right, but I also tried returning: return CallNextHookEx(hook, code, wParam, lParam); and return CallNextHookEx(0, code, wParam, lParam);

both didn't change anything in the results.

1

1 Answers

0
votes

The install function runs in the context of your main exe. Make it return the HHOOK handle on success. You need that handle to call the UnhookWindowsHookEx function when you terminate your exe.

Alternatively, you could just store the HHOOKin a regular global variable in your DLL and implement an exported uninstall function, which will call UnhookWindowsHookEx.

Anyway, drop the shared section, which serves no purpose and can only bring problems.

Note that the CallNextHookEx documentation contains:

Parameters
   hhk [in, optional]
      Type: HHOOK
      This parameter is ignored.

Pass NULL as parameter 1 when calling CallNextHookEx

Always return the return value of CallNextHookExin your Hook procedure.

do:

LRESULT CALLBACK meconnect(int code, WPARAM wParam, LPARAM lParam) {
    if (code >= 0) {
        FILE *file = 0;
        fopen_s(&file, "function.txt", "a+");
        if ( file ) {
            fprintf(file, "Function keyboard_hook called.\n");
            fclose(file);
        }
    }
    return CallNextHookEx( NULL, code, wParam, lParam);
}

The DLL is loaded in the processes with keyboard activity. The text file is then opened in their "current directory". It may fail for access rights reasons, and you don't want text files sprayed anywhere : Use a valid full path for your text file.

Finally, most important part, if the thread that called SetWindowsHookEx doesn't have a polled message queue, things will turn weird (as you noticed). The simpler way of doing the right thing is just to call MessageBox.

Replace your getchar call by:

MessageBox(NULL, "Ok to leave", "Hooking Keyboard", MB_OK);

Your DLL will be loaded only in the processes with same bitness (32b or 64b). If your DLL is 32 bits, keyboard activity in 64 bits proesses is reported by an invocation of your Hook Procedure, in the context of your 32 bits EXE. This is the reason why you have to provide a polled message queue (it makes possible the callback call).

Edited: WH_KEYBOARD allows global AND multi-bitness hooking.