Merhabalar;
Yine bir “kırarken yaz” tutorial ile karşınızdayım. Bir önceki tutoriala gösterdiğiniz ilgi için teşekkürler. Başlayalım:
Programı açtık. Deneme kullanıcı adı şifremizi yazıyoruz.
Name:errorinside
Key:12345678-abcdef09
“Kötü çocuk” mesajını gördük. Ollyde ilgili yere bakıp geliyoruz aşağıdaki koda
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
401489 PUSH EBP 40148A MOV EBP,ESP 40148C AND ESP,FFFFFFF0 40148F SUB ESP,20 401492 CALL [C]_keyg.00401C00 401497 JMP [C]_keyg.004015E8 40149C /CALL [C]_keyg.004015FF 4014A1 |MOV DWORD PTR SS:[ESP],[C]_keyg.0040B064 "Color 1A" 4014A8 |CALL <JMP.&msvcrt.system> \system 4014AD |MOV DWORD PTR SS:[ESP],[C]_keyg.0040B070 "*************************** [C] keygen me #1 by x0rz ***************************" 4014B4 |CALL [C]_keyg.00401460 4014B9 |MOV DWORD PTR SS:[ESP],[C]_keyg.0040B0C1 "Name: " 4014C0 |CALL [C]_keyg.00401460 4014C5 |MOV DWORD PTR SS:[ESP+4],[C]_keyg.0040EA40 4014CD |MOV DWORD PTR SS:[ESP],[C]_keyg.0040B0C8 4014D4 |CALL <JMP.&msvcrt.scanf> 4014D9 |MOV DWORD PTR SS:[ESP],[C]_keyg.0040EA40 4014E0 |CALL <JMP.&msvcrt.strlen> 4014E5 |MOV DWORD PTR SS:[ESP+1C],EAX 4014E9 |MOV EAX,DWORD PTR SS:[ESP+1C] 4014ED |MOV DWORD PTR SS:[ESP],EAX 4014F0 |CALL [C]_keyg.00401614 ;İlk kısmı yaratan algoritma 4014F5 |MOV EAX,DWORD PTR SS:[ESP+1C] 4014F9 |MOV DWORD PTR SS:[ESP+8],EAX 4014FD |MOV DWORD PTR SS:[ESP+4],[C]_keyg.0040EA40 401505 |MOV DWORD PTR SS:[ESP],[C]_keyg.0040EA7C 40150C |CALL <JMP.&msvcrt.strncpy> 401511 |MOV EAX,DWORD PTR SS:[ESP+1C] 401515 |ADD EAX,[C]_keyg.0040EA40 40151A |MOV BYTE PTR DS:[EAX],2D ;2D = "-" araya tire ekleniyor 40151D |MOV DWORD PTR SS:[ESP],[C]_keyg.0040EA40 401524 |CALL <JMP.&msvcrt.strlen> 401529 |MOV DWORD PTR SS:[ESP+18],EAX 40152D |MOV EAX,DWORD PTR SS:[ESP+18] 401531 |MOV DWORD PTR SS:[ESP],EAX 401534 |CALL [C]_keyg.00401696 ;İkinci kısmı yaratan algoritma 401539 |MOV DWORD PTR SS:[ESP],[C]_keyg.0040B0CB "Key: " 401540 |CALL [C]_keyg.00401460 401545 |MOV DWORD PTR SS:[ESP+4],[C]_keyg.0040EA7D 40154D |MOV DWORD PTR SS:[ESP],[C]_keyg.0040B0C8 401554 |CALL <JMP.&msvcrt.scanf> 401559 |MOV DWORD PTR SS:[ESP+4],[C]_keyg.0040EA40 401561 |MOV DWORD PTR SS:[ESP],[C]_keyg.0040EA7D 401568 |CALL <JMP.&msvcrt.strcmp> 40156D |TEST EAX,EAX ;tam istediğim mesaj üzerinde bir test ;) 40156F |JNZ SHORT [C]_keyg.0040158E ;eşit değilse hataya zıpla 401571 |MOV DWORD PTR SS:[ESP],[C]_keyg.0040B0D4 ;"Dogru Key Girdin Helal Sana :)\n" 401578 |CALL [C]_keyg.00401460 40157D |CALL <JMP.&msvcrt._getch> 401582 |MOV DWORD PTR DS:[40E020],1 40158C |JMP SHORT [C]_keyg.004015F8 40158E |MOV DWORD PTR SS:[ESP+8],3C 401596 |MOV DWORD PTR SS:[ESP+4],0 40159E |MOV DWORD PTR SS:[ESP],[C]_keyg.0040EA40 4015A5 |CALL <JMP.&msvcrt.memset> 4015AA |MOV DWORD PTR SS:[ESP],[C]_keyg.0040B0F4 "Yanlis oldu galiba :(\n\n" 4015B1 |CALL [C]_keyg.00401460 4015B6 |MOV DWORD PTR SS:[ESP],[C]_keyg.0040B10C "Tekrar denemek ister misin? (E/H)\n" 4015BD |CALL [C]_keyg.00401460 4015C2 |LEA EAX,DWORD PTR SS:[ESP+17] 4015C6 |MOV DWORD PTR SS:[ESP+4],EAX 4015CA |MOV DWORD PTR SS:[ESP],[C]_keyg.0040B12F 4015D1 |CALL <JMP.&msvcrt.scanf> 4015D6 |MOVZX EAX,BYTE PTR SS:[ESP+17] 4015DB |CMP AL,45 4015DD |JE SHORT [C]_keyg.004015E8 4015DF |MOVZX EAX,BYTE PTR SS:[ESP+17] 4015E4 |CMP AL,65 4015E6 |JNZ SHORT [C]_keyg.004015F7 4015E8 MOV EAX,DWORD PTR DS:[40E020] 4015ED |TEST EAX,EAX 4015EF \JE [C]_keyg.0040149C 4015F5 JMP SHORT [C]_keyg.004015F8 4015F7 NOP 4015F8 MOV EAX,0 4015FD LEAVE 4015FE RETN |
40156D adresine bir BP koydum. Tekrar aynı şekilde kullanıcı adı ve şifremizi girelim. Stack’e bakıyorum
ECX 0040EA40 ASCII “PKKGIXGIXVV-JZZXFNXFNKK”
EDX 0040EA7E ASCII “2345678-abcdef09”
ecx ‘te bir şeyler görüyoruz. şimdi tekrar deniyoruz. bu sefer:
name:errorinside
key:PKKGIXGIXVV-JZZXFNXFNKK
Hmm.. Gerekli keyi bulduk. Ama amacımız keygen yazmak. Şimdi algoritmayı bulalım ve çözelim. Girilen kullanıcı adını scanf ile okuyor, strlen ile uzunluğunu alıyor ve biraz daha aşağıda ilk call adresinini 401614 olduğunu görüyoruz. Şimdi burayı inceleyelim.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
401614/$ PUSH EBP 401615|. MOV EBP,ESP 401617|. SUB ESP,10 40161A|. MOV [LOCAL.1],0 401621|. JMP SHORT [C]_keyg.0040168B 401623|> /MOV EAX,[LOCAL.1] 401626|. |ADD EAX,[C]_keyg.0040EA40 ;Kullanıcı adını buradan(40EA40) al eaxa yaz 40162B|. |MOVZX EAX,BYTE PTR DS:[EAX] 40162E|. |MOVSX EAX,AL 401631|. |MOV [LOCAL.2],EAX ;Kullanıcı adının "i"nci karakterini al LOCAL.2'ye yaz 401634|. |SAR [LOCAL.2],1 ;SAR 1 uygula 401637|. |MOVZX EAX,BYTE PTR DS:[40EA42] ;Kullanıcı adının 3üncü karakterini al 40163E|. |MOVSX EAX,AL ; 401641|. |MOV [LOCAL.3],EAX ;LOCAL.3'e yaz 401644|. |SHL [LOCAL.3],1 ;SHL 1 uygula 401647|. |MOV EAX,[LOCAL.3] ;Sonucu eax a yaz 40164A|. |ADD EAX,0A ;eax'a A ekle 40164D|. |XOR [LOCAL.2],EAX ;LOCAL.2 ile eax XOR la 401650|. |JMP SHORT [C]_keyg.00401656 ;zıpla 401652|> |/ADD [LOCAL.2],10 ;bundan sonrasını aşağıda ayrıntılı anlattım 401656|> | CMP [LOCAL.2],2F 40165A|.^|\JLE SHORT [C]_keyg.00401652 40165C|. |JMP SHORT [C]_keyg.00401662 40165E|> |/SUB [LOCAL.2],14 401662|> | CMP [LOCAL.2],5A 401666|.^|\JG SHORT [C]_keyg.0040165E 401668|. |CMP [LOCAL.2],39 40166C|. |JLE SHORT [C]_keyg.00401678 40166E|. |CMP [LOCAL.2],40 401672|. |JG SHORT [C]_keyg.00401678 401674|. |ADD [LOCAL.2],0C 401678|> |MOV EAX,[LOCAL.2] 40167B|. |MOV EDX,EAX 40167D|. |MOV EAX,[LOCAL.1] 401680|. |ADD EAX,[C]_keyg.0040EA40 401685|. |MOV BYTE PTR DS:[EAX],DL 401687|. |ADD [LOCAL.1],1 ;iterasyonu 1 arttır 40168B|> MOV EAX,[LOCAL.1] 40168E|. |CMP EAX,[ARG.1] 401691|.^\JL SHORT [C]_keyg.00401623 401693|. NOP 401694|. LEAVE 401695\. RETN |
Yukarıdaki döngüyü açıklayalım. Öncelikle 3 tane LOCAL değişken var bunlar
LOCAL.1: Kullanıcı adı karakter sayısı kadar olan iterasyon sayısı döngünün “i” si diyelim
LOCAL.2: Kullanıcı adının “i”nci karakteri(ve onun işlem görmüş hali)
LOCAL.3: Kullanıcı adının 3üncü karakteri(ve 3üncü karakterden sonrasında işlem görmüş hali)
1) Kullanıcı adının “i”nci karakterini al
2) SAR 1 uygula
3) Kullanıcı adının 3üncü karakterini al
4) SHL 1 uygula ve sonucu 0xA ile topla
5) İşlem görmüş “i”nci karakter ile işlem görmüş 3üncü karakteri XOR la
6) Sonuç 2F mi?
6. a) Küçük eşitse +10 yap, ta ki 0x2F ten büyük olana kadar
6. b) Büyükse 401662ye zıpla
7) Yeni sonuç 0x5A mı?
7. a) Büyükse -14 yap, ta ki 0x5A’dan küçük olana kadar
7. b) Küçükse devam
8) Yeni sonuç 39 mu?
8. a) Küçük eşitse i+1 yap döngüyü başa sar
8. b) Büyükse devam
9) Yeni Sonuç 40 mı?
9. a) Büyükse i+1 yap döngüyü başa sar
9. b) 40’sa +0xC yap; i+1 yap döngüyü başa sar
evet bu kadar basit :P
(itiraf ediyorum bu döngüyü çözdükten sonra yazdım çünkü sonlara doğru sürekli bir “cmp” ve koşullu jump söz konusuydu. komut komut anlatmak daha fazla kafa karıştıracağı için en sonda algoritma şeması kullanmayı tercih ettim. Umarım anlaşılacaktır)
Kullanıcı adı kadar döngü tekrarladıktan sonra oluşan yeni anahtarı göreceksiniz.
Bu döngü bittikten sonra ana fonksiyona dönüp araya “-” ekleniyor ve 00401696 adresindeki ikinci kısmı yaratan algoritma başlıyor. İnceleyelim:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
401696/$ PUSH EBP 401697|. MOV EBP,ESP 401699|. SUB ESP,10 40169C|. MOV [LOCAL.1],0 4016A3|. JMP SHORT [C]_keyg.0040170F 4016A5|> /MOV EAX,[LOCAL.1] 4016A8|. |ADD EAX,[C]_keyg.0040EA7C 4016AD|. |MOVZX EAX,BYTE PTR DS:[EAX] 4016B0|. |MOVSX EAX,AL 4016B3|. |MOV [LOCAL.2],EAX 4016B6|. |SAR [LOCAL.2],1 4016B9|. |MOVZX EAX,BYTE PTR DS:[40EA7E] 4016C0|. |MOVSX EAX,AL 4016C3|. |MOV [LOCAL.3],EAX 4016C6|. |SHL [LOCAL.3],1 4016C9|. |MOV EAX,[LOCAL.3] 4016CC|. |ADD EAX,0B 4016CF|. |XOR [LOCAL.2],EAX 4016D2|. |JMP SHORT [C]_keyg.004016D8 4016D4|> |/ADD [LOCAL.2],0D 4016D8|> | CMP [LOCAL.2],2F 4016DC|.^|\JLE SHORT [C]_keyg.004016D4 4016DE|. |JMP SHORT [C]_keyg.004016E4 4016E0|> |/SUB [LOCAL.2],15 4016E4|> | CMP [LOCAL.2],5A 4016E8|.^|\JG SHORT [C]_keyg.004016E0 4016EA|. |CMP [LOCAL.2],39 4016EE|. |JLE SHORT [C]_keyg.004016FA 4016F0|. |CMP [LOCAL.2],40 4016F4|. |JG SHORT [C]_keyg.004016FA 4016F6|. |ADD [LOCAL.2],0B 4016FA|> |MOV EDX,[ARG.1] 4016FD|. |MOV EAX,[LOCAL.1] 401700|. |ADD EAX,EDX 401702|. |MOV EDX,[LOCAL.2] 401705|. |MOV BYTE PTR DS:[EAX+40EA40],DL 40170B|. |ADD [LOCAL.1],1 40170F|> MOV EAX,[ARG.1] 401712|. |SUB EAX,1 401715|. |CMP EAX,[LOCAL.1] 401718|.^\JG SHORT [C]_keyg.004016A5 40171A|. NOP 40171B|. LEAVE 40171C\. RETN |
Yukarıdaki döngüyü açıklayalım. Öncelikle 3 tane LOCAL değişken var bunlar
LOCAL.1: İlk algoritmada üretilen anahtarın karakter sayısı kadar olan iterasyon sayısı döngünün “i” si diyelim
LOCAL.2: İlk algoritmada üretilen anahtarın “i”nci karakteri(ve onun işlem görmüş hali)
LOCAL.3: İlk algoritmada üretilen anahtarın 3üncü karakteri(ve 3ncü karakterden sonrasında işlem görmüş hali)
1) İlk algoritmada üretilen anahtarın “i”nci karakterini al
2) SAR 1 uygula
3) İlk algoritmada üretilen anahtarın 3üncü karakterini al
4) SHL 1 uygula ve sonucu B ile topla
5) İşlem görmüş “i”nci karakter ile işlem görmüş 3üncü karakteri XOR la
6) Sonuç 0x2F mi?
6. a)Küçük eşitse +0xD yap, ta ki 2F ten büyük olana kadar
6. b) Büyükse 4016E4e zıpa
7) Yeni sonuç 0x5A mı?
7. a) Büyükse -15 yap, ta ki 5A’dan küçük olana kadar
7. b) Küçükse devam
8) Yeni sonuç 39 mu?
8. a) Küçük eşitse i+1 yap döngüyü başa sar
8. b) Büyükse devam
9) Yeni Sonuç 40 mı?
9. a) Büyükse i+1 yap döngüyü başa sar
9. b) 40’sa +B yap; i+1 yap döngüyü başa sar
Gördüğünüz gibi ilk algoritmanın neredeyse aynı sadece ufak sayı değişiklikleri var. bu yüzden kod yanına açıklama eklemedim bu sefer.
Bu tutorialda algoritmayı çok açık yazdığım için şimdi direkt keygen yazma bölümüne geçiyorum. Keygene ait kaynak kodları yazının ekinde bulacaksanız.
Keygen 3 karakterden kısa kullanıcı adı girdiğinizde “patlıyor”. Bunu düzeltmek de “ödeviniz” olsun :)
Kolay gelsin.
[dm]161[/dm]
Comments of this post
d36f
16 July 2018
Ellerinize sağlık.