Learn to crack
by Ignatz

Number 3: slightly advanced Techniques (keygen) explained with Clipmate5

Welcome to my third tutorial.
I hope you enjoyed the last first two ones and whish to proceed in refining your skills. Why the title you might ask me. One step back two steps forth? Well I´ll explain in short words: Going back to the basics like in my first tutorial should only prepare us for the new things to come. Getting it back in mind why we are acting as we do and what cracking is about. IMOPORTANT: This tutorial is just for educational purpose! I do not want to support any illegal actions (you might take). If you do use the knowledge I offer you to take illigal actions, against my whish and my advice, problems are all yours. After the trial Version expired it´s BUY OR DIE for your Targetprogram! Buy it or delete it.

How to protect your products better visit:

go and learn

What we need:
1) Soft ICE
2) HView
3) W32Dasm
4) Clipmate 5.0, (the protection-scheme is the same in the higher versions 5.x)

For 1 - 3 visit:
CrackZ´s Tool Shop

For 4 visit:

Always use the best tools you can get your hand on!

Let´s get started:
First of all, we want to know what we want. This program uses a name-serial protection and since really we want to test our skills, let´s write a Keygenerator. What will we have to do in order to write a keygen? We will have to find A) the compare routine and B) the serial generation routine. After finding them, we have to reverse those them in order to fulfill our goal and put it in C or Pascal or Delphi or what ever you want code.

Always know what you want!

Start Clipmate and you will see a nice screen asking you if you´d like to regiser or begin your evaluation period. We want to register of course. So choose Enter Registration Key. After entering a fake key like Pirate Copy and 12345678 you get a nag screen 'This is an invalid Name/Number combination'. Perfect! Now make a copy from the .exe file and disassamble it with W32Dasm. Now search for the string we just encountered. searching for 'name/number' is enough. We even won´t find the whole string because it´s saved in two lines.

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:004F1FDB(C), :004F1FEC(C), :004F1FFD(C), :004F200E(C), :004F201F(C)
:004F2120 6A00                                push 00000000
:004F2122 668B0D68214F00           mov cx, word ptr [004F2168]
:004F2129 B201                                mov dl, 01

* Possible StringData Ref from Code Obj ->"This Is An Invalid Name/Number " \
                                                                   ->"Combination"                                  | string is parted so we won´t find it searching for the whole
:004F212B B8CC234F00                 mov eax, 004F23CC
:004F2130 E8677EF6FF                  call 00459F9C

Well this looks really neat. We have 5 jumps (:004F1FDB(C), :004F1FEC(C), :004F1FFD(C), :004F200E(C), :004F201F(C)) to the ebeggar off screen. So we could now try to change them and see if it would work. But we wanted to write a keygen and just finished the first part which was findingt the code for the compare. So we now take a closer look at the jumps.

:004F1FD3 E81075F1FF              call 004094E8
:004F1FD8 83F80D                  cmp eax, 0000000D
:004F1FDB 0F853F010000            jne 004F2120  --------------> no good
:004F1FE1 8D45F2                  lea eax, dword ptr [ebp-0E]
:004F1FE4 E8FF74F1FF              call 004094E8
:004F1FE9 83F80D                  cmp eax, 0000000D
:004F1FEC 0F852E010000            jne 004F2120  --------------> no good
:004F1FF2 A19C425000              mov eax, dword ptr [0050429C]
:004F1FF7 8A4003                  mov al, byte ptr [eax+03]
:004F1FFA 3A45F5                  cmp al, byte ptr [ebp-0B]
:004F1FFD 0F851D010000            jne 004F2120  --------------> no good
:004F2003 A19C425000              mov eax, dword ptr [0050429C]
:004F2008 8A400B                  mov al, byte ptr [eax+0B]
:004F200B 3A45FD                  cmp al, byte ptr [ebp-03]
:004F200E 0F850C010000            jne 004F2120  --------------> no good
:004F2014 A19C425000              mov eax, dword ptr [0050429C]
:004F2019 8A400C                  mov al, byte ptr [eax+0C]
:004F201C 3A45FE                  cmp al, byte ptr [ebp-02]
:004F201F 0F85FB000000            jne 004F2120  --------------> no good

* Possible StringData Ref from Code Obj ->"Software\Thornsoft\ClipMate5"  & bonus: we see where the name and serial are stored in the
                                                                                                                                registration. It´s in CURRENT_USER or
                                                                                                                                LOCAL_MACHINE + Software\Thornsoft\ClipMate5
                                                                                                                                let´s find out.
:004F2025 B914234F00              mov ecx, 004F2314

Now let´s find out more about the code with the help of SoftICE:

First, find the place of code you´re interested in, then analyze it. Don´t fool around, not knowing where you are in the code!

Return to Clipmate and start SoftICE to  enter a breakpoint like hmemcpy. Now try to register. Breaking into SoftICE we see step through whith F12 until we are in the program. there we set a breakpoint at the first call that would be :004F1FD3. We now disable the hmemcpy breakpoint and koncentrate on the things to come.
As we check on the registers we see, that eax contains our serial. So this must be some kind of serial-style check. As we continue we see that the result of the call, returned in eax is the length of the serial. It is compared with D (hex) which equals 13 (dec) Hence we know now, that our serial has to have a lenght of 13 characters. The second call does the same, but did you recognize the lea eax, dword ptr [ebp-0E]? This means that an other string is checked. ??? Which string? This is interesting because there should not be a second check or are we following a false trace. Entering SoftICE again to find out, we take a look at what stands in the [ebp-0E] register before the suspicious call and $ BINGO $ we see the real serial. The programmer also checks the real searial again. We should say big thanks to him. For now we also know, that the generation routine must be somewhere before this part of code. So we know where to look for it. Something more that should make s think is hidden in here. We would expect, that the compare of the serial begins with the first character, wouldn´t we? But as we can see in SoftICE, simply by viewing the register contens at the compare, the compare stars at th 4th character. Number 1, 2 and 3 seem to have a special meaning (useless for the code?).
With al that knowledge we should now search the generating routine. In order to do this, we always have a look at the place we know the serial will be stored in. remember it was [ebp-0E]. Then we just set breakpoints at calls before the compare and see if one of this calls puts the serial into the memory. You might also use the bpm (breakpoint on memory access). But I prefer the other method.
Now keep the breakpoint of the call, it´s at adress :004F1F93 and step into it with F8 to find out more about it. The call seems to be uninterestig but at the end of the call we can see a jump. Following this jump and continuing with F10, always checking the registers for integesting values like our name we get here:
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
:0046F966 33C0                    xor eax, eax                          \
:0046F968 8A01                    mov al, byte ptr [ecx]            |
:0046F96A F7EB                    imul ebx                               |
:0046F96C BF0A000000              mov edi, 0000000A       |     calculates 10 numbers which
:0046F971 99                      cdq                                           |     are then partially replaced
:0046F972 F7FF                    idiv edi                                  |     actually the first and the last two
:0046F974 8816                    mov byte ptr [esi], dl              |     numbers will be replaced
:0046F976 43                      inc ebx                                      |
:0046F977 46                      inc esi                                       |
:0046F978 41                      inc ecx                                      |
:0046F979 83FB0A                  cmp ebx, 0000000A            |
:0046F97C 75E8                    jne 0046F966                        /
:0046F97E 33C0                    xor eax, eax
:0046F980 8A45E2                  mov al, byte ptr [ebp-1E]
:0046F983 B90A000000              mov ecx, 0000000A
:0046F988 33D2                    xor edx, edx
:0046F98A F7F1                    div ecx
:0046F98C 8855D7                  mov byte ptr [ebp-29], dl    1st place of code
:0046F98F 33C0                    xor eax, eax
:0046F991 8A45EA                  mov al, byte ptr [ebp-16]
:0046F994 03C0                    add eax, eax                     ATTENTION! Here we don´t take the original char but the char multipilied by 2
:0046F996 B90A000000              mov ecx, 0000000A
:0046F99B 33D2                    xor edx, edx
:0046F99D F7F1                    div ecx
:0046F99F 8855DF                  mov byte ptr [ebp-21], dl    9th place of code
:0046F9A2 33C0                    xor eax, eax
:0046F9A4 8A45EB                  mov al, byte ptr [ebp-15]
:0046F9A7 03C0                    add eax, eax                     ATTENTION! Here we don´t take the original char but the char multipilied by 2
:0046F9A9 B90A000000              mov ecx, 0000000A
:0046F9AE 33D2                    xor edx, edx
:0046F9B0 F7F1                    div ecx
:0046F9B2 8BDA                    mov ebx, edx
:0046F9B4 885DE0                  mov byte ptr [ebp-20], bl    10st place of code
:0046F9B7 8D45D0                  lea eax, dword ptr [ebp-30]
:0046F9BA 50                      push eax
& many moves
:0046FA38 8D9578FFFFFF            lea edx, dword ptr [ebp+FFFFFF78]
:0046FA3E B90A000000              mov ecx, 0000000A

* Possible StringData Ref from Code Obj ->"G%.2x%d%d%d%d%d%d%d%d%d%d"
:0046FA43 B888FA4600              mov eax, 0046FA88

What have we got here? This looks odd. But it also looks like the generationcode. Very good. Let´s test that with SoftICE but first a thing that really knocks us off: G%.2x%d%d%d%d%d%d%d%d%d%d.WHOW This is the serial. It starts with a G then there is a formatted  hexnumber (.2) and 10 decimals. Cool all we have to do now: is to find out how the decimals are generated and where the hexnumber comes from. Therefore let´s ask SoftICE for a little help.
Start it and set the breakpoint at :0046F966. to take an indepht look as we will take out this routine step by step and theres nothing that can stop us.

:0046F966 33C0                    xor eax, eax                         - clear the register eax
:0046F968 8A01                    mov al, byte ptr [ecx]         - move the first char of the string used to generate the code to al.
                                                                                             one char needs one byte to be saved. al can take exactly one byte
                                                                                             equals one char.
:0046F96A F7EB                    imul ebx                            - IMUL. befor we continue we need to know what IMUL does:
                                                                                             it multiplies the give register by al if it´s a byte value (which is the case here)
                                                                                             the result is then stored in ax. (NOTE: Since bx ist 0 the first time, the result
                                                                                             will always be zero the forst time, that´s why the first number is replaced later)
:0046F96C BF0A000000              mov edi, 0000000A    - Now edi is filled with A which is 10 dec. This will be a part of the division
:0046F971 99                      cdq                                        - Converts signed DWORD in EAX to a signed quad word in EDX:EAX by
                                                                                             extending the high order bit of EAX throughout EDX. this shouldn´t bother us.
:0046F972 F7FF                    idiv edi                               - This is the division. let´s also have a closer look at idiv to see why this division
                                                                                             is done: Signed binary division of accumulator by source.  If source is a
                                                                                             byte value, AX is divided by "src" and the quotient is stored in
                                                                                            AL and the remainder in AH.  If source is a word value, DX:AX is
                                                                                            divided by "src", and the quotient is stored in AL and the
                                                                                             remainder in DX. Hence we have here a word division we´ll get the remainder
                                                                                             DX. Ver important as you can see right...
:0046F974 8816                    mov byte ptr [esi], dl          - ..NOW because the remainder is put to memory at [esi] bytewise.
:0046F976 43                      inc ebx                                  \
:0046F977 46                      inc esi                                    | These are done to prepare the next character.
:0046F978 41                      inc ecx                                  /
:0046F979 83FB0A                  cmp ebx, 0000000A       - The whole routine is done 10 times.
:0046F97C 75E8                    jne 0046F966

1) ax is cleared (because of the division and multiplication) and then a char is moved to al.
2) ax is multiplied by the value of bx at the start. bx is a controlling variable for the loop and increases by one each time the loop is redone.
3) the result of ax * bx (step 2) is divided by 10 and the remainder gets moved into memory, hence the code will consist of 10 digits between 0..9
4) the next character is prepared
Fine, this gets 10 digits but remember there was some additional portion of code:

:0046F97E 33C0                    xor eax, eax                         - eax gets cleared again. Seems to be storing another char
:0046F980 8A45E2                  mov al, byte ptr [ebp-1E]  - we were right another char is moved to al. Tends to be the same scheme as                                                                                           like last time
:0046F983 B90A000000              mov ecx, 0000000A      - again 10 dec
:0046F988 33D2                    xor edx, edx                         - edx gets prepared to store the remainder
:0046F98A F7F1                    div ecx                                - we calculate the remainder
:0046F98C 8855D7                  mov byte ptr [ebp-29], dl - move the remainder to the first place of the generated serial

The next two code-parts do the same. The only difference is the add eax, eax (marked out green) which leaves us at 2*eax for the rest of the calculation; the division, which looks like ((eax+eax) div ecx) and that the character that is replaced is the 9th and 10th. Also notice that there is no imul(it´s replaced by the add).

What´s left to do:
1) Find the Characters that are put to al for the calculation
2) Find out where the values between G??SERIAL come from.
3) Understand completely

numero uno is easy to do. Just check it out in SoftICE. As we can see, we get the name we entered repeateldy and upcased.
Fine. This string is worked through char by char for the first routine. For the first the ninth and tenth char the code uses the first, ninth and tenth char of the upcased string, too. You can also aquire this knowledge easily by entering abcdefghij as name.

1) OK
Therefore lets SoftICE again and test some serials. You know where to find them, don´t you. As you can see all serials strat with G01#serial. fine. So assume we always get away with this. Well we do. So what´s the meaning of this all? A bit of luck will guide us to the problem. Do you recognize the information about the number of licenses ? Play around with the value of the jet 01 assumed part and see what impact is has on the regisrtation and the about box. Tell me when you found out.
2) OK
3) OK with me
    If you still have difficulties tell me at  Ignatz_x_@hotmail.com

Now for the pascal code:
program clipmate;
uses crt;

var i, s, pass:longint;
  writeln(' This Keygen for ClipMate 5.0 is brougt to you by Ignatz');

  write('Name: ');
  until length(name) > 0;

  for i:= 1 to length(name) do
    name[i]:= upcase(name[i]);

  name:= name + name + name + name + name;

  write('Pass: G01');
  write(ord(name[1]) mod 10);
  for i := 0 to 7 do
    s:= (i*ord(name[i+1]) ) mod 10;
    pass:= 10*pass+s;
  write((2*ord(name[9])) mod 10);
  write((2*ord(name[10])) mod 10);
  writeln('Thanks for using Ignatzï quality products');
  writeln('eMail: Ignatz_x_@hotmail.com');