January 1999
 
"Linkbot Pro 4.0 Beta 1"
'memory echo/patching'
W32 PROGRAM
Code Reversing
by   N i X e
Code Reversing For Beginners

Program Details
Program Name: linkbot4.exe
Program Type: Web utility
Program Location: Here
Program Size: 4.33 Mb


Tools Used:
Softice - Win'95 Debugger
W32Dasm - Win'95 Disassembler

Rating
Easy ( X )  Medium ( )  Hard ( )  Pro ( )

 
Solving the puzzle



Introduction


LINKBOT PRO: YOUR WEBRAGE CONTROL SYSTEM

Linkbot Pro is a complete Website testing solution that can automatically scan a Website for more than fifty potential problems, generate graphical reports detailing what errors need to be fixed, and provide all the tools Web development teams need to ensure the accessibility, functionality and usability of their Websites.


About this protection system


The beta 1 is a trial version and will expire the 16th of february.
Even though this program is a trial version the registering function still works... so this is a kind of double crack me ;-)
This main focus of this tutorial is on the registration function.

To register go to the Help menu and choose Purchase...
The instructions here says: When you purchase Linkbot, Tetranet will provide you with a serial and PIN numbre that will unlock the software.

I used the following registering information:
  • User Name: NiXe NiXe
  • Company: NiXe
  • Serial#: 8888
  • PIN: 999999


  • I don't think this this information is saved at all...



    The Essay


    PART 1 - The Registration Screen


    Try to run Linkbot Pro 4.0 and enter something in the Linkbot Registration screen.
    If you get the message "Please enter an integer between 1 and 100000000" then do just that;-)
    Notice the text in the messagebox that pops up: "Sorry, your PIN number is not valid for the given serial number. Please try again". This gives us a clue about how the PIN number is generated - it's probably calculated from the serial! Write down the bad guy message.

    Create a deadlisting in W32Dasm. Among the imported dll (Dynamic Link Library) files you will find MFC42.DLL. This tell us that the program is written in Microsoft Visual C++ using Microsoft Foundation Classes (MFC). We better include this MFC42.DLL in the SoftIce.Ini file! Include MSVCRT.DLL too.
    Now find the "Sorry, your PIN number is not valid for the given serial number. Please try again" message. Study the surrounding code. Try to search for the bad guy string again. Hey, the bad guy string appears many different places! This makes analysing the deadlisting a bit more difficult because we don't know which bad guy string we got when entering our invalid registration information.
    I think it's a very good idea to disassemble, analyse and print the interesting places of a program before starting to debug with SoftIce. But in this case we need to do a little bit of debugging in SoftIce to find serial/PIN check.

    Load Linkbot into SoftIce and go to the registration screen. Enter some registration information and press Ctrl+d to enter SoftIce. Set a breakpoint at hmemcpy (bpx hmemcpy). Press Ctrl+d to continue and press the OK button.
    Now SoftIce breaks just before hmemcpy. Step into the hmemcpy with F10 until you have excuted two repz movsb instructions (that's about 31 F10's). Now ds:esi points to just after where the string was being copied from and es:edi points just after where the string was copied to. In order to see what was copied simply do a d es:edi-4 where 4 is the number of characters you'll see - if you only get the last part of your string you can increase 4 to the length of your string.
    The first data we see is our serial. Lets us follow the serial and monitor where it is read. Clear old breakpoints (bc *) and set a new breakpoint at read/write access to our serial (bpr es:edi-4 es:edi rw). If you do not remember the last 'rw' SoftIce only breaks on writes.
    Press Ctrl+d and SoftIce will break in MFC42!ORD_08f1+0074. Step with F10 past MSVCRT!strtol. Now EAX contains our serial as a number! A few lines below eax is moved to a new memory location 'MOV [ECX],EAX'. Execute the 'MOV [ECX],EAX and clear old breakpoints (bc *) and set a new breakpoint at this new memory location of our serial (bpr ecx ecx+3 rw) and press Ctrl+d again. Now we break here:

    :004596E3 E854BA0300              Call 0049513C
    :004596E8 8B03                    mov eax, dword ptr [ebx] ; WE BREAK HERE 
    :004596EA 6800E1F505              push 05F5E100		; 100000000 
    :004596EF 6A01                    push 00000001		; 1 
    :004596F1 50                      push eax		; save serial on stack
    :004596F2 56                      push esi
    :004596F3 E862BA0300              Call 0049515A		; This must be the function that checks 
    							; if our serial is between 1 and 100000000!
    

    Here we have some values being pushed before a call. To see the decimal value of the numbers in SoftIce just write ? number.
    ? 05F5E100 show the decimal value 100000000. Hex 1 is decimal 1. This must be the check to see if the serial is between 1 and 100000000. Remember the message "Please enter an integer between 1 and 100000000"?
    This is not really of interest so press Ctrl+d again. Now we break here:


    :00459786 8B4E64                  mov ecx, dword ptr [esi+64] ; 99999999 - our pin 
    :00459789 8B5660                  mov edx, dword ptr [esi+60] ; 88888888 - our serial - WE BREAK HERE
    :0045978C 51                      push ecx		; save pin on stack 
    :0045978D 52                      push edx		; save serial on stack 
    :0045978E 8D8818010000            lea ecx, dword ptr [eax+00000118] ; 5295176 
    :00459794 E89743FCFF              call 0041DB30 	; call to interesting routine  
    :00459799 83F80A                  cmp eax, 0000000A 	; compare on eax 
    :0045979C 7510                    jne 004597AE
    * Possible Reference to String Resource ID=00255: ""
    :0045979E 6AFF                    push FFFFFFFF
    :004597A0 6A00                    push 00000000
    * Possible Reference to String Resource ID=00140: "Sorry, your PIN number is not valid for the given serial num"
    :004597A2 688C000000              push 0000008C
    * Reference To: MFC42.Ordinal:04AF, Ord:04AFh
    :004597A7 E8E4B00300              Call 00494890
    :004597AC 5E                      pop esi
    :004597AD C3                      ret
    * Referenced by a (U)nconditional or (C)onditional Jump at Address: 0045979C(C)
    :004597AE 83F80E                  cmp eax, 0000000E
    :004597B1 7510                    jne 004597C3
    :004597B3 6AFF                    push FFFFFFFF
    :004597B5 6A00                    push 00000000
    * Possible Reference to String Resource ID=00272: "The serial number and PIN combination you are using is from "
    :004597B7 6810010000              push 00000110
    :004597BC E8CFB00300              Call 00494890
    :004597C1 5E                      pop esi
    :004597C2 C3                      ret
    * Referenced by a (U)nconditional or (C)onditional Jump at Address:004597B1(C)
    :004597C3 83F80B                  cmp eax, 0000000B
    :004597C6 7510                    jne 004597D8
    

    This pice of code is much more interesting. Here we have a call which has our entered serial and pin as parameters!
    After the calls we have a lot of compares on eax and some bad guy messages! We better debug this call to 0041DB30.

    Here is the complete routine at 0041DB30 with the comments I added while tracing in SoftIce with F10:


    * Referenced by a CALL at Addresses: 0041D66F ,00459794   
    :0041DB30 53                      push ebx
    :0041DB31 8B5C2408                mov ebx, dword ptr [esp+08] 	; 8888 - our serial 
    :0041DB35 55                      push ebp
    :0041DB36 56                      push esi
    :0041DB37 57                      push edi
    :0041DB38 8BF9                    mov edi, ecx
    :0041DB3A 53                      push ebx			; save serial on stack			
    :0041DB3B E860030000              call 0041DEA0			; check to see if serial is 1997, 1998,
    								; 2353, 13579 or 131313	
    :0041DB40 84C0                    test al, al
    :0041DB42 740C                    je 0041DB50
    :0041DB44 B80B000000              mov eax, 0000000B		; B = old serial return code 
    :0041DB49 5F                      pop edi
    :0041DB4A 5E                      pop esi
    :0041DB4B 5D                      pop ebp
    :0041DB4C 5B                      pop ebx
    :0041DB4D C20800                  ret 0008
    * Referenced by a (U)nconditional or (C)onditional Jump at Address: 0041DB42(C)
    :0041DB50 53                      push ebx
    :0041DB51 8BCF                    mov ecx, edi
    :0041DB53 E8480A0000              call 0041E5A0			; is serial 1900? 
    :0041DB58 84C0                    test al, al
    :0041DB5A 740C                    je 0041DB68
    :0041DB5C B80E000000              mov eax, 0000000E		; return code = E 
    :0041DB61 5F                      pop edi
    :0041DB62 5E                      pop esi
    :0041DB63 5D                      pop ebp
    :0041DB64 5B                      pop ebx
    :0041DB65 C20800                  ret 0008
    * Referenced by a (U)nconditional or (C)onditional Jump at Address: 0041DB5A(C)
    :0041DB68 8B6C2418                mov ebp, dword ptr [esp+18]	; our PIN 
    :0041DB6C 81FB40080000            cmp ebx, 00000840		; is our serial = 2112 
    :0041DB72 7514                    jne 0041DB88
    :0041DB74 81FD8E150B00            cmp ebp, 000B158E		; is our PIN 726414 
    :0041DB7A 750C                    jne 0041DB88
    :0041DB7C B80D000000              mov eax, 0000000D		; return code = D 
    :0041DB81 5F                      pop edi
    :0041DB82 5E                      pop esi
    :0041DB83 5D                      pop ebp
    :0041DB84 5B                      pop ebx
    :0041DB85 C20800                  ret 0008
    * Referenced by a (U)nconditional or (C)onditional Jump at Addresses:0041DB72(C), 0041DB7A(C)
    :0041DB88 8BC5                    mov eax, ebp			; PIN 
    :0041DB8A 53                      push ebx			; push serial 
    :0041DB8B 99                      cdq
    :0041DB8C 33C2                    xor eax, edx			; some calcualtions on PIN 
    :0041DB8E 8BCF                    mov ecx, edi
    :0041DB90 2BC2                    sub eax, edx
    :0041DB92 83E001                  and eax, 00000001
    :0041DB95 33C2                    xor eax, edx
    :0041DB97 8BF0                    mov esi, eax
    :0041DB99 2BF2                    sub esi, edx
    :0041DB9B F7DE                    neg esi
    :0041DB9D 1BF6                    sbb esi, esi
    :0041DB9F 46                      inc esi
    :0041DBA0 E84B020000              call 0041DDF0			; Generate real PIN 
    :0041DBA5 8BC8                    mov ecx, eax
    :0041DBA7 85F6                    test esi, esi
    :0041DBA9 99                      cdq
    :0041DBAA 7427                    je 0041DBD3
    :0041DBAC 33C2                    xor eax, edx
    :0041DBAE 2BC2                    sub eax, edx
    :0041DBB0 83E001                  and eax, 00000001
    :0041DBB3 33C2                    xor eax, edx
    :0041DBB5 2BC2                    sub eax, edx
    :0041DBB7 7440                    je 0041DBF9			; if PIN is a non-equal number jump to PIN compare
    :0041DBB9 51                      push ecx
    :0041DBBA 8BCF                    mov ecx, edi
    :0041DBBC E82F020000              call 0041DDF0
    :0041DBC1 8BC8                    mov ecx, eax
    :0041DBC3 99                      cdq
    :0041DBC4 33C2                    xor eax, edx
    :0041DBC6 2BC2                    sub eax, edx
    :0041DBC8 83E001                  and eax, 00000001
    :0041DBCB 33C2                    xor eax, edx
    :0041DBCD 2BC2                    sub eax, edx
    :0041DBCF 7428                    je 0041DBF9
    :0041DBD1 EB25                    jmp 0041DBF8
    * Referenced by a (U)nconditional or (C)onditional Jump at Address:0041DBAA(C)
    :0041DBD3 33C2                    xor eax, edx
    :0041DBD5 2BC2                    sub eax, edx
    :0041DBD7 83E001                  and eax, 00000001
    :0041DBDA 33C2                    xor eax, edx
    :0041DBDC 2BC2                    sub eax, edx
    :0041DBDE 7519                    jne 0041DBF9
    :0041DBE0 51                      push ecx
    :0041DBE1 8BCF                    mov ecx, edi
    :0041DBE3 E808020000              call 0041DDF0			; Generate real PIN again
    :0041DBE8 8BC8                    mov ecx, eax
    :0041DBEA 99                      cdq
    :0041DBEB 33C2                    xor eax, edx
    :0041DBED 2BC2                    sub eax, edx
    :0041DBEF 83E001                  and eax, 00000001
    :0041DBF2 33C2                    xor eax, edx
    :0041DBF4 2BC2                    sub eax, edx
    :0041DBF6 7501                    jne 0041DBF9			; if not PIN is an equal number jump to PIN compare
    * Referenced by a (U)nconditional or (C)onditional Jump at Address:0041DBD1(U)
    :0041DBF8 41                      inc ecx			; Add 1 to real PIN
    * Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
    :0041DBB7(C), :0041DBCF(C), :0041DBDE(C), :0041DBF6(C)		; PIN compare
    :0041DBF9 3BCD                    cmp ecx, ebp			; Compare REAL PIN with our fake PIN
    :0041DBFB 7503                    jne 0041DC00
    :0041DBFD 89771C                  mov dword ptr [edi+1C], esi
    * Referenced by a (U)nconditional or (C)onditional Jump at Address:0041DBFB(C)
    :0041DC00 8BC1                    mov eax, ecx
    :0041DC02 5F                      pop edi
    :0041DC03 2BC5                    sub eax, ebp
    :0041DC05 5E                      pop esi
    :0041DC06 F7D8                    neg eax
    :0041DC08 1BC0                    sbb eax, eax
    :0041DC0A 5D                      pop ebp
    :0041DC0B 24FE                    and al, FE
    :0041DC0D 5B                      pop ebx
    :0041DC0E 83C00C                  add eax, 0000000C
    :0041DC11 C20800                  ret 0008
    

    Now just exchange your fake PIN with the real PIN and press the OK button again!

    Ehh.. hmmn. When you rerun the program you are not registered:-( I hope this is due to fact that this is a trial version which expires the 16th february...?



    PART 2 - The Expiration Check


    The real protection of this program is the expiration. When the program expires you get the message "This copy of Linkbot 4.0 Beta 1 has expired..." in a messagebox!
    Set the computer's date to anything afthe the 16th february and fire up SoftIce again. Set a breakpoint at MessageBoxA. Now SoftIce break just before the expired messagebox appears. Press F12 until you are back into LINKBOT. Here I stepped with F10 until I met a ret instruction. Two F10s later I saw this:
    :0041F093 8BCE                    mov ecx, esi
    :0041F095 E8E61E0000              call 00420F80		; Display expired messagebox
    :0041F09A 85C0                    test eax, eax
    :0041F09C 7526                    jne 0041F0C4
    


    After the call eax is zero. I tried to reverse the result of test eax,eax (r fl z). Hey, now the program continues insted of quitting back to windows - but we still get the expired messagebox. Now I sat the clock back to a date before the 16th february and debugged the above code again. This time the call returned with eax=1.
    How can we allways return with eax=1 and avoid the expired messagebox? I have an idea to a patch:

    :0041F093 8BCE                    mov ecx, esi		; before the fix
    :0041F095 E8E61E0000              call 00420F80		
    :0041F09A 85C0                    test eax, eax
    :0041F09C 7526                    jne 0041F0C4
    
    :0041F093 8BCE                    mov ecx, esi		; after this fix
    :0041F095 B801000000              mov eax,1
    :0041F09A 85C0                    test eax, eax
    :0041F09C 7526                    jne 0041F0C4
    
    He he, it works. We do not call the function the display the expiration messagebox. Eax is allways 1 when the test eax,eax executes so the program allways continues as a non expired version.


    Final Notes


    I used the W32Dasm deadlisting very little for this crack.
    Including MFC42.DLL in the winice.dat was not very useful either as the functions in MFC42 is called something like MFC42!ORD_08f1...

    To crack this program you must spend quite some time in SoftIce... but hey, that's fun!

    This program compares the PINs unencrypted (as numeric values, not as strings). If the PINs had been encrypted the program would have been harder to crack.


    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.
    nbsp; ->    "