Compare commits

...

58 Commits

Author SHA1 Message Date
Ole André Vadla Ravnås 86d4b4b4bf subprojects: Prepare for release 2026-03-27 11:36:40 +01:00
Ole André Vadla Ravnås b5808d7b27 subprojects: Bump outdated 2026-03-27 11:35:06 +01:00
Ole André Vadla Ravnås 5466050755 subprojects: Prepare for release 2026-03-26 20:43:48 +01:00
Ole André Vadla Ravnås 4db854a02c subprojects: Bump outdated 2026-03-26 20:42:58 +01:00
Ole André Vadla Ravnås cc9a78ef19 device: Add override_option()
Expose Device.override_option() for overriding backend-specific
options on a device.

Overrides apply when establishing a host session. If one already
exists, changes take effect on the next connection.
2026-03-26 20:30:10 +01:00
Ole André Vadla Ravnås 22ed1fac3c examples: Add a spawn gating example 2026-03-26 15:27:31 +01:00
Ole André Vadla Ravnås 9b15bde24e examples: Fix the child gating example 2026-03-25 21:04:14 +01:00
Ole André Vadla Ravnås a613d87b08 subprojects: Prepare for release 2026-03-24 15:40:55 +01:00
Ole André Vadla Ravnås 9ef240eff4 subprojects: Bump outdated 2026-03-24 15:39:30 +01:00
Ole André Vadla Ravnås 43a443f582 subprojects: Prepare for release 2026-03-14 11:52:06 +01:00
Ole André Vadla Ravnås dcc95216fd subprojects: Bump outdated 2026-03-14 11:51:33 +01:00
Ole André Vadla Ravnås 69e7c6c0ce subprojects: Prepare for release 2026-03-13 13:22:09 +01:00
Ole André Vadla Ravnås 3278173be8 subprojects: Bump outdated 2026-03-13 13:21:27 +01:00
Ole André Vadla Ravnås d8fa422062 subprojects: Bump outdated 2026-03-13 13:12:14 +01:00
Ole André Vadla Ravnås 3943d2eed2 subprojects: Bump outdated 2026-03-13 00:01:32 +01:00
Ole André Vadla Ravnås 8030b5aa68 submodules: Bump releng 2026-03-13 00:01:32 +01:00
Ole André Vadla Ravnås fa5f378176 subprojects: Prepare for release 2026-03-08 20:35:48 +01:00
Ole André Vadla Ravnås a814a4aa9b Revert "meson: Switch Python resolution strategy (#270)"
Turns out this breaks our CI. We should probably make this an option
instead.

This reverts commit 60a4a032d6.
2026-03-08 20:07:43 +01:00
Ole André Vadla Ravnås a48ff22b6f subprojects: Bump outdated 2026-03-08 19:44:15 +01:00
Ole André Vadla Ravnås eb4f8d37f3 subprojects: Bump outdated 2026-03-07 23:51:50 +01:00
James 60a4a032d6 meson: Switch Python resolution strategy (#270)
Use the `system` strategy, as .pc metadata is often wrong.
2026-03-07 14:49:23 +01:00
Ole André Vadla Ravnås 9f46dfaa80 subprojects: Bump outdated 2026-02-18 22:54:10 +01:00
Ole André Vadla Ravnås e57ca181f8 submodules: Bump releng 2026-02-18 22:54:10 +01:00
Ole André Vadla Ravnås 0fccd75bc7 subprojects: Prepare for release 2026-02-16 22:45:45 +01:00
Ole André Vadla Ravnås dea4ffb1c9 subprojects: Bump outdated 2026-02-16 22:08:19 +01:00
Ole André Vadla Ravnås da17d3badb subprojects: Prepare for release 2026-02-14 10:52:14 +01:00
Ole André Vadla Ravnås 33922241fc subprojects: Bump outdated 2026-02-14 10:50:37 +01:00
Ole André Vadla Ravnås fb8fdbb231 variant: Support cast to uint64 2026-02-14 10:49:06 +01:00
Ole André Vadla Ravnås 0f50b58a04 subprojects: Prepare for release 2026-02-13 22:48:36 +01:00
Ole André Vadla Ravnås f63ea5903f subprojects: Bump outdated 2026-02-13 22:47:43 +01:00
Ole André Vadla Ravnås a99767e501 subprojects: Prepare for release 2026-02-13 15:12:36 +01:00
Ole André Vadla Ravnås 07bbd3d488 subprojects: Bump outdated 2026-02-13 15:09:57 +01:00
Ole André Vadla Ravnås 81403cf383 subprojects: Bump outdated 2026-02-12 20:46:27 +01:00
Ole André Vadla Ravnås 2ea0b944a2 subprojects: Bump outdated 2026-02-12 13:27:14 +01:00
Ole André Vadla Ravnås 35c412c6cf subprojects: Bump outdated 2026-02-07 21:19:57 +01:00
Ole André Vadla Ravnås ec4524d155 submodules: Bump releng 2026-02-07 21:19:57 +01:00
Ole André Vadla Ravnås d9d53a89cc service: Fix Service.request() GVariant lifetime
The variant unmarshal helpers returned floating GVariants. When these
values were stored in containers, the floating reference was consumed.

Service.request() later unref'd the same GVariant, leading to refcount
underflow and memory corruption, or appearing to work by accident when
the memory was not yet reused.

Ensure all unmarshalled GVariants are non-floating before returning them
so that Service.request() always owns a full reference.
2026-01-29 14:59:10 +01:00
Ole André Vadla Ravnås dfb002de49 variant: Fix signedness in uint64 marshaling 2026-01-29 12:46:38 +01:00
Ole André Vadla Ravnås 0f56e44abd variant: Add support for additional GVariant types
This adds support for:
- Additional integer types: byte, int16, uint16, int32, uint32
- Tuples
- Nested variants in any context
2026-01-29 12:45:54 +01:00
Ole André Vadla Ravnås d28a2a4988 subprojects: Prepare for release 2026-01-23 22:31:27 +01:00
Ole André Vadla Ravnås 1fc39289ef subprojects: Bump outdated 2026-01-23 22:30:37 +01:00
Ole André Vadla Ravnås 2c757a08f3 subprojects: Prepare for release 2026-01-20 23:12:51 +01:00
Ole André Vadla Ravnås fc735c048f subprojects: Bump outdated 2026-01-20 23:09:30 +01:00
Ole André Vadla Ravnås 4d84536160 subprojects: Bump outdated 2026-01-20 20:26:47 +01:00
Ole André Vadla Ravnås 9e51c78c5c submodules: Bump releng 2026-01-20 20:26:47 +01:00
Ole André Vadla Ravnås a6d51e8384 subprojects: Bump outdated 2026-01-20 18:54:35 +01:00
Ole André Vadla Ravnås 3e80ed726d submodules: Bump releng 2026-01-20 18:54:35 +01:00
Ole André Vadla Ravnås 985410b6ff subprojects: Prepare for release 2026-01-17 08:43:35 +01:00
Ole André Vadla Ravnås 21c7b9ee6a subprojects: Bump outdated 2026-01-17 00:24:37 +01:00
Ole André Vadla Ravnås 7fba1cdc67 subprojects: Bump outdated 2026-01-16 15:32:05 +01:00
Ole André Vadla Ravnås a709856e2a subprojects: Bump outdated 2026-01-16 13:44:50 +01:00
Ole André Vadla Ravnås c3afe6089d submodules: Bump releng 2026-01-16 13:44:49 +01:00
Ole André Vadla Ravnås 6435a78d13 subprojects: Bump outdated 2026-01-15 18:08:16 +01:00
Ole André Vadla Ravnås 09175036ea submodules: Bump releng 2026-01-15 18:08:16 +01:00
Ole André Vadla Ravnås e0c90c5203 subprojects: Bump outdated 2026-01-11 00:48:16 +01:00
Abhi 9f463fb602 Fix regressions reported by mypi and black (#269) 2026-01-07 09:14:51 +01:00
Ole André Vadla Ravnås 9fdee2270f subprojects: Bump outdated 2026-01-06 22:40:32 +01:00
Ole André Vadla Ravnås 6e536a56b1 submodules: Bump releng 2026-01-06 22:40:32 +01:00
6 changed files with 208 additions and 24 deletions
+3 -3
View File
@@ -44,11 +44,11 @@ class Application:
print("✔ create_script()")
script = session.create_script(
"""\
Interceptor.attach(Module.getExportByName(null, 'open'), {
onEnter: function (args) {
Interceptor.attach(Module.getGlobalExportByName('open'), {
onEnter(args) {
send({
type: 'open',
path: Memory.readUtf8String(args[0])
path: args[0].readUtf8String()
});
}
});
+80
View File
@@ -0,0 +1,80 @@
import threading
from frida_tools.application import Reactor
import frida
class Application:
def __init__(self):
self._stop_requested = threading.Event()
self._reactor = Reactor(run_until_return=lambda reactor: self._stop_requested.wait())
self._device = frida.get_usb_device()
self._sessions = set()
self._sessions_lock = threading.Lock()
self._device.on("spawn-added", lambda spawn: self._reactor.schedule(lambda: self._on_spawn_added(spawn)))
self._device.on("spawn-removed", lambda spawn: self._reactor.schedule(lambda: self._on_spawn_removed(spawn)))
def run(self):
self._reactor.schedule(lambda: self._start())
self._reactor.run()
def _start(self):
self._device.enable_spawn_gating()
def _instrument(self, pid):
print(f"✔ attach(pid={pid})")
session = self._device.attach(pid)
session.on("detached", lambda reason: self._reactor.schedule(lambda: self._on_detached(pid, session, reason)))
print("✔ create_script()")
script = session.create_script(
"""\
const puts = new NativeFunction(Module.getGlobalExportByName('puts'), 'int', ['pointer']);
puts(Memory.allocUtf8String('Hello from Frida agent'));
Interceptor.attach(Module.getGlobalExportByName('open'), {
onEnter(args) {
send({
type: 'open',
path: args[0].readUtf8String()
});
}
});
"""
)
script.on("message", lambda message, data: self._reactor.schedule(lambda: self._on_message(pid, message)))
print("✔ load()")
script.load()
print(f"✔ resume(pid={pid})")
self._device.resume(pid)
with self._sessions_lock:
self._sessions.add(session)
def _on_spawn_added(self, spawn):
print(f"⚡ spawn_added: {spawn}")
t = threading.Thread(target=self._handle_spawn, args=(spawn,))
t.start()
def _handle_spawn(self, spawn):
if "/bin/ls" in spawn.identifier:
self._instrument(spawn.pid)
else:
pid = spawn.pid
print(f"✔ resume(pid={pid})")
self._device.resume(pid)
def _on_spawn_removed(self, spawn):
print(f"⚡ spawn_removed: {spawn}")
def _on_detached(self, pid, session, reason):
print(f"⚡ detached: pid={pid}, reason='{reason}'")
with self._sessions_lock:
self._sessions.remove(session)
def _on_message(self, pid, message):
print(f"⚡ message: pid={pid}, payload={message['payload']}")
app = Application()
app.run()
+112 -17
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2013-2023 Ole André Vadla Ravnås <oleavr@nowsecure.com>
* Copyright (C) 2013-2026 Ole André Vadla Ravnås <oleavr@nowsecure.com>
* Copyright (C) 2024 Håvard Sørbø <havard@hsorbo.no>
*
* Licence: wxWindows Library Licence, Version 3.1
@@ -378,6 +378,7 @@ static PyObject * PyGObject_marshal_variant (GVariant * variant);
static PyObject * PyGObject_marshal_variant_byte_array (GVariant * variant);
static PyObject * PyGObject_marshal_variant_dict (GVariant * variant);
static PyObject * PyGObject_marshal_variant_array (GVariant * variant);
static PyObject * PyGObject_marshal_variant_tuple (GVariant * variant);
static gboolean PyGObject_unmarshal_variant (PyObject * value, GVariant ** variant);
static gboolean PyGObject_unmarshal_variant_from_mapping (PyObject * mapping, GVariant ** variant);
static gboolean PyGObject_unmarshal_variant_from_sequence (PyObject * sequence, GVariant ** variant);
@@ -403,6 +404,7 @@ 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_is_lost (PyDevice * self);
static PyObject * PyDevice_override_option (PyDevice * self, PyObject * args, PyObject * kw);
static PyObject * PyDevice_query_system_parameters (PyDevice * self);
static PyObject * PyDevice_get_frontmost_application (PyDevice * self, PyObject * args, PyObject * kw);
static PyObject * PyDevice_enumerate_applications (PyDevice * self, PyObject * args, PyObject * kw);
@@ -619,6 +621,7 @@ static PyMethodDef PyDeviceManager_methods[] =
static PyMethodDef PyDevice_methods[] =
{
{ "is_lost", (PyCFunction) PyDevice_is_lost, METH_NOARGS, "Query whether the device has been lost." },
{ "override_option", (PyCFunction) PyDevice_override_option, METH_VARARGS | METH_KEYWORDS, "Override a backend-specific option." },
{ "query_system_parameters", (PyCFunction) PyDevice_query_system_parameters, METH_NOARGS, "Returns a dictionary of information about the host system." },
{ "get_frontmost_application", (PyCFunction) PyDevice_get_frontmost_application, METH_VARARGS | METH_KEYWORDS, "Get details about the frontmost application." },
{ "enumerate_applications", (PyCFunction) PyDevice_enumerate_applications, METH_VARARGS | METH_KEYWORDS, "Enumerate applications." },
@@ -1749,10 +1752,20 @@ PyGObject_marshal_variant (GVariant * variant)
{
case G_VARIANT_CLASS_STRING:
return PyGObject_marshal_string (g_variant_get_string (variant, NULL));
case G_VARIANT_CLASS_BYTE:
return PyLong_FromLong (g_variant_get_byte (variant));
case G_VARIANT_CLASS_INT16:
return PyLong_FromLong (g_variant_get_int16 (variant));
case G_VARIANT_CLASS_UINT16:
return PyLong_FromUnsignedLong (g_variant_get_uint16 (variant));
case G_VARIANT_CLASS_INT32:
return PyLong_FromLong (g_variant_get_int32 (variant));
case G_VARIANT_CLASS_UINT32:
return PyLong_FromUnsignedLong (g_variant_get_uint32 (variant));
case G_VARIANT_CLASS_INT64:
return PyLong_FromLongLong (g_variant_get_int64 (variant));
case G_VARIANT_CLASS_UINT64:
return PyLong_FromLongLong (g_variant_get_uint64 (variant));
return PyLong_FromUnsignedLongLong (g_variant_get_uint64 (variant));
case G_VARIANT_CLASS_DOUBLE:
return PyFloat_FromDouble (g_variant_get_double (variant));
case G_VARIANT_CLASS_BOOLEAN:
@@ -1765,6 +1778,19 @@ PyGObject_marshal_variant (GVariant * variant)
return PyGObject_marshal_variant_dict (variant);
return PyGObject_marshal_variant_array (variant);
case G_VARIANT_CLASS_TUPLE:
return PyGObject_marshal_variant_tuple (variant);
case G_VARIANT_CLASS_VARIANT:
{
GVariant * inner;
PyObject * result;
inner = g_variant_get_variant (variant);
result = PyGObject_marshal_variant (inner);
g_variant_unref (inner);
return result;
}
default:
break;
}
@@ -1823,13 +1849,6 @@ PyGObject_marshal_variant_array (GVariant * variant)
for (i = 0; (child = g_variant_iter_next_value (&iter)) != NULL; i++)
{
if (g_variant_is_of_type (child, G_VARIANT_TYPE_VARIANT))
{
GVariant * inner = g_variant_get_variant (child);
g_variant_unref (child);
child = inner;
}
PyList_SetItem (list, i, PyGObject_marshal_variant (child));
g_variant_unref (child);
@@ -1838,6 +1857,28 @@ PyGObject_marshal_variant_array (GVariant * variant)
return list;
}
static PyObject *
PyGObject_marshal_variant_tuple (GVariant * variant)
{
GVariantIter iter;
PyObject * tuple;
guint i;
GVariant * child;
g_variant_iter_init (&iter, variant);
tuple = PyTuple_New (g_variant_iter_n_children (&iter));
for (i = 0; (child = g_variant_iter_next_value (&iter)) != NULL; i++)
{
PyTuple_SetItem (tuple, i, PyGObject_marshal_variant (child));
g_variant_unref (child);
}
return tuple;
}
static gboolean
PyGObject_unmarshal_variant (PyObject * value, GVariant ** variant)
{
@@ -1847,14 +1888,14 @@ PyGObject_unmarshal_variant (PyObject * value, GVariant ** variant)
PyGObject_unmarshal_string (value, &str);
*variant = g_variant_new_take_string (str);
*variant = g_variant_ref_sink (g_variant_new_take_string (str));
return TRUE;
}
if (PyBool_Check (value))
{
*variant = g_variant_new_boolean (value == Py_True);
*variant = g_variant_ref_sink (g_variant_new_boolean (value == Py_True));
return TRUE;
}
@@ -1867,14 +1908,14 @@ PyGObject_unmarshal_variant (PyObject * value, GVariant ** variant)
if (l == -1 && PyErr_Occurred ())
return FALSE;
*variant = g_variant_new_int64 (l);
*variant = g_variant_ref_sink (g_variant_new_int64 (l));
return TRUE;
}
if (PyFloat_Check (value))
{
*variant = g_variant_new_double (PyFloat_AsDouble (value));
*variant = g_variant_ref_sink (g_variant_new_double (PyFloat_AsDouble (value)));
return TRUE;
}
@@ -1888,7 +1929,7 @@ PyGObject_unmarshal_variant (PyObject * value, GVariant ** variant)
PyBytes_AsStringAndSize (value, &buffer, &length);
copy = g_memdup2 (buffer, length);
*variant = g_variant_new_from_data (G_VARIANT_TYPE_BYTESTRING, copy, length, TRUE, g_free, copy);
*variant = g_variant_ref_sink (g_variant_new_from_data (G_VARIANT_TYPE_BYTESTRING, copy, length, TRUE, g_free, copy));
return TRUE;
}
@@ -1934,12 +1975,13 @@ PyGObject_unmarshal_variant_from_mapping (PyObject * mapping, GVariant ** varian
g_variant_builder_add (&builder, "{sv}", PyBytes_AsString (key_bytes), raw_value);
g_variant_unref (raw_value);
Py_DecRef (key_bytes);
}
Py_DecRef (items);
*variant = g_variant_builder_end (&builder);
*variant = g_variant_ref_sink (g_variant_builder_end (&builder));
return TRUE;
@@ -1962,6 +2004,31 @@ PyGObject_unmarshal_variant_from_sequence (PyObject * sequence, GVariant ** vari
is_tuple = PyTuple_Check (sequence);
if (is_tuple && PyTuple_Size (sequence) == 2)
{
gchar * type;
gboolean is_uint64_cast;
if (!PyGObject_unmarshal_string (PyTuple_GetItem (sequence, 0), &type))
return FALSE;
is_uint64_cast = strcmp (type, "uint64") == 0;
g_free (type);
if (is_uint64_cast)
{
unsigned PY_LONG_LONG l;
l = PyLong_AsUnsignedLongLong (PyTuple_GetItem (sequence, 1));
if (l == (unsigned PY_LONG_LONG) -1 && PyErr_Occurred ())
return FALSE;
*variant = g_variant_ref_sink (g_variant_new_uint64 (l));
return TRUE;
}
}
g_variant_builder_init (&builder, is_tuple ? G_VARIANT_TYPE_TUPLE : G_VARIANT_TYPE ("av"));
n = PySequence_Length (sequence);
@@ -1984,10 +2051,11 @@ PyGObject_unmarshal_variant_from_sequence (PyObject * sequence, GVariant ** vari
else
g_variant_builder_add (&builder, "v", raw_value);
g_variant_unref (raw_value);
Py_DecRef (val);
}
*variant = g_variant_builder_end (&builder);
*variant = g_variant_ref_sink (g_variant_builder_end (&builder));
return TRUE;
@@ -2455,6 +2523,33 @@ PyDevice_is_lost (PyDevice * self)
return PyBool_FromLong (is_lost);
}
static PyObject *
PyDevice_override_option (PyDevice * self, PyObject * args, PyObject * kw)
{
static char * keywords[] = { "name", "value", NULL };
const char * name;
PyObject * value;
GVariant * raw_value;
GError * error = NULL;
if (!PyArg_ParseTupleAndKeywords (args, kw, "sO", keywords, &name, &value))
return NULL;
if (!PyGObject_unmarshal_variant (value, &raw_value))
return NULL;
Py_BEGIN_ALLOW_THREADS
frida_device_override_option (PY_GOBJECT_HANDLE (self), name, raw_value, &error);
Py_END_ALLOW_THREADS
g_variant_unref (raw_value);
if (error != NULL)
return PyFrida_raise (error);
PyFrida_RETURN_NONE;
}
static PyObject *
PyDevice_query_system_parameters (PyDevice * self)
{
@@ -2887,7 +2982,7 @@ PyDevice_spawn (PyDevice * self, PyObject * args, PyObject * kw)
goto invalid_dict_value;
}
g_hash_table_insert (aux, raw_key, g_variant_ref_sink (raw_value));
g_hash_table_insert (aux, raw_key, raw_value);
}
}
+11 -2
View File
@@ -883,6 +883,14 @@ class Device:
return self._impl.is_lost()
@cancellable
def override_option(self, name: str, value: Any) -> None:
"""
Override a backend-specific option
"""
self._impl.override_option(name, value)
@cancellable
def query_system_parameters(self) -> Dict[str, Any]:
"""
@@ -1524,6 +1532,7 @@ CompilerSourceMaps = Literal["included", "omitted"]
CompilerCompression = Literal["none", "terser"]
CompilerPlatform = Literal["neutral", "gum", "browser"]
class Compiler:
def __init__(self) -> None:
self._impl = _frida.Compiler()
@@ -1544,7 +1553,7 @@ class Compiler:
platform: Optional[CompilerPlatform] = None,
externals: Optional[Sequence[str]] = None,
) -> str:
kwargs = {
kwargs: dict[str, Any] = {
"project_root": project_root,
"output_format": output_format,
"bundle_format": bundle_format,
@@ -1570,7 +1579,7 @@ class Compiler:
platform: Optional[CompilerPlatform] = None,
externals: Optional[Sequence[str]] = None,
) -> None:
kwargs = {
kwargs: dict[str, Any] = {
"project_root": project_root,
"output_format": output_format,
"bundle_format": bundle_format,
+1 -1
Submodule releng updated: c144673b9d...5595d31705
+1 -1
View File
@@ -1,6 +1,6 @@
[wrap-git]
url = https://github.com/frida/frida-core.git
revision = 17.5.2
revision = 17.9.1
depth = 1
[provide]