L                ZZZZZZ         RRRRR           SSSSS
                     L                    Z          R    R         S
                     L          aaa      Z      aaa  R    R  u   u  S
                     L            a     Z         a  RRRRR   u   u  SSSSS
               XX    L         aaaa    Z       aaaa  R    R  u   u       S
              XXXX   L        a   a   Z       a   a  R    R  u   u       S
             XXXXXX  LLLLLLL  aaaaa  ZZZZZZZ  aaaaa  R    R  uuuuu  SSSSSS
             XXXXXX       
        XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
       XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
        XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
             XXXXXX
             XXXXXX
              XXXX        proudly presents his 26.Cracking Tutorial (16.07.1999)
               XX                    KeyGenning ToggleMouse 4.4.7

I.    Introduction
I.1   The tools
II.   The essay
III.  BTW
IV.   All Tutorials by LaZaRuS

I.   This time I will describe nothing special, just another easy keygen. Today's target is
     ToggleMouse 4.4.7 - A nice tool that adds some special functions to the mouse cursor. In
     fact it is one of the few programs I cracked and left on my PC, also the only functions I
     use are only counting how often I left-/right-/double clicked and how far I have moved my
     mouse :)

I.1  I am still in holidays and forgot SICE, so I "only" have W32Dasm. You can use W32Dasm to
     debug or SICE, whatever you prefer.

II.  The essay
     After showing how to get rid of the nag-screen in a former tutorial (19), this time we will
     get not only a valid serial, but keygen the little bastard ;)
     Start ToggleMouse and click on "Order now" when the nag-screen appears. Then click on
     "Enter your registration code" and enter something. I always enter LaZaRuS as name, 
     currently I leave the "Company" empty and as serial I choose 666999 (which is A2D77h; this
     is of importance later). A messagebox appears saying "The registration information you have
     entered is not valid." Then disassemble ToggleMouse.exe in W32Dasm and search for "is not
     valid". In fact, I hope you DASM the file in the background while executing it the first
     time. That saves some time. Search for "not valid" and you should see this:

     :00410F52 FF75FC                  push [ebp-04]
     :00410F55 E885670000              call 004176DF
     :00410F5A 3D2A5F6B00              cmp eax, 006B5F2A ;; EARLIER HARDCODED SERIAL ?
     :00410F5F 59                      pop ecx
     :00410F60 7461                    je 00410FC3 ;; IF EQUAL TO OUR SERIAL, THEN JUMP
     :00410F62 FF75FC                  push [ebp-04]
     :00410F65 E875670000              call 004176DF
     :00410F6A 3DF6336A2C              cmp eax, 2C6A33F6 ;; EARLIER HARDCODED SERIAL ?
     :00410F6F 59                      pop ecx
     :00410F70 7451                    je 00410FC3 ;; IF EQUAL TO OUR SERIAL, THEN JUMP
     :00410F72 51                      push ecx
     :00410F73 8D45FC                  lea eax, dword ptr [ebp-04]
     :00410F76 8BCC                    mov ecx, esp
     :00410F78 50                      push eax
     :00410F79 E85D400100              call 00424FDB
     :00410F7E 51                      push ecx
     :00410F7F 8D45F8                  lea eax, dword ptr [ebp-08]
     :00410F82 8BCC                    mov ecx, esp
     :00410F84 50                      push eax
     :00410F85 E851400100              call 00424FDB
     :00410F8A 51                      push ecx
     :00410F8B 8D45F4                  lea eax, dword ptr [ebp-0C]
     :00410F8E 8BCC                    mov ecx, esp
     :00410F90 50                      push eax
     :00410F91 E845400100              call 00424FDB
     :00410F96 8B4E60                  mov ecx, dword ptr [esi+60]
     :00410F99 E859FCFFFF              call 00410BF7 ;; IMPORTANT CALL
     :00410F9E 83F801                  cmp eax, 00000001 ;; IS FLAG SET ???
     :00410FA1 57                      push edi
     :00410FA2 7516                    jne 00410FBA ;; IF NOT, THEN JUMP TO "WRONG SERIAL"

     * Possible Reference to Dialog: DialogID_00CB, CONTROL_ID:0040, "E"
                                       |
     :00410FA4 6A40                    push 00000040 ;; ELSE, SHOW "THANK YOU" MESSAGE

     * Possible StringData Ref from Data Obj ->"Registration is Complete!"
                                       |
     :00410FA6 681C094400              push 0044091C
     :00410FAB E8ADB80100              call 0042C85D
     :00410FB0 57                      push edi
     :00410FB1 8BCE                    mov ecx, esi
     :00410FB3 E839540100              call 004263F1
     :00410FB8 EB16                    jmp 00410FD0 ;; GO ON REGISTERED

     * Referenced by a (U)nconditional or (C)onditional Jump at Address:
     |:00410FA2(C) XXX(1)XXX
     |
     :00410FBA 6A10                    push 00000010 ;; SHOW "WRONG SERIAL" MESSAGE

     * Possible StringData Ref from Data Obj ->"The registration information you "
                                             ->"have entered is not valid."
                                       |
     :00410FBC 688C084400              push 0044088C


     Look few lines above (XXX(1)XXX) and you see that the "Wrong" message is refered to by a
     conditioned jump at adress :00410FA2. So let's take a look at this section. Look at my
     comments and you should get the idea. In the call at :00410F99 the correct serial is
     calculated and compared to our serial. If they are the same, then set the flag. How I know
     that this one is the important call? I am clairvoyant! No, not really. I just traced into
     it and had a quick look.
     btw: Did you see the strange compares from :004106FA upwards. There are dozens of that kind.
     At first I thought they are blacklisted serials, but as I changed one jump to EB in order
     to see what happens, and I found out that these serial are of earlier versions and must be
     updated. You can easily see the screen by entering 745157622 as serial (for example).

     Now let's enter the call. We find this:

     * Referenced by a CALL at Address:
     |:00410F99   
     |
     :00410BF7 55                      push ebp
     :00410BF8 8BEC                    mov ebp, esp
     :00410BFA 51                      push ecx // ECX = 7A05h (important for calculation)
     :00410BFB A1FC1B4400              mov eax, dword ptr [00441BFC]
     :00410C00 53                      push ebx
     :00410C01 56                      push esi
     :00410C02 57                      push edi
     :00410C03 FF7510                  push [ebp+10]
     :00410C06 8BD9                    mov ebx, ecx // EBX = 7A05h
     :00410C08 8945FC                  mov dword ptr [ebp-04], eax
     :00410C0B E8CF6A0000              call 004176DF // LOADS OUR SERIAL INTO EAX (Mine:A2D77)
     :00410C10 3D10270000              cmp eax, 00002710 // IS SERIAL LESS THAN 2710h=10000
     :00410C15 59                      pop ecx // ECX POINTS TO YOUR SERIAL
     :00410C16 0F8CE9000000            jl 00410D05 // THEN JUMP TO "WRONG"
     :00410C1C 8D4508                  lea eax, dword ptr [ebp+08] // I
     :00410C1F 8D4DFC                  lea ecx, dword ptr [ebp-04] // NEVER TRIED
     :00410C22 50                      push eax                    // WHAT THESE
     :00410C23 E82B470100              call 00425353               // CALLS
     :00410C28 8D4DFC                  lea ecx, dword ptr [ebp-04] // DO
     :00410C2B E87E2A0100              call 004236AE               // BUT
     :00410C30 8D4DFC                  lea ecx, dword ptr [ebp-04] // IN
     :00410C33 E82A2A0100              call 00423662               // THE
     :00410C38 8D4DFC                  lea ecx, dword ptr [ebp-04] // END OUR NAME
     :00410C3B E8DC4A0100              call 0042571C               // IS CONVERTED TO UPPERCASE
     :00410C40 8B45FC                  mov eax, dword ptr [ebp-04] // EAX POINTS TO NAME
     :00410C43 8B48F8                  mov ecx, dword ptr [eax-08] // ECX=LENGTH OF NAME
     :00410C46 83F906                  cmp ecx, 00000006           // COMPARE LENGTH WITH SIX
     :00410C49 0F8CB6000000            jl 00410D05                 // IF BELOW, THEN JUMP
     :00410C4F 8B3B                    mov edi, dword ptr [ebx]    // EDI = 7A05
     :00410C51 33F6                    xor esi, esi
     :00410C53 85C9                    test ecx, ecx               // IF LENGTH OF NAME=0
     :00410C55 7E21                    jle 00410C78                // THEN JUMP

     * Referenced by a (U)nconditional or (C)onditional Jump at Address:
     |:00410C76(C) // AT THE BEGINNING OD THIS LOOP, ESI=0 AND EDI=7A05
     |             // THIS LOOP IS PASSED FOR EVERY LETTER OF THE NAME
     :00410C57 0FBE0406                movsx eax, byte ptr [esi+eax] // LOAD 1st LETTER IN EAX
     :00410C5B 50                      push eax
     :00410C5C E88E790000              call 004185EF                 // IF IT IS NO CHAR, SET FLAG
     :00410C61 85C0                    test eax, eax                 // IF FLAG NOT SET
     :00410C63 8B45FC                  mov eax, dword ptr [ebp-04]
     :00410C66 59                      pop ecx
     :00410C67 7409                    je 00410C72                   // THEN SKIP THIS LETTER
     :00410C69 0FBE0C06                movsx ecx, byte ptr [esi+eax] // LOAD 1st letter again
     :00410C6D 03CE                    add ecx, esi                  // ADD ESI TO LETTER
     :00410C6F 0FAFF9                  imul edi, ecx                 // IMUL EDI WITH LETTER

     * Referenced by a (U)nconditional or (C)onditional Jump at Address:
     |:00410C67(C)
     |
     :00410C72 46                      inc esi // ESI=ESI+1
     :00410C73 3B70F8                  cmp esi, dword ptr [eax-08] // STILL LETTERS TO COME?
     :00410C76 7CDF                    jl 00410C57 // IF SO, THEN JUMP TO THE START OF THE LOOP

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

     * Possible Reference to Dialog: DialogID_7801, CONTROL_ID:0064, ""
                                  |
     :00410C78 6A64                    push 00000064 // SAVE 64h=100
     :00410C7A 8BC7                    mov eax, edi  // EAX=CALCULATED SERIAL
     :00410C7C 33D2                    xor edx, edx
     :00410C7E 59                      pop ecx       // ECX=64h=100
     :00410C7F F7F1                    div ecx       // EAX=EAX/ECX=SERIAL/64h
     :00410C81 FF7510                  push [ebp+10]
     :00410C84 8BF8                    mov edi, eax  // EDI=CORRECT SERIAL
     :00410C86 E8546A0000              call 004176DF // LOAD ENTERED SERIAL IN EAX
     :00410C8B 3BC7                    cmp eax, edi  // COMPARE ENTERED AND CALCULATED SERIAL
     :00410C8D 59                      pop ecx
     :00410C8E 7575                    jne 00410D05  // IF THEY ARE NOT THE SAME, THEN JUMP
     AT THE NEXT LINES, THE REGISTRATION INFORMATION IS WRITTEN TO THE REGISTRY
     
     So, now let's convert this one to C++ Builder Code.
     01.Step: Serial must be bigger then 2170h
     02.Step: Convert name to UpperCase (for example: LaZaRuS -> LAZARUS)
     03.Step: Length of name must be bigger than 5
     04.Step: ESI=0 and EDI=7A05h
     05.Step: Create a loop from 1 to length of name+1
     06.Step: If i. character of name is between A and Z
                Add ASCII(i.letter) to i
                Multiply 7A05h with the value you get one line above
              If i. character is not between A and Z, then skip this one and take the next one
     07.Step: Divide value you get from the loop by 64h=100 and you get the correct serial.

     In C++ Builder source, it look like this:

     String name=UpperCase(Edit1->Text); // GET THE NAME AND CONVERT IT TO UPPERCASE
     if (name.Length()>=6) // IF LENGTH IS 6 OR BIGGER
     {
       int ecx=0; // INITIALIZE ECX WITH 0
       unsigned int edi=0x7A05; // INITIALIZE EDI WITH 0x7A05; WATCH OUT: 32BIT DATATYPE
       for (int i=1;i<name.Length()+1;i++) // FOR EVERY CHARACTER
       {
         if ((name[i]>='A') && (name[i]<='Z')) // IF A "REAL" LETTER
         {
           ecx = name[i] + i-1;                // EDX = LETTER + LOOP VARIABLE
           edi *= ecx;                         // EDI = EDI * ECX
         }
       }
 
     edi /= 0x64;  // DIVIDE EDI BY 64h
     Edit3->Text=IntToStr(edi); // DISPLAY SERIAL
     }
     else Edit3->Text="Enter a name with at least 6 chars"; // IF LESS THAN 6 CHARS, DISPLAY THIS


     If you are not familiar with C++ Builder, the loop might look strange to you. Normally the
     first letter of a string has index 0, in C++ Builder it has 1. So the loop must go from 1
     to Length+1. Alternatively it might look like this:

     for (int i=0;i<name.Length();i++) // FOR EVERY CHARACTER
     {
       if ((name[i+1]>='A') && (name[i+1]<='Z')) // IF A "REAL" LETTER
       {
         ecx = name[i+1] + i;                // EDX = LETTER + LOOP VARIABLE
         edi *= ecx;                         // EDI = EDI * ECX
       }
     }

 
III. BTW
     
     Greets to: tKC, Ed!son, Moral Insanity, +Sandman, Fravia+ and everyone at #cracking4newbies,
     +Sandman's forum and Fravia+'s forum.

IV.  All tutorials by LaZaRuS
      
Since 4th of July I made 39171 left clicks, 1651 right clicks, 5787 double clicks and 311118
key strokes. In this time my mouse moved 930,312 meters over the screen.
(reported by ToggleMouse; I just love this stat :)