14 Aralık 2009 Pazartesi

Milw0rm artık yok mu?

Bugün tekrar aktif hayata dönme çabalarım içerisinde güncel haberleri okuma atraksiyonumu ifa ederken üzücü bir haberle karşılaştım. Str0ke nickli ünlü Milw0rm sitesinin owner'i geçirdiği kalp yetmezliği nedeni ile vefat etmiş. Haberin kaynağı her ne kadar beni pek ikna edememiş olsa da doğruluk payı ihtimalini göz ardı edemiyoruz. Malum milw0rm uzun süredir güncellenmiyordu. Umarım haber hoax çıkar ve Str0ke sevenlerini yalnız bırakmaz.

Haberin kaynağı: Milw0rm is gone

Düzeltme: Evet tahminlerim beni yanıltmadı = Milw0rm is Alive

Sanal alemde ki haberlere hemen zıplamayın'a güzel bir örnek :)

10 Kasım 2009 Salı

Warning: Your body is infected by A(H1N1) virus

Söylenenler sahiden doğruymuş; bu grip denen melet hemde h1n1'li si ilaçlı 7 gün ilaçsız 1 haftada geçiyor. Önceki hafta Cuma günü beni yatağa mıhlayıp bugün itibari ile doğrulmama izin verdiği için saygıdeğer virüsümüze sonsuz şükranlarımı iletiyorum. Doğrusunu söylemek gerekirse diğer grip sendromlarının çok üstünde bir efor harcattı bünyeme. Doktor tarafından verilen ilaçlardan tutunda annemin bitkisel ilaç karışımlarına kadar onlarca şey denemem sadece bol bol uyumama neden oldu ve hala beynimdeki ve ellerimde ki uyuşukluk geçmiş değil bu yüzden imla hataları ve saçmalamalar yüzünden peşinen özür diliyorum :)

Hastalık sürecinde canımı en çok sıkan ama alışkanlıktan olsa gerek pek umursatmayan ülkemiz insanlarının ve onları bu denli bir paranoyaya sokan devlet organları ve medyanın tutumu oldu. 2 gün üst üste , gece yarıları dahil farklı saat dilimlerinde 7 kez 5 farklı hastaneye (2'si devlet 3'ü özel) girme girişimim derbi maç öncesi stat önünden farksız olan kalabalık yüzünden başarısızlıkla sonuçlandı. İnsanlar çıldırmış gibi hastahanelere akın etmişler. Bir kez hapşıran da gelmiş , gözü sulanan da. Benim gibi 41 derece ateşliler ise ya o hengamede beklemeyi tercih edecek ya da evine gidip makus kaderine razı olup yorganı üstüne çekecek.

Soranlar olabilir ! Nereden biliyorsun o virüsü taşıdığını ? diye. Tabi ki bilmiyorum ama karşılaşma fırsatı bulduğum ve 1dk lık bir görüşme şansı yakaladığım acil dokturu ile aramda geçen diyalog:

Dr House - "hımm " dereceye bakıyor "40 derece .... kaç gündür hastasın"
Ben - "bugün 4.gün ve ateşim 38.5 ile 41 arasında"
Dr House - "bulantı, ishal filan oldumu?"
Ben - "evet sanırım 18 kez istiğfra ettim ve karın kaslarım işlemez halde"
Dr House - "delikanlı işte sende kapmışsın domuzun gribini ama neyse varmı evde ilacın?"
Ben - "Evde??? İlaç ???"
DR House - "tmm " bişiler karalıyor "bunları al istrahat et"

Bende bu gribin birilerinin cebini doldurabilmek için türetilmiş bir varyant olduğunu düşünenlerdenim ve onların asla kazanmasını istemem ancak hayatınızdan vereceğiniz bir 5 gününüz yoksa gidip Sam amcanın iğnesini vurulmakta bir şık olarak önünüze çıkıyor.

Hepinize sağlıklı ve mutlu günler.

3 Kasım 2009 Salı

Günlükten Çıkanlar - 2

2005 Yılının ajandasınıda buldum , sadece 8 sayfa not karalamışım ve birbirinden kopuk bilgilerden oluşuyor lakin meraklıları için güzel nimet :

- Device Driver'lar SYSTEM olark anılan özel bir context'te çalışırlar. Bunu taskmanager'da görünen SYSTEM kullanıcısı olarakta görebiliriz.

- Her Aygıt sürücüsü (Device Driver) bir Device Name tag'ı ile tanımlanır. Her sürücü kullanacağı aygıt için bir isim oluşturmalıdır.

- Sürücüler DriverEntry rutininde aygıt için DeviceObject adı verilen aygıtı tanımlayısı sistem taraflı bir nesne ve SymbolicLink adı da verilen ve aygıt adının usermode tarafında da görülebilmesini sağlyan ortak nesne yaratır. Ayrıca bazı driver'a ve aygıta özel başlangıç işlemleride yapar.

- Driver'lar fiziksel bir aygıtı kontrol etmek zorunda değildirler. Bunun yerine sadece sürücü kodu içerisinde verilen görevleride yapabilirler. Ancak unutulmaması gereken en önemli husus bu kodların ring0 denilen en imtiyazlı seviyede çalıştıklarıdır.

- Driver'lara yapılan tüm istekler birer I/O Request Packet (IRP) biçiminde yollanır. Driver, tüm sürücü istekleri için önceden DriverEntry rutininde tanımlanmış olan fonskiyon pointer'larını SYSTEM context'inde bekler.

- Tüm işlemlerin virtual address (sanal adresleri) aynı olabilir ancak fiziksel sayfaları farklı adresleri işaret eder.

- Farklı process'lerin her iki modda aynı hafıza alanını kullanabilmesi için named memory mapped file oluşturması gerekmektedir.

- ObReferenceObjectByHandle komutu belirtilen handle'in istenen erişim izinlerine uygun olup olmadığına bakar. Eğer handle'a istenilen kriterlerde erişim izni verilirse programcıya STATUS__SUCCESS durumu döner.

- 32bit işlemciler bir hafıza adresine erişirken 16bit'lik bir Segment Selector ve 32bit'lik segmentle birlikte kullanılacak offset değeri kullanır.

- Segmentlere erişim ile alakalı gerekli blgiler işlemciye segment table yoluyla aktarılır.Segment Selector, segment table içindeki bir index'tir.

- Herhangi bir anda yalnızca 2 adet segment tablosu aktif olabilir. Bunlar GDT v LDT'dir.

- Segment Selector'de ki bir bit kullanılarak CPU hangi Segment tablosunu kullanacağına karar verir.

- Segment Descriptor'lar, hafızanın bir bölgesini işaret eden bilgiyi ve o bölgeye erişebilmek için gereken erişim haklarına ait bilgiyi tutar. Segment Descriptorlar , Segment Tablosunun içerisinde array şeklinde yer alırlar. Bir Segment Descriptor kısaca bir segmentin başlangıç adresi ile boyutunu tutar ve imtiyaz seviyesini belirten DPL olarakta bilinen 2 bit'i kullanır.

- İşlemci bir segment'e erişim izni vermeden önce DPL ve RPL'i karşılaştırır. RPL selector'de yer alan 2 bitlik bir imtiyaz belirteçidir.

- Address Translation işlemindeki ilk adım, segmetin taban adresi ile offset'in toplanmasıdır. Bu işlemin sonucunda eğer paging mekanizması aktif değil ise doğrudan çıkan sonuç fiziksel adresi gösterir. Paging aktif ise bu adrese logical veya lineer adres adı verilir ve fiziksel adresi bulabilmek için eldeki veri tekrar Paging Address Translation adı verilen bir başka mekanizmaya devr edilir.

- Memory Management şeması Paging olarak anılır. Çünkü Hafıza, Pages olarak bilinen sabit boyutlu birimler halinde tanımlanır. Intel işlemciler üzerinde bir sayfa 4kb olarak varsayılır.

- 32bit Adresleme ile fiziksel hafıza ancak 4GB adreslenebilir. Bunun anlamı 1 milyon sayfayı adresleyebilirsiniz demektir.

- Bir PageDirectoryEntry'si eğer LSB(Least Significant bit) bit'i 1 ise geçerli olarak değerlendirilir.

- WindowsNT her process için ayrı bir PageTable tutar ve bunun sanal adres aralığıda 0xC0000000 dan 0xC03fffff'dir.

- Page Table Directory (1024)1K adet Page Table'in adresini tutar. PDT Lineer adresin son 10bit'inde (22-32 bitleri) yer alır ve bu tabloda ki bir girişe işaret eder.

- Page Table , adresleri PDT'de bulunan ve kendi tablolarında 1024 adet PageTableEntry(PTE) tutan PageTableFrame(PTF)'ye işaret eden tablolardır. Lineer adresin 12 ve 22 bit'leri arasında yer alır.

- Address space olarak bilinen kavram PageDirectory'den başka bişi değildir. Page Directory'nin gösterdiği table'lar üst yarısı bütün process'ler için aynıdır.

- MMCreateProcessAddressSpace fonksiyonu hafızanın 3 aşağıdaki işler için ayırır:
Birinci sayfayı PageDirectory için, ikinci sayfayı HyperSpace Page table girişlerini tutmak için ve 3.Sayfayıda Process ilk defa oluşturulduğunda working set olarak anılan , processin .code , .data , stack gibi nesnelerini tutmaya yarayan hafıza öbeğinin adresini tutar.

- Memory-Mapped, dosyaları, NT section nesneleri ile çalışabilmek için kullanır.

- Bir Process'in çalışma anında fiziksel hafızaya alınamayan kısımları işaretlenir. Process ne zaman hafızada bulunmayan bir datasına ulaşmaya çalışırsa , önceden işaretlenmiş alanlar ikincil depolama aygıtından (senaryomuzda bu hdd'dir) ana hafızaya getirilir.

- Eğer İşletim sistemi fiziksel hafızayı(RAM) tüketirse kendine yer açailmek için bazı dataları atmak durumunda kalır. Ancak bu boşaltım işlemi geri dönüşümsüz bir silinme şeklinde değil swapping yapılarak tekrar hdd'ye atılır ve dilendiği zaman oradan geri alınabilir. Bu dataların atılma işlemine karar verme mekanizması "Replacement Policy" olarak bilinir. Bu mekaizmada WindowsNT FIFO(İlk giren ilk çıkar) yönetimini kullanarak yerine getirir. Bu policy'ye göre bir yer sıkıntısı olduğunda bellekte ki en eski veri atılmış olacaktır.

- Eğer bir Page fiziksel Ram'in üzerinde map edilmemişse WindowsNT bu sayfayı "invalid" olarak işaretler. Bu sayfaya herhangi bir erişim gerçekleşirse bir "page fault" gerçekleşir ve bu hatayı yakalayan "page fault handler" hdd'den ilgili datayı az önce yukarıdaki bahsettiğimiz şekilde getirir.

- Eğer Page bir dll veya executable code içeriyor ise saygfa da o ilgili dll veya exe dosyadan alınır. Şayet sayfa bir data içeriyor ise sayfayı swap dosyasından alacaktır. Yani kod içeren bölgeler datalardan önceliklidir. Eğer sayfa Memory-Mapped paylaşımlı dosya alanından alınacak ise sayfa uygun dosyadan alınır.

- Windows NT fiziksel hafızadaki boş alanı sürekli tahrip eder, böylece bir page fault meydana geldiğinde hdd'den çıkarılacak sayfa için yer ayırabilecektir. Bu takip bilgileri, Page Frame Database (PFD) olarak anılan Kernel data yapısında tutulur.

- PFD hafızadaki sayfaları FIFO tabanlı bir listede tutar ve yer sıkıntısı olduğu durumlarda atılacak sayfaya karar verir. Ancak bir sayfayı atmadan önce WindowsNT bu sayfanın "dirty" kirli olmadığından emin olmalıdır. Dirty biti sayfanın yazılmış olduğunu ve hafızadan atılmak icap eden durumlarda bu sayfanın ilgili swapping işlemine uygun olduğunu gösterir. Ayrıca PFD paylaşılan sayfalar içine bir referans sayacı tutar ve yalnız bu sayaç ilgili sayfa için sıfır olduğunda atılır. Genelde PFD her fiziksel sayfanın durumuna bakar. PFD her fiziksel sayfa için 24byte 'lık bir array'dir. PFD arrayinin boyutu bir kernel değişkeninde depolanan fiziksel sayfanın sayısına eşittir. Bu değeri tutan değişken "MmNumberOfPhysicalPages"'dir. PFD'nin adresini yine bir kernel değişkeni olan MmPfnDatabase tutar. Bir fiziksel sayfa farklı durumlarda olabilir. Örneğin in-use, free ,free ama dirty gibi. PFD girişi bir doubly linkd list'e ve fiziksel sayfanın durumuna bağlıdır. Örneğin boş sayfaları tanımlayacak PFD girişleri free page listesine bağlıdır.

- Virtual Address Descriptor: Windows NT her boş fiziksel sayfanın listesi ile birlikte ayrıca her Process için ayrılmış olan virtual address boşluğunuda izlemeye ihtiyaç duyar. Bir Process ,bir hafıza bloğu ayırmak istediği zaman ki bu işlem örneğin bir dll i hafızaya almakta olabilir bu esnada WindowsNT Virtual Address boşluğundaki boş bloklar için bir kontrol yapar ve ondan sonra gereken yeri ayırır, ve Virtual Address map'i bu doğrultuda günceller ve hali ile bu işlem bilgilerini alabileceği en doğru yer Page Table'dir.

- IO Manager , gerekli şartlar oluşup bir IRP oluşturulduğunda IRP yapısının AssociatedIRP.SystemBuffer alanına usermode'da yer alan buffer'indaki bilgiyi geçer.

2 Kasım 2009 Pazartesi

Biraz sinerji katalım

Takip edenler bilir, yaklaşık bir aydır eski nostaljim olan kernelmode dünyasına geri döndüm. Kendisi ile 2 sene önce hazin bir ayrılık yaşamış ve highlvl yollarını aşındırır olmuştum. Sağolsun Emre Tınaztepe ve Kutalmis dostlarım sayesinde tekrar gerçeten severek uğraştığım işe geri döndüm. Bu sebeple yıllar önce şirketteki a4 ve toner kapasitesinin tükenmesine neden olduğum kernelmode dökümanlarımı tekrar gün yüzüne çıkardım ve hararetle okumaya başladım.

Dökümanları karıştırıken günlük gibi tuttuğum ve iyice sararmaya yüz tutmuş olan not defterime denk geldim. Okudukça iyiki yazmışım bunları dedim ve sizlerle paylaşmak için hemen bloguma giriş yaptım. Umarım sizlerinde işine yarar:

== 2004 ==
- User-Mode kodları Objectlere handle'ları kullanarak erişir ancak Kernel-Mode kodları Object'lere doğrudan erişirken pointer'ları kullanır.

- Object'lerde bulunan ReferenceCount hem user-mode dan handle lar vasıtası ile yapılan erişimlerde hem de kernel-mode'dan yapılan erişimlerde 1 artar.

- Bir process zaten çok küçük zaman aralıklarında çalıştığından (quantum slice) hafıza bölgelerinede bitişik olsalar dahi çok küçük erişim boyutlarında erişir.

- İşletim Sistemi, bir processin sadece o an hafızada çalıştığı kümelerini (bknz:working set) saklamaya ihtiyaç duyar

- Her device controller local bir buffer'a sahiptir. CPU bu local bufferdan, ana hafızaya veya ana hafızdan local buffera data taşır

- I/O: Aygıttın kendi device controllerinde bulunan local buffer'a yapılan işlemdir.
Device controller daha sonra bu i/o işleminin bittiğini Cpu'ya interrupt kullanarak bildirir.

- Trap bir kullanıcı hatası veya başka bir problemden dolayı meydana gelen yazılımsal bir interrupt'tır

- I/O Manager, bir IRP oluşturduğunda _IRP yapısının AssociatedIrp.SystemBuffer buffer alanına kullanıcı taraflı buffer alanındaki bilgiyi geçer.

- IofCompleteRequest çağrısı ile bir irp için gerekli işlemlerin tümünün yapıldığı varsayılır. Bu komut sonrasında I/O Manager driver taraflı buffer alanını user taraflı buffer alanına kopyalar.

- IRQL Notları

1.Bir fonksiyona girdiğinizde mutlaka IRQL'ni kontrol edin
2.Her hangi bir fonksiyonu çağırmadan önce IRQL'ı için DDK'ya göz atın
3.Eğer bir thread en düşük IRQL seviyesinde çalışıyorsa onu daha fazla alt seviyeye indiremezsiniz, ancak yükseltebilirsiniz.
4.DISPATCH_LEVEL da PAGE_FAULT yaşamazsınız
5.Paging I/O APC level'da yapılır
6.Kullanıcı her zaman PASSIVE_LEVEL da çalışır
7.Kernel'de PASSIVE_LEVEL da çalışabilir.
8.PASSIVE_LEVEL da iş yükü dağıtımına izin verilir
9.DPC'ler DISPATCH_LEVEL da çalışırlar ve preempt edilemez(etkisizleştirilemez) (ama interrupt edilebilirler tabiki) ve dispatcher olduklarından DISPATCH_LEVEL'da çalışırlar.
10.IRQL'ları manipüle etmek için KeLowerIrql() ve KeRaiseIrql fonksiyonları kullanılır.

- IRP Notları

1.IRP'ler bir uygulamanın veya driver'in davranışları üzerinden IoManager tarafından üretilirler. IRP'in üst kısmı (header) sabit bilgilerden oluşur, alt kısım ise stack location adı verilen bilgi yığınından oluşur.
2.Uygulama driver'a yalnızca kontrolü IRP'lar vasıtası ile devredebilir, ve bilgiler paylaşılan bir hafıza tarafından değiş tokuş edilir.
3.IoManager driver'lar için bir IRP kuyruğu tutmaz, sadece ne zaman alınacaklarını ve gönderileceklerine bakar. IRP'leri kuyruklamaktan driver kendisi sorumludur.
4.IRP sürücü IoCompleteRequest isteği çağrıldığında işlemini sonlandırır.
5.Irp->IoStatus.Information transfer edilen data boyutunu içerir ve bu bilgi usermode tarafındaki DeviceIOController'in en son paramtresi olan bytesreturned'e aktarilir.
6.IoManager geri donen bilgiyi SystemBuffer'dan OutputBuffer'a kopyalar.
7.IoCompleteRequest fonksiyonu IoManager'a bildirilen en son IRP çağrısıdır ve bu IRP'in artık işinin sona erdiğini bildirir. Bu çağrı bir kez yapıldıktan sonra artık o IRP'e erişilemez.
8. Driver'dan Driver'a IRP'ler vasıtası ile haberleşilebilir. Driver'lar aynı adres boşluğunda çalıştıklarından her biri bir diğeri ile paylaşımlı hafıza alanları sayesinde iletişim kurabilir.
9.IRP, sürücü katmanları arasında dolaşabilir. Bu IRP'in bilgilerine IoGetCurrentIrpStackLocation çağrısı ile ulaşılabilir.

İşe yarar temelinizi oluşturacak şeyler buldukça paylaşmaya devam edeceğim... ,

Şimdilik sağlıcakla.

21 Ekim 2009 Çarşamba

Programcı Kütüphanesi

Buldukça ekliyeceğim bazı eski yazılarım ve sanal ortamlarda yaptigimiz münazarlara ait linkleri sizinle paylaşmak isterim. Şimdilik bunlar çıktı :

Konu:Bir ara gaza gelip komple çevirisini yapmaya niyetlendiğim Win32 Api'nin Windows'lara ait çevirisi.
Link:Win32: Pencereler

Konu:Sene 2003 Masm32 ile yeni tanışmışım bi yandan okuyorum bi yandan kodluyorum. Baktım kavraması zor her satırı ileride anlıyayım diye commentlemişim. Buyrun aynı çileyi çekmeyin:
Link:Masm32 Iskelet

Konu:Masm32 yi çözdük ama bu seferde ddk ya merak saldık ve aynı "anla+kodla ve çevir" sistemini bunada uyguladım. Sağolsun rus dostlardan F-Four sağlam bi makale serisi hazırlamış bizede çevirip derlemesi düştü:
Link:Sistem Programcılığı Serisi

Konu:Win32 Pipe mantığı ve bir örnek
Link:Pipe'ler

Konu:Exe'ler nasıl çalışır . Ben baktım güldüm açın sizde gülün :)
Link:Exe'ler nasıl çalışır

Konu:Kripto ve Sıkıştırma hk. Bi aralar güzel münazaralar oluyordu hey gidi günler...
Link:Sıkıştırma ve Kriptografi

Konu:O zamanlar popüler olan Pe header yapısı hakkında münazara ediyorduk
Link:Import Section olmaksızın executable derleme

Konu:İşe girdim ve ilk defa kısıtlı bir domain kullanıcısı ile tanıştım. Nereye el atsam erişim engellendi hatası. Ben ve Erişim Engellendi hatası aaa hiç olurmu :) Kabul ediyorum acaip amatörce keşifler.
Link:Microsoft ve Group Policy Açıkları
Link:Gpo ile Kısıtlanan Çalıştır (Run) menüsünü geri getirme
Link:

Assembly ve Win32Api Voltran Voltran Voltran

Okuyacağınız bu makale 2006 yılında yazılmıştır. Yaptığım uslüp ve makale içindeki komik hata ve eksikler nedeni ile özür dilerim. Okuduğumda bana eski ve yeni durumum hakkında ölçüm yapmamı sağladığından mevcut hataları olduğu gibi bırakmayı tercih ettim.

Masm32 ve Win32'nin Güçlü Birlikteliği

Bu dökümanı ayrıntılı olarak yazmamın en büyük sebebi Türkiye'de ki yanlış anlaşılan ve uygulanan sistem programcılığı müessesini bir nevi olsa da gerçek manasıyla anlaşılabilirliğini sağlamaktır. Dil olarak assembly'i seçmemin manası ise, sistemin işleyişini akıllarda soru işareti bırakmayacak bir şekilde yalın olmasını sağlamaktır. Zaten öncelikle bu dokümanın okuyucuları için assembly temelden inceleyen bir giriş yapılacaktır.

Assembly öğrenmek demek,

· Çalıştığınız mimariyi çok iyi tanımak,
· Hatasız kodlar üretebilmeyi sağlamak,
· Yazılım eksikliklerini keşfedebilmek,
· Hızlı ve eksiksiz programlama süreçleri oluşturabilmek,

gibi yetenekler kazandıracaktır. Assembly de en azından orta seviye bir programcı olabilmek için; hardware yapıları, işlemci mimarisi, hafıza yönetimi, os mimarisi, process davranışları ve eğer ilgileniyorsanız network alt yapısının, katmanlarının ve iletişim mimarisinin nasıl çalıştığı hakkında bilgilere sahip olmak zorundasınızdır. Korktunuz mu! Yapmayın hani sistem uzmanı olmak istiyordunuz?

Ben şöyle düşünüyorum. Sonuç olarak derlenmiş kodlar makine koduna dönüyor ve tüm işleri yapan işlemcimiz de en iyi ondan anlıyor, öyleyse önce onu öğrenmeliyim ki sonra üst katman dilleri geçtiğimde daha hatasız kodlar derleyeyim. Tabi birde karşılaşacağım opcode seviyesi hataların da yorumlayıp hata tespiti yapabileyim. Ayrıca işin birde tilki tarafı var ancak bahsetmeyeyim şimdilik. :)

Dokümana başlamadan önce şunu da belirtmek isterim ki, bu dokümanın hedef kitlesi herhangi bir programlama dilinde en azından orta seviyede bilgili ancak kendini sistem programcılığı konusunda da yetiştirmek isteyen arkadaşlar olacaktır. Dokümanı elimden geldiğince basitleştirip, arada bir iğrenç espirilerimden sıkıştırıp eğlenceli hale getirmeye çalışacağım.

Kısa bir giriş İşlemci

Burada işlemcinin ne olduğunu ve hayat hikayesini anlatacak değilim . Sadece bizi ilgilendiren yerlerini bilmemiz şu anlık yeterli olacaktır.

Nasıl ki diğer programlama dillerinde değişkenler kullanarak bazı değerleri onların içlerinde saklayıp işlemler yapıyorsak assembly içinde işlemcide bulunan registerlar o anlamı ifade eder. Register kavramı eskiden üretici firmalar arasında farklılıklar gösterse de günümüzde bu protokol artık yerleşmiştir.

Registerlar ile değişkenler arasında bir benzetme yapacak olursak.

Delphi için:


var
sayi1,sayi2,sonuc :integer;
begin
sayi1:=10
sayi2:=20
sonuc=sayi1+sayi2



ise

assembly de bu

mov ax,10 ;ax artık 10 sayısını saklıyor
mov bx,20 ;bx artık 20 sayısını saklıyor
add ax,bx ;topladık ve ax artık 30





Bu register'lar dan işlemci de genel amaçlı olanlarından 8 adet bulunur. Bunlar:

EAX,EBX,ECX ve EDX tir. Bunlar 32 bit'lik bilgileri saklarlar ve kendi içlerinde voltran :) oluşturduklarından ayrıca bölünebilirler. Şöyle ki:

*EAX -> AX -> AH,AL
32b 16b 8b, 8b

*E demek Extended demek ilk işlemcilerde bu yoktu ve 16 bittiler registerlar
bu örnek yukarıdaki dörtlü için aynıdır. EBX -> BX -> BH,BL gibi

Şu ana kadar yazdıklarımdan bir şey anlamadıysanız baştan tekrar okuyun veya google da daha basit olan ingilizce dökümanları bulun fakat bu anlatılanlar sizi zaten bildiğiniz şeyleri tekrar okutup sıkıyorsa bir sonraki serileri doğrudan ilerleyen konulardan devam etmeniz daha iyi olacaktır.

Bu yukarıdaki dört register cpu tarafından kunta kinte şeklinde yönetilirler ve her şey için kullanılabilir. Bazı işletim sistemleri bu register'ları kendi isteklerine göre gruplandırmıştır. Örneğin Microsoft kendi API sistemin de işletilen fonksiyon geri dönüşlerini sürekli eax'a gönderir. Birde bunların haricinde EDI ve ESI vardır Intel bunları programcılara bir nevi kıyak olsun programcılar uğraşmasınlar diziler ile, koysunlar kopyalanması istenilen diziyi ESI'ye versinler hedef olarak EDI'yi atsınlar bi dongu komutu hepsi EDI'de Yani bi nevi kopyala yapıştır için iyi bir halta yarar bu iki kardeş register . İlerleyen zamanlarda movs, cmps gibi yardımcı komutlarından çıkması ile işlevsellikleri kanıtlanmıştır index registerlarının.

Unutmadan birde ESP var. Amacı ve işleme mantığı şöyledir Esp'yi bir bidon olarak düşünürsek hatta turşu bidonu olarak düşününki :P olay daha da basitleşsin. Turşu bidonumuza zerzevatı ben şu şekilde yerleştirirsem:

| domates |
| kavun |
| hıyar |
| zerdali |
| floppy :)|
\________/

bunları alırken hangi sırayla alırım . Intel işlemcileri bunu FILO işlemiyle alır yani First In Last Out - Türkçesi: İlk giren Son çıkar dileyen LIFO yani Last In,First Out'da diğebilir aynı şey J. Kısaca bu istiften yada Intel'in deyimi ile stack'ten ilk çıkan domates olur. Onun peşinden kavun ve en son floppy olur. Halbuki domates en son yığına giren nesnemizdi dimi ama? ESP genelde iki asm komutuyla yönetilir bunlar Push ve Pop tur. Örnekten devam edecek olursak Push komutu kovaya(stack) bi yeşillik atar ve kovanın içindekilerin in sayısını ve yerini tutan bir kayıttaki değeri(ESP) küçültür Pop ise tam tersini yapar kovadan en son atılan malzemeyi alır. Intel işlemcilerinde stackten veri alıp veri koyma işlemleri yaparken register değeri ya 4byte(32bit) artar yada 4byte azalır.


örnek
push 20 ; Stacke(kovaya) bi 20'lik attık
push 10 ; Peşinden onunda üstüne bi 10'luk
pop ax ; pop komutunu vererek stackin en üstündeki veriyi ax'e aldık ax=10
pop bx ; bx artık 20
add ax,bx ;ax=30

kolaymış değilmi?

Tabi bu stackten veriyi illaki en üstündeki alacağız diye bir kaide yok, dilersek stackteki en alttaki veriyi bile elde edebiliriz ama bunu yapan kodlar konumunuz hasebiyle şimdilik size uygun değil.

Şimdi sırada EIP registeri var
Bu yazmaç yazdığınız programların kodlarını bir sıraya sokar ve adım adım işler. Basit bir benzetme olması açısından Qbasic'i bilenler varsa hatırlarlar:

1 CLS
2 print "muck muck"
goto 2

deyip her komutu etiketliyorduk ya işte onun daha gelişmişi eip'tir. Bu register'a dışarıdan komutlarla müdahale şansı doğrudan yoktur. Onu derleyici bir kere ayarlar işletim sistemi de işlemciye yollar işlemcide bu sıraya göre teker teker gider. Ollydbg adlı debugger'ı kullanarak EIP yazmacının mantığını anlamanız daha kolay.

Segmentler:
CS: SS: DD: ES: FS: GS


CS DS ve SS : Programınızı yazıp derlediğiniz zaman, programınız sizin onu kodladığınız halinden milyon kez değişik bir halde çalıştırılabilir dosya haline gelir. Yani sizin anladığınız programlama yapısı ile işlemcinin anladığı yapı çok farklıdır. Siz kodunuzun kodlarının nerede,tanımlamaların nerede,sabitlerin nerede olduğunu bilirsiniz. Ama işlemci bunu ancak programınızı derleyen derleyicinin programınızın çalıştırılabilir kod haline getirdiği zaman içerisine eklediği bazı ipuçlarından faydalanarak bulabilir. İşte programınızın kodlarının nerede mahfuz tutulduğunu işaret eden olaya Code Segment(CS), verilerinizi işaret eden bölüme Data Segment(DS), değişkenleriniz,fonksiyon geri dönüşleriniz ve işlemci taraflı kod dallanmaları gibi göstergeyede Stack Segment(SS) denir. İşlemci programınızı çalıştırmak için hazırlık yaparken CS segmentine bakarak kodların yerini DS segmentine bakarak tanımlamaların yerini SS'ye bakar ise Stack'in yerinin bulur.

Peki işlemci kodların yerini buldu diyelim ancak bu kadar kodun içerisinden nereden başlayacağını nasıl bilecek. Yukarıda yazmıştık değil mi? EIP yazmacından. Siz programınızı derlediğinizde programlama dilinize ait compileriniz bu işlemi sizin için ve cpu için yapar. Programlama dili konseptlerin de şu vardır ki her yazılan kod için bir Entry Point vardır. Siz programınızı derler ve çalıştırırsınız ancak compiler önce sizin yazdığınız kodu icra etmek yerine, yazdığınız program için çalışacak ortamı hazırlamak için öncü bazı hazırlıklar yapacaktır. Her program için işletim sistemi o programa ait giriş noktasını gösteren CS:EIP çiftini hazırlar. İşlemci'de o CS:EIP ikilisine ait ,bazı çevrimler yaparak kodu icra etmeye başlar.

Şimdi hızlı bir giriş yaparak assembly programlamaya başlayabiliriz.

www.masm32.com Bu yazdığımız programları işe yarar hale getirmek için gerekli. Çektiğiniz zaman zipi sürücülerinizi kök dizinlerine açın ör: C: D: E: Ğ: :)

OllyDbg Buda derlediğimiz programlarımızı irdeleyebilmemiz için gerekecek.

Evet gerekenler bunlar ve hepsi içerisindeki örneklerden oluşan kabarıklığı saymazsak 1.5 mb kadar alan kaplıyor .

Masm32 Win ortamlarda assembly kodları ile çalışmak için geliştirilmiş bir derleyicidir. Yazdığınız *.asm uzantılı kodlarınızı size *.exe *.dll olarak sunar. Kabul ettiği ve anladığı tek şey assembly komutlarıdır.

Basit bir giriş yaparak aşağıdaki gibi bir örnek verecek olursak:


.386
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

.data
Baslik db "Ben bir başlığım",0
Mesaj db "Selamün Aleyküm Dünya!",0

.code
start:
invoke MessageBox, NULL,addr Baslik, addr Mesaj, MB_OK
invoke ExitProcess,NULL

end start





Evet yapısı itibari ile biraz karışık olduğu konusunda haklısınız ancak bu kanınızın ileride değişeceğine eminim. Şimdi yukarıda ki kod örneğimiz üzerinde ayrıntılı bir inceleme yapalım.


.386



Bu komut masm32 derleyecisine(compiler)'e kısaca şöyle der: "Dostum bu programı yazan herifin yazdığı kodlar eski 386 işlemcilerin anladığı opcode'lardan oluşuyor derleme yaparken ona göre yap" der.Ancak bu seçeneği seçerseniz yeni nesil .686 işlemciler için çıkmış son nesil kodlardan yararlanamazsınız. Bu seçeneği isterseniz .686 da yapar yeni nesil komutlarla çalışabilirsiniz. Ayrıca bir diğer önemli hususta adresleme modlarıdır. Yani bu komut eğer .386 altı bir değer ise ör: .286 ve daha aşağısı gibi adresleme modları daha yeni nesil adresleme modlarını örmeğin(80386 Scaled Indexed Addressing Modes) [çok iyi bir indeks bulma yöntemidir zatî alîler-i]desteklemez. O yüzden en iyisi siz .386 ve yukarısını işlemci aileleri ile çalışmayı seçin sonra kafanız ağrımasın.


.model flat,stdcall





Bu komut ise programınızı kodlarken bir hafıza işlemi yaptığınızda ve yahut bir komut çağırdığınızda işe yarar. Şöyle ki: Eğer 32.bit için program yazıyorsanız genelde flat hafıza yöntemi kullanırsınız çünkü flat komutu hafızayı 4GB sanal bellek olarak varsayar.

Ne demek 4Gb sanal bellek kullanmak? Eski işlemcilerle hafıza sadece 640kb olarak adreslenebiliyordu, sonraları bu sınır segmentasyonda yapılan bazı değişikliklerle 1MB sınırına ulaştı. Ancak işlemci teknoloji gelişmiş ve 32'bitlik bir mimari kazanmıştı. Buda artık hafızaya 32 bitlik erişimler yapılabileceği anlamına geliyordu. Kısaca 32Bit erişimlerle 4GB hafıza adreslenebiliyor. (Bunu windowsunuzun hesap makinesinde 32 adet 1'lik biti yan yana getirip daha sonra decimale çevirdiğinizde görebilirsiniz. ) Peki sisteminizde 32 Mb Ram 512mb hdd varken(küçümsemeyin benim hala böyle çalışan bir sistemim var J) nasıl oluyor da her program 4GB hafıza kullanabiliyor. Bu aslında işlemci üreticilerinin geliştirdiği basit ama bir o kadar da harikulade bir numara. Olay şöyle cereyan ediyor. Her program için işletim sisteminiz sadece programınızı ilgilendiren bir tablo tutar. Bu tabloda programınıza ait hafıza adreslerini gösteren adına linear address dediğimiz konumlandırıcılar için fiziksel hafızada nereye denk geldiklerini gösteren girdiler vardır. Daha da basitleştirirsek: olayı 2 sütunlu excel tablosu gibi düşünebiliriz. A sütunu Doğrusal adresleri(linear) b sutunu ise Fiziksel adresleri belirtiyor olsun. Fiziksel adresten kastımız Ram'imizdir. Bu sütunlarda programınıza ait bazı en çok kullanılan doğrusal adreslere denk düşen fiziksel sayfa numaraları bulunur. Tabi o sütunların hepsinde her doğrusal adrese bir fiziksel adres denk geliyor diye bir kaide yok. Dedik ya sadece çok sık kullanılanlar o tabloda yer alıyor. Eğer işlemci programınızdan o tablonun fiziksel sütununda bulunmayan bir doğrusal adresini çağırırsa, işletim sistemi cpu için hdd'ye giderek o programın o doğrusal adresine denk düşen veriyi alır ve o fiziksel sayfa sütununa koyar. İşlemci de "'her şey ne kadar güzel 1.76 gb'da bile verilere erişebiliyorum "' der J. Biraz daha anlatmaya devam edersem Hafıza modelleme konusuna geçiş yapmak zorunda kalacağım en iyisi burada kesmek.

Şimdi stdcall'e geçelim. Bu komut compilere(compiler masm32 de ml.exe'dir) prosedür çağrılarının stack'e hangi sırayla atılacağını ve alınacağını belirtir. Üç çeşitli vardır :

1-C 2-Pascal 3'te - Stdcall

Biz hep StdCall'i kullanırız . Niyemi?
Ne demiştik her programlama dili eninde sonunda kodlarını assembly'de anlaşılacak bir hale getirecektir. Ama bu çevrim işleminde bazı yerler vardır ki o programlama dilini yazan firmanın tercihidir karışamayız. Mesela C çağrım şartı için:

goster(int par1,int par2, int par3) gibi bir prosedür çağrısında işlemci bunu

push [par3]
push [par2]
push [par1]
call goster
add sp,12

şeklinde işleyecektir.

Yukarıdaki kod stacke par3'ten başlayarak değerleri koyar ve goster prosedürünün altındaki komutları icra edip kaldığı yere geri döner ve add sp,12 ise stack'i eski haline geri döndürür. Yani stacki eski haline döndürme işlemi prosedürün işi bittikten sonra yapılır .Ama Pascal çağrım şartında bu tam tersidir. Şöyleki:

topla:= par1+par2+par3 için bu asm'de
push par1
push par2
push par3
call **pla

dır.

Add sp,12'nerde? Tabiiki **pla prosedürünün içerisinde . Yani stacki derleyip toparlama işi çağrım yapılan fonksiyonun görevidir.

Son olarak STDCALL ise bunların ikisinin karışımıdır. Yine örnekle açıklarsak

**pla(int par1,int par2,int par3) prosedürü asm'de

push [par3]
push [par2]
push [par1]
call **pla

dır.

C çağrım şartı, fonksiyon veya prosedürle verilen operatörlerin en sağından başlayarak stacke koyma işlemini yapar ve fonksiyondan sonra stacki düzenler.Ama Pascal bunun tam tersini yapar ve stacke koyma işlemini soldan sağa yapar ve stacki fonksiyonun içinden çıkmadan düzenler.Stdcall ise C gibi stacke alma işlemini sağdan başlar ama pascal gibide fonksiyon içerisinde stacki düzenler.

Bu anlatılanları bir debuger'la sınarsanız mantığı daha iyi kavrayacağınıza eminim.

Evet bu kısmıda anladıysak devam ediyoruz..


option casemap:none




Bu yönerge programcının isteğine bağlıdır. Şöyleki Bununla compilere dersinizki: "Yazdığım tüm komutlar ve ne kadar şey varsa bunları küçük büyük harf ayrımına tutma. Ben acaip bi insanımdır bazen "push" yazarım bazende "PuSh" sen benim keyfime karışma" der. Bunuda anladıysak kaynak kodumuzdan bir satır daha aşağıya iniyoruz.


include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc


Yukarıdaki komutlar compilere (derleyiciye) bizim hangi yardımcı komutlarla çalışacağımızı söyler. Bu .inc dosyalarının içerisinde bazen komut makroları bazende işletim sistemi fonksiyonlarının komutun kaç paramtre ve hangi tipte boyda veri alacağını belirten tanımlamalar yer alır. İlgili dizindeki dosyaları açarak ne demek istediğimi daha iyi anlayacağınıza inanıyorum.


includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib





includelib komutuda compilere çalıştığımız yardımcı komut kütüphanelerinin hafızadan veya dosyadan çağrılacak offset tanımlamalarını belirtir.


.DATA
.DATA?
.CONST
.CODE


Evet EXE'ler nasıl çalışır adlı dokümanımı okumayanlar için bir daha tekrarlayayım . Her çalıştırılabilir dosya ki buna .dll'lerde dahildir, içlerinde programcı tarafından önceden tanımlanmış bilgiler ".data" veya kullanıcıdan veyahut etkileşimli bir komuttan alacağı verileri muhafaza için ".data?" ve program içinden dahi değiştirilemeyecek readonly, gerekli ön tanımlama bilgileri ".const" ve tüm yazılımsal kodları içeren ".code" gibi alanlara sahiptir.

Özetle

.DATA Kullanıcıya iletilecek önceden tanımlanmış veriler veya program içerisinde kullanılacak bazı ön tanımlı değerleri tutar. Buna örnek olarak kaynak kodumuzda belirttiğimiz


.data
Baslik db "Ben bir başlığım",0
Mesaj db "Selamün Aleyküm Dünya!",0


gibi bir tanımlama verilebilir.

.DATA? ise hafızada yeri ve mekanı belli ama içerisinde hiç bir bilgi olmayan , dışarıdan gelecek her veriye "gel ne olursan ol yine gel" diyen bir alandır Örneğin


.data?
buffer db 512 dup(?)

.code
mov dword ptr[buffer],'X'



Yukarıdaki gibi bir kodda programı ilk çalıştırdığınızda buffer alanı hafızada ayrılmış ancak hiç bir bilgi içermeyecektir. Ta ki yukarıdaki "'mov"' komutu icra edilene kadar.

.CONST Komutu ise program icra edilirken, ne kendi içerisinde ki bir müdahaleyle ne de dışarıdan alınacak bir girişimle değiştirilemez verileri tanımlar. Mesela bir web server yazdık bunun portunun değiştirilmez bir şekilde 80 olmasını istedik. Bunu :


.CONST
webport equ 080h


diyerek yapabiliriz.

Her programlama dilinde olduğu gibi assembly'de de data tanımlama belirteçleri vardır. Bunlar:

db = Define Byte (8Bit)
dw = Define Word (16Bit)
dd = Define Dword(32Bit)
..
dup(?) = Define memory up (miktar)

Yukarıdaki tanımlamalar hafızada belirtilen değerlerde veri girişi sağlar.

Elinize bir kalem kağıt alın yada paint'i açın. Büyük bi dikdörtgen çizin . Bu çizdiğiniz şey sizin programınızın kullanacağı hafıza alanı . Evet windows sizin programınızı böyle bir şey gibi görür. Sizin yapmanız gereken az önce bazılarını yukarıda da anlattığım .data .data? .const .code gibi sınır çizgileri ile bunları bölmek. Yani programınız hafızada artık en basitinden ".data .code ve .stack" gibi görünecektir.

Evet artık size düşen bu alanlarla oynamak. Yukarıdaki kodumuzu inceleyin o hem .data section için hafızada ayrılan boşluğa veri yazar, hemde .code içinde belirtilen kodlar için hafızada kod bloğu oluşturur. Bu data yazma işlemini örneğin

mesaj db "Selam millet",0
veya
sayi dd 0125468984h
veya
handle dw 015fah

gibi yazarız . Bunlar ne anlama gelir.

Eğer hafızaya bir string girecekseniz bunu db ile yapmalısınız. Niyemi? hatırlayın her ascii harfinin tekinin boyutu nedir? 1Byte!. Öyle ise ben :

mesaj db "Selam",0

dediğimde bu hafızaya byte byte yazılacaktır . Şöyleki:
Hafıza:

00403000 53 65 6C 61 6D 00 00 00 00 00 00 00 00 00 00 00 Selam

gibi olacaktır.

Ama bunu gidip
mesaj dd "Selam" deseydim hafıza:

00403000 53 00 00 00 65 00 00 00 6c 00 00 00 00 61 00 00 S...T...R

gibi birşey olacaktı ve programınızın ekrana S yazıp bitecekti. Çünki windows stringler için 00'ı terminated data(sonlandırıcı) olarak tanır.

Evet artık .code .stack. data .const compile, verilerin hafızada nasıl yerleştiği, çalışan processin bir debuggerda nasıl gözüktüğü,sectionlar anlamış olmalısınız ve evet artık sizinle güzel örneklere başlayabiliriz.

Burada şöyle bir yöntem kullanacağım . Sizinle birlikte daha kolay anlayasınız diye masm32'nin içinde yer alan icztutes klasörünün içindeki Iczelion'un yazdığı örnekler üzerinde çalışacağız .

Şimdi ilk önceliğimiz size göre tute02 almalıydı ama o zaten yukarıda verdiğim örneklerle birebir aynı ben onu geçip doğrudan TUTE03 klasöründe yer alan WIN.asm uygulamasının üzerinde çalışmayı yeğliyorum.

Win.asm'nin içeriği aşağıdaki gibidir.


.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

WinMain proto :DWORD,:DWORD,:DWORD,:DWORD

.data
ClassName db "SimpleWinClass",0
AppName db "Our First Window",0

.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke GetCommandLine
mov CommandLine,eax
invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
invoke ExitProcess,eax

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInstance
pop wc.hInstance
mov wc.hbrBackground,COLOR_WINDOW+1
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc
INVOKE CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\
hInst,NULL
mov hwnd,eax
invoke ShowWindow, hwnd,SW_SHOWNORMAL
invoke UpdateWindow, hwnd
.WHILE TRUE
invoke GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.ENDW
mov eax,msg.wParam
ret
WinMain endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.IF uMsg==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
WndProc endp
end start


Program çok basit bir windows penceresidir. içinde hiç bir şey yoktur ve kapat komutundan başka hiç bir komuttan anlamaz.

Windows'ta işler çoğunlukla pencerelerle yürür. Örneğin siz şu anda bu sayfayı Windows işletim sistemi yardımıyla görüntülüyorsanız bu Pencerelerin sayesinde oluyor. Yani şu anda bu okuduğunuz doküman bir pencerenin içinde yer alıyor ve bu pencere genel olarak "açma,kapama,ölçekleme,büyütme ve küçültme, üzerinde yapılan değişiklikleri algılama,fare hareketleri,klavye gönderimleri, başka pencerelerle veri akışı vs.. bir çok yapıyı idare eden bir yapıdadır. Penceremizi yöneten ve onunla çalışmamızı sağlayan GUI'dir, iş akışını idare eden ise Win32 Messaging sistemidir. Yani siz bu pencerenin üzerinde her mouse hareketi yaptığınızda win32 subsystem bu pencereyi kontrol eder ve mouse koordinatlarını yine bu pencereye mesaj olarak iletir ve eğer bu pencereyi yazan programcı bu hareketler için özel tepkiler programladıysa onları pencerenin icra etmesini sağlar. Yukarıdaki örnekteki kodda penceremiz sadece gelen kapat bildirimini almakta ve pencereyi yok etmektedir. Bundan başka gelen her komutu ise DefWindowProc prosedürüne ileterek isteğin Win32 tarafından denetlenmesini ister. GUI kütüphanesi ile pencerelerinizin tasarımını yönetirsiniz. İkonu, şekli, üzerinde yer alacak butonlar,resimler vs.. sizin için hazır olarak bulunan Api'ler ile bunları rahatlıkla yapmanız için GUI tarafından desteklenir.

Her pencere standart olarak bir çerçeveye o çerçeve üzerinde bir başlık çubuğuna, başlık çubuğu üzerinde opsiyonel olarak kapatma,ölçekleme ve simge durumuna alma tuşlarına sahiptir. Bu Windows'un pencere standartıdır. Ama biz gerçekte daha zengin pencerelerle karşılaşabiliyoruz. İşte buda pencerelerin opsiyonelleştirilebilmesi gerçeğini ortaya koyuyor. Evet pencereler aslında her özellikleri ile değiştirilebilecek nesnelerdir.

Windows'da pencere oluşturmak istersek yapmamız gereken bazı zorunlu haller vardır onlar her pencere için bir ana prosedür olan WinMain proceduru ve o pencereye gelecek mesajları irdeleyecek WndProc prosedürü. Bu ikili bir pencerede birlikte olmak zorundadırlar. Biri ki bu WinMain oluyor Pencere ve özelliklerini ayarlayıp pencereyi kullanıcıya sunar ve gelen her isteği dinler, diğer yani Wndproc ise bu gelen mesajlara göre programcının tepkisini yansıtır. Aslında pencere konusunu biraz daha açarsak, bir pencere oluşumu için gerekenler şunlardır.

1. Win32'nin programımıza bağlı pencere ile iletişime geçebilmesi için bir instance handle alınır. Bu handle vasıtası ile penceremizin ana fonksiyonuna ulaşırız.
2. Penceremiz için bir class name ve de bir class yapısının içini oluşturmalıyız. Bu class, penceremizin temeli niteliğindedir. Penceremiz için gereken görsel ve yapısal ayarların geneli burada yapılmalıdır. Örneğin: Penceremize gelen mesajları hangi prosedürün inceleyeceği, mouse imlecinin şekli,arkaplan rengi gibi çoğunu örnek kodumuzda da göreceğiniz ayarları bu sınıfta tanımlarız.
3. Oluşturduğumuz Class'ı Register etmeliyiz. Bu RegisterClassEx api'si ile yapılır. Böylece penceremizi oluşturduğumuzda ne tür bir yapı ile çalışacağını windows'a belirtmiş olacağız.
4. Penceremizi oluştururuz. CreateWindowEx api'si ile bunu yapabiliriz. Bu komut ile birlikte artı penceremiz hafızada yapısal olarak son şeklini almıştır.
5. Pencere görünür hale getirilir. Hafızada yapısal olarak bitmiş penceremizi ShowWindow komutu ile artık kullanıcılara sunarız.
6. Bir defaya mahsus Windowsun penceremiz için Refreshing işlemi yapmasını sağlarız. Bu sayede penceremiz artık gerçekten desk**pumuzda aktif işlem olur.
7. Penceremiz için istekleri dinleriz. Evet artık penceremiz hazır ve aktif olduğuna göre penceremiz için kullanıcı bazlı veya diğer programlardan gelebilecek istekler için sonsuz bir dinleme haline girmeliyiz. Bunu GetMessage ve DispatchMessage api'leri vasıtası ile yaparız. GetMessage api'si penceremize uğrayan her mesajı Windows'un mesaj kuyruğundan alır ve DispatchMessage gönderir. DispatchMessage işe gelen isteği irdeler ve 2. adımda belirttiğimiz Pencere prosedürüne gönderir.
8. Ve penceremiz ile işimiz bittiğinde onu sonlandırırız.

Şimdi kodu inceleyelim:


.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

WinMain proto :DWORD,:DWORD,:DWORD,:DWORD


Buraları anlatmıştım o yüzden es geçiyorum.


.data
ClassName db "SimpleWinClass",0
AppName db "Our First Window",0


ClassName pencereler için çok önemlidir. Çünkü her pencere Windows iyi bir kategorilendirme yapabilsin diye ve de mesajlaşma sistemi kullanılabilsin için bu class name ve application name ihtiyaç duymaktadır . Hani bilirsiniz kendi uygulamanızdan başka bir uygulamaya mesajlar gönderirsiniz FindWindow ile bu iş, işte böyle yürür.


.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?


hInstance daha öncede bahsettiğim gibi Windows'un programımızın varlığını bilsin için ve kendi içinde haberleşmelerde kullanması hasebiyle kullanmak zorunda olduğumuz bir değer. Bu değer Win32 tarafından bize sağlanan 32 bitlik sayısal bir değerdir ve çoğunlukla win32 altında bu değer programımızın hafızadaki doğrusal adresidir.

CommandLine ise tamamen programcının isteğine bağlı tek amacı programınıza dışarıdan gelen komut parametrelerini almak olan bir api'dir. Örneğin programınızın adının spy.exe olduğunu düşünürsek, kullanıcı bu programa doğrudan çalıştırma yoluna gitmeyip parametre ekleyerek(ör:spy.exe minimize) çalıştırırsa siz bu ilave parametreyi CommandLine sayesinde programınızın içerisinde değerlendirip tepki verebilirsiniz.


.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke GetCommandLine
mov CommandLine,eax
invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
invoke ExitProcess,eax
.....
end start


Evet sonunda bizi gerçekten ilgilendiren yere yani kodumuza girmiş bulunuyoruz. Şu unutulmamalıdır ki masm32 ile programla yaparken icra edilecek kodlarımız .code section'da iki ana etiket arasında bulunmalıdır . Bu programımızın iskeleti niteliğindedir. Ön tanımlı olarak masm32'de bu etiketler start: end start olarak tanımlanmıştır ve bu isimleri rahatlıkla dilediğiniz gibi değiştirebilirsiniz. GetModuleHandle komutumuz yukarıda da belirttiğim gibi bizim için windowstan bir başlık alır. Bu komutun icrasından geri dönen değer "'eax"' yazmacında dır.

Not: Windows kendi tanımlaması olarak fonksiyon dönüşlerini eax'ta alır .Bizde bu mimariye uymak zorundayız.

Eax'te ki değeri "'mov"' komutu ile ileride kullanabilmek için hInstance değişkenimize alıyoruz. Ardından GetCommandLine ile programımıza dışarıdan gelen isteklerin bulunduğu hafıza alanına ait değeri yine "'eax"' vasıtası ile alıp CommanLine değişkenimize gönderiyoruz. Dilersek daha sonra bu alandaki verileri değerlendirip özel işlemler yapabiliriz ancak bu örneğimizde böyle bir şey yok.

WinMain penceremizi oluşturmamız için giriş noktamızdır. WinMain ismi tamamen isteğe bağlıdır yine diğerlerinde olduğu gibi bunu da dilediğiniz gibi değiştirebilirsiniz. WinMain 4 parametre alır. Bunlar sırası ile
1. Win32'den aldığımız handle'mız,
2. Win16 günlerinden kalma ama artık kullanılmasının pek esprisi olmadığını düşündüğüm yedek handlemiz,
3. Komut satırı verilerini barındıran parametrelerimizin yerini gösteren pointerimiz.
4. Penceremizin başlangıçta hangi biçimde görüneceğini belirten CmdShow belirtecimiz.

ExitProcess ile de programımızı güvenle terk ederiz.


LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND


LOCAL komutu biz herhangi bir fonksiyonda yalnızca o fonksiyonun kullanması için değişkenler atadığımızda bizim için stackten hafıza ayırır. Bizi ilgilendiren yer ise penceremiz olduğundan daha öncede bahsettiğim pencere sınıfımız için yapılması gereken bazı tanımlamaların kullanması gereken bir yapının kurulması. Windows bu yapıyı WNDCLASSEX içinde görmek istediğinden onu ve ona point olan "'wc"' değişkenimizi yazdık. Ayrıca mesajlarımız için yine win32 ön tanımlı olarak MSG yapısı ve penceremizi için mesajlaşmalarda kullanacağımız 32 bitlik bir dword olan HWND'yi belirttik. Biz bunları local ile yaptığımızdan bu fonksiyonun dışında başka yerde kullanılmaları söz konusu değildir.


mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInstance
pop wc.hInstance
mov wc.hbrBackground,COLOR_WINDOW+1
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax


Yukarıdaki komut kümesi tamamı ile sık sık kendinden bahsettiğimiz pencere sınıfımızın içeriğini doldurmak ile ilgilidir. WNDCLASSEX gibi bir yapıyı doldurmamızın amacı ileride aynı şablonda birden fazla pencere oluşturacağımız anlarda bunu bir çok hafıza alanı tüketmektense varolan bir hafıza alanında onu point ederek üretmek olacaktır. Ayrıca yine belirtmeliyim ki WNDCLASSEX yapısı gibi Windows'ta hazır olarak ön tanımlı bir çok pencere sınıfı vardır. Örneğin editbox, button bu gibi sınıflardır ve sadece CreateWindowEx api'si ile herhangi bir yapının içini doldurma gereği olmadan oluşturulabilirler. Şimdi herşeyin neden object olduğunu anlamışsınızdır umarım J . WNDCLASSEX yalın halde aşağıdaki gibi bir yapıdır.



WNDCLASSEX STRUCT DWORD
cbSize DWORD ?
style DWORD ?
lpfnWndProc DWORD ?
cbClsExtra DWORD ?
cbWndExtra DWORD ?
hInstance DWORD ?
hIcon DWORD ?
hCursor DWORD ?
hbrBackground DWORD ?
lpszMenuName DWORD ?
lpszClassName DWORD ?
hIconSm DWORD ?
WNDCLASSEX ENDS


mov wc.cbSize,SIZEOF WNDCLASSEX ile kullanacağımız yapının boyutunu alırız. Bu bound ayarı ve windows'a register ederken doğru tanımlama yaptığımızı garantilemek açısından önemlidir.

mov wc.style, CS_HREDRAW or CS_VREDRAW, ise pencerelerimizin ölçeklendirme işlemlerinin her taraftan yapılabileceğini belirtir. Dilerseniz farklı bir çok seçenek daha eklenebilir. İlgili opsiyonlar Windows.inc dosyasında yer alırlar.

mov wc.lpfnWndProc, OFFSET WndProc penceremize uğrayacak her türlü mesajın işlenmek için hangi prosedüre yollanacağını belirtir.

mov wc.cbClsExtra,NULL işletim sistemi tarafından boş bırakılır . Extra sınıf tanımlamaları için sonradan kullanılması planlanan veriler buraya point edilir.

mov wc.cbWndExtra,NULL. Eğer class tanımlaması ayrı bir dosyada (*.rc) yapılmış bir dialog kutusu sınıfı ile çalışacaksanız bu alanı doldurmak zorundasınızdır.Tabi bizim ilgi alanımız şimdilik yalın pencereler olduğundan boş bırakıyoruz.

push hInstance
pop wc.hInstance ile programımıza ait handle'i pencere sınıfımıza atıyoruz.

mov wc.hbrBackground,COLOR_WINDOW+1 penceremizin arka plan renk seçimini yapıyoruz. Daha fazla renk seçeneği için include dosyaları incelenebilir.

mov wc.lpszMenuName,NULL Eğer pencerenizde tıpkı internet explorerda veya office programlarında olduğu gibi Dosya,Düzen,Görünüm,Yardım gibi ilave araçlar içeren bir menü çubuğu istiyorsanız ilgili yapının adresini de buraya belirtmelisiniz.

mov wc.lpszClassName,OFFSET ClassName. Bu pencere sınıfımızı register edebilmek ve ileride program içinden veya dışından penceremizin görsel ayarları ile oynamak istediğimizde kolayca ulaşabilmemizi sağlayan bir belirteçtir.

invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax ile penceremizin sol üst köşesinde veyahut ta minimize edilirken ki halinde gözükmesini istediğimiz icon'u belirtiriz.

invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax burada da tıpkı LoadIcon api'sinde olduğu gibi pencere içinde mouse'mizin almasını istediğimiz şeklini çizdirebiliriz.

invoke RegisterClassEx, addr wc ve artık istediğimiz ayarlamaları yaptıktan sonra bu komut ile penceremizi windows'a kayıt ettiriyoruz.

INVOKE CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\
hInst,NULL

ve artık penceremizi servise sunma zamanı geldi. CreateWindowEx fonksiyonu 12 parametre içerir . Genel yapısı şöyledir.

CreateWindowExA proto dwExStyle:DWORD,\
lpClassName:DWORD,\
lpWindowName:DWORD,\
dwStyle:DWORD,\
X:DWORD,\
Y:DWORD,\
nWidth:DWORD,\
nHeight:DWORD,\
hWndParent:DWORD ,\
hMenu:DWORD,\
hInstance:DWORD,\
lpParam:DWORD

.dwExStyle: Bu parametreyi biz boş geçtik ama dilerseniz siz pencerenizin sürekli ekranın üstünde görünmesi gibi özel ayarlamalar yapabilirsiniz.

.lpClassName: Bu mutlaka gerekli bir parametredir. Çünkü hangi pencere sınıfının gösterileceğini daha önceden kayıt ettirdiğiniz pencere sınıfı ismini alarak yapmaktadır.

.lpWindowName: Pencerenizin başlık çubuğunda yazmasını istediğiniz string ifadeyi alır. Eğer NULL geçerseniz başlık çubuğunuzda hiçbir şey yazmaz.

.dwStyle: Bu parametreyi doldurmazsak başlık çubuğunda ne kapama nede büyültme ve küçültme tuşları olmazdı. Biz ortak bir tanımlama olan WS_OVERLAPPEDWINDOW ile standart butonların olmasını istedik.

X,Y: Pencerenin sol üst köşesin bulunacağı koordinatı verir. Biz default değeri vererek bu işi windowsun gönlüne bıraktık

.nWidth,nHeight: Kısaca penceremizin eni ve boyu. Biz yine bu işi windowsa bıraktık.

.hWndparent: Eğer aynı özelliklerde ana pencerenize bağlı başka bir alt pencere oluşturmak isterseniz bu değeri ilgili child pencerenin handle ile doldurmalısınız. Bu bir nevi MDI tarzı bir görüntü oluştursa da child pencere hiçbir zaman ana pencerenin boyut sınırları arasında değildir. Yani istediğiniz yere masa üstünde sürükleyebilirsiniz. Ancak bu şekilde üretilen child pencereler ana pencere kapandı anda otomatik olarak kapanacaktır.

.hMenu: Eğer zaten WNDCLASSEX ile pencere sınıfınıza menü eklediyseniz bu parametreyi boş geçebilirsiniz. Menü kullanmak istemediğinizde de boş tur. Ancak menu kullandığınızı ve menu sisteminizi sayısal değerlere sahip id ler ile yönetmek istediğinizi varsayarsak o zaman bu parametre sizin için kullanışlı olabilir.

.hInstance:Bu da yine kalıtımsal olarak hiyerarşik bir şekilde programımızın başında windowstan elde ettiğimiz handle'dir.

.lParam: Kendi tasarladığınız veya ön tanımlı yapıların mesaj olarak pencerenize iletilmesinde kullanacağınız bir parametredir. Örneğin çok pencereli MDI formlarda CLIENTCREATESTRUCT yapısını pencerenize vererek daha sonra client lara GetWindowLong ve SetWindowLong api'leri vasıtası ile değişiklikler yapabilirsiniz.

Evet ayrıntılı bir şekilde de CreateWindowEx api'mizi inceledikten sonra devam ediyoruz.
CreateWindowEx apiside çalıştıktan sonra yine "'eax"' içinde hafıza oluşmuş penceremizi gösteren pointer'i dönderiyor. Artık penceremizin hafıza belli bir imajı çıktı ve bizim onu görücüye çıkartmamızı bekliyor. Bunu yapmanın yolu ShowWindow api'si. ShowWindow api'si iki paramtre alır bunlardan ilki hafıza yer alan ve bize ait olan pencerenin handle'ı, diğer ise pencerenin kullanıcıya sunum şeklini belirten CmdShow parametresi.

İnvoke ShowWindow,hwnd,CmdShow ; diyerek penceremizin kullanıcıya daha önceden WinMain içinde verdiğimiz CmdShow değişkeninde belirtilen niteliğe göre gösterilmesini sağlarız.

Artık penceremiz gözüküyor ancak bu kaba bir tabirle kuru bir yaprak sayfası gibidir. Bu pencereyi kullanıcıdan mesaj alıp verebilmesi için bir kere tetiklememiz lazım ve bunu

İnvoke UpdateWindow,hwnd; ile yapıyoruz.

Artık program emir almaya hazır ancak bu gelecek olan istekleri ne ile **playacak ve ne ile işleyecek. İşte buraya sıradaki adamlarımız mesaj komutları devreye girer. Kısaca şöyledir.


.WHILE TRUE
invoke GetMessage,Addr msg,NULL,0,0
.BREAK .IF(!eax)
invoke TranslateMessage,addr msg
invoke DispatchMessage,addr msg
.ENDW


Gördüğünüz gibi bu işlemi sonsuz bir döngüde yapmak zorundayız aksi halde dakikada binlerce mesaj akan bu win32 sisteminden bize ait olan mesajları almamız olanaksız olurdu.GetMessage api'si penceremize ait bir mesaj gelene kadar bekler. Yani kod akışı orada durur. Ta ki dışarıdan bir müdahale gelsin ve gereken prosesler başlasın.

İnvoke GetMessage,addr msg,NULL,0,0 Win32'nin mesaj kuyruğundan bir mesaj alır ve eğer mesaj bizim penceremize ait ise msg yapısının için doldurarak bir alt yordama havale eder. GetMessage geriye eğer WM_QUIT gibi bir çıkış mesajı alır ve False döndürürse bu döngüden çıkılması anlamına gelir.


.invoke TranslateMessage api'si aslında kullanılması zorunlu olmayan bir api'dir. Tek amacı pencerenize klavyeden gelen klavye vuruşlarını ascii kod olarak doğrudan işlemesidir. Dilerseniz kullanmayabilirsiniz.

İnvoke DispatchMessage ise mesajı alır ve Mesajları işlemekle yükümlü fonksiyona gönderir. Bizim örneğimizde bu WndProc'tur.

mov eax,msg.wParam
ret
WinMain endp

Mesaj döngüsünden çıkılıp program sonlandırılacağında msg yapısının wParam parametresinde çıkış kodu yer alır. Aslında windows bu değer bir daha kullanmaz ama oyunun kuralı gereği güvenli çıkış adına bunu şart koşmuştur. Keşke her işlerinde bu kadar sağlam olsalar J .

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

Bu bizim pencere işleyicimiz. Bu yapının anlaşılması çok önemlidir. Fonksiyonun aldığı parametreler şunlardır.

HWND: Her fonksiyonda olduğu gibi buradada ilgili handle'mızı kullanıyoruz.

.umsg:UINT: Gördüğünüz gibi bu msg yapısı gibi bir şey değil sadece bir sayısal ifade. Windows'ta binlere mesaj vardır ancak programlarımız sadece kendilerini alakadar eden mesajlarla ilgilenirler. Bu UINT değeri sayesinde sadece istediğimiz ilgili mesajın sayısal ifadesine denk gelen mesajla ilgilenebileceğiz anlamına gelir. Örnekleri ileride görecekseniz.

WParam,LParam: Bazı mesajlarla birlikte bazı ilave bilgiler de gelir. Örneğin pencerenizde yer alan bir butona basıldığında bunun mouse ile mi yoksa klavye ile mi gelen bir mesaj olduğunu wParam ve lParam öğeleri ile birlikte gelen değerlerden anlarız.


.IF uMsg==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
WndProc endp
end start


Bu kısım en can alıcı noktayı içeriyor. Burayı iyi anlamınız şart. Ne demiştik! Her pencere devamlı mesajlarla meşgul olur. Bunu bir debugger'la daha iyi anlayabilirsiniz. Siz pencereleriniz üzerinde işlem yapıldığında gelen isteklere gerekli yanıtı verebilmek adına bir filitre belirlemelisiniz. Örneğin siz programınızı her ne kadar da sakin rahat rahat çalışıyo sansanız da, programınız kendisi ile alakalı veya alakasız binlerce mesaj bombardımanına tutulur. Üziernde fare ile gezerken,bir click atarken, bir yerde bir yere taşırken,klavye ile bazı tuşlara basarken, siz programınıza bu isteklere karşı cevap verecek bir modül yazmasanız dahi bu istekler ile programınız meşgul olur. Peki bu kadar mesaj nasıl oluyorda siz bir şey yapmadan işleniyor. Yani pencereyi sürüklüyorsunuz ve istediğiniz yere gidiyor ama bunu siz yazmamıştınız. İşte bunu DefWindowProc halleder. Bu api sizin programınızda belirttikleriniz dışında programınıza gelen mesajları windows'a yönlendirir ve onun muhatap olmasını sağlar sizde böylece sadece kendi belirlediğiniz mesajlar ile rahatça ilgilenebilirsiniz. Tıpkı .IF uMsg==WM_DESTROY da ki gibi. Biz bu komutla uMsg'ya gelen sayısal değeri WM_DESTROY mesajına denk düşen mesajları işleyeceğimizi belirttik ve eğer mesaj gelirse şu işlemi yap dedik.

Evet bu yazınında sonuna geldik. Yazım hataları ve anlam karmaşası olan yerler için özür dilerim. Bir daha ki bölümlerimizde kaldığımız örneklerden devam etmeye çalışacağız inşAllah.

....

Not: Döküman biraz karışık ve birbirinden kopuk ilerliyor farkındayım. Ancak üzülerek söylemeliyim ki bu dökümanı bile iş aralarından fırsat bulup ilerletebiliyorum o yüzden inşAllah döküman bittiğinde baştan aşağı bir tarama yapıp gerekli düzenlemeyi yapıcam. kod:


Evet uzun süredir dökümanı editliyemiyorum ve sizde haliyle yeni şeyler bekliyorsunuz. Bu kısa ara, benim içinde dökümanda takip etmem gereken yol hakkında inceden inceye düşünmeye itti, ve artık stilde bazı değişiklikler yapmak zorunda hissettim açıkcası kendimi.

Yukarıdaki yazıyı okuyan arkadaşlar artık kısaca assembly ile bir mesaj kutusu nasıl çıkartılıyor biliyor. Bu aşamaya gelene kadar ise hafıza da veriler nasıl ve hangi tanımlayıcılar la tanımlanır, derlenmiş dosyanın hafızadaki şablonu nasıl bir hal alır, Stack nedir,section nedir,veriler hafızada nasıl dizilir,byte,word,dword tanımlamalar arasındaki fark ve bir çok kafa karıştıran konu artık bana göre kafanızdan silinmiş olmalı. Olmalı ki artık verilen örneklerden ve incelediğiniz kodlardan daha çok şey çıkarabileseniz.

Şimdi benim bu yazıda anlatmak istediklerim ise yine konumuzla bağımlı ve öğrenme sürecinizi maximum seviyeye çıkarmaktır. Örneğin bu yazımızda sizlere Win32 programlama yaparken API'lerin ne olduğu,nasıl çalışıldığı Win32 için olan önemleri ve kategorizasyonları. Kaç çeşit oldukları,kaç şekilde ulaşılabildikleri, hafızada ki konumlarının değişkenlik haritasının tanımı gibi kafanızı darman durman edecek bilgileri anlatmaya çabılayacağım. Ve artık bunları siz iyi kavradıktan sonra hangi dil ile olursa olsun win32 programlam yapmanız çok daha basit olacaktır. Ama tabi ben isterimki programlama dili seçeneğiniz Masm32 olsun .

API'ler

Application Programming Interface(Uygulama Programlama Arayüzü) de derler bu arkadaşa. Ama ben de bir tanım eklersem "Programcıların başka programcılara kıyak olsun "zaten ben bi tane yazmışım gariplerim uğraşmasın" diye ve üstelik kendi programlarının veya yapılarınında bütünlük garantisi olsun diye geliştirip export ettikleri bir fonksiyonlar destesi" diyebiliriz. Şöyleki siz kullandığınız işletim sisteminde olmayan bir disk onarım programı yazdınız ama dedinizki "yaw ben bunun görselliğini iyi yapamadım hem bu fonksiyonları yazana kadar göbeğim çatladı bi de kullanılabilirliğilemi uğraşacaktım bi çok yeride eksik kaldı,banane canım: "ederim işlevsel fonksiyonları export uğraşsın başkası "" derseniz bu yaptığınız şeye api denir. millet sizin dll'yi çeker programına import eder ve o fonksiyonları kullanır ve sizinkinden daha janjanlı program yazar ise o vatandaş sizin api'lerle bu işi yaptı demektir.Ve üstelik bu sayede de hem sizin geliştirdiğiniz teknoloji dehası kodlarınız bütünlüğü ve yapısallığı ile korunmuş olacak hemde sizin şablonunuz üzerinden kim bilir daha ne proglar geliştirlecek.

İşte Win32 Api'leride kendi yeteneklerini programcılara sunan geniş bir yelpazeyle yapar bu API işini. Aslında buna pek sunmak değilde dayatmak desek daha yerinde olur. Yani win32 açıkcası programcıların ince mevzularla kendi başlarına fazla haşır neşir olmasını istemez ve illa benim yeteneklerimi kullan der. Örneğin winnt serisinde seri porta dahi direk çıkış yapamazsınız illa bunu win32api leriyle yapıp bill gates'i rahatlatmanız lazım .

API'ler yukarıda yapılarından da bahsettiğimiz gibi programcısının yazdığı ve export ettiği bir fonksyionlar yumağıdır ve bu api'ler executable dosyalar içerisinde hizmet etmek için depolanırlar. Kernel32.dll,ntdll.dll,gdi32.dll,user32.dll ve bazı *.exe'lerin içlerinde hayatlarını idame ettirirler. Windows amca bu api'leri bazı kategorilere ayırmıştır. örneğin

Bir nesne veya dosya oluşturuken
Bir dosya ararken
Parametre yollar veya alırken
Sürücülerle çalışırken
Programlar arası veri transferi yaparken
Programdan girerken veya çıkarken
Hafıza ayırırken
Sistem mesajlarıyla boğuşurken
vb.. daha buna benzer veya daha farklı yaklaşık 949 ince tefferuatlı iş için KERNEL32.DLL

String çevrim işleri yaparken
Kullanıcı etkileşimli dialoglar görüntülerken
Klavye düzeni ve mouse hareketleriyle haşır neşir olurken
Cut+copy+paste işlemlerini yönetirken
Ekrana kalıp şekiller çizerken
Mesajların istenilen yerlere yönlendirmesini sağlarken
Başka programlara erişirken
ekrana yazı yazdırıken
vb.. daha buna benzer veya daha farklı yaklaşık 732 ince tefferuatlı iş için USER32.DLL

Fontlarla çalışırken
Ekrana cicili bicili şeyler çıkartırken
grafiklerle boğşurken
vb.. daha buna benzer veya daha farklı yaklaşık 609 ince tefferuatlı iş için GDI32.DLL

gösterilebilir.

Yukarıdakine benzer neredeyse x:\windows klasörünüz altında ki executable sayısına eşit oranda api'ler mevcuttur, ve bunları kullanmak ve keşfetmek sizin programcılık ve ihtiyaç merakınıza doğru orantılıdır.

Benim gibi işi sadece şifre kırmak,exploit yazmak,hinliklerle uğraşmak gibi tembel işleriyle uğraşanlar için yukarıdaki api'ler yeterde artar bile. Ama unutulmamalıdırki iyi bir win32 programcısı api'leri kullandığı programlama dilinin komutları kadar iyi bilmeli ve kullanabilmelidir. Ancak o zaman ortaya yetenkli ve işlevsel bir program çıkar.

Evet kaldığımız yerden devam edersek. Programcılar WinApi'leri ile çalışmadan önce kullandıkları programlam diline hangi api'ler ile çalışacaklar ise bunu compilerlerine belirtmek zorundadırlar. Tabi bazı programlama dilleri bunu otomatik yapmıyor değil ama şunu unutmayınki ne kadar hazır o kadar çok filesize demektir. Sadece size yarayan api'leri import etmeniz hem kodunuzun boyutunu korur hemde hızını.

devam edecek... yoruldum :)

7 yıl sonra gelen edit: yalana bak devam edecek demişim 7 sene geçmiş hala devam edicek :p

20 Ekim 2009 Salı

Passworks for Enterprise Domain (Active Directory)

Büyük ölçekli domain yönetmiş arkadaşlar bilirler, piyasada bilinen mevcut domain member olan computer'lara local admin parolası çakmak için en sık kullanılan yöntem group policyler vasıtası ile bilgisayar ilkesi üzerine basılan script vasıtası ile yapılır. Bir başka yöntem ve biraz daha güvenli olanıda aslında Wmi'lar vasıtası ile yapılanı'dır, ancak onuda aşmanın yolları fazlaca mevcut.

En sık kullanılan ve kolay olan yöntemin scriptler vasıtası ile yapıldığından bahsettik peki ama neden bu bir açık teşkil ediyordu ki? Domain Admin'i olan arkadaşımız Active Directory Users and Computers altından ilgili pc'lerin toplandığı OU üzerinde group policy atarken aşağıdakine benzer bir kodu kullanır:


strPassword = "p455w0rd" 'uygulanacak şifre
set objUser = getobject("WinNT://./Administrator,user") 'hangi user?
objUser.SetPassword strPassword 'şifreyi ata
objUser.SetInfo ' Değişiklikleri kaydet


Artık domaine üye olan her pc açıldığında ilk olarak bu scripti uygular ve böylece local admin şifresi değişmiş olur. Böylece sistem üzerinde yer alan tek tam denetimli kullanıcı güvene alınmış olunur!!!mu acaba?

Bu tip bir password distributed mekanizması uygulanan domaine üye bilgisayar açıldığında ilk olarak üyesi bulunduğu domain server rolünü üstlenmiş pc de bulunan sysvol klasörü üzerinde yer alan computer policylerini barındıran oid klasörüne bağlanır ve adminin aslında group policy editoru vasıtası ile gösterdiği script var ise bunu local yönetici hesap hakları ile çalıştırır ve uygular sonrasında ise tipik gpo ayarları alınır ve oturum açan kullanıcı üzerindeki hakların alınması ile süreç devam eder. İşte bu aşamada burada kritik rol üstlenen sysvol klasörünün public erişime mecburi olarak readonly de olsa açık olması bir zaafiyeti ortaya çıkarıyor. Bu scriptin burada yer aldığını bilen kullanıcı en kısıtlı kullanıcı hakları ile bile çalışsa bu dizine erişerek passwordu ele geçirebiliyor.

Olayın birde ERD Commander tarzı bootable programlar vasıtası ile yapılan local admin parolası sıfırlama kısmı var ki bunun önüne geçmek neredeyse imkansız ancak monitoring uygulamaları ile hemen bu tip bir değişiklik algılanıp denetleyici server'a bildirimi yapılarak suçu işleyen kişinin yakayı ele verdirmesini sağlayabilirsiniz.

Bu aşamada nacizane bende üstüme düşen görevi yapmak için basit bir tool hazırladım. Gelişim aşaması içerisinde Dameware tarzı bir ürün ortaya çıkarmak istiyorum ama bakalım süreç neyi gösterecek. Reklam kuşağını hızlıca geçip kısa bir tanıtımının ardından programımın buglar ve hatalarla dolu ama işinizi görecek sürümünü buradan sunuyorum.

Tüm os'ler ile rahatça çalışabilmesi için en son .net framework olan 3.5 derledim. Bu yüzden çalıştırmadan önce .net framework 3.5'i kurmanızı tavsiye ederin. Kabaca program'ın özellikleri şunlar:

- Bağlantı protokolleri olarak tüm Ldap servislerini çalıştıran server'lardan computer ve user bilgilerini alıp üzerinde işlem yapabiliyor

- Ldap connection için şu an her ne kadar programa Ldap 2 seçeneğini eklesem de sadece Ldap 3 protokolü ile bağlanıyor.

- Yine bağlantı metodları olarak Negotiate, SimpleAuthenticate ve SSL destekli olarak domain server'ina bağlanabiliyor.

- Şimdilik amaca uygun olarak sadece Computer ve User nesnelerini ekledim ancak tüm active directory destekli işleri yapmaya müsait bir taban üzerine inşaa etmeye çalışıyorum

- Tüm domainde ki açık olan pc'lere sıralı olarak istenilen local admin parolasını çakıyor ve raporluyor.

- İstenilen pc'de istenilen local user için parola doğrulama testi yapılabiliyor

- User'lar da parola sıfırlama işlemi yapılabiliyor

- Seçilen pc'ye varsayılan remote monitor tool ile erişim imkanı..

Programla alakalı olumlu/olumsuz görüşlerinizi ve esprilerinizi :p bekler iyi çalışmalar dilerim.

Download link: Passworks Download

Yeniden Uyanış

8 sene önce aktif olarak başladığım Sistem programcılığı sürecinde ne yazık ki hep tek başıma kaldım. Bu doğrultuda başlattığım onlarca proje ya daha doğduğunda ya da bitişine çok az kala, tek kişi olmanın verdiği motivasyonsuzluk ve ekip ruhunun vermesi gerektiği sinerjinin yokluğu yüzünden ölü projeler sayfalarına girdi. Ancak sanırım artık şu sıralar bu durum değişecek gibi. 2 hafta önce tanıştığım Emre Tınaztepe ve bugün bloguna denk geldiğim Kutalmis arkadaşlarım ülkemizdeki bu hiç doğma şansı bile yakalamamış Sistem Programcılığı konusunda hala umudum olması gerektiğini hatırlattı. Kendilerine blogum vasıtası ile çalışmalarında başarılar der, fırsatı doğduğunda birlikte güzel projeleri hayata geçirebilecek ortamlarda bulunmayı dilerim.

6 Ekim 2009 Salı

Hepinizi Koruycam! Ama Kendimi Nasıl Koruycam?

Bir yazılım düşünün! Hedef kitlesi antivirüsler'in dahi baş edemediği zararlıları yakalamak ve engellemek. İşinde de, gayet iyi gidiyor ki zaman geçtikçe müşteri yelpazesi genişliyor. Update update üstüne sürekli yeni güncellemeler ve ek özelliklerle kullanıcılarını hoşnut etmesinide biliyor. Bir gün biri çıkıp sistemleri dolayısı ile de kullanıcıları koruması gereken bu sistemin, kendini koruyamadığını ve uzman c coder'larının daha bir window'u handle edememelerinden dolayı, korumakla yükümlü oldukları tüm sistemin korumasız kaldığını buluyor. Hikayede burada başlıyor!

Öncelikle şunu belirteyim tartışmalar http://blog.zemana.com/2009/09/guncelleme-zaman.html adresinde yayınlanan bir bildirim yüzünden başladı. Kendi yazılımlarında ki açıkları affetmeyen!!! ve anında yamayan!!! Zemana ekibi ve çok değerli arkadaşları büyük bir operasyonla!! ilgili açığı kapatıp yeni bir versiyon yayınlıyorlar. Yukarıdaki hikayede yer alan arkadaşta kendi kendine "Halbuki bende tam 4 ay önce kritik bir açık bildirdim ve de bypass filan da değil doğrudan sistemi koruması gereken uygulamanın kendisini etkisiz kılıyorum, lakin neden bundan hiç bahsedilmiyor?" diye düşünüp haklı olarak aynı konu başlığı altına gidip sitemlerini bildiriyor. Kıyamette ondan sonra kopuyor. Buyurun gidin konuyu ve tartışmaları okuyun. Bana açığı önce onlara bildirmediğimden dem vuruyorlar. Yazık! diyorum ve işinin uzmanı!!! arkadaşa kendi blogunda ki şu linke bakıp utanmasını istiyorum: Açığın yayınlanma çabaları . Sizin Error Report mekanizmanız çalışmıyorsa veya bildirimlere bakmıyorsanız suç benim mi oluyor?

Üstelik sanki onlar adına çalışan Analyst'mişim gibi, bana: "niye ifşa ediyorsun" diye kızıyorlar. Lütfen beyler biraz işinizin ehli ciddi insanlar olun. Birde kalkmış güvenlik uygulaması yazıyoruz diyorsunuz! Şu güvenlik piyasasın da 1 veya 10 sene olsun, çalışan insanlar gayet iyi bilir ve görürler ki açıklar 2 yönlü şekilde yayınlanır ve üreticinin derhal çözüm bulması tetiklenmiş olur. Tabi sizden bahsetmiyorum sayın Zemana üyeleri. Bu tartışmalar yaşanmamış olsaydı kim bilir daha ne kadar duracaktı o zaafiyet yerinde! Bir de Zemana güvenlikçisi Erkan bey'in "global takibimizde AntiLogger'a herhangi bir virus veya spyware tarafindan bu tarzda bir saldiri yoktur olay sadece PoC'tur." demesine halen gülüyorum. Mantığa bakarmısınız lütfen :) Demek ki aslında açık bildirilmeden önce bir malware yazmamız gerekiyormuş. Kim bilir belkide o zaman bu yazılımı kullanıp kendini güvende hisseden binlerce bedbaht insanın her türlü loglanabilecek bilgisine sahip olup saygıdeğer yazılım firmamızın cümle aleme rezil olmasını seyretmek daha etik olurdu. Yazık diyorum başkada söz bulamıyorum.

Ciddi ciddi düşünüyorum sektör neden böyle yozlaşmış diye? Ntvmsnbc'nin gerek görsel gerek yazılı ve sanal basında cafcaflıya cafcaflıya duyurduğu Sipru adlı multimedia uygulamasında tüm sistemi köle yapan açık bulduk bildirdik üstüne hakaret yedik! Microsoftun tüm işletim sistemleri dahil Command Prompt (cmd.exe) unda policy açığı bulduk raporladık aradan 4 sene geçti açığı kapatan olmadı!Yine Microsoftun Domain Password Distrubited mekanizmasında açık bulduk yayınladık yine aynı. Bu saygıdeğer Zemanacı'lara 4 ay önce açık bildiriyoruz, bizimki sanki kritik bir açık değilmiş gibi arkadaşımızın "reg add" ile eklediği startup bypass'ını ballandıra ballandıra kapatıp ilan ediyorlar bizim açık hala yerinde. Sitemim işte bu yaklaşıma dır. Bir de son anda tartışmaya katılan ve yazdığım PoC koduna bakıp C bilgimi ortaya çıkaran Hayri bey'ide ayrıca Oscar'a aday göstermek istiyorum! 4 ay öncesinden itibaren sürekli üstüne basa basa söylediğim gibi ardı üstü bir window'a Wm_Close message'i gönderiyoruz sayın Hayri, ne bekliyodunuz yani yalandan yere kodun opcode çıktısını alıp onu shellcode haline getirip öylemi yapsaydım? Emin olun hava atmak isteseydim öyle yapardım ve koda bakanlarda vay anasını derdi. Açın bakın milw0rm ü securityfocus'u o gördüğünüz exploit kodlarının en az yarısı bu tip kodlardan oluşuyor. Neyse Hayri Bey'imizi o engin C bilgisine sahip coder'ları ile başbaşa bırakalım.

Bu tartışmadan hemen sonra 2 DoS birde Bypass açığı buldum ama yeni versiyonlarını bekliyorum çünkü şu an hali hazırda bulmuş olduğum tüm açıklara aynı sebepten .ok atacaklarını iyi biliyorum ve o zaman ne kadar sağlam!!! ve kendi güvenliklerine önem veren bir firma olduklarını hepinizin göreceğini garanti ediyorum. Beni ve onları takip etmeye lütfen devam edin.
Şimdilik kalın sağlıcakla.

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

26 Haziran 2009 Cuma

Benmi geç kaldım! Yoksa birileri fazlamı uyanık?

Bilgisayar teknolojilerinin gelişimi ile birlikte iyi ve kötünün yararlı ve zararlının da savaşı siber alemde başlamış oldu. Donanımlar ve İşletim sistemleri gelişip yaygınlaştıkça, bunları suistimal edip kendi çıkarlarına kullanmaya çalışanların sayısında doğru orantılı bir artış oldu. Tabi tepkisel olarakda aynı düzlemde bu zararlılara karşı bir çok önlem alındı.

Özellikle 90'lı yıllardan sonra büyüme trendi maksimuma çıkan ve internet'in de yaygınlaşması ile artık önü bir türlü alınamayan bilgi hırsızlığı problemi altın çağını yaşamakta. Her zaman bir adım önde olan zararlı üreticileri, kendilerini egale etmeye çalışan onlarca orta ve büyük ölçekli sistem savunma firmalarına her defasında çalım atmaktalar. Tek bir coder'in yazdığı zararlının peşinden koşan bu büyük abiler günlerce uğraşmalarına rağmen çoğu zaman çaresiz kalmaktadırlar. Şu an hepinizin anımsayacağı bu büyük Güvenlik firmaları onlarca çalışanı ve ar-ge çalışmaları ile her yeni gün savaşta bir adım daha önde olabilmek için gayret göstermekteler. Ancak bugune değin hiç bir zaman kendilerinden zararlılara karşı kökten çözüm vaadi ve kendilerini kusursuz bir savunma sistemi imiş gibi beyan ettiklerini görmedim. Çünkü böyle bir söylem işletim sistemini üretenlere bile gerçekçi gelmiyorken bu sektörde yer alan orta halli bir kullanıcıya dahi komik gelecektir.

Ancak her ne hikmettirki uzun zamandır takip edemediğim ancak son 1 haftadır "dur bakalım neler yeni" edası ile göz atarken Türk Sistem!!! yazılımcılarının geliştirdiklerini iddaa ettikleri koruma yazılımlarından bir çoğu bu safsata ile kendilerini sektöre lanse eder olmuş. Bu beyanatlar çok dikkatimi çekmiş olacak ki bu ürünlerden en iddaalı olan üçünü sistemime kurdum ve tipik zararlı mantığı ile önce düşmanı yok et hedefini gözeterek yaptığım defeat&inject testleri ile kendilerini test ettim. Sonuçmu? Home 3:0 Away

Kendi Processlerinin açıklarını yamamayan bu yazılımlar bizi nasıl koruyacak! Açıkcası şayet bu aşamayı geçselerdi vaadettikleri koruma modüllerini deneme hevesim olacaktı.


Zaten x64 bit işlemciler sayesinde x64 Windows os'lerin desteklediği KPP sistemi ile artık kernel rootkitlerinden kurtuluyor gibi görünüyoruz. Bu vesile ile AV üreticilerinde neden tedirgin olup Microsoft ile savaşa tutuştuklarınıda anlamış oluyoruz sanırım. System Service Table'i hook edip bu yolla kernel mode'da cirit atma devri uzun bir müddet sekteye uğrayacak gibi ve bu yüzden teknolojilerinin belini bu mode'a bağlayanları epeyce üzeceğe benziyor.

Hepiniz sağlıcakla kalın.

24 Haziran 2009 Çarşamba

Sistemi kimler programlar

Yaklaşık 12 senelik programcılık hayatımın en verimli evrelerini bundan 3-4 sene önce yaşamıştım ve birikimlerimden doğan bir kaç yazı kaleme almıştım. Merak edenler olabilir diye linklerini paylaşmak istedim.

Bu linklerde yer alan Windows için Sistem Programcılığı serisi'ne ait bilgiler ile umuyorumki sizler için karanlık kalan bir çok nokta aydınlanacak ve o karanlık delhiz sanılan düşük seviyeli programlama fobinizden de kurtulmuş olacaksınız. Ne yazık ki ülkemiz os ve işlemciler için mimarisel anlamda programlama yapmaktan çok uzak. Tüm bilinen kaynakların yabancı dillerde olması ve konun profesyonel derecede programlama alt yapısı gerektirmesinden dolayı bu iş insanların gözünde dahada büyüyor. Sizleri aşağıda linkini verdiğim adresteki makaleleri okumaya davet ediyor ve en kısa zamanda örnek çalışmalarınızı yine aynı platformda paylaşmanızı istiyorum.

Sistem Programcılığı Serisi

23 Haziran 2009 Salı

Zemana AntiLogger ve Güvenlik!

Makale tadında bir şeyler yazmaktan ve karalamaktan nefret ederim ancak yazmaya başladığımda sanki hiç bitmeyecek bir romanı yazıyormuşum gibi olur ve kendimi durduramam.


Bir blog açma fikrini bile ancak boş bir vaktimde "dur bakalım bide bunu deneyelim atraksiyon olsun" tadına denk gelen anlarımdan birinde hayata geçirdim. O yüzden şimdiden size güzel bir haber: her gün yazıp sizlerin kafasını ütülemeyeceğim ve sadece gerçekten bilgilendirmeye değer gördüğüm durumları sizlerle paylaşmak için bana ayrılan bandwidth hakkımı kullanacağım.

Sizlere , 1-2 ay önce hiç birini hayata geçirmediğim yüzlerce projemden herhangi biri ile ilgilendiğim bir vakitte izlediğim bir video sayesinde varlığından haberdar olduğum Zemana firmasının geliştirmiş olduğu AntiLogger yazılımından bahsetmek istiyorum.


Her ne kadar kısa bir süreç içerisinde, yalnızca çalışma mantığı ve güvenlik zaafiyetleri üzerine göz atmış olsamda şahsi kanaatim uzun vadede geleceği parlak ve güzel bir uygulama olacağı yönünde. Programı burada tanıtıp advertorial kuşağına girmek istemediğimden sizlere sadece üreticisinin adresini vermekle yetiniyorum http://www.zemana.com/tr/default.aspx .

Evet siteye girip programın açıklamalarını okuduğunuzu ve download edip kullanarak ne işe yaradığını - neleri vaadettiğini - gelişim evrelerini ve işleyiş süreçlerini kavradığınızı düşünerek yazıma devam ediyorum.

Zemana AntiLogger'la ilk olarak sanırım 1.8.x.x versiyonu ile tanıştım ki zaten kullandığım süreç içerisinde sadece 5 adet patch yayınlandı. Bu makaleyi yazdığım sırada son versiyonu 1.9.2.104'dü ve yaklaşık 2 haftadır yeni bir patch yayınlanmadı. Sanırım üretici ya mevsim şartları gereği iş temposunu düşürerek istrahata çekildi ya da çok daha stabil versiyon için harıl harıl çalışıyor. Dileğim ikinci ihtimalin olması yönünde. Tanıyanlar bilirler yapım gereği elime geçen bir sistem veya programı kullanmak yerine çalışma mantığını ve bundan elde ettiğim verilerle güvenlik zaafiyetlerini bulmaktan hoşlanırım. Bu en büyük hobilerim arasında yer alıyor. Bu nedenlede AntiLogger'la tanışmam sonrası süreç aynı düzlemde ilerledi.

Programı sistemime ilk kurduğumda hali ile vaad edilen koruma yeteneklerinin gerçekliğini test ettim ve tatmin edici buldum. Daha önceden userland için kodladığım bir çok code injection, keylogger ve screen capture'ı başarı ile tespit edip engellemişti. Antilogger vaad ettiği koruma testlerinden başarı ile geçmişti ancak kendini koruyabiliyormuydu? İlk işlem olarak newbee seviyesindeki bir attacker mantığı üzerinden hareketle işlem sonlandırma girişiminde bulundum ve sonuç Access Denied'dı. Antilogger kendine yöneltilen tüm sonlandırma isteklerini ret ediyordu. Bu iyiye işaretti, böylece zararlıların ilk yaptığı iş olan "düşmanı egale etme" girişimi de zararlı için hüsranla sonuçlanıyordu. Testlerim devam ediyor ve tüm parametreler Zemana için iyiye işaret ediyordu.

İkinci test günümde yine AntiLogger'a kendi yazdığım ve çok bilinen 12 process terminate yöntemi ile saldırmayı denedim ve fonksiyonlarımın tümü "FALSE" değeri ile döndü. Ancak tam o esnada AntiLogger'in penceresini görünür yaptım ve mouse'umu üzerine doğru getiriyordum ki birden AntiLogger'in error trap mekanizması ekranda beliriverdi ve sunduğu seçeneklerden herhangi birini seçtikten sonra kendini sonlandırarak sistemi koruma görevinden vazgeçti. Sanırım bir zaafiyet bulmuştuk ve error reporting den aldığımız ip uçları ile de problemin program içerisinde nerede, hangi şartlar altında olduğu ve probleme neyin sebep olduğunu bulmak ve PoC yazmak artık çok kolay olacaktı.

Zayıflık programın tüm child pencerelerine WM_CLOSE veya SC_CLOSE mesajının gönderilmesi ve akabinde TfrmMain parent window'una bağlı controller'dan TfrmVistaButton sınıfının Borland Vcl kütüphanelerinde kullanılan ve başa bela olması ile de bi aralar bayağı meşhur olan TTimer nesnesinin UpdateTimer prosedürü içerisinde kullanılan FWindowHandle handle'ini zaten bir önceki mesajla kapatılmış olan window handle'ı ile işlemeye çalışmasından kaynaklanıyor. Aslında TTimer nesnesinin hafıza yönetimi baştan beri hep programcıların canını sıkmıştır ve buradada kendini gösteriyor.

Açık kısaca yukarıda tanımlandığı gibi işliyor ve AntiLogger'in işleyişini error trap mekanizmasına iletiyor. Bu esnada AntiLogger arka planda hizmet vermeye devam ediyor ancak aynı mesajı ikinci kez gönderdiğinizde artık tümü ile kendini sonlandırıp sizi terk ediyor. Bu kadar tanımdan sonra sanırım Zemana Yazılım ekibi çok kısa bir sürede bu açığıda kapatacaklar ve daha stabil bir sürümle bizleri sevindirecekler. Bu bahse son vermeden öncede örnek olması açısından http://rapidshare.de/files/48444246/KillWindows.rar.html adresindeki basit PoC'u Zemana AntiLogger yüklü os'niz de deneyebilirsiniz. Ben testlerimi Xp Sp2+Sp3 üzerinde yaptığımdan Vista ve Windows 7 üzerindeki User32.dll:SetTimer fonksiyonun bu hataya karşı gerçekleştireceği tepkiyi şu an için bilemiyorum. Test edip sonuçlarını bana yazarsanız onunda üstesinden gelen birşeyler yapabiliriz.

Makalenin bundan sonrası AntiLogger ve türevi yazılımların çalışma prensipleri ve işlevsellikerini nasıl sağladıkları üzerine olacaktır.Amacım sizlere İşlemci ve OS mimarisini anlatmak değil ama bazı kavramları anlamanız, makalenin ilerleyen kısımlarındaki terimelere yabancılık çekmemeniz için şart.

İşletim sistemleri sağladıkları yetenekleri tüm sistem,kullanıcı ve uyguluma geliştirme programcılarına - bütünleşik, hızlı, esnek ve güvenilir olarak sunmalıdırlar. Bilindiği üzere ve konu mankeni olarak kullanacağımız işletim sistemi ailesi Windows olduğundan bu işletim sistemi mimarisel olarak iki katmandan oluşur (UserMode-KernelMode). Bu katmanlar birbirlerinden soyutsal olarak ayrıdır ve bu ayırım işletim sisteminin bütünlüğünü kendi içinde koruması ve daha stabil olarak yönetmesi için gereklidir. UserMode katmanı donanımdan tümü ile soyutlanmıştır. Yani bu modda çalışan hiç bir process doğrudan diske yazamaz, okuyamaz, herhangi bir porta erişemez, hafıza alanlarına müdahelede bulunamaz ve bunun gibi daha bir çok yetenekten uzaktır. Yukarıda saydığımız tüm işlemleri yapabilecek olan yer KernelMode katmanıdır.

İşte bu aşamada gerek işlemci üreticilerinin sağladıkları yetenekler sayesinde olsun, gerekse OS içerisinde yer alan ve işlemcinin usermode ve kernelmode arabuluculuğunu yapan komutunu kullanarak güvenli ve hızlı bir iletişimi sağlayan yapısal yetenekleri olsun tümü ile bütünleşik bir yapı ile karşı karşıya kalırız. Intel ailesi komut setlerinden olan SysEnter Amd ailesi işlemcilerinde yer alan SysCall çağrıları az önce bahsettiğimiz çevrimleri bizler için çok hızlı ve güvenilir bir şekilde gerçekleştirir. Burada şöyle bir senaryo ile konun daha iyi ve net anlaşılmasını sağlayalım:

Herhangi bir dille Win32 api'lerini kullanarak dosya okuma işlemi gerçekleştirdiğinizi varsayalım. Bunu kernel32.dll altında ReadFile api'si ni kullanarak yaparsınız. Dilerseiniz programınızı yazıp gerekli parametreleri ile derledikten sonra çalıştırdığınızda neler olduğuna bakalım.

1-ReadFile çağrısı çalıştığında öncelikle programınız içerisindeki iat'den dosya okuma işlemi api'si için hangi işletim sistemi dosyasının çalışması gerektiği bilgisi alınır ve bu normal şartlarda (hooksuz) kernel32.dll:ReadFile api'sini gösterir. İşlemci eip yazmacı artık kernel32.dll içerisindeki ReadFile apisini fonksyion kodlarının bulunduğu alanı işaret eder.

2 - Kernel32.dll:ReadFile api'si bazı denetimleri yaptıktan sonra süreci ntdll.dll içerisinde yer alan ZwReadFile native api'sine devreder ve burada bir kaç denetim işleminden sonra ReadFile işleminin KernelMode tarafında asıl işlemerini gerçekleştirecek koduna dallanması için işletim sistemi tarafından kendine verilmiş olan ServiceID'sini ve parametreleride içeren stack registeri ile birlikte az önce yukarıda bahsettiğim ve işlemciye göre değişen mode çevrim komutunu çalıştırır.

3-Intel işlemcisi için konuşursak Sysenter çağrısı sonrası usermode da yer alan ntdll.dll içerisinden serviceID si ve parametreleri belirtilmiş değerler artık kernelmode tarafındadırlar. Kernelmode az öncede bahsettiğimiz üzere doğrudan hafıza ve donanıma erişim yetkisi bulunan bir yerdir ve bu yüzden de yukarıdaki ilk 2 adımda belirtilen denetim mekanizmalarından geçen veriler bu seviyeye ulaşabilmelidirler. Aksi takdirde sistemin güvenliği ve stabilitesi tehlikeye atılmış olunur.

Güncel microsoft ailesi işletim sistemleri UserMode dan gelen fonksiyonlar için KernelMode tarafında sysenter (amd'de syscall)komutundan gelen ServiceID numarasına göre çalışacak olan fonksiyonun gerçek adresini tutan ve adına Service Descriptor Table denen bir tablo bulunur.
Bu tablo yardımı ile usermode dan gelen serviceID'ye uygun gerçek fonksiyon adresi bulunur ve buraya dallanılır.

İşte dananın kuyruğunun koptuğu noktada burada devreye girer. Gerek zararlı rootkitler olsun, gerek sizi bu rootkitlerden koruyacağını idda eden savunma programları olsun 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 ilede 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) .

Daha fazla ayrıntı ve teknik detaya girerek kafaları karıştırmak istemiyorum. Son söz olarak yukarıda Zemana AntiLogger'in sonlanmasına neden olan işlemden sonra \\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 Zemanın bir dahaki reboota kadar yeniden başlasada etkisiz kalmasını sağlayabilir veya doğrudan bir kernel rootkit yazarak Zemana'nın tümü ile etkisiz kalmasını sağlayabilirsiniz.

Son söz olarak Zemana AntiLogger gerçekten geleceği parlak ve güzel bir yazılım ve umarım gelişimi KPP engeline takılmadan Microsftun New Api desteği adını verdiği yeni framework ile çalışıp şu anda hizmet veremedeği x64 ailesi işlemci ve os desteğinide vermesi ile daha da iyi bir şekilde sürer.

Hepiniz bir dahaki entry'me kadar sağlıcakla kalın.

İbrahim Akgül
bilgislem@hotmail.com