Table of Contents

About

SubEthaEdit is a collaborative coding utility for the Mac, allowing people to code in real-time by inviting them from the iChat contact list or via bonjour.

The download is a 30 day, no-limitation trial that can be patched efficiently to defeat all the protections. The application is definitely not coded with copy-protection in mind since most of the protections can be defeated by just circumventing control-flow over the isValidSerial procedures.

Attacking the Serial Check

The isValidSerial procedure is triggered at various, yet limited points around the code. It is sufficient to attack just the first few of them to defeat numerous trial and registration checks.

                                    objc_msg_isValidSerial:
001064c0                                 dd         0x000e4bde                            ; XREF=0x507f4, 0x5e3a7, 0x5e91a, 0x5ed2a, 0x5edf4, 0x5f06f

First Candidate Point

The first candidate point referred by 0x507f4 making an isValidSerial call has to do with the trial. It is a simple check, if the serial is valid, then there are no additional trial operations performed (measuring the elapsed time, etc…) and the program loads without prompting for registration.

000507f4 A1C0641000                      mov        eax, dword [ds:objc_msg_isValidSerial] ; @selector(isValidSerial)
000507f9 893C24                          mov        dword [ss:esp], edi
000507fc 89442404                        mov        dword [ss:esp+0x4], eax
00050800 E83CC20C00                      call       imp___jump_table__objc_msgSend
00050805 84C0                            test       al, al
00050807 90                              nop        
00050808 90                              nop        
00050809 8B4508                          mov        eax, dword [ss:ebp+0x8]
0005080c 8B5038                          mov        edx, dword [ds:eax+0x38]
0005080f A1885E1000                      mov        eax, dword [ds:objc_msg_setHidden_]   ; @selector(setHidden:)
00050814 C744240800000000                mov        dword [ss:esp+0x8], 0x0
0005081c 891424                          mov        dword [ss:esp], edx
0005081f 89442404                        mov        dword [ss:esp+0x4], eax
00050823 E819C20C00                      call       imp___jump_table__objc_msgSend
00050828 8B4508                          mov        eax, dword [ss:ebp+0x8]
0005082b 8B503C                          mov        edx, dword [ds:eax+0x3c]
0005082e A1C4641000                      mov        eax, dword [ds:objc_msg_setObjectValue_] ; @selector(setObjectValue:)
00050833 89742408                        mov        dword [ss:esp+0x8], esi
00050837 891424                          mov        dword [ss:esp], edx
0005083a 89442404                        mov        dword [ss:esp+0x4], eax
0005083e E8FEC10C00                      call       imp___jump_table__objc_msgSend
00050843 8B4508                          mov        eax, dword [ss:ebp+0x8]
00050846 8B5040                          mov        edx, dword [ds:eax+0x40]
00050849 895C2408                        mov        dword [ss:esp+0x8], ebx
0005084d E91B010000                      jmp        0x5096d
00050852 8B4508                          mov        eax, dword [ss:ebp+0x8]               ; XREF=0x507f2, 0x50807
00050855 8B5038                          mov        edx, dword [ds:eax+0x38]
00050858 A1885E1000                      mov        eax, dword [ds:objc_msg_setHidden_]   ; @selector(setHidden:)
0005085d C744240801000000                mov        dword [ss:esp+0x8], 0x1
00050865 891424                          mov        dword [ss:esp], edx
00050868 89442404                        mov        dword [ss:esp+0x4], eax
0005086c E8D0C10C00                      call       imp___jump_table__objc_msgSend
00050871 A1C8641000                      mov        eax, dword [ds:objc_msg_daysLeft]     ; @selector(daysLeft)

This is performed by noping the jump around 0x00050807.

Second Candidate Point

The second candidate point, referenced by 0x5e3a7 also makes an isValidSerial call and is also related to trial procedures.

005e3a7 A1C0641000                      mov        eax, dword [ds:objc_msg_isValidSerial] ; @selector(isValidSerial)
0005e3ac 891C24                          mov        dword [ss:esp], ebx
0005e3af 89442404                        mov        dword [ss:esp+0x4], eax
0005e3b3 E889E60B00                      call       imp___jump_table__objc_msgSend
0005e3b8 31D2                            xor        edx, edx
0005e3ba 84C0                            test       al, al
0005e3bc E98F030000                      jmp        0x5e750
0005e3c1 90                              nop        
0005e3c2 A14C501000                      mov        eax, dword [ds:objc_msg_alloc]        ; @selector(alloc) XREF=0x5e3a5
0005e3c7 89442404                        mov        dword [ss:esp+0x4], eax
0005e3cb A1B47F1000                      mov        eax, dword [ds:cls_NSDate]
0005e3d0 890424                          mov        dword [ss:esp], eax
0005e3d3 E869E60B00                      call       imp___jump_table__objc_msgSend
0005e3d8 8B1578681000                    mov        edx, dword [ds:objc_msg_initWithTimeIntervalSinceNow_] ; @selector(initWithTimeIntervalSinceNow:)
...
0005e750 83C43C                          add        esp, 0x3c                             ; XREF=0x5e3bc
0005e753 89D0                            mov        eax, edx
0005e755 5B                              pop        ebx
0005e756 5E                              pop        esi
0005e757 5F                              pop        edi
0005e758 C9                              leave      
0005e759 C3                              ret

In order to jump over the time interval checks, we jump at 0x0005e3bc to 0x5e750 as if the serial is valid.

Defeating the Popup On Load

The popup appears (conveniently) in the applicationDidFinishLaunching method and is easily circumvented by jumping at 0x0005231a to 0x5275a which effectively jumps over all the popups and into the start-up part of the code.

                                    meth_AppController_applicationDidFinishLaunching_:
000522f6 55                              push       ebp
000522f7 89E5                            mov        ebp, esp
000522f9 57                              push       edi
000522fa 56                              push       esi
000522fb 53                              push       ebx
000522fc 83EC3C                          sub        esp, 0x3c
000522ff A164651000                      mov        eax, dword [ds:objc_msg_shouldRun]    ; @selector(shouldRun)
00052304 8B7D08                          mov        edi, dword [ss:ebp+0x8]
00052307 89442404                        mov        dword [ss:esp+0x4], eax
0005230b A184811000                      mov        eax, dword [ds:cls_LicenseController]
00052310 890424                          mov        dword [ss:esp], eax
00052313 E829A70C00                      call       imp___jump_table__objc_msgSend
00052318 84C0                            test       al, al
0005231a E93B040000                      jmp        0x5275a
...
0005275a A178501000                      mov        eax, dword [ds:objc_msg_class]        ; @selector(class) XREF=0x5231a, 0x526ed, 0x5270b, 0x52713
0005275f 8B1DD07F1000                    mov        ebx, dword [ds:cls_TCMBEEPChannel]
00052765 89442404                        mov        dword [ss:esp+0x4], eax
00052769 A1A8811000                      mov        eax, dword [ds:cls_HandshakeProfile]
0005276e 890424                          mov        dword [ss:esp], eax
00052771 E8CBA20C00                      call       imp___jump_table__objc_msgSend
00052776 C744240CA4E00F00                mov        dword [ss:esp+0xc], 0xfe0a4           ; @"http://www.codingmonkeys.de/BEEP/SubEthaEditHandshake"

Eliminating Purchase and Registration Menu Items

The purchase and registration menu items are shown conditionally depending on whether the application is registered or not. In order to get rid of them we attack the validateMenuItem procedure and nop the jump at 0x0005546b:

                                    meth_AppController_validateMenuItem_:
0005534d 55                              push       ebp
0005534e 89E5                            mov        ebp, esp
00055350 83EC38                          sub        esp, 0x38
00055353 895DF4                          mov        dword [ss:ebp+0xfffffff4], ebx
00055356 8975F8                          mov        dword [ss:ebp+0xfffffff8], esi
00055359 8B7510                          mov        esi, dword [ss:ebp+0x10]
0005535c 897DFC                          mov        dword [ss:ebp+0xfffffffc], edi
0005535f A13C661000                      mov        eax, dword [ds:objc_msg_action]       ; @selector(action)
00055364 893424                          mov        dword [ss:esp], esi
00055367 89442404                        mov        dword [ss:esp+0x4], eax
0005536b E8D1760C00                      call       imp___jump_table__objc_msgSend
...
0005545e A148661000                      mov        eax, dword [ds:objc_msg_canUndo]      ; @selector(canUndo)
00055463 EB7B                            jmp        0x554e0
00055465 3B1D2C661000                    cmp        ebx, dword [ds:objc_msg_redo_]        ; @selector(redo:) XREF=0x553f2
0005546b 90                              nop        
0005546c 90                              nop        
0005546d 90                              nop        
0005546e 90                              nop        
0005546f 90                              nop        
00055470 90                              nop
...
000554f5 3B1D54661000                    cmp        ebx, dword [ds:objc_msg_enterSerialNumber_] ; @selector(enterSerialNumber:) XREF=0x5546b
000554fb 7408                            je         0x55505
000554fd 3B1D58661000                    cmp        ebx, dword [ds:objc_msg_purchaseSubEthaEdit_] ; @selector(purchaseSubEthaEdit:)
00055503 7512                            jne        0x55517
00055505 A164651000                      mov        eax, dword [ds:objc_msg_shouldRun]    ; @selector(shouldRun) XREF=0x554fb
0005550a 89450C                          mov        dword [ss:ebp+0xc], eax
0005550d A184811000                      mov        eax, dword [ds:cls_LicenseController]
00055512 894508                          mov        dword [ss:ebp+0x8], eax
00055515 EBCF                            jmp        0x554e6

This effectively avoids the enterSerialNumber and purchaseSubEthaEdit messages and thereby disable the registration and purchase menu.

That is it for version 2.1.3.