Paranoyaklar için :)

// 17 Mayıs 2009 // Delphi, Programlama

Muhtemelen başlığa bakıp kimse bu yazının ilerleyen satırlarını okumak istemeyecektir, çünkü insan psikolojisi gereği bilinçaltı başlığın kendisine uygun olmadığını düşündürecektir. Ama kimbilir belki yanılırım okuyanlar olur, ne de olsa tüm dünya üzerinde for Dummies serisi makale ve kitaplar nerede ise yok satıyor :)

Siz değerli okuyucularıma paranoyak demiyorum ama benim bazen paranoyakça davrandığım ve meyvesini bu makale haline getiren bazı olaylar oluyor. Bu makalenin tohumlarının atılmaya başladığı zaman, tam olarak işletim sistemimde bazı gariplikleri hissetiğim zamana tekabül ediyor. Bir müddet önce makinamda bir kısım yavaşlık hissettim, yazdığım yazılar sırasında bu yavaşlığı hissetmem beni hemen keylogger olma ihtimali üzerinde düşündürmeye başlamıştı. Bu bağlamda, Startup, registry’de çalışan uygulamalar listelerini incelemiş, ardından servisleri de gözden geçirmiştim. Gereksiz olduğuna inandığım belki de gerekli olduğu halde sildiğim pek çok program oldu :) Ancak insanın içine şüphe girdimi bir kere imkan yok çıkmıyor :)

Bu şüphe ile Task Manager’ı açarak çalışan uygulamaları incelemeye başladım. Kısa bir müddet sonra Task Manager’da bazı zaman dilimlerinde ortaya çıkan bir uygulama gördüm. Bir müddet çalışıyor ve kendiliğinden yok oluyordu.(Kendiliğinden yok olmadığı durumlarda ben yokediyordum itiraf edeyim) Tam sorunu buldum, evet bu EXE dosyasını siler kurtulurum derken, bu uygulamanın belirli zaman periyotlarında çalışmasının kendi kendine olmayacağını bunu çalıştıran bir servisin yada ona benzer bir zamanlanmış görevin olması gerektiğini düşünmeye başladım.

Önce bu uygulamayı çalıştıran mikrobun atasını bulmalıydım. İlk aklıma gelen EXE’nin adını değiştirmek oldu. Bu durumda beklediğim şey, adı değişen EXE’yi çalıştırmaya çalışacak olan uygulamanın EXE’yi bulamaması ve hata vermesi idi. Ancak elbetteki pek bir iyimsermişim. O mikrop uygulama benim adını değiştirdiğim EXE’yi yine oluşturmuştu :) O zaman servisleri incelemeye karar vermiştim. Kahretsin ki makinamda da dünya kadar şey yüklü idi. Yani hiç de kolay olmayan bir süreçti bu. Epey bir inceleme yaptıktan sonra durdum ve kendi kendime dedim ki:”Yahu Tuğrul, sen ne yapıyorsun? Sen programcı değil misin?” , sonra diğer ben dedi ki:”Evet, öyleyim ne olacak?”, o zaman diğeri de “ee o zaman bu EXE’yi kim çalıştırmış onu bulan bir program yazsana yahu ;) ”.. Bir anda kafamda şimşek çaktı, öyle ya ben bir programcıydım bunu bulabilirdim :)

Açtım Delphi’mi nereden başlayacağımı düşünmeye başladım. Daha önceleri çeşitli projelerimde sistemde çalışan process’leri almam gerektiğini ve gerekli kodları yazdığımı hatırladım. Kısa bir araştırmadan sonra process listesi için CreateToolHelp32SnapShot API’sini kullandığımı hatırladım. Bir kaç deneme yanılmadan sonra istediğimi elde ettim. Eğer sizde bazı zamanlar sisteminizden şüpheye düşerseniz, yazdığım bu metodu kullanmayı bir deneyin. Eminim ki mikrobu bulup kendinizi rahatlamış hissedeceksiniz :)

Buyrun kodlamaya başlayalım:

  function CreateToolhelp32Snapshot(dwFlags, th32ProcessID: DWORD): THandle;

Yukarıda yazmış olduğum fonksiyon TLHelp32.pas dosyası içinde tanımlıdır. Bu yüzden uses kısmına bu unit’i eklemeyi unutmamalıyız öncelikle. Bu fonksiyona geçilen birinci parametre aşağıdaki değerleri alabilir:

TH32CS_SNAPHEAPLIST  = $00000001;
TH32CS_SNAPPROCESS   = $00000002;
TH32CS_SNAPTHREAD     = $00000004;
TH32CS_SNAPMODULE     = $00000008;
TH32CS_INHERIT            = $80000000;
TH32CS_SNAPALL           = TH32CS_SNAPHEAPLIST or
                                     TH32CS_SNAPPROCESS or
                                     TH32CS_SNAPTHREAD or
                                     TH32CS_SNAPMODULE;

Bu sabitler aslında işletim sistemi üzerinde nelerin aranacaklarını isimlerinden anlatıyorlar. Ancak bir noktaya dikkat çekmek gerekiyor. CreateToolhelp32Snapshot fonksiyonunun ikinci parametresi bizden bir process id beklemektedir. Eğer o parametreye geçerli bir process’in id’sini verirseniz sadece o process için arama yapmış olacaksınız. Farzı misal TH32CS_SNAPTHREAD kullanıyorsunuz ve çalışan uygulamanızın process id’sini de ikinci paremetre olarak geçtiniz.Bu durumda çalışan uygulamanızın içindeki thread’ler içinde dönmüş olacaksınız. Yani sadece sizin belirttiğiniz uygulamadaki Thread’lerin o anlık görüntüsünün fotoğrafı çekilecektir(Snapshot). Ancak, eğer ikinci parametreye herhangi bir id vermezseniz yani sıfır olarak geçerseniz, o zaman işletim sistemi üzerindeki tüm thread’lerle ilgileniyorsunuz demektir. Peki biz ne ile ilgileniyorduk ?

İşletim sistemi üzerinde çalışan process’ler ile. Dolayısı ile diğer bilgilerin anlık fotoğrafını çekip gelecek result’ı arttırmanın bir alemi yok benim için. Bu uygulamada TH32CS_SNAPPROCESS sabitini kullanmam benim için yeterli olacaktır. Tamam diyelim ki CreateToolhelp32Snapshot ile o anda işletim sisteminde çalışan uygulamaların fotoğrafını çektik, ama hala o processler arasında nasıl dolaşılacağını bilmiyoruz. Windows API Help’ten CreateToolhelp32Snapshot’ı bulup, Group kısmına baktığımızda bizim ihtiyacımız olan iki fonksiyonu da gözlemleyebiliyoruz. Bunlar; Process32First ve Process32Next. Delphi’deki tanımlarına hep birlikte bakalım:

  function Process32First(hSnapshot: THandle; var lppe: TProcessEntry32): BOOL;
  function Process32Next(hSnapshot: THandle; var lppe: TProcessEntry32): BOOL;

Fonksiyonlardan anlaşıldığı üzere her iki fonksiyonda parametre olarak CreateToolHelp32SnapShot’dan geri dönen snapshot id’sini alıyor ve bir de TProcessEntry32 tipinde bir record variable’ın adresini istiyor. Tüm bu bilgilerin ışığında kodumuzu yazmaya başlayabiliriz:

function FindParentProcess(const ExeName : String) : String;
var
  SnapHandle : THandle;
  peCurrent,
  peParent	 : TProcessEntry32;
  found	 : Boolean;
begin
  Result := '';

  SnapHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

  peCurrent.dwSize := SizeOf(TProcessEntry32);
  peParent.dwSize  := SizeOf(TProcessEntry32);

  Process32First(SnapHandle, peCurrent);

  found := false;
  while 1 <> 2 do
  begin
    if peCurrent.szExeFile = ExeName then
    begin
      found := true;
      Break;
    end;

    if not Process32Next(SnapHandle, peCurrent) then Break;
  end;

  if not found then
  begin
    CloseHandle(SnapHandle);
    raise Exception.Create('Belirtilen ' + ExeName + ' bulunamadı.!');
  end;

  Process32First(SnapHandle, peParent);

  found := false;
  while 1 <> 2 do
  begin
    if peParent.th32ProcessID = peCurrent.th32ParentProcessID then
    begin
    	found := true;
      Break;
    end;

    if not Process32Next(SnapHandle, peParent) then Break;
  end;

  if found then Result := peParent.szExeFile;

  CloseHandle(SnapHandle);
end;

Yukarıdaki kodda unutulmaması gereken büyük-küçük harf duyarlılığıdır. Dilerseniz yazdığımız fonksiyonu test edelim:

uses ShellAPI;
..
..
..
procedure TForm1.Button1Click(Sender: TObject);
begin
  ShellExecute(Handle, PChar('open'), PChar('calc.exe'), nil, nil, SW_SHOW);

  ShowMessage(FindParentProcess('calc.exe')); // Project1.exe
  ShowMessage(FindParentProcess('Project1.exe')); // delphi32.exe
  ShowMessage(FindParentProcess('delphi32.exe')); // explorer.exe
end;

Sanıyorum hepimizin bazı zamanlar virüsler yada trojanlarla alakalı paranoyalarımız olur,işte o zamanlarınızda bu kodu kullanıp virüse yada trojana hak ettiği dersi verebilirsiniz :)

Saygılar, sevgiler..

“Paranoyaklar için :)” için 4 Yorum

  1. Olcay DAĞLI diyor ki:

    Her bilgisayar kullanıcısı mutlaka bu tarz trojanlar ile karşılaşabilir yada karşılaşmıştır. Gerçekten çok faydalı bir kod olmuş hocam, ben şahsen bu paronayayı çok yaşamış biri olarak eline sağlık diyorum… ;)

  2. Tuğrul HELVACI diyor ki:

    Şu Desktop create etme ile ilgili makaleyi yazana kadar daha ne paranoyalar geçiririm ben sanırım , acaba sana ödev olarak mı versem ne de olsa mevzuyu anlattım sana :p

  3. Olcay DAĞLI diyor ki:

    Sen onu bana verirsen ben o makaleyi muhtemelen API lerin kullanılmadığı bir dönemde bitirmiş olurum ki o zamanda pek kullanan olmaz sanırım :D

  4. Furkan BACACI diyor ki:

    Evt Gercekten cok yararlı olmus ellerine saglık ancak mesela yazdıgınız kodda hesap makınesını calıstırmıssınız onuda aynı proje ıcınde project1 adında calıstırmıssınız soylekı baska bi programdan calc.exe yi calıstırdıgınızda calc.exe yi neyin çalıştırdıgını gösteriyor ama eğer calc.exe yi çalıştırdıkdan sonra program kapatıyorsa kendını gostermıyor bu yolla calısan trojanlerde mevcut =) ama gercekten güzel olmus

Yorum Yazın