device: Add open_service() and Service API

Co-authored-by: Håvard Sørbø <havard@hsorbo.no>
This commit is contained in:
Ole André Vadla Ravnås
2024-05-29 22:53:47 +02:00
parent de55d964a0
commit 8b888558c7
9 changed files with 310 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
import frida
import pprint
device = frida.get_usb_device()
deviceinfo = device.open_service("dtx:com.apple.instruments.server.services.deviceinfo")
response = deviceinfo.request({"method": "runningProcesses"})
pprint.pp(response)
+26
View File
@@ -0,0 +1,26 @@
import frida
import sys
def on_message(message):
print("on_message:", message)
device = frida.get_usb_device()
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],
}
)
sys.stdin.read()
@@ -0,0 +1,30 @@
import frida
import sys
def on_message(message):
print("on_message:", message)
device = frida.get_usb_device()
control = device.open_service("dtx:com.apple.instruments.server.services.processcontrol")
control.on("message", on_message)
pid = control.request(
{
"method": "launchSuspendedProcessWithDevicePath:bundleIdentifier:environment:arguments:options:",
"args": [
"",
"no.oleavr.HelloIOS",
{},
[],
{
"StartSuspendedKey": False,
},
],
}
)
control.request({"method": "startObservingPid:", "args": [pid]})
print(f"App spawned, PID: {pid}. Kill it to see an example message being emitted.")
sys.stdin.read()
+14
View File
@@ -0,0 +1,14 @@
import frida
import sys
if len(sys.argv) != 2:
print(f"Usage: {sys.argv[0]} outfile.png", file=sys.stderr)
sys.exit(1)
outfile = sys.argv[1]
device = frida.get_usb_device()
screenshot = device.open_service("dtx:com.apple.instruments.server.services.screenshot")
png = screenshot.request({"method": "takeScreenshot"})
with open(outfile, "wb") as f:
f.write(png)
+28
View File
@@ -0,0 +1,28 @@
import frida
import time
def on_message(message):
print("on_message:", message)
device = frida.get_usb_device()
sysmon = device.open_service("dtx:com.apple.instruments.server.services.sysmontap")
sysmon.on("message", on_message)
sysmon.request(
{
"method": "setConfig:",
"args": [
{
"ur": 1000,
"cpuUsage": True,
"sampleInterval": 1000000000,
},
],
}
)
sysmon.request({"method": "start"})
time.sleep(5)
sysmon.request({"method": "stop"})
time.sleep(1)
+9
View File
@@ -0,0 +1,9 @@
import frida
device = frida.get_usb_device()
diag = device.open_service("plist:com.apple.mobile.diagnostics_relay")
diag.request({"type": "query", "payload": {"Request": "RSDCheckin", "ProtocolVersion": "2", "Label": "Frida"}})
diag.request({"type": "read"})
diag.request({"type": "query", "payload": {"Request": "Sleep", "WaitForDisconnect": True}})
diag.request({"type": "query", "payload": {"Request": "Goodbye"}})
+14
View File
@@ -0,0 +1,14 @@
import frida
import pprint
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": {},
}
)
pprint.pp(response)
+109
View File
@@ -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;
@@ -256,6 +257,11 @@ struct _PyBus
PyGObject parent;
};
struct _PyService
{
PyGObject parent;
};
struct _PySession
{
PyGObject parent;
@@ -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);
@@ -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);
@@ -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 }
};
@@ -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." },
@@ -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 },
@@ -2966,6 +2992,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)
{
@@ -3465,6 +3510,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)
{
@@ -5334,6 +5442,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);
+72
View File
@@ -792,6 +792,70 @@ class Bus:
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]
@@ -1019,6 +1083,14 @@ class Device:
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:
"""