<div>
<div>
<div>
<div>
<div>
<h2>Introduction</h2><p>In the last two blogs, we have discussed briefly how we can use Frida with applications, today we will cover briefly how to do that with the system binaries.</p><p>Before we can proceed with the binaries, we first need to discuss <em><b>XPC</b></em> which is used as a means of communication between processes. XPC is a type of IPC (InterProcess Communication) used on <b>*OS</b>.</p><p>According to the <a href="https://developer.apple.com/documentation/xpc?language=objc" rel="noreferrer" target="_blank">documentation</a>:</p><blockquote><p><b>XPC provides a lightweight mechanism for basic interprocess communication. </b></p></blockquote><h2>Operation modes and usage</h2><p>There exist two modes of operation:</p><ul><li><p>server</p></li><li><p>client</p></li></ul><p>In the <em>server _mode, binary creates a specific _mach service</em> and registers it with <em>launchd</em>, while in the <em>client</em> mode connects to that specific <em>mach service</em> and sends a specific message to the server.</p><p>The first function that gets called from the server and client is <code>xpc_connection_create_mach_service</code> which returns <code>xpc_connection_t</code>.</p><p>This function accepts three parameters:</p><ul><li><p>name of the service</p></li><li><p>dispatch queue (can be <em>NULL</em>)</p></li><li><p>mode (1 for the listener/server mode or 0 for the client mode)</p></li></ul><p>Once we have done this, we need to configure the handler which is actually ObjC block by calling <code>xpc_connection_set_event_handler</code>.</p><p>Parameters are:</p><ul><li><p>connection of <code>xpc_connection_t</code></p></li><li><p>handler of <code>xpc_handler_t</code></p></li></ul><p><code>xpc_handler_t</code> is a block, defined as <code>void (^xpc_handler_t)(xpc_object_t object)</code></p> </div>
</div>
</div>
</div>
</div>
<div>
<div>
<div>
<div>
<div>
<h2>Sending message</h2><p>To send the message, we first need to define from what does the message consists of. Message consists for <code>xpc_object_t</code> types where the main one being <code>xpc_dictionary</code>. </p><p><code>xpc_dictionary</code> consists of values mapped to distinct key.</p><p>The main function to create <em>xpc_dictionary</em> is <code>xpc_dictionary_create(const char *const _Nonnull *keys, xpc_object_t _Nullable const *values, size_t count)</code></p><p>Once we have created the dictionary, we can use one of the following to send the actual message:</p><ul><li><p><code>xpc_session_send_message</code> – send a message</p></li><li><p><code>xpc_session_send_message_with_reply</code> – send a message while blocking to get the reply</p></li><li><p><code>xpc_session_send_message_with_reply_async</code> – send a message with reply handler asynchronously</p></li></ul><p>Since we want over the basics of XPC, the steps for server and client are the following:</p><p><em>Server:</em></p><ol start=""><li><p>Call <code>xpc_connection_create_mach_service</code> with some specific name, while setting <code>flags</code> parameter to 1</p></li><li><p>Call <code>xpc_connection_set_event_handler</code> to setup the handler for the connections</p></li><li><p>Call <code>xpc_connection_resume</code> to resume the connection (start listening)</p></li></ol><p><em>Client:</em></p><ol start=""><li><p>Call <code>xpc_connection_create_mach_service</code> with the name used for server and setting <code>flags</code> parameter to 0</p></li><li><p>Call <code>xpc_connection_set_event_handler</code> to setup the handler for the connection</p></li><li><p>Call <code>xpc_connection_resume</code> to actually connect to the server</p></li><li><p>Craft the message </p></li><li><p>Call one of <code>xpc_session_send_message*</code> variants to send the message</p></li></ol><p>Now that we have covered that, let’s create a simple server and client using C.</p><p><strong>server.c:</strong></p> </div>
</div>
</div>
</div>
</div>
<div>
<div>
<div>
<div>
<div>
<div>
<pre>
<code>
#include <stdio.h>
#include <stdlib.h>
#include <dispatch/dispatch.h>
#include <xpc/xpc.h>
#define NAME “io.8ksec.xpc”
int main(void)
{
xpc_connection_t conn;
conn = xpc_connection_create_mach_service(NAME, NULL,
XPC_CONNECTION_MACH_SERVICE_LISTENER);
xpc_connection_set_event_handler(conn, ^(xpc_object_t peer) {
xpc_connection_set_event_handler(peer, ^(xpc_object_t event) {
if (event == XPC_ERROR_CONNECTION_INVALID) {
return;
}
if (xpc_get_type(event) != XPC_TYPE_DICTIONARY) {
return;
}
xpc_object_t resp = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(resp, "hello", "8ksec");
xpc_dictionary_set_int64(resp, "blogCount", 3);
xpc_connection_send_message(peer, resp);
});
xpc_connection_resume(peer);
});
xpc_connection_resume(conn);
dispatch_main();
}
<div>
<div>
<div>
<div>
<div>
<ul><li><p>server creates new mach service called <em>io.8ksec.xpc</em></p></li><li><p>sets up event_handler for the new connection</p></li><li><p>for each connection, sets up event handler</p></li><li><p>this event handler checks whether the type is XPC_TYPE_DICTIONARY; it is new dictionary is created</p></li><li><p>dictionary contains string <em>8ksec</em> under key <em>hello</em> and int64_t 3 under key <em>blogCount</em></p></li><li><p>sends the message to this connection</p></li><li><p>in the outside handler connection is resumed for the peer(client)</p></li><li><p>finally, connection is resumed for the entire xpc connection</p></li></ul> </div>
</div>
</div>
</div>
</div>
<div>
<div>
<div>
<div>
<div>
<div>
<pre>
<code>
#include <stdio.h>
#include <stdlib.h>
#include <xpc/xpc.h>
#define NAME “io.8ksec.xpc”
int main(void)
{
xpc_connection_t conn;
xpc_object_t msg;
msg = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(msg, "Hello", "world");
conn = xpc_connection_create_mach_service(NAME, NULL, 0);
if (conn == NULL) {
perror("xpc_connection_create_mach_service");
return (1);
}
xpc_connection_set_event_handler(conn, ^(xpc_object_t obj) {
const char * hello_value = xpc_dictionary_get_string(obj, "hello");
int64_t count_value = xpc_dictionary_get_int64(obj, "blogCount");
printf("hello=%s\n", hello_value);
printf("blogCount=%lld\n", count_value);
});
xpc_connection_resume(conn);
xpc_connection_send_message(conn, msg);
dispatch_main();
}
<div>
<div>
<div>
<div>
<div>
<ul><li><p>client creates a new dictionary with key <em>Hello</em> and value <em>world</em></p></li><li><p>connects to the mach service which is exposed by the server (<em>io.8ksec.xpc</em>)</p></li><li><p>sets up event handler for the connection where it extracts the values for the keys defined in the servers dictionary</p></li><li><p>resumes the connection</p></li><li><p>and sends the dummy message so that event handler inside the server is triggered which sends the message</p></li></ul><p>We also need to create <em>Info.plist</em> file the server which looks like this:</p> </div>
</div>
</div>
</div>
</div>
<div>
<div>
<div>
<div>
<div>
<div>
<pre>
<code>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC “-//Apple//DTD PLIST 1.0//EN” “http://www.apple.com/DTDs/PropertyList-1.0.dtd”>
<plist version=“1.0”>
<dict>
<key>CFBundleIdentifier</key>
<string>io.8ksec.xpc</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>XPCService</key>
<dict>
<key>ServiceType</key>
<string>Application</string>
</dict>
</dict>
</plist>
<div>
<div>
<div>
<div>
<div>
<p>Once we did that we will embed this file into the `__info_plist` sections inside `__TEXT` segment during compilation.</p> </div>
</div>
</div>
</div>
</div>
<div>
<div>
<div>
<div>
<div>
<img alt="" height="184" src="https://i0.wp.com/8ksec.io/wp-content/uploads/2023/07/compiling.png?fit=800%2C184&ssl=1" width="800" /> </div>
</div>
</div>
</div>
</div>
<div>
<div>
<div>
<div>
<div>
<p>Once we did that, we will add our server to the _LaunchDaemons_, to do that we need to create plist file. The plist file looks like this:</p> </div>
</div>
</div>
</div>
</div>
<div>
<div>
<div>
<div>
<div>
<img alt="" height="373" src="https://i0.wp.com/8ksec.io/wp-content/uploads/2023/07/daemon_plist.png?fit=800%2C373&ssl=1" width="800" /> </div>
</div>
</div>
</div>
</div>
<div>
<div>
<div>
<div>
<div>
<p>After loading this plist, we can try connecting to the server and we can see that we got the correct values.</p> </div>
</div>
</div>
</div>
</div>
<div>
<div>
<div>
<div>
<div>
<img alt="" height="256" src="https://i0.wp.com/8ksec.io/wp-content/uploads/2023/07/loading_daemon.png?fit=800%2C256&ssl=1" width="800" /> </div>
</div>
</div>
</div>
</div>
<div>
<div>
<div>
<div>
<div>
<p>Now that we have covered basics and showed an example of XPC server/listener and the client, let’s now use Frida to analyse a bit of some daemon on macOS.</p><p>We will create frida script that will intercept a couple of functions:</p><ul><li><p><code>xpc_connection_create_mach_service</code></p></li><li><p><code>xpc_connection_send_message</code></p></li><li><p><code>xpc_dictionary_set_string</code></p></li></ul><p>To examine the <code>xpc_object_t</code> type we can use <code>xpc_copy_description</code> which accepts <code>xpc_object_t</code> and returns the description as <code>char *</code>.</p><p>Since we went over the server/client example, we want to do the following:</p><ul><li><p>for <code>xpc_connection_create_mach_service</code> read first parameter (<code>char*</code>)</p></li><li><p><code>xpc_connection_send_message</code> has <code>xpc_object_t</code> as a second argument and we want to inspect that</p></li><li><p><code>xpc_dictionary_set_string</code> we want to inspect second and third argument as they are key and value</p></li></ul><p>We will use <code>Interceptor.attach</code> on the addresses of the function above, however we will also create <code>NativeFunction</code> using the address of <code>xpc_copy_description</code> so that we can inspect <code>xpc_object_t</code> and another <code>NativeFunction</code> using the address of <code>xpc_connection_get_name</code> to get the name of the connection. We will also create two helper function which will just read that C string (char*) and return it back to us. </p><p>The script looks like this:</p> </div>
</div>
</div>
</div>
</div>
<div>
<div>
<div>
<div>
<div>
<div>
<pre>
<code>
// Get addresses of the functions that we will intercept
var xpc_connection_create_mach_service = Module.findExportByName(null, “xpc_connection_create_mach_service”);
var xpc_connection_send_message = Module.findExportByName(null, “xpc_connection_send_message”);
var xpc_dictionary_set_string = Module.findExportByName(null, “xpc_dictionary_set_string”);
// Get address of xpc_copy_description and create new NativeFunction
// It accepts xpc_object_t and returns char *
var xpc_copy_description_addr = Module.findExportByName(null, “xpc_copy_description”);
var xpc_copy_description = new NativeFunction(xpc_copy_description_addr, “pointer”, [“pointer”]);
// Get address of xpc_connection_get_name and create new NativeFunction
// It accepts xpc_connection_t and returns char *
var xpc_connection_get_name_addr = Module.findExportByName(null, “xpc_connection_get_name”);
var xpc_connection_get_name = new NativeFunction(xpc_connection_get_name_addr, “pointer”, [“pointer”]);
// Helper function to read char *
function readCString(cstr) {
return Memory.readUtf8String(cstr);
}
/* parameters:
1. name
2. dispatch queue (not interested in this now)
3. flags (listener or client mode)
/
Interceptor.attach(xpc_connection_create_mach_service, {
onEnter(args) {
// first argument is char name and we want to read it
var serviceName = readCString(args[0]);
console.log([*] xpc_connection_create_mach_service called for service: ${serviceName}
);
}
});
/* parameters:
1. connection (xpc_connection_t)
2. message (xpc_object_t)
*/
Interceptor.attach(xpc_connection_send_message, {
onEnter(args) {
var conn = args[0];
var connName = readCString(xpc_connection_get_name(conn));
var message = args[1];
var messageDescription = readCString(xpc_copy_description(message));
console.log([*] xpc_connection_send_message(name=${connName}) called for ${conn} with description: ${messageDescription}
);
}
});
/* parameters:
1. dictionary (xpc_object_t)
2. key (char*)
3. value (char*)
*/
Interceptor.attach(xpc_dictionary_set_string, {
onEnter(args) {
var key = readCString(args[1]);
var value = readCString(args[2]);
console.log([*] xpc_dictionary_set_string called for ${key} = ${value}
);
}
});
<div>
<div>
<div>
<div>
<div>
<p>We will run this script against Signal macOS application.</p> </div>
</div>
</div>
</div>
</div>
<div>
<div>
<div>
<div>
<div>
<img alt="" height="732" src="https://i0.wp.com/8ksec.io/wp-content/uploads/2023/07/script_running_first.png?fit=800%2C732&ssl=1" width="800" /> </div>
</div>
</div>
</div>
</div>
<div>
<div>
<div>
<div>
<div>
<img alt="" height="278" src="https://i0.wp.com/8ksec.io/wp-content/uploads/2023/07/script_running_second.png?fit=800%2C278&ssl=1" width="800" /> </div>
</div>
</div>
</div>
</div>
<div>
<div>
<div>
<div>
<div>
<p>We can see that the Signal application is making a bunch of `xpc_connection_create_mach_service` function calls and sending a lot of different messages to these connections. We can go even further with this, just like the tools such as [xpcspy](<a href="https://github.com/hot3eed/xpcspy" rel="noreferrer" target="_blank">https://github.com/hot3eed/xpcspy</a>) did it and cover almost entire applications communication with XPC services.</p> </div>
</div>
</div>
</div>
</div>
<div>
<div>
<div>
<div>
<div>
<h2>References</h2><ul><li><p><a href="https://developer.apple.com/documentation/xpc?language=objc" rel="noreferrer" target="_blank">https://developer.apple.com/documentation/xpc?language=objc</a></p></li><li><p><a href="https://github.com/hot3eed/xpcspy" rel="noreferrer" target="_blank">https://github.com/hot3eed/xpcspy</a></p></li></ul><p> </p> </div>
</div>
</div>
</div>
</div>
<div>
<div>
<div>
<div>
<div>
<h2><strong>GET IN TOUCH</strong></h2><p>Visit our <a href="https://8ksec.io/ksec7.wpcomstaging.com/training" rel="noreferrer" target="_blank">training</a> page if you’re interested in learning more about these techniques and developing your abilities further. Additionally, you may look through our <a href="https://8ksec.io/ksec7.wpcomstaging.com/event-and-calendar/" rel="noreferrer" target="_blank">Events</a> page and sign up for our upcoming Public trainings. </p><p>Please don’t hesitate to reach out to us through out <a href="https://8ksec.io/ksec7.wpcomstaging.com/contact-us/" rel="noreferrer" target="_blank">Contact Us</a> page or through the Button below if you have any questions or need assistance with Penetration Testing or any other Security-related Services. We will answer in a timely manner within 1 business day.</p><p>We are always looking for talented people to join our team. Visit out <a href="https://8ksec.io/ksec7.wpcomstaging.com/careers/" rel="noreferrer" target="_blank">Careers</a> page to look at the available roles. We would love to hear from you.</p> </div>
</div>
</div>
</div>
</div>
</div><p>The post <a href="https://8ksec.io/advanced-frida-usage-part-3-inspecting-ios-xpc-calls/" rel="noreferrer" target="_blank">Advanced Frida Usage Part 3 – Inspecting XPC Calls</a> first appeared on <a href="https://8ksec.io" rel="noreferrer" target="_blank">New</a>.</p>