From c7ae43e531768fa638dd191cace559daa2a31f9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20Andr=C3=A9=20Vadla=20Ravn=C3=A5s?= Date: Thu, 12 Jan 2017 05:17:17 +0100 Subject: [PATCH] Refactor to enable automatic signal bindings This gives us the Script#destroyed signal which we need for solving the RPC deadlock. It also gets rid of technical debt where a ton of duplicated error-prone code was required per signal binding. There was even a bug where every single one was unreffing the wrong Python object. Oops. --- src/_frida.c | 2256 +++++++++++++++++---------------------------- src/frida/core.py | 19 +- 2 files changed, 857 insertions(+), 1418 deletions(-) diff --git a/src/_frida.c b/src/_frida.c index 3f167c0..7ee1c2c 100644 --- a/src/_frida.c +++ b/src/_frida.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2015 Ole André Vadla Ravnås + * Copyright (C) 2013-2017 Ole André Vadla Ravnås * * Licence: wxWindows Library Licence, Version 3.1 */ @@ -59,55 +59,93 @@ # define PyRepr_FromFormat PyString_FromFormat #endif +#define PYFRIDA_TYPE(name) \ + G_PASTE (G_PASTE (Py, name), Type) +#define PYFRIDA_TYPE_SPEC(name) \ + G_PASTE (PYFRIDA_TYPE (name), _type_spec) +#define PYFRIDA_DEFINE_TYPE(name, init_from_handle, destroy) \ + static const PyGObjectTypeSpec PYFRIDA_TYPE_SPEC (name) = { &PYFRIDA_TYPE (name), init_from_handle, destroy } +#define PYFRIDA_REGISTER_TYPE(name, gtype) \ + G_BEGIN_DECLS \ + { \ + PyTypeObject * pytype = &PYFRIDA_TYPE (name); \ + pytype->tp_new = PyType_GenericNew; \ + if (PyType_Ready (pytype) < 0) \ + return MOD_ERROR_VAL; \ + PyGObject_register_type (gtype, &PYFRIDA_TYPE_SPEC (name)); \ + Py_INCREF (pytype); \ + PyModule_AddObject (module, G_STRINGIFY (name), (PyObject *) pytype); \ + } \ + G_END_DECLS + +#define PY_GOBJECT(o) ((PyGObject *) (o)) +#define PY_GOBJECT_HANDLE(o) (PY_GOBJECT (o)->handle) +#define PY_GOBJECT_SIGNAL_CLOSURE(o) ((PyGObjectSignalClosure *) (o)) + #define FRIDA_FUNCPTR_TO_POINTER(f) (GSIZE_TO_POINTER (f)) static PyObject * inspect_getargspec; -static PyObject * json_loads; -static PyObject * json_dumps; +static PyObject * inspect_ismethod; +static GHashTable * pygobject_type_spec_by_type; static GHashTable * exception_by_error_code; -typedef struct _PyDeviceManager PyDeviceManager; -typedef struct _PyDevice PyDevice; -typedef struct _PyApplication PyApplication; -typedef struct _PyProcess PyProcess; -typedef struct _PySpawn PySpawn; -typedef struct _PyIcon PyIcon; -typedef struct _PySession PySession; -typedef struct _PyScript PyScript; -typedef struct _PyFileMonitor PyFileMonitor; +typedef struct _PyGObject PyGObject; +typedef struct _PyGObjectTypeSpec PyGObjectTypeSpec; +typedef struct _PyGObjectSignalClosure PyGObjectSignalClosure; +typedef struct _PyDeviceManager PyDeviceManager; +typedef struct _PyDevice PyDevice; +typedef struct _PyApplication PyApplication; +typedef struct _PyProcess PyProcess; +typedef struct _PySpawn PySpawn; +typedef struct _PyIcon PyIcon; +typedef struct _PySession PySession; +typedef struct _PyScript PyScript; +typedef struct _PyFileMonitor PyFileMonitor; -struct _PyDeviceManager +typedef void (* PyGObjectInitFromHandleFunc) (PyObject * self, gpointer handle); + +struct _PyGObject { PyObject_HEAD - FridaDeviceManager * handle; - GList * on_changed; + gpointer handle; + const PyGObjectTypeSpec * spec; + + GSList * signal_closures; +}; + +struct _PyGObjectTypeSpec +{ + PyTypeObject * type; + gpointer init_from_handle; + GDestroyNotify destroy; +}; + +struct _PyGObjectSignalClosure +{ + GClosure parent; + guint signal_id; + guint max_arg_count; +}; + +struct _PyDeviceManager +{ + PyGObject parent; }; struct _PyDevice { - PyObject_HEAD - - FridaDevice * handle; - + PyGObject parent; PyObject * id; PyObject * name; PyObject * icon; PyObject * type; - - GList * on_spawned; - GList * on_output; - GList * on_uninjected; - GList * on_lost; }; struct _PyApplication { - PyObject_HEAD - - FridaApplication * handle; - + PyGObject parent; PyObject * identifier; PyObject * name; guint pid; @@ -115,28 +153,21 @@ struct _PyApplication struct _PyProcess { - PyObject_HEAD - - FridaProcess * handle; - + PyGObject parent; guint pid; PyObject * name; }; struct _PySpawn { - PyObject_HEAD - - FridaSpawn * handle; - + PyGObject parent; guint pid; PyObject * identifier; }; struct _PyIcon { - PyObject_HEAD - + PyGObject parent; gint width; gint height; gint rowstride; @@ -145,41 +176,54 @@ struct _PyIcon struct _PySession { - PyObject_HEAD - - FridaSession * handle; - GList * on_detached; + PyGObject parent; + guint pid; }; struct _PyScript { - PyObject_HEAD - - FridaScript * handle; - GList * on_message; + PyGObject parent; }; struct _PyFileMonitor { - PyObject_HEAD - + PyGObject parent; GFile * file; GFileMonitor * monitor; GList * on_change; }; -static int PyDeviceManager_init (PyDeviceManager * self); +static PyObject * PyGObject_new_take_handle (gpointer handle, const PyGObjectTypeSpec * spec); +static PyObject * PyGObject_try_get_from_handle (gpointer handle); +static int PyGObject_init (PyGObject * self); +static void PyGObject_dealloc (PyGObject * self); +static void PyGObject_take_handle (PyGObject * self, gpointer handle, const PyGObjectTypeSpec * spec); +static gpointer PyGObject_steal_handle (PyGObject * self); +static PyObject * PyGObject_on (PyGObject * self, PyObject * args); +static PyObject * PyGObject_off (PyGObject * self, PyObject * args); +static gint PyGObject_compare_signal_closure_callback (PyGObjectSignalClosure * closure, PyObject * callback); +static gboolean PyGObject_parse_signal_method_args (PyObject * args, GType instance_type, guint * signal_id, PyObject ** callback); +static const gchar * PyGObject_class_name_from_c (const gchar * cname); +static GClosure * PyGObject_make_closure_for_signal (GType instance_type, guint signal_id, PyObject * callback, guint max_arg_count); +static void PyGObjectSignalClosure_finalize (gpointer data, GClosure * closure); +static void PyGObjectSignalClosure_marshal (GClosure * closure, GValue * return_gvalue, guint n_param_values, const GValue * param_values, + gpointer invocation_hint, gpointer marshal_data); +static PyObject * PyGObjectSignalClosure_marshal_params (const GValue * params, guint params_length); +static PyObject * PyGObject_marshal_value (const GValue * value); +static PyObject * PyGObject_marshal_enum (gint value, GType type); +static PyObject * PyGObject_marshal_bytes (GBytes * bytes); +static PyObject * PyGObject_marshal_object (gpointer handle, GType type); + +static int PyDeviceManager_init (PyDeviceManager * self, PyObject * args, PyObject * kwds); static void PyDeviceManager_dealloc (PyDeviceManager * self); static PyObject * PyDeviceManager_close (PyDeviceManager * self); static PyObject * PyDeviceManager_enumerate_devices (PyDeviceManager * self); static PyObject * PyDeviceManager_add_remote_device (PyDeviceManager * self, PyObject * args); static PyObject * PyDeviceManager_remove_remote_device (PyDeviceManager * self, PyObject * args); -static PyObject * PyDeviceManager_on (PyDeviceManager * self, PyObject * args); -static PyObject * PyDeviceManager_off (PyDeviceManager * self, PyObject * args); -static void PyDeviceManager_on_changed (PyDeviceManager * self, FridaDeviceManager * handle); -static PyObject * PyDevice_from_handle (FridaDevice * handle); -static int PyDevice_init (PyDevice * self); +static PyObject * PyDevice_new_take_handle (FridaDevice * handle); +static int PyDevice_init (PyDevice * self, PyObject * args, PyObject * kw); +static void PyDevice_init_from_handle (PyDevice * self, FridaDevice * handle); static void PyDevice_dealloc (PyDevice * self); static PyObject * PyDevice_repr (PyDevice * self); static PyObject * PyDevice_get_frontmost_application (PyDevice * self); @@ -195,40 +239,39 @@ static PyObject * PyDevice_kill (PyDevice * self, PyObject * args); static PyObject * PyDevice_attach (PyDevice * self, PyObject * args); static PyObject * PyDevice_inject_library_file (PyDevice * self, PyObject * args); static PyObject * PyDevice_inject_library_blob (PyDevice * self, PyObject * args); -static PyObject * PyDevice_on (PyDevice * self, PyObject * args); -static PyObject * PyDevice_off (PyDevice * self, PyObject * args); -static void PyDevice_on_spawned (PyDevice * self, FridaSpawn * spawn, FridaDevice * handle); -static void PyDevice_on_output (PyDevice * self, guint pid, gint fd, GBytes * data, FridaDevice * handle); -static void PyDevice_on_uninjected (PyDevice * self, guint id, FridaDevice * handle); -static void PyDevice_on_lost (PyDevice * self, FridaDevice * handle); -static PyObject * PyApplication_from_handle (FridaApplication * handle); -static int PyApplication_init (PyApplication * self); +static PyObject * PyApplication_new_take_handle (FridaApplication * handle); +static int PyApplication_init (PyApplication * self, PyObject * args, PyObject * kw); +static void PyApplication_init_from_handle (PyApplication * self, FridaApplication * handle); static void PyApplication_dealloc (PyApplication * self); static PyObject * PyApplication_repr (PyApplication * self); static PyObject * PyApplication_get_small_icon (PyApplication * self); static PyObject * PyApplication_get_large_icon (PyApplication * self); -static PyObject * PyProcess_from_handle (FridaProcess * handle); -static int PyProcess_init (PyProcess * self); +static PyObject * PyProcess_new_take_handle (FridaProcess * handle); +static int PyProcess_init (PyProcess * self, PyObject * args, PyObject * kw); +static void PyProcess_init_from_handle (PyProcess * self, FridaProcess * handle); static void PyProcess_dealloc (PyProcess * self); static PyObject * PyProcess_repr (PyProcess * self); static PyObject * PyProcess_get_small_icon (PyProcess * self); static PyObject * PyProcess_get_large_icon (PyProcess * self); -static PyObject * PySpawn_from_handle (FridaSpawn * handle); -static int PySpawn_init (PySpawn * self); +static PyObject * PySpawn_new_take_handle (FridaSpawn * handle); +static int PySpawn_init (PySpawn * self, PyObject * args, PyObject * kw); +static void PySpawn_init_from_handle (PySpawn * self, FridaSpawn * handle); static void PySpawn_dealloc (PySpawn * self); static PyObject * PySpawn_repr (PySpawn * self); -static PyObject * PyIcon_from_handle (FridaIcon * handle); -static int PyIcon_init (PyIcon * self); +static PyObject * PyIcon_new_from_handle (FridaIcon * handle); +static int PyIcon_init (PyIcon * self, PyObject * args, PyObject * kw); +static void PyIcon_init_from_handle (PyIcon * self, FridaIcon * handle); static void PyIcon_dealloc (PyIcon * self); static PyObject * PyIcon_repr (PyIcon * self); -static PyObject * PySession_from_handle (FridaSession * handle); -static int PySession_init (PySession * self); -static void PySession_dealloc (PySession * self); +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); +static PyObject * PySession_repr (PySession * self); static PyObject * PySession_detach (PySession * self); static PyObject * PySession_create_script (PySession * self, PyObject * args, PyObject * kw); static PyObject * PySession_create_script_from_bytes (PySession * self, PyObject * args, PyObject * kw); @@ -236,37 +279,25 @@ static PyObject * PySession_compile_script (PySession * self, PyObject * args, P static PyObject * PySession_enable_debugger (PySession * self, PyObject * args, PyObject * kw); static PyObject * PySession_disable_debugger (PySession * self); static PyObject * PySession_enable_jit (PySession * self); -static PyObject * PySession_on (PySession * self, PyObject * args); -static PyObject * PySession_off (PySession * self, PyObject * args); -static void PySession_on_detached (PySession * self, FridaSessionDetachReason reason, FridaSession * handle); -static PyObject * PyScript_from_handle (FridaScript * handle); -static int PyScript_init (PyScript * self); -static void PyScript_dealloc (PyScript * self); +static PyObject * PyScript_new_take_handle (FridaScript * handle); static PyObject * PyScript_load (PyScript * self); static PyObject * PyScript_unload (PyScript * self); static PyObject * PyScript_post (PyScript * self, PyObject * args, PyObject * kw); -static PyObject * PyScript_on (PyScript * self, PyObject * args); -static PyObject * PyScript_off (PyScript * self, PyObject * args); -static void PyScript_on_message (PyScript * self, const gchar * message, GBytes * data, FridaScript * handle); -static int PyFileMonitor_init (PyFileMonitor * self, PyObject * args); -static void PyFileMonitor_dealloc (PyFileMonitor * self); +static int PyFileMonitor_init (PyFileMonitor * self, PyObject * args, PyObject * kw); static PyObject * PyFileMonitor_enable (PyFileMonitor * self); -static gboolean PyFileMonitor_do_enable (PyFileMonitor * self); static PyObject * PyFileMonitor_disable (PyFileMonitor * self); -static gboolean PyFileMonitor_do_disable (PyFileMonitor * self); -static PyObject * PyFileMonitor_on (PyFileMonitor * self, PyObject * args); -static PyObject * PyFileMonitor_off (PyFileMonitor * self, PyObject * args); -static void PyFileMonitor_on_change (PyFileMonitor * self, GFile * file, GFile * other_file, GFileMonitorEvent event_type, GFileMonitor * handle); -static gchar * PyFileMonitor_get_file_path (GFile * file); -static const gchar * PyFileMonitor_event_type_to_string (GFileMonitorEvent event); static PyObject * PyFrida_raise (GError * error); -static const gchar * PyFrida_device_type_to_string (FridaDeviceType type); -static gboolean PyFrida_parse_signal_method_args (PyObject * args, const char ** signal, PyObject ** callback); static guint PyFrida_get_max_argument_count (PyObject * callable); -static gint PyFrida_compare_pyobjects (gconstpointer a, gconstpointer b); + +static PyMethodDef PyGObject_methods[] = +{ + { "on", (PyCFunction) PyGObject_on, METH_VARARGS, "Add a signal handler." }, + { "off", (PyCFunction) PyGObject_off, METH_VARARGS, "Remove a signal handler." }, + { NULL } +}; static PyMethodDef PyDeviceManager_methods[] = { @@ -274,8 +305,6 @@ static PyMethodDef PyDeviceManager_methods[] = { "enumerate_devices", (PyCFunction) PyDeviceManager_enumerate_devices, METH_NOARGS, "Enumerate devices." }, { "add_remote_device", (PyCFunction) PyDeviceManager_add_remote_device, METH_VARARGS, "Add a remote device." }, { "remove_remote_device", (PyCFunction) PyDeviceManager_remove_remote_device, METH_VARARGS, "Remove a remote device." }, - { "on", (PyCFunction) PyDeviceManager_on, METH_VARARGS, "Add an event handler." }, - { "off", (PyCFunction) PyDeviceManager_off, METH_VARARGS, "Remove an event handler." }, { NULL } }; @@ -294,17 +323,15 @@ static PyMethodDef PyDevice_methods[] = { "attach", (PyCFunction) PyDevice_attach, METH_VARARGS, "Attach to a PID." }, { "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." }, - { "on", (PyCFunction) PyDevice_on, METH_VARARGS, "Add an event handler." }, - { "off", (PyCFunction) PyDevice_off, METH_VARARGS, "Remove an event handler." }, { NULL } }; static PyMemberDef PyDevice_members[] = { - { "id", T_OBJECT_EX, G_STRUCT_OFFSET (PyDevice, id), READONLY, "Device ID."}, - { "name", T_OBJECT_EX, G_STRUCT_OFFSET (PyDevice, name), READONLY, "Human-readable device name."}, - { "icon", T_OBJECT_EX, G_STRUCT_OFFSET (PyDevice, icon), READONLY, "Icon."}, - { "type", T_OBJECT_EX, G_STRUCT_OFFSET (PyDevice, type), READONLY, "Device type. One of: local, tether, remote."}, + { "id", T_OBJECT_EX, G_STRUCT_OFFSET (PyDevice, id), READONLY, "Device ID." }, + { "name", T_OBJECT_EX, G_STRUCT_OFFSET (PyDevice, name), READONLY, "Human-readable device name." }, + { "icon", T_OBJECT_EX, G_STRUCT_OFFSET (PyDevice, icon), READONLY, "Icon." }, + { "type", T_OBJECT_EX, G_STRUCT_OFFSET (PyDevice, type), READONLY, "Device type. One of: local, tether, remote." }, { NULL } }; @@ -317,9 +344,9 @@ static PyMethodDef PyApplication_methods[] = static PyMemberDef PyApplication_members[] = { - { "identifier", T_OBJECT_EX, G_STRUCT_OFFSET (PyApplication, identifier), READONLY, "Application identifier."}, - { "name", T_OBJECT_EX, G_STRUCT_OFFSET (PyApplication, name), READONLY, "Human-readable application name."}, - { "pid", T_UINT, G_STRUCT_OFFSET (PyApplication, pid), READONLY, "Process ID, or 0 if not running."}, + { "identifier", T_OBJECT_EX, G_STRUCT_OFFSET (PyApplication, identifier), READONLY, "Application identifier." }, + { "name", T_OBJECT_EX, G_STRUCT_OFFSET (PyApplication, name), READONLY, "Human-readable application name." }, + { "pid", T_UINT, G_STRUCT_OFFSET (PyApplication, pid), READONLY, "Process ID, or 0 if not running." }, { NULL } }; @@ -332,24 +359,24 @@ static PyMethodDef PyProcess_methods[] = static PyMemberDef PyProcess_members[] = { - { "pid", T_UINT, G_STRUCT_OFFSET (PyProcess, pid), READONLY, "Process ID."}, - { "name", T_OBJECT_EX, G_STRUCT_OFFSET (PyProcess, name), READONLY, "Human-readable process name."}, + { "pid", T_UINT, G_STRUCT_OFFSET (PyProcess, pid), READONLY, "Process ID." }, + { "name", T_OBJECT_EX, G_STRUCT_OFFSET (PyProcess, name), READONLY, "Human-readable process name." }, { NULL } }; static PyMemberDef PySpawn_members[] = { - { "pid", T_UINT, G_STRUCT_OFFSET (PySpawn, pid), READONLY, "Process ID."}, - { "identifier", T_OBJECT_EX, G_STRUCT_OFFSET (PySpawn, identifier), READONLY, "Application identifier."}, + { "pid", T_UINT, G_STRUCT_OFFSET (PySpawn, pid), READONLY, "Process ID." }, + { "identifier", T_OBJECT_EX, G_STRUCT_OFFSET (PySpawn, identifier), READONLY, "Application identifier." }, { NULL } }; static PyMemberDef PyIcon_members[] = { - { "width", T_INT, G_STRUCT_OFFSET (PyIcon, width), READONLY, "Width in pixels."}, - { "height", T_INT, G_STRUCT_OFFSET (PyIcon, height), READONLY, "Height in pixels."}, - { "rowstride", T_INT, G_STRUCT_OFFSET (PyIcon, rowstride), READONLY, "Row stride in bytes."}, - { "pixels", T_OBJECT_EX, G_STRUCT_OFFSET (PyIcon, pixels), READONLY, "Pixels as a raw string containing RGBA data."}, + { "width", T_INT, G_STRUCT_OFFSET (PyIcon, width), READONLY, "Width in pixels." }, + { "height", T_INT, G_STRUCT_OFFSET (PyIcon, height), READONLY, "Height in pixels." }, + { "rowstride", T_INT, G_STRUCT_OFFSET (PyIcon, rowstride), READONLY, "Row stride in bytes." }, + { "pixels", T_OBJECT_EX, G_STRUCT_OFFSET (PyIcon, pixels), READONLY, "Pixels as a raw string containing RGBA data." }, { NULL } }; @@ -362,8 +389,12 @@ static PyMethodDef PySession_methods[] = { "enable_debugger", (PyCFunction) PySession_enable_debugger, METH_VARARGS | METH_KEYWORDS, "Enable the Node.js compatible script debugger." }, { "disable_debugger", (PyCFunction) PySession_disable_debugger, METH_NOARGS, "Disable the Node.js compatible script debugger." }, { "enable_jit", (PyCFunction) PySession_enable_jit, METH_NOARGS, "Enable JIT." }, - { "on", (PyCFunction) PySession_on, METH_VARARGS, "Add an event handler." }, - { "off", (PyCFunction) PySession_off, METH_VARARGS, "Remove an event handler." }, + { NULL } +}; + +static PyMemberDef PySession_members[] = +{ + { "pid", T_UINT, G_STRUCT_OFFSET (PySession, pid), READONLY, "Process ID." }, { NULL } }; @@ -371,9 +402,7 @@ static PyMethodDef PyScript_methods[] = { { "load", (PyCFunction) PyScript_load, METH_NOARGS, "Load the script." }, { "unload", (PyCFunction) PyScript_unload, METH_NOARGS, "Unload the script." }, - { "post", (PyCFunction) PyScript_post, METH_VARARGS | METH_KEYWORDS, "Post a JSON-formatted message to the script." }, - { "on", (PyCFunction) PyScript_on, METH_VARARGS, "Add an event handler." }, - { "off", (PyCFunction) PyScript_off, METH_VARARGS, "Remove an event handler." }, + { "post", (PyCFunction) PyScript_post, METH_VARARGS | METH_KEYWORDS, "Post a JSON-encoded message to the script." }, { NULL } }; @@ -381,11 +410,51 @@ static PyMethodDef PyFileMonitor_methods[] = { { "enable", (PyCFunction) PyFileMonitor_enable, METH_NOARGS, "Enables the file monitor." }, { "disable", (PyCFunction) PyFileMonitor_disable, METH_NOARGS, "Disables the file monitor." }, - { "on", (PyCFunction) PyFileMonitor_on, METH_VARARGS, "Add an event handler." }, - { "off", (PyCFunction) PyFileMonitor_off, METH_VARARGS, "Remove an event handler." }, { NULL } }; +static PyTypeObject PyGObjectType = +{ + PyVarObject_HEAD_INIT (NULL, 0) + "_frida.Object", /* tp_name */ + sizeof (PyGObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor) PyGObject_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + NULL, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL, /* tp_hash */ + NULL, /* tp_call */ + NULL, /* tp_str */ + NULL, /* tp_getattro */ + NULL, /* tp_setattro */ + NULL, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "Frida Object", /* tp_doc */ + NULL, /* tp_traverse */ + NULL, /* tp_clear */ + NULL, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + NULL, /* tp_iter */ + NULL, /* tp_iternext */ + PyGObject_methods, /* tp_methods */ + NULL, /* tp_members */ + NULL, /* tp_getset */ + NULL, /* tp_base */ + NULL, /* tp_dict */ + NULL, /* tp_descr_get */ + NULL, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc) PyGObject_init, /* tp_init */ +}; + +PYFRIDA_DEFINE_TYPE (GObject, NULL, g_object_unref); + static PyTypeObject PyDeviceManagerType = { PyVarObject_HEAD_INIT (NULL, 0) @@ -418,7 +487,7 @@ static PyTypeObject PyDeviceManagerType = PyDeviceManager_methods, /* tp_methods */ NULL, /* tp_members */ NULL, /* tp_getset */ - NULL, /* tp_base */ + &PyGObjectType, /* tp_base */ NULL, /* tp_dict */ NULL, /* tp_descr_get */ NULL, /* tp_descr_set */ @@ -426,6 +495,8 @@ static PyTypeObject PyDeviceManagerType = (initproc) PyDeviceManager_init, /* tp_init */ }; +PYFRIDA_DEFINE_TYPE (DeviceManager, NULL, frida_unref); + static PyTypeObject PyDeviceType = { PyVarObject_HEAD_INIT (NULL, 0) @@ -458,7 +529,7 @@ static PyTypeObject PyDeviceType = PyDevice_methods, /* tp_methods */ PyDevice_members, /* tp_members */ NULL, /* tp_getset */ - NULL, /* tp_base */ + &PyGObjectType, /* tp_base */ NULL, /* tp_dict */ NULL, /* tp_descr_get */ NULL, /* tp_descr_set */ @@ -466,6 +537,8 @@ static PyTypeObject PyDeviceType = (initproc) PyDevice_init, /* tp_init */ }; +PYFRIDA_DEFINE_TYPE (Device, PyDevice_init_from_handle, frida_unref); + static PyTypeObject PyApplicationType = { PyVarObject_HEAD_INIT (NULL, 0) @@ -498,7 +571,7 @@ static PyTypeObject PyApplicationType = PyApplication_methods, /* tp_methods */ PyApplication_members, /* tp_members */ NULL, /* tp_getset */ - NULL, /* tp_base */ + &PyGObjectType, /* tp_base */ NULL, /* tp_dict */ NULL, /* tp_descr_get */ NULL, /* tp_descr_set */ @@ -506,6 +579,8 @@ static PyTypeObject PyApplicationType = (initproc) PyApplication_init, /* tp_init */ }; +PYFRIDA_DEFINE_TYPE (Application, PyApplication_init_from_handle, g_object_unref); + static PyTypeObject PyProcessType = { PyVarObject_HEAD_INIT (NULL, 0) @@ -538,7 +613,7 @@ static PyTypeObject PyProcessType = PyProcess_methods, /* tp_methods */ PyProcess_members, /* tp_members */ NULL, /* tp_getset */ - NULL, /* tp_base */ + &PyGObjectType, /* tp_base */ NULL, /* tp_dict */ NULL, /* tp_descr_get */ NULL, /* tp_descr_set */ @@ -546,6 +621,8 @@ static PyTypeObject PyProcessType = (initproc) PyProcess_init, /* tp_init */ }; +PYFRIDA_DEFINE_TYPE (Process, PyProcess_init_from_handle, g_object_unref); + static PyTypeObject PySpawnType = { PyVarObject_HEAD_INIT (NULL, 0) @@ -578,7 +655,7 @@ static PyTypeObject PySpawnType = NULL, /* tp_methods */ PySpawn_members, /* tp_members */ NULL, /* tp_getset */ - NULL, /* tp_base */ + &PyGObjectType, /* tp_base */ NULL, /* tp_dict */ NULL, /* tp_descr_get */ NULL, /* tp_descr_set */ @@ -586,6 +663,8 @@ static PyTypeObject PySpawnType = (initproc) PySpawn_init, /* tp_init */ }; +PYFRIDA_DEFINE_TYPE (Spawn, PySpawn_init_from_handle, g_object_unref); + static PyTypeObject PyIconType = { PyVarObject_HEAD_INIT (NULL, 0) @@ -618,7 +697,7 @@ static PyTypeObject PyIconType = NULL, /* tp_methods */ PyIcon_members, /* tp_members */ NULL, /* tp_getset */ - NULL, /* tp_base */ + &PyGObjectType, /* tp_base */ NULL, /* tp_dict */ NULL, /* tp_descr_get */ NULL, /* tp_descr_set */ @@ -626,18 +705,20 @@ static PyTypeObject PyIconType = (initproc) PyIcon_init, /* tp_init */ }; +PYFRIDA_DEFINE_TYPE (Icon, PyIcon_init_from_handle, g_object_unref); + static PyTypeObject PySessionType = { PyVarObject_HEAD_INIT (NULL, 0) "_frida.Session", /* tp_name */ sizeof (PySession), /* tp_basicsize */ 0, /* tp_itemsize */ - (destructor) PySession_dealloc, /* tp_dealloc */ + NULL, /* tp_dealloc */ NULL, /* tp_print */ NULL, /* tp_getattr */ NULL, /* tp_setattr */ NULL, /* tp_compare */ - NULL, /* tp_repr */ + (reprfunc) PySession_repr, /* tp_repr */ NULL, /* tp_as_number */ NULL, /* tp_as_sequence */ NULL, /* tp_as_mapping */ @@ -656,9 +737,9 @@ static PyTypeObject PySessionType = NULL, /* tp_iter */ NULL, /* tp_iternext */ PySession_methods, /* tp_methods */ - NULL, /* tp_members */ + PySession_members, /* tp_members */ NULL, /* tp_getset */ - NULL, /* tp_base */ + &PyGObjectType, /* tp_base */ NULL, /* tp_dict */ NULL, /* tp_descr_get */ NULL, /* tp_descr_set */ @@ -666,13 +747,15 @@ static PyTypeObject PySessionType = (initproc) PySession_init, /* tp_init */ }; +PYFRIDA_DEFINE_TYPE (Session, PySession_init_from_handle, frida_unref); + static PyTypeObject PyScriptType = { PyVarObject_HEAD_INIT (NULL, 0) "_frida.Script", /* tp_name */ sizeof (PyScript), /* tp_basicsize */ 0, /* tp_itemsize */ - (destructor) PyScript_dealloc, /* tp_dealloc */ + NULL, /* tp_dealloc */ NULL, /* tp_print */ NULL, /* tp_getattr */ NULL, /* tp_setattr */ @@ -698,21 +781,23 @@ static PyTypeObject PyScriptType = PyScript_methods, /* tp_methods */ NULL, /* tp_members */ NULL, /* tp_getset */ - NULL, /* tp_base */ + &PyGObjectType, /* tp_base */ NULL, /* tp_dict */ NULL, /* tp_descr_get */ NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ - (initproc) PyScript_init, /* tp_init */ + NULL, /* tp_init */ }; +PYFRIDA_DEFINE_TYPE (Script, NULL, frida_unref); + static PyTypeObject PyFileMonitorType = { PyVarObject_HEAD_INIT (NULL, 0) "_frida.FileMonitor", /* tp_name */ sizeof (PyFileMonitor), /* tp_basicsize */ 0, /* tp_itemsize */ - (destructor) PyFileMonitor_dealloc, /* tp_dealloc */ + NULL, /* tp_dealloc */ NULL, /* tp_print */ NULL, /* tp_getattr */ NULL, /* tp_setattr */ @@ -738,7 +823,7 @@ static PyTypeObject PyFileMonitorType = PyFileMonitor_methods, /* tp_methods */ NULL, /* tp_members */ NULL, /* tp_getset */ - NULL, /* tp_base */ + &PyGObjectType, /* tp_base */ NULL, /* tp_dict */ NULL, /* tp_descr_get */ NULL, /* tp_descr_set */ @@ -746,14 +831,461 @@ static PyTypeObject PyFileMonitorType = (initproc) PyFileMonitor_init, /* tp_init */ }; +PYFRIDA_DEFINE_TYPE (FileMonitor, NULL, frida_unref); + + +static PyObject * +PyGObject_new_take_handle (gpointer handle, const PyGObjectTypeSpec * spec) +{ + PyObject * object; + + if (handle == NULL) + Py_RETURN_NONE; + + object = PyGObject_try_get_from_handle (handle); + if (object == NULL) + { + object = PyObject_CallFunction ((PyObject *) spec->type, NULL); + PyGObject_take_handle (PY_GOBJECT (object), handle, spec); + + if (spec->init_from_handle != NULL) + ((PyGObjectInitFromHandleFunc) spec->init_from_handle) (object, handle); + } + else + { + spec->destroy (handle); + Py_INCREF (object); + } + + return object; +} + +static PyObject * +PyGObject_try_get_from_handle (gpointer handle) +{ + return g_object_get_data (handle, "pyobject"); +} static int -PyDeviceManager_init (PyDeviceManager * self) +PyGObject_init (PyGObject * self) { - self->handle = frida_device_manager_new (); - self->on_changed = NULL; + self->handle = NULL; + self->spec = &PYFRIDA_TYPE_SPEC (GObject); - g_object_set_data (G_OBJECT (self->handle), "pyobject", self); + self->signal_closures = NULL; + + return 0; +} + +static void +PyGObject_dealloc (PyGObject * self) +{ + gpointer handle; + + handle = PyGObject_steal_handle (self); + if (handle != NULL) + { + Py_BEGIN_ALLOW_THREADS + self->spec->destroy (handle); + Py_END_ALLOW_THREADS + } + + Py_TYPE (self)->tp_free ((PyObject *) self); +} + +static void +PyGObject_take_handle (PyGObject * self, gpointer handle, const PyGObjectTypeSpec * spec) +{ + self->handle = handle; + self->spec = spec; + + g_object_set_data (G_OBJECT (handle), "pyobject", self); +} + +static gpointer +PyGObject_steal_handle (PyGObject * self) +{ + gpointer handle = self->handle; + GSList * entry; + + if (handle == NULL) + return NULL; + + for (entry = self->signal_closures; entry != NULL; entry = entry->next) + { + PyGObjectSignalClosure * closure = entry->data; + guint num_matches; + + num_matches = g_signal_handlers_disconnect_matched (handle, G_SIGNAL_MATCH_CLOSURE, closure->signal_id, 0, &closure->parent, NULL, NULL); + g_assert_cmpuint (num_matches, ==, 1); + } + g_clear_pointer (&self->signal_closures, g_slist_free); + + g_object_set_data (G_OBJECT (handle), "pyobject", NULL); + + self->handle = NULL; + + return handle; +} + +static PyObject * +PyGObject_on (PyGObject * self, PyObject * args) +{ + GType instance_type; + guint signal_id; + PyObject * callback; + guint max_arg_count, allowed_arg_count_including_sender; + GSignalQuery query; + GClosure * closure; + + instance_type = G_OBJECT_TYPE (self->handle); + + if (!PyGObject_parse_signal_method_args (args, instance_type, &signal_id, &callback)) + return NULL; + + max_arg_count = PyFrida_get_max_argument_count (callback); + if (max_arg_count != G_MAXUINT) + { + g_signal_query (signal_id, &query); + + allowed_arg_count_including_sender = 1 + query.n_params; + + if (max_arg_count > allowed_arg_count_including_sender) + goto too_many_arguments; + } + + closure = PyGObject_make_closure_for_signal (instance_type, signal_id, callback, max_arg_count); + g_signal_connect_closure_by_id (self->handle, signal_id, 0, closure, TRUE); + + self->signal_closures = g_slist_prepend (self->signal_closures, closure); + + Py_RETURN_NONE; + +too_many_arguments: + { + return PyErr_Format (PyExc_TypeError, + "callback expects too many arguments, the '%s' signal only has %u but callback expects %u", + g_signal_name (signal_id), query.n_params, max_arg_count); + } +} + +static PyObject * +PyGObject_off (PyGObject * self, PyObject * args) +{ + guint signal_id; + PyObject * callback; + GSList * entry; + GClosure * closure; + guint num_matches; + + if (!PyGObject_parse_signal_method_args (args, G_OBJECT_TYPE (self->handle), &signal_id, &callback)) + return NULL; + + entry = g_slist_find_custom (self->signal_closures, callback, (GCompareFunc) PyGObject_compare_signal_closure_callback); + if (entry == NULL) + goto unknown_callback; + + closure = entry->data; + self->signal_closures = g_slist_delete_link (self->signal_closures, entry); + + num_matches = g_signal_handlers_disconnect_matched (self->handle, G_SIGNAL_MATCH_CLOSURE, signal_id, 0, closure, NULL, NULL); + g_assert_cmpuint (num_matches, ==, 1); + + Py_RETURN_NONE; + +unknown_callback: + { + PyErr_SetString (PyExc_ValueError, "unknown callback"); + return NULL; + } +} + +static gint +PyGObject_compare_signal_closure_callback (PyGObjectSignalClosure * closure, + PyObject * callback) +{ + int result; + + result = PyObject_RichCompareBool (closure->parent.data, callback, Py_EQ); + + return (result == 1) ? 0 : -1; +} + +static gboolean +PyGObject_parse_signal_method_args (PyObject * args, GType instance_type, guint * signal_id, PyObject ** callback) +{ + const gchar * signal_name; + + if (!PyArg_ParseTuple (args, "sO", &signal_name, callback)) + return FALSE; + + if (!PyCallable_Check (*callback)) + { + PyErr_SetString (PyExc_TypeError, "second argument must be callable"); + return FALSE; + } + + *signal_id = g_signal_lookup (signal_name, instance_type); + if (*signal_id == 0) + goto invalid_signal_name; + + return TRUE; + +invalid_signal_name: + { + GString * message; + guint * ids, n_ids, i; + + message = g_string_sized_new (128); + + g_string_append (message, PyGObject_class_name_from_c (g_type_name (instance_type))); + + ids = g_signal_list_ids (instance_type, &n_ids); + + if (n_ids > 0) + { + g_string_append_printf (message, " does not have a signal named '%s', it only has: ", signal_name); + + for (i = 0; i != n_ids; i++) + { + if (i != 0) + g_string_append (message, ", "); + g_string_append_c (message, '\''); + g_string_append (message, g_signal_name (ids[i])); + g_string_append_c (message, '\''); + } + } + else + { + g_string_append (message, " does not have any signals"); + } + + g_free (ids); + + PyErr_SetString (PyExc_ValueError, message->str); + + g_string_free (message, TRUE); + + return FALSE; + } +} + +static const gchar * +PyGObject_class_name_from_c (const gchar * cname) +{ + if (g_str_has_prefix (cname, "Frida")) + return cname + 5; + + return cname; +} + +static void +PyGObject_class_init (void) +{ + pygobject_type_spec_by_type = g_hash_table_new_full (NULL, NULL, NULL, NULL); +} + +static void +PyGObject_register_type (GType instance_type, const PyGObjectTypeSpec * spec) +{ + g_hash_table_insert (pygobject_type_spec_by_type, GSIZE_TO_POINTER (instance_type), (gpointer) spec); +} + +static GClosure * +PyGObject_make_closure_for_signal (GType instance_type, guint signal_id, PyObject * callback, guint max_arg_count) +{ + GClosure * closure; + PyGObjectSignalClosure * pyclosure; + + closure = g_closure_new_simple (sizeof (PyGObjectSignalClosure), callback); + Py_IncRef (callback); + + g_closure_add_finalize_notifier (closure, callback, PyGObjectSignalClosure_finalize); + g_closure_set_marshal (closure, PyGObjectSignalClosure_marshal); + + pyclosure = PY_GOBJECT_SIGNAL_CLOSURE (closure); + pyclosure->signal_id = signal_id; + pyclosure->max_arg_count = max_arg_count; + + return closure; +} + +static void +PyGObjectSignalClosure_finalize (gpointer data, GClosure * closure) +{ + PyObject * callback = data; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure (); + + Py_DecRef (callback); + + PyGILState_Release (gstate); +} + +static void +PyGObjectSignalClosure_marshal (GClosure * closure, GValue * return_gvalue, guint n_param_values, const GValue * param_values, + gpointer invocation_hint, gpointer marshal_data) +{ + PyGObjectSignalClosure * self = PY_GOBJECT_SIGNAL_CLOSURE (closure); + PyObject * callback = closure->data; + PyGILState_STATE gstate; + PyObject * args, * result; + + gstate = PyGILState_Ensure (); + + if (PyGObject_try_get_from_handle (g_value_get_object (¶m_values[0])) == NULL) + goto beach; + + if (self->max_arg_count == n_param_values) + args = PyGObjectSignalClosure_marshal_params (param_values, n_param_values); + else + args = PyGObjectSignalClosure_marshal_params (param_values + 1, MIN (n_param_values - 1, self->max_arg_count)); + if (args == NULL) + { + PyErr_Print (); + goto beach; + } + + result = PyObject_CallObject (callback, args); + if (result == NULL) + PyErr_Print (); + else + Py_DECREF (result); + + Py_DECREF (args); + +beach: + PyGILState_Release (gstate); +} + +static PyObject * +PyGObjectSignalClosure_marshal_params (const GValue * params, guint params_length) +{ + PyObject * args; + guint i; + + args = PyTuple_New (params_length); + + for (i = 0; i != params_length; i++) + { + PyObject * arg; + + arg = PyGObject_marshal_value (¶ms[i]); + if (arg == NULL) + goto marshal_error; + + PyTuple_SetItem (args, i, arg); + } + + return args; + +marshal_error: + { + Py_DECREF (args); + return NULL; + } +} + +static PyObject * +PyGObject_marshal_value (const GValue * value) +{ + GType type; + + type = G_VALUE_TYPE (value); + + switch (type) + { + case G_TYPE_BOOLEAN: + return PyBool_FromLong (g_value_get_boolean (value)); + case G_TYPE_INT: + return PyInt_FromLong (g_value_get_int (value)); + case G_TYPE_UINT: + return PyInt_FromSize_t (g_value_get_uint (value)); + case G_TYPE_FLOAT: + return PyFloat_FromDouble (g_value_get_float (value)); + case G_TYPE_DOUBLE: + return PyFloat_FromDouble (g_value_get_double (value)); + case G_TYPE_STRING: + return PyUnicode_FromUTF8String (g_value_get_string (value)); + default: { + if (G_TYPE_IS_ENUM (type)) + return PyGObject_marshal_enum (g_value_get_enum (value), type); + else if (type == G_TYPE_BYTES) + return PyGObject_marshal_bytes (g_value_get_boxed (value)); + else if (G_TYPE_IS_OBJECT (type)) + return PyGObject_marshal_object (g_value_get_object (value), type); + else + goto unsupported_type; + } + } + + g_assert_not_reached (); + +unsupported_type: + { + return PyErr_Format (PyExc_NotImplementedError, + "unsupported type: '%s'", + g_type_name (type)); + } +} + +static PyObject * +PyGObject_marshal_enum (gint value, GType type) +{ + GEnumClass * enum_class; + GEnumValue * enum_value; + PyObject * result; + + enum_class = g_type_class_ref (type); + + enum_value = g_enum_get_value (enum_class, value); + g_assert (enum_value != NULL); + + result = PyUnicode_FromUTF8String (enum_value->value_nick); + + g_type_class_unref (enum_class); + + return result; +} + +static PyObject * +PyGObject_marshal_bytes (GBytes * bytes) +{ + gconstpointer data; + gsize size; + + if (bytes == NULL) + Py_RETURN_NONE; + + data = g_bytes_get_data (bytes, &size); + + return PyBytes_FromStringAndSize (data, size); +} + +static PyObject * +PyGObject_marshal_object (gpointer handle, GType type) +{ + const PyGObjectTypeSpec * spec; + + if (handle == NULL) + Py_RETURN_NONE; + + spec = g_hash_table_lookup (pygobject_type_spec_by_type, GSIZE_TO_POINTER (type)); + if (spec == NULL) + spec = &PYFRIDA_TYPE_SPEC (GObject); + + return PyGObject_new_take_handle (g_object_ref (handle), spec); +} + + +static int +PyDeviceManager_init (PyDeviceManager * self, PyObject * args, PyObject * kw) +{ + if (PyGObjectType.tp_init ((PyObject *) self, args, kw) < 0) + return -1; + + PyGObject_take_handle (&self->parent, frida_device_manager_new (), &PYFRIDA_TYPE_SPEC (DeviceManager)); return 0; } @@ -761,29 +1293,25 @@ PyDeviceManager_init (PyDeviceManager * self) static void PyDeviceManager_dealloc (PyDeviceManager * self) { - if (self->on_changed != NULL) - { - g_signal_handlers_disconnect_by_func (self->handle, FRIDA_FUNCPTR_TO_POINTER (PyDeviceManager_on_changed), self); - g_list_free_full (self->on_changed, (GDestroyNotify) Py_DecRef); - } + FridaDeviceManager * handle; - if (self->handle != NULL) + handle = PyGObject_steal_handle (&self->parent); + if (handle != NULL) { - g_object_set_data (G_OBJECT (self->handle), "pyobject", NULL); Py_BEGIN_ALLOW_THREADS - frida_device_manager_close_sync (self->handle); - frida_unref (self->handle); + frida_device_manager_close_sync (handle); + frida_unref (handle); Py_END_ALLOW_THREADS } - Py_TYPE (self)->tp_free ((PyObject *) self); + PyGObjectType.tp_dealloc ((PyObject *) self); } static PyObject * PyDeviceManager_close (PyDeviceManager * self) { Py_BEGIN_ALLOW_THREADS - frida_device_manager_close_sync (self->handle); + frida_device_manager_close_sync (PY_GOBJECT_HANDLE (self)); Py_END_ALLOW_THREADS Py_RETURN_NONE; @@ -798,7 +1326,7 @@ PyDeviceManager_enumerate_devices (PyDeviceManager * self) PyObject * devices; Py_BEGIN_ALLOW_THREADS - result = frida_device_manager_enumerate_devices_sync (self->handle, &error); + result = frida_device_manager_enumerate_devices_sync (PY_GOBJECT_HANDLE (self), &error); Py_END_ALLOW_THREADS if (error != NULL) return PyFrida_raise (error); @@ -807,7 +1335,7 @@ PyDeviceManager_enumerate_devices (PyDeviceManager * self) devices = PyList_New (result_length); for (i = 0; i != result_length; i++) { - PyList_SET_ITEM (devices, i, PyDevice_from_handle (frida_device_list_get (result, i))); + PyList_SET_ITEM (devices, i, PyDevice_new_take_handle (frida_device_list_get (result, i))); } frida_unref (result); @@ -825,12 +1353,12 @@ PyDeviceManager_add_remote_device (PyDeviceManager * self, PyObject * args) return NULL; Py_BEGIN_ALLOW_THREADS - result = frida_device_manager_add_remote_device_sync (self->handle, host, &error); + result = frida_device_manager_add_remote_device_sync (PY_GOBJECT_HANDLE (self), host, &error); Py_END_ALLOW_THREADS if (error != NULL) return PyFrida_raise (error); - return PyDevice_from_handle (result); + return PyDevice_new_take_handle (result); } static PyObject * @@ -843,7 +1371,7 @@ PyDeviceManager_remove_remote_device (PyDeviceManager * self, PyObject * args) return NULL; Py_BEGIN_ALLOW_THREADS - frida_device_manager_remove_remote_device_sync (self->handle, host, &error); + frida_device_manager_remove_remote_device_sync (PY_GOBJECT_HANDLE (self), host, &error); Py_END_ALLOW_THREADS if (error != NULL) return PyFrida_raise (error); @@ -851,197 +1379,45 @@ PyDeviceManager_remove_remote_device (PyDeviceManager * self, PyObject * args) Py_RETURN_NONE; } -static PyObject * -PyDeviceManager_on (PyDeviceManager * self, PyObject * args) -{ - const char * signal; - PyObject * callback; - - if (!PyFrida_parse_signal_method_args (args, &signal, &callback)) - return NULL; - - if (strcmp (signal, "changed") == 0) - { - if (self->on_changed == NULL) - { - g_signal_connect_swapped (self->handle, "changed", G_CALLBACK (PyDeviceManager_on_changed), self); - } - - Py_INCREF (callback); - self->on_changed = g_list_append (self->on_changed, callback); - } - else - { - PyErr_SetString (PyExc_NotImplementedError, "unsupported signal"); - return NULL; - } - - Py_RETURN_NONE; -} static PyObject * -PyDeviceManager_off (PyDeviceManager * self, PyObject * args) +PyDevice_new_take_handle (FridaDevice * handle) { - const char * signal; - PyObject * callback; - - if (!PyFrida_parse_signal_method_args (args, &signal, &callback)) - return NULL; - - if (strcmp (signal, "changed") == 0) - { - GList * entry; - - entry = g_list_find_custom (self->on_changed, callback, PyFrida_compare_pyobjects); - if (entry != NULL) - { - self->on_changed = g_list_delete_link (self->on_changed, entry); - Py_DECREF (callback); - } - else - { - PyErr_SetString (PyExc_ValueError, "unknown callback"); - return NULL; - } - - if (self->on_changed == NULL) - { - g_signal_handlers_disconnect_by_func (self->handle, FRIDA_FUNCPTR_TO_POINTER (PyDeviceManager_on_changed), self); - } - } - else - { - PyErr_SetString (PyExc_NotImplementedError, "unsupported signal"); - return NULL; - } - - Py_RETURN_NONE; -} - -static void -PyDeviceManager_on_changed (PyDeviceManager * self, FridaDeviceManager * handle) -{ - PyGILState_STATE gstate; - - gstate = PyGILState_Ensure (); - - if (g_object_get_data (G_OBJECT (handle), "pyobject") == self) - { - GList * callbacks, * cur; - - g_list_foreach (self->on_changed, (GFunc) Py_IncRef, NULL); - callbacks = g_list_copy (self->on_changed); - - for (cur = callbacks; cur != NULL; cur = cur->next) - { - PyObject * result = PyObject_CallFunction ((PyObject *) cur->data, NULL); - if (result == NULL) - PyErr_Print (); - else - Py_DECREF (result); - } - - g_list_free_full (callbacks, (GDestroyNotify) Py_DecRef); - } - - PyGILState_Release (gstate); -} - - -static PyObject * -PyDevice_from_handle (FridaDevice * handle) -{ - PyObject * device; - - device = g_object_get_data (G_OBJECT (handle), "pyobject"); - if (device == NULL) - { - const gchar * id, * name, * type; - PyDevice * dev; - - id = frida_device_get_id (handle); - name = frida_device_get_name (handle); - type = PyFrida_device_type_to_string (frida_device_get_dtype (handle)); - - device = PyObject_CallFunction ((PyObject *) &PyDeviceType, NULL); - - dev = (PyDevice *) device; - dev->handle = handle; - dev->id = PyUnicode_FromUTF8String (id); - dev->name = PyUnicode_FromUTF8String (name); - dev->icon = PyIcon_from_handle (frida_device_get_icon (handle)); - dev->type = PyUnicode_FromUTF8String (type); - - g_object_set_data (G_OBJECT (handle), "pyobject", device); - } - else - { - frida_unref (handle); - Py_INCREF (device); - } - - return device; + return PyGObject_new_take_handle (handle, &PYFRIDA_TYPE_SPEC (Device)); } static int -PyDevice_init (PyDevice * self) +PyDevice_init (PyDevice * self, PyObject * args, PyObject * kw) { - self->handle = NULL; + if (PyGObjectType.tp_init ((PyObject *) self, args, kw) < 0) + return -1; self->id = NULL; self->name = NULL; self->icon = NULL; self->type = NULL; - self->on_spawned = NULL; - self->on_output = NULL; - self->on_uninjected = NULL; - self->on_lost = NULL; - return 0; } +static void +PyDevice_init_from_handle (PyDevice * self, FridaDevice * handle) +{ + self->id = PyUnicode_FromUTF8String (frida_device_get_id (handle)); + self->name = PyUnicode_FromUTF8String (frida_device_get_name (handle)); + self->icon = PyIcon_new_from_handle (frida_device_get_icon (handle)); + self->type = PyGObject_marshal_enum (frida_device_get_dtype (handle), FRIDA_TYPE_DEVICE_TYPE); +} + static void PyDevice_dealloc (PyDevice * self) { - if (self->on_spawned != NULL) - { - g_signal_handlers_disconnect_by_func (self->handle, FRIDA_FUNCPTR_TO_POINTER (PyDevice_on_spawned), self); - g_list_free_full (self->on_spawned, (GDestroyNotify) Py_DecRef); - } - - if (self->on_output != NULL) - { - g_signal_handlers_disconnect_by_func (self->handle, FRIDA_FUNCPTR_TO_POINTER (PyDevice_on_output), self); - g_list_free_full (self->on_output, (GDestroyNotify) Py_DecRef); - } - - if (self->on_uninjected != NULL) - { - g_signal_handlers_disconnect_by_func (self->handle, FRIDA_FUNCPTR_TO_POINTER (PyDevice_on_uninjected), self); - g_list_free_full (self->on_uninjected, (GDestroyNotify) Py_DecRef); - } - - if (self->on_lost != NULL) - { - g_signal_handlers_disconnect_by_func (self->handle, FRIDA_FUNCPTR_TO_POINTER (PyDevice_on_lost), self); - g_list_free_full (self->on_lost, (GDestroyNotify) Py_DecRef); - } - Py_XDECREF (self->type); Py_XDECREF (self->icon); Py_XDECREF (self->name); Py_XDECREF (self->id); - if (self->handle != NULL) - { - g_object_set_data (G_OBJECT (self->handle), "pyobject", NULL); - Py_BEGIN_ALLOW_THREADS - frida_unref (self->handle); - Py_END_ALLOW_THREADS - } - - Py_TYPE (self)->tp_free ((PyObject *) self); + PyGObjectType.tp_dealloc ((PyObject *) self); } static PyObject * @@ -1072,13 +1448,13 @@ PyDevice_get_frontmost_application (PyDevice * self) FridaApplication * result; Py_BEGIN_ALLOW_THREADS - result = frida_device_get_frontmost_application_sync (self->handle, &error); + result = frida_device_get_frontmost_application_sync (PY_GOBJECT_HANDLE (self), &error); Py_END_ALLOW_THREADS if (error != NULL) return PyFrida_raise (error); if (result != NULL) - return PyApplication_from_handle (result); + return PyApplication_new_take_handle (result); else Py_RETURN_NONE; } @@ -1092,7 +1468,7 @@ PyDevice_enumerate_applications (PyDevice * self) PyObject * applications; Py_BEGIN_ALLOW_THREADS - result = frida_device_enumerate_applications_sync (self->handle, &error); + result = frida_device_enumerate_applications_sync (PY_GOBJECT_HANDLE (self), &error); Py_END_ALLOW_THREADS if (error != NULL) return PyFrida_raise (error); @@ -1101,7 +1477,7 @@ PyDevice_enumerate_applications (PyDevice * self) applications = PyList_New (result_length); for (i = 0; i != result_length; i++) { - PyList_SET_ITEM (applications, i, PyApplication_from_handle (frida_application_list_get (result, i))); + PyList_SET_ITEM (applications, i, PyApplication_new_take_handle (frida_application_list_get (result, i))); } g_object_unref (result); @@ -1117,7 +1493,7 @@ PyDevice_enumerate_processes (PyDevice * self) PyObject * processes; Py_BEGIN_ALLOW_THREADS - result = frida_device_enumerate_processes_sync (self->handle, &error); + result = frida_device_enumerate_processes_sync (PY_GOBJECT_HANDLE (self), &error); Py_END_ALLOW_THREADS if (error != NULL) return PyFrida_raise (error); @@ -1126,7 +1502,7 @@ PyDevice_enumerate_processes (PyDevice * self) processes = PyList_New (result_length); for (i = 0; i != result_length; i++) { - PyList_SET_ITEM (processes, i, PyProcess_from_handle (frida_process_list_get (result, i))); + PyList_SET_ITEM (processes, i, PyProcess_new_take_handle (frida_process_list_get (result, i))); } g_object_unref (result); @@ -1139,7 +1515,7 @@ PyDevice_enable_spawn_gating (PyDevice * self) GError * error = NULL; Py_BEGIN_ALLOW_THREADS - frida_device_enable_spawn_gating_sync (self->handle, &error); + frida_device_enable_spawn_gating_sync (PY_GOBJECT_HANDLE (self), &error); Py_END_ALLOW_THREADS if (error != NULL) return PyFrida_raise (error); @@ -1153,7 +1529,7 @@ PyDevice_disable_spawn_gating (PyDevice * self) GError * error = NULL; Py_BEGIN_ALLOW_THREADS - frida_device_enable_spawn_gating_sync (self->handle, &error); + frida_device_enable_spawn_gating_sync (PY_GOBJECT_HANDLE (self), &error); Py_END_ALLOW_THREADS if (error != NULL) return PyFrida_raise (error); @@ -1170,7 +1546,7 @@ PyDevice_enumerate_pending_spawns (PyDevice * self) PyObject * spawns; Py_BEGIN_ALLOW_THREADS - result = frida_device_enumerate_pending_spawns_sync (self->handle, &error); + result = frida_device_enumerate_pending_spawns_sync (PY_GOBJECT_HANDLE (self), &error); Py_END_ALLOW_THREADS if (error != NULL) return PyFrida_raise (error); @@ -1179,7 +1555,7 @@ PyDevice_enumerate_pending_spawns (PyDevice * self) spawns = PyList_New (result_length); for (i = 0; i != result_length; i++) { - PyList_SET_ITEM (spawns, i, PySpawn_from_handle (frida_spawn_list_get (result, i))); + PyList_SET_ITEM (spawns, i, PySpawn_new_take_handle (frida_spawn_list_get (result, i))); } g_object_unref (result); @@ -1233,7 +1609,7 @@ PyDevice_spawn (PyDevice * self, PyObject * args) envp_length = g_strv_length (envp); Py_BEGIN_ALLOW_THREADS - pid = frida_device_spawn_sync (self->handle, argv[0], argv, argc, envp, envp_length, &error); + pid = frida_device_spawn_sync (PY_GOBJECT_HANDLE (self), argv[0], argv, argc, envp, envp_length, &error); Py_END_ALLOW_THREADS g_strfreev (envp); @@ -1264,7 +1640,7 @@ PyDevice_input (PyDevice * self, PyObject * args) data = g_bytes_new (data_buffer, data_size); Py_BEGIN_ALLOW_THREADS - frida_device_input_sync (self->handle, (guint) pid, data, &error); + frida_device_input_sync (PY_GOBJECT_HANDLE (self), (guint) pid, data, &error); Py_END_ALLOW_THREADS g_bytes_unref (data); @@ -1285,7 +1661,7 @@ PyDevice_resume (PyDevice * self, PyObject * args) return NULL; Py_BEGIN_ALLOW_THREADS - frida_device_resume_sync (self->handle, (guint) pid, &error); + frida_device_resume_sync (PY_GOBJECT_HANDLE (self), (guint) pid, &error); Py_END_ALLOW_THREADS if (error != NULL) return PyFrida_raise (error); @@ -1303,7 +1679,7 @@ PyDevice_kill (PyDevice * self, PyObject * args) return NULL; Py_BEGIN_ALLOW_THREADS - frida_device_kill_sync (self->handle, (guint) pid, &error); + frida_device_kill_sync (PY_GOBJECT_HANDLE (self), (guint) pid, &error); Py_END_ALLOW_THREADS if (error != NULL) return PyFrida_raise (error); @@ -1322,12 +1698,12 @@ PyDevice_attach (PyDevice * self, PyObject * args) return NULL; Py_BEGIN_ALLOW_THREADS - handle = frida_device_attach_sync (self->handle, (guint) pid, &error); + handle = frida_device_attach_sync (PY_GOBJECT_HANDLE (self), (guint) pid, &error); Py_END_ALLOW_THREADS if (error != NULL) return PyFrida_raise (error); - return PySession_from_handle (handle); + return PySession_new_take_handle (handle); } static PyObject * @@ -1342,7 +1718,7 @@ PyDevice_inject_library_file (PyDevice * self, PyObject * args) return NULL; Py_BEGIN_ALLOW_THREADS - id = frida_device_inject_library_file_sync (self->handle, (guint) pid, path, entrypoint, data, &error); + id = frida_device_inject_library_file_sync (PY_GOBJECT_HANDLE (self), (guint) pid, path, entrypoint, data, &error); Py_END_ALLOW_THREADS if (error != NULL) return PyFrida_raise (error); @@ -1371,7 +1747,7 @@ PyDevice_inject_library_blob (PyDevice * self, PyObject * args) blob = g_bytes_new (blob_buffer, blob_size); Py_BEGIN_ALLOW_THREADS - id = frida_device_inject_library_blob_sync (self->handle, (guint) pid, blob, entrypoint, data, &error); + id = frida_device_inject_library_blob_sync (PY_GOBJECT_HANDLE (self), (guint) pid, blob, entrypoint, data, &error); Py_END_ALLOW_THREADS g_bytes_unref (blob); @@ -1382,349 +1758,41 @@ PyDevice_inject_library_blob (PyDevice * self, PyObject * args) return PyLong_FromUnsignedLong (id); } -static PyObject * -PyDevice_on (PyDevice * self, PyObject * args) -{ - const char * signal; - PyObject * callback; - - if (!PyFrida_parse_signal_method_args (args, &signal, &callback)) - return NULL; - - if (strcmp (signal, "spawned") == 0) - { - if (self->on_spawned == NULL) - { - g_signal_connect_swapped (self->handle, "spawned", G_CALLBACK (PyDevice_on_spawned), self); - } - - Py_INCREF (callback); - self->on_spawned = g_list_append (self->on_spawned, callback); - } - else if (strcmp (signal, "output") == 0) - { - if (self->on_output == NULL) - { - g_signal_connect_swapped (self->handle, "output", G_CALLBACK (PyDevice_on_output), self); - } - - Py_INCREF (callback); - self->on_output = g_list_append (self->on_output, callback); - } - else if (strcmp (signal, "uninjected") == 0) - { - if (self->on_uninjected == NULL) - { - g_signal_connect_swapped (self->handle, "uninjected", G_CALLBACK (PyDevice_on_uninjected), self); - } - - Py_INCREF (callback); - self->on_uninjected = g_list_append (self->on_uninjected, callback); - } - else if (strcmp (signal, "lost") == 0) - { - if (self->on_lost == NULL) - { - g_signal_connect_swapped (self->handle, "lost", G_CALLBACK (PyDevice_on_lost), self); - } - - Py_INCREF (callback); - self->on_lost = g_list_append (self->on_lost, callback); - } - else - { - PyErr_SetString (PyExc_NotImplementedError, "unsupported signal"); - return NULL; - } - - Py_RETURN_NONE; -} static PyObject * -PyDevice_off (PyDevice * self, PyObject * args) +PyApplication_new_take_handle (FridaApplication * handle) { - const char * signal; - PyObject * callback; - - if (!PyFrida_parse_signal_method_args (args, &signal, &callback)) - return NULL; - - if (strcmp (signal, "spawned") == 0) - { - GList * entry; - - entry = g_list_find_custom (self->on_spawned, callback, PyFrida_compare_pyobjects); - if (entry != NULL) - { - self->on_spawned = g_list_delete_link (self->on_spawned, entry); - Py_DECREF (callback); - } - else - { - PyErr_SetString (PyExc_ValueError, "unknown callback"); - return NULL; - } - - if (self->on_spawned == NULL) - { - g_signal_handlers_disconnect_by_func (self->handle, FRIDA_FUNCPTR_TO_POINTER (PyDevice_on_spawned), self); - } - } - else if (strcmp (signal, "output") == 0) - { - GList * entry; - - entry = g_list_find_custom (self->on_output, callback, PyFrida_compare_pyobjects); - if (entry != NULL) - { - self->on_output = g_list_delete_link (self->on_output, entry); - Py_DECREF (callback); - } - else - { - PyErr_SetString (PyExc_ValueError, "unknown callback"); - return NULL; - } - - if (self->on_output == NULL) - { - g_signal_handlers_disconnect_by_func (self->handle, FRIDA_FUNCPTR_TO_POINTER (PyDevice_on_output), self); - } - } - else if (strcmp (signal, "uninjected") == 0) - { - GList * entry; - - entry = g_list_find_custom (self->on_uninjected, callback, PyFrida_compare_pyobjects); - if (entry != NULL) - { - self->on_uninjected = g_list_delete_link (self->on_uninjected, entry); - Py_DECREF (callback); - } - else - { - PyErr_SetString (PyExc_ValueError, "unknown callback"); - return NULL; - } - - if (self->on_uninjected == NULL) - { - g_signal_handlers_disconnect_by_func (self->handle, FRIDA_FUNCPTR_TO_POINTER (PyDevice_on_uninjected), self); - } - } - else if (strcmp (signal, "lost") == 0) - { - GList * entry; - - entry = g_list_find_custom (self->on_lost, callback, PyFrida_compare_pyobjects); - if (entry != NULL) - { - self->on_lost = g_list_delete_link (self->on_lost, entry); - Py_DECREF (callback); - } - else - { - PyErr_SetString (PyExc_ValueError, "unknown callback"); - return NULL; - } - - if (self->on_lost == NULL) - { - g_signal_handlers_disconnect_by_func (self->handle, FRIDA_FUNCPTR_TO_POINTER (PyDevice_on_lost), self); - } - } - else - { - PyErr_SetString (PyExc_NotImplementedError, "unsupported signal"); - return NULL; - } - - Py_RETURN_NONE; -} - -static void -PyDevice_on_spawned (PyDevice * self, FridaSpawn * spawn, FridaDevice * handle) -{ - PyGILState_STATE gstate; - - gstate = PyGILState_Ensure (); - - if (g_object_get_data (G_OBJECT (handle), "pyobject") == self) - { - PyObject * args; - GList * callbacks, * cur; - - g_object_ref (spawn); - args = PyTuple_Pack (1, PySpawn_from_handle (spawn)); - - g_list_foreach (self->on_spawned, (GFunc) Py_IncRef, NULL); - callbacks = g_list_copy (self->on_spawned); - - for (cur = callbacks; cur != NULL; cur = cur->next) - { - PyObject * result = PyObject_CallObject ((PyObject *) cur->data, args); - if (result == NULL) - PyErr_Print (); - else - Py_DECREF (result); - } - - g_list_free_full (callbacks, (GDestroyNotify) Py_DecRef); - - Py_DECREF (args); - } - - PyGILState_Release (gstate); -} - -static void -PyDevice_on_output (PyDevice * self, guint pid, gint fd, GBytes * data, FridaDevice * handle) -{ - PyGILState_STATE gstate; - - gstate = PyGILState_Ensure (); - - if (g_object_get_data (G_OBJECT (handle), "pyobject") == self) - { - gconstpointer data_buffer; - gsize data_size; - PyObject * args; - GList * callbacks, * cur; - - data_buffer = g_bytes_get_data (data, &data_size); - -#if PY_MAJOR_VERSION >= 3 - args = Py_BuildValue ("Iiy#", pid, fd, data_buffer, (int) data_size); -#else - args = Py_BuildValue ("Iis#", pid, fd, data_buffer, (int) data_size); -#endif - - g_list_foreach (self->on_output, (GFunc) Py_IncRef, NULL); - callbacks = g_list_copy (self->on_output); - - for (cur = callbacks; cur != NULL; cur = cur->next) - { - PyObject * result = PyObject_CallObject ((PyObject *) cur->data, args); - if (result == NULL) - PyErr_Print (); - else - Py_DECREF (result); - } - - g_list_free_full (callbacks, (GDestroyNotify) Py_DecRef); - - Py_DECREF (args); - } - - PyGILState_Release (gstate); -} - -static void -PyDevice_on_uninjected (PyDevice * self, guint id, FridaDevice * handle) -{ - PyGILState_STATE gstate; - - gstate = PyGILState_Ensure (); - - if (g_object_get_data (G_OBJECT (handle), "pyobject") == self) - { - PyObject * args; - GList * callbacks, * cur; - - args = Py_BuildValue ("(I)", id); - - g_list_foreach (self->on_uninjected, (GFunc) Py_IncRef, NULL); - callbacks = g_list_copy (self->on_uninjected); - - for (cur = callbacks; cur != NULL; cur = cur->next) - { - PyObject * result = PyObject_CallObject ((PyObject *) cur->data, args); - if (result == NULL) - PyErr_Print (); - else - Py_DECREF (result); - } - - g_list_free_full (callbacks, (GDestroyNotify) Py_DecRef); - - Py_DECREF (args); - } - - PyGILState_Release (gstate); -} - -static void -PyDevice_on_lost (PyDevice * self, FridaDevice * handle) -{ - PyGILState_STATE gstate; - - gstate = PyGILState_Ensure (); - - if (g_object_get_data (G_OBJECT (handle), "pyobject") == self) - { - GList * callbacks, * cur; - - g_list_foreach (self->on_lost, (GFunc) Py_IncRef, NULL); - callbacks = g_list_copy (self->on_lost); - - for (cur = callbacks; cur != NULL; cur = cur->next) - { - PyObject * result = PyObject_CallFunction ((PyObject *) cur->data, NULL); - if (result == NULL) - PyErr_Print (); - else - Py_DECREF (result); - } - - g_list_free_full (callbacks, (GDestroyNotify) Py_DecRef); - } - - PyGILState_Release (gstate); -} - - -static PyObject * -PyApplication_from_handle (FridaApplication * handle) -{ - const gchar * identifier, * name; - PyObject * result; - PyApplication * application; - - identifier = frida_application_get_identifier (handle); - name = frida_application_get_name (handle); - - result = PyObject_CallFunction ((PyObject *) &PyApplicationType, NULL); - - application = (PyApplication *) result; - application->handle = handle; - application->identifier = PyUnicode_FromUTF8String (identifier); - application->name = PyUnicode_FromUTF8String (name); - application->pid = frida_application_get_pid (handle); - - return result; + return PyGObject_new_take_handle (handle, &PYFRIDA_TYPE_SPEC (Application)); } static int -PyApplication_init (PyApplication * self) +PyApplication_init (PyApplication * self, PyObject * args, PyObject * kw) { - self->handle = NULL; + if (PyGObjectType.tp_init ((PyObject *) self, args, kw) < 0) + return -1; self->identifier = NULL; self->name = NULL; + self->pid = 0; return 0; } +static void +PyApplication_init_from_handle (PyApplication * self, FridaApplication * handle) +{ + self->identifier = PyUnicode_FromUTF8String (frida_application_get_identifier (handle)); + self->name = PyUnicode_FromUTF8String (frida_application_get_name (handle)); + self->pid = frida_application_get_pid (handle); +} + static void PyApplication_dealloc (PyApplication * self) { Py_XDECREF (self->name); Py_XDECREF (self->identifier); - if (self->handle != NULL) - g_object_unref (self->handle); - - Py_TYPE (self)->tp_free ((PyObject *) self); + PyGObjectType.tp_dealloc ((PyObject *) self); } static PyObject * @@ -1758,39 +1826,27 @@ PyApplication_repr (PyApplication * self) static PyObject * PyApplication_get_small_icon (PyApplication * self) { - return PyIcon_from_handle (frida_application_get_small_icon (self->handle)); + return PyIcon_new_from_handle (frida_application_get_small_icon (PY_GOBJECT_HANDLE (self))); } static PyObject * PyApplication_get_large_icon (PyApplication * self) { - return PyIcon_from_handle (frida_application_get_large_icon (self->handle)); + return PyIcon_new_from_handle (frida_application_get_large_icon (PY_GOBJECT_HANDLE (self))); } static PyObject * -PyProcess_from_handle (FridaProcess * handle) +PyProcess_new_take_handle (FridaProcess * handle) { - const gchar * name; - PyObject * result; - PyProcess * process; - - name = frida_process_get_name (handle); - - result = PyObject_CallFunction ((PyObject *) &PyProcessType, NULL); - - process = (PyProcess *) result; - process->handle = handle; - process->pid = frida_process_get_pid (handle); - process->name = PyUnicode_FromUTF8String (name); - - return result; + return PyGObject_new_take_handle (handle, &PYFRIDA_TYPE_SPEC (Process)); } static int -PyProcess_init (PyProcess * self) +PyProcess_init (PyProcess * self, PyObject * args, PyObject * kw) { - self->handle = NULL; + if (PyGObjectType.tp_init ((PyObject *) self, args, kw) < 0) + return -1; self->pid = 0; self->name = NULL; @@ -1798,15 +1854,19 @@ PyProcess_init (PyProcess * self) return 0; } +static void +PyProcess_init_from_handle (PyProcess * self, FridaProcess * handle) +{ + self->pid = frida_process_get_pid (handle); + self->name = PyUnicode_FromUTF8String (frida_process_get_name (handle)); +} + static void PyProcess_dealloc (PyProcess * self) { Py_XDECREF (self->name); - if (self->handle != NULL) - g_object_unref (self->handle); - - Py_TYPE (self)->tp_free ((PyObject *) self); + PyGObjectType.tp_dealloc ((PyObject *) self); } static PyObject * @@ -1828,39 +1888,27 @@ PyProcess_repr (PyProcess * self) static PyObject * PyProcess_get_small_icon (PyProcess * self) { - return PyIcon_from_handle (frida_process_get_small_icon (self->handle)); + return PyIcon_new_from_handle (frida_process_get_small_icon (PY_GOBJECT_HANDLE (self))); } static PyObject * PyProcess_get_large_icon (PyProcess * self) { - return PyIcon_from_handle (frida_process_get_large_icon (self->handle)); + return PyIcon_new_from_handle (frida_process_get_large_icon (PY_GOBJECT_HANDLE (self))); } static PyObject * -PySpawn_from_handle (FridaSpawn * handle) +PySpawn_new_take_handle (FridaSpawn * handle) { - const gchar * identifier; - PyObject * result; - PySpawn * spawn; - - identifier = frida_spawn_get_identifier (handle); - - result = PyObject_CallFunction ((PyObject *) &PySpawnType, NULL); - - spawn = (PySpawn *) result; - spawn->handle = handle; - spawn->pid = frida_spawn_get_pid (handle); - spawn->identifier = PyUnicode_FromUTF8String (identifier); - - return result; + return PyGObject_new_take_handle (handle, &PYFRIDA_TYPE_SPEC (Spawn)); } static int -PySpawn_init (PySpawn * self) +PySpawn_init (PySpawn * self, PyObject * args, PyObject * kw) { - self->handle = NULL; + if (PyGObjectType.tp_init ((PyObject *) self, args, kw) < 0) + return -1; self->pid = 0; self->identifier = NULL; @@ -1868,15 +1916,19 @@ PySpawn_init (PySpawn * self) return 0; } +static void +PySpawn_init_from_handle (PySpawn * self, FridaSpawn * handle) +{ + self->pid = frida_spawn_get_pid (handle); + self->identifier = PyUnicode_FromUTF8String (frida_spawn_get_identifier (handle)); +} + static void PySpawn_dealloc (PySpawn * self) { Py_XDECREF (self->identifier); - if (self->handle != NULL) - g_object_unref (self->handle); - - Py_TYPE (self)->tp_free ((PyObject *) self); + PyGObjectType.tp_dealloc ((PyObject *) self); } static PyObject * @@ -1905,33 +1957,20 @@ PySpawn_repr (PySpawn * self) static PyObject * -PyIcon_from_handle (FridaIcon * handle) +PyIcon_new_from_handle (FridaIcon * handle) { if (handle != NULL) - { - PyObject * result; - PyIcon * icon; - gconstpointer pixels; - gsize pixels_size; + g_object_ref (handle); - result = PyObject_CallFunction ((PyObject *) &PyIconType, NULL); - - icon = (PyIcon *) result; - icon->width = frida_icon_get_width (handle); - icon->height = frida_icon_get_height (handle); - icon->rowstride = frida_icon_get_rowstride (handle); - pixels = g_bytes_get_data (frida_icon_get_pixels (handle), &pixels_size); - icon->pixels = PyBytes_FromStringAndSize ((char *) pixels, (Py_ssize_t) pixels_size); - - return result; - } - - Py_RETURN_NONE; + return PyGObject_new_take_handle (handle, &PYFRIDA_TYPE_SPEC (Icon)); } static int -PyIcon_init (PyIcon * self) +PyIcon_init (PyIcon * self, PyObject * args, PyObject * kw) { + if (PyGObjectType.tp_init ((PyObject *) self, args, kw) < 0) + return -1; + self->width = 0; self->height = 0; self->rowstride = 0; @@ -1940,12 +1979,25 @@ PyIcon_init (PyIcon * self) return 0; } +static void +PyIcon_init_from_handle (PyIcon * self, FridaIcon * handle) +{ + gconstpointer pixels; + gsize pixels_size; + + self->width = frida_icon_get_width (handle); + self->height = frida_icon_get_height (handle); + self->rowstride = frida_icon_get_rowstride (handle); + pixels = g_bytes_get_data (frida_icon_get_pixels (handle), &pixels_size); + self->pixels = PyBytes_FromStringAndSize ((char *) pixels, (Py_ssize_t) pixels_size); +} + static void PyIcon_dealloc (PyIcon * self) { Py_XDECREF (self->pixels); - Py_TYPE (self)->tp_free ((PyObject *) self); + PyGObjectType.tp_dealloc ((PyObject *) self); } static PyObject * @@ -1956,60 +2008,39 @@ PyIcon_repr (PyIcon * self) static PyObject * -PySession_from_handle (FridaSession * handle) +PySession_new_take_handle (FridaSession * handle) { - PyObject * session; - - session = g_object_get_data (G_OBJECT (handle), "pyobject"); - if (session == NULL) - { - session = PyObject_CallFunction ((PyObject *) &PySessionType, NULL); - ((PySession *) session)->handle = handle; - g_object_set_data (G_OBJECT (handle), "pyobject", session); - } - else - { - frida_unref (handle); - Py_INCREF (session); - } - - return session; + return PyGObject_new_take_handle (handle, &PYFRIDA_TYPE_SPEC (Session)); } static int -PySession_init (PySession * self) +PySession_init (PySession * self, PyObject * args, PyObject * kw) { - self->handle = NULL; - self->on_detached = NULL; + if (PyGObjectType.tp_init ((PyObject *) self, args, kw) < 0) + return -1; + + self->pid = 0; return 0; } static void -PySession_dealloc (PySession * self) +PySession_init_from_handle (PySession * self, FridaSession * handle) { - if (self->on_detached != NULL) - { - g_signal_handlers_disconnect_by_func (self->handle, FRIDA_FUNCPTR_TO_POINTER (PySession_on_detached), self); - g_list_free_full (self->on_detached, (GDestroyNotify) Py_DecRef); - } + self->pid = frida_session_get_pid (handle); +} - if (self->handle != NULL) - { - g_object_set_data (G_OBJECT (self->handle), "pyobject", NULL); - Py_BEGIN_ALLOW_THREADS - frida_unref (self->handle); - Py_END_ALLOW_THREADS - } - - Py_TYPE (self)->tp_free ((PyObject *) self); +static PyObject * +PySession_repr (PySession * self) +{ + return PyRepr_FromFormat ("Session(pid=%u)", self->pid); } static PyObject * PySession_detach (PySession * self) { Py_BEGIN_ALLOW_THREADS - frida_session_detach_sync (self->handle); + frida_session_detach_sync (PY_GOBJECT_HANDLE (self)); Py_END_ALLOW_THREADS Py_RETURN_NONE; @@ -2027,7 +2058,7 @@ PySession_create_script (PySession * self, PyObject * args, PyObject * kw) return NULL; Py_BEGIN_ALLOW_THREADS - handle = frida_session_create_script_sync (self->handle, name, source, &error); + handle = frida_session_create_script_sync (PY_GOBJECT_HANDLE (self), name, source, &error); Py_END_ALLOW_THREADS PyMem_Free (source); @@ -2036,7 +2067,7 @@ PySession_create_script (PySession * self, PyObject * args, PyObject * kw) if (error != NULL) return PyFrida_raise (error); - return PyScript_from_handle (handle); + return PyScript_new_take_handle (handle); } static PyObject * @@ -2060,7 +2091,7 @@ PySession_create_script_from_bytes (PySession * self, PyObject * args, PyObject bytes = g_bytes_new (data, size); Py_BEGIN_ALLOW_THREADS - handle = frida_session_create_script_from_bytes_sync (self->handle, name, bytes, &error); + handle = frida_session_create_script_from_bytes_sync (PY_GOBJECT_HANDLE (self), name, bytes, &error); Py_END_ALLOW_THREADS g_bytes_unref (bytes); @@ -2069,7 +2100,7 @@ PySession_create_script_from_bytes (PySession * self, PyObject * args, PyObject if (error != NULL) return PyFrida_raise (error); - return PyScript_from_handle (handle); + return PyScript_new_take_handle (handle); } static PyObject * @@ -2087,7 +2118,7 @@ PySession_compile_script (PySession * self, PyObject * args, PyObject * kw) return NULL; Py_BEGIN_ALLOW_THREADS - bytes = frida_session_compile_script_sync (self->handle, source, &error); + bytes = frida_session_compile_script_sync (PY_GOBJECT_HANDLE (self), source, &error); Py_END_ALLOW_THREADS PyMem_Free (source); @@ -2113,7 +2144,7 @@ PySession_enable_debugger (PySession * self, PyObject * args, PyObject * kw) return NULL; Py_BEGIN_ALLOW_THREADS - frida_session_enable_debugger_sync (self->handle, port, &error); + frida_session_enable_debugger_sync (PY_GOBJECT_HANDLE (self), port, &error); Py_END_ALLOW_THREADS if (error != NULL) return PyFrida_raise (error); @@ -2127,7 +2158,7 @@ PySession_disable_debugger (PySession * self) GError * error = NULL; Py_BEGIN_ALLOW_THREADS - frida_session_disable_debugger_sync (self->handle, &error); + frida_session_disable_debugger_sync (PY_GOBJECT_HANDLE (self), &error); Py_END_ALLOW_THREADS if (error != NULL) return PyFrida_raise (error); @@ -2141,7 +2172,7 @@ PySession_enable_jit (PySession * self) GError * error = NULL; Py_BEGIN_ALLOW_THREADS - frida_session_enable_jit_sync (self->handle, &error); + frida_session_enable_jit_sync (PY_GOBJECT_HANDLE (self), &error); Py_END_ALLOW_THREADS if (error != NULL) return PyFrida_raise (error); @@ -2149,163 +2180,11 @@ PySession_enable_jit (PySession * self) Py_RETURN_NONE; } -static PyObject * -PySession_on (PySession * self, PyObject * args) -{ - const char * signal; - PyObject * callback; - - if (!PyFrida_parse_signal_method_args (args, &signal, &callback)) - return NULL; - - if (strcmp (signal, "detached") == 0) - { - if (self->on_detached == NULL) - { - g_signal_connect_swapped (self->handle, "detached", G_CALLBACK (PySession_on_detached), self); - } - - Py_INCREF (callback); - self->on_detached = g_list_append (self->on_detached, callback); - } - else - { - PyErr_SetString (PyExc_NotImplementedError, "unsupported signal"); - return NULL; - } - - Py_RETURN_NONE; -} static PyObject * -PySession_off (PySession * self, PyObject * args) +PyScript_new_take_handle (FridaScript * handle) { - const char * signal; - PyObject * callback; - - if (!PyFrida_parse_signal_method_args (args, &signal, &callback)) - return NULL; - - if (strcmp (signal, "detached") == 0) - { - GList * entry; - - entry = g_list_find_custom (self->on_detached, callback, PyFrida_compare_pyobjects); - if (entry != NULL) - { - self->on_detached = g_list_delete_link (self->on_detached, entry); - Py_DECREF (callback); - } - else - { - PyErr_SetString (PyExc_ValueError, "unknown callback"); - return NULL; - } - - if (self->on_detached == NULL) - { - g_signal_handlers_disconnect_by_func (self->handle, FRIDA_FUNCPTR_TO_POINTER (PySession_on_detached), self); - } - } - else - { - PyErr_SetString (PyExc_NotImplementedError, "unsupported signal"); - return NULL; - } - - Py_RETURN_NONE; -} - -static void -PySession_on_detached (PySession * self, FridaSessionDetachReason reason, FridaSession * handle) -{ - PyGILState_STATE gstate; - - gstate = PyGILState_Ensure (); - - if (g_object_get_data (G_OBJECT (handle), "pyobject") == self) - { - GEnumClass * enum_class; - GEnumValue * enum_value; - PyObject * args; - GList * callbacks, * cur; - - enum_class = g_type_class_ref (FRIDA_TYPE_SESSION_DETACH_REASON); - enum_value = g_enum_get_value (enum_class, reason); - g_assert (enum_value != NULL); - args = Py_BuildValue ("(s)", enum_value->value_nick); - g_type_class_unref (enum_class); - - g_list_foreach (self->on_detached, (GFunc) Py_IncRef, NULL); - callbacks = g_list_copy (self->on_detached); - - for (cur = callbacks; cur != NULL; cur = cur->next) - { - PyObject * callback = (PyObject *) cur->data; - PyObject * result; - - /* TODO: remove this argument list kludge in Frida 10.x */ - result = PyObject_CallObject (callback, (PyFrida_get_max_argument_count (callback) == 0) ? NULL : args); - if (result == NULL) - PyErr_Print (); - else - Py_DECREF (result); - } - - g_list_free_full (callbacks, (GDestroyNotify) Py_DecRef); - - Py_DECREF (args); - } - - PyGILState_Release (gstate); -} - - -static PyObject * -PyScript_from_handle (FridaScript * handle) -{ - PyObject * script; - - script = g_object_get_data (G_OBJECT (handle), "pyobject"); - if (script == NULL) - { - script = PyObject_CallFunction ((PyObject *) &PyScriptType, NULL); - ((PyScript *) script)->handle = handle; - g_object_set_data (G_OBJECT (handle), "pyobject", script); - g_signal_connect_swapped (handle, "message", G_CALLBACK (PyScript_on_message), script); - } - else - { - frida_unref (handle); - Py_INCREF (script); - } - - return script; -} - -static int -PyScript_init (PyScript * self) -{ - self->handle = NULL; - self->on_message = NULL; - - return 0; -} - -static void -PyScript_dealloc (PyScript * self) -{ - if (self->handle != NULL) - { - g_signal_handlers_disconnect_by_func (self->handle, FRIDA_FUNCPTR_TO_POINTER (PyScript_on_message), self); - g_list_free_full (self->on_message, (GDestroyNotify) Py_DecRef); - g_object_set_data (G_OBJECT (self->handle), "pyobject", NULL); - Py_BEGIN_ALLOW_THREADS - frida_unref (self->handle); - Py_END_ALLOW_THREADS - } - - Py_TYPE (self)->tp_free ((PyObject *) self); + return PyGObject_new_take_handle (handle, &PYFRIDA_TYPE_SPEC (Script)); } static PyObject * @@ -2314,7 +2193,7 @@ PyScript_load (PyScript * self) GError * error = NULL; Py_BEGIN_ALLOW_THREADS - frida_script_load_sync (self->handle, &error); + frida_script_load_sync (PY_GOBJECT_HANDLE (self), &error); Py_END_ALLOW_THREADS if (error != NULL) return PyFrida_raise (error); @@ -2328,7 +2207,7 @@ PyScript_unload (PyScript * self) GError * error = NULL; Py_BEGIN_ALLOW_THREADS - frida_script_unload_sync (self->handle, &error); + frida_script_unload_sync (PY_GOBJECT_HANDLE (self), &error); Py_END_ALLOW_THREADS if (error != NULL) return PyFrida_raise (error); @@ -2340,43 +2219,22 @@ static PyObject * PyScript_post (PyScript * self, PyObject * args, PyObject * kw) { static char * keywords[] = { "message", "data", NULL }; - PyObject * message_object, * message_json; + char * message; gconstpointer data_buffer = NULL; int data_size = 0; - char * message_utf8; GBytes * data; GError * error = NULL; - if (!PyArg_ParseTupleAndKeywords (args, kw, "O|z#", keywords, &message_object, &data_buffer, &data_size)) + if (!PyArg_ParseTupleAndKeywords (args, kw, "es|z#", keywords, "utf-8", &message, &data_buffer, &data_size)) return NULL; - - message_json = PyObject_CallFunction (json_dumps, "O", message_object); - if (message_json == NULL) - return NULL; - -#if PY_MAJOR_VERSION >= 3 - { - PyObject * message_bytes; - - message_bytes = PyUnicode_AsUTF8String (message_json); - Py_DECREF (message_json); - message_json = message_bytes; - - message_utf8 = PyBytes_AsString (message_bytes); - } -#else - message_utf8 = PyString_AsString (message_json); -#endif - data = (data_buffer != NULL) ? g_bytes_new (data_buffer, data_size) : NULL; Py_BEGIN_ALLOW_THREADS - frida_script_post_sync (self->handle, message_utf8, data, &error); + frida_script_post_sync (PY_GOBJECT_HANDLE (self), message, data, &error); Py_END_ALLOW_THREADS g_bytes_unref (data); - - Py_DECREF (message_json); + PyMem_Free (message); if (error != NULL) return PyFrida_raise (error); @@ -2384,388 +2242,51 @@ PyScript_post (PyScript * self, PyObject * args, PyObject * kw) Py_RETURN_NONE; } -static PyObject * -PyScript_on (PyScript * self, PyObject * args) -{ - const char * signal; - PyObject * callback; - - if (!PyFrida_parse_signal_method_args (args, &signal, &callback)) - return NULL; - - if (strcmp (signal, "message") == 0) - { - Py_INCREF (callback); - self->on_message = g_list_append (self->on_message, callback); - } - else - { - PyErr_SetString (PyExc_NotImplementedError, "unsupported signal"); - return NULL; - } - - Py_RETURN_NONE; -} - -static PyObject * -PyScript_off (PyScript * self, PyObject * args) -{ - const char * signal; - PyObject * callback; - - if (!PyFrida_parse_signal_method_args (args, &signal, &callback)) - return NULL; - - if (strcmp (signal, "message") == 0) - { - GList * entry; - - entry = g_list_find_custom (self->on_message, callback, PyFrida_compare_pyobjects); - if (entry != NULL) - { - self->on_message = g_list_delete_link (self->on_message, entry); - Py_DECREF (callback); - } - else - { - PyErr_SetString (PyExc_ValueError, "unknown callback"); - return NULL; - } - } - else - { - PyErr_SetString (PyExc_NotImplementedError, "unsupported signal"); - return NULL; - } - - Py_RETURN_NONE; -} - -static void -PyScript_on_message (PyScript * self, const gchar * message, GBytes * data, FridaScript * handle) -{ - PyGILState_STATE gstate; - - gstate = PyGILState_Ensure (); - - if (g_object_get_data (G_OBJECT (handle), "pyobject") == self) - { - PyObject * message_object, * args; - gconstpointer data_buffer; - gsize data_size; - GList * callbacks, * cur; - - message_object = PyObject_CallFunction (json_loads, "s", message); - g_assert (message_object != NULL); - - if (data != NULL) - { - data_buffer = g_bytes_get_data (data, &data_size); - } - else - { - data_buffer = NULL; - data_size = 0; - } - -#if PY_MAJOR_VERSION >= 3 - args = Py_BuildValue ("Oy#", message_object, data_buffer, (int) data_size); -#else - args = Py_BuildValue ("Os#", message_object, data_buffer, (int) data_size); -#endif - - g_list_foreach (self->on_message, (GFunc) Py_IncRef, NULL); - callbacks = g_list_copy (self->on_message); - - for (cur = callbacks; cur != NULL; cur = cur->next) - { - PyObject * result = PyObject_CallObject ((PyObject *) cur->data, args); - if (result == NULL) - PyErr_Print (); - else - Py_DECREF (result); - } - - g_list_free_full (callbacks, (GDestroyNotify) Py_DecRef); - - Py_DECREF (args); - - Py_DECREF (message_object); - } - - PyGILState_Release (gstate); -} - static int -PyFileMonitor_init (PyFileMonitor * self, PyObject * args) +PyFileMonitor_init (PyFileMonitor * self, PyObject * args, PyObject * kw) { const char * path; - self->file = NULL; - self->monitor = NULL; - self->on_change = NULL; + if (PyGObjectType.tp_init ((PyObject *) self, args, kw) < 0) + return -1; if (!PyArg_ParseTuple (args, "s", &path)) return -1; - self->file = g_file_new_for_path (path); + PyGObject_take_handle (&self->parent, frida_file_monitor_new (path), &PYFRIDA_TYPE_SPEC (FileMonitor)); return 0; } -static void -PyFileMonitor_dealloc (PyFileMonitor * self) -{ - g_list_free_full (self->on_change, (GDestroyNotify) Py_DecRef); - self->on_change = NULL; - - if (self->monitor != NULL) - { - g_signal_handlers_disconnect_by_func (self->monitor, FRIDA_FUNCPTR_TO_POINTER (PyFileMonitor_on_change), self); - g_object_set_data (G_OBJECT (self->monitor), "pyobject", NULL); - } - - Py_BEGIN_ALLOW_THREADS - if (self->monitor != NULL) - frida_unref (self->monitor); - Py_END_ALLOW_THREADS - - g_clear_object (&self->file); - - Py_TYPE (self)->tp_free ((PyObject *) self); -} - static PyObject * PyFileMonitor_enable (PyFileMonitor * self) { - GSource * source; - - Py_INCREF (self); + GError * error = NULL; Py_BEGIN_ALLOW_THREADS - - source = g_idle_source_new (); - g_source_set_callback (source, (GSourceFunc) PyFileMonitor_do_enable, self, NULL); - g_source_attach (source, frida_get_main_context ()); - g_source_unref (source); - + frida_file_monitor_enable_sync (PY_GOBJECT_HANDLE (self), NULL, &error); Py_END_ALLOW_THREADS + if (error != NULL) + return PyFrida_raise (error); Py_RETURN_NONE; } -static gboolean -PyFileMonitor_do_enable (PyFileMonitor * self) -{ - PyGILState_STATE gstate; - - if (self->monitor == NULL) - { - self->monitor = g_file_monitor (self->file, G_FILE_MONITOR_NONE, NULL, NULL); - - if (self->monitor != NULL) - { - g_object_set_data (G_OBJECT (self->monitor), "pyobject", self); - g_signal_connect_swapped (self->monitor, "changed", G_CALLBACK (PyFileMonitor_on_change), self); - } - } - - gstate = PyGILState_Ensure (); - Py_DECREF (self); - PyGILState_Release (gstate); - - return FALSE; -} - static PyObject * PyFileMonitor_disable (PyFileMonitor * self) { - GSource * source; - - Py_INCREF (self); + GError * error = NULL; Py_BEGIN_ALLOW_THREADS - - source = g_idle_source_new (); - g_source_set_callback (source, (GSourceFunc) PyFileMonitor_do_disable, self, NULL); - g_source_attach (source, frida_get_main_context ()); - g_source_unref (source); - + frida_file_monitor_disable_sync (PY_GOBJECT_HANDLE (self), &error); Py_END_ALLOW_THREADS + if (error != NULL) + return PyFrida_raise (error); Py_RETURN_NONE; } -static gboolean -PyFileMonitor_do_disable (PyFileMonitor * self) -{ - PyGILState_STATE gstate; - - if (self->monitor != NULL) - { - g_signal_handlers_disconnect_by_func (self->monitor, FRIDA_FUNCPTR_TO_POINTER (PyFileMonitor_on_change), self); - g_file_monitor_cancel (self->monitor); - g_object_unref (self->monitor); - self->monitor = NULL; - } - - gstate = PyGILState_Ensure (); - Py_DECREF (self); - PyGILState_Release (gstate); - - return FALSE; -} - -static PyObject * -PyFileMonitor_on (PyFileMonitor * self, PyObject * args) -{ - const char * signal; - PyObject * callback; - - if (!PyFrida_parse_signal_method_args (args, &signal, &callback)) - return NULL; - - if (strcmp (signal, "change") == 0) - { - Py_INCREF (callback); - self->on_change = g_list_append (self->on_change, callback); - } - else - { - PyErr_SetString (PyExc_NotImplementedError, "unsupported signal"); - return NULL; - } - - Py_RETURN_NONE; -} - -static PyObject * -PyFileMonitor_off (PyFileMonitor * self, PyObject * args) -{ - const char * signal; - PyObject * callback; - - if (!PyFrida_parse_signal_method_args (args, &signal, &callback)) - return NULL; - - if (strcmp (signal, "change") == 0) - { - GList * entry; - - entry = g_list_find_custom (self->on_change, callback, PyFrida_compare_pyobjects); - if (entry != NULL) - { - self->on_change = g_list_delete_link (self->on_change, entry); - Py_DECREF (callback); - } - else - { - PyErr_SetString (PyExc_ValueError, "unknown callback"); - return NULL; - } - } - else - { - PyErr_SetString (PyExc_NotImplementedError, "unsupported signal"); - return NULL; - } - - Py_RETURN_NONE; -} - -static void -PyFileMonitor_on_change (PyFileMonitor * self, GFile * file, GFile * other_file, GFileMonitorEvent event_type, GFileMonitor * monitor) -{ - PyGILState_STATE gstate; - - gstate = PyGILState_Ensure (); - - if (g_object_get_data (G_OBJECT (monitor), "pyobject") == self) - { - gchar * file_path, * other_file_path; - const gchar * event_type_string; - PyObject * args; - GList * callbacks, * cur; - - file_path = PyFileMonitor_get_file_path (file); - other_file_path = PyFileMonitor_get_file_path (other_file); - event_type_string = PyFileMonitor_event_type_to_string (event_type); - - args = Py_BuildValue ("sss", file_path, other_file_path, event_type_string); - - g_free (other_file_path); - g_free (file_path); - - g_list_foreach (self->on_change, (GFunc) Py_IncRef, NULL); - callbacks = g_list_copy (self->on_change); - - for (cur = callbacks; cur != NULL; cur = cur->next) - { - PyObject * result = PyObject_CallObject ((PyObject *) cur->data, args); - if (result == NULL) - PyErr_Print (); - else - Py_DECREF (result); - } - - g_list_free_full (callbacks, (GDestroyNotify) Py_DecRef); - - Py_DECREF (args); - } - - PyGILState_Release (gstate); -} - -static gchar * -PyFileMonitor_get_file_path (GFile * file) -{ - gchar * path_raw, * path_utf8; - - if (file == NULL) - return NULL; - - path_raw = g_file_get_path (file); - if (path_raw == NULL) - return NULL; - path_utf8 = g_filename_to_utf8 (path_raw, -1, NULL, NULL, NULL); - g_free (path_raw); - - return path_utf8; -} - -static const gchar * -PyFileMonitor_event_type_to_string (GFileMonitorEvent event) -{ - switch (event) - { - case G_FILE_MONITOR_EVENT_CHANGED: - return "changed"; - case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: - return "changes-done-hint"; - case G_FILE_MONITOR_EVENT_DELETED: - return "deleted"; - case G_FILE_MONITOR_EVENT_CREATED: - return "created"; - case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED: - return "attribute-changed"; - case G_FILE_MONITOR_EVENT_PRE_UNMOUNT: - return "pre-unmount"; - case G_FILE_MONITOR_EVENT_UNMOUNTED: - return "unmounted"; - case G_FILE_MONITOR_EVENT_MOVED: - return "moved"; - case G_FILE_MONITOR_EVENT_RENAMED: - return "renamed"; - case G_FILE_MONITOR_EVENT_MOVED_IN: - return "moved-in"; - case G_FILE_MONITOR_EVENT_MOVED_OUT: - return "moved-out"; - default: - g_assert_not_reached (); - } -} - static void PyFrida_object_decref (gpointer obj) @@ -2795,39 +2316,6 @@ PyFrida_raise (GError * error) return NULL; } -static const gchar * -PyFrida_device_type_to_string (FridaDeviceType type) -{ - switch (type) - { - case FRIDA_DEVICE_TYPE_LOCAL: - return "local"; - case FRIDA_DEVICE_TYPE_TETHER: - return "tether"; - case FRIDA_DEVICE_TYPE_REMOTE: - return "remote"; - default: - g_assert_not_reached (); - } - - return NULL; -} - -static gboolean -PyFrida_parse_signal_method_args (PyObject * args, const char ** signal, PyObject ** callback) -{ - if (!PyArg_ParseTuple (args, "sO", signal, callback)) - return FALSE; - - if (!PyCallable_Check (*callback)) - { - PyErr_SetString (PyExc_TypeError, "second argument must be callable"); - return FALSE; - } - - return TRUE; -} - static guint PyFrida_get_max_argument_count (PyObject * callable) { @@ -2835,6 +2323,7 @@ PyFrida_get_max_argument_count (PyObject * callable) PyObject * spec; PyObject * varargs = NULL; PyObject * args = NULL; + PyObject * is_method; spec = PyObject_CallFunction (inspect_getargspec, "O", callable); if (spec == NULL) @@ -2851,6 +2340,12 @@ PyFrida_get_max_argument_count (PyObject * callable) result = PyObject_Size (args); + is_method = PyObject_CallFunction (inspect_ismethod, "O", callable); + g_assert (is_method != NULL); + if (is_method == Py_True) + result--; + Py_DECREF (is_method); + beach: Py_XDECREF (args); Py_XDECREF (varargs); @@ -2859,101 +2354,36 @@ beach: return result; } -static gint -PyFrida_compare_pyobjects (gconstpointer a, gconstpointer b) -{ - int result; - - result = PyObject_RichCompareBool ((PyObject *) a, (PyObject *) b, Py_EQ); - - return (result == 1) ? 0 : -1; -} - MOD_INIT (_frida) { - PyObject * inspect, * json; - PyObject * module; + PyObject * inspect, * module; PyEval_InitThreads (); inspect = PyImport_ImportModule ("inspect"); inspect_getargspec = PyObject_GetAttrString (inspect, "getargspec"); + inspect_ismethod = PyObject_GetAttrString (inspect, "ismethod"); Py_DECREF (inspect); - json = PyImport_ImportModule ("json"); - json_loads = PyObject_GetAttrString (json, "loads"); - json_dumps = PyObject_GetAttrString (json, "dumps"); - Py_DECREF (json); - frida_init (); - PyDeviceManagerType.tp_new = PyType_GenericNew; - if (PyType_Ready (&PyDeviceManagerType) < 0) - return MOD_ERROR_VAL; - - PyDeviceType.tp_new = PyType_GenericNew; - if (PyType_Ready (&PyDeviceType) < 0) - return MOD_ERROR_VAL; - - PyApplicationType.tp_new = PyType_GenericNew; - if (PyType_Ready (&PyApplicationType) < 0) - return MOD_ERROR_VAL; - - PyProcessType.tp_new = PyType_GenericNew; - if (PyType_Ready (&PyProcessType) < 0) - return MOD_ERROR_VAL; - - PySpawnType.tp_new = PyType_GenericNew; - if (PyType_Ready (&PySpawnType) < 0) - return MOD_ERROR_VAL; - - PyIconType.tp_new = PyType_GenericNew; - if (PyType_Ready (&PyIconType) < 0) - return MOD_ERROR_VAL; - - PySessionType.tp_new = PyType_GenericNew; - if (PyType_Ready (&PySessionType) < 0) - return MOD_ERROR_VAL; - - PyScriptType.tp_new = PyType_GenericNew; - if (PyType_Ready (&PyScriptType) < 0) - return MOD_ERROR_VAL; - - PyFileMonitorType.tp_new = PyType_GenericNew; - if (PyType_Ready (&PyFileMonitorType) < 0) - return MOD_ERROR_VAL; + PyGObject_class_init (); MOD_DEF (module, "_frida", "Frida", NULL); PyModule_AddStringConstant (module, "__version__", frida_version_string ()); - Py_INCREF (&PyDeviceManagerType); - PyModule_AddObject (module, "DeviceManager", (PyObject *) &PyDeviceManagerType); - - Py_INCREF (&PyDeviceType); - PyModule_AddObject (module, "Device", (PyObject *) &PyDeviceType); - - Py_INCREF (&PyApplicationType); - PyModule_AddObject (module, "Application", (PyObject *) &PyApplicationType); - - Py_INCREF (&PyProcessType); - PyModule_AddObject (module, "Process", (PyObject *) &PyProcessType); - - Py_INCREF (&PySpawnType); - PyModule_AddObject (module, "Spawn", (PyObject *) &PySpawnType); - - Py_INCREF (&PyIconType); - PyModule_AddObject (module, "Icon", (PyObject *) &PyIconType); - - Py_INCREF (&PySessionType); - PyModule_AddObject (module, "Session", (PyObject *) &PySessionType); - - Py_INCREF (&PyScriptType); - PyModule_AddObject (module, "Script", (PyObject *) &PyScriptType); - - Py_INCREF (&PyFileMonitorType); - PyModule_AddObject (module, "FileMonitor", (PyObject *) &PyFileMonitorType); + PYFRIDA_REGISTER_TYPE (GObject, G_TYPE_OBJECT); + PYFRIDA_REGISTER_TYPE (DeviceManager, FRIDA_TYPE_DEVICE_MANAGER); + PYFRIDA_REGISTER_TYPE (Device, FRIDA_TYPE_DEVICE); + PYFRIDA_REGISTER_TYPE (Application, FRIDA_TYPE_APPLICATION); + PYFRIDA_REGISTER_TYPE (Process, FRIDA_TYPE_PROCESS); + PYFRIDA_REGISTER_TYPE (Spawn, FRIDA_TYPE_SPAWN); + PYFRIDA_REGISTER_TYPE (Icon, FRIDA_TYPE_ICON); + PYFRIDA_REGISTER_TYPE (Session, FRIDA_TYPE_SESSION); + PYFRIDA_REGISTER_TYPE (Script, FRIDA_TYPE_SCRIPT); + PYFRIDA_REGISTER_TYPE (FileMonitor, FRIDA_TYPE_FILE_MONITOR); exception_by_error_code = g_hash_table_new_full (NULL, NULL, NULL, PyFrida_object_decref); #define PYFRIDA_DECLARE_EXCEPTION(code, name) \ diff --git a/src/frida/core.py b/src/frida/core.py index dd4df5d..17cfbc1 100644 --- a/src/frida/core.py +++ b/src/frida/core.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals, print_function import _frida import bisect import fnmatch +import json import numbers import sys import threading @@ -300,8 +301,9 @@ class Script(object): def unload(self): self._impl.unload() - def post(self, *args, **kwargs): - self._impl.post(*args, **kwargs) + def post(self, message, **kwargs): + raw_message = json.dumps(message) + self._impl.post(raw_message, **kwargs) def on(self, signal, callback): if signal == 'message': @@ -328,7 +330,7 @@ class Script(object): result[0] = True result[1] = value result[2] = error - self._cond.notifyAll() + self._cond.notify_all() with self._cond: request_id = self._next_request_id @@ -336,7 +338,12 @@ class Script(object): self._pending[request_id] = on_complete message = ['frida:rpc', request_id] message.extend(args) - self.post(message) + try: + self.post(message) + except Exception as e: + del self._pending[request_id] + raise + while not result[0]: self._cond.wait() @@ -358,7 +365,9 @@ class Script(object): callback(value, error) - def _on_message(self, message, data): + def _on_message(self, raw_message, data): + message = json.loads(raw_message) + mtype = message['type'] payload = message.get('payload', None) if mtype == 'log':