19 April 2015
2.0.56
.22 December 2014
2.0.55
- instructions remain roughly the same with a few minor changes. 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.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:
OnDemoTimer
has not been eliminated!and the most notable shortcomings:
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…
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 je
s 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.
Easy one, just return by NOP
ing 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] ...
For demoExpired
, jump nop
the mov
s:
; 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
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):
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! 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!