28 Mayıs 2016

Rootkit Geliştirmenin Temelleri-I

Posted by: onuralanbel 28 Mayıs 2016
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:\RTDriver\objfre_win7_x86\i386\rtdriver.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
Makalelerin kötüye kullanım kullanıcının sorumluluğundadır. | networkpentest.net. Blogger tarafından desteklenmektedir.