Easy Keygen Tutorial HarvestR '98 ---[ CONTENT ]-------------------------------------------------------------------------------- You should find in this archive: keygentut.txt : (you're reading it right now) resizeimage.zip : our target, ResizeImage v3.3 wallpaper.zip : a second target for you to practice, WallPaper 1.2 ---[ WARNING ]-------------------------------------------------------------------------------- This Tutorial is for education purpose only. I wrote it to allow you to understand how are coded some protections schemes in software. I didn't make it to allow you to use the target program without paying the author. If you plan to use these programs regularly, please remeber to send your $ to the authors, don't be a outlaw, and over all, don't be a LAMER !!! ---[ INTRO ]---------------------------------------------------------------------------------- target: ResizeImage 3.3 where : http://pages.whowhere.com/internet/mudry Tools : SoftIce for Win9x v3.24 Programming Language (C, Pascal, asm, anyone you want, I'll use our old QBASIC) This is my first tutorial in english. I hope my bad spelling won't make this text too much hard to understand for you. :) I'll try to teach you how to make a key generator for a program (aka keygen). Our target will be an easy one, as the protection scheme is really easy to understand and follow. I'll assume you know the following: - basic use of SoftIce - asm instructions (at least the ones used for cracking) ---[ TUTORIAL ]------------------------------------------------------------------------------- At first, launch SoftICe (assuming you know the basics, and how to setup this Numega's nice tool). Then launch our target, ResizeImage.exe ! A popup window shows up (called a nag-screen) asking to enter a name and a serial. Well, we'll try to find how this protection is running. Let's enter HarvestR as a name and 12121212 as a serial. Don't click the OK button yet, but hit CTRL & D to bring up SoftICe. We'll define a breakpoint, using the classical BPX GetWindowTextA. Hit CTRL-D again to go back to the program. Click OK and... SoftICe pop up, with the words: Break due to BPX USER32!GetWindowTextA USER32!GetWindowTextA Well, as we entered 2 fields (name and serial), let's type CTRL-D again. SoftIce pops again with the same words than above. We should begin to trace the code from here, but while cracking this program, I saw that another GetWindowTextA call was done, so, to avoid you to trace in crappy code, just type again CTRL-D. Now we're at the right place, were the breakpoint bringed us. (if u hit CTRL-D one more time, you'll get the message "wrong key", meaning you missed the interesting part... the calculation of the true code). Hit F11 key to go back to the code that called the GetWindowTextA API. You must see, in the code window title, ResizeImage!.text......, and, under that, the begining of our code. you should see hex value where I put xxxx, but as it can be different on each computer, I'll use this way to paste the code here. xxxx:00436280 CALL [USER32!GetWindowTextA] <---- our breakpoint (3rd) xxxx:00436286 push FF xxxx:00436288 mov ecx, [ebp+10] xxxx:0043628B call 00433DA5 xxxx:00436290 jmp 0043629D We can step over the CALL at 0043628B (using F10) cause we won't find any interesting thing in it, then we jump to 0043629D xxxx:0043629D pop edi <--------- we jump here xxxx:0043629E pop esi xxxx:0043629F pop ebp xxxx:004362A0 ret 000C continuing to use F10, we come back from the call (RET 000C) and we land in the following code: xxxx:00406550 call 00436251 xxxx:00406555 pop edi <----- we are back here, from the CALL above xxxx:00406556 pop esi xxxx:00406557 ret 0004 continuing (yep, back from another call...) we arrive here: xxxx:00432974 call [eax+0000008C] xxxx:0043297A mov [ebp-18], 00000001 <---- we arrive here, back from the CALL ... ... several other lines of code here ... ... xxxx:004329A3 ret 0004 continuing again, lots of CALL :) xxxx:00406580 call 0043292C xxxx:00406585 mov edi, [ebx] <--------- we are here this time... Use F10 to pass the line 406585. then type D EDI, and you'll see our name in the data window. It seems we are in the right place... xxxx:00406587 mov ecx, FFFFFFFF xxxx:0040658C sub eax, eax xxxx:0040658E repnz xxxx:0040658F scasb xxxx:00406590 not ecx xxxx:00406592 dec ecx That's becoming interesting. This code will calculate the number of characters we entered as name. This number will be stored in ecx. Just after we have: xxxx:00406593 je 004066A4 If ecx=0 (no name entered) then jump to the line 4066A4, if not, continue: xxxx:00406599 mov edi, [esi+5C] Hit F10 to pass the line 406599. then type D EDI. Bingo, our fake serial is here. Seems like we're on the right way. xxxx:0040659C mov ecx, FFFFFFFF xxxx:004065A1 sub eax, eax xxxx:004065A3 repnz xxxx:004065A4 scasb xxxx:004065A5 not ecx xxxx:004065A7 dec ecx xxxx:004065A8 je 004066A4 Again, the test to define the length of the serial, and verifying it's not empty. as our is 8 characters, we can continue: xxxx:004065AE push 00000000 xxxx:004065B0 mov ecx, ebx xxxx:004065B2 call 00433D50 We now meet a CALL. you can pass over it, no interesting code inside... use F10 to step over. We continue and meet another CALL : xxxx:004065B7 push eax xxxx:004065B8 mov ecx, esi xxxx:004065BA call 004066E0 <----------- interesting :) Let's go into this code. Just type F8 to step into the jump. We can see: xxxx:004066E0 sub esp, 0000002C xxxx:004066E3 mov [esp], 00000005 * xxxx:004066EB mov [esp+04], 00000003 * xxxx:004066F3 mov [esp+08], 00000007 * xxxx:004066FB mov [esp+0C], 00000001 * Hmm, that's really strange... The program is storing some fixed values... Well, we'd better remember that... 5, 3, 7, 1. We could see them later. xxxx:00406703 push ebx xxxx:00406704 push esi xxxx:00406705 push edi And now, another strange line. xxxx:00406706 mov ebx, 12345678 * storing the hex number 12345678 in EBX register... well, let's see more...: xxxx:0040670B mov [esp+20], 00000002 * xxxx:00406713 mov [esp+24], 00000006 * xxxx:0040671B push ebp xxxx:0040671C push 00000009 xxxx:0040671E mov [esp+30], 00000004 * hmmm, some other hard coded numbers: 2, 6 and 4. Well, I think we'll meet them again later. These numbers are not here without a reason, I presume. xxxx:00406726 xor ebp, ebp * xxxx:00406728 mov [esp+24], ebp * Hop, do not forget this one... with the XOR, we know that now EBP=0, and it's stored too... hmm, resuming what we met earlier, we have: 5, 3, 7, 1, 0, 2, 6, 4. well, could be an special ordered suite... like "shaking" numbers from 0 to 7, no ? I you want to see the exact order where this numbers are in, just type ED ESP+24, and hit CURSOR UP. In the data window, you'll see something like: xxxx:0068E874 00000005 00000003 00000007 00000001 xxxx:0068E884 00000000 00000002 00000006 00000004 Well, now it's time to be on the next line, wich is a CALL xxxx:0040672C call 0041DFB0 nothing interesting here, several other CALLs inside, but nothing we need... Let's pass over it with F10, to be on the following lines : xxxx:00406731 mov edx, dword ptr [esp+44] Hmmm, let's type D EDX, and we see that our name HarvestR is in the data window. Well as we suppose that the serial number is build from our name, maybe that's becoming interesting. xxxx:00406735 add esp, 00000004 xxxx:00406738 mov esi, eax xxxx:0040673A mov edi, edx xxxx:0040673C mov ecx, FFFFFFFF xxxx:00406741 sub eax, eax xxxx:00406743 repnz xxxx:00406744 scasb xxxx:00406745 not ecx xxxx:00406747 dec ecx xxxx:00406748 je 00406764 Hmm, how long is our name ? more than 0 ? good, let's continue xxxx:0040674A inc ebp Wait... EBP is now equal to 1... maybe a counter ? xxxx:0040674B mov edi, edx xxxx:0040674D movsx eax, byte ptr [edx+ebp-01] * Hehehe, this line 0040674D is really interesting. We know that EBP=1 for now. So, in EAX, will be loaded the byte (because of MOVSX instruction) at EDX+EBP-01, wich for now is equal to EDX+1-01, equal to EDX... :) Well, EDX is where is stored our name, so it looks like the calculation is beginning. EX is now 48, the hex value for letter H. xxxx:00406752 add ebx, eax Bingo !!! You remember the line 00406706 [if no, just scroll up :)] ? EBX=12345678, and, now we have EBX=EBX+EAX, so we have EBX=12345678+48. Our piece of code just added the hex value of the first letter of our name to ebx... let's see further. xxxx:00406754 mov ecx, FFFFFFFF xxxx:00406759 sub eax, eax xxxx:0040675B repnz xxxx:0040675C scasb xxxx:0040675D not ecx xxxx:0040675F dec ecx xxxx:00406760 cmp ecx, ebp xxxx:00406762 ja 0040674A Well, the code recalculates again the lenght of our name (still 8) and compare it to the value of EBP (wich is 1, as we saw sooner). While EBP < ECX, we loop to the line 0040674A. 2nd Loop ebp=2 (INC EBP) eax=61 (hex value for a) ebx=12345678+48+61 3rd Loop ebp=3 (INC EBP) eax=72 (hex value for r) ebx=12345678+48+61+72 ... 8th Loop (and last one) ebp=8 (INC EBP) eax=52 (hex value for R) ebx=12345678+48+61+72+76+65+73+74+52 basis + H a r v e s t R Well, I hope you followed me here :). The value in EBX is now 123459A7 (don't forget our addition is in hexa, not in decimal). Let's examine what's happening after that. We are now on the line: xxxx:00406762 ja 0040674A But this time, as ECX=EBP, we won't jump and continue bellow: xxxx:00406764 lea eax, dword ptr [esp+30] xxxx:00406768 push ebx xxxx:00406769 push 00442854 xxxx:0040676E push eax xxxx:0040676F call 0041D2F0 In line 00406768, it saves EBX, for a further use of it. We can bypass the CALL at 40676F using F10 key, then continue here: xxxx:00406774 add esp, 0000000C xxxx:00406777 xor eax, eax Bellow is another loop, from 406779 to 406789. Hehe, this part is really interesting for us... it's creating the key we need to register our program. Let's have a look at it. xxxx:00406779 mov ecx, dword ptr [esp+4*eax+10] This move in ECX the value at ESP+10 (because EAX=0). Typing D ECX will show you the value 5... remember the suite of numbers we met earlier ? 5, 3, 7, 1, 0, 4, 6, 2.... xxxx:0040677D inc eax Now EAX=1 xxxx:0040677E cmp eax, 00000008 if EAX=8, we're in the last loop xxxx:00406781 mov cl, byte ptr [esp+ecx+30] xxxx:00406785 mov byte ptr [eax+esi-01], cl xxxx:00406789 jb 00406779 <----- Loop while EAX < 8 These two lines are creating the final serial (the one we need to register the proggy). 1st Loop ECX=5 EAX=1 CL= 9 (the number that is at [ESP+30] + 5) store CL in [EAX+ESI-1] (=ESI) 2nd Loop ECX=3 EAX=2 CL= 4 (the number that is at [ESP+30] + 3) store CL in [EAX+ESI-1] (=ESI+1) 3rd Loop ECX=7 EAX=3 CL= 7 (the number that is at [ESP+30] + 7) store CL in [EAX+ESI-1] (=ESI+2) ... Last Loop ECX=2 EAX=8 CL= 3 (the number that is at [ESP+30] + 2) store CL in [EAX+ESI-1] (=ESI+7) Let's resume what happened. We have our magic number 123459A7 and the suite 5, 3, 7, 1, 0, 4, 6, 2. With the loop above, the program move each number to his final position: - get the number at position ESP+30+5, store it at ESI (=9) - get the number at position ESP+30+3, store it at ESI+1 (=4) - get the number at position ESP+30+7, store it at ESI+2 (=7) - get the number at position ESP+30+1, store it at ESI+3 (=2) - get the number at position ESP+30+0, store it at ESI+4 (=1) - get the number at position ESP+30+2, store it at ESI+5 (=3) - get the number at position ESP+30+6, store it at ESI+6 (=A) - get the number at position ESP+30+4, store it at ESI+7 (=5) Our final serial is 947213A5. Now we know how to calculate it, and that's the same scheme for all the names we could enter. Here is the source of a QBASIC keygen (I know, you could thing strange I use this old language, but it'll be easy for everyone to convert it to any other language). I have added comments for some lines bellow: ---[ QBASIC CODE ]---------------------------------------------------------------------------- 1) | CLS 2) | LOCATE 2, 1 3) | COLOR 3, 0: PRINT TAB(24); "Resize Image v3.3 «Serial Maker»" 4) | COLOR 7, 0: PRINT TAB(30); "by "; : COLOR 15, 0: PRINT "HarvestR CIA '98"; : 5) | LOCATE 5, 15: PRINT "Enter you Name : "; : COLOR 15, 0: LINE INPUT ; name$ 6) | TmpVal# = 305419896 7) | FOR i = 1 TO LEN(name$) 8) | TmpVal# = TmpVal# + ASC(MID$(name$, i, 1)) 9) | NEXT i 10) | TmpVal$ = HEX$(TmpVal#) 11) | FOR i = 0 TO 7 12) | code$(i) = MID$(TmpVal$, i, 1) 13) | NEXT i 14) | serial$ = code$(5) + code$(3) + code$(7) + code$(1) + code$(0) + code$(2) + code$(6) + code$(4) 15) | LOCATE 6, 15: COLOR 7, 0: PRINT "Your serial is : "; : COLOR 7, 4: PRINT " "; ---[ CODE EXPLANATION ]----------------------------------------------------------------------- Lines 1 to 5 : display a short message and ask the user to enter his name. Line 6 : declare TmpVal# = 305419896. Why ? Because that's the decimal value of 12345678 hex :) Lines 7 to 9 : add the ASCII value of each characters of the name to TmpVal# Line 10 : convert the decimal value of TmpVal# into hex, puting them in a string. Lines 11 to 13 : create a string called code$(i) for each number of our magic number Line 14 : create the final serial by moving each number in the right place, according to the suite we found (5,3,7,1,0,2,6,4) Line 15 : display the final serial Now you can register ResizeImage 3.3 with any name you want. To unregister and try with another name, just delete resizeImage.ini in you Windows directory. ---[ TRAINING ]------------------------------------------------------------------------------- You can try to make a keygen, using the same scheme, for this second program : WallPaper 1.2. It's made by the same company, and of course it use the same scheme to register it, with some little (easy) differences. ---[ THAT'S ALL FOLKS ]----------------------------------------------------------------------- HarvestR 'CIA 98 ================