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