Beyond the good ol' LaunchAgents - 26 - Finder Sync Plugins

This is part 26 in the series of “Beyond the good ol’ LaunchAgents”, where I try to collect various persistence techniques for macOS. For more background check the introduction.

This method was documented very detailed by Patrick Wardle in his blogpost back in 2016. It was also covered by Leo Pitt in his Modern macOS Persistence talk, and he also made a POC, which can be found at his GitHub. With there is really nothing to add here, so this post will be only a high level summary, for everything else refer to the above resources.

Creating a Plugin

Applications can have, so called Finder Sync Extensions. It’s rather easy to create one, they can be added to any app in Xcode, by adding a new target to an existing macOS app and select Finder Sync Extension. Xcode will generate a template for us. We can either use the init function in it, or we can create a constructor function, which will be started when the plugin is loaded. Something like this (modified version of Patrick’s code):

__attribute__((constructor)) static void gogogo()
{
   NSLog(@"FINDERSYNC: extension (%s) off and running via constructor()",           [[[NSBundle mainBundle] bundlePath] UTF8String]);
}

One important item about the plugin, is that it has to be sandboxed, otherwise the system will refuse to execute it. This also means that the extension will run on its own, and not inside another process, we can find that either via Activity Monitor, or by inspecting the system log.

I made an app called FindIt.app and it has a Finder extension called FindItSync.appex. The logs clearly shows that it runs on its own.

2022-02-02 16:06:25.311466+0100 0x6c99ef   Default     0x0                  10147  0    FindItSync: FINDERSYNC: extension (/Applications/FindIt.app/Contents/PlugIns/FindItSync.appex) off and running via constructor()
2022-02-02 16:08:28.390230+0100 0x6ca688   Default     0x0                  10202  0    FindItSync: FINDERSYNC: extension (/Applications/FindIt.app/Contents/PlugIns/FindItSync.appex) off and running via constructor()

Activating the Plugin

The plugin will be recognized when we place the application on the system, however won’t be enabled. We can either do that in System Preferences -> Extensions or we can use the pluginkit process, which has com.apple.private.pluginkit.manager entitlement, as shown below.

Executable=/usr/bin/pluginkit
Identifier=com.apple.pluginkit
Format=Mach-O universal (x86_64 arm64e)
CodeDirectory v=20400 size=780 flags=0x0(none) hashes=14+7 location=embedded
Platform identifier=13
Signature size=4442
Signed Time=2021. Nov 13. 15:50:28
Info.plist=not bound
TeamIdentifier=not set
Sealed Resources=none
Internal requirements count=1 size=68
[Dict]
	[Key] com.apple.private.pluginkit.manager
	[Value]
		[Bool] true

We need to supply the tool with a path to the extension and then the bundle ID to enable it. Here is how I enabled my one:

pluginkit -a /Applications/FindIt.app/Contents/PlugIns/FindItSync.appex
pluginkit -e use -i com.csaba.fitzl.FindIt.FindItSync

That’s about this in short. For more details I highly recommend the linked resources at the beginning.