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:
What we need:
1) Soft ICE
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
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.
: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.
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:
xor eax, eax
- eax gets cleared again. Seems to be storing
: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).
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.
Example: Pirate -> PIRATEPIRATEPIRATEPIRATEPIRATE
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.
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.
3) OK with me
If you still have difficulties tell me at Ignatz_x_@hotmail.com
Now for the pascal
var i, s, pass:longint;
writeln(' This Keygen for ClipMate 5.0 is brougt to you by Ignatz');
until length(name) > 0;
for i:= 1 to length(name) do
name:= name + name + name + name + name;
write(ord(name) mod 10);
for i := 0 to 7 do
s:= (i*ord(name[i+1]) ) mod 10;
write((2*ord(name)) mod 10);
write((2*ord(name)) mod 10);
writeln('Thanks for using Ignatzï quality products');