A nice colleague of mine asked me if I could took a look at this program...
I told him I would... when I had some time ...
That was last december ( 98 ) Finally last week it was so far :)
(begin may 99) I did look at it ... I disassembled it with win32dasm,
and looked for the error message : "Registration code entry FAILED."
that was the one I was getting :-) and found it :)
______________________________________________________________________________
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0041A6BC(C)
|
* Possible StringData Ref from Data Obj ->"Registration code entry FAILED."
|
:0041A769 68F4734300 push 004373F4
:0041A76E 8D8588EDFFFF lea eax, dword ptr [ebp+FFFFED88]
______________________________________________________________________________
This line was referenced from address 41A6BC... so I went there ....
______________________________________________________________________________
:0041A6B1 E8A2120000 call 0041B958 <<---- the call ..
:0041A6B6 33C9 xor ecx, ecx
:0041A6B8 8AC8 mov cl, al
:0041A6BA 85C9 test ecx, ecx <<---- the test ..
:0041A6BC 0F84A7000000 je 0041A769 <<---- the jump ..
:0041A6C2 8B8DB8EAFFFF mov ecx, dword ptr [ebp+FFFFEAB8]
:0041A6C8 E80B010000 call 0041A7D8
:0041A6CD 8B85B8EAFFFF mov eax, dword ptr [ebp+FFFFEAB8]
:0041A6D3 8B806C0A0000 mov eax, dword ptr [eax+00000A6C]
:0041A6D9 50 push eax
* Possible StringData Ref from Data Obj ->"%s\pktsts"
|
:0041A6DA 6858734300 push 00437358
:0041A6DF 8D8588EDFFFF lea eax, dword ptr [ebp+FFFFED88]
:0041A6E5 50 push eax
:0041A6E6 E8E5D60000 call 00427DD0
:0041A6EB 83C40C add esp, 0000000C
:0041A6EE 8D8588EDFFFF lea eax, dword ptr [ebp+FFFFED88]
:0041A6F4 50 push eax
:0041A6F5 E866E50000 call 00428C60
:0041A6FA 83C404 add esp, 00000004
* Possible StringData Ref from Data Obj ->"CONGRATULATIONS! "
|
:0041A6FD 6864734300 push 00437364
______________________________________________________________________________
Look .. this view is soooo nice :-)
It is not for nothing called *reverse* engineering :-)
We start at the dialog... and go back :-)
Now ... we have landed at the final decision point before the program
determines to show us the bad code dialog. go a bit back ( reverse ) the
test ... a bit further back ... the call :-))
That must be the call that compares the entered serial to the true serial ...
Dive in that call :-)
Hmmm... nothing ... Only two calls ... The last call .. dive in that one....
(just a zen feeling ;-))
You will land at this point :
_____________________________________________________________________________
* Referenced by a CALL at Addresses:
|:0041B019 , :0041B983
|
:0041B766 55 push ebp
______________________________________________________________________________
The two references at the top makes this call suspect. A call which is
referenced twice, can always be the keygeneration routine which is called at
registration *and* at program startup ...
Now look further ... Man oh man .... what a math ... what a logic operations.
If this is not the keygeneration routine ... Then I am not a cracker ;-)
To verify this, I had to reboot to Softice...
______________________________________________________________________________
First, print this small call out ... will be nice to make notes while you are
in softice ...
Start this program with the softice loader.. And when the program breaks at
the program entry point, ( that is when softice shows up after you push the
Load button in loader ... dont you know how to ? find out ...) Since you are
now at the programs own address space, you can put your breakpoint at address
41B766 ... That is the beginning of our key generation routine .... Press F5
and exit softice ... If it breaks, press F5 again ...
Now go and enter your name, a license number like 5 ... or something else (31?)
then your serial .... Press the OK button. You will break into softice ...
right at the start of this routine ....
Do a d eax, and there is your name :)
Trace a few steps untill address
:0041B772 0FBE450C movsx eax, byte ptr [ebp+0C]
look at eax :-) there is your number of licenses ...
Trace further till address
:0041B781 8B4508 mov eax, dword ptr [ebp+08]
do a d eax ... hey ! there is your name :-)
Trace a few steps further till address
:0041B79A 8B4D10 mov ecx, dword ptr [ebp+10]
do a d ecx ... and just keep tracing .....
and look .. there your serial appears in the data window :-)
That is cool ... we now have the serial ... but do we want to know more ? :-)
read on then ....I will lead you into the Keygens World ;-)
______________________________________________________________________________
If you carefully analyse the call you printed out on paper, you will see that
things are done pretty periodically .... Would be imaginable that the code
takes the characters from your name, and converts them to a serial ... after
applying some strange math ... This is very common ... and pretty popular
among the programmers :-)
So if you have seen several of these, you will recognize immediately what is
going on :-)
:0041B7AE 8B4508 mov eax, dword ptr [ebp+08]
:0041B7B1 0FBE4001 movsx eax, byte ptr [eax+01]
These lines keep coming ... The only thing that changes, is the number after the
eax in : 'byte ptr [eax+xx]'
We already know that dword ptr [ebp+08] stands for our name .... so what goes on
here is, everytime the next character in the name is taken and moved into eax.
The corresponding c code looks like this :
eax = name[i] ;
where i is the character number you want.
Also lines that keep repeating are these ....
:0041B7C4 8B4D10 mov ecx, dword ptr [ebp+10]
:0041B7C7 884101 mov byte ptr [ecx+01], al
:0041B7CA 0FBE450C movsx eax, byte ptr [ebp+0C]
We know from softice that the program writes our serial to dword ptr [ebp+10]
The factor that changes here is the adder to ecx in line : 'mov byte ptr [ecx+xx]'
All pretty familiar huh ? :-) What happens is : the newly generated character is
written to the serial :-)
The corresponding c code looks like this :
serial[i] = (BYTE) eax ;
where i is the character number you want.
Ok.. so much about the name and serial :-)
The rest of the code does some math stuff ...
We do not have to understand this part for 100 % ...
All we have to do is being able to convert it !
I will be converting it to c code ...
There are just a few operators that are used here ... repeatedly ...
Here I will convert the first character of the name ... the rest you can download
to view how it was done.
I use variables of type DWORD in c for the registers ...
And renamed the the addressess of the name, serial, and number of licenses to
variable names ...
Just look at the code below ...
______________________________________________________________________________
void CalculateSerial(char * name, int NumLicenses)
{
DWORD eax, ebx, ecx, edx;
char serial[20];
//:0041B772 0FBE450C movsx eax, NumLicenses
//:0041B776 B903000000 mov ecx, 00000003
//:0041B77B 83C007 add eax, 00000007
//:0041B77E 99 cdq
//:0041B77F F7F9 idiv ecx
eax = NumLicense;
ecx = 3;
eax = 7;
edx = 0; // cdq does the same as making edx = 0
eax = eax / ecx // result of division put in eax
edx = eax % ecx // rest of division put in edx
// one idiv does both above operations :-)
//:0041B781 8B4508 mov eax, name
//:0041B784 0FBE00 movsx eax, byte ptr [eax]
//:0041B787 8D441008 lea eax, dword ptr [eax+edx+08]
//:0041B78B 99 cdq
//:0041B78C 33C2 xor eax, edx
//:0041B78E 2BC2 sub eax, edx
//:0041B790 83E007 and eax, 00000007
//:0041B793 33C2 xor eax, edx
//:0041B795 2BC2 sub eax, edx
//:0041B797 83C032 add eax, 00000032
//:0041B79A 8B4D10 mov ecx, serial
//:0041B79D 8801 mov byte ptr [ecx], al
eax = name[0]; // that means the result of the division
// is not important ! see above ...
// so the relevan c code above was : eax = eax % ecx
eax = eax + edx; // the rest is used though :-)
eax = eax + 8;
edx = 0;
eax = eax ^ edx; // the xor in c
eax = eax - edx;
eax = eax & 7; // the and operator in c
eax = eax ^ edx;
eax = eax - edx;
eax = eax + 0x032; // to tell the c compiler you are using a hex number,
// place a 0x0 infront of the hex number
serial[0] = (BYTE) eax; // just take the first byte ... cause eax
// consists of 8 bytes :)
return serial;
}
______________________________________________________________________________
Well ... As I said ... what we do here is : Take the license number, do
some math with it..
Combine the result of this math with the i'th character you get from the name...
Perform some other math stuff ... And there you go .. there is your number for the
i'th character of your serial :-)
______________________________________________________________________________
That is it what you are getting from me people :-)
The rest of this routine is almost the same ...
I include here several different versions which I have built up consecutively...
The final version is optimized ... Look through it, and you will understand
how and why :-)
The Keygenerator can also be downloaded from this page[ARdTutNotes.zip - MISSING]. The c code will
compile with any c compiler that produces win32 pe files ...
You can download a copy of lcc32 from my homepage...
______________________________________________________________________________
In this tutorial we saw that to reverse engineer, you really have to go in reverse :-)
That once you have found a serial routine, you can reproduce it, so that it does the same
for you in your code :-) Only this time to show the calculated serial, instead
of comparing it to some entered number. A call with two references are suspicious...
esspecially when they contain some math stuff ...look better into them ... That the
characters of your name have to be read ... and this is always a recognizable pattern...
______________________________________________________________________________