ShareKitTest: Research into injecting custom sharing services for OS X
OS X 10.8 Mountain Lion has introduced a share button as a concept. This was integrated into various applications shipping with the OS, and was exposed as a public API for application developers.
It's a very handy way to share content for users, and easy to implement for developers.
The trouble is, some of us don't use just the "proscribed" services such as Twitter or Facebook. OS X 10.9 Mavericks has introduced LinkedIn and more, but some services are sorely missing.
Note: The code was developed under OS X 10.8, which is why I am releasing it. I am uninterested in further exploration on how to write sharing plugins, since I have never went into working on the Google+ plugin that was the motivation behind the search (aside from the fact that Apple actively blocked something so trivial).
I am not a security researcher nor do I ordinarily play with defeating systems. This has piqued my interest because I was being blocked from using trivial services on my own machine. And having upgraded to 10.9, and this method still working, but me no longer being motivated to continue exploration of the APIs, I release this in hope someone else will play with it.
Hopefully, Apple will not be inspired to block people completely off. I really like the deep integration of something that works more elegantly than NeXT-style Services. Please, Apple, open ShareKit up.
OS X 10.8 has a helper process that actually provides the sharing service
to applications. Access to this helper process is provided solely through
a simple API. This is alright. What's even better is that there are bundles
.sharingservice implementing individual services.
Surely we could just implement a plugin and have it loaded by
as this entire framework is fondly named by Apple?
Of course not. If you try that, first you find out that the plugin is not
even looked for in the expected location such as
which would be analogous to where these are looked for in the System domain's
Library folder. Not wanting to dig into
/System (which is a big no-no),
you figure out that you can put the framework in
Hurray? Of course not! You get informed that:
com.apple.ShareKitHelper: --error: [ShareKit-Plugin] ShareKit plugin is not signed by Apple: file:///AppleInternal/Library/ShareKit/PlugIns/ShareKitTest.sharingservice/ com.apple.ShareKitHelper: ShareKit plugin is not signed by Apple: file:///AppleInternal/Library/ShareKit/PlugIns/ShareKitTest.sharingservice/
Thanks so much, for first not documenting this and then blocking enterprising developers and hackers from even trying to figure out how to load their own plugins. Oh well -- there must be reasons for not disclosing a way to access ShareKit.
You can use a debugger such as
lldb to attach to the
com.apple.ShareKitHelper process as soon as it launches. When it launches,
you tell the process to break as soon as it enters
you want some setup to be done and some essential frameworks to be loaded
before loading your own code.
Then you load your plugin. Inside this code, we abuse the fact that Objective-C categories override the base class methods. That is, if we extend an Objective-C class with a category (those not familiar with the language: a category is not a subclass), we actually replace the implementation of the method.
ShareKit has an interesting class
SHKServicesManager with an even more
- (BOOL)isFileSignedByAppleAtURL:(id)arg1. Accepting an
NSURL, we can trivially return
YES and every single plugin will be loaded
by ShareKitHelper. (Our plugin is already loaded, so no problem there.)
Next we have to implement a
SHKShareWindowServiceProvider. Our subclass
will return services in appropriate contexts, window controller class,
service images, etc.
We also need to implement a
SHKShareWindowController subclass, which will
contain our actual user interface.
On the xcode project
The Xcode project contains a custom 'Run Script' build step which deploys
the plugin into
/AppleInternal path. It also contains a 'shared schema'
which is configured to, before running,
killall -9 com.apple.ShareKitHelper.
Then it waits for 'something' (your click on a Share button) to run
Service should then be loaded and the Share button should show two new options, the second of which actually has some user interface.
(Looking back, I don't know why my original instructions include breaking
NSApplicationMain(). Obviously because otherwise the plugin didn't work.
However, looking at the Xcode project's configuration, obviously this is not
My research into injecting an extra service has stopped once I succeeded in injecting custom dummy services into ShareKit.
When today I was researching whether the project still works under OS X 10.9, initially it didn't work. I didn't know why; fiddling around, it started to work as if nothing happened.
Everything is an experiment created during 10.8. Apple might block off
attaching a debugger from
ShareKitHelper in the future, which is why I
still would advise people not to create finished products based on this
knowledge. You may want to keep your plugin and application and what-not
for other hackers. It's your choice, of course.
-- Ivan Vucica email@example.com - Oct 5 2013