Rootkit Geliştirme Temelleri-I

Rootkitler,
bir sistem üzerinde sistem yöneticisinine fark ettirmeden kalıcı
kontrol sağlayabilen yazılımlar olarak tanımlanabilir. Bir yandan
işletim sisteminin bir parçası gibi davranıp(ya da gerçekten olmayı
başarıp) gizli kalmaya çalışırken, diğer yandan dışarı bilgi aktarmak
veya uzaktan kontrol için arkakapı oluşturmak gibi amaçlara hizmet
ederler. 
Bu yazıda, Windows işletim sisteminde, rootkitlerin olmazsa
olmazı dosya veya dizinleri gizlemek ve processleri görünmez kılmak için
kullanılabilecek bazı yöntemler ele alınmıştır.

Windows
işletim sistemi günümüz işlemcilerinde bulunan modlardan iki tanesini
kullanır, protected mode and supervisor mode. Şekildeki gösterimden
dolayı ring3 ve ring0 olarak da adlandırılırlar.

Windows’ta
işletim sistemi çekirdeği ve sürücüler ring0, uygulamalar ise ring3
seviyesinde çalışırlar. Sistem seviyesinde bir gizlilik sağlamak için
rootkitler de ring0 seviyesinde çalışırlar.

Kernel Mode Driver

KMD
(kernel mode driver), çekirdek seviyesinde çalışan bir uygulama olarak
düşünülebilir ancak derlemek için kullanılan araçlar ve kodlamada
kullanılan API farklıdır. Temel olarak bir KMD’nin yapısı şu şekildedir.

driver.c
#include “ntddk.h”
void Unload(IN PDRIVER_OBJECT pDriverObject) {
       DbgPrint(“Unload çalıştı.”);
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING theRegistryPath) {
   DbgPrint(“DriverEntry çalıştı.”);
   pDriverObject->DriverUnload = Unload;
   return STATUS_SUCCESS;
}

DriverEntry
fonksiyonunu KMD’nin main fonksiyonu olarak düşünülebilir. KMD
çalışmaya buradan başlar. DbgPrint fonksiyonu ile debug ekranına
yazılabilir. KMD sonlanırken de çalışacak fonksiyonu(Unload) parametre
olarak gelen pDriverObject nesnesinin (buradaki nesne bir sınıfın örneği
anlamında değil belli bir veri yapısındaki değişken anlamında
kullanılmıştır.) DriverUnload öğesine atanmalıdır. KMD WDK ile
derlenebilir. Debug çıktılarını görmek içinse Sysinternals’ın DbgView
uygulaması kullanılabilir. Kodu derlemek için basit bir MAKEFILE ve
SOURCES dosyası yeterli olacaktır.
MAKEFILE
!INCLUDE $(NTMAKEENV)makefile.def
SOURCES
TARGETNAME=RTDRIVER
TARGETPATH=OBJ
TARGETTYPE=DRIVER
SOURCES=driver.c

1. WDK x86 build environment’ı açıp driver dosyalarının bulunduğu dizine geçip build komutunu çalıştırarak dosyalar derlenir.
2.
Yönetici haklarıyla çalıştırılmış bir konsolda derlediğimiz sürücüyü
sisteme yükleyecek komutlar çalıştırılır. Kolaylık olması açısından
drvreg.bat dosyası düzenlenerek kullanılabilir.
drvreg.bat
@echo off
setlocal
REM Notice how there are no spaces between the parameters and the equals sign
set CREATE_OPTIONS= type= kernel start= demand error= normal DisplayName= rkdriver
sc.exe create rkdriver binpath= “C:RTDriverobjfre_win7_x86i386rtdriver.sys” %CREATE_OPTIONS%
sc.exe description rkdriver “SOOL subsystem for Windows Resource Protected file”
endlocal
3. DbgView uygulaması yönetici hakları ile açılıp üst menüden capture->capture kernel seçeneği işaretlenir.
4. “sc start rkdriver” komutu ile sürücü başlatılıp çıktı dbgview’de gözlenir.
5. “sc stop rkdriver” komutu ile sürücü durdurulup çıktı yine dbgview ile gözlenebilir.

6. “sc delete rkdriver” komutu ile sürücüyü kaldırabilirsiniz.
KMD’nin
donanımla ya da ring3 uygulamalarla iletişim kurması için IRP’leri (I/O
Request Packet) kabul edip yorumlayabilmesi gerekir. IRP’leri
Windows’ta  I/O Manager kontrol eder. Desteklenen IRP tipleri wdm.h
dosyasında bulunmakla beraber genelde
  • IRP_MJ_READ,
  • IRP_MJ_WRITE,
  • IRP_MJ_DEVICE_CONTROL
yeterli olacaktır.
KMD
ekteki şekilde(driver.c) güncellenerek ring3 seviyesinde uygulamalarla
iletişime geçebilecek(komut alabilecek) hale getirilmiştir. Yapılan
değişiklikler temel olarak şu şekildedir:
  • DriverEntry
    fonksiyonu IRP’leri kullanabilecek şekilde güncellendi. Aslında
    IRP_MJ_DEVICE_CONTROL durumu için mesajı işleyecek olan
    dispatchIoControl fonksiyonu atandı. Geri kalan durumlar içinse bir
    işlem yapmadan durumu geçiştiren bir defaultDispatch fonksiyonu atandı.
  • Gelen komutu inputbuffer’dan okuyup kontrol edecek dispatchIoControl fonksiyonu yazıldı.
  • Sürücüye erişim için isim ve link oluşturan fonksiyonlar yazılıp DriverEntry’de çağırıldı.
  • Sürücü durdurulup tekrar çalıştığında çakışma olmaması için Unload fonksiyonunda İsim ve link kaldırıldı.
RING3 to RING3 İletişimi
sendcmd.c
dosyasında basitçe KMD’nin adını ve CreateFile WINAPI fonksiyonu
kullanılarak bir file handle oluşturulup, bu handle ve DeviceIoControl
kontrol fonksiyonu kullanılarak KMD’ye komut gönderilmiştir. Program
Visual Studio ile derlenip KMD çalışır durumdayken çalıştırıldığında
DbgView’in örnek görüntüsü şu şekilde olmalıdır.
Birinci
bölümde KMD genel hatlarıyla tamamlanıp ring0 ve ring3 iletişimi
sağlanmış ve test edilmiştir. İkinci bölümde ise dosya ve process
gizleme işlemleri için kullanılan bazı yöntemleri inceleyip şuana kadar
yapılan çalışmanın üzerine eklenecektir.

Yazıda kullanılan kodlara aşağıdaki adreslerden erişebilirsiniz.
driver.c
https://docs.google.com/file/d/0B2ItycPl6RKKNDdQcVJvMTNYX2s/edit?usp=sharing

sendcmd.c
https://docs.google.com/file/d/0B2ItycPl6RKKQk12YnJBTVFjRUk/edit?usp=sharing

Kaynaklar:
The Rootkit Arsenal 1st Edition by R. Bill Blunden
Subverting The Windows Kernel by Greg Hoglund, James Butler
Professional Rootkits by Ric Vieler
Onur ALANBEL <onur.alanbel@bga.com.tr>