Archive

Posts Tagged ‘cracking’

Η ιστορία ενός cracking

January 14th, 2009

Όταν γράφτηκα στην REA και κατέβασα το πρώτο crack project (είχε 4 κατηγορίες από projects) , είχα ένα μήνα μπροστά μου για να βρω την λύση. Αν περνούσε αυτό το διάστημα δεν θα μπορούσα να συνεχίσω, οπότε η πρόκληση ήταν μεγάλη. Έπρεπε λοιπόν σε αυτό το διάστημα να βρω τα εργαλεία (debugger, disassembler, hex editor κτλ)  και να μάθω πως θα τα χρησιμοποιήσω όλα αυτά μαζί. Νέα εμπειρία για ένα προγραμματιστή.

Έτσι το πρώτο εργαλείο που έπεσε στα χέρια μου, ήταν ο Win32Dasm, οι παλιοί θα τον γνωρίζουν. Τώρα βέβαια τον έχω αντικαταστήσει με τον OllyDbg, που τον θεωρώ καλύτερο. Πάντως ο Win32Dasm για απλά project τα καταφέρνει καλά (για περισσότερα cracking εργαλεία δείτε εδώ).

Η πρώτη αποστολή ήταν ένα πρόγραμμα το splish.exe το οποίο εμφανίζει ένα nag screen και στην συνέχεια έχει μια φόρμα με πεδία για pass phases. Αυτό που έπρεπε να κάνω ήταν να μην εμφανίζετε το splash screen και να βρω τα pass phases.

Η αποστολή είχε 3 sections:

A hardcoded Serial

Το πρώτο βήμα πάντα είναι να εκτελέσουμε την εφαρμογή για να δούμε τι εμφανίζει ώστε να αναλύσουμε τον τρόπο που θα κινηθούμε. Έτσι και εγώ εκτέλεσα τον πρόγραμμα και πάτησα το κουμπί “Check Hardcoded”. Ένα message box με το κείμενο “Sorry, please try again” εμφανίστηκε στην οθόνη.

Έτσι σκέφτηκα να ψάξω να βρω το κείμενο μέσα στον Win32Dasm. Βρήκα 2 διευθύνσεις που είχε το κείμενο.

A)

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:00401386(C)

|

:004013D2 6A00                    push 00000000

* Possible StringData Ref from Data Obj ->”Splish, Splash”

|

:004013D4 680A304000              push 0040300A

* Possible StringData Ref from Data Obj ->”Sorry, please try again.”

|

:004013D9 6867304000              push 00403067

:004013DE 6A00                    push 00000000

* Reference To: USER32.MessageBoxA, Ord:01BBh

|

:004013E0 E863030000              Call 00401748

B)

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:004016C8(C)

|

:004016E2 6A00                    push 00000000

* Possible StringData Ref from Data Obj ->”Splish, Splash”

|

:004016E4 680A304000              push 0040300A

* Possible StringData Ref from Data Obj ->”Sorry, please try again.”

|

:004016E9 6867304000              push 00403067

:004016EE 6A00                    push 00000000

* Reference To: USER32.MessageBoxA, Ord:01BBh

|

:004016F0 E853000000              Call 00401748

Έβαλα ένα breakpoint στο πρώτο reference “004013D9″,έτρεξα την εφαρμογή και πάτησα το κουμπί “Check Hardcoded” και η εκτέλεση σταμάτησε.

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:0040138A(U)

|

:0040137B 803800                 cmp byte ptr [eax], 00

:0040137E 740C                    je 0040138C

:00401380 8A08                    mov cl, byte ptr [eax]

:00401382 8A13                    mov dl, byte ptr [ebx]

:00401384 38D1                    cmp cl, dl

:00401386 754A                    jne 004013D2

:00401388 40                      inc eax

:00401389 43                      inc ebx

:0040138A EBEF                    jmp 0040137B

Η κλήση του message box έγινε από την διεύθυνση 00401386. Έτσι πήγα εκεί να δω τον κώδικα. Είχε την εντολή “jne 004013D2″ για την εντολή “cmp cl, dl”, μάλλον ένας έλεγχος χαρακτήρα-χαρακτήρα “byte ptr [eax]” & “byte ptr [ebx]“, προηγούμενες εντολές. Είδα στην μνήμη τι περιέχουν και ανακάλυψα ότι η μία είχε αυτό που πληκτρολόγησα ενώ η άλλη πιθανών τον σωστό password. Έτσι λοιπόν πήγα στην διεύθυνση μνήμης της μεταβλητής για να δω τι περιέχει. Οπότε στην θέση 401353 βρήκα το κείμενο “HardCoded”. Ξαναέτρεξα την εφαρμογή και έβαλα αυτό το password, εμφανίστηκε το μήνυμα “Congratulations, you got the hard coded serial”.

A simple serial-protection

Με παρόμοιο τρόπο, γεμίζουμε τα πεδία με ένα όνομα και ένα serial. Εγώ έβαλα “Kostas” και “1″ και πάτησα το κουμπί να δω τι θα γίνει. Εμφανίστηκε το ίδιο μήνυμα λάθους “Sorry, please try again.”. Έτσι αμέσως κατάλαβα ότι είναι η 2η αναφορά στο message box που βρήκα προηγουμένως. Έβαλα ένα break point στην διεύθυνση “004016E9″ και ξαναδοκίμασα με τα ίδια δεδομένα. Γενικά αυτή είναι η ποιο απλή μεθοδολογία για να ψαρέψεις ένα password. Ο debugger σταμάτησε πριν εμφανιστεί το message box. Βρήκα την διεύθυνση απ’ όπου είχε έρθει 004016C8.Πηγά εκεί και βρήκα την εντολή “jne 004016E2″ για την εντολή “cmp eax, ecx”

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:0040167C(U)

|

:004016A8 8D354D324000            lea esi, dword ptr [0040324D]

:004016AE 8D3D58324000            lea edi, dword ptr [00403258]

:004016B4 33DB                    xor ebx, ebx

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:004016CB(U)

|

:004016B6 3B1D63344000            cmp ebx, dword ptr [00403463]

:004016BC 740F                    je 004016CD

:004016BE 0FBE041F                movsx eax, byte ptr [edi+ebx]

:004016C2 0FBE0C1E                movsx ecx, byte ptr [esi+ebx]

:004016C6 3BC1                    cmp eax, ecx

:004016C8 7518                    jne 004016E2

:004016CA 43                      inc ebx

:004016CB EBE9                    jmp 004016B6

Μάλλον και εδώ έχουμε έλεγχο string και σίγουρα έχουν σχέση τα κείμενα που έχω δώσει στα πεδία. Πήγα στην “0040167C” που είναι reference από compare και βρήκα τα παρακάτω:

* Reference To: USER32.GetWindowTextA, Ord:015Bh

|

:0040160D E818010000              Call 0040172A

:00401612 85C0                    test eax, eax

:00401614 7468                    je 0040167E

:00401616 A363344000              mov dword ptr [00403463], eax

:0040161B 33C9                    xor ecx, ecx

:0040161D 33DB                    xor ebx, ebx

:0040161F 33D2                    xor edx, edx

:00401621 8D3536324000            lea esi, dword ptr [00403236]

:00401627 8D3D58324000            lea edi, dword ptr [00403258]

:0040162D B90A000000              mov ecx, 0000000A

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:00401650(C)

|

:00401632 0FBE041E                movsx eax, byte ptr [esi+ebx]

:00401636 99                      cdq

:00401637 F7F9                    idiv ecx

:00401639 33D3                    xor edx, ebx

:0040163B 83C202                  add edx, 00000002

:0040163E 80FA0A                  cmp dl, 0A

:00401641 7C03                    jl 00401646

:00401643 80EA0A                  sub dl, 0A

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:00401641(C)

|

:00401646 88141F                  mov byte ptr [edi+ebx], dl

:00401649 43                      inc ebx

:0040164A 3B1D63344000            cmp ebx, dword ptr [00403463]

:00401650 75E0                    jne 00401632

:00401652 33C9                    xor ecx, ecx

:00401654 33DB                    xor ebx, ebx

:00401656 33D2                    xor edx, edx

:00401658 8D3542324000            lea esi, dword ptr [00403242]

:0040165E 8D3D4D324000            lea edi, dword ptr [0040324D]

:00401664 B90A000000              mov ecx, 0000000A

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:0040167A(C)

|

:00401669 0FBE041E                movsx eax, byte ptr [esi+ebx]

:0040166D 99                      cdq

:0040166E F7F9                    idiv ecx

:00401670 88141F                  mov byte ptr [edi+ebx], dl

:00401673 43                      inc ebx

:00401674 3B1D67344000            cmp ebx, dword ptr [00403467]

:0040167A 75ED                    jne 00401669

:0040167C EB2A                    jmp 004016A8

Εδώ έχουμε πολύ κώδικα. Ξέχασα να αναφέρω ξεσκόνισα ότι βιβλίο είχα για assembly από την σχολή μου, γιατί είχα ξεχάσει όλες τις εντολές και τους καταχωρητές του επεξεργαστή.

Μετά από πολύ μελέτη πάνω στον κώδικα έφτασα στο συμπέρασμα ότι έχουμε ένα decoded name το οποίο φτιάχνει το σωστό serial (00401632-00401650).

Ο αλγόριθμος είναι κάπως έτσι: για κάθε χαρακτήρα του ονόματος χρησιμοποιεί την cdq εντολή, idiv με ecx=0x0A, και στην συνέχεια το υπόλοιπο της idiv γίνεται xor με τον αριθμό της θέσης του χαρακτήρα μέσα στο string (σίγουρα πολλοί προγραμματιστές έχουν χρησιμοποιήσει την θέση του χαρακτήρα, χωρίς όμως να γνωρίζουν ότι είναι πολύ απλός σε assembly) και προσθέτει το 2. Αν το αποτέλεσμα είναι > 10 τότε αφαιρεί το 10.

πχ. Για τον χαρακτήρα K έχουμε 0x4B = 75 MOD 10 = 5 XOR 0 = 5 + 2 = 7.

Με τον ίδιο αλγόριθμο για το κείμενο “Kostas” έχουμε serial “729752″, άλλα είναι αυτό το σωστό :(

Όχι γιατί έχουμε και decoded serial το οποίο δημιουργείτε εδώ (00401669-0040167A).

Η διαφορά με τον προηγούμενο αλγόριθμό είναι η εντολή “add edx,00000002″.

Έτσι τελικά το σωστό serial υπολογίζεται για κάθε αριθμό του προηγούμενου serial προσθέτοντας το  2 και αν είναι > 10 τότε αφαιρεί το 10.

Στο παράδειγμα μας έχουμε “941974″. :)

Τρέχουμε το πρόγραμμα (χωρίς debugger) βάζουμε το “Kostas”, serial “941974″,

και εμφανίζεται το μήνυμα “Good job, now key gen it”.

A Nag-Screen at startup

Πρώτα εκτελούμε τον debuger και προχωράμε βήμα-βήμα την εκτέλεση της εφαρμογής μέχρι να βρούμε που εμφανίζεται το nag screen.

* Reference To: USER32.GetSystemMetrics, Ord:0143h

|

:00401060 E8BF060000              Call 00401724

:00401065 50                      push eax

:00401066 FF3573344000           push dword ptr [00403473]

:0040106C E8F0030000              call 00401461

:00401071 A37B344000              mov dword ptr [0040347B], eax

:00401076 FF7508                  push [ebp+08]

:00401079 E8F9030000              call 00401477

:0040107E C745D030000000          mov [ebp-30], 00000030

:00401085 C745D403000000          mov [ebp-2C], 00000003

:0040108C C745D878114000          mov [ebp-28], 00401178

:00401093 C745DC00000000          mov [ebp-24], 00000000

:0040109A C745E000000000          mov [ebp-20], 00000000

:004010A1 FF7508                  push [ebp+08]

:004010A4 8F45E4                  pop [ebp-1C]

:004010A7 C745F010000000          mov [ebp-10], 00000010

:004010AE C745F400000000          mov [ebp-0C], 00000000

Στην εντολή “call 00401477″ ανοίγει το nag screen, έτσι αν προσπεράσουμε το “jmp to 0040107E” έχουμε βρει την λύση :)

Υπάρχουνε πολλές διαφορετικές λύσεις. Μία από αυτές είναι αντί για το “call 00401477″ να το αντικαταστήσουμε με το “jmp 0040107E”. Άλλη μία λύση είναι να αντικατασταθεί με 5 nop εντολές. Η nop εντολή είναι μια εντολή που έχει ο επεξεργαστής, ώστε να μην κάνει τίποτα.

Θα μου πείτε γιατί υπάρχει αφού δεν κάνει τίποτα, άλλα στον προγραμματισμό τα έχουμε συνηθίσει αυτά, null στην C, “ ” στην html, “none” στα css κτλ.

Για να πειράξουμε το αρχείο χρειαζόμαστε ένα hex editor, βρήκα έναν τον hexedit, άνοιξα τη εφαρμογή πήγα στην διεύθυνση 0×479 (αφού πρώτα έπρεπε να μάθω πως υπολογίζω την σχετική διεύθυνση από την θέση μνήμης στην θέση αρχείου και έβαλα 0×90 (nop) μέχρι την διεύθυνση 0x47D και δημιούργησα μία άλλη εφαρμογή χωρίς nag screen.

Αν θέλετε να πειραματιστείτε με το project κατεβάστε το εκτελέσιμο απο εδώ.

Reverse Engineering , ,