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 a 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 its implementation pseudo-code, it'll 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 and scroll through the results. You will find some isExpired
method:
Looks very promising. Maybe just return false here?
Patch jmp
and mov
in assembly:
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 is, 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 code signing 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