Windows 7 ile değişen API dinamik kütüphane mimarisi

Merhaba.

Yine uzun bir aradan sonra bir başka yazı ile burdayım. Bugün değinmek istediğim konu başlıktan da anlaşılabileceği üzere Windows 7 (NT 6.1)’de API sağlayan dinamik kütüphanelerde yapılmış değişiklik hakkında.

Eğer bir program yazdıysak ve bu program Windows API’larından herhangi birisini (Misal registry, file i/o vs) kullanmışsa bu işleri sizin programınıza aracılık etmekle görevli API Dinamik Bağlanılabilir Kütüphane (DLL) dosyaları linking aşamasında programımıza yerleştirilir. Bu DLL dosyaları içinde çağırdığımız API’yı ilk elden alarak gerekli ön işlemlerini (Programcı tarafından geçilen verilerin doğruluğu veya hasarsız olduğu gibi işlemler olabilir) geçerek ve eğer çağrı Kernel mode altında çalışması gereken bir şeyse kernel mode’a geçmesine aracılık ederler. Normalde bu işleri yürüten kodlar bu DLL’lerin içerisinde statik olarak dururlar. Ancak Windows 7’da bu böyle değildir. Aslında bu anlatacaklarım daha ziyade NT çekirdeğinin MinWin adı verilen bir şekle kaydırılması. MinWin nedir diye soracak olursanız kısaca NT Çekirdeğinin çoğu şeyden arındırılıp küçük ve hızlı bir kernel ortaya çıkarma fikrinin adı. Belki ilerde bununla alakalı birşeyler de yazabilirim. Ama şimdiki konumuz MinWin değil.

Pek çoğumuz herhangi bir Win32 API DLL’ini incelerken şu tarz bir şey görmüş olabilirsiniz.

Örnek olarak incelediğimiz Task Manager (Görev Yöneticisi) taskmgr.exe’ye bağlanmış DLL’leri görüyoruz. Misal bu uygulama advapi32.dll tarafından export edilmiş bir kaç API call yapmış. Buraya kadar herşey tamam. Ancak baktığımızda Advapi32.dll’in de bir kaç DLL’den referans aldığını görüyoruz. Bu DLL isimlerine bakarsak belli bir prefix (ön ek) alıp sınıflandırılmış. Peki bu DLL’ler ne işe yarıyor. Esasında hiçbir işe yaramıyorlar. Bu DLL’ler sınıflara ayrılmış birer taslak. Yani mantıksal Dll dosyaları. API Fonksiyonlarını içeriyorlar ancak hiçbirşey yapmıyorlar.

Örneğin taskmgr.exe’nin Advapi32.dll’inde kullandığı bir API’ı ele alalım.

Bu API fonksiyonu OpenSCManagerW olsun. Bu fonksiyon belirtilen bir makineye ait servis yönetici veritabanı ile bir bağlantı kurar. Bunu taskmgr.exe Advapi32.dll’inden referans almıştı.  Seçtiğimiz API fonksiyonu bir servis yönetici fonksiyonu olduğu için Service Management kategorisine ayrılmış taslak DLL’de bulunmalı.

Gördüğünüz gibi API-MS-WIN-Service-Management-L1-1-0 taslak dll’inde export edilmiş. Peki taskmgr.exe bütün bunları bilmeden sadece advapi32.dll’ini bağlamış ve OpenSCManagerW API fonksiyonunu çağırmıştı. Peki bu çağrılan fonksiyon ne yapıyor? Bu fonksiyon statik durumda iken bu referans aldığı taslak dll’deki ilgili fonksiyon implementasyonuna zıplıyor.

Görüldüğü gibi Advapi32.dll’deki OpenSCManagerW API koduna bakarsak gördüğümüz taslak kısma zıplayan bir koddan ibaret. Peki taslak kısımda durum nasıl.

Taslak kısmındaki API fonksiyonun yaptığı şey NULL döndermek. 3 adet parametre aldığı için ret 0xc (12 byte) ile stack’I dengeleyip NULL dönderiyor. Bu fonksiyonun türüne göre ufak farklılık gösterir ama pointer dönderen fonksiyonlar için NULL, diğer değerler için genel de 1 (TRUE) dönderir.

NT 6.1 Kernel bir kütüphane yükleneceği zaman prosese ait adres alanına bu statik kod yerine gerçek fonksiyona ait koda dallanacak şekilde dinamik olarak değiştirilir.

Yükleyici kütüphaneleri yüklerken her zamanki gibi ntdll altında sağlanmış Loader fonksiyonlarını çağırır. Windows 7 ile bu fonksiyonlara demin bahsettiğimiz taslak dll’leri çözen rutinler eklenmiş gerekli ise çözümlenerek eşlenmektedirler. Örneğin bir kütüphane yüklemek istediğimiz (LoadLibraryEx) nasıl bir işlemden geçmekedir?

Yükleyici API fonksiyonunu çağırdığımızda ilk elden işlemi devralan ntdll fonksiyonu işlemeye başlayacaktır.

ntdll.dll!_ApiSetResolveToHost@20()  + 0xf bytes
ntdll.dll!_LdrpApplyFileNameRedirection@28()  + 0x35 bytes
ntdll.dll!_LdrpLoadDll@24()  + 0xae bytes
ntdll.dll!_LdrLoadDll@16()  + 0x74 bytes
KernelBase.dll!_LoadLibraryExW@12()  + 0x120 bytes

Yukarıda kütüphane yüklenmesi sırasında bir callstack çıktısı görüyorsunuz. LdrpApplyFileNameRedirection ve sonraki kısım bahsettiğimiz mekanizmanın işletilmesi için gerekli rutinlerdir. LdrpApplyFileNameRedirection ile yüklenmek istenen Dll’in taslak bir dll olup olmadığı eğer taslak bir dll ise o yönde yönlendirme yapılması işlevlerini yapan ilk rutindir. Hemen sonrasında ise gerçek anlamda bu kontrol ve çözümleme işlemi ApiSetResolveToHost aracılığı ile yapılıyor.

LdrpApplyFileNameRedirection fonksiyonun içeriğini gördüğümüz gibi esas kontrol rutini ApiSetResolveToHost çağrılıyor. Eğer taslak bir kütüphane değilse fonksiyondan çıkılıyor. Bir de ApiSetResolveToHost fonksiyonuna göz atalım.

ApiSetResolveToHost yüklenmek istenen kütüphane dosya adını kontrol ediyor. Yukarda bahsetmiştik taslak Dll dosyaları API- şeklinde bir prefix’e sahipti. Fonksiyon dosya adının ilk 4 kısmının “API-“ prefixi olup olmadığını kontrol ediyor. Eğer değilse bu baştan bir taslak dll’i olmadığını belirtiyor devam etmeye gerek yok ve çıkıyor. Eğer API prefix’i mevcutsa taslak dll ile ilgili çözümleme yapan kod bloğuna zıplayarak tam anlamı ile dosya adını parçalayıp (parse) kategorilere ayrılmış karşılıkları duran bir hashtable dan eşleyerek gerçek kütüphaneyi buluyor. Eğer zaten normal bir kütüphane dosyası ise başarısız olarak dönüp Yükleme işlemine devam ediliyor. Tüm bu kontrollerden sonra LdrpLoadDll, LdrpFindOrMapDll isimli fonksiyonu çağırarak gerçek anlamda kütüphaneyi eşleme işlemini tamamlıyor.

ntdll.dll!_LdrpFindOrMapDll@24()  + 0x56 bytes
ntdll.dll!_LdrpLoadDll@24()  + 0x145 bytes
ntdll.dll!_LdrLoadDll@16()  + 0x74 bytes
KernelBase.dll!_LoadLibraryExW@12()  + 0x120 bytes

Taslak kontrol sonrası eşleme fonksiyonu çağrısı sonrası callstack görünümü. Bu işlem ardından eğer geçerli bir kütüphane ise bu kütüphanenin modül tutamaç (module handle) bilgisi dönderiliyor.

Peki ya programlar bundan etkilenmiyor mu?

Hayır. Çünkü geriye uyumluluk mevcut. Görece eski bir uygulama Kernel32.dll ‘den bir API kullandıysa yine yukardaki şekilde kernel32.dll tarafından taslak DLL’ler aracılığı ile yönlendirilmektedir. Bu sebeple önceki versiyon Windows işletim sistemlerinde kullandığınız programları sıkıntı yaşamadan kullanabiliyorsunuz.

Şimdilik benden bu kadar. İyi günler.

2 responses to “Windows 7 ile değişen API dinamik kütüphane mimarisi

  1. Merhaba yazınız için tşk ederim. Bu konuda size ufak bi sorum olacak yardımcı olabilirseniz çok sevinirm.

    Ben bilgisayara basit bir kartlı oturum açma uygulaması yapmaya çalışıyorum. Bitirme tezim için. Bunun için bir windows uygulamsaı yazıcam oturum açma kısmında windowsun ekranı yerine geçip kart okuyucudan bilgi bekleyecek. bilgi geldiğinde karttaki bilgilerle oturum açmaya çalışacak. bunun için netten advapi32.dll dll’ini kullanmam gerekiyortiğini öğrendim ama tam bilgi bulamadım.

    Bu konuda kısaca bilgi vereilir misiniz araştırmamda yardımcı olması için?

  2. Merhaba. Bu kadar çok uzun aradan sonra cevap verdiğim için özür dilerim. Blogumla ilgilenecek vakti pek bulamıyordum. Sorunuza gelecek olursak yapmak istediğiniz şey advapi32’nin biraz ötesinde bu iş için NT local security authory konusunu araştırmanızı öneririm. http://msdn.microsoft.com/en-us/library/ms721855(v=VS.85).aspx ve http://msdn.microsoft.com/en-us/library/ms721849(v=VS.85).aspx bu linklere göz atmanızda fayda var.

Leave a Reply to Oguz Kartal Cancel reply

Your email address will not be published.