Cracking and finding the name to serial algorithm in Chainie1 Crackme

Sunday, July 09 2006 @ 04:28 PM CEST

Contributed by: LucyE

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 newbie’s 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 won’t have any nasty surprises like anti-debug or other tricks.

Ok let’s 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 didn’t 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

0012F610 0012F638

0012F614 0012F7B4

0012F618 00428FD0 Chainie.00428FD0

0012F61C 00E936A8

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"

0012F634 00000006

Let’s 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

8C1DB+4C+8C1DB+75+8C1DB+63+8C1DB+79+8C1DB+45+8C1DB= 348D04

Make a note or remember that EAX = 00348D04

You might think that this is the end of the name to serial algorithm but it’s 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.

Regards LucyE