Windows Debugging 201

Belki Windows Debugging 106 ya kadar geldiniz ve birkaç sorun çözdünüz, ama artik debugging becerilerinizle pek ilerleyemiyorsunuz? Nedenini size söyleyebilirim: mimari bilginiz yeterli degil. Konseptleri yeterince anlayamiyorsunuz. Bilgiler arasinda derin iliskiler kuramiyorsunuz. Bu gayet normal, çünkü örnegin çevrenizde de belki bu tarz derin bilgilere inmek isteyenler yok. Sasirtici olsada dünyadaki çogu IT ci ve özellikle system adminler deep dive yapmakdan hoslanmaz. Ama neden? Onlarca milyon satir koddan olusan yapiyi anlayabilmek zor oldugundan mi? Hayir, nedeni asla disiplinli bir sekilde konseptleri anlayarak ilerlenmemis olmasi. Yani hep puzzle gibi parçalar birikiyor ama genelde bir ders de oldugu gibi mantiksal ilerlenmiyor. Heycan var, ama kaynak az ve çogu zaten can sikici ve herseyi birlestirmek de kolay degil. Belki biraz hayati kolaylastiracak bakis açilarina ihtiyaciniz var? O zaman 200 e hazirsiniz ve buradan basliyoruz.
Isletim sisteminin versiyonunu bütün Windows larda run/search den veya cmd den ‘winver’ komutunu çalistirarak görebilirsiniz. C:\Windows\System32 altindaki winver.exe isletim sistemini, edition i ve versiyonunu, yani Service Pack seviyesini gösterir. Örnegin kullanilan bir isletim sistemi sürücüsü dosyasinin özelliklerinde Detail tab indan Product version a bakarsaniz, bunun Windows Server 2008 R2/7 SP1 için 6.1.7601… ve RTM için 6.1.7600… olarak göstirilecektir. Iste bunu winver de gösterir. 6.0… ile Windows Server 2008/Vista baslayacaktir ve örnegin 5.2… ile Windows Server 2003. Yani ilk iki basamak Kernel versiyonudur ve takip eden 4 basamak SP seviyesi ve son noktadan sonra gelen haneler o modülün versiyonu (hotfix vs. ile güncellenmis). ÖrneginHotfix içeren KB makalelerinde modüllerin versiyonlarini ve tarihlerini görebiliriz.

Iletim sisteminde istedigimiz rutinleri çalistirmak, programlamak istersek, Windows un application programming interface ini kullaniriz . Bu hazir API lerdeki cagrilabilir fonksiyonlar ile aslinda herseyi yapabiliriz. Örnegin CreateProcess ile Kernel in bizim için bir process yaratmasini talep edebiliriz: https://msdn.microsoft.com/en-us/library/ms682425(VS.85).aspx Ama daha üst seviyede çalismak isterseniz daha basit bir .Net programi da yazabiliriz. O zaman belki hiç process yaratmak gibi islemlere önem vermemiz gerekmez, çünkü .Net istedigimiz altyapi ile ilgili islemleri bizim için yapar. API seviyesinin altinda da bizim örnek için aslinda NtCreateProcessEX fonksiyonu çalisir, yani asil isletim sisteminin Kernel kodunda çalisan fonksiyon budur. Bunlara native veya executive system services deriz. Ayrica direk API si olmayan sadece Kernel de manifeste edilmis fonksiyonlar da vardir, örnegin ExAllocatePoolWithTag. Bunlara da Kernel support functions/routines deriz. Bütünlük için: Service ler vardir, yani sisteme kullanici login olmadan ilk session da system control manager tarafindan çalistirilabilen user mode (.net ve API leri çalistirdigimiz gibi) kodlardir. Son olarak da DLL lerimiz vardir. Örnegin yine API seviyesinde CreateProcess i çagrirken burada çalisan alt rutin Kernel32.dll dir. Bu user mode tarafindadir ama en nihayetinde elbette bir yerden sonra asil islemler için, yani NtCreateProcessEX fonksiyonuna ulasip asil islemi yapabilmek için, isletim sistemi bizim için daha karisik yollar izler. Buradaki detaylara ancak daha sonra giriyor olacagiz.

Bilmemiz gereken ikinci grup terimler Process ve Thread dir. Bir Processin sanal adres bölümü vardir ve burada cpu da çalistiracagi kod bulunur. Bunu da çalistirabilmesi için baska kaynaklara tutulan Handle listesi olur, bir güvenlik konteksi altinda çalisir, ID si vardir ve bu kodu çalistiabilecek en az bir thread i olur. Process in bir yaratici processi olur, ama bu takip edilmez. Örnegin bir cmd açin ve ‘start cmd’ yazin, yeni bir cmd processi baslayacaktir. Processleri task manager da not edin. Sonra ikinci cmden ‘start mspaint’ ile painti baslatin. Simdi task manager da ilk cmdiye sag tiklayip end process tree yi seçersek bütün üç process de sonlandirilir. Ama bunu yapmadan önce ikinci cmd yi sadece kapatirsaki sadece ilk cmd sonlandirilir ve paint açik kalir. Yani zincir kopar. Processler arasi ilski takip edilmez. Daha fazla detay görebilmek için process explorer i kullanabiliriz: https://technet.microsoft.com/en-us/sysinternals/bb896653

Sanal bellek. Isletim sistemi islemleri virtual memory de, logical adressler ile yapar ve fiziki adresslere arka planda çevirir, physical memory e tercümeyi yapar. Yani arka planda hep iki bellek arasi tercüme yapilir, ama process bir varlik olsaydi sadece sanal bellek de varligini sürdürdügünü sanirdi. Bunun nedeni bugünkü sistemler için fiziki bellegin karisik olmasi ve sanal bellekde processlere sadece kendilerine ait bir adres bölgesinin verilebilmesi. Bu tasirimin asil nedeni ama eskiden 32bit de 4GB in yeterli oldugu zamanlarda fiziki bellegin çok düsük olmasiydi. Bugün 4GB yetmiyor ve 64bit e geçiyoruz. Kisaca sistemlerde birkaç MB RAM oldugu zamanlarda sanal bellek hala 4GB di. Ondan processlere 4GB lik evren verilirdi ve bu sanal evreni arka planda RAM deki verileri donanim yardimi ile hizlica degistirerek ve mümkün oldugunca page file a atarak ayakta tutulurdu. Mantik hala aynen.Bu sanal evren ortadan ikiye bölünür. 2GB Kernel adress bölümüne (adresslerin üst yarisi) ve 2GB user mode adres bölümüne (adreslerin alt yarisi). CPU un da en az iki mode olur ve böylece cpu Kernel ring deyken, Kernel adresler ile çalisabilir ve user mode ring deyken user mode adress ler ile çalisabilir. 2GB user mode peki ne demektir? Bir process burada maksimum 2GB sanal alana kadar kullanabilir. / 3GB boot.ini switchi ile Kernel dan 1GB alarak usermode tarafini 3GB ye artitririz. Veritabaninizin 3GB den de büyük adres alanina ihtiyaci varsa boot.ini ye / PAE (physical address extension) ekleyerek isteyen yazilimlarinAWE (address windowing extension) kullanabilmelerini saglayabiliriz. AWE aware ise yazilim ve bunu yine API ler ile SQL gibi yapabilir, 4GB üstü RAM i de kullanabilir. Yani sanal adresinden küçük bir yer kullanarak, buradan çok daha büyük bir RAM adres alanina bir pencere açabilir ve böylece çok büyük bir sanal adres bölgesi kullanabilir. X64, yani AMD64, Itanium olmayan 64Bit de de user mode ve Kernel alanlari yaklasik 8TB dir ve Itanium gerçek 64bit IA-64 de 7TB.
Kernel ve user mode ayirimin nedeni güvenlikdir. User mode da bir processin yapabilecekleri limitlidir. Kernel mode da çalisan bir aygit sürücüsünün kodu hemen hemen istedigi her seyi yapabilir. Elbette ama user mode bir processin Kernel de de çalismasi gerekebilir. Örnegin ilk cmd ikinci cmd yi baslatirken, process yarattigimiz için Kernel üzerinden gitmek zorundayiz. Yani bir asamada Kernel e gireriz, oradaki sanak adressleri kullanmaya baslariz ve isimiz bitince yine Kernel bizi user mode a geri yönelendirir. Bir threadin stackinde degisen adres bölgelerini görürsünüz. Bir Process in veya onun threadlerin ne kadar user mode ve kernel de çalistiklarini performans monitörden takip edebiliriz. Processor, Thread ve Process altinda %Priviledged Time ve % User Time olarak takip edebiliriz.

Windows da internal structures dedigimiz yapilar disinda her sey bir objedir. Bir dosya bir file objesi türündendir ve bir process bir process türünden bir objedir. Yani objectlerin atrribute lari vardir ve bunlari method lari ile manipüle ederiz. Örnegin Open bir method dur. Bunlarin yönetimini Kernel deki Object Manager yapar. Objelerin kolay okunabilir isimlerinden sorumludur, örnegin Handle lar ile resource larin ve verilerin processler arasi paylasimindan sorumludur, bunun ile beraber kaynaklarin güvenlik açisindan gerekli erisim haklari da uyarlar ve objeleri takip edip silinebilirliklerini belirler. Data structure larin içerigi transparandir ama onjelerin içi görünmez. Özel method lar ile onlardan veri alip geri koyabiliriz. Obje ve handle lara ileride geri dönecegiz.

Güvenlik de isletim sisteminin temel sütunlarindan biridir. Objeler üzerinde üç farkli güvenlik konsepti uyarlanir. Ilki discretionary dir. Bu hepimizin kullandigi haklar ve paylasim haklaridir. Yani bir kullanici kullanici adi ve sifresi ile bir logon seklinde otantike olduktan sonra farkli kaynaklara otorize olur. Bu authentication ve authorization Windows güvenliginin temelidir. Yani sahis tanima ve sahisin haklarina ve bilmesi gerekenlere göre sistemde hareketlerini saglamak.
Priviledged acess control, discretionary in üstüne gelen yapidir. Örnegin artik kullanilmayan bir kullanicinin üstünde sadece onun hakki olan dosyalarinin kurtarilmasi gibi durmlarda devreye girer. Yani admin o dosyalarin ownershipligini üstüne alir ve sonra haklari istedigi gibi degistirebilir.
Objeleri son koruyan katman da mandatory integrity control dur. Bu da örnegin User Account Control dür.

Baska kisa basliklar? Registy bildiginiz gibi Isletim sisteminin veri tabanidir. Windows genelde internal text stringlerinde 16 bit Unicode kullanir.
Bir çok anlayisinizi artirabilecek toolu https://technet.microsoft.com/en-us/sysinternals bulabilirsiniz. .exe lerin ve DLL lerin aralarindaki ilskileri daha net görebilmek için dependency walker i kullabilirsiniz: https://www.dependencywalker.com/.
Performans monitörü hala en önemli toolardandir. Hem mimari anlayisinizi artirabilen ve hem de troubleshooting kabiliyetlerinizi artirabilen bir tooldur. Farkli technet makalelerimde debugging dahil olmak üzere zaten farkli araçlarimizdan hep konustuk. Uzun vade de ayrica Windows Software Development Kit ve Windows Driver Kit konularina giriyor olacagiz.

En temel konsept ve araçlarimizi konu aldik.

Konular hakkinda daha detayli Ingilizce bilgi Windows Internals 5th ed. Chapter 1 ‘Concepts and Tools’ altinda bulunabilir:
https://technet.microsoft.com/en-us/sysinternals/bb963901

Eger kendinizi Windows mimari konularinda gelistirmek istiyorsaniz, veya sadece bütün konulari kapsayan el alti bir referansa ihtiyaciniz varsa, kitap i almanizi siddetle öneririm.

Basar Güner