30 Haziran 2009 Salı

SSDT Hooking nedir?

Bilgisayarlarımızı amacı doğrultusunda güzel güzel kullanmak varken - birde kalkmış ne yaptığı belirsiz sayısız zararlı tehdit'i ile uğraşıyoruz. Sanki her biri belirli biz masum son kullanıcıların üzerine atılmış birer KANCA! gibi.

Çok fazla Steven Spielberg okuyorum herhalde jargonum değişti. Neyse; Hooking! Kimine göre gerekli bir mekanizma ama çoğunluk öyle düşünmüyor. İşletim sisteminde yer alan bu faideli ama tehlikeli oyuncak ile dilediğiniz emele ulaşmak içinizdeki şeytanın fısıltıları ile doğru orantılı. Gerek usermode taraflı gerekse kernel taraflı çeşitleri olan hooking işlemini kısa tanımı şöyle olsa gerek:

KernelMode Hooking = "İşletim sistemi bünyesinde bulunan orjinal hizmet fonksiyonlarının hafıza tabanlı adreslerinin ikinci bir dış odaklı amaca hizmet edecek başka bir fonksiyon adresi ile değiştirilmesine" denir. Bu alanların değiştirilmesi işletim sistemi tarafından belirli koruma mekanizmaları ile sağlanmaktadır (bkz:cr0 flags), ancak malumdur ki bu konuda başarı sağlanamamaktadır.

UserMode Hooking = İşletim Sisteminin GUI arayüzünü temsil eden ve usermode çağrılarının ilgili window'lara gönderilmeden önce birinci elden kendini legal hooking mekanizmasına kayıt ettiren kullanıcı processi tarafından işlenmesi ile yapılan hooking çeşitidir. Kullanımı ve dökümantasyonu Microsoft tarafından yapılır.

Api Hooking = Kernelmode hooking de anlatılan mantıkla çalışır ancak bunu koruyan bir mekanizma yoktur. Processlere ait hafıza alanlarında yer alan fonksyion adreslerinin değiştirilmesine dayanır.

Görüldüğü üzere var olan bir sistem akışını ikinci bir müdahale ile istenilen başka bir davranış biçimine sokmaya hooking deniyor. Bunu diler injection ile yapın dilerseniz legal olarak register ile yapın farketmez eğer amacınız sistemin veya kullanıcın hassasiyetlerini gözetmeden suistimal etmekse yaptığınız zararlı yazılım davranışı olacaktır. Burada etraflıca hooking'in bilinen tüm tekniklerini anlatmak ve örnekleri ile açıklamak gibi bir maceraya atılacağımı düşünmüyorsunuz herhalde :) Amacım sadece son yıllarda popülerliğini ve sahip olduğu low level hakimiyeti ile risk derecesini tavan yaptıran KernelMode Hooking kapsamına giren System Service Descriptor Table (SSDT)'nin nasıl modifiye edilebileceği, hangi amaçlar doğrultusunda kullanılabileceği ve nasıl bu yapının korunabileceğine dair kısa açıklamalar yapmaktır. Anlatacaklarımın kalan kısmını okuyan arkadaşların orta seviyede usermode ve kernelmode bilgisi sahibi olması tercih sebebidir.

Win32 Api ortamında kullandığımız fonksiyonların önemli bir kısmı yeteneklerini yardımcı kütüphaneler vasıtası ile gerekli güvenlik ve parametre kontrol işlemlerinden geçtikten sonra kernel mode taraflı bir fonksiyona dallanarak gerçekleştirirler. Bunlardan en çok bilinenleri kernel32.dll ve user32.dll kütüphanelerinde yer alan fonksiyonlardır. Bu kütüphanelerinden birinin export ettiği fonksiyonu kullanan bir process'i usermode çalışan bir debugger(bkz:ollydbg) ile debug ettiğinizde kodun akışını en fazla ntdll.dll kütüphanesi içerisinde yer alan "sysenter" komutuna kadar trace edebilirsiniz. Bu komuttan sonrasını izleyemez ve arka planda gerçekte ne gibi işlemler döndüğünden haberdar olamazsınız. Örnek olarak ExitProcess api'sini uygulamanızdan çağırdınızda izlediği yol şöyledir:

1- Processinizin iat'da yer alan JMP DWORD PTR DS:[&Kernel32.ExitProcess] gerçek fonskiyon adresine zıplar .
2- Oradan da bir kaç dizi parametre kontrol işlemi geçirdikten sonra ntdll.NtTerminateProcess apisini çağırır
3- Son olarakta ntdll.dll kütüphanesi içerisinde bu api ye (NtTerminateProcess) atanmış olan serviceID (bu xp sp3 için 0x101'dir) ile birlikte parametreleride stack'te hazırlayıp "sysenter" komutu ile kontrol asıl fonksiyonu yerine getirecek kernelmode taraflı fonksiyona geçer.

Bu aşamadan sonra süreç kernelmode katmanına geçer. Peki bu süreç nasıl işler? Şimdi de dilerseniz biraz derinlere dalalım ve sysenter sonrası işlemler silsilesine göz atalım.

Windows Xp ve 2003'ün çıkması ile birlikte Microsoft, Intel x86 komut seti kümesine kazandırılan "sysenter" adlı komut ile system service hizmetini sunmaya başladı. Bu komutun çalışması için 2 ön şart gereklidir:

1- Kullanılcak native api serviceID'si
2- Bu ServiceID'ye denk gelen kernel taraflı fonksyion adresini tutan bir tablo.

Windows işletim sistemi boot esnasında bu tabloyu işlemci ailesine göre kullandığı uygun çekirdek dosyası ile ki genelde bu ntoskrnl.exe'dir alarak doğru fonksiyon adresleri ve serviceID'lerini hazırlar ve sysenter komutunun çevrimsel başvurusu için kendini referans gösterip usermode çağrıları için hizmet verecek hale getirir.
Bu tablo kernel symbol referansı olarak KiServiceTable adını alır ve KeServiceDescriptorTable olarak bilinen struct içerisinde adresi tutulur. Tabloda yer alan her serviceID'ye fonksiyonu yerine getirecek uygun kernel taraflı fonksiyonun hafıza adresleri atanır ve özetle tablo artık usermode çağrılarına cevap verecek halini almış olur. Az önce de bahsettiğim gibi normal şartlar altında bu tablo readonly dir ve kernel tarafından yazma korumalıdır ancak minik bir trick le üstesinden gelinip bsod'a meydan vermenden değişiklik yapma şansınız olabiliyor.

Hikayenin TerminateProces ve usermode'dan bir sonraki adımına geldiğimize göre sürecin işleyişinide yukarıdaki anlatımlara göre nasıl şekillendiğinide anlamış olmalısınız. Artık posta kuşumuz elimizden uçtu ve tüm kontrol onda. Win32 api'lerinin tasarımı süphesiz kendi güvenlikliklerinide kapsıyordu ve bunun için System Service Table'larının bu amaçla kullanımı gayet uygundu. Tüm parametre ve çağrılar birinci elden usermode tarafındaki kütüphanelerde gerekli kontrollerden geçiyor ve son olarak artık kullanıcı kodunun erişim imkanı olmayan ve tamamı ile microsoft yazılımcılarının yazdığı güvenilir!!! kod akışına geçiyordu. Ta ki bu işi yüklenmiş olan bu güzide tabloya birinin müdahele etmeyi başardığı zamana kadar.

Aslında bu tabloyu antivirüs üreticileri bile modify ederken bunu başka bir zararlının yapamayacağını düşünmek mantıksız olurdu. Evet çoğu antivirüs ve yazılım tabamlı firewall üreticileri bu tabloyu hook ederek sistemin işleyişine müdahil olurlar. Bir önceki makalemde açığından bahsettiğim Zemana Antilogger gibi HIPS kategorisindeki yazılımlarında kalbide bu katmanda atar. Günümüzde halen usermode taraflı keylogger yazmayı düşünen arkadaşların ne yazık ki bu tip doğrudan api function'una yönelik kısıtlama getiren anti'lere karşı hiç bir şansları yok. Ta ki onlarda bu tabloya müdahele edip kendi amaöçları için değiştirinceye kadar. Peki bu tabloya programcı nasıl müdahale eder. Şunun farkındayım; bu blog çatısı altında kodlama ile uğraşanların çoğu high level dillere aşina ve burada anlattıklarımı koda dökmeleri çok zor ama yinede meraklısının bilmesi gerektiği kanaatindeyim.

Gerek zararlı rootkitler olsun, gerek sizi bu rootkitlerden koruyacağını idda eden savunma programları olsun SSDT denen bu tabloyu hook ederek bu işlevselliklerini sağlarlar. Yani iki tarafında yaptığı bu tabloyu uygun şekilde modifiye ederek kendi amaçları doğrultusunda kullanmaktan ibaret. Örneğin aslında tamamı ile Windows çekirdeğine ait fonksiyon adresleri ile dolu olması gereken bu tablonun Zemana Antilogger uğradıktan sonraki şekli aşağıdaki gibidir:

c:\program files\antilogger\antilog32.sys
0x0025 - NtCreateFile
0x0035 - NtCreateThread
0x003F - NtDeleteKey
0x0041 - NtDeleteValueKey
0x0061 - NtLoadDriver
0x006C - NtMapViewOfSection
0x0074 - NtOpenFile
0x0077 - NtOpenKey
0x007A - NtOpenProcess
0x007D - NtOpenSection
0x0080 - NtOpenThread
0x00B4 - NtQueueApcThread
0x00D2 - NtSecureConnectPort
0x00D5 - NtSetContextThread
0x00F0 - NtSetSystemInformation
0x00F7 - NtSetValueKey
0x0101 - NtTerminateProcess
0x0115 - NtWriteVirtualMemory

Gördüğünüz gibi 18 adet hook edilmiş fonksiyonun listesi ve yanlarında ait oldukları serviceID'leri. UserMode tarafında bir process erişimi, dosya işlemi, port erişimi, fiziksel hafızaya işlemleri ve code injection gibi bir çok işleme ait orjinal fonksiyon çağrıları birinci elden KernelMode katmanında AntiLogger sürücüsü tarafından işlenmekte. Böylelikle program sistem'de erişim kısıtlama ve erişim izni verme yetkilerinede sahip olmuş oluyor. Tabi amacı itibari ile de olması gereken bir işlem bu. Ancak bu işlemin aynını rootkitlerde yapıyor ki bu yüzden microsoft ve işlemci üreticileri buna dur diyerek KPP (Kernel Patch Protection) adı verilen bir sistemle bunun önüne geçmiş durumda(yada şimdilik öyle görünüyor) [1 yıl sonra gelen edit : evet öyle görünüyormuş artık ilk x64 rootkit örnekleri piyasaya çıktı]

Gelelim bu tabloyu nasıl değiştireceğinize. Hızlıca özetlersem \\device\\physicalmemory nesnesine erişim izni alarak işletim sisteminizin kullandığı orjinal kernel dosyasının içerisinden (benim core2 işlemcim için bu ntkrpamp.exe'dir) orjinal Service Dispatch Table fonksiyon adreslerini alıp hook edilmiş olanların üzerlerine yazarak çalışacak her türlü anti'den önce etkisiz kalmasını sağlayabilir veya doğrudan bir kernel rootkit yazarak bazı Antilerin tümü ile etkisiz kalmasını sağlayabilirsiniz.

Sizlerde dilediğiniz gibi üzerinde oynayabilir yada SSDT Hooking mantığını anlayıp kendi özel hook'unuzu yazıp korkusuzca sistemlerde cirit atabilirsiniz. Birdaha ki makaleye kadar sağlıcakla.

İbrahim Akgül

3 yorum:

  1. şimdiye kadar gördüğüm en teknik, wn bulunmaz, en güzel makale teşekkür ederim.

    YanıtlaSil
  2. tam da usermode hookingle çalışan logger kodlamaktan bıktığım; kernelmode çalışan rootkitlere merak saldığım bir anda ssdt hooking hakkında böyle güzel bir türkçe kaynakla karşılaşmam harika oldu
    teşekkür ediyorum.

    YanıtlaSil
  3. Oldukça açıklayıcı bir makale olmuş. Kod bazında biraz örnek verseydiniz keşke:) Ama arıştırıyorum teşekkürler.

    YanıtlaSil