"Crackme #2" |
| |
| |
|
Araçlar:
|
| |
Bu crackme yi ilk olarak mesaj tahtasındaki arkadaşlara sormuştum.Bu yazıyı yazdığım tarih itibariyle çözen olmadı.Bu yazıyla size yeni bir pencere açmayı umuyorum.Umarım faydalı olur.
| |
Crackme yi dissamble edersek daha fazla bilgi edinmememiz mümkün.Ben dissambler olarak IDA yı kullanıyorum.IDA ile dissamble ederken bilmediğiniz sabitler varsa mesela push 0F0000000h gibi.O sabitin üstüne gelip use standard symbolic constant ı seçin ve size mantıklı olan değeri seçin.Böylelikle dissambler çıktısı çok daha anlaşılır olucaktır.
Programın Register tuşuna bastığımızda şu olaylar oluyor.
.text:00401151 push dword_4033BD ; hWnd .text:00401157 push [ebp+hDlg] .text:0040115A call Level2 ;ben IDA da ismini değiştirdim .text:0040115F test eax, eax .text:00401161 jnz short @serialdogru .text:00401163 push 0 .text:00401165 push offset aBadSerial .text:0040116A push offset aTryAgain .text:0040116F push 0 .text:00401171 call MessageBoxA .text:00401176 leave .text:00401177 retn 10h .text:0040117A ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ .text:0040117A .text:0040117A @serialdogru: .text:0040117A push 0 .text:0040117C push offset aAferin .text:00401181 push offset Text .text:00401186 push 0 .text:00401188 call MessageBoxA
* Bundan böyle ben dissamble çıktısında bazı yerlerin ismini değiştiricem fakat yan tarafta adresi de verdiğimden takip etmeniz yine kolay olucak
Şimdi Level2 fonksiyonunu inceliyelim.
.text:00401240 Level2 proc near ; CODE XREF: DialogFunc+10Ep
.text:00401240
.text:00401240 szSerial = byte ptr -20h
.text:00401240 hWnd = dword ptr 0Ch
.text:00401240
.text:00401240 push ebp
.text:00401241 mov ebp, esp
.text:00401243 add esp, 0FFFFFFE0h ;stackı düzenle 0FFFFFFE0h =-20h
.text:00401246 push 82h
.text:0040124B lea eax, [ebp+szSerial]
.text:0040124E push eax
.text:0040124F push [ebp+hWnd]
.text:00401252 call GetWindowTextA
.text:00401257 cmp eax, 15h ;21 karakter
.text:0040125A jnz short @hata ;o zaman hatalı
.text:0040125C push 0
.text:0040125E push offset szBuffer
.text:00401263 lea eax, [ebp+szSerial]
.text:00401266 push eax
.text:00401267 call CryptFunction ;serialin MD5 hashini al
.text:0040126C push offset a958aef7ca43503 ;sabit değer
.text:00401271 push offset szBuffer ; serialin MD5 hash'i
.text:00401276 call lstrcmpA ;karşılaştır
.text:0040127B test eax, eax ;eşit değilse hata
.text:0040127D jnz short @hata
.text:0040127F xor eax, eax ;eax=0
.text:00401281 inc eax ;eşitse program kayıtlı eax=1
.text:00401282 leave
.text:00401283 retn 8
.text:00401286 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
.text:00401286
.text:00401286 @hata: ; CODE XREF: Level2+1Aj
.text:00401286 ; Level2+3Dj
.text:00401286 xor eax, eax ;eax =0
.text:00401288 leave
.text:00401289 retn 8
.text:00401289 Level2 endp
MD5 bir hash fonksiyonu.Hash fonskiyonları verilen herhangi bir uzunluktaki bilginin n-bit olaraka çıktısını verir.Bu n 128,160 olabilir.Bu fonksiyonların amacı bir datayı temsil etmektir.Bu fonksiyonlar hızlı olduklarından ve hash den orjinal data ya ulaşmak zor hatta imkansız olduğndan veri kontrolü ve veri aramasında da kullanılırlar.Mesela siz 200 karakterli iki tane dosyanın aynı olup olmadığını kontrol için ikisinin de Hash'ini alırsınız ve kontrol edersiniz.Hash ler aynı ise dosyalarda aynıdır.Bu fonksiyonlar tek yollu fonksiyondur.Yani girilen veriden Hash e ulaşmak çok basittir fakat hangi girdinin bir hash değerine eşit olduğunu bulmak zor hatta imkansızır.
Yukarıdaki fonksiyon 21 karakterli bir serial istiyor ve bunun MD5 hash i eğer 958AEF7CA43503C94E74246E03CC74EC değerine eşitse program seriali kabul ediyor.Yukarı da belirttiğim gibi bunu bulmak çok zor.Bilinen yol 21 karakterli bütün kombinasyonları denemek ki inannın bana bu çok uzun bir süre.Peki ben sizlere çözülemez bir crackme mi sordum.
Keh keh hiç birşey göründüğü gibi değil crackmeyi tekrar inceliyoruz.Programın about kısmında ne diyor Bunu başarmak için cıstacklı bir müzik dinleyin.Bu ipucunu mesaj tahtasından birisi anladı bende tırstım o mesajı kapadım.Sonunda ödül var ne de olsa :)
Şimdi stack da neyin nesidir falan diyebilirsiniz.Ben şimdi size uzun bunun teknik açıklamasını yapmak istemiyorum.Buna ne yer ne de benim bilgim müsade ediyor.Bir değer push edildiğinde esp azaltılır ve değer buraya yazılır.Bir değer pop edildiğinde is esp artırılır.Ayrıca stacktan birşey pop edildiğinde pop edilen değere en son push edilen değer yazılır.Mesela bir örnekle açıklıyalım.esp = 650000 olsun
push 555 ;555 650000-4 e yazılacak esp = 650000-4 push 777 ;777 650000-8 e yazılacak esp = 650000-8 pop eax ;eax a esp deki yani 777 yazılacak esp = 650000-8+4 pop ebx ;ebx e esp deki yani 55 yazılacak esp = 650000-8+4+4
Ayrıca call fonksiyonu çağrıldığında geriye dönülecek adres [esp] nin gösterdiği yere yapılır.Şimdi bu kadar açıklamadan sonra Level2 fonksiyonuna tekrar geri gönüyoruz.add esp, 0FFFFFFE0h satırı local bir değişken kullanmak için 20h lık bir yer açıyor.Yani biz kendimize esp nin gerisinde bir yer açıyoruz.Bu bölgenin yeri esp in olduğu yere ve kullanıcağımız büyüklüğe göre değişyor.Yani program serial için sadece 20h yani 32 karakterlik bir local tampon oluşturmuş.Ayrıca GetWindowText apisi dikkat ederseniz 32 karakterlik local yer olmaısna rağmen 82h=130 karakterlik text almaya göre ayarlanmış.Peki eğer biz 32 karakteri aşarsak ne olur.Buffer overflow!
Kih kih.Ben 21 karakterden olmıyan seriallerle ilgilenmediğim için kimse tabii ki bunu hiç düşünmedi.Herkes hash fonksiyonu ile ilgilendi bruteforce felan diye kendilerini heba ettiler.SwordFish ve Conspiracy Theory i hatırlayın.Hiç birşey göründüğü gibi değil.Free your mind Neo :) Şimdi crackme yi açalım ve 40 tane A yazalım ve Ne demiştik bir call yapıldığında dönüş adresi esp ye yazılır.Eğer biz 32 karakteri aşarsak yazdığımız 33. karakter stackı bozmaya başlar.Bizim istediğimiz öyle bir serial yazalım ki callın döneceği adres doğru serial mesajı olsun.Peki kaç karaktere ihtiyacımız var.32 karakter lokal tampon için 4 karakter ilk yapılan push ebp için ve 4 karakter de zıplıycağımız adres için.40 tane A yazın ve Register butonuna tıklayın.Karşınıza şu güzel hata mesajı gelecektir.
CRACKME2 caused an invalid page fault in moduleat 0084:41414141. Registers: EAX=00000000 CS=0167 EIP=41414141 EFLGS=00010246 EBX=0063fb98 SS=016f ESP=0063fb44 EBP=41414141 ECX=80007d00 DS=016f ESI=00008bbc FS=1137 EDX=80007cf8 ES=016f EDI=0063fb4c GS=0000 Bytes at CS:EIP: Stack dump: 0063fb64 bff7363b 000009f4 00000111 000003e9 00000a00 8b961147 0000016f 0063fb78 bff94407 3daf8bbc 00003daf 00000000 bff719b8 00008bb6 0063ff68
Heh heh.Gördüğünüz gibi EIP i yönlendirmeyi başardık(41h=A).Şimdi yapacağımız iş çok basit.40 hanelik bir serial girmek -ilk 36 hanesi hiç önemli değil- ve 4 karaktere patch ediceğimiz adresi yazmak.Crackme yi inclerseniz eğer program 0040117A adresine dönerse programın kayıtlı olcağını görürsünüz.Şimdi serial olarak bizim 36 karakter ve bu adresin ASCII karşılığını yazmamız lazım.Fakat unutmayın bizim tersten yazmamız lazım yani 7A114000.Sondaki sıfırı yazmamız imkansız.Fakat eğer 39 karakter yazarsak GetWindowText fonksiyonu en son sıfırı zaten kendisinden ekliyor.Seviyorum arada sırada şu Bill amcayı.7A1140 = z@ .Ortadaki karakter 11h a tekabül ediyor.Bunu yazmak içinbir hex editör kullanabilirsiniz.Sonuçta çalışan serial şu şekilde olucaktır.
123456789012345678901234567890123456z@
Hih hih.Gördüğünüz gibi 1 den fazla doğru serial var çünkü ilk 36 karakteri sadece stack ı bozmak için kullanıyoruz.Ters çevrilmeyen bir fonksiyondan trilyonlarca katrilyonlarca - 40 haneli sayılara ne denir bilmiyorum ama :) -doğru seriale ulaştık.
Bu buffer overflow gerçekten çok önemli bir konu.Benden tecrübeli ve bilgi arkadaşlar bilirler, etrafta gördüğümüz bir sürü exploit bu sayede yazılıyor.İlk başta bir taşma noktası buluyoursun.Daha sonra bir shellcode(yani size giriş hakkı verecek küçük birkod mesela bir porta bağlanan command.com) u taşan bölgeye yazıp kontrolü oraya devrediyorsunuz.Shellcode yazımı okadar da kolay birşey değil kullandığınız opcodelarda 00 olmaması gerekiyor bildiğiniz üzere 00 stringlerin bölen birşey.O yüzden shellcode yazarken ya 00 olmayn opcodelar kullanılır yahutta orata çıkan kod 00 lardan arındırılacak şekilde bir fonksiyona sokulur.Bu konu hakkında yazılmış etrafta bir sürü yazı var ama Phrack ın bir saysında geçen Smashing the stack for fun and profit yazısı oldukça bilgilendirici.Ayrıca Türkçe yazılmış çok kapsamlı bir yazı daha var.Bu yazıyı da şiddetle okumanızı tavsiye ediyorum.Buffer Overflow`lar hakkında (c) Murat Balaban
Şimdi burda beylik bir söz söylemem lazım ne de olsa kitleleri peşimden koştuyorum.Milyonlarca müridime derim ki;
Bazen yanlış cevap cevabın ta kendisidir.
Oldu oldu süper oldu.Hep beraber çağ atladık sevgili okuyucalarım.
ps:Ben cıstak mıstak anlamam diyorsanız diğer geçerli serial de benbirkucukkeloglanim :)
| |
Böö!