Kayıt Ol

Giriş

Şifremi Kaybettim

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

soru ekleme

Soru sormak için giriş yapmalısınız.

Giriş

Kayıt Ol

.........

Windows Kernel Sürücüsü Geliştirmek

Windows Kernel Sürücüsü Geliştirmek

Merhabalar,

Öncelikle çekirdek sürücülerinin ne olduğundan bahsedelim.(kernelturk)

  • Mimariyi Tanıyalım

Ana Sistem Bileşenleri

Windows NT’nin mimarisi dahili olarak code denetimi (code permissions) ve adres boşluğu (address space) olarak iki kısma ayrılmıştır. Bu ayırım işlemi ile daha güvenli ve daha esnek bir işletim sistemi oluşturulması amaçlanmıştır. Ayrıca programcılar içinde yeni nesil işlemcilerin tüm yeteneklerinin kullanılması amaçlanmıştır. İşletim sistemi üzerinde çalışacak her programın çalışması için bir hafıza alanına ihtiyacı vardır. Bu alanlar işletim sistemi tarafından adres boşluklarının organize bir şekilde yönetilmesi ile uygulamalara paylaştırılır. Adres boşluğunun paylaşımı ise sanıldığının aksine basit bir mantığa dayanmaktadır. 32-Bit işlemci mimarisinde Adreslenebilir 4GB hafıza iki eşit parçaya ayrılır (tabi burada Fiziksel Adres açılımı olan PAE desteğini yok sayıyoruz)  ve bu iki parçadan kullanıcı modun’da (user-mode) olana bu boşluğun en düşük alanı olan 00000000 – 7FFFFFFFh adresleri arasındaki 2GB’lık alan verilir. Yani User-Mode dediğimiz user process’leri bu hafıza alanında çalışır ve bu onlar için bir sınır değerdir. Diğer kalan üst limit 80000000 – 0FFFFFFFFh ‘lik doğrusal hafıza alan adresi oranı ise aygıt sürücüleri (device drivers) , sistem hafıza havuzu (system memory pools) ve sistem data yapıları (system data structures) gibi sistem bileşenlerine verilir. Bu adres oranlarına adreslenebilir hafıza alanları diyoruz. Bu hafıza alanları arasındaki ayrım ve yönetim işlemlerini ise hangi bileşenlerin kontrol ettiğini makalenin ilerleyen kısımlarında ayrıntılı bir şekilde işleyeceğiz.

User-mode’da çalışan temel işlemleri aşağıdaki şekilde tanımlayabiliriz:

  • Sistem Destek İşlemleri (System Support Processes) – örneğin, Logon process’i (\%SystemRoot%\System32\Winlogon.exe dizininde yer alır);
  • Hizmet İşlemleri (Service Processes) – örneğin, Yazıcılar için Spooler servisi (\%SystemRoot%\System32\spoolsv.exe’da yer alır);
  • Kullanıcı uygulamaları (User Applications) – beş çeşittir: Win32, Windows 3.1, MS-DOS, POSIX ve OS/2;
  • Ortam AltSistemleri (Environment Subsystems) – Windowsta üç çeşit ortama ait processleri çalıştırabilirsiniz: Win32 (\%SystemRoot%\System32\Csrss.exe yer alır); POSIX (\%SystemRoot%\System32\Psxss.exe’yer alır); OS/2 (\%SystemRoot%\System32\Os2ss.exe yer alır).

Windows XP ile birlikte artık OS/2 alt sistemi kaldırılmıştır.

Kernel-Mode bileşenleri ise aşağıdaki gibi tanımlanabilir:

  • Yönetim (Executive) – hafıza yönetimi, process ve thread yönetimi, security, etc.;
  • Kernel – thread’ların planlanması, kesme isteği(interrupt) ve istisna işleme (exception dispatching), etc. (Executive ve Kernel \%SystemRoot%\System32\Ntoskrnl.exe tarafından icra edilir);
  • Aygıt Sürücler (Device Drivers) – Donanım aygıt sürücüleri (hardware device drivers), dosya sistemi sürücüleri (file system) ve ağ sürücüleri ( network drivers);
  • Donanımdan soyutlandırma katmanı (Hardware Abstraction Layer), HAL – Kernel’den aygıt sürücülerden yönetim biriminden ve platforma özel donanım farklılıklarından yalıtılmış bir birimdir. ( \%SystemRoot%\System32\Hal.dll’de yer alır);
  • Pencere ve Grafik sistemi (Windowing And Graphics System) – Pencerelerle çalışmak, kullanıcı arayüz kontrolleri ve çizim (drawing) işlemleri ile uğraşmak için grafiksel kullanıcı arayüzü (Graphical user interface [GUI]) fonksiyonları sağlar. ( \%SystemRoot%\System32\Win32k.sys’de yer alır).

1.1.2 Kernel Mode vs. User Mode

Aslında Intel x86 işlemcileri 4 adet imtiyaz seviyesi (privilege levels) sağlar (ring olarakta anılırlar) , ancak Windows bunlardan sadece 2 sini kullanır. Bunlar Kernel-Mode için privilege levels 0 (veya ring0) , user-mode için ise privilege levels 3 (veya ring3) seviyesidir.

Her user-mode processi kendine ait özel bir hafıza boşluğuna sahiptir. Processler en düşük imtiyaz seviyesinde (user-mode veya ring 3 diyebilirsiniz) çalıştıklarından, özel cpu komutlarını icra edemez, sistem data’ları ve sistem adres boşluğuna erişim sağlayamaz ve donanıma doğrudan erişim yapamazlar. Örneğin user-mode’da çalışan bir process adres boşluğunun kernel-mode tarafına ait bir orandaki hafıza adresine (8000000-0FFFFFFFFh) ulaşmaya çalışırsa, sistem o işlemi hemen sonlandıracaktır. User-Mode processleri sistem servislerini çağırarak kernel-mode’a geçiş yapabilirler ancak bu durum o hizmete yaptırılan işlemlerle sınırlıdır ve  process user-mode’a döner dönmez tüm kontrolü tekrar kaybedecektir.

User-Mode processleri sistem stabilizesini bozabileceklerinden potansiyel tehlike olarak görünürler. Bu yüzden sahip olduğu imtiyazlar sert çizgilerle belirlenmiştir ve yetkisizce yapmaya çalıştığı her işlem anında sonlandırılır.

Kernel-Mode bileşenleri ise kernel-mode hafıza alanını ortak bir şekilde paylaşırlar, en üst imtiyazlarla (ring0) çalışabilir ve istedikleri CPU komutunu çalıştırabilirler. Kısacası erişimleri sınırsızdır.

Sistemin adres boşluğunda çalışan kodlar tümüyle güvenilir olarak düşünülür. Bir sürücünün yüklenmesi esnasında sistem o sürücü kodlarını kendi bölümüymüş gibi varsayar. Driver’lar kernel’in kendi güvenilir bileşenleri listesinde yer aldığından istediği her erişimi sınırsızca yapabilir.

Tam olarak ifade edersek user-mode uygulamaları işletim sistemi tarafından bütünüyle soyutlanmıştır. Aslında bu işletim sisteminin bütünlüğü açısından iyidir, fakat , debugging araçları gibi bazı yardımcı araçların için tam bir baş ağrısıdır. User-Mode uygulamaları ile sistemle bütünleşik bir yazılım gerçekleştirmek çoğu zaman imkansızdır. İşletim sisteminin dahili fonksiyonları ve data yapıları’na user-mode’dan asla ulaşamazsınız bunun için yapmanız gereken sistem adres boşluğunun içerisine girmektir buda  kernel-mode düşerek olur.

Windows NT Device Drivers

1.2.1 Aygıt Sürücülerinin Tipleri

Windows NT geniş bir yelpazede aygıt sürücü tiplerini destekler, bunları aşağıdaki gibi listeleyebiliriz:

  • User-Mode Drivers:
    • Virtual Device Drivers (VDD) – 16-bit MS-DOS uygulamalarını emule edebilmek için kullanılan bir user-mode bileşenidir. Karıştırmayasınız diye yazıyorum Win 9x zamanı VxD’lerle benzer bir yanları yoktur.
    • Printer Drivers – Aygıttan bağımsız baskı isteklerini yazıcıya özel komutlara çevirirler.
  • Kernel-Mode Drivers:
    • File System Drivers – Standart dosya sistem işlemlerini yerine getirirler.
    • Legacy Drivers – Windows 2000/XP/2003 üzerinde değişmemiş ama önceki Windows NT versiyonları için yazılmış farklı sürücülerden yardım almaksızın bir donanım aygıtını kontrol etmeye yarayan sürücü çeşididir.
    • Video Drivers – görsel data işleme;
    • Streaming Drivers – ses ve tv kartı gibi multimedia aygıtları içindirler;
    • WDM-Drivers – Windows Driver Model konseptine bağlıdırlar. WDM; Windows NT’nin güç yönetim desteğini ve tak çalıştır desteğini destekler. WDM’ler işletim sistemleri arasında binary uyumlulukları sayesinde kaynak-uyumu sağlarlar. Örneğin Windows 2000 için yazılmış bir WDM driver Windows Me ve 98 üzerinde çalışabilir.

Bunlardan farklı modellerde vardır ancak şimdilik bu konsepti tanımanız açısından yeterlidir.

Adlarında da gayet net anlaşılacağı gibi aygıt sürücüler bir aygıtı kontrol etmek için kullanılırlar. Ancak iyi bir tarafları vardır ki bu aygıt illa ki fiziksel bir aygıt olmak zorunda değildir. Dilerseniz sanal bir aygıt oluşturup onu programlayabilirsiniz.

Yapısal olarak aslında aygıt sürücüleri bir PE-format (Exe) dosyasından başka bir şey değildir. Aygıt sürücüler (Device Drivers) yüklenebilir kernel-mode modülleridirler. Genel olarak .sys uzantılarına sahiptirler. Aygıt sürücüler yükleme ve yönetim açısından bütünüyle farklı yollara sahiptirler. Gerçekte kernel-mode dll’leri user-mode tarafında çözülemeyecek görevleri yerine getirilmesi için tasarlanırlar. Bir de şu var ki biz user-mode processlerimiz ile aygıt sürücülerimizin ne kod ne de data alanlarına ulaşamayız. Bizim sürücülerimizle irtibat kuracağımız tek yol I/O Yöneticisi (I/O Manager)’dir.

Kernel-mode aygıt sürücüsü geliştirme aşamasında kendinizi bütünüyle çaylak hissedecek ve aslında önceden öğrendiğiniz onca programlama ve Win32API bilgisinin şimdi nasıl olup ta size yardımcı olamadığına şahit olacaksınız. Belki bundan önce hatırı sayılır user-mode uygulamaya imza atmış olabilirsiniz ancak kernel-mode mimarisinin komutları ve yapıları bütünüyle farklıdır.

  • Katmanlı ve Monolithic (Tek-Katmanlı) Aygıt Sürücüleri

Katmanlı sürücülerin çoğu fiziksel aygıtları kontrol etmek için yazılırlar. Adlarından gayet net anlaşıldığı gibi katmanlı sürücüler drivers stack olarak ta anılan bir konseptle en alt katmandaki sürücülere en üst katmandan aldıkları istekleri işleyerek veya bunun tam tersini yaparak çalışırlar. Bu mimaride I/O isteklerinin işlenmesi (handling request) görevi farklı sürücüler arasında dağıtılmıştır. Örneğin sabit disk üzerindeki bir dosyayı okumak isteyen uygulama’nın i/o istekleri önce dosya sistem sürücüsüne geçirilecek, oradan da disk sürücüsüne yönlenecek ve disk üzerinde veriyi okuyacaktır. Driver geldiği katmansal yolun tam tersini işleyerek veriyi uygulamaya ulaştıracaktır. Dilerseniz sizde bu katmansal mimarinin herhangi bir yerinde araya girerek filter-driver yazabilir , gelen ve giden veriyi encrypt/decrypt gibi şifreleme işlemlerine tabi tutabilirsiniz.

Monolithic driver ‘lar ise aygıt sürücülerin en basit tipleridirler. Yine adlarından anlaşılacağı gibi katmansız bir mimarileri vardır ve layered modeldeki gibi diğer driver’lar ile i/o işleme konusunda herhangi bir paylaşım yapmazlar. Sık olarak doğrudan user-mode uygulamalarına tek başlarına arayüz olarak destek vermeleri gerektiklerinde yazılırlar. Geliştirme ve debugging hizmetleri ise tanımlanabilir en basit görevleridir. Zaten makalenin ilerleyen kısımlarında böyle bir driver yazacağız ve ne anlatmak istediğimi daha iyi anlayacaksınız. Diğer aygıt sürücüsü kategorileri ise şimdilik yazımızın kapsamı dışındadır.

  • Thread context

Çoğu durumda yalnızca tek bir işlemciye sahip olduğumuz için, sistemin uygulamaları icra ediş şekli bizi hep bu işlemlerin aynı anda oluyormuşcasına izlenimine sokar. Çalışan tüm uygulamalar için işletim sistemi cpu zamanını herbir processin thread’ları için ayrı ayrı dilimlere ayırır. Cpu tek bir kaynaktır ve bu kaynağı işlemlerin sırası ile kullanabilmesi için Round-Robin denen algoritma kullanılır. Bu teknik sayesinde cpu ile olan işi kendine verilen quantum sürelik zamanı aşmasına rağmen bitmeyen bir thread’ın o anki tüm çalışma bilgileri bir yapıya geçirilip (CONTEXT) makine durum registerleri (msr)’lere saklanır ve sonraki thread’a geçilir.  Tabi bu teknik aslında çok daha kompleks işlerde yapar ama şimdilik bunlar bizim için yeterlidir. Birde fiziksel olarak işlemcilerin 1’den fazla olduğu durumlar vardır ki o zaman thread scheduling işlemi daha da karmaşık bir hal alır. Böyle bir yapıda thread’lar çekirdekler arası yük paylaşımına sokulur ve işletim sistemi çok daha gelişmiş kompleks algoritmalar kullanarak yönetim yapar. Thread’lar arası geçişte eğer bir sonraki çalışma sırası gelen thread aynı uygulamaya ait bir thread ise , işlemci tarafında sadece yukarıda tanımlamasını yaptığım basit bir thread context gerçekleşir. Lakin geçiş yapılan thread farklı bir process’e ait bir thread ise , işte o zaman hem bir “thread context switch” hemde işlemcinin CR3 register’inin içerisine o processe ait page table yüklenir.

Her kullanıcı işlemi (user process) kendine ait özel bir adres alanına sahiptir. Bu da şu demektir ki : her user process’i sayfa tablolarını (page tables) farklı sayfa dizinlerinde (page directory) tutar. Sayfa tabloları (page tables) sanal (virtual) adresleri fiziksel adreslere çevirmek için işlemcinin kullandığı tablolardır. Bu tabloları hazırlamak işlemcinin sorumluluğundadır ve her process’te mutlaka olmalıdır. İşlemci context’ine girdiği thread’in cr3 register’inada bakarak kullanacağı hafıza alanını tespit eder ve hafıza alanından faydalanmasını sağlar. Aslında kernel-mode’da driver yazarken bu işlemlerle bizim doğrudan bir etkileşimimiz yoktur. Fakat her context switch cpu israfına neden olduğundan driverlar genellikle kendileri thread olusturmazlar . Bu yüzden context switch’ler esnasında CPU zamanından tasarruf edebilmek için kernel-mode’da çalışan driver’lar üç çeşit context’ten birini kullanır:

  • Kullanıcı thread’inin context’in de bir I/O işlemi ile birlikte ;
  • Kernel-mode sistemi bağlamındaki threadlar olarak;

         Veya bir interrupt vasıtası ile  .

  • Kesme isteği seviyeleri

Kesmeler (interrupts) her işletim sisteminin de bulunan en önemli kısımlardandır. Her kesme oluştuğunda işlenmesi gerekir ve bu yüzden işlemci bir kesme oluştuğunda o anki normal akışını durdurur ve kesme’yi ilgilendiren koda dallanır. Yazılımsal ve Donanımsal olarak iki tip kesme vardır. Kesme’lere önceliklerine göre hizmet edilir. Düşük önceliğe sahip bir kesme akışına devam ederken, sonradan gelen yüksek öncelikli bir kesme bu akışı durdurup akışı ele geçirebilir.

Windows kesmelerin öncelik şemasını kesme isteği seviyeleri (interrupt request levels[IRQL]) olarak bilinen bir sistemle yönetir. Kernel IRQL’leri 0 dan 31’e kadar olan bir öncelik sırasına göre sıralar. Bu seviyelerden en yüksek duruma sahip olan en imtiyazlı interrupt olarak bilinir. Unutmadan belirtmeliyim ki IRQL imtiyaz seviyeleri ile işleç-programlama (thread-scheduling) arasında farklılıklar vardır. Bu yüzden birbirleri ile karıştırmayın.

Yukarıda ki tanımlamalarımıza göre IRQL=0 ‘a sahip bir kesme aslında bir kesme olayı başlatıp bir kodun akışını kesmez. Yani açıkçası aslında zaten o bir kesme değildir. User-Mode’da çalışan her thread passive level’de yürütülür. Bizim yazacağımız kodlarda bu IRQL seviyesinde olacaklardır. Böylelikle yazdığımız kodlar, başka akışların yarıda kesilmesine sebebiyet doğurmayacak. Tabi bu demek değildir ki her driver passive level de çalışacak. Bu sadece bizim örneklerimiz için geçerlidir.

Son olarak şunları belirtmekte fayda var:

Birincisi: Sürücü kodlarını icra ederken daha yüksek IRQL’le sahip bir işlem tarafından her zaman için akışı kesilebilir. Sürücü içersinde kod işleme aşamasında güncel IRQL seviyenizi öğrenebilir ve işleminizin yarıda kesilmemesi gereken kod bloklarında IRQL seviyenizi arttırabilir ve azaltabilirsiniz.

İkinci olarak: Passive IRQL seviyesindeyken bile her kernel fonksiyonunu çağırabilirsiniz. (Ayrıca DDK her fonksiyon için istenen IRQL seviyesini belirtmiştir). Ayrıca sayfalı(paged) ve sayfasız(nonpaged) adresleme yapabilirsiniz. Hafıza Yöneticisi sayfa hatası (page fault) hizmetleri açısından yetersiz kaldığından yüksek bir IRQL’de (DISPATCH_LEVEL veya daha yüksek (15-31 arası mesala)) paged bir hafıza alanına erişmeyi denerseniz sistemin çökmesine sebep olursunuz.

  • Sistem Çökmeleri

Daha önce hiç rastlamadım demeniz mümkün değil! Neden mi bahsediyorum? Tabi ki Meşhur Mavi Ekrandan (BSOD[Blue Screen of Death]). Muhtemelen hepte hiç beklemediğimiz bir anda ansızın karşımıza çıkmıştır. Ama onu uzun süredir göremiyorsanız üzülmeyin, çünkü kernel-mode’da driver yazarken kendisi ile bol bol haşır neşir olucaz 🙂

Windows kermel-mode ‘da çalışan sürücüler tarafından kullanılan özel sistem hafızasını korumak için herhangi bir koruma işlemi yapmaz. Driver kernel-mode’a bir kere kancayı attımı artık tüm işletim sistemi dataları ve sistem hafıza alanı onun için serbest bölgedir. Bu yüzden driver’imizi kodlarken önceden planlı bir yapılanma izleyip sistem stabilitesini tehlikeye atmamamız şart.

Artık yukarıda anlatılanları iyice kavramanız şart. Şayet sizde kernel-mode’da bir driver’da benim olsun diyenlerdenseniz thread context, interrupt request levels, kernel-mode ve user-mode etc… gibi kavramlara mutlaka aşina olmak zorundasınız.

  • Driver Development Kit

Windows DDK ile aygıt sürücü geliştirme aşamasında ihtiyacımız olan tüm dahili sistem rutinleri ve data yapılarına erişebiliriz. Windows DDK, MSDN Profesyonel üyeliliğinin bir parçasıdır. Dilerseniz http://msdn.microsoft.com ‘dan online olarak dokümantasyonlara erişebilir ve eğer Türkiye’de iseniz sembolik ( kızmayın :p ) bir ücret ödeyerek kargo ile microsoftun size gerekli kütüphane ve örneklerle komple kiti  göndermesini sağlayabilirsiniz.

*WDK 8.1 ve Visual Studio 2013 kullanmanızı tavsiye edetim.

Bir sonraki derste nasıl kodlama yapacağınız hakkında bilgi vereceğim.

Hakkında Yazılım Geliştiricileri


Beni Takip Et

Leave a reply

*