Using private API
The idea
I needed a little tool that could show me which app has registered a certain URL on my Mac. Since the ouput of lsregister -dump
is not quite eyecandy I decided to hack together a minimal tool that could do two things:
- show me a list of all registered URLs and their handlers
- be able to unregister a handler
Unfortunately the public API of LaunchServices doesn't help with any of these.
The rescue
Well, lsregister
can unregister apps so it's time to drop it into Hopper and start digging around. Often times this is way easier than you think. Drop lsregister into Hopper and search for unregister. You'll find a symbol _LSUnregisterURL
immediately. If you don't have Hopper available you can use nm lsregister | grep register
.
The trick
Helge Heß pointed me to a nice way of making a private function available in Swift. Basically you can load a symbol with dlsym
and then cast it to a type that has C calling convention.
private let handle = dlopen(nil, RTLD_NOW)
private let fnUnregister = dlsym(handle, "_LSUnregisterURL")
typealias fnUnregisterType = @convention(c) (CFURL) -> OSStatus
// now you can cast
let LSUnregisterURL = unsafeBitCast(fnUnregister, to: fnUnregisterType.self)
// and call the function
let result = LSUnregisterURL(url as CFURL)
The constraints
Actually you cannot run this function out of a sandbox. The obvious choice for such a tool would be to just disable the sandbox but hey: Why not wrap it in an XPCService?
The tool
If you want to check out the tool or find it useful yourself you can find it here: Schemes. Source available here: Scheme Source.