January 1999
"mIRC 5.5 32bit"
'Patching' 
W32 PROGRAM Code Reversing
by   N i X e 
Code Reversing For Beginners 

Program Details
Program Name: mirc55t.exe
Program Type: Chat program
Program Location: Here
Program Size: 952 Kb

Tools Used:
Softice - Win'95 Debugger
W32Dasm - Win'95 Disassembler
 
Rating  Easy ( X )  Medium ( )  Hard ( )  Pro ( ) 
Solving the puzzle
 
 
Introduction
 

mIRC attempts to provide a user-friendly interface for use with the Internet Relay Chat network. The IRC network is a virtual meeting place where people from all over the world can meet and talk.

To IRC all you need to do is Connect to a server, Join a channel, and Chat!

mIRC will guide you through these initial stages and hopefully you'll be chatting in no time. If you get stuck or want to find out more about a certain feature, just click on a Help button eg. in the Setup dialog, and you should find some hints there to help you.

As you become more experienced you can also start configuring mIRC's features to suit your own needs and tastes, features such as colours, fonts, function keys, aliases, popup menus, scripts, sounds and many others.
 
About this protection system
 

This shareware will end up registered if you enter your "Full Name:" and the correct "Registration Code:". But as you know by now, there are other ways to get registered;-)

The following entries are created in the registry:

  • HKEY_CURRENT_USER\Software\mIRC\name
  • HKEY_CURRENT_USER\Software\mIRC\date

  • (Encrypted)
  • HKEY_CURRENT_USER\Software\mIRC\code

  • (Encrypted)

    Note: Use Regmon to find out what is written to/read from the Windows Registry.
     
    The Essay
     

    Run mIRC a couple of time and try entering something in the registration screen. Write down the string you get when entering an invalid registration code: 'Invalid registration code'. We can use this string to find out where the registration code check is.

    Now disassemble mirc32.exe with W32Dasm and look for our string "Invalid registration code".
    I found it at 00435DEE. Scroll up till you get to a reference by a call or a reference by a jump.

    Here is the W32Dasm listing from "Sorry, your..." up to the first reference by a jump/call:

    * Referenced by a (U)nconditional or (C)onditional Jump at Address:     ; first ref by jmp/call
    |:00435D09(C)
    :00435DAA 6A00                    push 00000000
    * Reference To: USER32.MessageBeep, Ord:0000h
    :00435DAC E80B1C0900              Call 004C79BC
    :00435DB1 68E9AD4C00              push 004CADE9
    :00435DB6 6A00                    push 00000000
    :00435DB8 6A0C                    push 0000000C
    * Possible Ref to Menu: MenuID_0017, Item: "Search..."
    * Possible Reference to Dialog: DialogID_0033, CONTROL_ID:0083, ""
    :00435DBA 6883000000              push 00000083
    :00435DBF 8B5508                  mov edx, dword ptr [ebp+08]
    :00435DC2 52                      push edx
    * Reference To: USER32.SendDlgItemMessageA, Ord:0000h
    :00435DC3 E8481C0900              Call 004C7A10
    :00435DC8 68EBAD4C00              push 004CADEB
    :00435DCD 6A00                    push 00000000
    :00435DCF 6A0C                    push 0000000C
    * Possible Ref to Menu: MenuID_0017, Item: "Contents"
    * Possible Reference to Dialog: DialogID_0033, CONTROL_ID:0082, ""
    :00435DD1 6882000000              push 00000082
    :00435DD6 8B4D08                  mov ecx, dword ptr [ebp+08]
    :00435DD9 51                      push ecx
    * Reference To: USER32.SendDlgItemMessageA, Ord:0000h
    :00435DDA E8311C0900              Call 004C7A10
    :00435DDF 6A10                    push 00000010
    :00435DE1 6A00                    push 00000000
    * Possible Reference to String Resource ID=01912: "mIRC Registration!"
    :00435DE3 6878070000              push 00000778
    :00435DE8 E81348FDFF              call 0040A600
    :00435DED 50                      push eax
    :00435DEE 6A00                    push 00000000
    ; and here we have our string:
    * Possible Reference to String Resource ID=01913: "Sorry, your registration name and number don't match!Pleas"
    Okay, this piece of code dosen't looks like seiral comparing - there are no compares and it starts with a beep which probably means that we are allready in the 'bad guy' routine. Let's check out where this routine was jumped to from - 00435D09. Here is the W32Dasm deadlisting from 00435D09 and a few lines up:
     
    :00435CF8 68235F4D00              push 004D5F23         ; our entered name
    :00435CFD 683C5B4D00              push 004D5B3C         ; our entered serial
    :00435D02 E871C50500              call 00492278         ; interesting call
    :00435D07 85C0                    test eax, eax         ; eax = 0 is bad!
    :00435D09 0F849B000000            je 00435DAA           ; je to "Sorry, your..."
    A call followed by a compare on eax is allways interesting. A call often returns an important value in eax.
    This compare jumps to 'Sorry, your registration name and number don't match' if eax equals 0!

    Fire up SoftIce and break a couple of lines before the bad jump - at :00435CF8 (bpx 00435CF8).
    After testing this piece of code in SoftIce we can see that just before the call to 00492278 our name and serial were pushed onto the stack!
    00492278 must be the location of the 'is serial valid check'! Let's try reversing the result of text eax,eax in SoftIce. Pres "r fl z" after executing the test instruction. Yep, now it's registered... but when restarting the program it's unregistered again - Damn.

    Okay, let's try to think like a programmer. After the registration the program saves your entered name and your entered serial (not the real serial - we are not that lucky) in the Win32 registry. Your name and serial are checked at two places - when you enter name/serial and when the program starts. The programmer probably uses the same routine both places because it would be stupid to write exactly the same routine twice! So, let's have a look at the 'is serial valid check' routine:

    * Referenced by a CALL at Addresses:
    |:00435D02   , :0049240F   
    :00492278 55                      push ebp
    :00492279 8BEC                    mov ebp, esp
    :0049227B 53                      push ebx
    :0049227C 56                      push esi
    :0049227D 57                      push edi
    :0049227E 8B750C                  mov esi, dword ptr [ebp+0C]
    :00492281 8B5D08                  mov ebx, dword ptr [ebp+08]
    :00492284 53                      push ebx
    :00492285 E82A8C0200              call 004BAEB4
    :0049228A 59                      pop ecx
    :0049228B 83F805                  cmp eax, 00000005     
    :0049228E 7304                    jnb 00492294  
    :00492290 33C0                    xor eax, eax          ; eax = 0 -> Sorry, your... 
    :00492292 EB5C                    jmp 004922F0          ; jump to exit from routine 
    .
    .
    .
    * Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
    |:00492292(U), :004922A4(U), :004922EC(U)
    :004922F0 5F                      pop edi
    :004922F1 5E                      pop esi
    :004922F2 5B                      pop ebx
    :004922F3 5D                      pop ebp
    :004922F4 C20800                  ret 0008

    If this routine exits with eax=0 then we get the "Sorry, you..." message. I hate that, so let's exit with eax=1.
    Here it is very important that the the stack pointer (esp) and the other registers are the same after you patch the call or you will probably get a protection fault because all adresses will be wrong. If you are very good at assembler you have many options, but if you a not an assembly master do as me: Make your patch as small as possible!

    With that in mind search for a patch that will make this function return with eax=1 without changing too much.
    Let's try this possible fix where no registeres execpt eax are changed:

    :0049228A 59                      pop ecx               ; before the fix
    :0049228B 83F805                  cmp eax, 00000005     
    :0049228E 7304                    jnb 00492294  
    :00492290 33C0                    xor eax, eax          ; eax = 0 -> Sorry, your... 
    :00492292 EB5C                    jmp 004922F0          ; jump to exit from routine 
    
    :0049228A 59                      pop ecx               ; After the fix
    :0049228B B801000000              mov eax,1             ; if 0=bad then 1=good?
    :00492290 90                      nop
    :00492291 90                      nop                   
    :00492292 EB5C                    jmp 004922F0          ; jump to exit from routine

    He he. Now we are also registered when we restart the application:)
     
    Final Notes
     

    Maybe you could also have sniffed the password, but this works just fine. Enter anything you like as "Full Name:" and "Registration Code:" and it is accepted!

    If the first crack you apply don't work - think hard and try again.
     

    Greetings/thanks to The Sandman, Razzia, Volatility, Eternal Bliss, and all other tutorial writers!
     
    Ob Duh
     

    I wont even bother explaining you that you should BUY this target program if you intend to use it for a longer period than the allowed one.


     
     
     Return