Grappler is a software package able to download and search movies for OSX. It allows downloading YouTube movies even with the new redesign of their webpages. The trial contains limits imposed on the number of downloads.
First check whether the application has expired is to be found in the checkRegistration
method at 0x100002878
:
methImpl_GrapplerAppDelegate_checkRegistration: 0000000100002878 55 push rbp 0000000100002879 4889E5 mov rbp, rsp 000000010000287c 4157 push r15 000000010000287e 4156 push r14 0000000100002880 53 push rbx 0000000100002881 50 push rax 0000000100002882 4989FE mov r14, rdi 0000000100002885 488B0544070400 mov rax, qword [ds:_OBJC_IVAR_$_GrapplerAppDelegate.checkedRegistration] 000000010000288c 41C6040601 mov byte [ds:r14+rax], 0x1 0000000100002891 B001 mov al, 0x1 0000000100002893 488B0D3E070400 mov rcx, qword [ds:_OBJC_IVAR_$_GrapplerAppDelegate.checkedRegistrationIsExpired] 000000010000289a 41803C0E00 cmp byte [ds:r14+rcx], 0x0 000000010000289f E9BA000000 jmp 0x10000295E ... 000000010000295e 0FB6C0 movzx eax, al ; XREF=0x10000289f 0000000100002961 4883C408 add rsp, 0x8 0000000100002965 5B pop rbx 0000000100002966 415E pop r14 0000000100002968 415F pop r15 000000010000296a 5D pop rbp 000000010000296b C3 ret
The canAnotherFileStart
method is responsible for checking whether the number of downloads has been reached. We jump over that at 0x100004e90
:
methImpl_GrapplerAppDelegate_canAnotherFileStart: 0000000100004e5c 55 push rbp 0000000100004e5d 4889E5 mov rbp, rsp 0000000100004e60 4157 push r15 0000000100004e62 4156 push r14 0000000100004e64 53 push rbx 0000000100004e65 50 push rax 0000000100004e66 4989FE mov r14, rdi 0000000100004e69 488B3540B90300 mov rsi, qword [ds:objc_sel_sharedRegistrationManager] ; @selector(sharedRegistrationManager) 0000000100004e70 488B3D59CF0300 mov rdi, qword [ds:bind__OBJC_CLASS_$_AFRegistrationManager] 0000000100004e77 488B1D92320300 mov rbx, qword [ds:imp___got__objc_msgSend] 0000000100004e7e FFD3 call rbx 0000000100004e80 488B3591BC0300 mov rsi, qword [ds:objc_sel_isRegistered] ; @selector(isRegistered) 0000000100004e87 4889C7 mov rdi, rax 0000000100004e8a FFD3 call rbx 0000000100004e8c B101 mov cl, 0x1 0000000100004e8e 84C0 test al, al 0000000100004e90 E943000000 jmp 0x100004ED8 ... 0000000100004ed8 0FB6C1 movzx eax, cl ; XREF=0x100004e90 0000000100004edb 4883C408 add rsp, 0x8 0000000100004edf 5B pop rbx 0000000100004ee0 415E pop r14 0000000100004ee2 415F pop r15 0000000100004ee4 5D pop rbp 0000000100004ee5 C3 ret
Additionally we avoid incrementing the counter in the fileDidComplete
method by jumping at 0x100004e13
:
methImpl_GrapplerAppDelegate_fileDidComplete_: 0000000100004d07 55 push rbp ... 0000000100004d61 E9AB000000 jmp 0x100004E11 0000000100004d66 90 nop 0000000100004d66 90 nop 0000000100004d67 488B3542BA0300 mov rsi, qword [ds:objc_sel_sharedRegistrationManager] ; @selector(sharedRegistrationManager) 0000000100004d6e 488B3D5BD00300 mov rdi, qword [ds:bind__OBJC_CLASS_$_AFRegistrationManager] 0000000100004d75 4C8B3594330300 mov r14, qword [ds:imp___got__objc_msgSend] 0000000100004d7c 41FFD6 call r14 0000000100004d7f 488B357ABD0300 mov rsi, qword [ds:objc_sel_incrementTrial] ; @selector(incrementTrial) ... 0000000100004e11 84DB test bl, bl ; XREF=0x100004d61 0000000100004e13 74EF je 0x100004E04
The registration frameworks to be found at Grappler.app/Contents/Frameworks/AFRegistration.framework/Versions/A/AFRegistration
contains further checks.
First, the nag screen can be avoided altogether by suppressing the showTrial
method.
methImpl_AFRegistrationWindowController_showTrial: 0000000000002f00 55 push rbp ... 0000000000002f44 488B35DD490100 mov rsi, qword [ds:objc_sel_supressNagWindow] ; @selector(supressNagWindow) 0000000000002f4b 4889C7 mov rdi, rax 0000000000002f4e 41FFD6 call r14 0000000000002f51 3C01 cmp al, 0x1 0000000000002f53 E902000000 jmp 0x2F5A 0000000000002f58 5D pop rbp 0000000000002f59 C3 ret 0000000000002f5a 488B35CF490100 mov rsi, qword [ds:objc_sel_close] ; @selector(close) XREF=0x2f53 0000000000002f61 4889DF mov rdi, rbx 0000000000002f64 5B pop rbx 0000000000002f65 415E pop r14 0000000000002f67 5D pop rbp 0000000000002f68 FF25FA100100 jmp qword [ds:imp___got__objc_msgSend]
Similarly, we avoid incrementing the trial count:
methImpl_AFRegistrationManager_incrementTrial: 000000000000577e 55 push rbp ... 00000000000057d4 E925000000 jmp 0x57FE 00000000000057d9 7523 jne 0x57FE 00000000000057db 488B05C6490100 mov rax, qword [ds:_OBJC_IVAR_$_AFRegistrationManager.delegate] 00000000000057e2 488B3C03 mov rdi, qword [ds:rbx+rax] 00000000000057e6 488B1553240100 mov rdx, qword [ds:objc_sel_registrationExpired] ; @selector(registrationExpired) 00000000000057ed 488D359C2A0100 lea rsi, qword [ds:objc_msg_respondsToSelector_] ; @selector(respondsToSelector:) 00000000000057f4 FF15962A0100 call qword [ds:objc_msg_respondsToSelector_] ; @selector(respondsToSelector:) 00000000000057fa 84C0 test al, al 00000000000057fc 750B jne 0x5809 00000000000057fe 4883C408 add rsp, 0x8 ; XREF=0x57d4, 0x57d9 0000000000005802 5B pop rbx 0000000000005803 415E pop r14 0000000000005805 415F pop r15 0000000000005807 5D pop rbp 0000000000005808 C3 ret
Finally, we set the application to never expire:
methImpl_AFRegistrationManager_isTrialExpired: 0000000000004728 55 push rbp 0000000000004729 4889E5 mov rbp, rsp 000000000000472c 4156 push r14 000000000000472e 53 push rbx 000000000000472f 4889FB mov rbx, rdi 0000000000004732 488B05775A0100 mov rax, qword [ds:_OBJC_IVAR_$_AFRegistrationManager.configuration] 0000000000004739 488B3C03 mov rdi, qword [ds:rbx+rax] 000000000000473d 488B35F4330100 mov rsi, qword [ds:objc_sel_expirationDate] ; @selector(expirationDate) 0000000000004744 FF151EF90000 call qword [ds:imp___got__objc_msgSend] 000000000000474a 30C9 xor cl, cl 000000000000474c 4885C0 test rax, rax 000000000000474f E945000000 jmp 0x4799 ... 0000000000004799 0FB6C1 movzx eax, cl ; XREF=0x474f, 0x4795 000000000000479c 5B pop rbx 000000000000479d 415E pop r14 000000000000479f 5D pop rbp 00000000000047a0 C3 ret