How To Code A KeyGen A Lesson For Newbies By: Cardenal Mendoza Introduction ------------------------------------------------------------------- This time I will teach you how to code a very simple keygen. The essay I wrote is one year old, so it is time for a new, is it? OK, this time you will need SoftIce (of course!), W32dasm or IDA for making a dead listing, and a c++ compiler. I will use Borland Turbo C++ 3 :-) I know it is pretty old, but I have buyed a legal (!) copy of it for 15 $. And for our purpose it will be enough. Oh, of course you need GIF Movie Gear 2.63, our target. You can download it at www.gamani.com. If you use only SoftIce and not W32dasm you should have pen and paper, too. Don't ask me where to get these tools, ask you local software dealer ;-) I will assume that you know how to use SoftIce, W32dasm and your compiler. If not, go out and by a good book. Finding The Reg Routine ------------------------------------------------------------------- When you run the target, a silly nag pops up, probably a bug. So let us do a bit of debugging. Fire up SoftIce and run the target. Click a little bit around, and search some dialog where you can enter your name and a serial. Try to search under the menu, ;-) Type in your name and a dummy serial. Of course your serial is not the right one. If it is, wow, that is what I call zen cracking ;-) Lets try the default breakpoints. I think GetWindowTextA and GetDlgItemTextA will do good. With this two breakpoints, try to reg again. And, what a surprise, SoftIce pops up. Wait for the second call to GetWindowTextA and disable all breakpoints. Now you should see something like this: 0xxx:0042C33F lea ecx, [esp+78] ; ecx = our fake serial 0xxx:0042C343 lea edx, [esp+14] ; edx = our name 0xxx:0042C347 push ecx ; push our fake serial 0xxx:0042C348 push edx ; push our name 0xxx:0042C349 call 0042C0C0 ; call the reg routine 0xxx:0042C34E add esp, 8 ; add 8 to esp 0xxx:0042C351 test eax, eax ; is eax == 0? 0xxx:0042C353 jz 0042C3FF ; if yes, jmp bad_boy :-( I think this should be all clear. If not you should learn assembly. So we found our routine. Getting One Valid Serial ------------------------------------------------------------------- Before we code the keygen, we should fish one valid serial out of SoftIce. Step into the call and further. Always look what the code does. At first it compares the first char of our serial with 'm' if it is not equal, it jumps to the end of the routine. But before we follow this jump, because our serial probably starts not ith a 'm', look a little bit further. The code after it compares the second char with 'v', the third with 'g' and the fourth with '2'. If they aren't equal, our serial is wrong. OK, type in a new serial which starts with 'mvg2'. Step again in the call. You should pass all the compares without problems. No we get to this piece of code: 0xxx:0042C0F0 mov ebx, 004462A8 ; ebx = ptr to a serial 0xxx:0042C0F5 mov edx, dword ptr [ebx] ; edx = a serial 0xxx:0042C0F7 or ecx, FFFFFFFF ; 0xxx:0042C0FA mov edi, edx ; edi = a serial 0xxx:0042C0FC xor eax, eax ; eax = 0 0xxx:0042C0FE repnz 0xxx:0042C0FF scasb ; load serial 0xxx:0042C100 not ecx 0xxx:0042C102 dec ecx 0xxx:0042C103 mov edi, edx ; the serial 0xxx:0042C105 mov esi, ebp ; our fake serial 0xxx:0042C107 xor eax, eax ; eax = 0 0xxx:0042C109 repz ; while byte ptr != 0 0xxx:0042C10A cmpsb ; cmp edi, esi 0xxx:0042C10B je 0042C172 ; jmp bad_boy if equal 0xxx:0042C10D add ebx, 00000004 ; ebx += 4 0xxx:0042C110 cmp ebx, 0044635C ; ebx==offset last serial 0xxx:0042C116 jl 0042C0F5 ; if not jmp 0042C0F5 So what does this code do? It is easy, it just compares our serial with some other serials. So this serials are the right? Of course not, havn't you read my comments? ;-) They are all not legal ones. The programmer have searched the web for such cracker serials and if a serial is equal to one of them, it is always wrong. Instead of searching the net for cracks for their own programme, they should have coded a better protection! But they are so lazy. Therefore it would be senseless to publish a single serial, because next version it would be black-listed, but we are going to do a keygen :-) Just go on stepping. Now your fourth char is compared with 's'. Why? If it has a 's' as the fourth char it is a serial for the site license of the application. Of course we want to have that ;-) So replace the fourth char of your serial with a 's' and step again until you get to this point. Now the programme changes the pointer to our serial. It is esp, it skipps the first 7 ( or 6 if you have no site license ) chars. Ok, then a call follows. Overstep it, it only moves the serial in [eax]. But what does this mean? It simply means, that the 5th, 6th and 7th char could be anything you want. So we can give our serial a signature. I use eVC because it is my group, but you can use any 3 chars you want, of course you could use numbers, too. So after the call there is someting moved to edx. Guess what it is, it is our name! So we are near the bitchs nest! 0xxx:0042C12F mov edi, edx ; edi = our name 0xxx:0042C131 xor ecx, ecx ; ecx = 0 0xxx:0042C133 mov dl, byte ptr [edx] ; dl = name[0] 0xxx:0042C135 mov esi, 000006FE ; esi = 1790 0xxx:0042C13A test dl, dl ; dl == 0 0xxx:0042C13C je 0042C164 ; jmp to the cmp 0xxx:0042C13E movsx edx, dl ; edx = name[0] 0xxx:0042C141 inc ecx ; ecx = 1 0xxx:0042C142 imul edx, ecx ; edx *= ecx 0xxx:0042C145 add esi, edx ; esi = edx 0xxx:0042C147 cmp esi, 00000DFD ; esi <= 3581? 0xxx:0042C14D jle 0042C155 ; if not 0xxx:0042C14F sub esi, 00000DFD ; esi -= 3581 0xxx:0042C155 cmp ecx, 0000000A ; ecx == 10? 0xxx:0042C158 jle 0042C15C ; if yes 0xxx:0042C15A xor ecx, ecx ; ecx = 0 0xxx:0042C15C mov dl, byte ptr [edi+01] ; dl = next char 0xxx:0042C15F inc edi ; edi += 1 0xxx:0042C160 test dl, dl ; dl == 0? 0xxx:0042C162 jne 0042C13E ; if not loop 0xxx:0042C164 cmp esi, eax ; esi == eax? 0xxx:0042C166 jne 0042C172 ; if not jmp bad_boy I think with my comments this loop is easy to understand, too. At the point 0042C164 do a '? esi' and you see the second part of your serial. So, if you understand the loop completly, we could make the keygen, right?? Coding The Keygen ------------------------------------------------------------------- We will use C++, of course asm is better and normally I code my keygen's in w32 asm, but it is not so easy to understand, and since this text is for newbies... So how is a keygen build up? First we must show a logo. I think this is easy, is it? Then we must get the username, I will use gets() for this purpose. Then we will calculate the second part of the serial and print it our, with a 'mvg2seVC' in front of it. See my source code and mail me if you couldn't understand all: #include #include #include int main() { char n[255]; long ebx = 0, ecx = 0, edx = 0, esi = 0x6FE; cout << " *KeyGen*" << endl; cout << " By Cardenal Mendoza" << endl; cout << " ----------------------" << endl; cout << " !rEAD tHE .nFO!" << endl << endl; cout << "Please enter your name: "; gets( n ); if( strlen(n)==0 ) { cout << "You should enter a name!"; return 0; } for( int i = 0; i < strlen(n); i++) { ecx++; edx = n[i]; ebx = ecx; ebx *= edx; esi += ebx; if( esi > 0xDFD ) esi -= 0xDFD; if( ecx > 0xA ) ecx = 0; } cout << "Your serial is : mvg2seVC" << esi; cout << endl << endl << "Another KeyGen coded by Cardenal Mendoza..."; return 0; } This source code is really easy and not optimized. But you should understand it. In the appendix I will give you a optimized version. Outro ------------------------------------------------------------------- Ok, this is it for this time. I hope you learned something. If you want another tutor mail me. Of course you can also mail me flames, criticism, or any other things. But please no spam and mail bombs. I will trace you, trust me ;-) :13/10/99 Cardenal Mendoza [EVC]: Appendix ------------------------------------------------------------------- #include #include #include int main() { char n[255]; long ecx = 0, esi = 0x6FE; cout << " *KeyGen*" << endl; cout << " By Cardenal Mendoza" << endl; cout << " ----------------------" << endl; cout << " !rEAD tHE .nFO!" << endl << endl; cout << "Please enter your name: "; gets( n ); if( strlen(n)==0 ) { cout << "You should enter a name!"; return 0; } for( int i = 0; i < strlen(n); i++) { ecx++; esi += ecx*n[i]; if( esi > 0xDFD ) esi -= 0xDFD; if( ecx > 0xA ) ecx = 0; } cout << "Your serial is : mvg2eVC" << esi; cout << endl << endl << "Another KeyGen coded by Cardenal Mendoza..."; return 0; }