24 Haziran 2016

Rootkit Geliştirmenin Temelleri-II

Posted by: onuralanbel 24 Haziran 2016
Windows işletim sisteminde hem kullanıcı seviyesinde(user level) hem de çekirdek
seviyesinde(kernel level) hook işlemi yapılabilir. Hook işlemi sistemin veya diğer uygulamaların kullandığı belli fonksiyonların işlevini değiştirmek veya incelemek amacıyla yapılır. İşleyişi değiştirmek için fonksiyonu çalışma anında yamamak veya ürettiği sonucu isteği yapan uygulamaya göndermeden önce modifiye etmek gibi seçenekler uygulanabilir. 

Bu yazıda SSDT (system service dispatch table) kullanarak çekirdek seviyesinde hook işlemi ile dosya ve süreçlerin gizlenmesi ele alınmıştır. Bahsedilen uygulamaların kaynak kodlarının tam halini şu adresten indirebilirsiniz.


https://docs.google.com/file/d/0B2ItycPl6RKKYnF3T1VoWEdpS1k/edit?usp=sharing.
Kodlar Windows 7 professional x86 işletim sisteminde test edilmiştir.

SSDT Kullanarak Çekirdek Seviyesinde Hook işlemi


Windows işletim sisteminde sistem servislerinin adresleri SSDT’de tutulur. SSDT bir servis fonksiyonunun hafızadaki adresine erişmek için kullanılır. KeServiceDescriptorTable adındaki başka bir tablo da, SSDT üzerinde Ntoskrnl.exe tarafından sağlanan temel sistem fonksiyonlarının adreslerinin bulunduğu bölümü gösteren bir girdi içerir. SSDT’de, işlevi değiştirilmek istenen fonksiyonların yerine belirlenen fonksiyonların adresleri atanıp, fonksiyonlar çağırıldığında kontrolü rootkit yazarında olan yeni fonksiyonlar aracılığıyla istenen veri döndürülebilir. Örnek olarak süreç gizlemek için ZwQuerySystemInformation ve dizin gizlemek için ZwQueryDirectoryFile fonksiyonlarına hook işlemi ele alınmıştır.

1. SSDT’nin Yazma Korumasının Kaldırılması


SSDT gibi önemli sistem yapılarınının gelişigüzel değiştirilmesini engellemek için hafızanın bu bölümlerinde yazma koruması uygulanmaktadır. Bu korumayı aşmak için Win7 x86 ve öncesi sistemlerde şu kod kullanılabilir. (modwp.c)
Kodun mantığı temel olarak intel mimarisinde yazma koruması için kullanılan control register’ın CR0 bitinin değerini değiştirmeye dayanmaktadır.

disableWP_MDL fonksiyonu şu şekilde kullanılır.

WP_GLOBALS wpGlobals;

wpGlobals = disableWP_MDL(    KeServiceDescriptorTable.KiServiceTable,
KeServiceDescriptorTable.nSystemCalls);
  
if((wpGlobals.pMDL == NULL) || (wpGlobals.callTable == NULL)) {
       return(STATUS_UNSUCCESSFUL) ;
}
pMDL = wpGlobals.pMDL;
systemCallTable = (PVOID*)wpGlobals.callTable;
//hookSSDT(oldfunction, newfunction, systemCallTable)

2. HookSSDT Fonksiyonu

(hookssdt.c, ssdt.h)

hookssdt.c dosyası getSSDTIndex, NtRoutineAddress, hookSSDT ve unHookSSDT olmak üzere dört fonksiyon içermektedir. hookSSDT ve unHookSSDT ana fonksiyonlar, diğerleri ise bu fonksiyonların kullandığı yardımcı fonksiyonlardır. ssdt.h dosyası da gerekli veri yapısı tanımlarını içerir.


BYTE* hookSSDT(BYTE* apiCall, BYTE* oldAddr, DWORD* callTable) {

   PLONG target ;

   DWORD indexValue;

   indexValue = getSSDTIndex(apiCall);

   target = (PLONG) &(callTable[indexValue]);

   return( (BYTE*)InterlockedExchange(target, (LONG)oldAddr));

}

Fonksiyon parametre olarak sırasıyla değiştirilecek fonksiyonun adresi, yeni fonksiyonun adresi ve SSDT’nin adresini alır. getSSDTındex fonksiyonunu kullanarak fonksiyonun SSDT tablosundaki yerini bulur ve atomik(işleyiş sırasında kesilemez) olarak çalışan InterlockedExchange fonksiyonu ile yeni adresi ilgili indexe yazar.

unHookSSDT fonksiyonu da hook kaldırılmak istendiğinde çağırılır. hookSSDT fonksiyonunun ilk iki parametresini yer değiştirerek çağırmak da aynı işi görür ama karışıklık olmaması açısından ayrı bir fonksiyon yazılmıştır.

getSSDTIndex fonksiyonu adından da anlaşılacağı gibi parametre olarak verilen fonksiyonun SSDT indexini döndürür.

NtRoutineAddress ise kiServiceTable’da, verilen SSDT indexe karşılık gelen adresi döndürür.




3. Yeni ZwQueryDirectoryFile ve ZwQuerySystemInformation Fonksiyonlarının Yazılması


(ZwQueryDirectoryFile.c, ZwQuerySystemInformation.c)

İlk bakışta uzun C kodları gibi görünseler de temel mantıkları basittir.

ZwQueryDirectoryFile.c:
Fonksiyon çağırıldığında ilk olarak kendi parametreleri ile orijinal fonksiyonu çağırır. Geriye parametre olarak gelen file handle’ın gösterdiği dizindeki dosyaların bilgilerinin bulunduğu bir bağlı listenin başlangıcı döndürür. Devamında bu liste taranıp, RtlCompareMemory fonksiyonu kullanılarak hiddenDirName adlı değişkende belirlediğimiz öneki taşıyan dosyalar kontrol edilir. Koşula uyan dosyalar listeden çıkarılır. Bu sayede fonksiyon tamamlandığında, ZwQueryDirectoryFile fonksiyonunu çağıran uygulama dosyaların listesini taradığında çıkarılmış olan dosyalardan haberi olmaz.

ZwQuerySystemInformation.c:
Bu fonksiyonun da benzer mantıkla çalışır. Yine başlangıçta orijinal fonksiyonu çağırıp süreçlerin listesini elde eder. Daha sonra hiddenProc değişkeninde belirlediğimiz isimdeki süreci arar(yine önek ya da birden fazla isim de kullanılabilir). Eğer süreç bulunursa listeden çıkartılır ve tüm liste tarandıktan sonra fonksiyon sonlanır. Süreç listesini ZwQuerySystemInformation fonksiyonu aracılığıyla elde eden uygulamalarda (windows görev yöneticisi gibi) listeden çıkarılmış süreç gözükmez.

4. KMD’nin Ana Dosyasının Güncellenmesi


(driver.c)
Son olarak driver.c dosyasının, ring3 uygulamadan komut geldiğinde hookları aktif edecek ve driver kaldırılırken hookları kaldıracak şekilde güncellenmesi gerekmektedir. Bunun için adım 1’deki disableWP_MDL fonksiyonunu kullanarak yazma korumasını kaldıran ve adım 2’deki hookSSDT fonksiyonunu kullanarak hookları aktif eden hook isminde bir fonksiyon yazılmıştır. Bu fonksiyon “Rootkit Geliştirmenin Temelleri 1” adlı ilk yazıda hazırlanan ring3 seviyesindeki uygulamadan komut alma bölümüne eklenmiştir. Yine aynı yazıda hazırlanan sendcmd uygulamasında bir değişiklik yapmaya gerek yoktur. driver.c dosyasında yapılan bir diğer değişiklik ise Unload fonksiyonu içinde unhook fonksiyonu çağırılmıştır. Bu sayede driver kaldırıldığında sistem sorunsuzca çalışmaya devam edebilir.

5. Kodların Test Edilmesi


Kodlar ilk yazıda anlatılan araçlar ve yöntemler kullanılarak derlenip driver yüklenir. Driver derlendiğinde örnek çıktı:

Örnek kodlarda gizlenecek uygulama “notepad”, gizlenecek dosya/dizin öneki ise “000gizli” olarak belirlenmiştir. Driver çalışmasına rağmen henüz kullanıcı seviyesi uygulamadan komut gönderilmediği için hooklar aktif olmamıştır. hooklar aktif olmadan önceki ekran görüntüsü şu şekildedir.



İlk yazıda hazırlanan sendcmd uygulaması çalıştırılıp, görev yöneticisinden notepad’in masaüstünden de 000gizliaa dosyasının kaybolduğu gözlenir.



Driver çalışırken oluşan DbgView çıktısı:




Kodların tamamını satır satır incelemek şart olmasa da açıklanan bölümleri kod üzerinde çalışmak faydalı olabilir. WinAPI fonksiyonlarıyla ilgili detaylı bilgiye http://msdn.microsoft.com/library/default.aspx adresinden ulaşılabilir.



Kaynaklar:
The Rootkit Arsenal 1st Edition by R. Bill Blunden
Subverting The Windows Kernel by Greg Hoglund, James Butler
Professional Rootkits by Ric Viele
Makalelerin kötüye kullanım kullanıcının sorumluluğundadır. | networkpentest.net. Blogger tarafından desteklenmektedir.