Compare commits

...

114 Commits

Author SHA1 Message Date
Ole André Vadla Ravnås f57b0c1cfa subprojects: Prepare for release 2026-04-28 12:23:14 +02:00
Ole André Vadla Ravnås fd2c1f2424 subprojects: Bump outdated 2026-04-28 12:22:18 +02:00
Ole André Vadla Ravnås a9caf62a0c Reformat with black 26.3.1 2026-04-26 17:47:34 +02:00
Ole André Vadla Ravnås 8bc4415f34 subprojects: Bump outdated 2026-04-26 17:36:09 +02:00
Ole André Vadla Ravnås e3eca3179c subprojects: Bump outdated 2026-04-26 17:21:24 +02:00
Ole André Vadla Ravnås ef190d9957 submodules: Bump releng 2026-04-26 17:21:24 +02:00
Ole André Vadla Ravnås 1e06ebe9a3 subprojects: Bump outdated 2026-04-26 14:06:52 +02:00
Ole André Vadla Ravnås 925378439c subprojects: Bump outdated 2026-04-26 13:34:40 +02:00
Ole André Vadla Ravnås 7ae323a3cd subprojects: Bump outdated 2026-04-26 13:17:42 +02:00
Ole André Vadla Ravnås 9c5985c254 submodules: Bump releng 2026-04-26 13:17:42 +02:00
Ole André Vadla Ravnås b469134be4 subprojects: Bump outdated 2026-04-26 11:29:31 +02:00
Ole André Vadla Ravnås 9933d916ae subprojects: Bump outdated 2026-04-26 11:12:20 +02:00
Ole André Vadla Ravnås 09cac4e2a5 subprojects: Bump outdated 2026-04-26 10:28:31 +02:00
Ole André Vadla Ravnås 6b49e14ce1 subprojects: Bump outdated 2026-04-26 10:22:40 +02:00
Ole André Vadla Ravnås 7711fa12ac subprojects: Bump outdated 2026-04-26 10:16:43 +02:00
Ole André Vadla Ravnås d468dc038c submodules: Bump releng 2026-04-26 10:16:43 +02:00
Ole André Vadla Ravnås 58ff000596 subprojects: Bump outdated 2026-04-20 17:20:15 +02:00
Ole André Vadla Ravnås 3652e985d8 subprojects: Bump outdated 2026-04-20 17:16:46 +02:00
Ole André Vadla Ravnås 210c56e1b2 subprojects: Bump outdated 2026-04-20 16:31:57 +02:00
Ole André Vadla Ravnås b3d6aa8ffe submodules: Bump releng 2026-04-20 16:31:57 +02:00
Ole André Vadla Ravnås 16eb645844 subprojects: Bump outdated 2026-04-20 14:52:30 +02:00
Ole André Vadla Ravnås b7b1fcf0ff submodules: Bump releng 2026-04-20 14:52:30 +02:00
Ole André Vadla Ravnås 978b756134 subprojects: Bump outdated 2026-04-20 14:41:14 +02:00
Ole André Vadla Ravnås 7b1fc43a42 submodules: Bump releng 2026-04-20 14:41:14 +02:00
Ole André Vadla Ravnås 244cf6926b subprojects: Bump outdated 2026-04-13 14:36:51 +02:00
Ole André Vadla Ravnås 24b941fb8a submodules: Bump releng 2026-04-13 14:36:51 +02:00
Ole André Vadla Ravnås e2b340eda1 subprojects: Bump outdated 2026-04-10 23:55:22 +02:00
Ole André Vadla Ravnås 2b306c6d30 submodules: Bump releng 2026-04-10 23:55:22 +02:00
Ole André Vadla Ravnås 57cee13b43 subprojects: Bump outdated 2026-04-10 13:21:14 +02:00
Ole André Vadla Ravnås 23aa442826 subprojects: Bump outdated 2026-04-09 13:41:43 +02:00
Ole André Vadla Ravnås 65236f3b05 submodules: Bump releng 2026-04-09 13:41:43 +02:00
Ole André Vadla Ravnås e52e7a95bd subprojects: Bump outdated 2026-04-09 12:14:45 +02:00
Ole André Vadla Ravnås 3b57222cfa submodules: Bump releng 2026-04-09 12:14:45 +02:00
Ole André Vadla Ravnås 319ac9e699 subprojects: Bump outdated 2026-04-09 11:50:42 +02:00
Ole André Vadla Ravnås 2e842a4e44 submodules: Bump releng 2026-04-09 11:50:42 +02:00
Ole André Vadla Ravnås f9bf571497 subprojects: Bump outdated 2026-04-08 16:22:39 +02:00
Ole André Vadla Ravnås 8f50f743e1 submodules: Bump releng 2026-04-08 16:22:39 +02:00
Ole André Vadla Ravnås 6da337df6f subprojects: Bump outdated 2026-04-08 01:15:57 +02:00
Ole André Vadla Ravnås e29d41806c submodules: Bump releng 2026-04-08 01:15:57 +02:00
Ole André Vadla Ravnås 8faf01dc2e subprojects: Bump outdated 2026-04-06 15:37:09 +02:00
Ole André Vadla Ravnås 4286667bc6 submodules: Bump releng 2026-04-06 15:37:09 +02:00
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
Ole André Vadla Ravnås 74925d082e subprojects: Prepare for release 2025-12-15 21:28:40 +01:00
Etienne Maheux bf1245ddb0 typing: Remove generic @overload on handlers
Generic @overload definitions on signal handlers were masking
type-checking errors.
2025-12-15 21:23:57 +01:00
Etienne Maheux 0f247e9439 typing: Improve @cancellable; add flag literals
Refine @cancellable typing to better model control flow and
introduce Literal types for optional Compiler flags to
improve static checking and autocomplete.
2025-12-15 21:23:57 +01:00
Ole André Vadla Ravnås 17aae5fe5c subprojects: Bump outdated 2025-12-15 21:17:51 +01:00
Ole André Vadla Ravnås 477a90534e submodules: Bump releng 2025-12-15 21:17:51 +01:00
Ole André Vadla Ravnås c87cdca293 subprojects: Prepare for release 2025-11-05 18:59:11 +01:00
Ole André Vadla Ravnås 30968b3805 subprojects: Bump outdated 2025-11-05 18:57:30 +01:00
Ole André Vadla Ravnås 5e3f27d0cb subprojects: Prepare for release 2025-11-04 10:30:58 +01:00
Ole André Vadla Ravnås 904461eb01 subprojects: Bump outdated 2025-11-04 10:29:40 +01:00
Ole André Vadla Ravnås dc652faa90 package-manager: Plug leak in specs option parsing 2025-11-04 10:23:37 +01:00
Ole André Vadla Ravnås f5ba22ad36 compiler: Expose platform and externals options 2025-11-04 10:23:00 +01:00
Ole André Vadla Ravnås dccb6810ca subprojects: Prepare for release 2025-11-01 00:38:17 +01:00
Ole André Vadla Ravnås 82441c6d61 subprojects: Bump outdated 2025-11-01 00:36:38 +01:00
Ole André Vadla Ravnås 323dca48c2 subprojects: Prepare for release 2025-10-31 20:24:11 +01:00
Ole André Vadla Ravnås ef71f0fa92 subprojects: Bump outdated 2025-10-31 20:21:50 +01:00
11 changed files with 333 additions and 135 deletions
+5 -7
View File
@@ -42,18 +42,16 @@ class Application:
print("✔ enable_child_gating()")
session.enable_child_gating()
print("✔ create_script()")
script = session.create_script(
"""\
Interceptor.attach(Module.getExportByName(null, 'open'), {
onEnter: function (args) {
script = session.create_script("""\
Interceptor.attach(Module.getGlobalExportByName('open'), {
onEnter(args) {
send({
type: 'open',
path: Memory.readUtf8String(args[0])
path: args[0].readUtf8String()
});
}
});
"""
)
""")
script.on("message", lambda message, data: self._reactor.schedule(lambda: self._on_message(pid, message)))
print("✔ load()")
script.load()
+1 -1
View File
@@ -15,7 +15,7 @@ def on_uninjected(id):
print("on_uninjected id=%u" % id)
(target, library_path) = sys.argv[1:]
target, library_path = sys.argv[1:]
device = frida.get_local_device()
device.on("uninjected", on_uninjected)
+1 -1
View File
@@ -15,7 +15,7 @@ def on_uninjected(id):
print("on_uninjected id=%u" % id)
(target, library_path) = sys.argv[1:]
target, library_path = sys.argv[1:]
device = frida.get_local_device()
device.on("uninjected", on_uninjected)
+2 -4
View File
@@ -1,8 +1,7 @@
import frida
session = frida.attach("Twitter")
script = session.create_script(
"""\
script = session.create_script("""\
rpc.exports = {
hello: function () {
return 'Hello';
@@ -11,8 +10,7 @@ rpc.exports = {
oops;
}
};
"""
)
""")
script.load()
api = script.exports_sync
print("api.hello() =>", api.hello())
+2 -4
View File
@@ -22,8 +22,7 @@ class Application:
self._session = session
session.on("detached", lambda *args: self._reactor.schedule(lambda: self._on_detached(*args)))
script = session.create_script(
"""
script = session.create_script("""
let _puts = null;
Interceptor.attach(DebugSymbol.getFunctionByName('f'), {
@@ -48,8 +47,7 @@ function puts(s) {
}
_puts(Memory.allocUtf8String(s));
}
"""
)
""")
self._script = script
script.on("message", lambda *args: self._reactor.schedule(lambda: self._on_message(*args)))
script.load()
+78
View File
@@ -0,0 +1,78 @@
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()
+10
View File
@@ -754,8 +754,13 @@ class Compiler(Object):
self,
entrypoint: str,
project_root: Optional[str] = None,
output_format: Optional[str] = None,
bundle_format: Optional[str] = None,
type_check: Optional[str] = None,
source_maps: Optional[str] = None,
compression: Optional[str] = None,
platform: Optional[str] = None,
externals: Optional[Sequence[str]] = None,
) -> str:
"""
Build an agent.
@@ -766,8 +771,13 @@ class Compiler(Object):
self,
entrypoint: str,
project_root: Optional[str] = None,
output_format: Optional[str] = None,
bundle_format: Optional[str] = None,
type_check: Optional[str] = None,
source_maps: Optional[str] = None,
compression: Optional[str] = None,
platform: Optional[str] = None,
externals: Optional[Sequence[str]] = None,
) -> None:
"""
Continuously build an agent.
+169 -29
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);
@@ -533,7 +535,8 @@ static void PyCompiler_dealloc (PyCompiler * self);
static PyObject * PyCompiler_build (PyCompiler * self, PyObject * args, PyObject * kw);
static PyObject * PyCompiler_watch (PyCompiler * self, PyObject * args, PyObject * kw);
static gboolean PyCompiler_set_options (FridaCompilerOptions * options, const gchar * project_root_value, const gchar * output_format_value,
const gchar * bundle_format_value, const gchar * type_check_value, const gchar * source_maps_value, const gchar * compression_value);
const gchar * bundle_format_value, const gchar * type_check_value, const gchar * source_maps_value, const gchar * compression_value,
const gchar * platform_value, PyObject * externals_value);
static int PyPackageManager_init (PyPackageManager * self, PyObject * args, PyObject * kw);
static void PyPackageManager_dealloc (PyPackageManager * self);
@@ -618,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." },
@@ -1748,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:
@@ -1764,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;
}
@@ -1822,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);
@@ -1837,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)
{
@@ -1846,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;
}
@@ -1866,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;
}
@@ -1887,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;
}
@@ -1933,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;
@@ -1961,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);
@@ -1983,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;
@@ -2454,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)
{
@@ -2886,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);
}
}
@@ -4904,8 +5000,8 @@ static PyObject *
PyCompiler_build (PyCompiler * self, PyObject * args, PyObject * kw)
{
PyObject * result;
static char * keywords[] =
{ "entrypoint", "project_root", "output_format", "bundle_format", "type_check", "source_maps", "compression", NULL };
static char * keywords[] = { "entrypoint", "project_root", "output_format", "bundle_format", "type_check", "source_maps", "compression",
"platform", "externals", NULL };
const char * entrypoint;
const char * project_root = NULL;
const char * output_format = NULL;
@@ -4913,17 +5009,19 @@ PyCompiler_build (PyCompiler * self, PyObject * args, PyObject * kw)
const char * type_check = NULL;
const char * source_maps = NULL;
const char * compression = NULL;
const char * platform = NULL;
PyObject * externals = NULL;
FridaBuildOptions * options;
GError * error = NULL;
gchar * bundle;
if (!PyArg_ParseTupleAndKeywords (args, kw, "s|ssssss", keywords, &entrypoint, &project_root, &output_format, &bundle_format, &type_check,
&source_maps, &compression))
if (!PyArg_ParseTupleAndKeywords (args, kw, "s|sssssssO", keywords, &entrypoint, &project_root, &output_format, &bundle_format,
&type_check, &source_maps, &compression, &platform, &externals))
return NULL;
options = frida_build_options_new ();
if (!PyCompiler_set_options (FRIDA_COMPILER_OPTIONS (options), project_root, output_format, bundle_format, type_check, source_maps,
compression))
compression, platform, externals))
goto invalid_option_value;
Py_BEGIN_ALLOW_THREADS
@@ -4950,8 +5048,8 @@ invalid_option_value:
static PyObject *
PyCompiler_watch (PyCompiler * self, PyObject * args, PyObject * kw)
{
static char * keywords[] =
{ "entrypoint", "project_root", "output_format", "bundle_format", "type_check", "source_maps", "compression", NULL };
static char * keywords[] = { "entrypoint", "project_root", "output_format", "bundle_format", "type_check", "source_maps", "compression",
"platform", "externals", NULL };
const char * entrypoint;
const char * project_root = NULL;
const char * output_format = NULL;
@@ -4959,16 +5057,18 @@ PyCompiler_watch (PyCompiler * self, PyObject * args, PyObject * kw)
const char * type_check = NULL;
const char * source_maps = NULL;
const char * compression = NULL;
const char * platform = NULL;
PyObject * externals = NULL;
FridaWatchOptions * options;
GError * error = NULL;
if (!PyArg_ParseTupleAndKeywords (args, kw, "s|ssssss", keywords, &entrypoint, &project_root, &output_format, &bundle_format, &type_check,
&source_maps, &compression))
if (!PyArg_ParseTupleAndKeywords (args, kw, "s|sssssssO", keywords, &entrypoint, &project_root, &output_format, &bundle_format,
&type_check, &source_maps, &compression, &platform, &externals))
return NULL;
options = frida_watch_options_new ();
if (!PyCompiler_set_options (FRIDA_COMPILER_OPTIONS (options), project_root, output_format, bundle_format, type_check, source_maps,
compression))
compression, platform, externals))
goto invalid_option_value;
Py_BEGIN_ALLOW_THREADS
@@ -4991,7 +5091,8 @@ invalid_option_value:
static gboolean
PyCompiler_set_options (FridaCompilerOptions * options, const gchar * project_root_value, const gchar * output_format_value,
const gchar * bundle_format_value, const gchar * type_check_value, const gchar * source_maps_value, const gchar * compression_value)
const gchar * bundle_format_value, const gchar * type_check_value, const gchar * source_maps_value, const gchar * compression_value,
const gchar * platform_value, PyObject * externals_value)
{
if (project_root_value != NULL)
frida_compiler_options_set_project_root (options, project_root_value);
@@ -5046,6 +5147,43 @@ PyCompiler_set_options (FridaCompilerOptions * options, const gchar * project_ro
frida_compiler_options_set_compression (options, compression);
}
if (platform_value != NULL)
{
FridaJsPlatform platform;
if (!PyGObject_unmarshal_enum (platform_value, FRIDA_TYPE_JS_PLATFORM, &platform))
return FALSE;
frida_compiler_options_set_platform (options, platform);
}
if (externals_value != NULL)
{
gint n, i;
n = PySequence_Size (externals_value);
if (n == -1)
return FALSE;
for (i = 0; i != n; i++)
{
PyObject * element;
gchar * external = NULL;
element = PySequence_GetItem (externals_value, i);
if (element == NULL)
return FALSE;
PyGObject_unmarshal_string (element, &external);
Py_DecRef (element);
if (external == NULL)
return FALSE;
frida_compiler_options_add_external (options, external);
g_free (external);
}
}
return TRUE;
}
@@ -5208,6 +5346,8 @@ PyPackageManager_parse_install_options (const gchar * project_root, const char *
goto propagate_error;
frida_package_install_options_add_spec (options, spec);
g_free (spec);
}
}
+63 -87
View File
@@ -33,10 +33,15 @@ if sys.version_info >= (3, 8):
else:
from typing_extensions import Literal, TypedDict
if sys.version_info >= (3, 11):
from typing import NotRequired
if sys.version_info >= (3, 10):
from typing import ParamSpec
else:
from typing_extensions import NotRequired
from typing_extensions import ParamSpec
if sys.version_info >= (3, 11):
from typing import NotRequired, cast
else:
from typing_extensions import NotRequired, cast
from . import _frida
@@ -72,15 +77,18 @@ def _filter_missing_kwargs(d: MutableMapping[Any, Any]) -> None:
d.pop(key)
R = TypeVar("R")
P = ParamSpec("P")
R = TypeVar("R", covariant=True)
def cancellable(f: Callable[..., R]) -> Callable[..., R]:
def cancellable(f: Callable[P, R]) -> Callable[P, R]:
# currently there is no way to type properly the extended callable with optional cancellable parameter
# ref: https://github.com/python/typing/discussions/1905#discussioncomment-11696995
@functools.wraps(f)
def wrapper(*args: Any, **kwargs: Any) -> R:
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
cancellable = kwargs.pop("cancellable", None)
if cancellable is not None:
with cancellable:
with cast(Cancellable, cancellable):
return f(*args, **kwargs)
return f(*args, **kwargs)
@@ -351,9 +359,6 @@ class Script:
@overload
def on(self, signal: Literal["message"], callback: ScriptMessageCallback) -> None: ...
@overload
def on(self, signal: str, callback: Callable[..., Any]) -> None: ...
def on(self, signal: str, callback: Callable[..., Any]) -> None:
"""
Add a signal handler
@@ -370,9 +375,6 @@ class Script:
@overload
def off(self, signal: Literal["message"], callback: ScriptMessageCallback) -> None: ...
@overload
def off(self, signal: str, callback: Callable[..., Any]) -> None: ...
def off(self, signal: str, callback: Callable[..., Any]) -> None:
"""
Remove a signal handler
@@ -693,34 +695,22 @@ class Session:
_filter_missing_kwargs(kwargs)
return PortalMembership(self._impl.join_portal(address, **kwargs))
@overload
def on(
self,
signal: Literal["detached"],
callback: SessionDetachedCallback,
) -> None: ...
@overload
def on(self, signal: str, callback: Callable[..., Any]) -> None: ...
def on(self, signal: str, callback: Callable[..., Any]) -> None:
) -> None:
"""
Add a signal handler
"""
self._impl.on(signal, callback)
@overload
def off(
self,
signal: Literal["detached"],
callback: SessionDetachedCallback,
) -> None: ...
@overload
def off(self, signal: str, callback: Callable[..., Any]) -> None: ...
def off(self, signal: str, callback: Callable[..., Any]) -> None:
) -> None:
"""
Remove a signal handler
"""
@@ -763,9 +753,6 @@ class Bus:
@overload
def on(self, signal: Literal["message"], callback: BusMessageCallback) -> None: ...
@overload
def on(self, signal: str, callback: Callable[..., Any]) -> None: ...
def on(self, signal: str, callback: Callable[..., Any]) -> None:
"""
Add a signal handler
@@ -782,9 +769,6 @@ class Bus:
@overload
def off(self, signal: Literal["message"], callback: BusMessageCallback) -> None: ...
@overload
def off(self, signal: str, callback: Callable[..., Any]) -> None: ...
def off(self, signal: str, callback: Callable[..., Any]) -> None:
"""
Remove a signal handler
@@ -842,9 +826,6 @@ class Service:
@overload
def on(self, signal: Literal["message"], callback: ServiceMessageCallback) -> None: ...
@overload
def on(self, signal: str, callback: Callable[..., Any]) -> None: ...
def on(self, signal: str, callback: Callable[..., Any]) -> None:
"""
Add a signal handler
@@ -858,9 +839,6 @@ class Service:
@overload
def off(self, signal: Literal["message"], callback: ServiceMessageCallback) -> None: ...
@overload
def off(self, signal: str, callback: Callable[..., Any]) -> None: ...
def off(self, signal: str, callback: Callable[..., Any]) -> None:
"""
Remove a signal handler
@@ -905,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]:
"""
@@ -1144,9 +1130,6 @@ class Device:
@overload
def on(self, signal: Literal["lost"], callback: DeviceLostCallback) -> None: ...
@overload
def on(self, signal: str, callback: Callable[..., Any]) -> None: ...
def on(self, signal: str, callback: Callable[..., Any]) -> None:
"""
Add a signal handler
@@ -1178,9 +1161,6 @@ class Device:
@overload
def off(self, signal: Literal["lost"], callback: DeviceLostCallback) -> None: ...
@overload
def off(self, signal: str, callback: Callable[..., Any]) -> None: ...
def off(self, signal: str, callback: Callable[..., Any]) -> None:
"""
Remove a signal handler
@@ -1298,9 +1278,6 @@ class DeviceManager:
@overload
def on(self, signal: Literal["changed"], callback: DeviceManagerChangedCallback) -> None: ...
@overload
def on(self, signal: str, callback: Callable[..., Any]) -> None: ...
def on(self, signal: str, callback: Callable[..., Any]) -> None:
"""
Add a signal handler
@@ -1317,9 +1294,6 @@ class DeviceManager:
@overload
def off(self, signal: Literal["changed"], callback: DeviceManagerChangedCallback) -> None: ...
@overload
def off(self, signal: str, callback: Callable[..., Any]) -> None: ...
def off(self, signal: str, callback: Callable[..., Any]) -> None:
"""
Remove a signal handler
@@ -1344,7 +1318,7 @@ class EndpointParameters:
_filter_missing_kwargs(kwargs)
if authentication is not None:
(auth_scheme, auth_data) = authentication
auth_scheme, auth_data = authentication
if auth_scheme == "token":
kwargs["auth_token"] = auth_data
elif auth_scheme == "callback":
@@ -1490,9 +1464,6 @@ class PortalService:
@overload
def on(self, signal: Literal["message"], callback: PortalServiceMessageCallback) -> None: ...
@overload
def on(self, signal: str, callback: Callable[..., Any]) -> None: ...
def on(self, signal: str, callback: Callable[..., Any]) -> None:
"""
Add a signal handler
@@ -1554,6 +1525,13 @@ CompilerFinishedCallback = Callable[[], None]
CompilerOutputCallback = Callable[[str], None]
CompilerDiagnosticsCallback = Callable[[List[CompilerDiagnostic]], None]
CompilerOutputFormat = Literal["unescaped", "hex-bytes", "c-string"]
CompilerBundleFormat = Literal["esm", "iife"]
CompilerTypeCheck = Literal["full", "none"]
CompilerSourceMaps = Literal["included", "omitted"]
CompilerCompression = Literal["none", "terser"]
CompilerPlatform = Literal["neutral", "gum", "browser"]
class Compiler:
def __init__(self) -> None:
@@ -1567,19 +1545,23 @@ class Compiler:
self,
entrypoint: str,
project_root: Optional[str] = None,
output_format: Optional[str] = None,
bundle_format: Optional[str] = None,
type_check: Optional[str] = None,
source_maps: Optional[str] = None,
compression: Optional[str] = None,
output_format: Optional[CompilerOutputFormat] = None,
bundle_format: Optional[CompilerBundleFormat] = None,
type_check: Optional[CompilerTypeCheck] = None,
source_maps: Optional[CompilerSourceMaps] = None,
compression: Optional[CompilerCompression] = None,
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,
"type_check": type_check,
"source_maps": source_maps,
"compression": compression,
"platform": platform,
"externals": externals,
}
_filter_missing_kwargs(kwargs)
return self._impl.build(entrypoint, **kwargs)
@@ -1589,19 +1571,23 @@ class Compiler:
self,
entrypoint: str,
project_root: Optional[str] = None,
output_format: Optional[str] = None,
bundle_format: Optional[str] = None,
type_check: Optional[str] = None,
source_maps: Optional[str] = None,
compression: Optional[str] = None,
output_format: Optional[CompilerOutputFormat] = None,
bundle_format: Optional[CompilerBundleFormat] = None,
type_check: Optional[CompilerTypeCheck] = None,
source_maps: Optional[CompilerSourceMaps] = None,
compression: Optional[CompilerCompression] = None,
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,
"type_check": type_check,
"source_maps": source_maps,
"compression": compression,
"platform": platform,
"externals": externals,
}
_filter_missing_kwargs(kwargs)
return self._impl.watch(entrypoint, **kwargs)
@@ -1618,10 +1604,11 @@ class Compiler:
@overload
def on(self, signal: Literal["diagnostics"], callback: CompilerDiagnosticsCallback) -> None: ...
@overload
def on(self, signal: str, callback: Callable[..., Any]) -> None: ...
def on(self, signal: str, callback: Callable[..., Any]) -> None:
"""
Add a signal handler
"""
self._impl.on(signal, callback)
@overload
@@ -1636,10 +1623,11 @@ class Compiler:
@overload
def off(self, signal: Literal["diagnostics"], callback: CompilerDiagnosticsCallback) -> None: ...
@overload
def off(self, signal: str, callback: Callable[..., Any]) -> None: ...
def off(self, signal: str, callback: Callable[..., Any]) -> None:
"""
Remove a signal handler
"""
self._impl.off(signal, callback)
@@ -1711,22 +1699,10 @@ class PackageManager:
_filter_missing_kwargs(kwargs)
return self._impl.install(**kwargs)
@overload
def on(self, signal: Literal["install-progress"], callback: PackageManagerInstallProgressCallback) -> None: ...
@overload
def on(self, signal: str, callback: Callable[..., Any]) -> None: ...
def on(self, signal: str, callback: Callable[..., Any]) -> None:
def on(self, signal: Literal["install-progress"], callback: PackageManagerInstallProgressCallback) -> None:
self._impl.on(signal, callback)
@overload
def off(self, signal: Literal["install-progress"], callback: PackageManagerInstallProgressCallback) -> None: ...
@overload
def off(self, signal: str, callback: Callable[..., Any]) -> None: ...
def off(self, signal: str, callback: Callable[..., Any]) -> None:
def off(self, signal: Literal["install-progress"], callback: PackageManagerInstallProgressCallback) -> None:
self._impl.off(signal, callback)
+1 -1
Submodule releng updated: 800f2385c3...10b201e27d
+1 -1
View File
@@ -1,6 +1,6 @@
[wrap-git]
url = https://github.com/frida/frida-core.git
revision = 17.4.2
revision = 17.9.2
depth = 1
[provide]