Disabling Sketch license verification

Disclaimer: this article is for educational purposes only. Consider buying the license to support developers.

Sketch is a vector graphics editor for interface designers. It has demo version that works for 3 days or so. When the demo period is over, a blocking modal window appears at startup:

Let's see if we can outsmart it.

Approach #1: patching

Open Sketch executable (/Applications/Sketch.app/Contents/MacOS/Sketch) in a disassembler (I use Hopper Disassembler), search for the "trial days remaining" string, then search for references to it.

Look, some -[MSAboutWindowController refreshTrialNoteWithLicenseManager:] method was found:

It accepts void *arg2 pointer as an argument, and as the method name suggests, it must be an instance of some "license manager". That "license manager" has numberOfDaysLeftInTrialMode method:

var_48 = [arg2 retain];
[var_48 numberOfDaysLeftInTrialMode];

Open it's implementation pseudo code, it will be found in BCLicenseManager class:

So this BCLicenseManager class has license selector, that returns some license instance, which in turn has remainingTimeInterval method. If you search for implementations of remainingTimeInterval selector, two methods with the same name from different classes will be found:

Let's open the first one, which is BCRegularLicense:

Look through the pseudo code, there're many interesting methods. For instance validityInterval or isValid. Let's check what other methods does this BCRegularLicense have. Type the class name into the procedure search field, scroll through the results. You will find some isExpired method:

Looks very promising. Maybe just return false here?

Patch jmp and mov in assembly:

Before
After

Hmm. It works!

Update from Dec, 2019

Sketch also implements some kind of self-validation technique. Apparently it reads the signature of itself, and if it doesn't match its expectations it kills itself with code 173 (it literally just doing exit(173)).

Find this piece of code:

Look for references to sub_100414f20. You need to find the place where it's called.

You have to revert both conditions. In the first one, make it jump to the next instruction:

In the second, replace je with jne:

Save the patched binary (File -> Produce New Executable (select Keep Invalid Signature)), replacing the original.

Then you need to re-codesign Sketch with your certificate:

codesign --deep --force -s "YOUR INDENTITY" /Applications/Sketch.app

Then it should work. Tested with Sketch 61.

Approach #2: DYLD_INSERT_LIBRARIES

If you don't like patching binaries, you can spoof isExpired call by injecting code at runtime. To do that, you need to write a shared library that replaces method implementation and insert it into the Sketch process using DYLD_INSERT_LIBRARIES.

#import <objc/runtime.h>
#import <Foundation/Foundation.h>
#include <AppKit/AppKit.h>

@interface BCRegularLicensePatched : NSObject
- (bool)isExpired;
@end

@implementation BCRegularLicensePatched

+(void)load {
Class origClass = NSClassFromString(@"BCRegularLicense");
    Method origMethod = class_getInstanceMethod(origClass, @selector(isExpired));
    Method replMethod = class_getInstanceMethod(NSClassFromString(@"BCRegularLicensePatched"), @selector(isExpired));

    method_exchangeImplementations(origMethod, replMethod);
}

-(bool)isExpired {
    return false;
}

@end

Save this code to main.m and build as shared library:

$ gcc -dynamiclib -framework AppKit -framework Foundation main.m -o hacksketch.dylib

Unfortunately DYLD_INSERT_LIBRARIES doesn't work with SIP enabled, so in order to use this approach you need to disable SIP first. To do that, reboot to Recovery (press and hold ⌘+R at startup) and run csrutil disable in the Terminal.

Launch Sketch:

#!/bin/sh
export DYLD_INSERT_LIBRARIES=./hacksketch.dylib
/Applications/Sketch.app/Contents/MacOS/Sketch
If you have any comments, contact me by email.
powered by OpenBSD
© ch1p 2019