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='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='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 :)