ChangeLog

19 April 2015

  • Updated the crack patches for ShareMouse 2.0.56.

22 December 2014

  • Updated the crack patches for 32 and 64 bit for ShareMouse 2.0.55 - instructions remain roughly the same with a few minor changes.
  • Please note that you will have to download the 2.0.55 version by going to the download section of the official website and download from the Important Notes section. If you click the big green button you will end-up with an old 2.0.54 version from CNet which will not work.

About

As a special request from mighty cracker Rob (nice name for this business), we describe the cracking procedure for Sharemouse 2. Sharemouse 2 is the next version of Sharemouse 1, the most notable features are:

  • more crass license requirements, even connecting clients will have to be licensed!
  • the timebomb via OnDemoTimer has not been eliminated!
  • now with per-connecting client limitations, fresh out of the box!

and the most notable shortcomings:

  • it still does not do relative mouse positioning and you cannot play games on a second screen with it!

Cracking this one can be done in so many ways, it feels like a test of withstanding an avalanche of decisions... Shall we attack the isRegistered function? Shall we go through and jump over the calls to isRegistered? Shall we futz with the isEmptyLicense function? Should we waste twenty hours figuring out the percentage of the entire code that is dedicated to protecting itself?

Here is one way, there are better, most likely...

Fix Serial Requirement and Max Clients

Sharemouse 2 seems to have a limit on the number of allowed connecting clients when the application is not registered. This can be observed in handleReceiveEvent. For unlicensed clients, we have:

                                       ; Basic Block Input Regs: rax r12 r13 -  Killed Regs: rdx rsi rdi
000000010001a863 488B355E350600                  mov        rsi, qword [ds:objc_sel_cmd]  ; @selector(cmd)
000000010001a86a 4C89E7                          mov        rdi, r12
000000010001a86d 41FFD5                          call       r13
000000010001a870 488B3501250600                  mov        rsi, qword [ds:objc_sel_compare_] ; @selector(compare:)
000000010001a877 488D153A980600                  lea        rdx, qword [ds:cfstring_needsn] ; @"needsn"
000000010001a87e 4889C7                          mov        rdi, rax
000000010001a881 41FFD5                          call       r13
000000010001a884 4885C0                          test       rax, rax
000000010001a887 0F8438070000                    je         0x10001afc5
...
000000010001afc5 488D3D0C910600                  lea        rdi, qword [ds:cfstring_needsn__Serial_needed_to_communicate_with_the_client] ; @"needsn: Serial needed to communicate with the client" XREF=0x10001a887

For client limits, we have:

                                       ; Basic Block Input Regs: rax r12 r13 -  Killed Regs: rdx rsi rdi
000000010001a8b7 488B350A350600                  mov        rsi, qword [ds:objc_sel_cmd]  ; @selector(cmd)
000000010001a8be 4C89E7                          mov        rdi, r12
000000010001a8c1 41FFD5                          call       r13
000000010001a8c4 488B35AD240600                  mov        rsi, qword [ds:objc_sel_compare_] ; @selector(compare:)
000000010001a8cb 488D1546980600                  lea        rdx, qword [ds:cfstring_ignoremax] ; @"ignoremax"
000000010001a8d2 4889C7                          mov        rdi, rax
000000010001a8d5 41FFD5                          call       r13
000000010001a8d8 4885C0                          test       rax, rax
000000010001a8db 0F84D6090000                    je         0x10001b2b7
...
000000010001b2b7 488D3D7A8E0600                  lea        rdi, qword [ds:cfstring_This_client_was_ignored____max_clients_reached] ; @"This client was ignored -> max clients reached" XREF=0x10001a8db
...

So we NOP the two jes in such that after the tests, the jump will not take place. For the licensed client requirement:

000000010001a863 488B355E350600                  mov        rsi, qword [ds:objc_sel_cmd]  ; @selector(cmd)
000000010001a86a 4C89E7                          mov        rdi, r12
000000010001a86d 41FFD5                          call       r13
000000010001a870 488B3501250600                  mov        rsi, qword [ds:objc_sel_compare_] ; @selector(compare:)
000000010001a877 488D153A980600                  lea        rdx, qword [ds:cfstring_needsn] ; @"needsn"
000000010001a87e 4889C7                          mov        rdi, rax
000000010001a881 41FFD5                          call       r13
000000010001a884 4885C0                          test       rax, rax
000000010001a887 90                              nop        
000000010001a888 90                              nop        
000000010001a889 90                              nop        
000000010001a88a 90                              nop        
000000010001a88b 90                              nop        
000000010001a88c 90                              nop

For the client limit, we have:

000000010001a8c4 488B35AD240600                  mov        rsi, qword [ds:objc_sel_compare_] ; @selector(compare:)
000000010001a8cb 488D1546980600                  lea        rdx, qword [ds:cfstring_ignoremax] ; @"ignoremax"
000000010001a8d2 4889C7                          mov        rdi, rax
000000010001a8d5 41FFD5                          call       r13
000000010001a8d8 4885C0                          test       rax, rax
000000010001a8db 90                              nop        
000000010001a8dc 90                              nop        
000000010001a8dd 90                              nop        
000000010001a8de 90                              nop        
000000010001a8df 90                              nop        
000000010001a8e0 90                              nop

If you want to compare the stuff in the handleReceiveEvent function, it looks something like this in code:

...
if(cmd == "needsn") {
    goto complain_about_unlicensed_clients;
}
...
if(cmd == "ignoremax") [
    goto complain_about_max_clients_reached;
}
...
complain_about_unlicensed_clients:
  nag();
...
complain_about_max_clients_reached;
 nag();

And what we do is to eliminate the jumps such that the program proceeds to the next check.

Eliminate the Demo Timer

Easy one, just return by NOPing the jump to the block that sets up the timer event:

                                       methImpl_AppController_startDemoTimer:
000000010000a758 4889FB                          mov        rbx, rdi
000000010000a75b 488D054AD30700                  lea        rax, qword [ds:_IS_BETA]
000000010000a762 8A08                            mov        cl, byte [ds:rax]
000000010000a764 488B0595600700                  mov        rax, qword [ds:_OBJC_IVAR_$_AppController.demoTimerEnabled]
000000010000a76b 0A0C03                          or         cl, byte [ds:rbx+rax]
000000010000a76e 90                              nop        
000000010000a76f 90                              nop        
                                       ; Basic Block Input Regs: rsp -  Killed Regs: rbx rbp r14
000000010000a770 5B                              pop        rbx
000000010000a771 415E                            pop        r14
000000010000a773 5D                              pop        rbp
000000010000a774 C3                              ret        
                                       ; Basic Block Input Regs: rsp rdi r8 r9 -  Killed Regs: rax rcx rdx rbx rbp rsi rdi r8 r9 r11 r14 xmm0
000000010000a775 C6040301                        mov        byte [ds:rbx+rax], 0x1        ; XREF=0x10000a76e
000000010000a779 31FF                            xor        edi, edi
000000010000a77b E82C400400                      call       imp___stubs__time
000000010000a780 89C7                            mov        edi, eax
000000010000a782 E80D400400                      call       imp___stubs__srandom
000000010000a787 4C8B35824C0700                  mov        r14, qword [ds:bind__OBJC_CLASS_$_NSTimer]
...

Eliminate Other Demo Methods

For demoExpired, jump nop the movs:

                                       ; Basic Block Input Regs: rsp -  Killed Regs: rbp
                                            methImpl_AppController_demoExpired:
0000000100003419 55                              push       rbp
000000010000341a 4889E5                          mov        rbp, rsp
000000010000341d 90                              nop        
000000010000341e 90                              nop        
000000010000341f 90                              nop        
0000000100003420 90                              nop        
0000000100003421 90                              nop        
0000000100003422 90                              nop        
0000000100003423 90                              nop        
0000000100003424 90                              nop        
0000000100003425 90                              nop        
0000000100003426 90                              nop        
0000000100003427 90                              nop        
0000000100003428 5D                              pop        rbp
0000000100003429 C3                              ret

For setDemoExpired_, jump from 0x100003437 to the function end at 0x1000034a5:

                                            methImpl_AppController_setDemoExpired_:
000000010000342a 55                              push       rbp
000000010000342b 4889E5                          mov        rbp, rsp
000000010000342e 4157                            push       r15
0000000100003430 4156                            push       r14
0000000100003432 53                              push       rbx
0000000100003433 50                              push       rax
0000000100003434 4889FB                          mov        rbx, rdi
0000000100003437 E969000000                      jmp        0x1000034a5
000000010000343c 90                              nop        
000000010000343d 90                              nop        
...
                                       ; Basic Block Input Regs: rbx r15 -  Killed Regs: rax rbx rsp rbp rdi r14 r15
00000001000034a5 4889DF                          mov        rdi, rbx                      ; XREF=0x100003437
00000001000034a8 4C89F8                          mov        rax, r15
00000001000034ab 4883C408                        add        rsp, 0x8
00000001000034af 5B                              pop        rbx
00000001000034b0 415E                            pop        r14
00000001000034b2 415F                            pop        r15
00000001000034b4 5D                              pop        rbp
00000001000034b5 FFE0                            jmp        rax

For startDemoTimer, nop the jump at 0x10000a76e:

                                       ; Basic Block Input Regs: rsp rdi -  Killed Regs: rax rcx rbx rbp r14
                                            methImpl_AppController_startDemoTimer:
000000010000a751 55                              push       rbp
000000010000a752 4889E5                          mov        rbp, rsp
000000010000a755 4156                            push       r14
000000010000a757 53                              push       rbx
000000010000a758 4889FB                          mov        rbx, rdi
000000010000a75b 488D054AD30700                  lea        rax, qword [ds:0x100087aac]
000000010000a762 8A08                            mov        cl, byte [ds:rax]
000000010000a764 488B0595600700                  mov        rax, qword [ds:0x100080800]
000000010000a76b 0A0C03                          or         cl, byte [ds:rbx+rax]
000000010000a76e 90                              nop        
000000010000a76f 90                              nop        
000000010000a770 5B                              pop        rbx
000000010000a771 415E                            pop        r14
000000010000a773 5D                              pop        rbp
000000010000a774 C3                              ret

Remove Nag Demo Strings

cfstring_str_demoaddstr gave this one away. On some of the options, a [Demo] string is appended at the end. It does not mean that the option is not functional, it is just there, to stare at you and nag you.

We remove it in optsMenuClick by jumping over the whole code-block around 0x1000162d0, then we nop the next jump that would lead to cfstring_str_demoaddstr again:

                                       ; Basic Block Input Regs: rdi -  Killed Regs: rax rbx rbp rsi rdi r15
                                            methImpl_AppController_optsMenuClick_:
0000000100016248 55                              push       rbp
...
00000001000162b9 E99A0F0000                      jmp        0x100017258
00000001000162be 488B058BA40600                  mov        rax, qword [ds:_OBJC_IVAR_$_AppController.versionEdition] ; XREF=0x100016287
00000001000162c5 8B0403                          mov        eax, dword [ds:rbx+rax]
00000001000162c8 83F802                          cmp        eax, 0x2
00000001000162cb E934010000                      jmp        0x100016404
00000001000162d0 90                              nop        
...
00000001000163bd 488D1594D50600                  lea        rdx, qword [ds:cfstring_str_demoaddstr] ; @"str_demoaddstr"
00000001000163c4 488B35A5680600                  mov        rsi, qword [ds:objc_sel_localizedStringForKey_value_table_] ; @selector(localizedStringForKey:value:table:)
00000001000163cb 4889C7                          mov        rdi, rax
00000001000163ce 4C89E1                          mov        rcx, r12
00000001000163d1 4531C0                          xor        r8d, r8d
...
0000000100016404 83F803                          cmp        eax, 0x3                      ; XREF=0x1000162cb
0000000100016407 90                              nop        
0000000100016408 90                              nop        
0000000100016409 90                              nop        
000000010001640a 90                              nop        
000000010001640b 90                              nop        
000000010001640c 90                              nop        
...

and after that NOP slide, we are safe because the next one is a jmp out of the box and over the next cfstring_str_demoaddstr.

The illustration shows the cfstring_str_demoaddstr addition before performing this slalom (left) and after performing it (right):

Remove the Register Menu Item

Since the Register menu item is now very useless, we do the same as we did with Sharemouse 1. The Register menu entry can be removed using NibUnlocker. First we ise NibUnlocker to dump the xib of Resources/English.lproj/MainMenu.nib. We can then open up the xib as a text file, and search for Register which is the item that appears on the drop-down menu.

<object class="NSMenuItem" id="49">
    <reference key="NSMenu" ref="45"/>
    <int key="NSMnemonicLoc">2147483647</int>
    <string key="NSKeyEquiv"></string>
    <string key="NSTitle">Register</string>
    <reference key="NSOnImage" ref="504"/>
    <reference key="NSMixedImage" ref="505"/>
</object>

We note that the menu entry has the ID 49, so we search the rest of the xib for ref (references) to ID 49 and remove the whole parent. In order, the blocks that have to be removed are:

<object class="NSMenuItem" id="49">
    <reference key="NSMenu" ref="45"/>
    <int key="NSMnemonicLoc">2147483647</int>
    <string key="NSKeyEquiv"></string>
    <string key="NSTitle">Register</string>
    <reference key="NSOnImage" ref="504"/>
    <reference key="NSMixedImage" ref="505"/>
</object>
...
<object class="IBConnectionRecord">
    <object class="IBOutletConnection" key="connection">
        <string key="label">regItem</string>
        <reference key="source" ref="44"/>
        <reference key="destination" ref="49"/>
    </object>
    <int key="connectionID">1641</int>
</object>
...
<object class="IBConnectionRecord">
     <object class="IBActionConnection" key="connection">
         <string key="label">registerMenuClick:</string>
         <reference key="source" ref="44"/>
         <reference key="destination" ref="49"/> 
     </object>
     <int key="connectionID">1677</int>
 </object>
...
<reference ref="49"/>
...
<object class="IBObjectRecord">
    <int key="objectID">1401</int>
    <reference key="object" ref="49"/>
    <reference key="parent" ref="45"/>
</object>

We then assemble the xib back to a nib, using the command:

ibtool --notices --output-format human-readable-text --compile MainMenu.nib MainMenu.xib

That's it, for Sharemouse 2. Happy to hear if it's working, we have not even tested it! :-D However, we can definitely confirm that when it turns out to be year 2038 A.D., Sharemouse 2 will first recommend to check for an update but will still work fine on the U.S.S. Enterprise!

Index


cracks/sharemouse/2.x.txt ยท Last modified: 2017/02/22 18:30 (external edit)

Access website using Tor


For the copyright, license, warranty and privacy terms for the usage of this website please see the license and privacy pages.