Gehaxelts Blog

IT-Security & Hacking

[C++] KeyCounter - Tastenanschläge zählen

Da es für Windows Vista/7 ein Gadget namens “MouseMeter” gibt, welches die zurückgelegte Strecke der Maus auf dem Desktop berechnet, suchte ich nach einem ähnlichen Programm, welches die Tastaturanschläge mitzählt. Ich ging jedoch fundlos aus und stand nun vor der Aufgabe ein solches Programm selber zu entwickeln.

Ich dachte mir, ich müsste einfach eine Funktion der Tastatur überwachen, welche die angeschlagenen Tasten an das Betriebssystem weitergibt.

Dieses “Überwachen” bzw. “Einhaken” in eine andere Funktion nennt man “Hooken”. Die Windows API stellt dazu gleich eine Funktion bereit, die dies einem rel. einfach ermöglicht: SetWindowsHookEx

HHOOK WINAPI SetWindowsHookEx(
  __in  int idHook,
  __in  HOOKPROC lpfn,
  __in  HINSTANCE hMod,
  __in  DWORD dwThreadId
);

Diesen Hook richte ich folgendermaßen ein:

this->hook=SetWindowsHookEx(WH_KEYBOARD_LL,(HOOKPROC)::LowLevelKeyboardProc,NULL, 0);

Ich hake mich in die Funktion LowLevelKeyboardProc ein, welche Tastenschläge bearbeitet:

LRESULT CALLBACK LowLevelKeyboardProc(
  __in  int nCode,
  __in  WPARAM wParam,
  __in  LPARAM lParam
);

Diese Funktion kann ich dann nach belieben gestalten und dort mit den übergebenen Daten arbeiten, muss jedoch

return CallNextHookEx(0, nCode, wParam, lParam);

aufrufen, um die weiteren Abläufe nicht zu unterbrechen.

Meine LowLevelKeyboardProc sieht nun so aus:

LRESULT WINAPI LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{

    if(wParam==WM_KEYDOWN)
    {
     count++;
     file.seekp(0);
     file<<count;
    }
    return CallNextHookEx(0, nCode, wParam, lParam);
}

Ich möchte nur Tastendücke mitzählen, demnach prüfe ich, ob die Taste nach unten gedrückt wurde. Die restlichen Events, wie “Taste losgelassen”,etc werden ignoriert.

Der Counter “cout” wird erhöht und danach in die Datei “count.cnt” geschrieben, damit man bei einem späteren Start bei der letzten Zahl wieder aufhören kann.

Anmerkung:

Man könnte aus diesem Programm leicht einen Keylogger schreiben, in dem man statt des Counts den Buchstaben, welchen man aus den Parametern entnehmen kann, in die Datei schreibt und den Seekp. Doch die Entwicklun solcher Programme ist gesetzlich verboten, weswegen ich nicht weiter drauf eingehe.

Damit das Programm sich nicht nach einem Durchlauf beendet, braucht man eine Dauerschleife. Dazu nutze ich GetMessage,

BOOL WINAPI GetMessage(
  __out     LPMSG lpMsg,
  __in_opt  HWND hWnd,
  __in      UINT wMsgFilterMin,
  __in      UINT wMsgFilterMax
);

denn dieseprüft dauerhaft auf verschiedene Event, welche ich nicht weiter verarbeite.

Vorteil: Fast keine CPU-Auslastung im Gegensatz zu einer while(true)-Schleife.

Es folgt der komplette Code:

KeyCounter.h

//Copyright by selfcoded.de
//www.selfcoded.de
#ifndef KEYCOUNTER_H_
#define KEYCOUNTER_H_

#include <iostream>
#include <fstream>
#include <windows.h>

using namespace std;

class KeyCounter
{
    public:
        KeyCounter();
        ~KeyCounter();
        void start();
    private:
        HHOOK hook;
        void getLastCount();
        void openCountFile();
    protected:
};

#endif // KEYCOUNTER_H_

KeyCounter.cpp:

#include "keycounter.h"

LRESULT WINAPI LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
long long count;
fstream file;

KeyCounter::KeyCounter()
{
    count=0;
}

KeyCounter::~KeyCounter()
{
    file.close();
    UnhookWindowsHookEx(this->hook);
}

void KeyCounter::start()
{

    MSG message;

    getLastCount();
    openCountFile();

    this->hook=SetWindowsHookEx(WH_KEYBOARD_LL,(HOOKPROC)::LowLevelKeyboardProc,NULL, 0);

    while(GetMessage(&message, NULL, 0, 0) != 0)
    {
        //loop
    }

}

void KeyCounter::getLastCount()
{
    fstream file;
    file.open("count.cnt",ios::in);
    try {
        string tmp;
        file >> count;
    } catch(...) {}
    file.close();
}

void KeyCounter::openCountFile()
{
    file.open("count.cnt",ios::out);
}

LRESULT WINAPI LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{

    if(wParam==WM_KEYDOWN)
    {
     count++;
     file.seekp(0);
     file<<count;
    }
    return CallNextHookEx(0, nCode, wParam, lParam);
}

Wie man sieht, musste ich die LowLevelKeyBoardProc, und die Variablen file/count global deklarieren. Das ist OOP-mäßig nicht schön, aber ich habe keine andere Lösung gefunden, den Pointer der Funktion an SetWindowsHookEx zu übergeben.

Beispiel:

//Copyright by gehaxelt.in
//www.selfcoded.de
#include <iostream>

#include "keycounter.h"

using namespace std;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInst, LPTSTR lpCmdLine, int nShowCmd)
{
    KeyCounter* kc = new KeyCounter();
    kc->start();
    delete kc;
    return 0;
}

Download der kompilierten Version.

Viel Spaß beim Counten.

gehaxelt