Level : newbie
Cracking and finding the name to serial algorithm in Chainie1 Crackme
This is my first crackme tutorial: I wrote it to try and help other real newbies like me to better understand the simple basics of cracking. Although this is supposed to be a very simple crackme I found it quite hard to understand what was really going on and very nearly fell into a little trap of thinking I had found the name to serial algorithm too soon.
Tools: PeID, OllyDbg 1.10 and a pencil and paper
Well where do we begin? First I check the Chainie.exe with PeID. We see that this crackme is not packed and was created with Borland Delphi 6.0 7.0 so hopefully we wont have any nasty surprises like anti-debug or other tricks.
Ok lets have a look at our target; double click Chainie.exe and a dialog box asking for a name and a serial will appear.
Enter name LucyE and enter serial 47806 and press Check.
Bam a message box appears saying, Your name is too short
Press OK and close Chainie.exe. Then right click on Chainie.exe and open with Olly.
In Olly right click and select Search for all referenced text strings. You will see this:
Text strings referenced in Chainie: CODE
Address Disassembly Text string
0045012F ASCII "Unit1"
004501F5 PUSH Chainie.0045027C ASCII "Correct"
004501FA PUSH Chainie.00450284 ASCII "Good job you did it!!!"
00450213 PUSH Chainie.0045029C ASCII "WRONG!!!"
00450218 PUSH Chainie.004502A8 ASCII "Incorrect Serial try again...." (2)
0045022F PUSH 10 (Initial CPU selection)
00450231 PUSH Chainie.004502C8 ASCII "Oops...
00450236 PUSH Chainie.004502D0 ASCII "Your name is too short" (1)
I didnt want to guess how long may name should be so I decided to double click on (1) and see if I could fix this problem first and then come back and double click on (2) to see what I could see and learn from that.
After double clicking we land here at place marked (1)
0045022F > 6A 10 PUSH 10 ί---------------------------- ; Entry point to MessageBox function
00450231 . 68 C8024500 PUSH Chainie.004502C8 ; ASCII "Oops.."
(1) 00450236 68 D0024500 PUSH Chainie.004502D0 ; ASCII "Your name is too short" 0045023B . A1 D43B4500 MOV EAX, DWORD PTR DS:[453BD4]
00450240 . E8 EF58FEFF CALL Chainie.00435B34
00450245 . 50 PUSH EAX ; |hOwner = NULL
00450246 . E8 5562FBFF CALL ; MessageBoxA
0045024B > 33C0 XOR EAX, EAX
To find out where the check that called this function right click on the entry point at 0045022F and select Go to JLE from 0045017C and we land here:
00450179 83F8 05 CMP EAX, 5 ; is name length less than 6 letters?
0045017C 0F8E AD000000 JLE Chainie.0045022F If yes then Jump to Bad Name
There are probably many ways to fix this name check like NOP the JLE, but I like the idea of entering a name so I will patch this by changing the 5 to 1. This means that your name must have more than 2 letters to be valid. We do this by clicking on the location 00450179 pressing the Space bar, change the 5 to 1, then choose assemble followed by cancel. The code will now look like this:
00450179 83F8 01 CMP EAX, 1
0045017C 0F8E AD000000 JLE Chainie.0045022F
Now the name length check has been patched our next job is to find the correct serial for our name.
Looking at the code snippet below we see that at 004501F1 there is a check which if we fail we go to the Good job you did it!!! message. This tells me that there is a check for a valid serial in the Call on the line above that returns with a non-zero value if our serial is valid. Therefore, put a breakpoint (press F2) on the Call at 004501EC and Press F9 to run the crackme. Enter LucyE for the name and 47806 as the serial then Check to find out if the serial we entered is legitimate.
004501EC . E8 2B40FBFF CALL Chainie.0040421C ί----------we break here
004501F1 . 75 1E JNZ SHORT Chainie.00450211
004501F3 . 6A 30 PUSH 30
004501F5 . 68 7C024500 PUSH Chainie.0045027C ; ASCII "Correct"
004501FA . 68 84024500 PUSH Chainie.00450284 ; ASCII "Good job you did it!!!"
004501FF . A1 D43B4500 MOV EAX, DWORD PTR DS:[453BD4]
00450204 . E8 2B59FEFF CALL Chainie.00435B34
00450209 . 50 PUSH EAX ; |hOwner = 00E924E8
0045020A . E8 9162FBFF CALL ; MessageBoxA
0045020F . EB 3A JMP SHORT Chainie.0045024B
Hey look at the memory dump (stack) what do you see?
0012F604 00E924E8 ASCII "48706" ; the serial we entered
0012F608 0012F968 Pointer to next SEH record
0012F60C 0045026E SE handler
0012F618 00428FD0 Chainie.00428FD0
0012F620 00E924FC ASCII "3443972" ; maybe a valid serial
0012F624 00E924E8 ASCII "48706" ; the serial we entered
0012F628 00E924D4 ASCII "LucyE"
0012F62C 00E924C0 ASCII "LucyE" ; the name we entered
0012F630 00E924AC ASCII "LucyE"
Lets be brave and remove our breakpoint then hit F9 to run Chainie.exe.
After clicking OK at the Incorrect serial try again message enter this number (3443972) as the serial and press check. BINGO! We cracked it!
Our next job is to find out how this programme calculates the serial for our name.
Press Alt-E to view the Executable Modules then right click on Chanie.exe and select view names. Scroll down the list a bit and double click on the LoadStringA API then press F2 to set a breakpoint on the line highlighted in Olly at 00450152. Run Chainie.exe and press check; we break in Olly at 00450152.
00450152 . 55 PUSH EBP ί----------------------- We Break Here
00450153 . 68 6E024500 PUSH Chainie.0045026E
00450158 . 64:FF30 PUSH DWORD PTR FS:[EAX]
0045015B . 64:8920 MOV DWORD PTR FS:[EAX],ESP
0045015E . BB DBC10800 MOV EBX, 8C1DB
00450163 . 8D55 F8 LEA EDX, DWORD PTR SS:[EBP-8]
00450166 . 8B87 08030000 MOV EAX, DWORD PTR DS:[EDI+308]
0045016C . E8 E7F1FDFF CALL Chainie.0042F358
00450171 . 8B45 F8 MOV EAX, DWORD PTR SS:[EBP-8] ; name put in location EBP-8
00450174 . E8 573FFBFF CALL Chainie.004040D0 ; Length of Name = 5
00450179 83F8 05 CMP EAX, 5
Trace through the code with F8 but STOP when you reach the Call at 0045C01E3. I have commented the code to try and explain how our name is converted into a hex number.
00450182 . 8D55 F4 LEA EDX, DWORD PTR SS: [EBP-C]
00450185 . 8B87 08030000 MOV EAX, DWORD PTR DS: [EDI+308]
0045018B . E8 C8F1FDFF CALL Chainie.0042F358
00450190 . 8B45 F4 MOV EAX, DWORD PTR SS:[EBP-C] ; Name (LucyE)
00450193 . E8 383FFBFF CALL Chainie.004040D0
00450198 . 8BF0 MOV ESI, EAX ; Length of Name = 5
0045019A . 85F6 TEST ESI, ESI
0045019C . 7E 2E JLE SHORT Chainie.004501CC
0045019E . C745 FC 01000> MOV DWORD PTR SS:[EBP-4],1
004501A5 > 8D55 F0 LEA EDX,DWORD PTR SS:[EBP-10]
004501A8 . 8B87 08030000 MOV EAX, DWORD PTR DS:[EDI+308]
004501AE . E8 A5F1FDFF CALL Chainie.0042F358
004501B3 . 8B45 F0 MOV EAX, DWORD PTR SS:[EBP-10] ; Name in EAX (LucyE)
004501B6 . 8B55 FC MOV EDX, DWORD PTR SS:[EBP-4] ; 1 in EDX
004501B9 . 0FB64410 FF MOVZX EAX, BYTE PTR DS:[EAX+EDX-1] ; letter into EAX
004501BE . 03D8 ADD EBX, EAX ; Add letter to EBX (init EBX=8C1DB)
004501C0 . 81C3 DBC10800 ADD EBX, 8C1DB ; Add 8C1DB to EBX
004501C6 . FF45 FC INC DWORD PTR SS: [EBP-4] ; inc ss: [EBP-4] to get next letter
004501C9 . 4E DEC ESI ; Decrease name counter by 1
004501CA . ^ 75 D9 JNZ SHORT Chainie.004501A5 ; Get next letter until none left
004501CC > 8D55 EC LEA EDX, DWORD PTR SS:[EBP-14]
004501CF . 8B87 10030000 MOV EAX, DWORD PTR DS:[EDI+310]
004501D5 . E8 7EF1FDFF CALL Chainie.0042F358
004501DA . 8B45 EC MOV EAX, DWORD PTR SS:[EBP-14] ; Serial we entered
004501DD . 50 PUSH EAX ; Notice both serial and name entered are on the stack
004501DE . 8D55 E8 LEA EDX, DWORD PTR SS:[EBP-18]
004501E1 . 8BC3 MOV EAX, EBX ; result of manipulating our name in EAX
004501E3 . E8 6879FBFF CALL Chainie.00407B50 ; STOP HERE
The name LucyE is converted by the above code as follows:
L u c y E
Make a note or remember that EAX = 00348D04
You might think that this is the end of the name to serial algorithm but its not! So we will now continue from where we stopped above by pressing F7 to trace into the Call at 004501E3 until we reach here:
00407B04 /$ 08C9 OR CL, CL if result is not zero
00407B06 | 75 17 JNZ SHORT Chainie.00407B1F then Jump
00407B08 | 09C0 OR EAX, EAX if result is not signed
00407B0A | 79 0E JNS SHORT Chainie.00407B1A then Jump
.If both above checks fail algorithm is completed in this section .
00407B0C | F7D8 NEG EAX makes value in EAX positive
00407B0E | E8 07000000 CALL Chainie.00407B1A
00407B13 | B0 2D MOV AL, 2D
00407B15 | 41 INC ECX
00407B16 | 4E DEC ESI
00407B17 | 8806 MOV BYTE PTR DS: [ESI], AL ; adds value in AL to our serial
00407B19 | C3 RETN
.. Second part of algorithm
00407B1A |$ B9 0A000000 MOV ECX,0A ; Put the divisor x0A (10) in ECX
00407B1F |> 52 PUSH EDX
00407B20 | 56 PUSH ESI
00407B21 |> 31D2 /XOR EDX,EDX ; Zero EDX
00407B23 | F7F1 |DIV ECX ; Divide EAX by 0A Result in EAX remainder in EDX
00407B25 | 4E |DEC ESI ; Make room for next number of correct Serial
00407B26 | 80C2 30 |ADD DL, 30 ; Add 30 to low byte in EDX
00407B29 | 80FA 3A |CMP DL, 3A ; if DL is less than 3A
00407B2C | 72 03 |JB SHORT Chainie.00407B31 ; then Jump
00407B2E | 80C2 07 |ADD DL, 7
00407B31 |> 8816 |MOV BYTE PTR DS:[ESI],DL ; the correct serial is built here
00407B33 | 09C0 |OR EAX, EAX
00407B35 |^ 75 EA JNZ SHORT Chainie.00407B21 ; Get next number until EAX is zero
00407B37 | 59 POP ECX ; Chainie.00407B60
00407B38 | 5A POP EDX ; Chainie.00407B60
00407B39 | 29F1 SUB ECX, ESI ; the length of the correct serial
00407B3B | 29CA SUB EDX, ECX ; if EDX is bigger than ECX
00407B3D | 76 10 JBE SHORT Chainie.00407B4F ; then Jump
00407B3F | 01D1 ADD ECX, EDX
00407B41 | B0 30 MOV AL, 30
00407B43 | 29D6 SUB ESI, EDX ; Length of serial
00407B45 | EB 03 JMP SHORT Chainie.00407B4A
00407B47 |> 880432 /MOV BYTE PTR DS:[EDX+ESI],AL
00407B4A > 4A DEC EDX
00407B4B |^ 75 FA JNZ SHORT Chainie.00407B47 ; loop until EDX is zero
00407B4D | 8806 MOV BYTE PTR DS:[ESI],AL ; add AL i.e. 30 to our serial
00407B4F > C3 RETN
STOP pressing F7 when you reach RETN at 0407BF4 and note that ESI=3443972
Do you remember the number calculated from our name in the first part of the algorithm and do you recall where it was stored? Yes EAX = 348D04. Well to calculate the real valid serial this number is divided step by step by 0A at location 00407B23 until EAX is zero.
At each step the remainder of this integer division, if it is less than 0A (i.e. a single digit), is stored in ESI.
If the remainder is greater than 0A then 07 is added to DL before it is stored as a single digit in ESI.
If you recollect the serial for LucyE, was 344392. So in my case the first remainder was 2, the second 9, the third 3 and so on.
Press F8 seven times and look at the stack, at the bottom right of your screen you will see what we saw earlier, the name we entered, the serial we entered and the correct serial computed from our name. Also note that EDX = 3443972
So what have we learned?
1. How to check if a target is packed
2. How to patch a name length check
4 How to fish for a valid serial
5. How to find and understand the code that converts our name into a valid serial
6. Go slowly and keep our eye on what is happening with the registers and what is showing in the memory dump.
Although all the information to make a keygen is revealed I am not advanced enough to be able to make one but hope that someone will take the time and trouble to make a tutorial on how this can be done.
Well I have finished and it has taken me nearly 2 days to crack Chainie1 and write this little tutorial which I hope you like and will find helpful.