Compare commits

...

42 Commits

Author SHA1 Message Date
Ole André Vadla Ravnås facd6756b2 subprojects: Prepare for release 2024-07-05 15:32:51 +02:00
Ole André Vadla Ravnås f29f486c0d subprojects: Bump outdated 2024-07-05 15:32:13 +02:00
Ole André Vadla Ravnås 2135414777 subprojects: Bump outdated 2024-07-05 15:26:38 +02:00
Ole André Vadla Ravnås ba032180c6 subprojects: Bump outdated 2024-07-04 13:51:07 +02:00
Ole André Vadla Ravnås b29cbcd499 subprojects: Bump outdated 2024-07-04 11:27:12 +02:00
Ole André Vadla Ravnås 55cdadea6a subprojects: Bump outdated 2024-07-03 23:20:23 +02:00
Ole André Vadla Ravnås 17d39c725c submodules: Bump releng 2024-07-03 23:20:23 +02:00
Ole André Vadla Ravnås 72f1d651b6 examples: Add XPC application launching example
Co-authored-by: Håvard Sørbø <havard@hsorbo.no>
2024-07-03 22:33:48 +02:00
Ole André Vadla Ravnås 6d5c64d215 examples: Rename xpc.py to xpc/listprocesses.py
Co-authored-by: Håvard Sørbø <havard@hsorbo.no>
2024-07-03 22:33:44 +02:00
Ole André Vadla Ravnås 2b5f6492a2 extension: Support unmarshaling tuples to GVariant
Co-authored-by: Håvard Sørbø <havard@hsorbo.no>
2024-07-03 22:33:40 +02:00
Ole André Vadla Ravnås 316f88974d extension: Fix unmarshaling of bool to GVariant
A bool also satisfies PyLong_Check(), so we need to PyBool_Check() first.

Co-authored-by: Håvard Sørbø <havard@hsorbo.no>
2024-07-03 22:33:40 +02:00
Ole André Vadla Ravnås fee73e852b extension: Drop PyFrida_is_string()
Now that it does nothing special as we no longer support Python 2.

Co-authored-by: Håvard Sørbø <havard@hsorbo.no>
2024-07-03 22:33:40 +02:00
Ole André Vadla Ravnås 37847fd8c9 subprojects: Prepare for release 2024-06-04 14:14:47 +02:00
Ole André Vadla Ravnås 7158638eb9 subprojects: Bump outdated 2024-06-04 14:12:52 +02:00
Ole André Vadla Ravnås 77d9c51109 subprojects: Prepare for release 2024-06-04 13:41:17 +02:00
Ole André Vadla Ravnås 040fa5536b subprojects: Bump outdated 2024-06-04 13:38:55 +02:00
Ole André Vadla Ravnås c9226b976a examples: Fix the open_service() plist example
Co-authored-by: Håvard Sørbø <havard@hsorbo.no>
2024-06-04 12:36:37 +02:00
Ole André Vadla Ravnås d851e4eb6a subprojects: Prepare for release 2024-05-31 22:52:28 +02:00
Ole André Vadla Ravnås ccea05e00b subprojects: Bump outdated 2024-05-31 22:51:00 +02:00
Ole André Vadla Ravnås 6416edc773 subprojects: Prepare for release 2024-05-31 15:42:55 +02:00
Ole André Vadla Ravnås ce718c1dc9 subprojects: Bump outdated 2024-05-31 15:41:48 +02:00
Ole André Vadla Ravnås 0b854499cd rpc: Fix type hints for make_rpc_call_request()
Co-authored-by: Håvard Sørbø <havard@hsorbo.no>
2024-05-31 15:40:22 +02:00
Ole André Vadla Ravnås 243cce22e6 rpc: Add support for new binary data passing
Which means:
- Pass in data to RPC method.
- Return value and data from RPC method.

Co-authored-by: Håvard Sørbø <havard@hsorbo.no>
2024-05-31 15:11:05 +02:00
Ole André Vadla Ravnås c4d0fe55a5 subprojects: Bump outdated 2024-05-31 06:45:52 +02:00
Ole André Vadla Ravnås f3d767ecb6 submodules: Bump releng 2024-05-31 06:45:51 +02:00
Ole André Vadla Ravnås 8838d885ce _frida: Add missing type hints 2024-05-30 23:45:06 +02:00
Ole André Vadla Ravnås 213e373056 examples: Fix import ordering 2024-05-30 23:35:00 +02:00
Ole André Vadla Ravnås 8b888558c7 device: Add open_service() and Service API
Co-authored-by: Håvard Sørbø <havard@hsorbo.no>
2024-05-30 23:28:36 +02:00
Ole André Vadla Ravnås de55d964a0 extension: Support marshaling uint64 GVariant
Co-authored-by: Håvard Sørbø <havard@hsorbo.no>
2024-05-30 23:28:36 +02:00
Ole André Vadla Ravnås e920bad7f5 extension: Support marshaling double to/from GVariant
Co-authored-by: Håvard Sørbø <havard@hsorbo.no>
2024-05-30 23:28:36 +02:00
Ole André Vadla Ravnås 2b947e6d75 extension: Refactor the variant marshaling logic
Co-authored-by: Håvard Sørbø <havard@hsorbo.no>
2024-05-30 23:28:36 +02:00
Ole André Vadla Ravnås 9992e8ad7a extension: Support marshaling GVariant arrays of variant
Co-authored-by: Håvard Sørbø <havard@hsorbo.no>
2024-05-30 23:28:36 +02:00
Ole André Vadla Ravnås 3c7eb89653 extension: Support unmarshaling more types to GVariant
Co-authored-by: Håvard Sørbø <havard@hsorbo.no>
2024-05-30 23:28:36 +02:00
Ole André Vadla Ravnås 16f1be2a88 subprojects: Bump outdated 2024-05-30 21:59:09 +02:00
Ole André Vadla Ravnås 280c6d73f3 subprojects: Bump outdated 2024-05-30 21:50:49 +02:00
Ole André Vadla Ravnås 140dc6d13a subprojects: Bump outdated 2024-05-30 21:42:41 +02:00
Ole André Vadla Ravnås eac203e327 subprojects: Bump outdated 2024-05-30 20:52:08 +02:00
Ole André Vadla Ravnås bc3429a80d submodules: Bump releng 2024-05-30 20:52:08 +02:00
Ole André Vadla Ravnås e929477ecd subprojects: Prepare for release 2024-05-21 12:50:37 +02:00
Ole André Vadla Ravnås ebeb7a86b1 subprojects: Bump outdated 2024-05-21 12:49:09 +02:00
Ole André Vadla Ravnås 458a1f055a subprojects: Prepare for release 2024-05-20 22:54:32 +02:00
Ole André Vadla Ravnås de0b1643de subprojects: Bump outdated 2024-05-20 22:53:43 +02:00
14 changed files with 672 additions and 117 deletions
+9
View File
@@ -0,0 +1,9 @@
import pprint
import frida
device = frida.get_usb_device()
deviceinfo = device.open_service("dtx:com.apple.instruments.server.services.deviceinfo")
response = deviceinfo.request({"method": "runningProcesses"})
pprint.pp(response)
+27
View File
@@ -0,0 +1,27 @@
import sys
import frida
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,31 @@
import sys
import frida
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()
+15
View File
@@ -0,0 +1,15 @@
import sys
import frida
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)
+29
View File
@@ -0,0 +1,29 @@
import time
import frida
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)
+7
View File
@@ -0,0 +1,7 @@
import frida
device = frida.get_usb_device()
diag = device.open_service("plist:com.apple.mobile.diagnostics_relay")
diag.request({"type": "query", "payload": {"Request": "Sleep", "WaitForDisconnect": True}})
diag.request({"type": "query", "payload": {"Request": "Goodbye"}})
@@ -0,0 +1,64 @@
import pprint
import sys
from threading import Thread
import frida
def main():
device = frida.get_usb_device()
stdout_uuid, stdout_stream = create_stdio_socket(device)
stderr_uuid, stderr_stream = create_stdio_socket(device)
appservice = device.open_service("xpc:com.apple.coredevice.appservice")
response = appservice.request(
{
"CoreDevice.featureIdentifier": "com.apple.coredevice.feature.launchapplication",
"CoreDevice.action": {},
"CoreDevice.input": {
"applicationSpecifier": {
"bundleIdentifier": {"_0": "no.oleavr.HelloIOS"},
},
"options": {
"arguments": [],
"environmentVariables": {},
"standardIOUsesPseudoterminals": True,
"startStopped": False,
"terminateExisting": True,
"user": {"active": True},
"platformSpecificOptions": b'<?xml version="1.0" encoding="UTF-8"?><plist version="1.0"><dict/></plist>',
},
"standardIOIdentifiers": {
"standardOutput": ("uuid", stdout_uuid),
"standardError": ("uuid", stderr_uuid),
},
},
}
)
pprint.pp(response)
workers = set()
for stream, sink in {(stdout_stream, sys.stdout), (stderr_stream, sys.stderr)}:
t = Thread(target=process_console_output, args=(stream, sink))
t.start()
workers.add(t)
for worker in workers:
worker.join()
def create_stdio_socket(device):
stream = device.open_channel("tcp:com.apple.coredevice.openstdiosocket")
return (stream.read_all(16), stream)
def process_console_output(stream, sink):
while True:
chunk = stream.read(4096)
if not chunk:
break
sink.write(chunk.decode("utf-8"))
if __name__ == "__main__":
main()
@@ -0,0 +1,15 @@
import pprint
import frida
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)
+25
View File
@@ -342,6 +342,12 @@ class Device(Object):
"""
...
def open_service(self, address: str) -> Service:
"""
Open a device-specific service.
"""
...
def unpair(self) -> None:
"""
Unpair device.
@@ -629,6 +635,25 @@ class Script(Object):
"""
...
class Service(Object):
def activate(self) -> None:
"""
Activate the service.
"""
...
def cancel(self) -> None:
"""
Cancel the service.
"""
...
def request(self, parameters: Any) -> Any:
"""
Perform a request.
"""
...
class Session(Object):
@property
def pid(self) -> int:
+329 -94
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2013-2023 Ole André Vadla Ravnås <oleavr@nowsecure.com>
* Copyright (C) 2024 Håvard Sørbø <havard@hsorbo.no>
*
* Licence: wxWindows Library Licence, Version 3.1
*/
@@ -148,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;
@@ -255,6 +257,11 @@ struct _PyBus
PyGObject parent;
};
struct _PyService
{
PyGObject parent;
};
struct _PySession
{
PyGObject parent;
@@ -349,7 +356,12 @@ static gboolean PyGObject_unmarshal_enum (const gchar * str, GType type, gpointe
static PyObject * PyGObject_marshal_bytes (GBytes * bytes);
static PyObject * PyGObject_marshal_bytes_non_nullable (GBytes * bytes);
static PyObject * PyGObject_marshal_variant (GVariant * variant);
static PyObject * PyGObject_marshal_variant_byte_array (GVariant * variant);
static PyObject * PyGObject_marshal_variant_dict (GVariant * variant);
static PyObject * PyGObject_marshal_variant_array (GVariant * variant);
static gboolean PyGObject_unmarshal_variant (PyObject * value, GVariant ** variant);
static gboolean PyGObject_unmarshal_variant_from_mapping (PyObject * mapping, GVariant ** variant);
static gboolean PyGObject_unmarshal_variant_from_sequence (PyObject * sequence, GVariant ** variant);
static PyObject * PyGObject_marshal_parameters_dict (GHashTable * dict);
static PyObject * PyGObject_marshal_socket_address (GSocketAddress * address);
static gboolean PyGObject_unmarshal_certificate (const gchar * str, GTlsCertificate ** certificate);
@@ -391,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);
@@ -428,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);
@@ -528,7 +546,6 @@ static void PyCancellable_destroy_callback (PyObject * callback);
static PyObject * PyCancellable_cancel (PyCancellable * self);
static PyObject * PyFrida_raise (GError * error);
static gboolean PyFrida_is_string (PyObject * obj);
static gchar * PyFrida_repr (PyObject * obj);
static guint PyFrida_get_max_argument_count (PyObject * callable);
@@ -568,6 +585,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 }
};
@@ -635,6 +653,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." },
@@ -812,6 +838,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 },
@@ -1594,130 +1625,257 @@ PyGObject_marshal_bytes_non_nullable (GBytes * bytes)
static PyObject *
PyGObject_marshal_variant (GVariant * variant)
{
if (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING))
return PyGObject_marshal_string (g_variant_get_string (variant, NULL));
if (g_variant_is_of_type (variant, G_VARIANT_TYPE_INT64))
return PyLong_FromLongLong (g_variant_get_int64 (variant));
if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN))
return PyBool_FromLong (g_variant_get_boolean (variant));
if (g_variant_is_of_type (variant, G_VARIANT_TYPE ("ay")))
switch (g_variant_classify (variant))
{
gconstpointer elements;
gsize n_elements;
case G_VARIANT_CLASS_STRING:
return PyGObject_marshal_string (g_variant_get_string (variant, NULL));
case G_VARIANT_CLASS_INT64:
return PyLong_FromLongLong (g_variant_get_int64 (variant));
case G_VARIANT_CLASS_UINT64:
return PyLong_FromLongLong (g_variant_get_uint64 (variant));
case G_VARIANT_CLASS_DOUBLE:
return PyFloat_FromDouble (g_variant_get_double (variant));
case G_VARIANT_CLASS_BOOLEAN:
return PyBool_FromLong (g_variant_get_boolean (variant));
case G_VARIANT_CLASS_ARRAY:
if (g_variant_is_of_type (variant, G_VARIANT_TYPE ("ay")))
return PyGObject_marshal_variant_byte_array (variant);
elements = g_variant_get_fixed_array (variant, &n_elements, sizeof (guint8));
if (g_variant_is_of_type (variant, G_VARIANT_TYPE_VARDICT))
return PyGObject_marshal_variant_dict (variant);
return PyBytes_FromStringAndSize (elements, n_elements);
}
if (g_variant_is_of_type (variant, G_VARIANT_TYPE_VARDICT))
{
PyObject * dict;
GVariantIter iter;
gchar * key;
GVariant * raw_value;
dict = PyDict_New ();
g_variant_iter_init (&iter, variant);
while (g_variant_iter_next (&iter, "{sv}", &key, &raw_value))
{
PyObject * value = PyGObject_marshal_variant (raw_value);
PyDict_SetItemString (dict, key, value);
Py_DECREF (value);
g_variant_unref (raw_value);
g_free (key);
}
return dict;
}
if (g_variant_is_of_type (variant, G_VARIANT_TYPE_ARRAY))
{
GVariantIter iter;
PyObject * list;
guint i;
GVariant * child;
g_variant_iter_init (&iter, variant);
list = PyList_New (g_variant_iter_n_children (&iter));
for (i = 0; (child = g_variant_iter_next_value (&iter)) != NULL; i++)
{
PyList_SetItem (list, i, PyGObject_marshal_variant (child));
g_variant_unref (child);
}
return list;
return PyGObject_marshal_variant_array (variant);
default:
break;
}
Py_RETURN_NONE;
}
static PyObject *
PyGObject_marshal_variant_byte_array (GVariant * variant)
{
gconstpointer elements;
gsize n_elements;
elements = g_variant_get_fixed_array (variant, &n_elements, sizeof (guint8));
return PyBytes_FromStringAndSize (elements, n_elements);
}
static PyObject *
PyGObject_marshal_variant_dict (GVariant * variant)
{
PyObject * dict;
GVariantIter iter;
gchar * key;
GVariant * raw_value;
dict = PyDict_New ();
g_variant_iter_init (&iter, variant);
while (g_variant_iter_next (&iter, "{sv}", &key, &raw_value))
{
PyObject * value = PyGObject_marshal_variant (raw_value);
PyDict_SetItemString (dict, key, value);
Py_DECREF (value);
g_variant_unref (raw_value);
g_free (key);
}
return dict;
}
static PyObject *
PyGObject_marshal_variant_array (GVariant * variant)
{
GVariantIter iter;
PyObject * list;
guint i;
GVariant * child;
g_variant_iter_init (&iter, variant);
list = PyList_New (g_variant_iter_n_children (&iter));
for (i = 0; (child = g_variant_iter_next_value (&iter)) != NULL; i++)
{
if (g_variant_is_of_type (child, G_VARIANT_TYPE_VARIANT))
{
GVariant * inner = g_variant_get_variant (child);
g_variant_unref (child);
child = inner;
}
PyList_SetItem (list, i, PyGObject_marshal_variant (child));
g_variant_unref (child);
}
return list;
}
static gboolean
PyGObject_unmarshal_variant (PyObject * value, GVariant ** variant)
{
if (PyFrida_is_string (value))
if (PyUnicode_Check (value))
{
gchar * str;
PyGObject_unmarshal_string (value, &str);
*variant = g_variant_new_take_string (str);
return TRUE;
}
else if (PyBool_Check (value))
if (PyBool_Check (value))
{
*variant = g_variant_new_boolean (value == Py_True);
}
#if PY_MAJOR_VERSION < 3
else if (PyUnicode_Check (value))
{
PyObject * value_utf8;
value_utf8 = PyUnicode_AsUTF8String (value);
if (value_utf8 == NULL)
goto propagate_error;
*variant = g_variant_new_string (PyBytes_AsString (value_utf8));
Py_DECREF (value_utf8);
return TRUE;
}
else if (PyInt_Check (value))
{
*variant = g_variant_new_int64 (PyInt_AS_LONG (value));
}
#endif
else if (PyLong_Check (value))
if (PyLong_Check (value))
{
PY_LONG_LONG l;
l = PyLong_AsLongLong (value);
if (l == -1 && PyErr_Occurred ())
goto propagate_error;
return FALSE;
*variant = g_variant_new_int64 (l);
return TRUE;
}
else
if (PyFloat_Check (value))
{
goto unsupported_type;
*variant = g_variant_new_double (PyFloat_AsDouble (value));
return TRUE;
}
if (PyBytes_Check (value))
{
char * buffer;
Py_ssize_t length;
gpointer copy;
PyBytes_AsStringAndSize (value, &buffer, &length);
copy = g_memdup2 (buffer, length);
*variant = g_variant_new_from_data (G_VARIANT_TYPE_BYTESTRING, copy, length, TRUE, g_free, copy);
return TRUE;
}
if (PySequence_Check (value))
return PyGObject_unmarshal_variant_from_sequence (value, variant);
if (PyMapping_Check (value))
return PyGObject_unmarshal_variant_from_mapping (value, variant);
PyErr_SetString (PyExc_TypeError, "unsupported type");
return FALSE;
}
static gboolean
PyGObject_unmarshal_variant_from_mapping (PyObject * mapping, GVariant ** variant)
{
GVariantBuilder builder;
PyObject * items = NULL;
Py_ssize_t n, i;
g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
items = PyMapping_Items (mapping);
if (items == NULL)
goto propagate_error;
n = PyList_Size (items);
for (i = 0; i != n; i++)
{
PyObject * pair, * key, * val, * key_bytes;
GVariant * raw_value;
pair = PyList_GetItem (items, i);
key = PyTuple_GetItem (pair, 0);
val = PyTuple_GetItem (pair, 1);
if (!PyGObject_unmarshal_variant (val, &raw_value))
goto propagate_error;
key_bytes = PyUnicode_AsUTF8String (key);
g_variant_builder_add (&builder, "{sv}", PyBytes_AsString (key_bytes), raw_value);
Py_DECREF (key_bytes);
}
Py_DecRef (items);
*variant = g_variant_builder_end (&builder);
return TRUE;
unsupported_type:
{
PyErr_SetString (PyExc_TypeError, "unsupported type");
goto propagate_error;
}
propagate_error:
{
Py_XDECREF (items);
g_variant_builder_clear (&builder);
return FALSE;
}
}
static gboolean
PyGObject_unmarshal_variant_from_sequence (PyObject * sequence, GVariant ** variant)
{
gboolean is_tuple;
GVariantBuilder builder;
Py_ssize_t n, i;
PyObject * val = NULL;
is_tuple = PyTuple_Check (sequence);
g_variant_builder_init (&builder, is_tuple ? G_VARIANT_TYPE_TUPLE : G_VARIANT_TYPE ("av"));
n = PySequence_Length (sequence);
if (n == -1)
goto propagate_error;
for (i = 0; i != n; i++)
{
GVariant * raw_value;
val = PySequence_GetItem (sequence, i);
if (val == NULL)
goto propagate_error;
if (!PyGObject_unmarshal_variant (val, &raw_value))
goto propagate_error;
if (is_tuple)
g_variant_builder_add_value (&builder, raw_value);
else
g_variant_builder_add (&builder, "v", raw_value);
Py_DECREF (val);
}
*variant = g_variant_builder_end (&builder);
return TRUE;
propagate_error:
{
Py_XDECREF (val);
g_variant_builder_clear (&builder);
return FALSE;
}
}
@@ -2839,6 +2997,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)
{
@@ -3338,6 +3515,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)
{
@@ -5116,12 +5356,6 @@ PyFrida_raise (GError * error)
return NULL;
}
static gboolean
PyFrida_is_string (PyObject * obj)
{
return PyUnicode_Check (obj);
}
static gchar *
PyFrida_repr (PyObject * obj)
{
@@ -5207,6 +5441,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);
+98 -13
View File
@@ -176,7 +176,8 @@ class ScriptExportsSync:
js_name = _to_camel_case(name)
def method(*args: Any, **kwargs: Any) -> Any:
return script._rpc_request("call", js_name, args, **kwargs)
request, data = make_rpc_call_request(js_name, args)
return script._rpc_request(request, data, **kwargs)
return method
@@ -202,7 +203,8 @@ class ScriptExportsAsync:
js_name = _to_camel_case(name)
async def method(*args: Any, **kwargs: Any) -> Any:
return await script._rpc_request_async("call", js_name, args, **kwargs)
request, data = make_rpc_call_request(js_name, args)
return await script._rpc_request_async(request, data, **kwargs)
return method
@@ -210,6 +212,16 @@ class ScriptExportsAsync:
return self._script.list_exports_sync()
def make_rpc_call_request(js_name: str, args: Sequence[Any]) -> Tuple[List[Any], Optional[bytes]]:
if args and isinstance(args[-1], bytes):
raw_args = args[:-1]
data = args[-1]
else:
raw_args = args
data = None
return (["call", js_name, raw_args], data)
class ScriptErrorMessage(TypedDict):
type: Literal["error"]
description: str
@@ -404,7 +416,7 @@ class Script:
Asynchronously list all the exported attributes from the script's rpc
"""
result = await self._rpc_request_async("list")
result = await self._rpc_request_async(["list"])
assert isinstance(result, list)
return result
@@ -413,7 +425,7 @@ class Script:
List all the exported attributes from the script's rpc
"""
result = self._rpc_request("list")
result = self._rpc_request(["list"])
assert isinstance(result, list)
return result
@@ -429,7 +441,7 @@ class Script:
)
return self.list_exports_sync()
def _rpc_request_async(self, *args: Any) -> asyncio.Future[Any]:
def _rpc_request_async(self, args: Any, data: Optional[bytes] = None) -> asyncio.Future[Any]:
loop = asyncio.get_event_loop()
future: asyncio.Future[Any] = asyncio.Future()
@@ -442,14 +454,14 @@ class Script:
request_id = self._append_pending(on_complete)
if not self.is_destroyed:
self._send_rpc_call(request_id, *args)
self._send_rpc_call(request_id, args, data)
else:
self._on_destroyed()
return future
@cancellable
def _rpc_request(self, *args: Any) -> Any:
def _rpc_request(self, args: Any, data: Optional[bytes] = None) -> Any:
result = RPCResult()
def on_complete(value: Any, error: Optional[Union[RPCException, _frida.InvalidOperationError]]) -> None:
@@ -466,7 +478,7 @@ class Script:
request_id = self._append_pending(on_complete)
if not self.is_destroyed:
self._send_rpc_call(request_id, *args)
self._send_rpc_call(request_id, args, data)
cancellable = Cancellable.get_current()
cancel_handler = cancellable.connect(on_cancelled)
@@ -495,10 +507,8 @@ class Script:
self._pending[request_id] = callback
return request_id
def _send_rpc_call(self, request_id: int, *args: Any) -> None:
message = ["frida:rpc", request_id]
message.extend(args)
self.post(message)
def _send_rpc_call(self, request_id: int, args: Any, data: Optional[bytes]) -> None:
self.post(["frida:rpc", request_id, *args], data)
def _on_rpc_message(self, request_id: int, operation: str, params: List[Any], data: Optional[Any]) -> None:
if operation in ("ok", "error"):
@@ -509,7 +519,10 @@ class Script:
value = None
error = None
if operation == "ok":
value = params[0] if data is None else data
if data is not None:
value = (params[1], data) if len(params) > 1 else data
else:
value = params[0]
else:
error = RPCException(*params[0:3])
@@ -792,6 +805,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 +1096,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:
"""
+1 -1
Submodule releng updated: 6bad5eec71...54cc29651c
+1 -1
View File
@@ -1,6 +1,6 @@
[wrap-git]
url = https://github.com/frida/frida-core.git
revision = 16.2.3
revision = 16.4.0
depth = 1
[provide]
+21 -8
View File
@@ -31,19 +31,26 @@ class TestRpc(unittest.TestCase):
name="test-rpc",
source="""\
rpc.exports = {
add: function (a, b) {
var result = a + b;
add(a, b) {
const result = a + b;
if (result < 0)
throw new Error("No");
throw new Error("No");
return result;
},
sub: function (a, b) {
sub(a, b) {
return a - b;
},
speak: function () {
var buf = Memory.allocUtf8String("Yo");
speak() {
const buf = Memory.allocUtf8String("Yo");
return Memory.readByteArray(buf, 2);
}
},
speakWithMetadata() {
const buf = Memory.allocUtf8String("Yo");
return ['soft', Memory.readByteArray(buf, 2)];
},
processData(val, data) {
return { val, dump: hexdump(data, { header: false }) };
},
};
""",
)
@@ -52,7 +59,13 @@ rpc.exports = {
self.assertEqual(agent.add(2, 3), 5)
self.assertEqual(agent.sub(5, 3), 2)
self.assertRaises(Exception, lambda: agent.add(1, -2))
self.assertListEqual([x for x in iter(agent.speak())], [0x59, 0x6F])
self.assertEqual(agent.speak(), b"\x59\x6f")
meta, data = agent.speak_with_metadata()
self.assertEqual(meta, "soft")
self.assertEqual(data, b"\x59\x6f")
result = agent.process_data(1337, b"\x13\x37")
self.assertEqual(result["val"], 1337)
self.assertEqual(result["dump"], "00000000 13 37 .7")
def test_post_failure(self):
script = self.session.create_script(