About this tutorial:
Tutorial:Basic keygenning:Hang2000 1.31

Target:Hang2000 1.31(http://www.winograd.com)

Tools:SoftICE 3.2x, W32Dasm 8.9x

Date:5 Dec 2000

Descriptions&Comments:I am here bringing a very easy target (hopefully)to give a good introduction to any new crackers who cannot keygen yet and those who still have blur visions on the subject of keygen and keygenning. This kind of (easy)essay may not be produced anymore in the future(at least by me), so take this very good chance and learn as much as possible...

Protections:(easy)Name/serial

Disclaimer:This file is used for educational purposes only. Any misuse of the information presented here is not my responsibility.

Copyright information:This tutorial is copyright ManKind

Starting words:
Hello,welcome to my tutorial. I am ManKind, a newbie in cracking who want to share my cracking skills with other newbies. Contact me at mankind001@bigfoot.com


The process:
Allow me to start by explaining about keygen and how to keygen. A keygen is an automated program written by cracker to generate valid registration information for a specific shareware/commercial program(a generic keygen is sometimes possible). How it can generate valid registration information? Well, the cracker first has to have the program he wants to keygen and using some typical crackers' tools especially a debugger(SoftICE, no?) as his weapon, he will TRY to understand how valid registration information is generated in that program(usually the program takes in a name and a serial, and to test whether the serial is valid or not, it itself has to generate a valid serial out of the name before it can compare the valid serial with the one entered by user). If he succeed to understand how valid registration information is generated, he can try to re-code a routine in any programming language that will generate the same valid registration information. Even if he is not successful, he still has the options to brutally crack(patching!) the program by patching, ripping assembly codes from dead-listing and try to re-compile in an assembler without actually understanding how the valid registration information is being generated, sniff out a serial, build an internal(yes!) keygen in the program itself. However things like building an internal keygen and advanced patching is too advanced to be discussed in this essay. Though there exist quite some ways to keygen, I still consider by understanding the valid registration information generation routine and re-code it is the most original, unique and best way. It is also worthwhile to note that in the WAREZ or cracking scene, keygen is considered the best crack compared to patching and sniffing a serial. One last thing I want you to know is that there are actually a variety of different keygens available, some of them which are keyfilemaker(that's a variation of keygen!), single serial keygen and hmm, say generic keygen for several programs...

Now, let's get specific. I will show you from the beginning till the end how we can keygen this (easy)target of ours. Run Hang2000 and go to the registration screen(File -> Register, doh!). As I have told you, it will take in a name and a serial. Just in case you have not known yet, whenever we try to register a program, we have to enter some registration information eventhough we know that the information is not valid. The FAKE registration information is used to pass the very first check of the program(a check is a kind of protection to avoid users from easily registering the program). The check is usually done by checking the length of user's name and/or serial. Only name and/or serial with certain length will pass the check. If we do not pass the check, it is likely that we will immediately be confronted by message like "Sorry, your registration information is not valid" which I like to call the bad_boy message, and when so, the valid registration information will not be generated at all to be compared with our fake registration information and to conclude, if that happens we will not be able to understand how the valid registration information is generated. Until we dive into the codes, we will not know the check looks like, but one thing we are sure of is that we must not have empty(0 in length) name and serial(I am sure out of my experience :D ). So, in order to not have empty name and serial, we fill in the following temporary(not fake, as we are gonna validate a registration based on the following name) registration information in the appropriate text fields(you can of course change the following information but my explanation in this essay will be based on the MY own registration information):

Name:ManKind
Serial#:23199981
(NOTE:selection of 23199981 as serial is not adhered to any rules, it is just my lucky and usual fake(Oppss, temporary...) serial from the very beginning of my cracking career :D )

Set a breakpoint on GetDlgItemTextA in SoftICE which is a very common API function to get texts from text fields(another usual one is GetWindowTextA) with the following command:

bpx GetDlgItemTextA

With this breakpoint, we will be able to break into our target's code when it tries to get our name and serial(that is after we press the Register button) and that will land us quite near to where valid registration information, in this case, the valid serial will be generated and later compared with our temporary serial(actually you don't need to break in here, you can break in from the program's entry point with Symbol Loader but that will keep you tracing with F10(step over) for a long long time and still that does not promise you an exact place where the real serial is generated, so in fact, breaking into the program when you have entered your temporary registration information is the best and most recommended :D ). After setting the breakpoint, come out of SoftICE and press the Register button. You will be thrown into SoftICE and you are now in the middle of the GetDlgItemTextA API function and this is not what we are interested in, so, press F11 once to return to the caller of the API function that is you will land inside the process of Hang2000(disable your breakpoint on GetDlgItemTextA):

(my comment is preceeded by <-- ) 
(listing obtained from W32Dasm v8.93) 
(note that some instructions in the listing may differ a little from what may be seen from SoftICE like jne in listing is jnz in SoftICE, sorry for any inconvenience :( ) 

* Reference To: USER32.GetDlgItemTextA, Ord:0104h
                                  |
:00406A02 8B3524124100            mov esi, dword ptr [00411224] <-- esi contains the GetDlgItemTextA API function 
:00406A08 53                      push ebx
:00406A09 8B9C2410020000          mov ebx, dword ptr [esp+00000210]
:00406A10 8D8C248C000000          lea ecx, dword ptr [esp+0000008C]
:00406A17 6A28                    push 00000028
:00406A19 51                      push ecx

* Possible Reference to Dialog: DialogID_008A, CONTROL_ID:03EC, "&6" <-- text field for Name 
                                  |
:00406A1A 68EC030000              push 000003EC
:00406A1F 53                      push ebx
:00406A20 FFD6                    call esi <-- call GetDlgItemTextA API to get name
:00406A22 8D54240C                lea edx, dword ptr [esp+0C]
:00406A26 6A1E                    push 0000001E
:00406A28 52                      push edx

* Possible Reference to Dialog: DialogID_008A, CONTROL_ID:03ED, "&8" <-- text field for Serial# 
                                  |
:00406A29 68ED030000              push 000003ED
:00406A2E 53                      push ebx
:00406A2F FFD6                    call esi <-- text field for Serial# to get serial
:00406A31 8D44240C                lea eax, dword ptr [esp+0C]
:00406A35 8D8C248C000000          lea ecx, dword ptr [esp+0000008C]
:00406A3C 50                      push eax
:00406A3D 51                      push ecx
:00406A3E E88D020000              call 00406CD0 <-- ***
:00406A43 83C408                  add esp, 00000008
:00406A46 663D0100                cmp ax, 0001 <-- compare ax with one
:00406A4A 0F85A7000000            jne 00406AF7 <-- jump to bad_boy if ax not equal to 1

There is not much to be said about the above codes. The important code is the call at address 00406A3E which I have marked with three asterisks(*). After returning from the call, a compare will be done to the ax register to see if we have entered valid registration information. How do I know that the call marked with 3 asterisks is important and how do I know that the cmp and jne instructions at address 00406A46 and 00406A4A are the codes to verify whether we have entered valid registration information? Well, all the calls before the one marked with 3 asterisks do not look suspicious as they are only there to get our name and serial while immediately after returning from the call marked with 3 asterisks, verification is done to see if we have entered valid registration information(try to enter a fake name/serial and follow the jump to address 00406AF7 and you will see how I know that the cmp and jne instructions are the verification codes) and that makes the call very suspicious. I am very sure that the whole keygenneration routine(routine to generate valid registration information) is in that call, so let's trace into it by pressing F8(trace into) in SoftICE when the white line of indicator is on address 00406A3E:


* Referenced by a CALL at Addresses:
|:00401687   , :00406A3E   
|
:00406CD0 8B4C2404                mov ecx, dword ptr [esp+04]
:00406CD4 81EC80000000            sub esp, 00000080
:00406CDA 8D442400                lea eax, dword ptr [esp]
:00406CDE 50                      push eax
:00406CDF 51                      push ecx
:00406CE0 E8CBFEFFFF              call 00406BB0 <-- ****
:00406CE5 83C408                  add esp, 00000008
:00406CE8 6685C0                  test ax, ax
:00406CEB 7507                    jne 00406CF4 <-- this will always jump unless there is no name entered 
:00406CED 81C480000000            add esp, 00000080
:00406CF3 C3                      ret



* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00406CEB(C)
|
:00406CF4 53                      push ebx
:00406CF5 56                      push esi
:00406CF6 8BB42490000000          mov esi, dword ptr [esp+00000090] <-- move fake/temporary serial to esi 
:00406CFD 8D442408                lea eax, dword ptr [esp+08] <-- move the valid serial to eax 

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00406D23(C)
|
:00406D01 8A10                    mov dl, byte ptr [eax] <-- move current byte of valid serial to dl 
:00406D03 8A1E                    mov bl, byte ptr [esi] <-- move current byte of fake serial to bl 
:00406D05 8ACA                    mov cl, dl <-- move dl to cl 
:00406D07 3AD3                    cmp dl, bl <-- compare dl with bl 
:00406D09 752F                    jne 00406D3A <-- jump to bad_boy if not equal 
:00406D0B 84C9                    test cl, cl <-- see if cl = null
:00406D0D 7416                    je 00406D25 <-- if so, jump to good_boy because all serials' bytes have been compared and they are all same 
:00406D0F 8A5001                  mov dl, byte ptr [eax+01] <-- move current+1 byte of valid serial to dl
:00406D12 8A5E01                  mov bl, byte ptr [esi+01] <-- move current+1 byte of fake serial to bl 
:00406D15 8ACA                    mov cl, dl <-- move dl to cl 
:00406D17 3AD3                    cmp dl, bl <-- compare dl with bl 
:00406D19 751F                    jne 00406D3A <-- jump to bad_boy if not equal 
:00406D1B 83C002                  add eax, 00000002 <-- update position of eax as 2 bytes have been compared 
:00406D1E 83C602                  add esi, 00000002 <-- do the same to esi 
:00406D21 84C9                    test cl, cl see if cl = null 
:00406D23 75DC                    jne 00406D01 <-- jump if not because maybe there are still bytes to be compared 

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00406D0D(C)
|
:00406D25 33C0                    xor eax, eax <-- start of good_boy 
:00406D27 33C9                    xor ecx, ecx
:00406D29 85C0                    test eax, eax
:00406D2B 0F94C1                  sete cl    \
:00406D2E 5E                      pop esi     > important instructions
:00406D2F 668BC1                  mov ax, cx /
:00406D32 5B                      pop ebx
:00406D33 81C480000000            add esp, 00000080
:00406D39 C3                      ret



* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00406D09(C), :00406D19(C)
|
:00406D3A 1BC0                    sbb eax, eax <-- start of bad_boy
:00406D3C 5E                      pop esi
:00406D3D 83D8FF                  sbb eax, FFFFFFFF
:00406D40 33C9                    xor ecx, ecx
:00406D42 85C0                    test eax, eax \
:00406D44 0F94C1                  sete cl        > important instructions
:00406D47 668BC1                  mov ax, cx    /
:00406D4A 5B                      pop ebx
:00406D4B 81C480000000            add esp, 00000080
:00406D51 C3                      ret

See the call I marked with 4 asterisks(*) at address 00406CE0? I suspect that the keygenneration routine is all inside that call because immediately after returning from the call there is no other call and the fake serial is then compared to the valid serial. Where else can the valid serial be generated other than that call? However, before stepping into that call, I will like to ask you to not to pay attention to the part where the fake and valid serial are compared first, it is just a loop through all the chars of the two serials(never mind if you can't understand the codes of the loop, you just don't have to). Instead, look at address 00406D2B and 00406D42 which I have marked as important instructions. Why important instructions? That is because the (sete cl) and later (mov ax, cx) instructions will determine whether we are registered or not depending on the value of ax register once we return from this call(we are in a call, remember?) back to address 00406A43. By the way, take a fast look at the jne instruction at address 00406CEB, this is the first check I previously mentioned about that we must not have empty name and serial. We want to make a keygen, don't we? Yes, we do and so let's forget about sniffing the valid serial, and step into the call marked with 4 asterisks by pressing F8:


* Referenced by a CALL at Address:
|:00406CE0   
|
:00406BB0 8B542404                mov edx, dword ptr [esp+04] <-- move name to edx 
:00406BB4 83EC40                  sub esp, 00000040
:00406BB7 83C9FF                  or ecx, FFFFFFFF
:00406BBA 33C0                    xor eax, eax
:00406BBC 53                      push ebx
:00406BBD 55                      push ebp
:00406BBE 56                      push esi
:00406BBF 57                      push edi
:00406BC0 8BFA                    mov edi, edx
:00406BC2 33ED                    xor ebp, ebp
:00406BC4 F2                      repnz
:00406BC5 AE                      scasb
:00406BC6 F7D1                    not ecx <-- contains length_of_name+1
:00406BC8 49                      dec ecx <-- decrement ecx to get length_of_name 
:00406BC9 8BD9                    mov ebx, ecx <-- move ecx to ebx 
:00406BCB 6685DB                  test bx, bx <-- test if name actually exists 
:00406BCE 7F2D                    jg 00406BFD <-- jump if it does to good_boy
 

Since we do enter a name, we will always jump to address 00406BFD. Note that this is another check whether we have entered a name or not(confirming the facts that fake registration information is really important for us :D ). Continue tracing with F10(step over):


* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00406BCE(C)
|
:00406BFD 8BFA                    mov edi, edx
:00406BFF 83C9FF                  or ecx, FFFFFFFF
:00406C02 33C0                    xor eax, eax
:00406C04 8D742410                lea esi, dword ptr [esp+10]
:00406C08 F2                      repnz
:00406C09 AE                      scasb
:00406C0A F7D1                    not ecx
:00406C0C 2BF9                    sub edi, ecx
:00406C0E 8BC6                    mov eax, esi
:00406C10 8BD1                    mov edx, ecx
:00406C12 8BF7                    mov esi, edi
:00406C14 8BF8                    mov edi, eax
:00406C16 C1E902                  shr ecx, 02
:00406C19 F3                      repz
:00406C1A A5                      movsd
:00406C1B 8BCA                    mov ecx, edx
:00406C1D 83E103                  and ecx, 00000003
:00406C20 F3                      repz
:00406C21 A4                      movsb
:00406C22 8D4C2410                lea ecx, dword ptr [esp+10]
:00406C26 51                      push ecx
:00406C27 E834090000              call 00407560
:00406C2C 83C404                  add esp, 00000004

Lots of code but the above does not do a lot, what it does is barely uppercase all the characters of our name. How do I know? Do "d 0075F484" command in SoftICE without the quotes just before the call instruction at address 00406C27 and immediately after stepping over the call, the characters of your name will change to uppercase in the data window(and 1 thing I want you to note here, though here is quite an inappropriate place, is that whatever you see in data window with the d command is considered string while whatever you see in the code window with the ? command is considered number). Continue tracing and pay attention now because the following is the start of the keygenneration routine:


:00406C2F 6685DB                  test bx, bx <-- test if name exist
:00406C32 7E26                    jle 00406C5A <-- this will always not jump when we entered a name, think the programmer did something wrong here(newbies who do not understand this statement don't have to)
:00406C34 8D4C2410                lea ecx, dword ptr [esp+10] <-- move name to ecx 
:00406C38 0FBFD3                  movsx edx, bx

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00406C58(C)
|
:00406C3B 8A01                    mov al, byte ptr [ecx] <-- move current byte of name to al 
:00406C3D 3C41                    cmp al, 41 <-- compare it with 65 decimal("A")
:00406C3F 7C15                    jl 00406C56 <-- jump to 00406C56 to proceed to the next byte of name without calculating anything from the current byte 
:00406C41 3C5A                    cmp al, 5A <-- compare it with 90 decimal("Z") 
:00406C43 7F11                    jg 00406C56 <-- refer to comment for address 00406C3F
:00406C45 0FBEF0                  movsx esi, al <-- move al to esi 
:00406C48 03EE                    add ebp, esi <-- add esi to ebp 
:00406C4A 3C45                    cmp al, 45 <-- compare it with 69 decimal("E")
:00406C4C 7505                    jne 00406C53 <-- jump if al !="69" decimal to 00406C53 to add 3 to ebp 
:00406C4E 83C505                  add ebp, 00000005 <-- add ebp with 5
:00406C51 EB03                    jmp 00406C56 <-- fixed jump to 00406C56 

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00406C4C(C)
|
:00406C53 83C503                  add ebp, 00000003 <-- add ebp with 3

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00406C3F(C), :00406C43(C), :00406C51(U)
|
:00406C56 41                      inc ecx <-- go to next byte of name
:00406C57 4A                      dec edx <-- decrease the counter by one 
:00406C58 75E1                    jne 00406C3B <-- loop it as long as edx !=0(edx=0 means all bytes of name has been looped through, and <> 0 means not)

Basically the above is a loop for as many times as the length of our name(but one thing to note is that calculation will only be done to characters of name that are in the range of A-Z) to calculate a temporary value(ebp). Pay extra attention to the jumps(jmp, jne, jg, jl) and after some time, I guess you will be able to understand the loop. Anyway the following example of a loop in C++ may help to illustrate the loop better:

for(i=0;i 64 && temp1 < 91) 
        ebp = ebp + temp1 ; 
        if (temp1 !=69) 
            ebp= ebp + 3 ;
        else
            ebp= ebp + 5 ;

When the loop has finished, you will end up here which will add 13131 decimal to our temporary value, convert the temporary value into a string and concatenate it with "LJBEPC-" string(NOTE:the valid serial for my name is LJBEPC-13666). After concantenation, the new string is actually our valid serial which will be compared to our fake serial as soon as you return from this call(we are in a call of a call now! :D ):


* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00406C32(C)
|

* Possible StringData Ref from Data Obj ->"LJBEPC-" <-- the string
                                  |
:00406C5A BF78344100              mov edi, 00413478
:00406C5F 83C9FF                  or ecx, FFFFFFFF
:00406C62 33C0                    xor eax, eax
:00406C64 8B5C2458                mov ebx, dword ptr [esp+58]
:00406C68 F2                      repnz
:00406C69 AE                      scasb
:00406C6A F7D1                    not ecx
:00406C6C 2BF9                    sub edi, ecx
:00406C6E 81C54B330000            add ebp, 0000334B <-- add 13131 decimal to ebp
:00406C74 8BD1                    mov edx, ecx
:00406C76 8BF7                    mov esi, edi
:00406C78 8BFB                    mov edi, ebx
:00406C7A 55                      push ebp
:00406C7B C1E902                  shr ecx, 02
:00406C7E F3                      repz
:00406C7F A5                      movsd
:00406C80 8BCA                    mov ecx, edx
:00406C82 8D442414                lea eax, dword ptr [esp+14]
:00406C86 83E103                  and ecx, 00000003

* Possible StringData Ref from Data Obj ->"%ld"
                                  |
:00406C89 68C0334100              push 004133C0
:00406C8E F3                      repz
:00406C8F A4                      movsb
:00406C90 50                      push eax
:00406C91 E8C12B0000              call 00409857
:00406C96 8D7C241C                lea edi, dword ptr [esp+1C]
:00406C9A 83C9FF                  or ecx, FFFFFFFF
:00406C9D 33C0                    xor eax, eax
:00406C9F 83C40C                  add esp, 0000000C
:00406CA2 F2                      repnz
:00406CA3 AE                      scasb
:00406CA4 F7D1                    not ecx
:00406CA6 2BF9                    sub edi, ecx
:00406CA8 8BF7                    mov esi, edi
:00406CAA 8BD1                    mov edx, ecx
:00406CAC 8BFB                    mov edi, ebx
:00406CAE 83C9FF                  or ecx, FFFFFFFF
:00406CB1 F2                      repnz
:00406CB2 AE                      scasb
:00406CB3 8BCA                    mov ecx, edx
:00406CB5 4F                      dec edi
:00406CB6 C1E902                  shr ecx, 02
:00406CB9 F3                      repz
:00406CBA A5                      movsd
:00406CBB 8BCA                    mov ecx, edx
:00406CBD 66B80100                mov ax, 0001
:00406CC1 83E103                  and ecx, 00000003
:00406CC4 F3                      repz
:00406CC5 A4                      movsb
:00406CC6 5F                      pop edi
:00406CC7 5E                      pop esi
:00406CC8 5D                      pop ebp
:00406CC9 5B                      pop ebx
:00406CCA 83C440                  add esp, 00000040
:00406CCD C3                      ret
:00406CCE 90                      nop
:00406CCF 90                      nop

After pressing F10 when the white line of indicator of SoftICE is on address 00406CCD(the ret instruction), you will be returned to(this is what happens when you come to a ret instruction when you are in a call) address 00406CE5. Then, from there, verification of the validity of serials will be done and depending on the results a value(1 = serials equal and registered, 0 = serials not equal and not registered) will be placed on ax. Since in there we are still in a call(from address 00406A3E), we will soon return to address 00406A43 where immediately a final check to see if we are registered or not(depending on the value of ax) will be done(on ax register, refer to several lines above)...

Guess what? We have successfully gone through this program's keygenneration routine(I aplogize for my bad explanation and writing skills if you still do not understand everything yet, my only advice is re-read please... :( ) but until here we still have not keygenned it yet. I have told you that keygen is an automated program which will generate valid registration information for us and until we build that keygen we can only say that we understood the keygenneration routine but not keygenned it yet. Not much effort is needed to actually build a keygen for this program as the keygenneration routine is really short and simple and with the core of the keygen(the heart of the keygen) halfly-completed(remember the C++ example loop to calculate the temporary value? that is important part in our keygen for this program), our work is just like a walk in the park... Below is my source of the keygen(with comment!) which I compile using Microsoft Visual C++ 6.0(other compilers may be able to compile the source, but none has been tested yet :D ):

#include <conio.h> // getche()
#include <string.h> // strlen, strupr, etc.
#include <stdio.h> // printf, gets, etc.
#include <iostream.h> // cin, cout, etc.

void main() {
    char name[255] ; // variable for name
    int temp1=0, i, name2, ebp=0 ; // some variables
    printf("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n") ;
    printf("+ C++ KeyGen for Hang2000 v1.31 +\n") ; // intro
    printf("+     by ManKind on 5 Dec 2K    +\n") ; // intro
    printf("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n") ;
    printf("Name: ") ; // wait for input
    gets(name) ; // store user's name in variable name
    name2 = strlen(name) ; // get the length of name
    strupr(name) ; // uppercase all the chars of name

    for(i=0;i<name2;i++) { // this is the core loop
        temp1 = name[i] ; // get current byte of name
        if (temp1 > 64 && temp1 < 91) {
            ebp = ebp + temp1 ; // add current byte to ebp if it's in the A-Z range
            if (temp1 != 69)
	       ebp = ebp + 3 ; // if not equal to 69, add 3 to ebp
	   else
	       ebp = ebp + 5 ; // if equal to 69, add 5 to ebp
        }
 // boy, the programmer must have some special likings for 'E'
    }

    ebp = ebp + 13131 ; // add 13131 decimal to ebp
    printf("Serial#: LJBEPC-") ; // output the valid registration serial!
    cout<<ebp<<endl ;
    getche() ; // wait for user to press Enter before exit
}

As you probably may have known, I am not a good coder and that means the above source is not optimized and some things have to be added to make it a (quite)complete keygen(like check if user entered name or not, besides I know the keygen has some problem with name that has space in between the chracters). Though I can improve it, I have decided not to do so as it is only meant as an example and I don't expect the source to be distributed(for bad purpose, that is to register the program, eww!) at all without this essay. One last thing I want to tell you is that the registration information is kept in a file named wh2k.dat in your windows directory. Finally we have come to the end of this essay. Hope to see you soon on my next tutorial. As usual, contact me if I make any mistake, give me your feedback, comments, suggestions and opinions about this tutorial and my way of presenting it.

Extra notes:
Recently, I have read a few comments by tutorials' readers concerning the quality of cracking tutorials available. Quite a few of them said that there are some tutorials that are useless as they teach nothing and are just a scratch work by the author and I am greatly disturbed by those statements. I am not sure if my essays fall into that kind of category of useless essays but the truth is that I have tried my best to make every of my essays(at least those of my latest ones) resourceful and not just any essays that teach nothing. So, I will like to call out to all my essays' readers(if there are any, hehe :D ) to send me suggestions, comments, opinions and feedbacks so that I know whether my essay and writing style is acceptable to you(that means, you can understand what I try to present, learn something and not bored by my texts) or do they need some change. I am open to positive remarks, I will like to receive critics and is willing to change and improve if my essays and writing style are really that bad rather than continue writing USELESS essays. Thanks(and hope that I am not one of the authors who write useless essays :D )...

Well, whether or not we crack this program is not important at all here. I just want you to understand the approaches I have taken and the reasons for doing so and to learn from the methods I have shown you. However you must be clever enough to take other approaches and methods(based on your logics) when dealing with other targets. Ability to do so will make you a great cracker as tutorials I believe are not used to teach you how to crack only a specific target, they show you the methods, approaches and logics available while cracking and expect you to apply them on other targets with your own intelligence...


Ending:
Thanks and greetz to:
+ORC, +HCU, Sandman, HarvestR, tKC, ytc_, Punisher, Kwai_Lo, TORN@DO, CrackZ, cLUSTER, LaZaRuS, mISTER fANATIC, yes123, WhizKiD, Volatility, ACiD BuRN, Eternal Bliss, R!SC, Kwazy Webbit, +Mammon, MisterE, Shadow, Falcon, ^tCM^, WaJ, egis, Borna Janes, CyberBlade, Sheep140/Reclaim, josephCo, Kathras, +tsehp, Predator, tscube, AB4DS(Death), douby, Steinowitz, Lord Soth, seifer666, Latigo, Dawai, Lucifer48, NoodleSpa, Mercution, NeuRaL_NoiSE, Fravia+, [dshadow], yAtEs, Duelist, Alpine, hutch, flag eRRatum, Nitrus, LiQUiD8, +Frog's Print, Muad`Dib, Acid_Cool_178, Iczelion, Razzia, wOODY^dRN, Warezpup, Bomber Monkey, XMen, llama and other crackers, individuals and organisations who have helped me, either directly or indirectly.

Service for Mankind
ManKind
mankind001@bigfoot.com