About

The following article demonstrates the crack procedure for ShareMouse version 3 (currently at 3.0.29). There are not many differences in procedure between version 3 and the previous instructions for 2.x.

Eliminating the Demo Timer

A persistent mistake that the ShareMouse developers make lies within the startDemoTimer function that is responsible for starting the timer that checks for expiry because it is a function coded in such a way that it can easily be disabled.

In order to do so, we nop the first jump from the demoTimerEnabled conditional:

 startDemoTimer]:
0000000100011d2f         push       rbp                                         ; Objective C Implementation defined at 0x1000932d0 (instance)
0000000100011d30         mov        rbp, rsp
0000000100011d33         push       r14
0000000100011d35         push       rbx
0000000100011d36         mov        rbx, rdi
0000000100011d39         mov        rax, qword [ds:objc_ivar_offset_AppController_demoTimerEnabled] ; objc_ivar_offset_AppController_demoTimerEnabled
0000000100011d40         lea        rcx, qword [ds:0x1000a3be4]                 ; 0x1000a3be4
0000000100011d47         mov        cl, byte [ds:rcx]
0000000100011d49         or         cl, byte [ds:rbx+rax]
; jump starts here
0000000100011d4c         nop                                                    ; don't jump, just ignore
0000000100011d4d         nop        
0000000100011d4e         pop        rbx
0000000100011d4f         pop        r14
0000000100011d51         pop        rbp
0000000100011d52         ret                                                    ; and return
; the next part starts the timer

Removing DEMO Text from Controls

The string DEMO is stored in cfstring_str_demoaddstr which gets appended to the controls once the configuration is loaded. For example, the method optsMenuClick is paved with references to cfstring_str_demoaddstr which can easily be knocked out.

There are two ways to do this:

  • following the jumping technique from the previous 2.x version.
  • knocking the code-segments that are responsible with appending the DEMO string to the controls manually.

Since the second method is too much of a bother, we will have to turn all the jumps into unconditional jumps, slaloming across the code such that we do not enter any section that contains a reference to cfstring_str_demoaddstr. We locate optsMenuClick and follow the jumps.

The first jump is:

; ...
; preamble of optsMenuClick method
; ...
000000010001fed4         mov        rax, qword [ds:objc_ivar_offset_AppController_forumBtnPrefs] ; objc_ivar_offset_AppController_forumBtnPrefs, XREF=-[AppController optsMenuClick:]+46
000000010001fedb         mov        rdi, qword [ds:rbx+rax]                     ; argument "instance" for method imp___got__objc_msgSend
000000010001fedf         lea        rax, qword [ds:0x1000a3be4]                 ; 0x1000a3be4
000000010001fee6         cmp        byte [ds:rax], 0x0
000000010001fee9         sete       al
000000010001feec         mov        rsi, qword [ds:0x10009f2f0]                 ; @selector(setHidden:), argument "selector" for method imp___got__objc_msgSend
000000010001fef3         movzx      edx, al
000000010001fef6         call       qword [ds:imp___got__objc_msgSend]
000000010001fefc         mov        rax, qword [ds:objc_ivar_offset_AppController_versionEdition] ; objc_ivar_offset_AppController_versionEdition
000000010001ff03         mov        eax, dword [ds:rbx+rax]
000000010001ff06         cmp        eax, 0x2
; we need to turn this jump into an unconditional jmp to avoid crossing into the next section that contains the DEMO string
000000010001ff09         jne        0x1000202da

Turning the last jne into a jmp and following the jump brings us into the next check (we jumped to 0x1000202da):

00000001000202da         cmp        eax, 0x3                                    ; XREF=-[AppController optsMenuClick:]+165
00000001000202dd         jne        0x100020675

Now, this jne has to be entirely removed instead of jumping like we did previously. The reason for this is that the section following this jne does not contain any reference to cfstring_str_demoaddstr and at the end of the section the code already jump to the next section. So just remove the jne:

00000001000202da         cmp        eax, 0x3                                    ; XREF=-[AppController optsMenuClick:]+165
00000001000202dd         nop        
00000001000202de         nop        
00000001000202df         nop        
00000001000202e0         nop        
00000001000202e1         nop        
00000001000202e2         nop        
; rest follows and goes up to:
000000010002066d         mov        rdi, r13
0000000100020670         jmp        0x100020eae

which is fine.

All the DEMO strings should now be removed.

Convincing the Application that It is Registered

This is a funny one - we have not done this previously with 2.x since we just wanted to manipulate flow control instead of data but let's try attacking the application's isRegistered method. The original method looks as follows:

                     -[AppController isRegistered]:
0000000100008360         push       rbp                                         ; Objective C Implementation defined at 0x100092850 (instance)
0000000100008361         mov        rbp, rsp
0000000100008364         push       r14
0000000100008366         push       rbx
0000000100008367         mov        rbx, rdi
000000010000836a         mov        r14, qword [ds:objc_ivar_offset_AppController_licenseKey] ; objc_ivar_offset_AppController_licenseKey
0000000100008371         mov        rdi, qword [ds:rbx+r14]                     ; argument "instance" for method imp___got__objc_msgSend
0000000100008375         mov        rsi, qword [ds:0x10009ef38]                 ; @selector(isEqualToString:), argument "selector" for method imp___got__objc_msgSend
000000010000837c         lea        rdx, qword [ds:cfstring_]                   ; @""
0000000100008383         call       qword [ds:imp___got__objc_msgSend]
0000000100008389         test       al, al
000000010000838b         jne        0x1000083e1
 
000000010000838d         mov        rdi, qword [ds:rbx+r14]                     ; argument "instance" for method imp___got__objc_msgSend
0000000100008391         mov        rsi, qword [ds:0x10009ef38]                 ; @selector(isEqualToString:), argument "selector" for method imp___got__objc_msgSend
0000000100008398         lea        rdx, qword [ds:cfstring_DEMO]               ; @"DEMO"
000000010000839f         call       qword [ds:imp___got__objc_msgSend]
00000001000083a5         test       al, al
00000001000083a7         jne        0x1000083e1
 
00000001000083a9         mov        rdi, qword [ds:rbx+r14]                     ; argument "instance" for method imp___got__objc_msgSend
00000001000083ad         mov        rsi, qword [ds:0x10009ef38]                 ; @selector(isEqualToString:), argument "selector" for method imp___got__objc_msgSend
00000001000083b4         lea        rdx, qword [ds:cfstring_NONE]               ; @"NONE"
00000001000083bb         call       qword [ds:imp___got__objc_msgSend]
00000001000083c1         test       al, al
00000001000083c3         jne        0x1000083e1
 
00000001000083c5         mov        rdi, qword [ds:rbx+r14]                     ; argument "instance" for method imp___got__objc_msgSend
00000001000083c9         mov        rsi, qword [ds:0x10009ef38]                 ; @selector(isEqualToString:), argument "selector" for method imp___got__objc_msgSend
00000001000083d0         lea        rdx, qword [ds:cfstring_0]                  ; @"0"
00000001000083d7         call       qword [ds:imp___got__objc_msgSend]
00000001000083dd         test       al, al
00000001000083df         je         0x1000083eb
 
00000001000083e1         xor        eax, eax                                    ; XREF=-[AppController isRegistered]+43, -[AppController isRegistered]+71, -[AppController isRegistered]+99
 
00000001000083e3         movzx      eax, al                                     ; XREF=-[AppController isRegistered]+153
00000001000083e6         pop        rbx
00000001000083e7         pop        r14
00000001000083e9         pop        rbp
00000001000083ea         ret        
 
00000001000083eb         mov        rax, qword [ds:objc_ivar_offset_AppController_isIllegal] ; objc_ivar_offset_AppController_isIllegal, XREF=-[AppController isRegistered]+127
00000001000083f2         cmp        byte [ds:rbx+rax], 0x0
00000001000083f6         sete       al
00000001000083f9         jmp        0x1000083e3

What you notice is that regardless of the jnes along the way the application will end up at 0x1000083e1 where it executes the instruction:

xor eax, eax

That instruction simply sets the return value stored in eax to zero. In other words, it is semantically equivalent to:

mov eax, 0

In hex, the instructions encoding will be the sequence 0x31 0xC0. Now we are going to make this function return 1 regardless because the application is, of course, registered.

In order to do that, lets first force a jump to the xor instruction by turning the jne into a jmp:

Registered]:
0000000100008360         push       rbp                                         ; Objective C Implementation defined at 0x100092850 (instance)
0000000100008361         mov        rbp, rsp
0000000100008364         push       r14
0000000100008366         push       rbx
0000000100008367         mov        rbx, rdi
000000010000836a         mov        r14, qword [ds:objc_ivar_offset_AppController_licenseKey] ; objc_ivar_offset_AppController_licenseKey
0000000100008371         mov        rdi, qword [ds:rbx+r14]                     ; argument "instance" for method imp___got__objc_msgSend
0000000100008375         mov        rsi, qword [ds:0x10009ef38]                 ; @selector(isEqualToString:), argument "selector" for method imp___got__objc_msgSend
000000010000837c         lea        rdx, qword [ds:cfstring_]                   ; @""
0000000100008383         call       qword [ds:imp___got__objc_msgSend]
0000000100008389         test       al, al
000000010000838b         jmp        0x1000083e1

Next, we manipulate the xor eax, eax by overwriting it with mov eax, 1:

00000001000083e1         mov        eax, 0x1                                    ; XREF=-[AppController isRegistered]+43, -[AppController isRegistered]+71, -[AppController isRegistered]+99
00000001000083e6         pop        rbx
00000001000083e7         pop        r14
00000001000083e9         pop        rbp
00000001000083ea         ret        

such that the function returns 1 instead of 0.

The effects thereof is that the Register menu item disappears, and potentially other checks along the way are knocked out.

Index


cracks/sharemouse/3.x.txt ยท Last modified: 2022/04/19 08:28 by 127.0.0.1

Access website using Tor Access website using i2p Wizardry and Steamworks PGP Key


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