A useless sandbox issue on both macOS/iOS

You may have the experience that, when you hit media hotkey ▶️ on mac, the iTunes shows up. This hotkey is handled by process rcd:

* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x00007fff6a932420 MediaRemote`MRMediaRemoteSendCommandToApp
MediaRemote`MRMediaRemoteSendCommandToApp:
-> 0x7fff6a932420 <+0>: push rbp
0x7fff6a932421 <+1>: mov rbp, rsp
0x7fff6a932424 <+4>: sub rsp, 0x70
0x7fff6a932428 <+8>: mov rax, qword ptr [rbp + 0x10]
Target 0: (rcd) stopped.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x00007fff6a932420 MediaRemote`MRMediaRemoteSendCommandToApp
frame #1: 0x000000010d73829a rcd`HandleMediaRemoteCommand + 260
frame #2: 0x000000010d7387ff rcd`HandleHIDEvent + 736

Then the following XPC messages will be posted to mediaremoted, and the registered media player will be activated (even if not previous running).

conn: <OS_xpc_connection: <connection: 0x7f90d0304830> { name = com.apple.mediaremoted.xpc.peer.0x7f90d0304830, listener = false, pid = 2682, euid = 501, egid = 20, asid = 100008 }>
msg: <OS_xpc_dictionary: <dictionary: 0x7f90ce4097a0> { count = 2, transaction: 1, voucher = 0x7f90ce705df0, contents =
"MRXPC_NOWPLAYING_PLAYER_PATH_DATA_KEY" => <data: 0x7f90ce409860>: { length = 4 bytes, contents = 0x12020800 }
"MRXPC_MESSAGE_ID_KEY" => <uint64: 0x7f90ce4640b0>: 61461
}>
id: f015

conn: <OS_xpc_connection: <connection: 0x7f90d0304830> { name = com.apple.mediaremoted.xpc.peer.0x7f90d0304830, listener = false, pid = 2682, euid = 501, egid = 20, asid = 100008 }>
msg: <OS_xpc_dictionary: <dictionary: 0x7f90d0107d80> { count = 5, transaction: 1, voucher = 0x7f90ce705df0, contents =
"MRXPC_NOWPLAYING_PLAYER_PATH_DATA_KEY" => <data: 0x7f90d003a610>: { length = 23 bytes, contents = 0x0a150801120b6363616e742e6c6f63616c18cc86bde204 }
"MRXPC_COMMAND_KEY" => <uint64: 0x7f90d0038610>: 2
"MRXPC_MESSAGE_ID_KEY" => <uint64: 0x7f90d0035cd0>: 15728641
"MRXPC_COMMAND_OPTIONS_KEY" => <data: 0x7f90d0037a30>: { length = 359 bytes, contents = 0x62706c6973743030d401020304050607085f10356b4d524d... }
"MRXPC_COMMAND_APP_OPTIONS_KEY" => <uint64: 0x7f90d0051ed0>: 1
}>
id: f00001

This process is the one who manages the media controller

this one’s for macOS

and this is on iOS

Message will be dispatched in -[MRDMediaRemoteServer handleXPCMessage:fromClient:] according to its MRXPC_MESSAGE_ID_KEY.

v26 = xpc_dictionary_get_uint64(v28, "MRXPC_MESSAGE_ID_KEY");
v20 = v26 & 0xFFFFFFFFFF00LL;
v19 = (v26 & 0xFFFFFFFFFF00LL) - 3840;
if ( (v26 & 0xFFFFFFFFFF00LL) == 3840 )
{
v4 = "_handleServerXPCMessage:fromClient:";
objc_msgSend(v30, "_handleServerXPCMessage:fromClient:", v28, v27);
}
else
{
v18 = v20 - 0xF000;
if ( v20 == 0xF000 )
{
v4 = "handleXPCMessage:fromClient:";
objc_msgSend(*((void **)v30 + 5), "handleXPCMessage:fromClient:", v28, v27);
}
else
{
v17 = v20 - 0xF0000;
if ( v20 == 0xF0000 )
{
v4 = "handleXPCMessage:fromClient:";
objc_msgSend(*((void **)v30 + 10), "handleXPCMessage:fromClient:", v28, v27);
}
else
{
v16 = v20 - 0xF00000;
if ( v20 == 0xF00000 )
{
v4 = "handleXPCMessage:fromClient:";
objc_msgSend(*((void **)v30 + 7), "handleXPCMessage:fromClient:", v28, v27);
}
else
{
v15 = v20 - 0xF000000;
if ( v20 == 0xF000000 )
{
v4 = "handleXPCMessage:fromClient:";
objc_msgSend(*((void **)v30 + 8), "handleXPCMessage:fromClient:", v28, v27);
}

This message finally reaches here:

(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x00007fff3fbf9610 LaunchServices`LSOpenCFURLRef
frame #1: 0x00007fff5a239a86 MediaServices`MSVLaunchApplication + 127
frame #2: 0x000000010cac6bfa mediaremoted`MRDLaunchApplication + 234
frame #3: 0x000000010ca2e22f mediaremoted`-[MRDRemoteControlServer _enqueueCommand:forApplication:withCompletion:] + 1199
frame #4: 0x000000010ca2c2e0 mediaremoted`__66-[MRDRemoteControlServer _sendLocalCommand:withCompletionHandler:]_block_invoke + 2320
frame #5: 0x000000010ca32586 mediaremoted`-[MRDRemoteControlServer _shouldIgnoreCommand:completion:] + 998
frame #6: 0x000000010ca2b92b mediaremoted`-[MRDRemoteControlServer _sendLocalCommand:withCompletionHandler:] + 491
frame #7: 0x000000010ca2a690 mediaremoted`-[MRDRemoteControlServer _handleSendCommandMessage:fromClient:] + 560
frame #8: 0x000000010ca2a15f mediaremoted`-[MRDRemoteControlServer handleXPCMessage:fromClient:] + 159
frame #9: 0x000000010ca9d422 mediaremoted`-[MRDMediaRemoteServer handleXPCMessage:fromClient:] + 514
frame #10: 0x000000010cac2428 mediaremoted`-[MRDMediaRemoteClient _handleXPCMessage:] + 136

The LaunchServices api is responsible for the process creation. How about trigger this behavior programmatically?

Let’s go back to the XPC mesage payload. The MRXPC_NOWPLAYING_PLAYER_PATH_DATA_KEY is a serialized buffer of a MRNowPlayingPlayerPathProtobuf class. It has three properties that also serializable: origin, client and player.

The key is MRNowPlayingClientProtobuf, which has a bundleIdentifier getter that returns an NSString. Actually, we can pass arbitrary bundle id to make mediaremoted launch any known App.