Skip to content

Commit

Permalink
device: Add open_service() and Service API
Browse files Browse the repository at this point in the history
Co-authored-by: Håvard Sørbø <[email protected]>
  • Loading branch information
oleavr and hsorbo committed May 28, 2024
1 parent fd76674 commit 7bcd107
Show file tree
Hide file tree
Showing 3 changed files with 260 additions and 0 deletions.
79 changes: 79 additions & 0 deletions examples/open_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import frida

Check failure on line 1 in examples/open_service.py

View workflow job for this annotation

GitHub Actions / isort

Imports are incorrectly sorted and/or formatted.

device = frida.get_usb_device()

#appservice = device.open_service("xpc:com.apple.coredevice.appservice")
#response = appservice.request({
# "CoreDevice.featureIdentifier": "com.apple.coredevice.feature.listprocesses",
# "CoreDevice.action": {},
# "CoreDevice.input": {},
#})
#print("Got response:", response)

#screenshot = device.open_service("dtx:com.apple.instruments.server.services.screenshot")
#response = screenshot.request({ "method": "takeScreenshot" })
#print("Got response:", response)

#deviceinfo = device.open_service("dtx:com.apple.instruments.server.services.deviceinfo")
#response = deviceinfo.request({ "method": "runningProcesses" })
#print("Got response:", response)

#processcontrol = device.open_service("dtx:com.apple.instruments.server.services.processcontrol")
#response = processcontrol.request({
# "method": "launchSuspendedProcessWithDevicePath:bundleIdentifier:environment:arguments:options:",
# "args": [
# "",
# "no.oleavr.HelloIOS",
# {},
# [],
# {
# "StartSuspendedKey": False,
# "KillExisting": True,
# }
# ]
#})
#response = processcontrol.request({ "method": "killPid:", "args": [ 2729 ] })
#print("Got response:", response)

def on_message(message):
print("on_message:", message)

#sysmontap = device.open_service("dtx:com.apple.instruments.server.services.sysmontap")
#sysmontap.on("message", on_message)
#sysmontap.request({
# "method": "setConfig:",
# "args": [
# {
# "ur": 1000,
# "bm": 0,
# "cpuUsage": True,
# "sampleInterval": 1000000000,
# "procAttrs": [
# "cpuUsage",
# "ctxSwitch",
# "intWakeups",
# "memAnon",
# "memResidentSize",
# "memVirtualSize",
# "physFootprint",
# "pid",
# ],
# },
# ],
#})
#response = sysmontap.request({ "method": "start" })
#print("Got start() response:", response)

opengl = device.open_service("dtx:com.apple.instruments.server.services.graphics.opengl")
opengl.on("message", on_message)
opengl.request({
"method": "setSamplingRate:",
"args": [ 5.0 ],
})
opengl.request({
"method": "startSamplingAtTimeInterval:",
"args": [ 0.0 ],
})

import sys
sys.stdin.read()
109 changes: 109 additions & 0 deletions frida/_frida/extension.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ typedef struct _PySpawn PySpawn;
typedef struct _PyChild PyChild;
typedef struct _PyCrash PyCrash;
typedef struct _PyBus PyBus;
typedef struct _PyService PyService;
typedef struct _PySession PySession;
typedef struct _PyScript PyScript;
typedef struct _PyRelay PyRelay;
Expand Down Expand Up @@ -256,6 +257,11 @@ struct _PyBus
PyGObject parent;
};

struct _PyService
{
PyGObject parent;
};

struct _PySession
{
PyGObject parent;
Expand Down Expand Up @@ -397,6 +403,7 @@ static FridaSessionOptions * PyDevice_parse_session_options (const gchar * realm
static PyObject * PyDevice_inject_library_file (PyDevice * self, PyObject * args);
static PyObject * PyDevice_inject_library_blob (PyDevice * self, PyObject * args);
static PyObject * PyDevice_open_channel (PyDevice * self, PyObject * args);
static PyObject * PyDevice_open_service (PyDevice * self, PyObject * args);
static PyObject * PyDevice_unpair (PyDevice * self);

static PyObject * PyApplication_new_take_handle (FridaApplication * handle);
Expand Down Expand Up @@ -434,6 +441,11 @@ static PyObject * PyBus_new_take_handle (FridaBus * handle);
static PyObject * PyBus_attach (PySession * self);
static PyObject * PyBus_post (PyScript * self, PyObject * args, PyObject * kw);

static PyObject * PyService_new_take_handle (FridaService * handle);
static PyObject * PyService_activate (PyService * self);
static PyObject * PyService_cancel (PyService * self);
static PyObject * PyService_request (PyService * self, PyObject * args);

static PyObject * PySession_new_take_handle (FridaSession * handle);
static int PySession_init (PySession * self, PyObject * args, PyObject * kw);
static void PySession_init_from_handle (PySession * self, FridaSession * handle);
Expand Down Expand Up @@ -574,6 +586,7 @@ static PyMethodDef PyDevice_methods[] =
{ "inject_library_file", (PyCFunction) PyDevice_inject_library_file, METH_VARARGS, "Inject a library file to a PID." },
{ "inject_library_blob", (PyCFunction) PyDevice_inject_library_blob, METH_VARARGS, "Inject a library blob to a PID." },
{ "open_channel", (PyCFunction) PyDevice_open_channel, METH_VARARGS, "Open a device-specific communication channel." },
{ "open_service", (PyCFunction) PyDevice_open_service, METH_VARARGS, "Open a device-specific service." },
{ "unpair", (PyCFunction) PyDevice_unpair, METH_NOARGS, "Unpair device." },
{ NULL }
};
Expand Down Expand Up @@ -641,6 +654,14 @@ static PyMethodDef PyBus_methods[] =
{ NULL }
};

static PyMethodDef PyService_methods[] =
{
{ "activate", (PyCFunction) PyService_activate, METH_NOARGS, "Activate the service." },
{ "cancel", (PyCFunction) PyService_cancel, METH_NOARGS, "Cancel the service." },
{ "request", (PyCFunction) PyService_request, METH_VARARGS, "Perform a request." },
{ NULL }
};

static PyMethodDef PySession_methods[] =
{
{ "is_detached", (PyCFunction) PySession_is_detached, METH_NOARGS, "Query whether the session is detached." },
Expand Down Expand Up @@ -818,6 +839,11 @@ PYFRIDA_DEFINE_TYPE ("_frida.Bus", Bus, GObject, NULL, g_object_unref,
{ Py_tp_methods, PyBus_methods },
);

PYFRIDA_DEFINE_TYPE ("_frida.Service", Service, GObject, NULL, g_object_unref,
{ Py_tp_doc, "Frida Service" },
{ Py_tp_methods, PyService_methods },
);

PYFRIDA_DEFINE_TYPE ("_frida.Session", Session, GObject, PySession_init_from_handle, frida_unref,
{ Py_tp_doc, "Frida Session" },
{ Py_tp_init, PySession_init },
Expand Down Expand Up @@ -2964,6 +2990,25 @@ PyDevice_open_channel (PyDevice * self, PyObject * args)
return PyIOStream_new_take_handle (stream);
}

static PyObject *
PyDevice_open_service (PyDevice * self, PyObject * args)
{
const char * address;
GError * error = NULL;
FridaService * service;

if (!PyArg_ParseTuple (args, "s", &address))
return NULL;

Py_BEGIN_ALLOW_THREADS
service = frida_device_open_service_sync (PY_GOBJECT_HANDLE (self), address, g_cancellable_get_current (), &error);
Py_END_ALLOW_THREADS
if (error != NULL)
return PyFrida_raise (error);

return PyService_new_take_handle (service);
}

static PyObject *
PyDevice_unpair (PyDevice * self)
{
Expand Down Expand Up @@ -3463,6 +3508,69 @@ PyBus_post (PyScript * self, PyObject * args, PyObject * kw)
}


static PyObject *
PyService_new_take_handle (FridaService * handle)
{
return PyGObject_new_take_handle (handle, PYFRIDA_TYPE (Service));
}

static PyObject *
PyService_activate (PyService * self)
{
GError * error = NULL;

Py_BEGIN_ALLOW_THREADS
frida_service_activate_sync (PY_GOBJECT_HANDLE (self), g_cancellable_get_current (), &error);
Py_END_ALLOW_THREADS
if (error != NULL)
return PyFrida_raise (error);

Py_RETURN_NONE;
}

static PyObject *
PyService_cancel (PyService * self)
{
GError * error = NULL;

Py_BEGIN_ALLOW_THREADS
frida_service_cancel_sync (PY_GOBJECT_HANDLE (self), g_cancellable_get_current (), &error);
Py_END_ALLOW_THREADS
if (error != NULL)
return PyFrida_raise (error);

Py_RETURN_NONE;
}

static PyObject *
PyService_request (PyService * self, PyObject * args)
{
PyObject * result, * params;
GVariant * raw_params, * raw_result;
GError * error = NULL;

if (!PyArg_ParseTuple (args, "O", &params))
return NULL;

if (!PyGObject_unmarshal_variant (params, &raw_params))
return NULL;

Py_BEGIN_ALLOW_THREADS
raw_result = frida_service_request_sync (PY_GOBJECT_HANDLE (self), raw_params, g_cancellable_get_current (), &error);
Py_END_ALLOW_THREADS

g_variant_unref (raw_params);

if (error != NULL)
return PyFrida_raise (error);

result = PyGObject_marshal_variant (raw_result);
g_variant_unref (raw_result);

return result;
}


static PyObject *
PySession_new_take_handle (FridaSession * handle)
{
Expand Down Expand Up @@ -5332,6 +5440,7 @@ MOD_INIT (_frida)
PYFRIDA_REGISTER_TYPE (Child, FRIDA_TYPE_CHILD);
PYFRIDA_REGISTER_TYPE (Crash, FRIDA_TYPE_CRASH);
PYFRIDA_REGISTER_TYPE (Bus, FRIDA_TYPE_BUS);
PYFRIDA_REGISTER_TYPE (Service, FRIDA_TYPE_SERVICE);
PYFRIDA_REGISTER_TYPE (Session, FRIDA_TYPE_SESSION);
PYFRIDA_REGISTER_TYPE (Script, FRIDA_TYPE_SCRIPT);
PYFRIDA_REGISTER_TYPE (Relay, FRIDA_TYPE_RELAY);
Expand Down
72 changes: 72 additions & 0 deletions frida/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,70 @@ def _on_message(self, raw_message: str, data: Any) -> None:
traceback.print_exc()


ServiceCloseCallback = Callable[[], None]
ServiceMessageCallback = Callable[[Any], None]


class Service:
def __init__(self, impl: _frida.Service) -> None:
self._impl = impl

@cancellable
def activate(self) -> None:
"""
Activate the service
"""

self._impl.activate()

@cancellable
def cancel(self) -> None:
"""
Cancel the service
"""

self._impl.cancel()

def request(self, parameters: Any) -> Any:
"""
Perform a request
"""

return self._impl.request(parameters)

@overload
def on(self, signal: Literal["close"], callback: ServiceCloseCallback) -> None: ...

@overload
def on(self, signal: Literal["message"], callback: ServiceMessageCallback) -> None: ...

@overload
def on(self, signal: str, callback: Callable[..., Any]) -> None: ...

def on(self, signal: str, callback: Callable[..., Any]) -> None:
"""
Add a signal handler
"""

self._impl.on(signal, callback)

@overload
def off(self, signal: Literal["close"], callback: ServiceCloseCallback) -> None: ...

@overload
def off(self, signal: Literal["message"], callback: ServiceMessageCallback) -> None: ...

@overload
def off(self, signal: str, callback: Callable[..., Any]) -> None: ...

def off(self, signal: str, callback: Callable[..., Any]) -> None:
"""
Remove a signal handler
"""

self._impl.off(signal, callback)


DeviceSpawnAddedCallback = Callable[[_frida.Spawn], None]
DeviceSpawnRemovedCallback = Callable[[_frida.Spawn], None]
DeviceChildAddedCallback = Callable[[_frida.Child], None]
Expand Down Expand Up @@ -1019,6 +1083,14 @@ def open_channel(self, address: str) -> IOStream:

return IOStream(self._impl.open_channel(address))

@cancellable
def open_service(self, address: str) -> Service:
"""
Open a device-specific service
"""

return Service(self._impl.open_service(address))

@cancellable
def unpair(self) -> None:
"""
Expand Down

0 comments on commit 7bcd107

Please sign in to comment.