January 1999
"DubIt 1.0.1"
'Patching' 
W32 PROGRAM Code Reversing
by   N i X e 
Code Reversing For Beginners 

Program Details
Program Name: dubit.exe
Program Type: Multimedia tool
Program Location: Here
Program Size: 526 Kb

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

DubIt is a multimedia tool which lets you easily add audio to movie clips and images. Unlike video editors and presentation authoring products, DubIt adds audio in real-time as you watch the movie or image.With DubIt, it is easy to narrate a video clip and synchronize your voice with the video. DubIt is the perfect tool to quickly add voice annotation and sound effects to a movie or image.
 
About this protection system
 

This shareware will end up registered if you fill out a order form and enter the valid serial number.

The following entries are created in the registry:

  • HKEY_LOCAL_USER\Software\TechSmith\DubIt\Settings\RegisteredTo
  • HKEY_LOCAL_USER\Software\TechSmith\DubIt\SettingsRegisteredTo1\
  • HKEY_LOCAL_USER\Software\TechSmith\DubIt\Settings\RegistrationKey
  • Note: Use Regmon to find out what is written to/read from the Windows Registry.
     
    The Essay
     

    First run the target program a couple of times and try to enter any name og any reg code. Write down the message you get: 'You must enter a valid registration key'.

    Now disassemble DubIt.exe with W32Dasm and look for the string 'You must enter a valid registration key'. Study the code around the string reference. The bad guy string 'You must enter a valid registration key' appears twice and just below we have a 'Thank you for registering DubIt'.

    Take a closer look at the asm code. The important thing here is the jumps! Which jumps will lead us to the bad guy message and which jumps will lead us to the good guy message. After printing out 4-5 pages before the bad guy message and some analysing I came up with this:

    :004065E3 E85A3E0200              call 0042A442         ; eax = length(serial)
    :004065E8 8BD8                    mov ebx, eax  
    :004065EA 83FB12                  cmp ebx, 00000012     ; length(serial) = 12 hex (18 decimal)
    :004065ED 0F8C4B010000            jl 0040673E           ; if length(serial) < 12 jump to 'You must enter a valid...'
    .
    .
    .
    :0040668D E8160F0000              call 004075A8         ; check valid Name/Serial?!?!
    :00406692 6A01                    push 00000001         ; saves 1 on stack
    :00406694 8BD8                    mov ebx, eax          ; ebx = return value from call
    :00406696 58                      pop eax               ; restores 1 from stack in eax
    :00406697 3AD8                    cmp bl, al            ; is return value = 1?
    :00406699 0F8583000000            jne 00406722          ; if al <> bl then jump to 'You must enter a valid...'
    .
    .
    .
    :00406701 E84C000000              call 00406752         ; call to function that has a reference
                                                            ; to 'Thank you for registering DubIt.'!
    .
    .
    .
    * Referenced by a (U)nconditional or (C)onditional Jump at Address: 00406699(C)
    :00406722 53                      push ebx
    :00406723 57                      push edi
    :00406724 8BCE                    mov ecx, esi
    :00406726 E822100000              call 0040774D
    :0040672B 85C0                    test eax, eax
    :0040672D 75E9                    jne 00406718
    :0040672F 50                      push eax
    :00406730 50                      push eax
    * Possible Reference to String Resource ID=00010: "You must enter a valid registration key." ; bugger
    :00406731 6A0A                    push 0000000A
    :00406733 57                      push edi
    :00406734 E88B160000              call 00407DC4
    :00406739 83C410                  add esp, 00000010
    :0040673C EBDA                    jmp 00406718
    * Referenced by a (U)nconditional or (C)onditional Jump at Addresses: 004065ED(C), :00406605(C)
    :0040673E 6A00                    push 00000000
    :00406740 6A00                    push 00000000
    * Possible Reference to String Resource ID=00010: "You must enter a valid registration key." ; bugger
    :00406742 6A0A                    push 0000000A
    :00406744 57                      push edi
    :00406745 E87A160000              call 00407DC4
    :0040674A 83C410                  add esp, 00000010
    * Referenced by a (U)nconditional or (C)onditional Jump at Address: 00406720(U)
    :0040674D 5F                      pop edi
    :0040674E 5E                      pop esi
    :0040674F 5B                      pop ebx
    :00406750 C9                      leave
    :00406751 C3                      ret
    * Referenced by a CALL at Address: 00406701   
    :00406752 55                      push ebp              ; start of function with reference to
                                                            ; "Thank you for registering DubIt."
    :00406753 8BEC                    mov ebp, esp
    .
    .
    .
    * Referenced by a (U)nconditional or (C)onditional Jump at Address: 0040677C(C)
    * Possible StringData Ref from Data Obj ->"Thank you for registering DubIt."
    :0040679E 6854D34400              push 0044D354

    Fire up SoftIce with a breakpoint at :004065E3 (bpx 004065E3). Trace through the code. Display register values and memory contents before calls, after calls, and at cmp/test instructions. Write your findings down on your printed deadlisting.
    This process will take some time and you will have to do it several times...

    If the serial is not at least 18 (12 hex) characters long we get the bad guy message, so try to enter a 18 digit serial number.

    If the call to 004075A8 returns eax=1 we get the good guy message. If you just reverse the jump after the call to 004075A8 you are not registered after restarting because the program uses another routine at startup - but perhaps it calls the same function starting at 004075A8.

    Let's have a look at this function which could be the usual 'is valid serial' function:

    * Referenced by a CALL at Addresses: 0040668D, :00407278, :0040751D
    :004075A8 55                      push ebp
    .
    .
    .
    :004076A4 5F                      pop edi
    :004076A5 8A65FE                  mov ah, byte ptr [ebp-02]     ; building return value
    :004076A8 5E                      pop esi
    :004076A9 8A45FF                  mov al, byte ptr [ebp-01]     ; building return value
    :004076AC 5B                      pop ebx
    :004076AD C9                      leave
    :004076AE C21000                  ret 0010

    As we can read from the W32Dasm deadlisting this 'is valid serial' function is called from 3 different locations (0040668D, :00407278, :0040751D). It's probably easier to patch this one routine that to patch the 3 routines making the call!

    We need to return with eax = 1 without changing too much in the code and especially not the stack pointer (esp) which keeps track of program variables. If you mess with the esp you'll surely get a fault of some kind!

    So, change as little as possible:

    :004076A4                         pop edi                       ; before the fix
    :004076A5                         mov ah, byte ptr [ebp-02]     ; building return value
    :004076A8                         pop esi
    :004076A9                         mov al, byte ptr [ebp-01]     ; building return value
    :004076AC                         pop ebx
    
    :004076A4                         pop edi
    :004076A5                         mov ah, 0                     
    :004076A7                         nop
    :004076A8                         pop esi
    :004076A9                         mov al,1                      ; allways return 1
    :004076AB                         nop
    :004076AC                         pop ebx

    He he. We are now registered!

    I'm starting to like these 'is serial valid' functions...
     
    Final Notes
     

    Maybe you could also have sniffed the password, but I'm still not good enough... maybe you are?
    There is a lot of code dealing with the serial number so if you want to understand the code completely you better reserve a couple of days...

    This crack requires that you enter at least 18 characters/numbers as password!

    This 'is serial valid' function which returns 0 if not vaild and 1 or ? if valid was also used in mIRC and ACDSee. Look out for that.
     

    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