Όταν γράφτηκα στην 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=0×0A, και στην συνέχεια το υπόλοιπο της idiv γίνεται xor με τον αριθμό της θέσης του χαρακτήρα μέσα στο string (σίγουρα πολλοί προγραμματιστές έχουν χρησιμοποιήσει την θέση του χαρακτήρα, χωρίς όμως να γνωρίζουν ότι είναι πολύ απλός σε assembly) και προσθέτει το 2. Αν το αποτέλεσμα είναι > 10 τότε αφαιρεί το 10.
πχ. Για τον χαρακτήρα K έχουμε 0×4B = 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) μέχρι την διεύθυνση 0×47D και δημιούργησα μία άλλη εφαρμογή χωρίς nag screen.
Αν θέλετε να πειραματιστείτε με το project κατεβάστε το εκτελέσιμο απο εδώ.
Reverse Engineering
assembly, cracking, Reverse Engineering