How to find the correct serial number in Ken Winograds Hang2000 v1.1 Author : hmemcpy Tutorial # : 01 Tutorial Releasedate : 19-01-2000 Target Program : Hang2000 v1.1 Program URL : http://www.winograd.com/ Difficulty : [x] Easy, [ ]Intermediate, [ ]Expert Tools needed : SoftIce Hexeditor Welcome to my first tutorial and hopefully not the last. Our target is a game in the old hangman-style concept and it needs a serial to be registered. Now, let the tutorial begin. Start the program and press File, then Register. Now enter your name and any bogus serialnumber. I used hmemcpy as name and 989898 as serial. Before pressing 'Register' you'll have to edit some breakpoints in SoftIce. Press Ctrl-D to enter SoftIce. The two most common breakpoints used when dealing with name/serial protection are GetDlgItemTextA and GetWindowTextA. So we set a breakpoint on both of them. In SoftIce, enter: bpx getwindowtexta bpx getdlgitemtexta Note: bpx is short for BreakPoint on Execution Press Ctrl-D to leave SoftIce and return to our Registrationbox. Press 'Register' and we're back in SoftIce. At the bottom you can see Break due to BPX USER32!GetDlgItemTextA This means that the program uses the GetDlgItemTextA API-function when copying text from the registrationbox to memory. Just under the ASM code you see : USER32!.text+xxxx. That shows that the code we're looking at now belongs to the USER32.dll file. But we're not interested in this, we want the code of Hang2000.exe. Press F12 once end look under the code, now you'll se : Hang2000!.text+xxxx. Good! This is where we want to be. You can search the memory for a specific string with SoftIce. We now want to search for our serial because somewhere the program has to compare the good serial with our fake. So we write : s 0 l ffffffff '989898' This command means: (s)earch for the string 989898 in memory. Start at memory adress 0 and end at FFFFFFFF The following text appeared when I searched (You might get an other adress) : Pattern found at 0167:80144166 When you see an adress that high you'll know that that isn't the one you want. We want something like 0167:00xxxxxx. Why didn't we get it then, I mean we've entered the serial and the program has 'cought' it using GetDlgItemTextA. Well the answer is simple, GetDlgItemTextA only copied our name to memory. To get our serial the program has to copy it to memory first. Press Ctrl-D to leave SoftIce. Boom, we're back in SoftIce again. Now press F12 to leave USER32.dll and to get back Hand2000.exe. Do the search for the serial again. This time the adress looks like we want. In my case it is 0167:0074F4E8 Now when we know where the serial is stored in memory we want to know when the program is using it. Before we set a breakpoint we clear the old ones, we won't be needing them anymore. Use bc * to clear the old ones and set the new with bpm 0167:0074F4E8 Note : bpm is short for BreakPoint on Memorylocation Now press Ctrl-D. Back in SoftIce again. You'll see the following code : :00406CC4 53 push ebx :00406CC5 56 push esi :00406CC6 8BB42490000000 mov esi, dword ptr [esp+00000090] :00406CCD 8D442408 lea eax, dword ptr [esp+08] :00406CD1 8A10 mov dl, byte ptr [eax] :00406CD3 8A1E mov bl, byte ptr [esi] :00406CD5 8ACA mov cl, dl <- You land here :00406CD7 3AD3 cmp dl, bl :00406CD9 752F jne 00406D0A You will land on 406CD5. This means that the previous line handled your serial in some way. If you type d ESI you'll se our fake serial. Can you guess what we find if we look whats in the EAX register ? That's right, our good serial. In my case it was ......-..... Well I'm not gonna tell, do it yourself :) You now can use the serial you found or you can patch the program to register with any name/serial. How do I do this, you might wonder. Look at the code below: :00406CC4 53 push ebx : Save ebx to stack for later use :00406CC5 56 push esi : Save esi to stack for later use :00406CC6 8BB42490000000 mov esi, dword ptr [esp+00000090] : Move the fake serial to esi :00406CCD 8D442408 lea eax, dword ptr [esp+08] : Move the real serial to eax :00406CD1 8A10 mov dl, byte ptr [eax] : copy first token in good serial to dl :00406CD3 8A1E mov bl, byte ptr [esi] : copy first token in bad serial to bl :00406CD5 8ACA mov cl, dl : copy dl to cl :00406CD7 3AD3 cmp dl, bl : compare them :00406CD9 752F jne 00406D0A : If not equal - Jump to bad serial routine :00406CDB 84C9 test cl, cl : Are there more tokens left in serial ? :00406CDD 7416 je 00406CF5 : If not jump to good serial routine :00406CDF 8A5001 mov dl, byte ptr [eax+01] : copy second token in good serial to dl :00406CE2 8A5E01 mov bl, byte ptr [esi+01] : copy second token in bad serial to dl :00406CE5 8ACA mov cl, dl : copy dl to cl :00406CE7 3AD3 cmp dl, bl : compare them :00406CE9 751F jne 00406D0A : If not equal - Jump to bad serial routine :00406CEB 83C002 add eax, 00000002 : Add 2 to eax => eax + 2 = first token :00406CEE 83C602 add esi, 00000002 : Add 2 to esi => esi + 2 = first token :00406CF1 84C9 test cl, cl : Are there more tokens left in serial ? :00406CF3 75DC jne 00406CD1 : If yes, jump to 406CD1 and continue to compare :00406CF5 33C0 xor eax, eax : Good serial routine starts here :00406CF7 33C9 xor ecx, ecx :00406CF9 85C0 test eax, eax :00406CFB 0F94C1 sete cl :00406CFE 5E pop esi :00406CFF 668BC1 mov ax, cx :00406D02 5B pop ebx :00406D03 81C480000000 add esp, 00000080 :00406D09 C3 ret :00406D0A 1BC0 sbb eax, eax : Bad serial routine starts here :00406D0C 5E pop esi :00406D0D 83D8FF sbb eax, FFFFFFFF :00406D10 33C9 xor ecx, ecx :00406D12 85C0 test eax, eax :00406D14 0F94C1 sete cl :00406D17 668BC1 mov ax, cx :00406D1A 5B pop ebx :00406D1B 81C480000000 add esp, 00000080 :00406D21 C3 ret One way to always pass the serialtest is to make the program compare the good/fake serial with itself. This can be done in many ways. One way is to change the code at adress 406CCD from lea eax, dword ptr [esp+08] to move eax,esi The move instruction is only 2 bytes and the lea instruction is 4 bytes so we need to add 2 nop's to our code, otherwise the adresses won't be the same for the rest of the code. The new code look like this. :00406CC4 53 push ebx : Save ebx to stack for later use :00406CC5 56 push esi : Save esi to stack for later use :00406CC6 8BB42490000000 mov esi, dword ptr [esp+00000090] : Move the fake serial to esi :00406CCD 8BC6 mov eax,esi : Move the fake serial to eax :00406CCF 90 nop : No OPeration :00406CD0 90 nop : No OPeration :00406CD1 8A10 mov dl, byte ptr [eax] : copy first token in fake serial to dl :00406CD3 8A1E mov bl, byte ptr [esi] : copy first token in fake serial to bl :00406CD5 8ACA mov cl, dl : copy dl to cl :00406CD7 3AD3 cmp dl, bl : compare them :00406CD9 752F jne 00406D0A Close the program and make a copy of hang2000.exe and name it hang2000.org. Open hang2000.exe in your favorite hexeditor and search for the following pattern: 8BB424900000008D442408 When found change it to 8BB424900000008BC69090 Save the file and you have a copy of hang2000 that registers with any serial. If you want to make a patch for distribution over the net, use a patch maker. It can be found almost anywhere. That's it folks. I hope you've learned something today and hopefully I'll be back soon with a new tutorial Greets to everybody :) /hmemcpy