|
|
Win Code Reversing |
|
|
|
|
|
|
Program Details Program Name: Hard Copy V1.51 Program Type: Screen Capture Utility Program Location: http://www.desksoft.com Program Size: 106,496 bytes (tiny) |
||
W32Dasm and Softice
|
||
|
|
Potatoes have a very interesting life. |
"TIME is MORE than money, its life, and every moment is precious."
|
HardCopy Pro is the professional, easy to use screen capture utility
for Windows 95 / 98 and NT 4.0 or higher. It can capture rectangular screen
areas and whole windows. The captured images can be cropped very easily
and the color depth can be changed to any desired value from monochrome
to true color. Images can be printed, saved, copied to the clipboard or
edited with any image editing program. Many options allow the customization
of all these actions to individual user needs.
|
30 day trial to use this piece of hmmmmmm (EXCELLENT) software.
|
The main thing is that you get some kind of understanding from this essay, even if you dont understand all of it I hope you can come away with something new to apply to your future cracks.
Okay, here goes, again.
If you read my last TUTORial then you will be familiar with my methods of cracking, well I say my methods but they are simply the generic steps taken by most crackers I will run through them quickly.
STAGE 1.... Collect all relevant information on the
target as possible, this will no doubt help you with your crack.
STAGE 2.... This is where we enter (oooh) the target,
goggles at the ready.:o)
SORRY! once again I will explain ONLY how to get to the algorithm, the rest is for other TUTORials.
1. Load the target (Hard Copy V1.51) :o)
2. Goto the 'DEMO' tab and click 'REGISTER NOW'
3. You will be presented with a standard REGISTRATION
NAME/CODE box
4. Type in your name and code, i used - Name: sheep140
CODE:1212121212
5. Enter Softice type BPX HMEMCPY
6. press F5 to exit Softice, press OK on the registration
box
7. Softice will pop and you will be inside HMEMCPY,
press F11, you can now disable HMEMCPY. 8. Search for the name you entered
by typing s 0 lffffffff "sheep140" <----(you will use your name in here.
9. We need to place a BPM on the location of your
name, mine was ---> BPM 015F:418858
10. Press F5 twice and you should land at the code
point below.
--:00409BC0 xor edi, edi------------------;Zero
EDI
--:00409BC2 cmp edx, 00000005-------------;Compare
5 with Username Length
--:00409BC5 mov dword ptr [ebp-08], edi---;Set
[ebp-08] to Zero
S :00409BC8 jge 00409BD1------------------;Jump
if username 5 characters or more (GOODGUY)
E :00409BCA xor al,
al--------------------;Zero AL
C :00409BCC jmp 00409C6F
-----------------;Jump out of routine (BADGUY)
T :00409BD1 xor eax,
eax -----------------;Zero EAX
I :00409BD3 cmp edx,
edi -----------------;Compare EDX with EDI
O :00409BD5 jle 00409BE3
-----------------;Jump if Error to next section
N :00409BD7 movsx ecx,
byte ptr [eax+esi]-;Move letter into ECX (move letter
of username into ECX)<----- ALGORITHM STARTS
1 :00409BDB
add dword ptr [ebp-08], ecx --;Add Name[counter]
to [ebp-08] MAGIC_NUMBER_1<----- YOU LAND
HERE
--:00409BDE inc eax ----------------------;counter
= counter +1
--:00409BDF cmp eax, edx -----------------;Have
we finished MAGIC_NUMBER_1 ?
--:00409BE1 jl 00409BD7 ------------------;IF
NO, JUMP.
***************** END OF SECTION
1 ****************
SUMMARY OF SECTION 1
Its always easier if you can
break your algorithm down into sections.
Section 1 creates (MAGIC_NUMBER_1)
in [EBP-08] by adding all characters of your username together, even though
it only uses the second digits to XOR with later.
example....
USERNAME: sheep140
MAGIC_NUMBER_1: 02,aa :The
algorithm doesnt use the 02, only the aa.
I`m afraid your going to need a little C knowledge.
The CODE snippet for MAGIC_NUMBER_1 in C.....
printf("Please Enter Username:");
for (i=0;i<name_length;i++)
MAGIC_NUMBER_1&=0xFF;
//gets rid of the extra bit 02,aa becomes 00,aa
--:00409BE3 push ebx ---------------------;Save
EBX
SUMMARY OF SECTION 2
The CODE snippet for MAGIC_NUMBER_2
in C.....
int name_length,i,temp1,temp2,temp3,t=0,flag;
char LOOK_UP_TABLE_1[]="3He78tKo4L";
for (i=0;i<10;i++)
USERNAME:sheep140
--:00409C11 and dword ptr [ebp+08],
00000-;Zero [EBP+08]
SUMMARY OF SECTION 3
The CODE snippet for MAGIC_NUMBER_3
in C.....
for (i=0;i<flag;;i++)
t%=10;
if (temp1>0xff)
MAGIC_NUMBER_3[t]=MAGIC_NUMBER_2[t]^temp1;
THIS SNIPPET DOESNT MAKE MUCH
SENSE IT JUST SHOWS THE SUM TO GENERATE MAGIC_NUMBER_3
USERNAME:sheep140
:00409C3D xor esi, esi -----------------;Zero
esi (counter)
************ START OF CALL 409B7A
***************
:00409C48 test al, al ------------------;Is
the MAGIC_NUMBER_3[counter] a real CODE_DIGIT yet?
SUMMARY AND CONCLUSION
1. Look at first element of
(array) MAGIC_NUMBER_3
The WHOLE KEYGEN CODE in C.....
USERNAME:sheep140
WELL, thats it, I do appreciate
that TIME is a very precious commodity but if you could spare a few moments
to send me your comments I would appreciate it. thanks.
EMAIL - SHEEP140@OPERAMAIL.COM
I USED THE HTML TEMPLATE TO
SET THIS OUT, I DID NOT RIP THE ESSAY AND PUT MY NAME ON IT.
Do
I really have to remind you all that by buying and NOT stealing the software
you use will ensure that these software houses will continue to produce
even *better* software for us to use and more importantly, to continue
offering even more challenges to breaking their often weak protection systems.
If
your looking for cracks or serial numbers from these pages then your wasting
your time, try searching elsewhere on the Web under Warze, Cracks etc.
int MAGIC_NUMBER_1=0;
char name[20];
gets(name);
name_length=strlen(name);
MAGIC_NUMBER_1+=username[i]
S :00409BE4
mov ebx, dword ptr [ebp+0C] --;Move 64f938
(offset) into ECX
E :00409BE7
mov [ebp-04], 00414478 -------;Move Look Up
Table 1 (offset) into [EBP-04}
C :00409BEE
sub dword ptr [ebp-04], ebx --;SUBTRACT 64f938
from 414478
T :00409BF1
mov eax, edi -----------------;Move counter
into EAX
I :00409BF3
mov ecx, dword ptr [ebp-04] --;Move result
of above SUBTRACTION into ECX
O :00409BF6
cdq --------------------------;set up for
idiv
N :00409BF7
idiv [ebp-10] ----------------;Divide EAX
with username length - result is in EAX remainder in EDX
2 :00409BFA
mov eax, dword ptr [ebp+08] --;Move USERNAME(offset)
into EAX
--:00409BFD lea esi, dword
ptr [edi+ebx] -;Setup storage for MAGIC_NUMBER_2
--:00409C00 mov al, byte ptr
[eax+edx] ---;Move USERNAME[counter] into
AL (the program uses the remainder as a counter) :o)
--:00409C03 xor al, byte ptr
[ecx+esi] ---;XOR LOOK_UP_TABLE_1[counter]
with USERNAME[counter]
--:00409C06 xor al, byte ptr
[ebp-08] ----;XOR above result with MAGIC_NUMBER_1
--:00409C09 inc edi ----------------------;Increase
counter
--:00409C0A cmp edi, 0000000A
------------;Have we finished generating MAGIC_NUMBER_2
?
--:00409C0D mov byte ptr [esi],
al -------;Save MAGIC_NUMBER_2[counter]
--:00409C0F jl 00409BF1 ------------------;Carry
on generating? Jump if yes.
***************** END OF SECTION
2 ****************
Well it seems to get a little
bit complex here but dont worry this is what the summary is for.:o)
Before I show you the sum I
will explain why they use the USERNAME[remainder] instead of USERNAME[counter].
the reason they do it is so
that usernames less than 10 digits can produce a 10 digit code. example....
1. USERNAME[remainder=0]=s
2. USERNAME[remainder=1]=h
3. USERNAME[remainder=2]=e
4. USERNAME[remainder=3]=e
5. USERNAME[remainder=4]=p
6. .and so on...........=1
7. .....................=4
8. .....................=0
9. USERNAME[remainder=0]=s
10.USERNAME[remainder=1]=h
its the same as modulus in
C.
int MAGIC_NUMBER_1=0;
int MAGIC_NUMBER_2[10];
int MAGIC_NUMBER_3[10];
{
t%=name_length;
temp1=name[t];
temp2=temp1^LOOK_UP_TABLE[i];
temp3=temp2^MAGIC_NUMBER_1;
MAGIC_NUMBER_2[i]=temp3;
t++;
}
DONT WORRY IF YOU DONT UNDERSTAND,
THE WHOLE PROGRAM IS EXPLAINED AT THE END.
MAGIC_NUMBER_1: 02,aa
MAGIC_NUMBER_2: EA 8A AA F8
E2 EF D5 F5 ED 8E
--:00409C15 cmp dword ptr [ebp-0C],
00000-;Does [ebp-oc] = 0 ?
--:00409C19 jle 00409C3D -----------------;Jump
if error
--:00409C1B mov eax, dword
ptr [ebp+08] --;Move counter into EAX
--:00409C1E push 0000000A ----------------;Push
dec(10)
--:00409C20 cdq --------------------------;Setup
idiv
S :00409C21
pop ecx ----------------------;Move dec(10)
into ECX
E :00409C22
idiv ecx ---------------------;Divide EAX(counter)
with ECX dec(10)
C :00409C24
mov al, byte ptr [ebp+08] ----;Move counter
into AL
T :00409C27
imul al ----------------------;Multiply AL
with AL
I :00409C29
add al, byte ptr [ebp-10] ----;Add USERNAME
length to AL
O :00409C2C
xor byte ptr [edx+ebx], al ---;Xor AL with
MAGIC_NUMBER_2[counter]
N :00409C2F
inc [ebp+08] -----------------;Increase counter
3 :00409C32
mov eax, dword ptr [ebp+08] --;Move counter
into EAX
--:00409C35 cmp eax, dword
ptr [ebp-0C] --;Are we finished?
--:00409C38 lea ecx, dword
ptr [edx+ebx] -;Move offset of MAGIC_NUMBER_2
into ECX - no idea why , maybe someone can point this out?
--:00409C3B jl 00409C1B ------------------;if
not finished jump back to start of section 3
***************** END OF SECTION
3 ****************
Well nothing new here, section
3 uses the remainder counter again the SUM has become much easier
a simple Xor of MAGIC_NUMBER_2
to produce MAGIC_NUMBER_3
{
temp1=i;
temp1*=temp1;
temp1+=name_length;
temp1&=0xff;
MAGIC_NUMBER_2[t]=MAGIC_NUMBER_3[t];
t++;
}
WHOLE KEYGEN CODE COMING NEXT.....
MAGIC_NUMBER_1: aa02
MAGIC_NUMBER_2: EA 8A AA F8
E2 EF D5 F5 ED 8E
MAGIC_NUMBER_3: E2 83 A6 E9
FA CE F9 CC AD D7
:00409C3F mov al, byte ptr
[esi+ebx] ---;Move MAGIC_NUMBER_3[counter]
into AL
:00409C42 push eax ---------------------;Push
eax for CALL 409B7A
:00409C43 call
00409B7A ----------------;This
routine checks to see if your MAGIC_NUMBER_3[counter] is an alphanumeric
digit, if it isnt then its manipulated.
:00409B7A mov al, byte ptr
[esp+04] ----;Move MANIPULATED number into AL
:00409B7E cmp al, 31 -------------------;Compare
MANIP number with 31h "1"
:00409B80 jl 00409B86 ------------------;is
the MANIP number less than the 31h? if yes JUMP.
:00409B82 cmp al, 39 -------------------;Compare
MANIP number with 39h "9"
:00409B84 jle 00409B96 -----------------;Is
MANIP number a REAL number from 0-9? if yes JUMP
:00409B86 cmp al, 61 -------------------;Compare
MANIP number with 61h "a"
:00409B88 jl 00409B8E ------------------;Is
MANIP number less than 61h "a"?If yes JUMP
:00409B8A cmp al, 7A -------------------;Compare
MANIP number with 7ah "z"
:00409B8C jle 00409B96 -----------------;Is
MANIP number a REAL lowercase digit from a-z? if yes JUMP
:00409B8E cmp al, 41 -------------------;Compare
MANIP number with 41h "A"
:00409B90 jl 00409B99 ------------------;Is
MANIP number less than 41h "A"? if yes JUMP
:00409B92 cmp al, 5A -------------------;Compare
MANIP with 5ah "Z"
:00409B94 jg 00409B99 ------------------;Is
MANIP number a REAL uppercase digit between A-Z? if no JUMP
:00409B96 mov al, 01 -------------------;FLAG
to indicate no more manipulating on the MANIP number
:00409B98 ret --------------------------;Return
from call
:00409B99 xor al, al -------------------;FLAG
to indicate carry on manipulating MANIP number.
:00409B9B ret --------------------------;Return
from call
************ END OF CALL 409B7A
*****************
:00409C4A pop ecx ----------------------;Save
MANIPULATED number
:00409C4B jne 00409C62 -----------------;Jump
if MANIPULATED number is now a real CODE_DIGIT
:00409C4D movsx eax, byte ptr
[esi+ebx]-;carry on MANIPULATING number, move
FFFFFF?? into EAX
:00409C51 add eax, 00000046
------------;Add 46 to the MANIPULATED number
:00409C54 mov ecx, 000000FF
------------;Move FF into ECX
:00409C59 cdq --------------------------;setup
idiv
:00409C5A idiv ecx ---------------------;divide
MANIPULATED number with FF (this places the MANIPULATED number into EDX)
:00409C5C mov byte ptr [esi+ebx],
dl ---;Save MANIPULATED number again
:00409C5F push edx ---------------------;Push
MANIPULATED number for CALL again
:00409C60 jmp 00409C43 -----------------;Jump
to call
:00409C62 inc esi ----------------------;Increase
counter
:00409C63 cmp esi, 0000000A
------------;Are we finished the real CODE_DIGIT?
:00409C66 jl 00409C3F ------------------;If
not, JUMP BACK.
***************** END OF LAST
SECTION*****
We are finaly here, THE END,
well it has taken me about 7 hours to write this TUTORial, that includes
the 1 hour working out the algorithm.
I truely hope you get something
out of it, I know I`m very bad at explaining things, i tried my hardest,
I tried to keep it brief as possible.
The last part of the algorithm
converts your MAGIC_NUMBER_3 into a 10 digit displayable code, this is
how its done.
2. Is it a displayable digit
between 0-9, a-z or A-Z?
3. NO! okay, add 0x46 to it.
Make sure element doesnt exceed 0xff, if it does make it a negative number.
4. Is it a displayable digit
between 0-9, a-z or A-Z?
5. YES! okay, SAVE it into
REAL_CODE array.
6. Move to next element.
SORRY! its the easiest way
to explain this stuff. :o)
#include <stdio.h>
#include <string.h>
// ************************************* //
// * * //
// * HARDCOPY PRO v1.51 KEYGEN * //
// * * //
// * Coded by: SHeeP140 [PGC] * //
// * * //
// ************************************* //
int checkcode(int eq); // this declares the checkcode routine
void main() // main program
{
// Variable declaration
long eq; // Var for checkcode routine
int name_length,i,temp1,temp2,temp3,t=0,flag; // Var for general purpose
int MAG1=0; // Var for MAGIC_NUMBER_1
int MAG2[10]; // Var for MAGIC_NUMBER_2
int MAG3[10]; // Var for MAGIC_NUMBER_3
int REAL_CODE[10]; // Var for REAL_CODE display
char name[20]; // Var for USERNAME
char LUT1[]="3He78tKo4L"; // Look Up Table
printf("Hardcopy V1.51 Keygen coded by SHeeP140 [PGC]\n\n")
printf("Enter Username:"); // Display enter username message
gets(name); // Store username in var NAME
name_length=strlen(name); // Get NAME length
if (name_length<5)
{
printf("Username needs to be 5 or more characters");
exit(0);
}
flag=name_length; // Flag value needed later
//MAGIC NUMBER 1 GENERATION START **** -----------------------------//
for (i=0;i<name_length;i++) //For loop to calculate MAG1
MAG1+=name[i]; //Calculation for MAG1
MAG1&=0xFF; //AND's MAG1 to produce MAG1-1
//i.e 23aa becomes 00aa
//the algorithm only xor's
//the last digits.
//MAGIC NUMBER 1 GENERATION END ****** -----------------------------//
//MAGIC NUMBER 2 GENERATION START **** -----------------------------//
for (i=0;i<10;i++) //for loop to calculate MAG2
{
t%=name_length; //t=modulus x, so that username = 10
temp1=name[t]; //temp1 = letter of username
temp2=temp1^LUT1[i]; //xor look up table with letter of username
temp3=temp2^MAG1; //result of above is xored with MAG1-1
MAG2[i]=temp3; //store MAG2 using an array of 10 numbers
t++; //increase counter
}
//MAGIC NUMBER 2 GENERATION END ****** -----------------------------//
//MAGIC NUMBER 3 GENERATION START **** -----------------------------//
//zero t
t=0;
if (flag<10) //Another BUG fixed by this
flag=10; //instruction, names <> than 10
//digits are now both worked out
//correctly :o)
for (i=0;i<flag;;i++) //for loop to create MAG3
{
t%=10; //t=modulus 10 so that xoring cycles through MAG2
temp1=i; //temp1 = counter
temp1*=temp1; //temp1=temp1*temp1
temp1+=name_length; //temp1=temp1+namelength
if (temp1>0xff) //if condition for xor correction
{
temp1&=0xff; //when username is longer than 10 digits
} //the algorithm starts to re-xor
//MAG3 with MAG3 values it just generated
//this instruction stops the xoring digit
//exceed 0xff i.e 0134 becomes 0034
MAG3[t]=MAG2[t]^temp1; //MAG3=MAG2 xored with temp1
MAG2[t]=MAG3[t]; //This instruction stops fuckups if
//username is over 10 digits
//THIS FUCKER NEARLLY HAD NE STUMPED.
t++; //increase t by 1
}
//MAGIC NUMBER 3 GENERATION END ****** -----------------------------//
//FINAL CODE GENERATION START ******** -----------------------------//
for(i=0;i<10;i++) //for loop to create REAL_CODE
{
eq=MAG3[i]; //eq= MAGIC NUMBER 3 offset+counter
flag=checkcode(eq); //This routine checks if the MAGIC NUMBER
//in eq is a displayable character
//if it is then flag is set to 1
while(flag==0) //while loop (keep going until eq is displayable
{
temp2=0xff-eq; //Check if adding 0x46 will make temp2 exceed 0xff
if (temp2<0x46) //If temp2 is going to exceed 0xff
{ //
eq=0-temp2-1; //make the number negative so that
} //when 0x46 is added it wont exceed 0xff
eq+=0x46; //Add 0x46 to eq
flag=checkcode(eq); //check to see if eq is displayable
//
//If eq is displayable then
} //
REAL_CODE[i]=eq; //eq is saved in the REAL_CODE
//array.
printf("%c ",REAL_CODE[i]); //display REG CODE
}
}
int checkcode(int eq) // check routine
{
if (eq>0x30 && eq<0x3a) //Is eq a digit from 0-9?
{
return(1); //if yes return 1. (stop adding 0x46)
}
else if (eq>0x60 && eq<0x7b) //Is eq a letter between a-z?
{
return(1); //if yes return 1. (stop adding 0x46)
}
else if (eq>0x40 && eq <0x5b) //Is eq a letter between A-Z?
{
return(1); //if yes return 1. (stop adding 0x46)
}
else
{
return(0); //If none of the above, carry on adding 0x46
}
}
//END OF KEYGEN :o)//
I KNOW I KNOW I KNOW, I
SUCK BIG TIME AT C. :o) but hey, this is my first REAL keygen,
I promise to improve my C for
the next tutorial.:o)
MAGIC_NUMBER_1: 02,aa
MAGIC_NUMBER_2: EA 8A AA F8
E2 EF D5 F5 ED 8E
MAGIC_NUMBER_3: E2 83 A6 E9
FA CE F9 CC AD D7
REAL_CODE-----: n U 2 u X Z
W X 1 c
Essay
by: SheeP140
Page
Created: 5 Nov 1999