Compare commits

...
163 Commits
Author SHA1 Message Date
Ole André Vadla Ravnås cf1766d199 subprojects: Prepare for release 2025-05-20 22:40:50 +02:00
Ole André Vadla Ravnås 67fa4db816 Bump frida-compile and frida-fs 2025-05-20 22:39:22 +02:00
Ole André Vadla Ravnås 8e9363cfb5 subprojects: Bump outdated 2025-05-20 22:06:37 +02:00
Ole André Vadla Ravnås 710de8f174 submodules: Bump releng 2025-05-20 22:06:36 +02:00
Ole André Vadla Ravnås 350cfb2d30 subprojects: Prepare for release 2025-05-17 23:48:11 +02:00
Ole André Vadla Ravnås 95ca3422ce subprojects: Bump outdated 2025-05-17 23:46:48 +02:00
Ole André Vadla Ravnås 01cc4d15ac android: Bump frida-java-bridge to 7.0.1 2025-05-17 23:41:13 +02:00
Ole André Vadla Ravnås f8943edf87 darwin: Bump frida-objc-bridge to 8.0.4 2025-05-17 23:40:27 +02:00
Ole André Vadla Ravnås 80ff031073 base: Bump interface versions to match major version 2025-05-17 22:53:42 +02:00
Ole André Vadla Ravnås d133485443 subprojects: Prepare for release 2025-05-17 19:45:33 +02:00
Ole André Vadla Ravnås 56be2c35ad subprojects: Bump outdated 2025-05-17 19:10:44 +02:00
Ole André Vadla Ravnås 9c70e82545 meson: Require Node.js for Darwin and Android too
Now that these have agents built using frida-compile.
2025-05-17 19:07:58 +02:00
Ole André Vadla Ravnås a51fe412c2 subprojects: Bump outdated 2025-05-17 11:46:33 +02:00
Ole André Vadla Ravnås 87916f44b6 Move off deprecated GumJS APIs
Which are now gone.
2025-05-17 11:44:20 +02:00
Ole André Vadla Ravnås e58274b2a0 barebone: Upgrade Module API implementation 2025-05-17 11:43:11 +02:00
Ole André Vadla Ravnås f920aec415 git: Ignore Barebone's script-runtime.js 2025-05-17 11:42:35 +02:00
Ole André Vadla Ravnås f310cd876d Bump @types/frida-gum in internal agents 2025-05-17 11:41:49 +02:00
Ole André Vadla Ravnås dfce66b4b2 compiler: Bump @types/frida-gum 2025-05-17 11:03:37 +02:00
Ole André Vadla Ravnås cc554570f0 ios: Add frida-objc-bridge to agents
Now that the bridges are no longer baked into GumJS.
2025-05-17 09:55:14 +02:00
Ole André Vadla Ravnås 8311484510 android: Add frida-java-bridge to agent
Now that the bridges are no longer baked into GumJS.
2025-05-17 09:55:10 +02:00
Ole André Vadla Ravnås d1b3cb273c barebone: Factor out JS agent build logic 2025-05-17 09:27:33 +02:00
Ole André Vadla Ravnås 4f05cb60ce subprojects: Prepare for release 2025-05-14 15:26:46 +02:00
Ole André Vadla Ravnås 58b8a29938 subprojects: Bump outdated 2025-05-14 15:25:26 +02:00
Ole André Vadla Ravnås 524fa7c68a subprojects: Bump outdated 2025-05-14 09:40:18 +02:00
Ole André Vadla Ravnås fad0ea0209 submodules: Bump releng 2025-05-14 09:40:18 +02:00
Ole André Vadla Ravnås 0d6c0c4e60 subprojects: Prepare for release 2025-05-09 17:43:28 +02:00
Ole André Vadla Ravnås 1403ce084c subprojects: Bump outdated 2025-05-09 17:42:23 +02:00
Ole André Vadla Ravnås 6e29f7b3b6 fruity: Keep TcpTunnelConnection keypair alive
Now that TcpTunnelConnection no longer holds a reference of its own.
2025-05-09 17:33:38 +02:00
Ole André Vadla Ravnås 65d58b8a71 fruity: Use Apple's CoreDeviceProxy as fallback
So we can support systems where NCM is problematic.
2025-05-09 16:06:49 +02:00
Ole André Vadla Ravnås 80a3cb7a89 fruity: Add TcpTunnelConnection.open_stream() 2025-05-09 16:05:12 +02:00
Ole André Vadla Ravnås 59ad0989a7 fruity: Move lockdown service bits to UsbmuxTransport 2025-05-09 15:28:38 +02:00
Ole André Vadla Ravnås 0bdea096d1 fruity: Retransmit mDNS-SD request every 250 ms
Just in case we transmit it too early, we may need to retransmit.
2025-05-09 14:53:17 +02:00
Ole André Vadla Ravnås 3b62211346 subprojects: Prepare for release 2025-05-09 11:55:56 +02:00
Ole André Vadla Ravnås 7bd2507326 subprojects: Bump outdated 2025-05-09 11:54:51 +02:00
Ole André Vadla Ravnås 63739cc623 fruity: Handle OPACK boolean and compact integers
Support for the latter is needed during pairing on iOS 18.4.1.
2025-05-09 11:54:07 +02:00
Ole André Vadla Ravnås ab3026a1ed fruity: Improve portable tunnel error-handling
When we use lockdown to determine if the iDevice supports tunnels, and
that fails due to lack of lockdown-level pairing, simply assume that the
OS supports it.
2025-05-09 11:32:12 +02:00
Ole André Vadla Ravnås 6b712f2262 fruity: Add timeout to the Linux netif wait logic 2025-05-09 11:30:32 +02:00
Ole André Vadla Ravnås e3607bf260 fruity: Handle NetworkManager DISCONNECTED+CARRIER
So we actually wait until the device is ready when it quickly passes
through state=DISCONNECTED with reason=CARRIER.
2025-05-09 11:03:01 +02:00
Ole André Vadla Ravnås c58ad9bec6 fruity: Initiate pairing on macOS too, if needed 2025-05-09 09:52:42 +02:00
Ole André Vadla Ravnås 46a42f8c3d fruity: Move to XpcObjectReader.check_nserror() 2025-05-09 09:51:21 +02:00
Ole André Vadla Ravnås bc9d168581 xpc-object-reader: Add check_nserror() 2025-05-09 09:51:03 +02:00
Ole André Vadla Ravnås 9c8290b51b fruity: Tweak macOS CreateAssertion error handling
So we provide a clean error message when it fails.
2025-05-09 08:52:25 +02:00
Ole André Vadla Ravnås 086af542c9 subprojects: Prepare for release 2025-05-08 22:43:14 +02:00
Ole André Vadla Ravnås badd66adaf subprojects: Bump outdated 2025-05-08 22:41:26 +02:00
Ole André Vadla Ravnås b1bda6f351 subprojects: Prepare for release 2025-05-08 21:30:56 +02:00
Ole André Vadla Ravnås 7b43736e43 api: Install our GLib .gir files if needed
I.e. on systems without such infrastructure in place.
2025-05-08 19:21:15 +02:00
Ole André Vadla Ravnås 5cf879aac8 subprojects: Bump outdated 2025-05-08 17:06:24 +02:00
Ole André Vadla Ravnås b983f9b3fc bus: Remove the device property
Which wasn't meant to be exposed in the first place.
2025-05-07 19:32:46 +02:00
Ole André Vadla Ravnås 55e5cfa7e7 device-manager: Fix crash on early close()
In situations where HostSessionService start() gets cancelled.
2025-05-07 15:44:05 +02:00
Ole André Vadla Ravnås b8319f21e2 web-service: Fix handling of TLS connections
The remote address logic did not take them into account.
2025-05-07 15:21:02 +02:00
Ole André Vadla Ravnås 326190263d gadget: Unseal internal classes
To fix compiler warnings.
2025-05-07 14:41:45 +02:00
Ole André Vadla Ravnås 9acb2dcacd api: Include Injector type struct in the .h 2025-05-07 14:40:23 +02:00
Ole André Vadla Ravnås 2dcabf6a12 api: Hide AgentMessageSink in the .gir 2025-05-03 13:42:08 +02:00
Ole André Vadla Ravnås dce1c12de9 meson: Provide {GLib,GObject}-2.0.gir
For language bindings consuming us as a subproject.

This is a stopgap until we improve our SDKs so .gir assets are included.
2025-04-30 16:39:46 +02:00
Ole André Vadla Ravnås 1d9b0a4787 api: Fix up FridaBase references in the .gir 2025-04-30 16:29:34 +02:00
Ole André Vadla Ravnås f286a57c9c subprojects: Prepare for release 2025-04-25 22:35:55 +02:00
Ole André Vadla Ravnås 7cdc1fa5cd subprojects: Bump outdated 2025-04-25 22:34:26 +02:00
WorksButNotTested b3f7cfec01 linux: Update helpers for armbe8, arm64be and arm64beilp32 (#1160) 2025-04-17 18:36:28 +02:00
Ole André Vadla Ravnås 92f7b0b2a3 subprojects: Bump outdated 2025-04-17 18:15:36 +02:00
WorksButNotTested 7445ad2067 tests: Support big-endian arm64 2025-04-17 18:10:58 +02:00
WorksButNotTested a55e4dc331 tests: Fix labrat support to cover all systems (#1149) 2025-04-17 14:54:26 +02:00
WorksButNotTested 482f0ebebe tests: Skip slow tests on big-endian ARM (#1148) 2025-04-17 14:47:42 +02:00
Ole André Vadla Ravnås 4df7f6f422 subprojects: Prepare for release 2025-04-17 13:53:44 +02:00
Ole André Vadla Ravnås 96a3766f22 subprojects: Bump outdated 2025-04-17 13:52:03 +02:00
Ole André Vadla Ravnås 759dc3aae1 subprojects: Prepare for release 2025-04-16 20:26:45 +02:00
Ole André Vadla Ravnås 23e1dff791 subprojects: Bump outdated 2025-04-16 20:25:26 +02:00
Ole André Vadla Ravnås 08a9ccfe55 subprojects: Bump outdated 2025-04-16 20:16:43 +02:00
Ole André Vadla Ravnås 9f87f61f8e subprojects: Prepare for release 2025-04-14 17:59:46 +02:00
Ole André Vadla Ravnås e323cb1b88 subprojects: Bump outdated 2025-04-14 17:58:21 +02:00
Ole André Vadla Ravnås ef0bb9e844 darwin: Update injector dyld init detection for iOS 18.4 2025-04-14 17:56:53 +02:00
Shane G 35acf74f95 fruity: Update injector dyld init detection for iOS 18.4 (#1154) 2025-04-11 22:32:30 +02:00
Francesco Tamagni 3041f010fd network-stack: Reduce delay between writes
By flagging as writable as soon as some space is available, without
waiting for the low watermark.
2025-04-11 22:29:22 +02:00
Francesco Tamagni 310a3673bf network-stack: Fix TCP write chunk length (#1156) 2025-04-11 11:53:58 +02:00
Francesco Tamagni 270578183b network-stack: Always send enqueued data
This change makes sure `pcb.output()` is called even when no more
space is available on the queue, preventing stall.
2025-04-11 10:27:22 +02:00
Ole André Vadla Ravnås 0da9c2b3a1 subprojects: Prepare for release 2025-04-09 21:50:18 +02:00
Ole André Vadla Ravnås 615eb44e7d subprojects: Bump outdated 2025-04-09 21:48:38 +02:00
Ole André Vadla Ravnås bb3da1d561 network-stack: Fix TcpConnection transmit logic 2025-04-08 22:39:06 +02:00
Ole André Vadla Ravnås d391dc98ce network-stack: Improve VirtualStream locking
To improve batching and avoid unnecessary scheduling on Frida's thread.
2025-04-08 12:04:52 +02:00
Ole André Vadla Ravnås 4b34cb09a4 virtual-stream: Allow update_pending_io() w/o lock
For convenience when a subclass doesn't want to update any other state
before calling it.
2025-04-08 12:03:41 +02:00
Ole André Vadla Ravnås afd27c4235 subprojects: Prepare for release 2025-04-07 19:32:42 +02:00
Ole André Vadla Ravnås 794048e84e subprojects: Bump outdated 2025-04-07 19:31:49 +02:00
Francesco Tamagni 2b7c49c752 channel: Break read loop on empty buffer (#1150) 2025-04-07 19:29:40 +02:00
Ole André Vadla Ravnås 903d941ff0 device-manager: Fix teardown logic
Where we would also stop() the HostSessionService in cases where it
hadn't been start()ed.
2025-04-07 13:12:21 +02:00
Ole André Vadla Ravnås e5b422b8db subprojects: Prepare for release 2025-04-07 10:08:54 +02:00
Ole André Vadla Ravnås aac74e662e subprojects: Bump outdated 2025-04-07 10:08:01 +02:00
Ole André Vadla Ravnås ddab33010d subprojects: Prepare for release 2025-04-05 14:46:58 +02:00
Ole André Vadla Ravnås a2a77cdfa5 subprojects: Bump outdated 2025-04-05 11:14:07 +02:00
Ole André Vadla Ravnås 672bf55778 freebsd: Unseal Binjector to fix compilation
The C glue code depends on its fields for now.
2025-04-05 11:13:38 +02:00
Ole André Vadla Ravnås 722949d5fa subprojects: Prepare for release 2025-04-05 11:10:31 +02:00
Ole André Vadla Ravnås 5fed974dc5 subprojects: Bump outdated 2025-04-05 09:38:34 +02:00
Ole André Vadla Ravnås 7d2c0682e3 qnx: Unseal Qinjector to fix compilation
The C glue code depends on its fields for now.
2025-04-05 09:36:50 +02:00
Ole André Vadla Ravnås fcb66f61da subprojects: Prepare for release 2025-04-05 08:52:16 +02:00
Ole André Vadla Ravnås 23f1086bac subprojects: Bump outdated 2025-04-05 08:50:59 +02:00
Ole André Vadla Ravnås a0cf6a940b meson: Provide Gio-2.0.gir for convenience
So users won't need any GObject Introspection packages installed when
they're building language bindings and consuming us as a subproject.
2025-04-03 15:19:55 +02:00
Ole André Vadla Ravnås 0a4ee7acbb meson: Fix frida_girdir for the uninstalled case
It should point at the directory containing the refined .gir, not the
raw one from the Vala compiler.
2025-04-03 15:15:26 +02:00
Ole André Vadla Ravnås b8aeff0854 api: Seal classes not meant to be subclassed
Except for inner classes, as that results in C compiler warnings.
2025-04-03 12:23:57 +02:00
Ole André Vadla Ravnås 6a1f43f052 api: Fix vapi entries for sealed classes 2025-04-03 10:12:39 +02:00
Ole André Vadla Ravnås 87c293c831 api: Drop some accidentally exposed types 2025-04-02 18:40:57 +02:00
Ole André Vadla Ravnås 3e75fc9b84 subprojects: Prepare for release 2025-03-31 21:22:52 +02:00
Ole André Vadla Ravnås 1b6ca8fe46 subprojects: Bump outdated 2025-03-31 20:17:34 +02:00
Ole André Vadla Ravnås 9e35e245b1 host-session: Add support for remote services
So they are no longer exclusively an out-of-band local API. This means
that ControlService/frida-server can serve service sessions.
2025-03-31 20:10:49 +02:00
Ole André Vadla Ravnås 4a8c0bb13b api: Expose sealed classes 2025-03-31 20:10:49 +02:00
Ole André Vadla Ravnås 7c39f1783a stream: Factor out IOStream commonalities 2025-03-31 20:10:49 +02:00
Ole André Vadla Ravnås 194f025a98 host-session: Add support for remote channels
So they are no longer exclusively an out-of-band local API. This means
that ControlService/frida-server can serve channels.
2025-03-31 20:10:46 +02:00
Ole André Vadla Ravnås e6b2a6d6dd session: Remove unused ObjectPath constant 2025-03-30 16:26:58 +02:00
Ole André Vadla Ravnås e66b93b647 host-session: Factor out duplicated local logic 2025-03-28 17:18:35 +01:00
Ole André Vadla Ravnås 4a887eaed5 host-session: Rename BaseDBusHostSession to LocalHostSession
For clarity.
2025-03-28 17:18:17 +01:00
Ole André Vadla Ravnås 180075a7a0 control-service: Fix session logic for remote device 2025-03-28 15:29:14 +01:00
Ole André Vadla Ravnås 20ebf7fa15 host-session-provider: Add unlink_agent_session()
To support use-cases such as ControlService, where one specific client
gets disconnected and we need to tear down its agent sessions.
2025-03-28 15:29:11 +01:00
Ole André Vadla Ravnås 1018aca28d compiler: Bump frida-compile 2025-03-25 20:14:26 +01:00
Ole André Vadla Ravnås 93870b9f66 compiler: Bump @types/frida-gum 2025-03-24 17:33:23 +01:00
Ole André Vadla Ravnås 259ce04fe6 subprojects: Prepare for release 2025-03-21 14:20:50 +01:00
Ole André Vadla Ravnås 4cdfa4b09c subprojects: Bump outdated 2025-03-21 14:19:27 +01:00
Ole André Vadla Ravnås 7b54e41f88 droidy: Fix the MAX_MESSAGE_LENGTH declaration
The new maximum exceeds the range of a uint16.
2025-03-21 14:18:59 +01:00
Ole André Vadla Ravnås c7b1e17c3e subprojects: Prepare for release 2025-03-21 13:57:14 +01:00
Ole André Vadla Ravnås e844297a61 subprojects: Bump outdated 2025-03-20 20:38:52 +01:00
Ole André Vadla Ravnås 30b00eaa64 subprojects: Bump outdated 2025-03-20 17:00:25 +01:00
Ole André Vadla Ravnås 2109c38e06 submodules: Bump releng 2025-03-20 17:00:25 +01:00
Ole André Vadla Ravnås 1a3da37cf8 compiler: Bump @types/frida-gum 2025-03-20 16:59:53 +01:00
Jan S. 3d9fab2b0d fruity: Fix Input/Output Error on Windows (#1144)
By skipping devices with an empty UDID.
2025-03-19 15:12:07 +01:00
philippmao c58212fe8c droidy: Support more than ~8 ADB-connected devices (#1145)
By bumping the message size limit.
2025-03-19 15:07:44 +01:00
Ole André Vadla Ravnås bce2650980 subprojects: Bump outdated 2025-03-19 10:51:37 +01:00
Ole André Vadla Ravnås 0f03a0ee19 submodules: Bump releng 2025-03-19 10:51:36 +01:00
Ole André Vadla Ravnås d9b4d20adf linux: Include linux/unistd.h for syscall constant
Which, depending on the libc, may not be implicitly included.
2025-03-18 19:11:03 +00:00
Ole André Vadla Ravnås a8db90d6a5 subprojects: Bump outdated 2025-03-18 19:51:10 +01:00
Ole André Vadla Ravnås edcb76f066 submodules: Bump releng 2025-03-18 19:51:09 +01:00
Ole André Vadla Ravnås 1f72d5f102 subprojects: Prepare for release 2025-03-13 19:09:35 +01:00
Ole André Vadla Ravnås 8336d42b94 server: Create DeviceManager without local backend
Since we're pulling it in manually in order to run the frida-helper
in-process, we want to avoid having both implementations.

This reduces our footprint from 58M down to 49M on macOS, up from 46M
before the --device feature.
2025-03-13 19:06:33 +01:00
Ole André Vadla Ravnås 9404147517 device-manager: Support running w/o local backend
So consumers that don't need it can get a smaller footprint.
2025-03-13 19:01:20 +01:00
Ole André Vadla Ravnås ed464e9ccf subprojects: Bump outdated 2025-03-13 15:07:33 +01:00
Ole André Vadla Ravnås ce6178e125 server: Add --device for serving a specific device 2025-03-13 14:43:36 +01:00
Ole André Vadla Ravnås 0e69ec3e77 control-service: Support serving a specific Device 2025-03-13 14:42:57 +01:00
Ole André Vadla Ravnås 4eba770491 subprojects: Bump outdated 2025-03-13 14:09:11 +01:00
WorksButNotTested dc022e4bbe linux: Build helpers for arm64be and arm64beilp32 (#1141) 2025-03-13 13:47:09 +01:00
WorksButNotTested df04bb40c3 linux: Add support for arm64beilp32 (#1140) 2025-03-12 14:26:54 +01:00
WorksButNotTested 0f685ea496 linux: Support building helpers for armbe8 (#1139) 2025-03-12 10:07:43 +01:00
WorksButNotTested 48bfb1e054 linux: Add support for arm64be 2025-03-12 09:33:04 +01:00
Ole André Vadla Ravnås ab8a0a3927 compiler: Bump @types/frida-gum 2025-03-12 08:55:15 +01:00
Ole André Vadla Ravnås 9594e1a8b8 linux: Handle compat ranges during injection
So our spurious range detection doesn't make an incomplete candidate,
and we might end up picking the wrong one.
2025-03-03 23:38:47 +01:00
Ole André Vadla Ravnås 60a6770dba darwin: Fix racy leakage of memory during teardown
Where DarwinHelperBackend.close() would cancel dispatch sources, but
return before the cancel handler got a chance to run. While this leak
typically happened on teardown and wasn't necessarily a big deal
locally, the worse part was that we also leaked large regions of memory
in remote processes that we uninjected from just before teardown.
2025-02-28 17:34:49 +01:00
Ole André Vadla Ravnås c5376242e9 darwin: Fix HelperBackend MainContext assumptions
We should not blindly dispatch to the default one, but take note at
construction time.

This is to avoid surprises down the road, and to improve consistency
across the codebase.
2025-02-28 17:34:49 +01:00
Ole André Vadla Ravnås 17d6161435 linux: Avoid spurious .so ranges during injection
By checking that the mapping starts at file offset zero, and considering
all candidates ranked by the number of mappings, and whether executable
mappings exist in a given cluster.

Now that Gum.Module objects live longer, and may have an Gum.ElfModule
that has the ELF mapped, there's a much higher likelihood of running
into such spurious ranges.
2025-02-20 10:18:44 +01:00
Ole André Vadla Ravnås 26d9b9b6b1 fruity: Fix crash in the Linux getifaddrs() logic
Which failed to handle interfaces without an address.
2025-02-20 08:48:30 +01:00
Ole André Vadla Ravnås 1ed5590c77 submodules: Bump releng 2025-02-18 11:15:09 +01:00
Ole André Vadla Ravnås 25a283e43b ci: Fix the linux-x86 job
Now that ubuntu-latest refers to a newer Ubuntu release, we need to
move to the newer lib32stdc++ package version that matches that of
the gcc-multilib package.
2025-02-18 11:12:51 +01:00
Ole André Vadla Ravnås 04e04166b7 subprojects: Bump outdated 2025-02-18 11:12:51 +01:00
Ole André Vadla Ravnås 2c6c52d22a darwin: Port to the new ModuleResolver API 2025-02-18 11:12:51 +01:00
Ole André Vadla Ravnås ba7d01f232 subprojects: Prepare for release 2025-01-27 20:54:28 +01:00
Ole André Vadla Ravnås 8a16d42652 subprojects: Bump outdated 2025-01-27 20:51:53 +01:00
Ole André Vadla Ravnås 9c13120d67 fruity: Fix lockdown over CoreDevice regression
Introduced by the recent change in d1df792, where our RSDCheckin
includes an EscrowBag in order to support networked lockdown with
services such as “com.apple.crashreportmover”.

Turns out this broke support for quite a few other services, as the
presence of an EscrowBag requires that the particular service is able
to talk to AppleKeyStoreUserClient.

Not yet sure how to handle this. For now we'll maintain a list of
services that lack such privileges, so we can omit the EscrowBag for
those.

Kudos to @as0ler for reporting and helping troubleshoot.
2025-01-27 19:35:52 +01:00
Ole André Vadla Ravnås e70812a1e0 subprojects: Prepare for release 2025-01-23 20:46:57 +01:00
Ole André Vadla Ravnås 283381ca9e subprojects: Bump outdated 2025-01-23 20:31:30 +01:00
Mohamed Amine Amor 72a96226ce linux: Avoid risky code swaps with memfd regions
As they may not be writable, and unlike regular regions, ptrace() won't
help us in case of a missing writable bit.
2025-01-23 19:13:59 +01:00
Mohamed Amine Amor b6577afe81 linux: Relax injector's libc matching for Android
Due to how APEXes are bind-mounted.
2025-01-23 19:13:59 +01:00
Ole André Vadla Ravnås d1df7922bc fruity: Support networked lockdown for CoreDevice
Where we need to provide the remote unlock host key as part of the
RSDCheckin.

Kudos to @as0ler and @mrmacete for reporting and helping get to the
bottom of this one.
2025-01-23 18:41:01 +01:00
Ole André Vadla Ravnås af9c36ce6e xpc: Add support for Data objects 2025-01-23 15:27:47 +01:00
Ole André Vadla Ravnås da58033e9b subprojects: Prepare for release 2025-01-17 16:49:07 +01:00
Ole André Vadla Ravnås 702f3e83eb subprojects: Bump outdated 2025-01-17 16:46:54 +01:00
WorksButNotTested 7644f3dc6d linux: Revive support for ARM BE8 (#1130) 2025-01-17 16:30:59 +01:00
Ole André Vadla Ravnås 24d2d6f055 subprojects: Prepare for release 2025-01-14 19:35:29 +01:00
Ole André Vadla Ravnås 47d44f07ae subprojects: Bump outdated 2025-01-14 19:33:17 +01:00
Ole André Vadla Ravnås 8119fc7569 submodules: Bump releng 2025-01-14 19:33:17 +01:00
Ole André Vadla Ravnås 57409c8056 windows: Port injector to new Gum.Module API 2025-01-14 18:09:55 +01:00
223 changed files with 268142 additions and 2418 deletions

No files matched your search

+34 -2
View File
@@ -44,7 +44,7 @@ jobs:
if: matrix.id == 'linux-x86'
run: |
sudo apt-get update
sudo apt-get install gcc-multilib lib32stdc++-11-dev
sudo apt-get install gcc-multilib lib32stdc++-13-dev
- name: Build
if: ${{ startsWith(matrix.id, 'windows-') }}
run: |
@@ -249,7 +249,7 @@ jobs:
check-linux-helpers:
strategy:
matrix:
arch: [x86, x86_64, arm, arm64, mips, mipsel, mips64, mips64el]
arch: [x86, x86_64, arm, armbe8, arm64, arm64be, arm64beilp32, mips, mipsel, mips64, mips64el]
runs-on: ubuntu-latest
container: ghcr.io/frida/core-linux-helpers-${{ matrix.arch }}:latest
steps:
@@ -273,3 +273,35 @@ jobs:
else
echo "No unexpected changes detected."
fi
# This job is used to check that the Linux labrats are built correctly for all
# supported architectures. We do this because the binary artifacts are checked
# in, and we want to ensure that they are up-to-date with respect to the source
# for all architectures.
check-labrats:
strategy:
matrix:
arch: [x86, x86_64, arm, armbe8, arm64, arm64be, arm64beilp32, mips, mipsel, mips64, mips64el]
runs-on: ubuntu-latest
container: ghcr.io/frida/core-linux-helpers-${{ matrix.arch }}:latest
steps:
- name: Check out repo
uses: actions/checkout@v4
with:
submodules: recursive
- name: Build
run: |
./tests/labrats/rebuild.sh ${{ matrix.arch }}
- name: Check for unexpected changes
run: |
git config --global --add safe.directory "$(realpath .)"
status_output="$(git status --porcelain)"
if [ -n "$status_output" ]; then
echo "Unexpected changes detected:"
echo "$status_output"
echo "Diff:"
git diff
exit 1
else
echo "No unexpected changes detected."
fi
+7
View File
@@ -3,9 +3,16 @@
/src/barebone/helpers/memory-scanner/target/
/src/barebone/helpers/target/
/src/barebone/node_modules/
/src/barebone/script-runtime.js
/src/compiler/node_modules/
/src/darwin/agent/osanalytics/node_modules/
/src/darwin/agent/osanalytics/osanalytics.js
/src/darwin/agent/reportcrash/node_modules/
/src/darwin/agent/reportcrash/reportcrash.js
/src/droidy/helper/build/
/src/fruity/helpers/build/
/src/linux/agent/system-server/node_modules/
/src/linux/agent/system-server/system-server.js
/src/linux/helpers/build/
/src/linux/helpers/ext/
/subprojects/*
+2 -2
View File
@@ -147,7 +147,7 @@ namespace Frida.Inject {
public extern void init ();
}
public class Application : Object {
public sealed class Application : Object {
public string? device_id {
get;
construct;
@@ -426,7 +426,7 @@ namespace Frida.Inject {
#endif
}
private class ScriptRunner : Object, RpcPeer {
private sealed class ScriptRunner : Object, RpcPeer {
public TerminalMode terminal_mode {
get;
private set;
+2 -2
View File
@@ -11,7 +11,7 @@ namespace Frida.Agent {
PROCESS_TRANSITION
}
private class Runner : Object, ProcessInvader, AgentSessionProvider, ExitHandler, ForkHandler, SpawnHandler {
private sealed class Runner : Object, ProcessInvader, AgentSessionProvider, ExitHandler, ForkHandler, SpawnHandler {
public static Runner shared_instance = null;
public static Mutex shared_mutex;
private static string? cached_agent_path = null;
@@ -1621,7 +1621,7 @@ namespace Frida.Agent {
}
#endif
private class LiveAgentSession : BaseAgentSession {
private sealed class LiveAgentSession : BaseAgentSession {
public uint registration_id {
get;
set;
+3 -3
View File
@@ -1,5 +1,5 @@
namespace Frida {
public class BufferBuilder : Object {
public sealed class BufferBuilder : Object {
public ByteOrder byte_order {
get;
construct;
@@ -307,7 +307,7 @@ namespace Frida {
NUL
}
public class Buffer : Object {
public sealed class Buffer : Object {
public Bytes bytes {
get;
construct;
@@ -466,7 +466,7 @@ namespace Frida {
}
}
public class BufferReader {
public sealed class BufferReader {
public size_t available {
get {
return buffer.bytes.get_size () - offset;
+243
View File
@@ -0,0 +1,243 @@
namespace Frida {
public sealed class ChannelRegistry : Object {
public signal void channel_closed (ChannelId id);
private Gee.Map<ChannelId?, weak IOStream> channels =
new Gee.HashMap<ChannelId?, weak IOStream> (ChannelId.hash, ChannelId.equal);
~ChannelRegistry () {
clear ();
}
public void clear () {
foreach (IOStream stream in channels.values.to_array ()) {
var channel_stream = stream as ChannelStream;
if (channel_stream != null)
channel_stream.abandon ();
}
channels.clear ();
}
public void register (ChannelId id, IOStream stream) {
stream.set_data ("channel-registry-entry", new Entry (this, id));
lock (channels)
channels[id] = stream;
}
public IOStream link (ChannelId id) throws Error {
IOStream? stream;
lock (channels)
stream = channels[id];
if (stream == null)
throw new Error.INVALID_ARGUMENT ("Invalid channel ID");
return stream;
}
public void unlink (ChannelId id) {
lock (channels) {
if (!channels.unset (id))
return;
}
channel_closed (id);
}
private class Entry {
public ChannelRegistry parent;
public ChannelId id;
public Entry (ChannelRegistry parent, ChannelId id) {
this.parent = parent;
this.id = id;
}
~Entry () {
parent.unlink (id);
}
}
}
public sealed class ChannelEndpoint : Object, Channel {
private IOStream? stream;
private ByteArray write_queue = new ByteArray ();
private bool writing = false;
private Cancellable io_cancellable = new Cancellable ();
public ChannelEndpoint (IOStream stream) {
this.stream = stream;
read_loop.begin ();
}
public async void close (Cancellable? cancellable) throws Error, IOError {
io_cancellable.cancel ();
}
public async void input (uint8[] data, Cancellable? cancellable) throws Error, IOError {
if (io_cancellable.is_cancelled ())
throw new Error.INVALID_OPERATION ("Channel is closed");
write_queue.append (data);
if (!writing) {
writing = true;
var source = new IdleSource ();
source.set_callback (() => {
process_write_queue.begin ();
return false;
});
source.attach (MainContext.get_thread_default ());
}
}
private async void read_loop () {
var input = stream.get_input_stream ();
var buffer = new uint8[64 * 1024];
while (true) {
ssize_t n;
try {
n = yield input.read_async (buffer, Priority.DEFAULT, io_cancellable);
} catch (GLib.Error e) {
break;
}
output (buffer[:n]);
if (n == 0)
break;
}
stream.close_async.begin ();
stream = null;
}
private async void process_write_queue () {
if (stream != null) {
var output = stream.get_output_stream ();
while (write_queue.len > 0) {
uint8[] batch = write_queue.steal ();
size_t bytes_written;
try {
yield output.write_all_async (batch, Priority.DEFAULT, io_cancellable, out bytes_written);
} catch (GLib.Error e) {
break;
}
}
}
writing = false;
}
}
public sealed class ChannelStream : VirtualStream {
public Channel channel {
get;
construct;
}
private ByteArray recv_queue = new ByteArray ();
private ByteArray send_queue = new ByteArray ();
public ChannelStream (Channel channel) {
Object (channel: channel);
}
construct {
channel.output.connect (on_output);
}
public void abandon () {
with_state_lock (() => {
state = CLOSED;
update_pending_io ();
});
}
protected override IOCondition query_events () {
IOCondition new_events = 0;
if (recv_queue.len != 0 || state == CLOSED)
new_events |= IN;
if (state == OPEN)
new_events |= OUT;
return new_events;
}
protected override void handle_close () {
channel.close.begin (null);
}
public override ssize_t read (uint8[] buffer) throws IOError {
ssize_t n = 0;
with_state_lock (() => {
n = ssize_t.min (recv_queue.len, buffer.length);
if (n > 0) {
Memory.copy (buffer, recv_queue.data, n);
recv_queue.remove_range (0, (uint) n);
update_pending_io ();
} else {
if (state == OPEN)
n = -1;
}
});
if (n == -1)
throw new IOError.WOULD_BLOCK ("Resource temporarily unavailable");
return n;
}
public override ssize_t write (uint8[] buffer) throws IOError {
with_state_lock (() => {
send_queue.append (buffer);
});
if (main_context.is_owner ()) {
process_send_queue ();
} else {
var source = new IdleSource ();
source.set_callback (() => {
process_send_queue ();
return Source.REMOVE;
});
source.attach (main_context);
}
return buffer.length;
}
private void process_send_queue () {
uint8[]? chunk = null;
with_state_lock (() => {
size_t n = send_queue.len;
if (n == 0)
return;
chunk = send_queue.data[0:n];
send_queue.remove_range (0, (uint) n);
});
if (chunk == null)
return;
channel.input.begin (chunk, io_cancellable);
}
private void on_output (uint8[] data) {
with_state_lock (() => {
if (data.length != 0)
recv_queue.append (data);
else
state = CLOSED;
update_pending_io ();
});
}
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
namespace Frida {
public class CFArray<T> {
public sealed class CFArray<T> {
private CoreFoundation.Array handle;
public static CFArray<T> wrap<T> (void * handle) {
+1 -1
View File
@@ -60,7 +60,7 @@ namespace Frida {
return yield connection.get_proxy (null, ObjectPath.HOST_SESSION, DBusProxyFlags.NONE, cancellable);
}
private class DummyInputStream : InputStream {
private sealed class DummyInputStream : InputStream {
private bool done = false;
private Mutex mutex;
private Cond cond;
+3
View File
@@ -1,6 +1,9 @@
base_sources = [
'session.vala',
'session-glue.c',
'channel.vala',
'service.vala',
'stream.vala',
'rpc.vala',
'p2p.vala',
'p2p-glue.c',
+35 -233
View File
@@ -169,7 +169,7 @@ namespace Frida {
}
}
public class PeerSocket : Object, DatagramBased {
public sealed class PeerSocket : Object, DatagramBased {
public Nice.Agent agent {
get;
construct;
@@ -452,6 +452,8 @@ namespace Frida {
if ((_pending_io & c) != 0)
source.set_ready_time (0);
}
notify_property ("pending-io");
}
private void prepare_for_io (int64 timeout, Cancellable? cancellable, out int64 deadline) throws IOError {
@@ -563,7 +565,7 @@ namespace Frida {
}
}
public class SctpConnection : IOStream {
public sealed class SctpConnection : VirtualStream {
public DatagramBased transport_socket {
get;
construct;
@@ -584,55 +586,14 @@ namespace Frida {
construct;
}
public State state {
get {
return _state;
}
}
public override InputStream input_stream {
get {
return _input_stream;
}
}
public override OutputStream output_stream {
get {
return _output_stream;
}
}
public IOCondition pending_io {
get {
lock (state)
return sctp_events;
}
}
private State _state = CREATED;
private SctpInputStream _input_stream;
private SctpOutputStream _output_stream;
private DatagramBasedSource transport_source;
private uint8[] transport_buffer = new uint8[65536];
private void * sctp_socket;
private IOCondition sctp_events = 0;
private SctpTimerSource sctp_source;
private uint16 stream_id;
private ByteArray dcep_message = new ByteArray ();
private Gee.Map<unowned Source, IOCondition> sources = new Gee.HashMap<unowned Source, IOCondition> ();
private Cancellable io_cancellable = new Cancellable ();
public enum State {
CREATED,
OPENING,
OPENED,
CLOSED
}
public SctpConnection (DatagramBased transport_socket, PeerSetup setup, uint16 port, size_t max_message_size) {
Object (
transport_socket: transport_socket,
@@ -649,14 +610,9 @@ namespace Frida {
protected extern static void _initialize_sctp_backend ();
construct {
_input_stream = new SctpInputStream (this);
_output_stream = new SctpOutputStream (this);
sctp_socket = _create_sctp_socket ();
_connect_sctp_socket (sctp_socket, port);
var main_context = MainContext.get_thread_default ();
transport_source = transport_socket.create_source (IOCondition.IN, io_cancellable);
transport_source.set_callback (on_transport_socket_readable);
transport_source.attach (main_context);
@@ -669,17 +625,22 @@ namespace Frida {
protected extern void _connect_sctp_socket (void * sock, uint16 port);
public override bool close (GLib.Cancellable? cancellable) throws IOError {
do_close ();
return true;
protected override VirtualStream.State query_initial_state () {
return CREATED;
}
public override async bool close_async (int io_priority, GLib.Cancellable? cancellable) throws IOError {
do_close ();
return true;
protected override IOCondition query_events () {
return _query_sctp_socket_events (sctp_socket);
}
private void do_close () {
protected override void update_pending_io () {
base.update_pending_io ();
sctp_source.invalidate ();
}
protected extern static IOCondition _query_sctp_socket_events (void * sock);
protected override void handle_close () {
sctp_source.destroy ();
transport_source.destroy ();
@@ -689,13 +650,17 @@ namespace Frida {
public extern static void _close (void * sock);
public void shutdown (SctpShutdownType type) throws IOError {
_shutdown (sctp_socket, type);
public override void shutdown_read () throws IOError {
_shutdown (sctp_socket, READ);
}
public override void shutdown_write () throws IOError {
_shutdown (sctp_socket, WRITE);
}
public extern static void _shutdown (void * sock, SctpShutdownType type) throws IOError;
public ssize_t recv (uint8[] buffer) throws IOError {
public override ssize_t read (uint8[] buffer) throws IOError {
ssize_t n = -1;
try {
@@ -711,18 +676,18 @@ namespace Frida {
handle_dcep_message (stream_id, dcep_message.steal ());
}
throw new IOError.WOULD_BLOCK ("Resource temporarily unavailable");
} else if (protocol_id == NONE || _state != OPENED) {
} else if (protocol_id == NONE || state != OPEN) {
throw new IOError.WOULD_BLOCK ("Resource temporarily unavailable");
}
} finally {
update_sctp_events ();
update_pending_io ();
}
return n;
}
public ssize_t send (uint8[] buffer) throws IOError {
if (_state != OPENED)
public override ssize_t write (uint8[] buffer) throws IOError {
if (state != OPEN)
throw new IOError.WOULD_BLOCK ("Resource temporarily unavailable");
ssize_t n = ssize_t.min (buffer.length, (ssize_t) max_message_size);
@@ -730,20 +695,10 @@ namespace Frida {
try {
return _send (sctp_socket, stream_id, WEBRTC_BINARY, buffer[0:n]);
} finally {
update_sctp_events ();
update_pending_io ();
}
}
public void register_source (Source source, IOCondition condition) {
lock (state)
sources[source] = condition | IOCondition.ERR | IOCondition.HUP;
}
public void unregister_source (Source source) {
lock (state)
sources.unset (source);
}
private bool on_transport_socket_readable (DatagramBased datagram_based, IOCondition condition) {
var v = InputVector ();
v.buffer = transport_buffer;
@@ -783,9 +738,9 @@ namespace Frida {
}
protected void _on_sctp_socket_events_changed () {
update_sctp_events ();
update_pending_io ();
if (_state == CREATED && setup == ACTIVE && (sctp_events & IOCondition.OUT) != 0) {
if (state == CREATED && setup == ACTIVE && (pending_io & IOCondition.OUT) != 0) {
stream_id = 1;
uint8[] open_message = {
@@ -799,31 +754,12 @@ namespace Frida {
};
try {
_send (sctp_socket, stream_id, WEBRTC_DCEP, open_message);
_state = OPENING;
state = OPENING;
} catch (IOError e) {
}
}
}
private void update_sctp_events () {
IOCondition new_events = _query_sctp_socket_events (sctp_socket);
lock (state) {
sctp_events = new_events;
foreach (var entry in sources.entries) {
unowned Source source = entry.key;
IOCondition c = entry.value;
if ((new_events & c) != 0)
source.set_ready_time (0);
}
sctp_source.invalidate ();
}
}
protected extern static IOCondition _query_sctp_socket_events (void * sock);
protected extern static ssize_t _recv (void * sock, uint8[] buffer, out uint16 stream_id,
out PayloadProtocolId protocol_id, out SctpMessageFlags message_flags) throws IOError;
@@ -835,7 +771,7 @@ namespace Frida {
switch (type) {
case DATA_CHANNEL_OPEN: {
if (_state != CREATED || setup == ACTIVE)
if (state != CREATED || setup == ACTIVE)
return;
this.stream_id = stream_id;
@@ -843,15 +779,15 @@ namespace Frida {
uint8[] reply = { DcepMessageType.DATA_CHANNEL_ACK };
_send (sctp_socket, stream_id, WEBRTC_DCEP, reply);
_state = OPENED;
state = OPEN;
break;
}
case DATA_CHANNEL_ACK:
if (_state != OPENING)
if (state != OPENING)
return;
_state = OPENED;
state = OPEN;
break;
}
@@ -886,140 +822,6 @@ namespace Frida {
DATA_CHANNEL_ACK = 0x02
}
private class SctpInputStream : InputStream, PollableInputStream {
public weak SctpConnection connection {
get;
construct;
}
public SctpInputStream (SctpConnection connection) {
Object (connection: connection);
}
public override bool close (Cancellable? cancellable) throws IOError {
connection.shutdown (READ);
return true;
}
public override async bool close_async (int io_priority, Cancellable? cancellable) throws GLib.IOError {
return close (cancellable);
}
public override ssize_t read (uint8[] buffer, Cancellable? cancellable) throws IOError {
assert_not_reached ();
}
public bool can_poll () {
return true;
}
public bool is_readable () {
return (connection.pending_io & IOCondition.IN) != 0;
}
public PollableSource create_source (Cancellable? cancellable) {
return new PollableSource.full (this, new SctpIOSource (connection, IOCondition.IN), cancellable);
}
public ssize_t read_nonblocking_fn (uint8[] buffer) throws GLib.Error {
return connection.recv (buffer);
}
}
private class SctpOutputStream : OutputStream, PollableOutputStream {
public weak SctpConnection connection {
get;
construct;
}
public SctpOutputStream (SctpConnection connection) {
Object (connection: connection);
}
public override bool close (Cancellable? cancellable) throws IOError {
connection.shutdown (WRITE);
return true;
}
public override async bool close_async (int io_priority, Cancellable? cancellable) throws GLib.IOError {
return close (cancellable);
}
public override bool flush (GLib.Cancellable? cancellable) throws GLib.Error {
return true;
}
public override async bool flush_async (int io_priority, GLib.Cancellable? cancellable) throws GLib.Error {
return true;
}
public override ssize_t write (uint8[] buffer, Cancellable? cancellable) throws IOError {
assert_not_reached ();
}
public bool can_poll () {
return true;
}
public bool is_writable () {
return (connection.pending_io & IOCondition.OUT) != 0;
}
public PollableSource create_source (Cancellable? cancellable) {
return new PollableSource.full (this, new SctpIOSource (connection, IOCondition.OUT), cancellable);
}
public ssize_t write_nonblocking_fn (uint8[]? buffer) throws GLib.Error {
return connection.send (buffer);
}
public PollableReturn writev_nonblocking_fn (OutputVector[] vectors, out size_t bytes_written) throws GLib.Error {
assert_not_reached ();
}
}
private class SctpIOSource : Source {
public SctpConnection connection;
public IOCondition condition;
public SctpIOSource (SctpConnection connection, IOCondition condition) {
this.connection = connection;
this.condition = condition;
connection.register_source (this, condition);
}
~SctpIOSource () {
connection.unregister_source (this);
}
protected override bool prepare (out int timeout) {
timeout = -1;
return (connection.pending_io & condition) != 0;
}
protected override bool check () {
return (connection.pending_io & condition) != 0;
}
protected override bool dispatch (SourceFunc? callback) {
set_ready_time (-1);
if (callback == null)
return Source.REMOVE;
return callback ();
}
protected static bool closure_callback (Closure closure) {
var return_value = Value (typeof (bool));
closure.invoke (ref return_value, {});
return return_value.get_boolean ();
}
}
private class SctpTimerSource : Source {
private static int64 last_process_time = -1;
+1 -1
View File
@@ -1,5 +1,5 @@
namespace Frida {
public class Promise<T> {
public sealed class Promise<T> {
private Impl<T> impl;
public Future<T> future {
+1 -1
View File
@@ -1,5 +1,5 @@
namespace Frida {
public class RpcClient : Object {
public sealed class RpcClient : Object {
public weak RpcPeer peer {
get;
construct;
+48
View File
@@ -0,0 +1,48 @@
namespace Frida {
public sealed class ServiceSessionRegistry : Object {
public signal void session_closed (ServiceSessionId id);
private Gee.Map<ServiceSessionId?, ServiceSession> sessions =
new Gee.HashMap<ServiceSessionId?, ServiceSession> (ServiceSessionId.hash, ServiceSessionId.equal);
~ServiceSessionRegistry () {
clear ();
}
public void clear () {
foreach (var session in sessions.values.to_array ())
session.close ();
sessions.clear ();
}
public void register (ServiceSessionId id, ServiceSession session) {
sessions[id] = session;
ServiceSessionId? boxed_id = id;
session.set_data ("service-session-id", boxed_id);
session.close.connect (on_session_close);
}
public ServiceSession link (ServiceSessionId id) throws Error {
var session = sessions[id];
if (session == null)
throw new Error.INVALID_ARGUMENT ("Invalid session ID");
return session;
}
public void unlink (ServiceSessionId id) {
ServiceSession? session;
if (sessions.unset (id, out session)) {
session.close.disconnect (on_session_close);
session_closed (id);
}
}
private void on_session_close (ServiceSession session) {
ServiceSessionId? id = session.get_data ("service-session-id");
unlink (id);
}
}
}
+105 -25
View File
@@ -1,5 +1,5 @@
namespace Frida {
[DBus (name = "re.frida.HostSession16")]
[DBus (name = "re.frida.HostSession17")]
public interface HostSession : Object {
public abstract async void ping (uint interval_seconds, Cancellable? cancellable) throws GLib.Error;
@@ -27,6 +27,10 @@ namespace Frida {
public abstract async InjectorPayloadId inject_library_blob (uint pid, uint8[] blob, string entrypoint, string data,
Cancellable? cancellable) throws GLib.Error;
public abstract async ChannelId open_channel (string address, Cancellable? cancellable) throws GLib.Error;
public abstract async ServiceSessionId open_service (string address, Cancellable? cancellable) throws GLib.Error;
public signal void spawn_added (HostSpawnInfo info);
public signal void spawn_removed (HostSpawnInfo info);
public signal void child_added (HostChildInfo info);
@@ -34,10 +38,12 @@ namespace Frida {
public signal void process_crashed (CrashInfo crash);
public signal void output (uint pid, int fd, uint8[] data);
public signal void agent_session_detached (AgentSessionId id, SessionDetachReason reason, CrashInfo crash);
public signal void channel_closed (ChannelId id);
public signal void service_session_closed (ServiceSessionId id);
public signal void uninjected (InjectorPayloadId id);
}
[DBus (name = "re.frida.AgentSessionProvider16")]
[DBus (name = "re.frida.AgentSessionProvider17")]
public interface AgentSessionProvider : Object {
public abstract async void open (AgentSessionId id, HashTable<string, Variant> options,
Cancellable? cancellable) throws GLib.Error;
@@ -52,7 +58,7 @@ namespace Frida {
public signal void child_gating_changed (uint subscriber_count);
}
[DBus (name = "re.frida.AgentSession16")]
[DBus (name = "re.frida.AgentSession17")]
public interface AgentSession : Object {
public abstract async void close (Cancellable? cancellable) throws GLib.Error;
@@ -94,7 +100,7 @@ namespace Frida {
public signal void candidate_gathering_done ();
}
[DBus (name = "re.frida.AgentController16")]
[DBus (name = "re.frida.AgentController17")]
public interface AgentController : Object {
#if !WINDOWS
public abstract async HostChildId prepare_to_fork (uint parent_pid, Cancellable? cancellable, out uint parent_injectee_id,
@@ -115,7 +121,7 @@ namespace Frida {
Cancellable? cancellable) throws GLib.Error;
}
[DBus (name = "re.frida.AgentMessageSink16")]
[DBus (name = "re.frida.AgentMessageSink17")]
public interface AgentMessageSink : Object {
public abstract async void post_messages (AgentMessage[] messages, uint batch_id,
Cancellable? cancellable) throws GLib.Error;
@@ -145,7 +151,7 @@ namespace Frida {
DEBUGGER
}
public class AgentMessageTransmitter : Object {
public sealed class AgentMessageTransmitter : Object {
public signal void closed ();
public signal void new_candidates (string[] candidate_sdps);
public signal void candidate_gathering_done ();
@@ -743,13 +749,30 @@ namespace Frida {
}
}
[DBus (name = "re.frida.TransportBroker16")]
[DBus (name = "re.frida.Channel17")]
public interface Channel : Object {
public abstract async void close (Cancellable? cancellable) throws GLib.Error;
public abstract async void input (uint8[] data, Cancellable? cancellable) throws GLib.Error;
public signal void output (uint8[] data);
}
[DBus (name = "re.frida.ServiceSession17")]
public interface ServiceSession : Object {
public signal void close ();
public signal void message (Variant message);
public abstract async void activate (Cancellable? cancellable) throws GLib.Error;
public abstract async void cancel (Cancellable? cancellable) throws GLib.Error;
public abstract async Variant request (Variant parameters, Cancellable? cancellable) throws GLib.Error;
}
[DBus (name = "re.frida.TransportBroker17")]
public interface TransportBroker : Object {
public abstract async void open_tcp_transport (AgentSessionId id, Cancellable? cancellable, out uint16 port,
out string token) throws GLib.Error;
}
[DBus (name = "re.frida.PortalSession16")]
[DBus (name = "re.frida.PortalSession17")]
public interface PortalSession : Object {
public abstract async void join (HostApplicationInfo app, SpawnStartState current_state,
AgentSessionId[] interrupted_sessions, HashTable<string, Variant> options, Cancellable? cancellable,
@@ -758,19 +781,19 @@ namespace Frida {
public signal void kill ();
}
[DBus (name = "re.frida.BusSession16")]
[DBus (name = "re.frida.BusSession17")]
public interface BusSession : Object {
public abstract async void attach (Cancellable? cancellable) throws GLib.Error;
public abstract async void post (string json, bool has_data, uint8[] data, Cancellable? cancellable) throws GLib.Error;
public signal void message (string json, bool has_data, uint8[] data);
}
[DBus (name = "re.frida.AuthenticationService16")]
[DBus (name = "re.frida.AuthenticationService17")]
public interface AuthenticationService : Object {
public abstract async string authenticate (string token, Cancellable? cancellable) throws GLib.Error;
}
public class StaticAuthenticationService : Object, AuthenticationService {
public sealed class StaticAuthenticationService : Object, AuthenticationService {
public string token_hash {
get;
construct;
@@ -795,13 +818,13 @@ namespace Frida {
}
}
public class NullAuthenticationService : Object, AuthenticationService {
public sealed class NullAuthenticationService : Object, AuthenticationService {
public async string authenticate (string token, Cancellable? cancellable) throws Error, IOError {
throw new Error.INVALID_OPERATION ("Authentication not expected");
}
}
public class UnauthorizedHostSession : Object, HostSession {
public sealed class UnauthorizedHostSession : Object, HostSession {
public async void ping (uint interval_seconds, Cancellable? cancellable) throws Error, IOError {
throw_not_authorized ();
}
@@ -875,9 +898,17 @@ namespace Frida {
Cancellable? cancellable) throws Error, IOError {
throw_not_authorized ();
}
public async ChannelId open_channel (string address, Cancellable? cancellable) throws Error, IOError {
throw_not_authorized ();
}
public async ServiceSessionId open_service (string address, Cancellable? cancellable) throws Error, IOError {
throw_not_authorized ();
}
}
public class UnauthorizedPortalSession : Object, PortalSession {
public sealed class UnauthorizedPortalSession : Object, PortalSession {
public async void join (HostApplicationInfo app, SpawnStartState current_state,
AgentSessionId[] interrupted_sessions, HashTable<string, Variant> options,
Cancellable? cancellable, out SpawnStartState next_state) throws Error, IOError {
@@ -885,7 +916,7 @@ namespace Frida {
}
}
public class UnauthorizedBusSession : Object, BusSession {
public sealed class UnauthorizedBusSession : Object, BusSession {
public async void attach (Cancellable? cancellable) throws Error, IOError {
throw_not_authorized ();
}
@@ -1083,7 +1114,7 @@ namespace Frida {
}
}
public class FrontmostQueryOptions : Object {
public sealed class FrontmostQueryOptions : Object {
public Scope scope {
get;
set;
@@ -1113,7 +1144,7 @@ namespace Frida {
}
}
public class ApplicationQueryOptions : Object {
public sealed class ApplicationQueryOptions : Object {
public Scope scope {
get;
set;
@@ -1171,7 +1202,7 @@ namespace Frida {
}
}
public class ProcessQueryOptions : Object {
public sealed class ProcessQueryOptions : Object {
public Scope scope {
get;
set;
@@ -1313,7 +1344,7 @@ namespace Frida {
}
}
public class SessionOptions : Object {
public sealed class SessionOptions : Object {
public Realm realm {
get;
set;
@@ -1502,6 +1533,46 @@ namespace Frida {
}
}
public struct ChannelId {
public string handle;
public ChannelId (string handle) {
this.handle = handle;
}
public ChannelId.generate () {
this.handle = Uuid.string_random ().replace ("-", "");
}
public static uint hash (ChannelId? id) {
return id.handle.hash ();
}
public static bool equal (ChannelId? a, ChannelId? b) {
return a.handle == b.handle;
}
}
public struct ServiceSessionId {
public string handle;
public ServiceSessionId (string handle) {
this.handle = handle;
}
public ServiceSessionId.generate () {
this.handle = Uuid.string_random ().replace ("-", "");
}
public static uint hash (ServiceSessionId? id) {
return id.handle.hash ();
}
public static bool equal (ServiceSessionId? a, ServiceSessionId? b) {
return a.handle == b.handle;
}
}
public struct AgentScriptId {
public uint handle;
@@ -1518,7 +1589,7 @@ namespace Frida {
}
}
public class ScriptOptions : Object {
public sealed class ScriptOptions : Object {
public string? name {
get;
set;
@@ -1608,7 +1679,7 @@ namespace Frida {
SHARED_MEMORY
}
public class SnapshotOptions : Object {
public sealed class SnapshotOptions : Object {
public string? warmup_script {
get;
set;
@@ -1683,7 +1754,7 @@ namespace Frida {
}
}
public class PortalOptions : Object {
public sealed class PortalOptions : Object {
public TlsCertificate? certificate {
get;
set;
@@ -1746,7 +1817,7 @@ namespace Frida {
}
}
public class PeerOptions : Object {
public sealed class PeerOptions : Object {
public string? stun_server {
get;
set;
@@ -1807,7 +1878,7 @@ namespace Frida {
}
}
public class Relay : Object {
public sealed class Relay : Object {
public string address {
get;
construct;
@@ -2048,7 +2119,8 @@ namespace Frida {
public const string AGENT_SESSION = "/re/frida/AgentSession";
public const string AGENT_CONTROLLER = "/re/frida/AgentController";
public const string AGENT_MESSAGE_SINK = "/re/frida/AgentMessageSink";
public const string CHILD_SESSION = "/re/frida/ChildSession";
public const string CHANNEL = "/re/frida/Channel";
public const string SERVICE = "/re/frida/Service";
public const string TRANSPORT_BROKER = "/re/frida/TransportBroker";
public const string PORTAL_SESSION = "/re/frida/PortalSession";
public const string BUS_SESSION = "/re/frida/BusSession";
@@ -2061,6 +2133,14 @@ namespace Frida {
public static string for_agent_message_sink (AgentSessionId id) {
return AGENT_MESSAGE_SINK + "/" + id.handle;
}
public static string for_channel (ChannelId id) {
return CHANNEL + "/" + id.handle;
}
public static string for_service_session (ServiceSessionId id) {
return SERVICE + "/" + id.handle;
}
}
namespace Marshal {
+53 -240
View File
@@ -97,7 +97,7 @@ namespace Frida {
}
}
public class EndpointParameters : Object {
public sealed class EndpointParameters : Object {
public string? address {
get;
construct;
@@ -234,7 +234,7 @@ namespace Frida {
return (inet_addr.get_family () == IPV6) ? @"[$host]" : host;
}
public class WebService : Object {
public sealed class WebService : Object {
public signal void incoming (IOStream connection, SocketAddress remote_address, DynamicInterface? dynamic_iface);
public EndpointParameters endpoint_params {
@@ -548,12 +548,17 @@ namespace Frida {
IOStream soup_stream = connection.get_io_stream ();
SocketConnection socket_stream;
soup_stream.get ("base-iostream", out socket_stream);
IOStream base_iostream;
soup_stream.get ("base-iostream", out base_iostream);
SocketAddress remote_address;
SocketAddress? remote_address = null;
SocketConnection? sc = base_iostream as SocketConnection;
if (sc == null) {
IOStream tls_stream = base_iostream;
tls_stream.get ("base-io-stream", out sc);
}
try {
remote_address = socket_stream.get_remote_address ();
remote_address = sc.get_remote_address ();
} catch (GLib.Error e) {
assert_not_reached ();
}
@@ -852,7 +857,7 @@ namespace Frida {
public abstract void start ();
}
public class DynamicInterface : Object {
public sealed class DynamicInterface : Object {
public string name {
get;
construct;
@@ -870,7 +875,7 @@ namespace Frida {
public extern static unowned string _version_string ();
private class WebConnection : IOStream {
private sealed class WebConnection : VirtualStream {
public signal void websocket_closed ();
public Soup.WebsocketConnection websocket {
@@ -878,37 +883,9 @@ namespace Frida {
construct;
}
public override InputStream input_stream {
get {
return _input_stream;
}
}
public override OutputStream output_stream {
get {
return _output_stream;
}
}
public IOCondition pending_io {
get {
lock (state)
return _pending_io;
}
}
private WebInputStream _input_stream;
private WebOutputStream _output_stream;
private Soup.WebsocketState state;
private IOCondition _pending_io;
private ByteArray recv_queue = new ByteArray ();
private ByteArray send_queue = new ByteArray ();
private Gee.Map<unowned Source, IOCondition> sources = new Gee.HashMap<unowned Source, IOCondition> ();
private MainContext main_context;
public WebConnection (Soup.WebsocketConnection websocket) {
Object (websocket: websocket);
}
@@ -916,14 +893,6 @@ namespace Frida {
construct {
websocket.max_incoming_payload_size = (256 * 1024) + 1; // XXX: There's an off-by-one error in libsoup
_input_stream = new WebInputStream (this);
_output_stream = new WebOutputStream (this);
state = websocket.state;
_pending_io = (state == OPEN) ? IOCondition.OUT : IOCondition.IN;
main_context = MainContext.ref_thread_default ();
websocket.closed.connect (on_closed);
websocket.message.connect (on_message);
}
@@ -933,51 +902,50 @@ namespace Frida {
websocket.closed.disconnect (on_closed);
}
public override bool close (GLib.Cancellable? cancellable) throws IOError {
_close ();
return true;
}
public override async bool close_async (int io_priority, GLib.Cancellable? cancellable) throws IOError {
_close ();
return true;
}
private void _close () {
if (main_context.is_owner ()) {
do_close ();
} else {
var source = new IdleSource ();
source.set_callback (() => {
do_close ();
return Source.REMOVE;
});
source.attach (main_context);
protected override VirtualStream.State query_initial_state () {
switch (websocket.state) {
case OPEN:
case CLOSING:
return OPEN;
case CLOSED:
return CLOSED;
}
assert_not_reached ();
}
private void do_close () {
protected override IOCondition query_events () {
IOCondition new_events = 0;
if (recv_queue.len > 0 || state != OPEN)
new_events |= IN;
if (state == OPEN)
new_events |= OUT;
return new_events;
}
protected override void handle_close () {
if (websocket.state != OPEN)
return;
websocket.close (1000, "Closing");
}
public ssize_t recv (uint8[] buffer) throws IOError {
ssize_t n;
lock (state) {
public override ssize_t read (uint8[] buffer) throws IOError {
ssize_t n = 0;
with_state_lock (() => {
n = ssize_t.min (recv_queue.len, buffer.length);
if (n > 0) {
Memory.copy (buffer, recv_queue.data, n);
recv_queue.remove_range (0, (uint) n);
recompute_pending_io_unlocked ();
update_pending_io ();
} else {
if (state == OPEN)
n = -1;
}
}
});
if (n == -1)
throw new IOError.WOULD_BLOCK ("Resource temporarily unavailable");
@@ -985,9 +953,10 @@ namespace Frida {
return n;
}
public ssize_t send (uint8[] buffer) {
lock (state)
public override ssize_t write (uint8[] buffer) {
with_state_lock (() => {
send_queue.append (buffer);
});
if (main_context.is_owner ()) {
process_send_queue ();
@@ -1011,190 +980,34 @@ namespace Frida {
while (true) {
uint8[]? chunk = null;
lock (state) {
with_state_lock (() => {
size_t n = size_t.min (send_queue.len, max_message_size);
if (n == 0)
return;
chunk = send_queue.data[0:n];
send_queue.remove_range (0, (uint) n);
}
});
if (chunk == null)
return;
websocket.send_binary (chunk);
}
}
public void register_source (Source source, IOCondition condition) {
lock (state)
sources[source] = condition;
}
public void unregister_source (Source source) {
lock (state)
sources.unset (source);
}
private void on_closed () {
lock (state) {
state = websocket.state;
recompute_pending_io_unlocked ();
}
with_state_lock (() => {
state = CLOSED;
update_pending_io ();
});
websocket_closed ();
}
private void on_message (int type, Bytes message) {
lock (state) {
with_state_lock (() => {
recv_queue.append (message.get_data ());
recompute_pending_io_unlocked ();
}
}
private void recompute_pending_io_unlocked () {
IOCondition new_io = 0;
if (recv_queue.len > 0 || state != OPEN)
new_io |= IN;
if (state == OPEN)
new_io |= OUT;
_pending_io = new_io;
foreach (var entry in sources.entries) {
unowned Source source = entry.key;
IOCondition c = entry.value;
if ((new_io & c) != 0)
source.set_ready_time (0);
}
}
}
private class WebInputStream : InputStream, PollableInputStream {
public weak WebConnection connection {
get;
construct;
}
public WebInputStream (WebConnection connection) {
Object (connection: connection);
}
public override bool close (Cancellable? cancellable) throws IOError {
return true;
}
public override async bool close_async (int io_priority, Cancellable? cancellable) throws GLib.IOError {
return close (cancellable);
}
public override ssize_t read (uint8[] buffer, Cancellable? cancellable) throws IOError {
assert_not_reached ();
}
public bool can_poll () {
return true;
}
public bool is_readable () {
return (connection.pending_io & IOCondition.IN) != 0;
}
public PollableSource create_source (Cancellable? cancellable) {
return new PollableSource.full (this, new WebIOSource (connection, IOCondition.IN), cancellable);
}
public ssize_t read_nonblocking_fn (uint8[] buffer) throws GLib.Error {
return connection.recv (buffer);
}
}
private class WebOutputStream : OutputStream, PollableOutputStream {
public weak WebConnection connection {
get;
construct;
}
public WebOutputStream (WebConnection connection) {
Object (connection: connection);
}
public override bool close (Cancellable? cancellable) throws IOError {
return true;
}
public override async bool close_async (int io_priority, Cancellable? cancellable) throws GLib.IOError {
return close (cancellable);
}
public override bool flush (GLib.Cancellable? cancellable) throws GLib.Error {
return true;
}
public override async bool flush_async (int io_priority, GLib.Cancellable? cancellable) throws GLib.Error {
return true;
}
public override ssize_t write (uint8[] buffer, Cancellable? cancellable) throws IOError {
assert_not_reached ();
}
public bool can_poll () {
return true;
}
public bool is_writable () {
return (connection.pending_io & IOCondition.OUT) != 0;
}
public PollableSource create_source (Cancellable? cancellable) {
return new PollableSource.full (this, new WebIOSource (connection, IOCondition.OUT), cancellable);
}
public ssize_t write_nonblocking_fn (uint8[]? buffer) throws GLib.Error {
return connection.send (buffer);
}
public PollableReturn writev_nonblocking_fn (OutputVector[] vectors, out size_t bytes_written) throws GLib.Error {
assert_not_reached ();
}
}
private class WebIOSource : Source {
public WebConnection connection;
public IOCondition condition;
public WebIOSource (WebConnection connection, IOCondition condition) {
this.connection = connection;
this.condition = condition;
connection.register_source (this, condition);
}
~WebIOSource () {
connection.unregister_source (this);
}
protected override bool prepare (out int timeout) {
timeout = -1;
return (connection.pending_io & condition) != 0;
}
protected override bool check () {
return (connection.pending_io & condition) != 0;
}
protected override bool dispatch (SourceFunc? callback) {
set_ready_time (-1);
if (callback == null)
return Source.REMOVE;
return callback ();
}
protected static bool closure_callback (Closure closure) {
var return_value = Value (typeof (bool));
closure.invoke (ref return_value, {});
return return_value.get_boolean ();
update_pending_io ();
});
}
}
}
+336
View File
@@ -0,0 +1,336 @@
namespace Frida {
public abstract class VirtualStream : IOStream {
public override InputStream input_stream {
get {
return _input_stream;
}
}
public override OutputStream output_stream {
get {
return _output_stream;
}
}
public IOCondition pending_io {
get {
lock (state)
return _pending_io;
}
}
protected State state = OPEN;
private VirtualInputStream _input_stream;
private VirtualOutputStream _output_stream;
private IOCondition _pending_io;
private Gee.Map<unowned Source, IOCondition> sources = new Gee.HashMap<unowned Source, IOCondition> ();
protected Cancellable io_cancellable = new Cancellable ();
protected MainContext main_context;
protected enum State {
CREATED,
OPENING,
OPEN,
CLOSED
}
protected delegate void WorkFunc ();
construct {
_input_stream = new VirtualInputStream (this);
_output_stream = new VirtualOutputStream (this);
main_context = MainContext.ref_thread_default ();
state = query_initial_state ();
_pending_io = query_events ();
}
public override void dispose () {
_output_stream.detach ();
_input_stream.detach ();
io_cancellable.cancel ();
base.dispose ();
}
protected virtual State query_initial_state () {
return OPEN;
}
protected abstract IOCondition query_events ();
public override bool close (GLib.Cancellable? cancellable) throws IOError {
_close ();
return true;
}
public override async bool close_async (int io_priority, GLib.Cancellable? cancellable) throws IOError {
_close ();
return true;
}
private void _close () {
if (main_context.is_owner ()) {
do_close ();
} else {
var source = new IdleSource ();
source.set_callback (() => {
do_close ();
return Source.REMOVE;
});
source.attach (main_context);
}
}
private void do_close () {
if (state == CLOSED)
return;
handle_close ();
}
protected abstract void handle_close ();
public virtual void shutdown_read () throws IOError {
}
public virtual void shutdown_write () throws IOError {
}
public abstract ssize_t read (uint8[] buffer) throws IOError;
public abstract ssize_t write (uint8[] buffer) throws IOError;
protected void with_state_lock (WorkFunc func) {
lock (state)
func ();
}
public void register_source (Source source, IOCondition condition) {
lock (state)
sources[source] = condition | IOCondition.ERR | IOCondition.HUP;
}
public void unregister_source (Source source) {
lock (state)
sources.unset (source);
}
protected virtual void update_pending_io () {
lock (state) {
_pending_io = query_events ();
foreach (var entry in sources.entries) {
unowned Source source = entry.key;
IOCondition c = entry.value;
if ((_pending_io & c) != 0)
source.set_ready_time (0);
}
}
notify_property ("pending-io");
}
}
private sealed class VirtualInputStream : InputStream, PollableInputStream {
private weak VirtualStream stream;
public VirtualInputStream (VirtualStream stream) {
Object ();
this.stream = stream;
}
internal void detach () {
stream = null;
}
public override bool close (Cancellable? cancellable) throws IOError {
if (stream != null)
stream.shutdown_read ();
return true;
}
public override async bool close_async (int io_priority, Cancellable? cancellable) throws GLib.IOError {
return close (cancellable);
}
public override ssize_t read (uint8[] buffer, Cancellable? cancellable) throws IOError {
if (stream == null)
return 0;
if (!is_readable ()) {
bool done = false;
var mutex = Mutex ();
var cond = Cond ();
ulong io_handler = stream.notify["pending-io"].connect ((obj, pspec) => {
if (is_readable ()) {
mutex.lock ();
done = true;
cond.signal ();
mutex.unlock ();
}
});
ulong cancellation_handler = 0;
if (cancellable != null) {
cancellation_handler = cancellable.connect (() => {
mutex.lock ();
done = true;
cond.signal ();
mutex.unlock ();
});
}
if (!is_readable ()) {
mutex.lock ();
while (!done)
cond.wait (mutex);
mutex.unlock ();
}
if (cancellation_handler != 0)
cancellable.disconnect (cancellation_handler);
stream.disconnect (io_handler);
cancellable.set_error_if_cancelled ();
}
return stream.read (buffer);
}
public bool can_poll () {
return true;
}
public bool is_readable () {
if (stream == null)
return true;
return (stream.pending_io & IOCondition.IN) != 0;
}
public PollableSource create_source (Cancellable? cancellable) {
return new PollableSource.full (this, new VirtualIOSource (stream, IOCondition.IN), cancellable);
}
public ssize_t read_nonblocking_fn (uint8[] buffer) throws GLib.Error {
if (stream == null)
return 0;
return stream.read (buffer);
}
}
private sealed class VirtualOutputStream : OutputStream, PollableOutputStream {
private weak VirtualStream? stream;
public VirtualOutputStream (VirtualStream stream) {
Object ();
this.stream = stream;
}
internal void detach () {
stream = null;
}
public override bool close (Cancellable? cancellable) throws IOError {
if (stream != null)
stream.shutdown_write ();
return true;
}
public override async bool close_async (int io_priority, Cancellable? cancellable) throws GLib.IOError {
return close (cancellable);
}
public override bool flush (GLib.Cancellable? cancellable) throws GLib.Error {
return true;
}
public override async bool flush_async (int io_priority, GLib.Cancellable? cancellable) throws GLib.Error {
return true;
}
public override ssize_t write (uint8[] buffer, Cancellable? cancellable) throws IOError {
return stream.write (buffer);
}
public bool can_poll () {
return true;
}
public bool is_writable () {
if (stream == null)
return false;
return (stream.pending_io & IOCondition.OUT) != 0;
}
public PollableSource create_source (Cancellable? cancellable) {
return new PollableSource.full (this, new VirtualIOSource (stream, IOCondition.OUT), cancellable);
}
public ssize_t write_nonblocking_fn (uint8[]? buffer) throws GLib.Error {
if (stream == null)
throw new IOError.CLOSED ("Virtual is closed");
return stream.write (buffer);
}
public PollableReturn writev_nonblocking_fn (OutputVector[] vectors, out size_t bytes_written) throws GLib.Error {
assert_not_reached ();
}
}
private class VirtualIOSource : Source {
public VirtualStream? stream;
public IOCondition condition;
public VirtualIOSource (VirtualStream stream, IOCondition condition) {
this.stream = stream;
this.condition = condition;
if (stream != null)
stream.register_source (this, condition);
}
~VirtualIOSource () {
if (stream != null)
stream.unregister_source (this);
}
protected override bool prepare (out int timeout) {
timeout = -1;
return is_ready ();
}
protected override bool check () {
return is_ready ();
}
private bool is_ready () {
IOCondition pending_io = (stream != null) ? stream.pending_io : IOCondition.IN;
return (pending_io & condition) != 0;
}
protected override bool dispatch (SourceFunc? callback) {
set_ready_time (-1);
if (callback == null)
return Source.REMOVE;
return callback ();
}
protected static bool closure_callback (Closure closure) {
var return_value = Value (typeof (bool));
closure.invoke (ref return_value, {});
return return_value.get_boolean ();
}
}
}
+3 -3
View File
@@ -38,7 +38,7 @@ namespace Frida {
public abstract unowned string get_uuid_value () throws Error;
}
public class VariantReader : Object, ObjectReader {
public sealed class VariantReader : Object, ObjectReader {
public Variant root_object {
get {
return scopes.peek_head ().val;
@@ -180,7 +180,7 @@ namespace Frida {
}
}
public class JsonObjectBuilder : Object, ObjectBuilder {
public sealed class JsonObjectBuilder : Object, ObjectBuilder {
private Json.Builder builder = new Json.Builder ();
private Gee.Map<string, Bytes> raw_values = new Gee.HashMap<string, Bytes> ();
@@ -267,7 +267,7 @@ namespace Frida {
}
}
public class JsonObjectReader : Object, ObjectReader {
public sealed class JsonObjectReader : Object, ObjectReader {
private Json.Reader reader;
public JsonObjectReader (string json) throws Error {
+33 -2
View File
@@ -1,5 +1,5 @@
namespace Frida {
public class XpcClient : Object {
public sealed class XpcClient : Object {
public signal void message (Darwin.Xpc.Object obj);
public State state {
@@ -123,7 +123,7 @@ namespace Frida {
}
}
public class XpcObjectReader {
public sealed class XpcObjectReader {
public Darwin.Xpc.Object root_object {
get {
return scopes.peek_head ().object;
@@ -136,6 +136,8 @@ namespace Frida {
}
}
public delegate int TranslateErrorFunc (string domain, int code, string description);
private Gee.Deque<Scope> scopes = new Gee.ArrayQueue<Scope> ();
public XpcObjectReader (Darwin.Xpc.Object obj) {
@@ -204,6 +206,13 @@ namespace Frida {
return peek_scope ().get_object<Darwin.Xpc.UInt64> (Darwin.Xpc.UInt64.TYPE).get_value ();
}
public unowned uint8[] get_data_value () throws Error {
var data = peek_scope ().get_object<Darwin.Xpc.Data> (Darwin.Xpc.Data.TYPE);
unowned uint8[] buf = (uint8[]) data.get_bytes_ptr ();
buf.length = (int) data.get_length ();
return buf;
}
public unowned string get_string_value () throws Error {
return peek_scope ().get_object<Darwin.Xpc.String> (Darwin.Xpc.String.TYPE).get_string_ptr ();
}
@@ -217,6 +226,28 @@ namespace Frida {
return error.get_string (Darwin.Xpc.Error.KEY_DESCRIPTION);
}
public void check_nserror (TranslateErrorFunc translate_error) throws Error {
if (!has_member ("error"))
return;
read_member ("error");
unowned string domain = read_member ("domain").get_string_value ();
end_member ();
var code = (int) read_member ("code").get_int64_value ();
end_member ();
string description = read_member ("userInfo").read_member ("NSLocalizedDescription").get_string_value ();
if (description.has_suffix ("."))
description = description[:description.length - 1];
throw (Error) new GLib.Error.literal (
Quark.from_string ("frida-error-quark"),
translate_error (domain, code, description),
description);
}
public unowned Darwin.Xpc.Object get_object_value (Darwin.Xpc.Type expected_type) throws Error {
return peek_scope ().get_object<Darwin.Xpc.Object> (expected_type);
}
+21 -13
View File
@@ -1,5 +1,5 @@
namespace Frida.Gadget {
private class Config : Object, Json.Serializable {
private sealed class Config : Object, Json.Serializable {
public Object interaction {
get;
set;
@@ -93,7 +93,7 @@ namespace Frida.Gadget {
}
}
private class ScriptInteraction : Object, Json.Serializable {
private sealed class ScriptInteraction : Object, Json.Serializable {
public string path {
get;
set;
@@ -145,7 +145,7 @@ namespace Frida.Gadget {
}
}
private class ScriptDirectoryInteraction : Object {
private sealed class ScriptDirectoryInteraction : Object {
public string path {
get;
set;
@@ -164,7 +164,7 @@ namespace Frida.Gadget {
}
}
private class ScriptConfig : Object, Json.Serializable {
private sealed class ScriptConfig : Object, Json.Serializable {
public ProcessFilter? filter {
get;
set;
@@ -216,7 +216,7 @@ namespace Frida.Gadget {
}
}
private class ProcessFilter : Object {
private sealed class ProcessFilter : Object {
public string[] executables {
get;
set;
@@ -258,7 +258,7 @@ namespace Frida.Gadget {
}
}
private class ListenInteraction : SocketInteraction {
private sealed class ListenInteraction : SocketInteraction {
public PortConflictBehavior on_port_conflict {
get;
set;
@@ -287,7 +287,7 @@ namespace Frida.Gadget {
}
}
private class ConnectInteraction : SocketInteraction, Json.Serializable {
private sealed class ConnectInteraction : SocketInteraction, Json.Serializable {
public string[]? acl {
get;
set;
@@ -328,7 +328,7 @@ namespace Frida.Gadget {
}
}
private class Location : Object {
private sealed class Location : Object {
public string executable_name {
get;
construct;
@@ -988,7 +988,7 @@ namespace Frida.Gadget {
}
}
private class ScriptRunner : BaseController {
private sealed class ScriptRunner : BaseController {
private ScriptEngine engine;
private Script script;
@@ -1036,7 +1036,7 @@ namespace Frida.Gadget {
}
}
private class ScriptDirectoryRunner : BaseController {
private sealed class ScriptDirectoryRunner : BaseController {
public string directory_path {
get;
construct;
@@ -1241,7 +1241,7 @@ namespace Frida.Gadget {
}
}
private class Script : Object, RpcPeer {
private sealed class Script : Object, RpcPeer {
private const uint8 QUICKJS_BYTECODE_MAGIC = 0x02;
public enum ChangeBehavior {
@@ -1453,7 +1453,7 @@ namespace Frida.Gadget {
}
}
private class ControlServer : BaseController {
private sealed class ControlServer : BaseController {
public EndpointParameters endpoint_params {
get;
construct;
@@ -1927,6 +1927,14 @@ namespace Frida.Gadget {
throw new Error.NOT_SUPPORTED ("Unable to inject libraries when embedded");
}
public async ChannelId open_channel (string address, Cancellable? cancellable) throws Error, IOError {
throw new Error.NOT_SUPPORTED ("Unable to open channels when embedded");
}
public async ServiceSessionId open_service (string address, Cancellable? cancellable) throws Error, IOError {
throw new Error.NOT_SUPPORTED ("Unable to open services when embedded");
}
private void validate_pid (uint pid) throws Error {
if (pid != this_process.pid)
throw new Error.NOT_SUPPORTED ("Unable to act on other processes when embedded");
@@ -1958,7 +1966,7 @@ namespace Frida.Gadget {
}
}
private class ClusterClient : BaseController {
private sealed class ClusterClient : BaseController {
public SocketConnectable connectable {
get;
construct;
+1 -1
View File
@@ -1,4 +1,4 @@
public class Frida.TunnelInterfaceObserver : Object, DynamicInterfaceObserver {
public sealed class Frida.TunnelInterfaceObserver : Object, DynamicInterfaceObserver {
#if IOS || TVOS
private Gee.Map<string, DynamicInterface> interfaces = new Gee.HashMap<string, DynamicInterface> ();
+8 -8
View File
@@ -1,5 +1,5 @@
namespace Frida {
public class ThreadIgnoreScope {
public sealed class ThreadIgnoreScope {
public enum Kind {
APPLICATION_THREAD,
FRIDA_THREAD
@@ -43,7 +43,7 @@ namespace Frida {
}
#if ANDROID
public class ThreadCountCloaker : Object {
public sealed class ThreadCountCloaker : Object {
private ReadFunc * read_slot;
private static ReadFunc old_read_impl;
@@ -156,12 +156,12 @@ namespace Frida {
}
}
#else
public class ThreadCountCloaker : Object {
public sealed class ThreadCountCloaker : Object {
}
#endif
#if LINUX
public class ThreadListCloaker : Object, DirListFilter {
public sealed class ThreadListCloaker : Object, DirListFilter {
private string our_dir_by_pid;
private DirListCloaker cloaker;
@@ -180,7 +180,7 @@ namespace Frida {
}
}
public class FDListCloaker : Object, DirListFilter {
public sealed class FDListCloaker : Object, DirListFilter {
private string our_dir_by_pid;
private DirListCloaker cloaker;
@@ -199,7 +199,7 @@ namespace Frida {
}
}
private class DirListCloaker : Object {
private sealed class DirListCloaker : Object {
public weak DirListFilter filter {
get;
construct;
@@ -467,10 +467,10 @@ namespace Frida {
public abstract bool matches_file (string name);
}
#else
public class ThreadListCloaker : Object {
public sealed class ThreadListCloaker : Object {
}
public class FDListCloaker : Object {
public sealed class FDListCloaker : Object {
}
#endif
}
+1 -1
View File
@@ -1,5 +1,5 @@
namespace Frida {
public class ExitMonitor : Object, Gum.InvocationListener {
public sealed class ExitMonitor : Object, Gum.InvocationListener {
public weak ExitHandler handler {
get;
construct;
+2 -2
View File
@@ -1,6 +1,6 @@
namespace Frida {
#if WINDOWS
public class FileDescriptorGuard : Object {
public sealed class FileDescriptorGuard : Object {
public Gum.MemoryRange agent_range {
get;
construct;
@@ -11,7 +11,7 @@ namespace Frida {
}
}
#else
public class FileDescriptorGuard : Object {
public sealed class FileDescriptorGuard : Object {
public Gum.MemoryRange agent_range {
get;
construct;
+2 -2
View File
@@ -1,6 +1,6 @@
namespace Frida {
#if WINDOWS
public class FileDescriptorTablePadder {
public sealed class FileDescriptorTablePadder {
public static FileDescriptorTablePadder obtain () {
return new FileDescriptorTablePadder ();
}
@@ -9,7 +9,7 @@ namespace Frida {
}
}
#else
public class FileDescriptorTablePadder {
public sealed class FileDescriptorTablePadder {
private const int MIN_TABLE_SIZE = 32;
private static unowned FileDescriptorTablePadder shared_instance = null;
+2 -2
View File
@@ -1,6 +1,6 @@
namespace Frida {
#if WINDOWS
public class ForkMonitor : Object {
public sealed class ForkMonitor : Object {
public weak ForkHandler handler {
get;
construct;
@@ -11,7 +11,7 @@ namespace Frida {
}
}
#else
public class ForkMonitor : Object, Gum.InvocationListener {
public sealed class ForkMonitor : Object, Gum.InvocationListener {
public weak ForkHandler handler {
get;
construct;
+1 -1
View File
@@ -1,5 +1,5 @@
namespace Frida {
public class PortalClient : Object, AgentSessionProvider {
public sealed class PortalClient : Object, AgentSessionProvider {
public signal void resume ();
public signal void kill ();
+2 -2
View File
@@ -1,5 +1,5 @@
namespace Frida {
public class ScriptEngine : Object {
public sealed class ScriptEngine : Object {
public signal void message_from_script (AgentScriptId script_id, string json, Bytes? data);
public signal void message_from_debugger (AgentScriptId script_id, string message);
@@ -223,7 +223,7 @@ namespace Frida {
source.attach (Gum.ScriptBackend.get_scheduler ().get_js_context ());
}
public class ScriptInstance : Object, RpcPeer {
public sealed class ScriptInstance : Object, RpcPeer {
public signal void closed ();
public signal void message (string json, Bytes? data);
public signal void debug_message (string message);
+1 -1
View File
@@ -1,5 +1,5 @@
namespace Frida {
public class SpawnMonitor : Object, Gum.InvocationListener {
public sealed class SpawnMonitor : Object, Gum.InvocationListener {
public weak SpawnHandler handler {
get;
construct;
+2 -2
View File
@@ -1,6 +1,6 @@
namespace Frida {
#if DARWIN
public class ThreadSuspendMonitor : Object {
public sealed class ThreadSuspendMonitor : Object {
public weak ProcessInvader invader {
get;
construct;
@@ -131,7 +131,7 @@ namespace Frida {
}
}
#else
public class ThreadSuspendMonitor : Object {
public sealed class ThreadSuspendMonitor : Object {
public weak ProcessInvader invader {
get;
construct;
+2 -2
View File
@@ -1,6 +1,6 @@
namespace Frida {
#if DARWIN
public class UnwindSitter : Object {
public sealed class UnwindSitter : Object {
public weak ProcessInvader invader {
get;
construct;
@@ -62,7 +62,7 @@ namespace Frida {
public extern static void _unhook_libunwind ();
}
#else
public class UnwindSitter : Object {
public sealed class UnwindSitter : Object {
public weak ProcessInvader invader {
get;
construct;
+2 -2
View File
@@ -1,5 +1,5 @@
namespace Frida {
public class PipeTransport : Object {
public sealed class PipeTransport : Object {
public string local_address {
get;
construct;
@@ -42,7 +42,7 @@ namespace Frida {
}
#if WINDOWS
public class WindowsPipe : IOStream {
public sealed class WindowsPipe : IOStream {
public string address {
get;
construct;
+11 -2
View File
@@ -162,6 +162,14 @@ if host_os_family == 'darwin'
endif
endif
if host_machine.endian() == 'big'
if host_abi in ['arm', 'armhf']
host_abi = 'armbe8'
elif host_abi == 'arm64'
host_abi = 'arm64be'
endif
endif
if host_os_family == 'darwin' and host_arch == 'arm64'
host_is_modern = host_abi == 'arm64e'
else
@@ -414,7 +422,7 @@ foreach b : [['local', have_local_backend],
endif
endforeach
if have_barebone_backend or have_compiler_backend
if host_os_family == 'darwin' or host_os == 'android' or have_barebone_backend or have_compiler_backend
node = find_program('node', version: '>=18.0.0', native: true, required: false)
if not node.found()
error('Need Node.js >= 18.0.0 to process JavaScript code at build time')
@@ -431,7 +439,6 @@ if gi_dep.found()
else
girdir = get_option('prefix') / get_option('datadir') / 'gir-1.0'
endif
uninstalled_girdir = meson.current_build_dir() / 'src'
vapidir = get_option('prefix') / get_option('datadir') / 'vala' / 'vapi'
@@ -665,6 +672,8 @@ post_process = [
'@INPUT0@',
]
compile_js_agent = files('tools' / 'compile-js-agent.py')
mapper_opt = get_option('mapper')
if mapper_opt.auto()
have_mapper = host_os_family == 'darwin'
+1 -1
View File
@@ -142,7 +142,7 @@ namespace Frida.Portal {
return application.run ();
}
private class Application : Object {
private sealed class Application : Object {
public signal void ready (bool success);
public PortalService service {
+1 -1
Submodule releng updated: 79d6dfa3d6...5d9edf166c.
+52 -9
View File
@@ -3,6 +3,7 @@ namespace Frida.Server {
private const string DEFAULT_DIRECTORY = "re.frida.server";
private static bool output_version = false;
private static string? device_id = null;
private static string? listen_address = null;
private static string? certpath = null;
private static string? origin = null;
@@ -30,6 +31,7 @@ namespace Frida.Server {
const OptionEntry[] option_entries = {
{ "version", 0, 0, OptionArg.NONE, ref output_version, "Output version information and exit", null },
{ "device", 0, 0, OptionArg.STRING, ref device_id, "Serve device with the given ID", "ID" },
{ "listen", 'l', 0, OptionArg.STRING, ref listen_address, "Listen on ADDRESS", "ADDRESS" },
{ "certificate", 0, 0, OptionArg.FILENAME, ref certpath, "Enable TLS using CERTIFICATE", "CERTIFICATE" },
{ "origin", 0, 0, OptionArg.STRING, ref origin, "Only accept requests with “Origin” header matching ORIGIN " +
@@ -178,7 +180,7 @@ namespace Frida.Server {
#if DARWIN
var worker = new Thread<int> ("frida-server-main-loop", () => {
var exit_code = run_application (endpoint_params, options, on_ready);
var exit_code = run_application (device_id, endpoint_params, options, on_ready);
_stop_run_loop ();
@@ -190,15 +192,16 @@ namespace Frida.Server {
return exit_code;
#else
return run_application (endpoint_params, options, on_ready);
return run_application (device_id, endpoint_params, options, on_ready);
#endif
}
private static int run_application (EndpointParameters endpoint_params, ControlServiceOptions options, ReadyHandler on_ready) {
private static int run_application (string? device_id, EndpointParameters endpoint_params, ControlServiceOptions options,
ReadyHandler on_ready) {
TemporaryDirectory.always_use ((directory != null) ? directory : DEFAULT_DIRECTORY);
TemporaryDirectory.use_sysroot (options.sysroot);
application = new Application (new ControlService (endpoint_params, options));
application = new Application (device_id, endpoint_params, options);
Posix.signal (Posix.Signal.INT, (sig) => {
application.stop ();
@@ -232,22 +235,39 @@ namespace Frida.Server {
}
#endif
private class Application : Object {
private sealed class Application : Object {
public signal void ready (bool success);
public ControlService service {
public string? device_id {
get;
construct;
}
public EndpointParameters endpoint_params {
get;
construct;
}
public ControlServiceOptions options {
get;
construct;
}
private DeviceManager? manager;
private ControlService? service;
private Cancellable io_cancellable = new Cancellable ();
private MainLoop loop = new MainLoop ();
private int exit_code;
private bool stopping;
public Application (ControlService service) {
Object (service: service);
public Application (string? device_id, EndpointParameters endpoint_params, ControlServiceOptions options) {
Object (
device_id: device_id,
endpoint_params: endpoint_params,
options: options
);
}
public int run () {
@@ -265,6 +285,17 @@ namespace Frida.Server {
private async void start () {
try {
if (device_id != null && device_id != "local") {
manager = new DeviceManager.with_nonlocal_backends_only ();
var device = yield manager.get_device_by_id (device_id, 0, io_cancellable);
device.lost.connect (on_device_lost);
service = yield new ControlService.with_device (device, endpoint_params, options);
} else {
service = new ControlService (endpoint_params, options);
}
yield service.start (io_cancellable);
} catch (GLib.Error e) {
if (e is IOError.CANCELLED)
@@ -297,7 +328,15 @@ namespace Frida.Server {
io_cancellable.cancel ();
try {
yield service.stop ();
if (service != null) {
yield service.stop ();
service = null;
}
if (manager != null) {
yield manager.close ();
manager = null;
}
} catch (GLib.Error e) {
}
@@ -306,6 +345,10 @@ namespace Frida.Server {
return false;
});
}
private void on_device_lost () {
stop ();
}
}
private TlsCertificate? parse_certificate (string? path) throws GLib.Error {
+1 -1
View File
@@ -1,5 +1,5 @@
namespace Frida {
public class AgentContainer : Object, AgentSessionProvider {
public sealed class AgentContainer : Object, AgentSessionProvider {
public DBusConnection connection {
get;
private set;
+91284
View File
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+141723
View File
File diff suppressed because it is too large. Load diff
+17 -5
View File
@@ -16,10 +16,13 @@ GIR_NAMESPACES = {
"glib": GLIB_NAMESPACE,
}
CORE_TAG_IMPLEMENTS = f"{{{CORE_NAMESPACE}}}implements"
CORE_TAG_FIELD = f"{{{CORE_NAMESPACE}}}field"
CORE_TAG_CONSTRUCTOR = f"{{{CORE_NAMESPACE}}}constructor"
CORE_TAG_METHOD = f"{{{CORE_NAMESPACE}}}method"
OBJECT_TYPE_PATTERN = re.compile(r"\bpublic\s+(sealed )?(class|interface)\s+(\w+)\b")
def main():
parser = argparse.ArgumentParser(description="Generate refined Frida API definitions")
parser.add_argument('--output', dest='output_type', choices=['bundle', 'header', 'gir', 'vapi', 'vapi-stamp'], default='bundle')
@@ -203,7 +206,9 @@ def emit_gir(api: ApiSpec, core_gir: str, base_gir: str, output_dir: Path) -> st
for elem in core_elements + base_elements:
if tag_name == "class":
for child in list(elem):
if child.tag == CORE_TAG_FIELD or child.get("name").startswith("_"):
if (child.tag == CORE_TAG_IMPLEMENTS and child.get("name") == "FridaBase.AgentMessageSink") \
or child.tag == CORE_TAG_FIELD \
or child.get("name").startswith("_"):
elem.remove(child)
merged_namespace.append(elem)
@@ -215,6 +220,7 @@ def emit_gir(api: ApiSpec, core_gir: str, base_gir: str, output_dir: Path) -> st
result = ET.tostring(merged_root,
encoding="unicode",
xml_declaration=True)
result = result.replace("FridaBase.", "Frida.")
with OutputFile(output_dir / f"Frida-{api.version}.gir") as output_gir:
output_gir.write(result)
@@ -288,12 +294,18 @@ def parse_api(api_version, toplevel_code, core_header, core_vapi, base_header, b
"StaticAuthenticationService": "AuthenticationService",
}
internal_type_prefixes = [
"AgentMessageKind",
"Fruity",
"HostSession",
"MessageType",
"PeerSetup",
"PortConflictBehavior",
"ResultCode",
"SpawnStartState",
"State",
"StringTerminator",
"UnloadPolicy",
"WebService",
"Winjector"
]
seen_enum_names = set()
@@ -375,7 +387,7 @@ def parse_api(api_version, toplevel_code, core_header, core_vapi, base_header, b
if delegate_cname not in seen_cdelegates:
seen_cdelegates.add(delegate_cname)
object_type.c_delegate_typedefs.append(beautify_cprototype(d.group(0)))
if object_type.kind == 'interface' and object_type.name != "Injector":
if object_type.kind == 'interface':
for m in re.finditer("^(struct _" + object_type.c_name + "Iface {[^}]+};)$", all_headers, re.MULTILINE):
object_type.c_iface_definition = beautify_cinterface(m.group(1))
@@ -412,8 +424,8 @@ def parse_api(api_version, toplevel_code, core_header, core_vapi, base_header, b
current_enum.vapi_declaration = stripped_line
else:
ignoring = True
elif stripped_line.startswith("public class") or stripped_line.startswith("public interface"):
name = re.match(r"^public (class|interface) (\w+) ", stripped_line).group(2)
elif (match := OBJECT_TYPE_PATTERN.match(stripped_line)) is not None:
name = match.group(3)
if name not in object_type_by_name:
ignoring = True
else:
@@ -470,7 +482,7 @@ def function_is_public(name):
]
def parse_vala_object_types(source) -> List[ApiObjectType]:
return [ApiObjectType(m.group(2), m.group(1)) for m in re.finditer(r"^\t+public\s+(class|interface)\s+(\w+)\s+", source, re.MULTILINE)]
return [ApiObjectType(m.group(3), m.group(2)) for m in OBJECT_TYPE_PATTERN.finditer(source, re.MULTILINE)]
def parse_vapi_functions(vapi) -> List[ApiFunction]:
return [ApiFunction(m.group(1), m.group(0)) for m in re.finditer(r"^\tpublic static .+ (\w+) \(.+;", vapi, re.MULTILINE)]
+9 -3
View File
@@ -1,3 +1,5 @@
fs = import('fs')
generate_api = [python, files('generate.py')]
generate_api_args = [
@@ -32,6 +34,11 @@ core_public_h = core_api[0]
core_public_gir = core_api[1]
core_public_vapi = [core_api[2], core_api[3]]
install_glib_girs = not gi_dep.found() and not fs.exists(girdir / 'GLib-2.0.gir')
glib_gir = fs.copyfile('GLib-2.0.gir', install: install_glib_girs, install_dir: girdir)
gobject_gir = fs.copyfile('GObject-2.0.gir', install: install_glib_girs, install_dir: girdir)
gio_gir = fs.copyfile('Gio-2.0.gir', install: install_glib_girs, install_dir: girdir)
core_public_vapi_stamp = custom_target('frida-core-vapi-stamp',
input: core_public_vapi,
output: f'frida-core-@[email protected]',
@@ -59,8 +66,6 @@ core_public_lib = custom_target('frida-core-library',
install_dir: get_option('libdir'),
)
fs = import('fs')
core_public_extra_headers = []
if host_os == 'android'
core_public_extra_headers += fs.copyfile(frida_selinux_h)
@@ -71,6 +76,7 @@ if build_machine.system() == 'windows'
else
uninstalled_incdir = meson.current_build_dir()
endif
uninstalled_girdir = uninstalled_incdir
uninstalled_vapidir = uninstalled_incdir
uninstalled_variables = {
@@ -86,7 +92,7 @@ installed_variables = {
}
core_public_dep = declare_dependency(
sources: [core_public_h, core_public_gir, core_public_vapi_stamp, core_public_extra_headers],
sources: [core_public_h, core_public_gir, glib_gir, gobject_gir, gio_gir, core_public_vapi_stamp, core_public_extra_headers],
include_directories: include_directories('.'),
link_args: backend_libs_private,
link_with: core_public_lib,
+1 -1
View File
@@ -17,7 +17,7 @@ namespace Frida.Barebone {
public abstract async void deallocate (Cancellable? cancellable) throws Error, IOError;
}
public class SimpleAllocator : Object, Allocator {
public sealed class SimpleAllocator : Object, Allocator {
public size_t page_size {
get { return _page_size; }
}
+1 -1
View File
@@ -1,6 +1,6 @@
[CCode (gir_namespace = "FridaBarebone", gir_version = "1.0")]
namespace Frida.Barebone {
public class ArmMachine : Object, Machine {
public sealed class ArmMachine : Object, Machine {
public override GDB.Client gdb {
get;
set;
+1 -1
View File
@@ -1,6 +1,6 @@
[CCode (gir_namespace = "FridaBarebone", gir_version = "1.0")]
namespace Frida.Barebone {
public class Arm64Machine : Object, Machine {
public sealed class Arm64Machine : Object, Machine {
public override GDB.Client gdb {
get;
set;
+1 -1
View File
@@ -1,6 +1,6 @@
[CCode (gir_namespace = "FridaBarebone", gir_version = "1.0")]
namespace Frida.Barebone {
public class UnknownMachine : Object, Machine {
public sealed class UnknownMachine : Object, Machine {
public GDB.Client gdb {
get;
set;
+1 -1
View File
@@ -1,6 +1,6 @@
[CCode (gir_namespace = "FridaBarebone", gir_version = "1.0")]
namespace Frida.Barebone {
public class IA32Machine : Object, Machine {
public sealed class IA32Machine : Object, Machine {
public override GDB.Client gdb {
get;
set;
+1 -1
View File
@@ -1,6 +1,6 @@
[CCode (gir_namespace = "FridaBarebone", gir_version = "1.0")]
namespace Frida.Barebone {
public class X64Machine : Object, Machine {
public sealed class X64Machine : Object, Machine {
public override GDB.Client gdb {
get;
set;
+44 -5
View File
@@ -1,5 +1,5 @@
namespace Frida {
public class BareboneHostSessionBackend : Object, HostSessionBackend {
public sealed class BareboneHostSessionBackend : Object, HostSessionBackend {
private BareboneHostSessionProvider? provider;
private const uint16 DEFAULT_PORT = 3333;
@@ -30,7 +30,7 @@ namespace Frida {
}
}
public class BareboneHostSessionProvider : Object, HostSessionProvider {
public sealed class BareboneHostSessionProvider : Object, HostSessionProvider {
public string id {
get { return "barebone"; }
}
@@ -141,12 +141,35 @@ namespace Frida {
return yield this.host_session.link_agent_session (id, sink, cancellable);
}
public void unlink_agent_session (HostSession host_session, AgentSessionId id) {
if (host_session != this.host_session)
return;
this.host_session.unlink_agent_session (id);
}
public async IOStream link_channel (HostSession host_session, ChannelId id, Cancellable? cancellable)
throws Error, IOError {
throw new Error.NOT_SUPPORTED ("Channels are not supported by this backend");
}
public void unlink_channel (HostSession host_session, ChannelId id) {
}
public async ServiceSession link_service_session (HostSession host_session, ServiceSessionId id, Cancellable? cancellable)
throws Error, IOError {
throw new Error.NOT_SUPPORTED ("Services are not supported by this backend");
}
public void unlink_service_session (HostSession host_session, ServiceSessionId id) {
}
private void on_agent_session_detached (AgentSessionId id, SessionDetachReason reason, CrashInfo crash) {
agent_session_detached (id, reason, crash);
}
}
public class BareboneHostSession : Object, HostSession {
public sealed class BareboneHostSession : Object, HostSession {
public Barebone.Services services {
get;
construct;
@@ -260,6 +283,14 @@ namespace Frida {
return session;
}
public void unlink_agent_session (AgentSessionId id) {
BareboneAgentSession? session = agent_sessions[id];
if (session == null)
return;
session.message_sink = null;
}
public async InjectorPayloadId inject_library_file (uint pid, string path, string entrypoint, string data,
Cancellable? cancellable) throws Error, IOError {
throw_not_supported ();
@@ -270,6 +301,14 @@ namespace Frida {
throw_not_supported ();
}
public async ChannelId open_channel (string address, Cancellable? cancellable) throws Error, IOError {
throw new Error.NOT_SUPPORTED ("Channels are not supported by this backend");
}
public async ServiceSessionId open_service (string address, Cancellable? cancellable) throws Error, IOError {
throw new Error.NOT_SUPPORTED ("Services are not supported by this backend");
}
private void on_agent_session_closed (BareboneAgentSession session) {
AgentSessionId id = session.id;
@@ -282,7 +321,7 @@ namespace Frida {
}
}
private class BareboneAgentSession : Object, AgentSession {
private sealed class BareboneAgentSession : Object, AgentSession {
public signal void closed ();
public AgentSessionId id {
@@ -525,7 +564,7 @@ namespace Frida {
}
namespace Barebone {
public class Services : Object {
public sealed class Services : Object {
public Machine machine {
get;
construct;
+1 -1
View File
@@ -1,6 +1,6 @@
[CCode (gir_namespace = "FridaBarebone", gir_version = "1.0")]
namespace Frida.Barebone {
public class Callback : Object {
public sealed class Callback : Object {
private uint64 code;
private CallbackHandler handler;
private Machine machine;
-36
View File
@@ -1,36 +0,0 @@
from pathlib import Path
import shutil
import subprocess
import sys
def main(argv):
output_dir, priv_dir, input_dir, npm = [Path(d).resolve() for d in argv[1:]]
try:
generate_runtime(output_dir, priv_dir, input_dir, npm)
except Exception as e:
print(e, file=sys.stderr)
sys.exit(1)
def generate_runtime(output_dir, priv_dir, input_dir, npm):
priv_dir.mkdir(exist_ok=True)
shutil.copy(input_dir / "package.json", priv_dir)
shutil.copy(input_dir / "package-lock.json", priv_dir)
runtime_reldir = Path("script-runtime")
runtime_srcdir = input_dir / runtime_reldir
runtime_intdir = priv_dir / runtime_reldir
if runtime_intdir.exists():
shutil.rmtree(runtime_intdir)
shutil.copytree(runtime_srcdir, runtime_intdir)
subprocess.run([npm, "install"], capture_output=True, cwd=priv_dir, check=True)
shutil.copy(priv_dir / "script-runtime.js", output_dir)
if __name__ == "__main__":
main(sys.argv)
+1 -1
View File
@@ -1,6 +1,6 @@
[CCode (gir_namespace = "FridaBarebone", gir_version = "1.0")]
namespace Frida.Barebone {
public class Interceptor : Object {
public sealed class Interceptor : Object {
public Machine machine {
get;
construct;
+3 -3
View File
@@ -29,11 +29,11 @@ barebone_script_runtime = custom_target('frida-barebone-script-runtime',
],
command: [
python,
files('generate-script-runtime.py'),
meson.current_build_dir(),
compile_js_agent,
'@OUTPUT@',
'@PRIVATE_DIR@',
meson.current_source_dir(),
npm,
'@INPUT@',
],
)
backend_sources += custom_target('frida-data-barebone',
+32 -21
View File
@@ -1,15 +1,15 @@
{
"name": "frida-barebone-runtime",
"name": "frida-barebone-script-runtime",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "frida-barebone-runtime",
"name": "frida-barebone-script-runtime",
"version": "1.0.0",
"devDependencies": {
"@types/frida-gum": "^18.3.2",
"frida-compile": "^16.2.1"
"@types/frida-gum": "^19.0.0",
"frida-compile": "^17.0.0"
}
},
"node_modules/@frida/assert": {
@@ -74,6 +74,13 @@
"node": ">=14.9.0"
}
},
"node_modules/@frida/crypto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@frida/crypto/-/crypto-1.0.1.tgz",
"integrity": "sha512-WXTkVjESvX8TIVXIynJJv9BKSIdQP0Iis04StIXknkDi1ULdMlrypA9p5C4KW1H6GCkNsVnKbybpzsulYCTvag==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/diagnostics_channel": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/diagnostics_channel/-/diagnostics_channel-1.0.0.tgz",
@@ -316,10 +323,11 @@
"dev": true
},
"node_modules/@types/frida-gum": {
"version": "18.3.2",
"resolved": "https://registry.npmjs.org/@types/frida-gum/-/frida-gum-18.3.2.tgz",
"integrity": "sha512-bso8bJRxrhchNRrOMmT18st/THIdjzxFdcMtJ/gGSYSknJeerQ8ArBwBtlWt/f3pqVVs1Mz1Fg6lvUdjXswa+g==",
"dev": true
"version": "19.0.0",
"resolved": "https://registry.npmjs.org/@types/frida-gum/-/frida-gum-19.0.0.tgz",
"integrity": "sha512-qViK1KwvPEAkajwSUv0wpZvZLiX8xO4JFFCh8dfYZfzSyOEfoE0KliCP/nJSKIKG6N3hXnPowrvPufjs5fLKAA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/node": {
"version": "17.0.45",
@@ -366,24 +374,26 @@
"dev": true
},
"node_modules/commander": {
"version": "9.5.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz",
"integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==",
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
"integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.20.0 || >=14"
"node": ">=16"
}
},
"node_modules/frida-compile": {
"version": "16.2.1",
"resolved": "https://registry.npmjs.org/frida-compile/-/frida-compile-16.2.1.tgz",
"integrity": "sha512-be/U5h8l0cb0b+fWeZclhfw1s2xER8fPOjnTU4rZF8oh5GkB0BeAEaApwfGrdmeZkVNdUhDLXud7DqEljHRWmA==",
"version": "17.0.0",
"resolved": "https://registry.npmjs.org/frida-compile/-/frida-compile-17.0.0.tgz",
"integrity": "sha512-ixJRj14qLH/Z0ckFWd5fKeDMm0W2+2WDpSGnLRgpn0nuCQAbDHRCqVCWtPnV8uzPJmA6XOX0pujsMpYe9q9RRw==",
"dev": true,
"dependencies": {
"@frida/assert": "^3.0.1",
"@frida/base64-js": "^2.0.3",
"@frida/buffer": "^7.0.4",
"@frida/crosspath": "^3.0.0",
"@frida/crypto": "^1.0.1",
"@frida/diagnostics_channel": "^1.0.0",
"@frida/events": "^4.0.4",
"@frida/http": "^4.0.2",
@@ -406,8 +416,8 @@
"@frida/url": "^1.0.2",
"@frida/util": "^1.0.3",
"@frida/vm": "^2.0.0",
"commander": "^9.4.0",
"frida-fs": "^5.2.3",
"commander": "^11.1.0",
"frida-fs": "^6.0.0",
"typed-emitter": "^2.1.0"
},
"bin": {
@@ -415,10 +425,11 @@
}
},
"node_modules/frida-fs": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/frida-fs/-/frida-fs-5.2.3.tgz",
"integrity": "sha512-jJhtNI86UqDkOtB72XR7Ia9KHudQUxIFIbZadS9kxrDU6Io1jLhoMNp++iW7n7MaDgFQLRR8VgNj9VViGzaydA==",
"dev": true
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/frida-fs/-/frida-fs-6.0.0.tgz",
"integrity": "sha512-I0fnKupZh7fU2ixwCIjJnEqNdhfm/SC1ZYBMy58EmeqOWSbjw1Dpy99mJ7BJdbk2KNXJeaBZGxDYLtn0J9S+UA==",
"dev": true,
"license": "MIT"
},
"node_modules/http-parser-js": {
"version": "0.5.8",
+2 -2
View File
@@ -7,7 +7,7 @@
"build": "frida-compile script-runtime/entrypoint.ts -o script-runtime.js -c"
},
"devDependencies": {
"@types/frida-gum": "^18.3.2",
"frida-compile": "^16.2.1"
"@types/frida-gum": "^19.0.0",
"frida-compile": "^17.0.0"
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
[CCode (gir_namespace = "FridaBarebone", gir_version = "1.0")]
namespace Frida.Barebone {
private class RustModule : Object {
private sealed class RustModule : Object {
public signal void console_output (string message);
public Gee.List<Export> exports {
+16 -2
View File
@@ -278,6 +278,8 @@ Object.defineProperties(Process, {
base: NULL,
size: 0x1000,
path: "/kernel",
ensureInitialized() {
},
enumerateImports() {
return [];
},
@@ -290,11 +292,23 @@ Object.defineProperties(Process, {
enumerateRanges() {
return [];
},
enumerateSections() {
return [];
},
enumerateDependencies() {
return [];
},
findExportByName() {
return null;
},
getExportByName(exportName) {
throw new Error(`unable to find export '${exportName}'`);
getExportByName(name) {
throw new Error(`unable to find export '${name}'`);
},
findSymbolByName() {
return null;
},
getSymbolByName(name) {
throw new Error(`unable to find symbol '${name}'`);
}
}
];
+1 -1
View File
@@ -1,5 +1,5 @@
namespace Frida {
private class BareboneScript : Object {
private sealed class BareboneScript : Object {
public signal void message (string json, Bytes? data);
public AgentScriptId id {
+5 -5
View File
@@ -1,5 +1,5 @@
namespace Frida {
public class Compiler : Object {
public sealed class Compiler : Object {
public signal void starting ();
public signal void finished ();
public signal void output (string bundle);
@@ -199,7 +199,7 @@ namespace Frida {
try {
var device = yield manager.get_device_by_type (LOCAL, 0, io_cancellable);
var session = yield device.get_host_session (io_cancellable);
var agent = new Agent (this, (BaseDBusHostSession) session);
var agent = new Agent (this, (LocalHostSession) session);
load_request.resolve (agent);
} catch (GLib.Error e) {
@@ -238,7 +238,7 @@ namespace Frida {
private Promise<string> source_request = new Promise<string> ();
private Promise<Bytes?> snapshot_request = new Promise<Bytes?> ();
public Agent (Compiler parent, BaseDBusHostSession host_session) {
public Agent (Compiler parent, LocalHostSession host_session) {
Object (
parent: parent,
host_session: host_session,
@@ -465,10 +465,10 @@ namespace Frida {
}
}
public class BuildOptions : CompilerOptions {
public sealed class BuildOptions : CompilerOptions {
}
public class WatchOptions : CompilerOptions {
public sealed class WatchOptions : CompilerOptions {
}
public enum SourceMaps {
+39 -23
View File
@@ -9,15 +9,15 @@
"version": "1.0.0",
"dependencies": {
"@frida/crosspath": "3.0.0",
"frida-compile": "16.4.1",
"frida-fs": "5.2.5"
"frida-compile": "17.0.0",
"frida-fs": "6.0.0"
},
"devDependencies": {
"@frida/rollup-plugin-node-polyfills": "^1.0.3",
"@rollup/plugin-node-resolve": "^14.1.0",
"@rollup/plugin-replace": "^4.0.0",
"@rollup/plugin-typescript": "^8.3.4",
"@types/frida-gum": "18.7.2",
"@types/frida-gum": "19.0.0",
"@types/glob": "^8.0.0",
"@types/node": "18.7.23",
"glob": "^8.0.3",
@@ -252,6 +252,13 @@
"frida-fs": "^5.2.1"
}
},
"node_modules/@frida/rollup-plugin-node-polyfills/node_modules/frida-fs": {
"version": "5.2.5",
"resolved": "https://registry.npmjs.org/frida-fs/-/frida-fs-5.2.5.tgz",
"integrity": "sha512-Eyb4OqUlcv1/Eq7Q+B9IZmYZIgIM2YjqDojrjmAGzPSSXBuUKwSkuObQcQ8Dup9JTOMIUcSII9/I8DaTe6LFKw==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/stream": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@frida/stream/-/stream-1.0.2.tgz",
@@ -468,9 +475,9 @@
"dev": true
},
"node_modules/@types/frida-gum": {
"version": "18.7.2",
"resolved": "https://registry.npmjs.org/@types/frida-gum/-/frida-gum-18.7.2.tgz",
"integrity": "sha512-nOxTk8n45nQlFQhSSXcnePrzjw6k6JMJMESZ8HlHhUiIQqvGI4RYa69FYdUbGoBRnITn8srEq5vn0dkVwO/ezQ==",
"version": "19.0.0",
"resolved": "https://registry.npmjs.org/@types/frida-gum/-/frida-gum-19.0.0.tgz",
"integrity": "sha512-qViK1KwvPEAkajwSUv0wpZvZLiX8xO4JFFCh8dfYZfzSyOEfoE0KliCP/nJSKIKG6N3hXnPowrvPufjs5fLKAA==",
"dev": true,
"license": "MIT"
},
@@ -641,9 +648,9 @@
"dev": true
},
"node_modules/frida-compile": {
"version": "16.4.1",
"resolved": "https://registry.npmjs.org/frida-compile/-/frida-compile-16.4.1.tgz",
"integrity": "sha512-xI9HNtUFpHxuKBGXaL6XJAYH1zWTvNJDrHRnz1hp0oS24iPHt6c01Jmm3qljZek3oQWn8HhvfNvrzfgbsKzoBQ==",
"version": "17.0.0",
"resolved": "https://registry.npmjs.org/frida-compile/-/frida-compile-17.0.0.tgz",
"integrity": "sha512-ixJRj14qLH/Z0ckFWd5fKeDMm0W2+2WDpSGnLRgpn0nuCQAbDHRCqVCWtPnV8uzPJmA6XOX0pujsMpYe9q9RRw==",
"dependencies": {
"@frida/assert": "^3.0.1",
"@frida/base64-js": "^2.0.3",
@@ -673,7 +680,7 @@
"@frida/util": "^1.0.3",
"@frida/vm": "^2.0.0",
"commander": "^11.1.0",
"frida-fs": "^5.2.3",
"frida-fs": "^6.0.0",
"typed-emitter": "^2.1.0"
},
"bin": {
@@ -681,9 +688,10 @@
}
},
"node_modules/frida-fs": {
"version": "5.2.5",
"resolved": "https://registry.npmjs.org/frida-fs/-/frida-fs-5.2.5.tgz",
"integrity": "sha512-Eyb4OqUlcv1/Eq7Q+B9IZmYZIgIM2YjqDojrjmAGzPSSXBuUKwSkuObQcQ8Dup9JTOMIUcSII9/I8DaTe6LFKw=="
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/frida-fs/-/frida-fs-6.0.0.tgz",
"integrity": "sha512-I0fnKupZh7fU2ixwCIjJnEqNdhfm/SC1ZYBMy58EmeqOWSbjw1Dpy99mJ7BJdbk2KNXJeaBZGxDYLtn0J9S+UA==",
"license": "MIT"
},
"node_modules/fs.realpath": {
"version": "1.0.0",
@@ -1290,6 +1298,14 @@
"@frida/vm": "^2.0.0",
"@rollup/plugin-inject": "^4.0.4",
"frida-fs": "^5.2.1"
},
"dependencies": {
"frida-fs": {
"version": "5.2.5",
"resolved": "https://registry.npmjs.org/frida-fs/-/frida-fs-5.2.5.tgz",
"integrity": "sha512-Eyb4OqUlcv1/Eq7Q+B9IZmYZIgIM2YjqDojrjmAGzPSSXBuUKwSkuObQcQ8Dup9JTOMIUcSII9/I8DaTe6LFKw==",
"dev": true
}
}
},
"@frida/stream": {
@@ -1466,9 +1482,9 @@
"dev": true
},
"@types/frida-gum": {
"version": "18.7.2",
"resolved": "https://registry.npmjs.org/@types/frida-gum/-/frida-gum-18.7.2.tgz",
"integrity": "sha512-nOxTk8n45nQlFQhSSXcnePrzjw6k6JMJMESZ8HlHhUiIQqvGI4RYa69FYdUbGoBRnITn8srEq5vn0dkVwO/ezQ==",
"version": "19.0.0",
"resolved": "https://registry.npmjs.org/@types/frida-gum/-/frida-gum-19.0.0.tgz",
"integrity": "sha512-qViK1KwvPEAkajwSUv0wpZvZLiX8xO4JFFCh8dfYZfzSyOEfoE0KliCP/nJSKIKG6N3hXnPowrvPufjs5fLKAA==",
"dev": true
},
"@types/glob": {
@@ -1597,9 +1613,9 @@
"dev": true
},
"frida-compile": {
"version": "16.4.1",
"resolved": "https://registry.npmjs.org/frida-compile/-/frida-compile-16.4.1.tgz",
"integrity": "sha512-xI9HNtUFpHxuKBGXaL6XJAYH1zWTvNJDrHRnz1hp0oS24iPHt6c01Jmm3qljZek3oQWn8HhvfNvrzfgbsKzoBQ==",
"version": "17.0.0",
"resolved": "https://registry.npmjs.org/frida-compile/-/frida-compile-17.0.0.tgz",
"integrity": "sha512-ixJRj14qLH/Z0ckFWd5fKeDMm0W2+2WDpSGnLRgpn0nuCQAbDHRCqVCWtPnV8uzPJmA6XOX0pujsMpYe9q9RRw==",
"requires": {
"@frida/assert": "^3.0.1",
"@frida/base64-js": "^2.0.3",
@@ -1629,14 +1645,14 @@
"@frida/util": "^1.0.3",
"@frida/vm": "^2.0.0",
"commander": "^11.1.0",
"frida-fs": "^5.2.3",
"frida-fs": "^6.0.0",
"typed-emitter": "^2.1.0"
}
},
"frida-fs": {
"version": "5.2.5",
"resolved": "https://registry.npmjs.org/frida-fs/-/frida-fs-5.2.5.tgz",
"integrity": "sha512-Eyb4OqUlcv1/Eq7Q+B9IZmYZIgIM2YjqDojrjmAGzPSSXBuUKwSkuObQcQ8Dup9JTOMIUcSII9/I8DaTe6LFKw=="
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/frida-fs/-/frida-fs-6.0.0.tgz",
"integrity": "sha512-I0fnKupZh7fU2ixwCIjJnEqNdhfm/SC1ZYBMy58EmeqOWSbjw1Dpy99mJ7BJdbk2KNXJeaBZGxDYLtn0J9S+UA=="
},
"fs.realpath": {
"version": "1.0.0",
+3 -3
View File
@@ -9,15 +9,15 @@
},
"dependencies": {
"@frida/crosspath": "3.0.0",
"frida-compile": "16.4.1",
"frida-fs": "5.2.5"
"frida-compile": "17.0.0",
"frida-fs": "6.0.0"
},
"devDependencies": {
"@frida/rollup-plugin-node-polyfills": "^1.0.3",
"@rollup/plugin-node-resolve": "^14.1.0",
"@rollup/plugin-replace": "^4.0.0",
"@rollup/plugin-typescript": "^8.3.4",
"@types/frida-gum": "18.7.2",
"@types/frida-gum": "19.0.0",
"@types/glob": "^8.0.0",
"@types/node": "18.7.23",
"glob": "^8.0.3",
+237 -143
View File
@@ -1,6 +1,5 @@
namespace Frida {
#if HAVE_LOCAL_BACKEND
public class ControlService : Object {
public sealed class ControlService : Object {
public EndpointParameters endpoint_params {
get;
construct;
@@ -12,6 +11,7 @@ namespace Frida {
}
private HostSession host_session;
private HostSessionProvider provider;
private State state = STOPPED;
@@ -21,8 +21,12 @@ namespace Frida {
private Gee.Set<ControlChannel> spawn_gaters = new Gee.HashSet<ControlChannel> ();
private Gee.Map<uint, PendingSpawn> pending_spawn = new Gee.HashMap<uint, PendingSpawn> ();
private Gee.Map<AgentSessionId?, AgentSessionEntry> sessions =
private Gee.Map<AgentSessionId?, AgentSessionEntry> agent_sessions =
new Gee.HashMap<AgentSessionId?, AgentSessionEntry> (AgentSessionId.hash, AgentSessionId.equal);
private Gee.Map<ChannelId?, ChannelEntry> channels =
new Gee.HashMap<ChannelId?, ChannelEntry> (ChannelId.hash, ChannelId.equal);
private Gee.Map<ServiceSessionId?, ServiceSessionEntry> service_sessions =
new Gee.HashMap<ServiceSessionId?, ServiceSessionEntry> (ServiceSessionId.hash, ServiceSessionId.equal);
private Cancellable io_cancellable = new Cancellable ();
@@ -35,7 +39,8 @@ namespace Frida {
STOPPING
}
public ControlService (EndpointParameters endpoint_params, ControlServiceOptions? options = null) {
public ControlService (EndpointParameters endpoint_params, ControlServiceOptions? options = null) throws Error {
#if HAVE_LOCAL_BACKEND
ControlServiceOptions opts = (options != null) ? options : new ControlServiceOptions ();
HostSession session;
@@ -63,17 +68,24 @@ namespace Frida {
options: opts
);
assign_session (session);
assign_session (session, new PrecreatedLocalHostSessionProvider ((LocalHostSession) session));
#else
throw new Error.NOT_SUPPORTED ("Local backend not available");
#endif
}
internal ControlService.with_host_session (HostSession host_session, EndpointParameters endpoint_params,
ControlServiceOptions? options = null) {
public async ControlService.with_device (Device device, EndpointParameters endpoint_params,
ControlServiceOptions? options = null, Cancellable? cancellable = null) throws Error, IOError {
ControlServiceOptions opts = (options != null) ? options : new ControlServiceOptions ();
var session = yield device.get_host_session (cancellable);
Object (
endpoint_params: endpoint_params,
options: (options != null) ? options : new ControlServiceOptions ()
options: opts
);
assign_session (host_session);
assign_session (session, device.provider);
}
construct {
@@ -85,7 +97,7 @@ namespace Frida {
main_handler = new ConnectionHandler (this, null);
}
private void assign_session (HostSession session) {
private void assign_session (HostSession session, HostSessionProvider provider) {
host_session = session;
host_session.spawn_added.connect (notify_spawn_added);
host_session.child_added.connect (notify_child_added);
@@ -93,7 +105,11 @@ namespace Frida {
host_session.process_crashed.connect (notify_process_crashed);
host_session.output.connect (notify_output);
host_session.agent_session_detached.connect (on_agent_session_detached);
host_session.channel_closed.connect (on_channel_closed);
host_session.service_session_closed.connect (on_service_session_closed);
host_session.uninjected.connect (notify_uninjected);
this.provider = provider;
}
public async void start (Cancellable? cancellable = null) throws Error, IOError {
@@ -109,7 +125,7 @@ namespace Frida {
yield service.start (cancellable);
if (options.enable_preload) {
var base_host_session = host_session as BaseDBusHostSession;
var base_host_session = host_session as LocalHostSession;
if (base_host_session != null)
base_host_session.preload.begin (io_cancellable);
}
@@ -148,9 +164,8 @@ namespace Frida {
yield main_handler.close (cancellable);
var base_host_session = host_session as BaseDBusHostSession;
if (base_host_session != null)
yield base_host_session.close (cancellable);
if (provider is PrecreatedLocalHostSessionProvider)
yield provider.destroy (host_session, cancellable);
state = STOPPED;
}
@@ -212,17 +227,15 @@ namespace Frida {
}
private async void teardown_control_channel (ControlChannel channel) {
foreach (AgentSessionId id in channel.sessions) {
AgentSessionEntry entry = sessions[id];
foreach (AgentSessionId id in channel.agent_sessions) {
AgentSessionEntry entry = agent_sessions[id];
var base_host_session = host_session as BaseDBusHostSession;
if (base_host_session != null)
base_host_session.unlink_agent_session (id);
provider.unlink_agent_session (host_session, id);
AgentSession? session = entry.session;
if (entry.persist_timeout == 0 || session == null) {
sessions.unset (id);
agent_sessions.unset (id);
if (session != null)
session.close.begin (io_cancellable);
} else {
@@ -231,6 +244,24 @@ namespace Frida {
}
}
foreach (ChannelId id in channel.channels.to_array ()) {
ChannelEntry entry = channels[id];
provider.unlink_channel (host_session, id);
channels.unset (id);
Channel? ch = entry.channel;
if (ch != null)
ch.close.begin (null);
}
foreach (ServiceSessionId id in channel.service_sessions.to_array ()) {
provider.unlink_service_session (host_session, id);
service_sessions.unset (id);
}
try {
yield disable_spawn_gating (channel);
} catch (GLib.Error e) {
@@ -365,12 +396,22 @@ namespace Frida {
yield parent.reattach (id, requester, cancellable);
}
public async ChannelId open_channel (string address, ControlChannel requester, Cancellable? cancellable)
throws Error, IOError {
return yield parent.open_channel (address, requester, cancellable);
}
public async ServiceSessionId open_service (string address, ControlChannel requester, Cancellable? cancellable)
throws Error, IOError {
return yield parent.open_service (address, requester, cancellable);
}
public void open_tcp_transport (AgentSessionId id, Cancellable? cancellable, out uint16 port, out string token)
throws Error {
#if WINDOWS
throw new Error.NOT_SUPPORTED ("Not yet supported on Windows");
#else
var base_host_session = host_session as BaseDBusHostSession;
var base_host_session = host_session as LocalHostSession;
if (base_host_session == null)
throw new Error.NOT_SUPPORTED ("Not supported for remote host sessions");
if (!base_host_session.can_pass_file_descriptors_to_agent_session (id))
@@ -440,7 +481,7 @@ namespace Frida {
#if !WINDOWS
AgentSessionId session_id = transport.session_id;
var base_host_session = host_session as BaseDBusHostSession;
var base_host_session = host_session as LocalHostSession;
if (base_host_session == null)
throw new Error.NOT_SUPPORTED ("Not supported for remote host sessions");
@@ -523,12 +564,12 @@ namespace Frida {
throw_dbus_error (e);
}
requester.sessions.add (id);
requester.agent_sessions.add (id);
var opts = SessionOptions._deserialize (options);
var entry = new AgentSessionEntry (requester, id, opts.persist_timeout, io_cancellable);
sessions[id] = entry;
var entry = new AgentSessionEntry (requester, id, opts.persist_timeout);
agent_sessions[id] = entry;
entry.expired.connect (on_agent_session_expired);
yield link_session (id, entry, requester, cancellable);
@@ -537,11 +578,11 @@ namespace Frida {
}
private async void reattach (AgentSessionId id, ControlChannel requester, Cancellable? cancellable) throws Error, IOError {
AgentSessionEntry? entry = sessions[id];
AgentSessionEntry? entry = agent_sessions[id];
if (entry == null || entry.controller != null)
throw new Error.INVALID_OPERATION ("Invalid session ID");
requester.sessions.add (id);
requester.agent_sessions.add (id);
entry.attach_controller (requester);
@@ -560,28 +601,7 @@ namespace Frida {
throw_dbus_error (e);
}
AgentSession session;
var base_host_session = host_session as BaseDBusHostSession;
if (base_host_session != null) {
session = yield base_host_session.link_agent_session (id, sink, cancellable);
} else {
DBusConnection internal_connection = ((DBusProxy) host_session).g_connection;
try {
session = yield internal_connection.get_proxy (null, ObjectPath.for_agent_session (id),
DO_NOT_LOAD_PROPERTIES, cancellable);
} catch (IOError e) {
throw_dbus_error (e);
}
entry.internal_connection = internal_connection;
try {
entry.take_internal_registration (
internal_connection.register_object (ObjectPath.for_agent_message_sink (id), sink));
} catch (IOError e) {
assert_not_reached ();
}
}
var session = yield provider.link_agent_session (host_session, id, sink, cancellable);
entry.session = session;
try {
@@ -592,6 +612,52 @@ namespace Frida {
}
}
private async ChannelId open_channel (string address, ControlChannel requester, Cancellable? cancellable)
throws Error, IOError {
ChannelId id;
try {
id = yield host_session.open_channel (address, cancellable);
} catch (GLib.Error e) {
throw_dbus_error (e);
}
requester.channels.add (id);
var entry = new ChannelEntry (requester, id);
channels[id] = entry;
var stream = yield provider.link_channel (host_session, id, cancellable);
Channel channel = new ChannelEndpoint (stream);
entry.channel = channel;
entry.take_controller_registration (requester.connection.register_object (ObjectPath.for_channel (id), channel));
return id;
}
private async ServiceSessionId open_service (string address, ControlChannel requester, Cancellable? cancellable)
throws Error, IOError {
ServiceSessionId id;
try {
id = yield host_session.open_service (address, cancellable);
} catch (GLib.Error e) {
throw_dbus_error (e);
}
requester.service_sessions.add (id);
var entry = new ServiceSessionEntry (requester, id);
service_sessions[id] = entry;
var session = yield provider.link_service_session (host_session, id, cancellable);
entry.session = session;
entry.take_controller_registration (
requester.connection.register_object (ObjectPath.for_service_session (id), session));
return id;
}
private void notify_spawn_added (HostSpawnInfo info) {
foreach (ControlChannel channel in spawn_gaters)
channel.spawn_added (info);
@@ -632,15 +698,33 @@ namespace Frida {
private void on_agent_session_detached (AgentSessionId id, SessionDetachReason reason, CrashInfo crash) {
AgentSessionEntry entry;
if (sessions.unset (id, out entry)) {
if (agent_sessions.unset (id, out entry)) {
ControlChannel? controller = entry.controller;
if (controller != null) {
controller.sessions.remove (id);
controller.agent_sessions.remove (id);
controller.agent_session_detached (id, reason, crash);
}
}
}
private void on_channel_closed (ChannelId id) {
ChannelEntry entry;
if (channels.unset (id, out entry)) {
ControlChannel controller = entry.controller;
controller.channels.remove (id);
controller.channel_closed (id);
}
}
private void on_service_session_closed (ServiceSessionId id) {
ServiceSessionEntry entry;
if (service_sessions.unset (id, out entry)) {
ControlChannel controller = entry.controller;
controller.service_sessions.remove (id);
controller.service_session_closed (id);
}
}
private void notify_uninjected (InjectorPayloadId id) {
all_control_channels ().foreach (channel => {
channel.uninjected (id);
@@ -649,7 +733,7 @@ namespace Frida {
}
private void on_agent_session_expired (AgentSessionEntry entry) {
sessions.unset (entry.id);
agent_sessions.unset (entry.id);
}
private interface Peer : Object {
@@ -724,11 +808,21 @@ namespace Frida {
construct;
}
public Gee.Set<AgentSessionId?> sessions {
public Gee.Set<AgentSessionId?> agent_sessions {
get;
default = new Gee.HashSet<AgentSessionId?> (AgentSessionId.hash, AgentSessionId.equal);
}
public Gee.Set<ChannelId?> channels {
get;
default = new Gee.HashSet<ChannelId?> (ChannelId.hash, ChannelId.equal);
}
public Gee.Set<ServiceSessionId?> service_sessions {
get;
default = new Gee.HashSet<ServiceSessionId?> (ServiceSessionId.hash, ServiceSessionId.equal);
}
private Gee.Set<uint> registrations = new Gee.HashSet<uint> ();
private TimeoutSource? ping_timer;
@@ -853,6 +947,14 @@ namespace Frida {
return yield parent.host_session.inject_library_blob (pid, blob, entrypoint, data, cancellable);
}
public async ChannelId open_channel (string address, Cancellable? cancellable) throws GLib.Error {
return yield parent.open_channel (address, this, cancellable);
}
public async ServiceSessionId open_service (string address, Cancellable? cancellable) throws GLib.Error {
return yield parent.open_service (address, this, cancellable);
}
private async void open_tcp_transport (AgentSessionId id, Cancellable? cancellable, out uint16 port,
out string token) throws Error {
parent.open_tcp_transport (id, cancellable, out port, out token);
@@ -876,14 +978,45 @@ namespace Frida {
}
}
private class AgentSessionEntry {
public signal void expired ();
private abstract class Entry {
public ControlChannel? controller {
get;
private set;
get {
return _controller;
}
protected set {
unregister_all ();
_controller = value;
}
}
private ControlChannel? _controller;
private Gee.Collection<uint> registrations = new Gee.ArrayList<uint> ();
protected Entry (ControlChannel? controller) {
this.controller = controller;
}
~Entry () {
unregister_all ();
}
public void take_controller_registration (uint id) {
registrations.add (id);
}
private void unregister_all () {
if (_controller == null)
return;
var connection = _controller.connection;
foreach (uint id in registrations)
connection.unregister_object (id);
registrations.clear ();
}
}
private class AgentSessionEntry : Entry {
public signal void expired ();
public AgentSessionId id {
get;
private set;
@@ -899,36 +1032,20 @@ namespace Frida {
private set;
}
public DBusConnection? internal_connection {
get;
set;
}
public Cancellable io_cancellable {
get;
private set;
}
private Gee.Collection<uint> internal_registrations = new Gee.ArrayList<uint> ();
private Gee.Collection<uint> controller_registrations = new Gee.ArrayList<uint> ();
private TimeoutSource? expiry_timer;
public AgentSessionEntry (ControlChannel controller, AgentSessionId id, uint persist_timeout,
Cancellable io_cancellable) {
this.controller = controller;
public AgentSessionEntry (ControlChannel? controller, AgentSessionId id, uint persist_timeout) {
base (controller);
this.id = id;
this.persist_timeout = persist_timeout;
this.io_cancellable = io_cancellable;
}
~AgentSessionEntry () {
stop_expiry_timer ();
unregister_all ();
}
public void detach_controller () {
unregister_all ();
controller = null;
session = null;
@@ -942,27 +1059,6 @@ namespace Frida {
controller = c;
}
public void take_internal_registration (uint id) {
internal_registrations.add (id);
}
public void take_controller_registration (uint id) {
controller_registrations.add (id);
}
private void unregister_all () {
if (controller != null)
unregister_all_in (controller_registrations, controller.connection);
if (internal_connection != null)
unregister_all_in (internal_registrations, internal_connection);
}
private void unregister_all_in (Gee.Collection<uint> ids, DBusConnection connection) {
foreach (uint id in ids)
connection.unregister_object (id);
ids.clear ();
}
private void start_expiry_timer () {
if (expiry_timer != null)
return;
@@ -981,57 +1077,55 @@ namespace Frida {
expiry_timer = null;
}
}
}
#else
public class ControlService : Object {
public ControlService (EndpointParameters endpoint_params, ControlServiceOptions? options = null) {
}
public ControlService.with_host_session (HostSession host_session, EndpointParameters endpoint_params,
ControlServiceOptions? options = null) {
}
public async void start (Cancellable? cancellable = null) throws Error, IOError {
throw new Error.NOT_SUPPORTED ("Local backend not available");
}
public void start_sync (Cancellable? cancellable = null) throws Error, IOError {
create<StartTask> ().execute (cancellable);
}
private class StartTask : ControlServiceTask<void> {
protected override async void perform_operation () throws Error, IOError {
yield parent.start (cancellable);
}
}
public async void stop (Cancellable? cancellable = null) throws Error, IOError {
}
public void stop_sync (Cancellable? cancellable = null) throws Error, IOError {
create<StopTask> ().execute (cancellable);
}
private class StopTask : ControlServiceTask<void> {
protected override async void perform_operation () throws Error, IOError {
yield parent.stop (cancellable);
}
}
private T create<T> () {
return Object.new (typeof (T), parent: this);
}
private abstract class ControlServiceTask<T> : AsyncTask<T> {
public weak ControlService parent {
private class ChannelEntry : Entry {
public ChannelId id {
get;
construct;
private set;
}
public Channel? channel {
get;
set;
}
public ChannelEntry (ControlChannel controller, ChannelId id) {
base (controller);
this.id = id;
}
}
private class ServiceSessionEntry : Entry {
public ServiceSessionId id {
get;
private set;
}
public ServiceSession? session {
get;
set;
}
public ServiceSessionEntry (ControlChannel controller, ServiceSessionId id) {
base (controller);
this.id = id;
}
}
}
#endif
public class ControlServiceOptions : Object {
private sealed class PrecreatedLocalHostSessionProvider : LocalHostSessionProvider {
public PrecreatedLocalHostSessionProvider (LocalHostSession session) {
take_host_session (session);
}
protected override LocalHostSession make_host_session (HostSessionOptions? options) throws Error {
throw new Error.NOT_SUPPORTED ("Not supported");
}
}
public sealed class ControlServiceOptions : Object {
public string? sysroot {
get;
set;
+3 -3
View File
@@ -21,7 +21,7 @@ const substratePidsPending = new Map();
rpc.exports = {
dispose() {
if (suspendedPids.size > 0) {
const kill = new NativeFunction(Module.getExportByName(null, 'kill'), 'int', ['int', 'int']);
const kill = new NativeFunction(Module.getGlobalExportByName('kill'), 'int', ['int', 'int']);
for (const pid of suspendedPids) {
kill(pid, SIGKILL);
}
@@ -49,7 +49,7 @@ rpc.exports = {
applyJailbreakQuirks();
Interceptor.attach(Module.getExportByName('/usr/lib/system/libsystem_kernel.dylib', '__posix_spawn'), {
Interceptor.attach(Process.getModuleByName('/usr/lib/system/libsystem_kernel.dylib').getExportByName('__posix_spawn'), {
onEnter(args) {
const env = parseStringv(args[4]);
const prewarm = isPrewarmLaunch(env);
@@ -238,7 +238,7 @@ function instrumentInserter(at) {
}
function findJbdCallImpl() {
const impl = Module.findExportByName(null, 'jbd_call');
const impl = Module.findGlobalExportByName('jbd_call');
if (impl !== null)
return impl;
@@ -1,3 +1,5 @@
import ObjC from 'frida-objc-bridge';
const YES = ptr(1);
const {
@@ -53,7 +55,8 @@ function tryInitialize() {
}
if (!tryInitialize()) {
const listener = Interceptor.attach(Module.getExportByName('/usr/lib/system/libsystem_trace.dylib', 'os_log_type_enabled'), () => {
const listener = Interceptor.attach(
Process.getModuleByName('/usr/lib/system/libsystem_trace.dylib').getExportByName('os_log_type_enabled'), () => {
tryInitialize();
listener.detach();
});
+18
View File
@@ -0,0 +1,18 @@
osanalytics_js = custom_target('osanalytics.js',
input: [
'package.json',
'package-lock.json',
'index.js',
],
output: [
'osanalytics.js',
],
command: [
python,
compile_js_agent,
'@OUTPUT@',
'@PRIVATE_DIR@',
npm,
'@INPUT@',
],
)
+553
View File
@@ -0,0 +1,553 @@
{
"name": "frida-osanalytics-agent",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "frida-osanalytics-agent",
"version": "1.0.0",
"dependencies": {
"frida-objc-bridge": "^8.0.4"
},
"devDependencies": {
"@types/frida-gum": "^19.0.0",
"frida-compile": "^17.0.0"
}
},
"node_modules/@frida/assert": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@frida/assert/-/assert-3.0.2.tgz",
"integrity": "sha512-JXJq5SbXGrM5EkjrZKfRmB29zOoEOix02NC6A5TSJ+C1GE/X051EinJJsuOO2pEOx7KZwpvAHvS0WXW0+levKg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/base64-js": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@frida/base64-js/-/base64-js-2.0.3.tgz",
"integrity": "sha512-2w0F+1TynOTCZ/v7du9LdHPWwq0lJhazjo2fF9upMyQmA1zHetT14fLuQ1v/6T0qPgyeEGkiSrybstU8EsgeUA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/@frida/buffer": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/@frida/buffer/-/buffer-7.0.4.tgz",
"integrity": "sha512-RxQ1lZRRiCJj7nhcCiD8xeJx0NsLpGGnjqsmTg7jShGmbnVFMN5W7+J+3gqdPSQhc/IxNBIWc6zRXVp4+qnYHg==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT",
"dependencies": {
"base64-js": "^1.5.1",
"ieee754": "^1.2.1"
}
},
"node_modules/@frida/crosspath": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@frida/crosspath/-/crosspath-3.0.0.tgz",
"integrity": "sha512-bNdO1spIPD2P40XtK89N49oZpJhstdlnkJZcD4yJ17jrdkm9Ctu0sd9MIEX6Z8Tm8ydhVJBAOMEKl9/R27onAQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "^17.0.36"
},
"engines": {
"node": ">=14.9.0"
}
},
"node_modules/@frida/crypto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@frida/crypto/-/crypto-1.0.1.tgz",
"integrity": "sha512-WXTkVjESvX8TIVXIynJJv9BKSIdQP0Iis04StIXknkDi1ULdMlrypA9p5C4KW1H6GCkNsVnKbybpzsulYCTvag==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/diagnostics_channel": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/diagnostics_channel/-/diagnostics_channel-1.0.0.tgz",
"integrity": "sha512-mYX1jp/5Bpk24tHArJNx65iCk7qSuV8YJkdU0gFNVtJUXxfV8BG5WuPa4mL+ynxsbWWpsg/cwKZbLAepYKTdQQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/events": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/@frida/events/-/events-4.0.4.tgz",
"integrity": "sha512-qJVQ6VWHf9sjUKuiJzoCAC00frbpcwxeYfvQ+PP9LU/d70j+QvjWgYe98Qa3ekLaBU6r/AvWm8ThKCDUCLWrQQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.8.x"
}
},
"node_modules/@frida/http": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@frida/http/-/http-4.0.2.tgz",
"integrity": "sha512-cvkc7ex7GmVXVOWqtjXKBWUUbYEBgpNRKZbEEoMeI8KiIs8zejKwg+N7rx7296Ao+EP3+xcUr4wBVr3xLaUVfQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"http-parser-js": "^0.5.3"
}
},
"node_modules/@frida/http-parser-js": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/http-parser-js/-/http-parser-js-1.0.0.tgz",
"integrity": "sha512-2nMrNXt/OeTlWbqnE8AH4Sfz4I2+BGoN206dzKEyC/g2svtn83Xu+zuv/V3TkwrA27s26Mcy84ZwsXeNlqNxUQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/https": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/https/-/https-1.0.0.tgz",
"integrity": "sha512-OiqQ6qsALcWOktRLq07oJ0i6sH8eX6MXb/MdZS1qVKDRf6wchH4Pjn6fiLB+pt/OlYbggk+DOfpHwSdjTwuHMQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/ieee754": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@frida/ieee754/-/ieee754-2.0.2.tgz",
"integrity": "sha512-wlcUebnne4ENN7GDr5pTH598ZDLMVOsh0FjenxeVOe6u7ewZkz9gGRnLnZKJAm9kl5G6XhdxhI0cSXVQK/rQUw==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "BSD-3-Clause"
},
"node_modules/@frida/net": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@frida/net/-/net-4.0.2.tgz",
"integrity": "sha512-qQRe7hQ+ZfCcG/SE3P1TRqQ9bmuK/T7wPCYaT4z56rBPWAxsaQbQHpX4fR6OrFaSDr7X0xJLsTbdIp9hGhhLZg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/os": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@frida/os/-/os-1.0.2.tgz",
"integrity": "sha512-3ISAiGNiyIya3QN2EHBCz1wqP0enTdSxP99wUeroeh8+AQRmgoOr/5TRnrVry8pe378anay3fmV/tdUMMSkehQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/path": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@frida/path/-/path-2.0.3.tgz",
"integrity": "sha512-2RQy36QatoC846fzBhBhV8sXMsSOBGoYvwTHeaE1zUdz7F4RNScP4QEekTTooBYWYX/XjiF36KQpYAzc9OYFtg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/process": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@frida/process/-/process-1.2.1.tgz",
"integrity": "sha512-nvCu22DstFW2ttGFtOKekHM7vnjbZm+XgtvavOt427GNT6uV7k0JYK9tnMbcLMRWv57DG6udAmuJlWs8Paq1ag==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/punycode": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@frida/punycode/-/punycode-3.0.0.tgz",
"integrity": "sha512-XVSDY2KamDs1D5/fTVgHcOSNxdU4kTboxzqJMBbTjcQC7XScIT9c0EfbwKCq7Kci6gWQdsHSCr7lU+9Oc4KAdg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/querystring": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/querystring/-/querystring-1.0.0.tgz",
"integrity": "sha512-15m1fOZPmoO/vWlgPJrG/J9/BJDz6a2/JpVGpS8ynNzo+fBhTznaStX5nHxUs24mVTqh/OqLo0EiYJM5WWHXxg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/readable-stream": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/@frida/readable-stream/-/readable-stream-4.1.3.tgz",
"integrity": "sha512-ntGUFmi+CryRGRJIK13a/VST2Ad19uivbln8Xd92vKPAARq+6vMIASDyZIqyl5BLRccfiyCHdYgrgQ6RI5rUig==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/reserved-words": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/reserved-words/-/reserved-words-1.0.0.tgz",
"integrity": "sha512-2yG/XxJlsGlk/mm6eZTb4OAaQEhkTI2qaFfZFtAsrA/XuCpuMWkS4y/guyBlsRu4hAuhK2HPmNM8+OLLK1zM9Q==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/stream": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@frida/stream/-/stream-1.0.2.tgz",
"integrity": "sha512-4OuaC1ztmEKgTq3WeBhsy8Oq+AwW9n9cYnvLklcC9jwD93AEwgbWpecLlxJCVuALvTMdhKPg0nQVfyGYP/i9Bw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@frida/readable-stream": "^4.1.3"
}
},
"node_modules/@frida/string_decoder": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@frida/string_decoder/-/string_decoder-2.0.0.tgz",
"integrity": "sha512-in371tYZMHQiW9HF5MS3JDw6Ao6tyBoq34UWy2rzOswYyMG1rpizh85ofi/yVkxDiaqybEZefxzkVittpPGT6g==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/terser": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/terser/-/terser-1.0.0.tgz",
"integrity": "sha512-59h9WuNzD1Rx/zwoWqQ/FW/4Y/Q3R91Eng2hEwdHapqiTDvtKbZ08F6CynCR7ZVinrh4tLYsF46AtVPTz1ys9g==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"@jridgewell/source-map": "^0.3.2",
"acorn": "^8.5.0",
"commander": "^2.20.0",
"source-map-support": "~0.5.20"
},
"bin": {
"terser": "bin/terser"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@frida/terser/node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/timers": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@frida/timers/-/timers-3.0.0.tgz",
"integrity": "sha512-3b+0igv10aT8TMxefrTAd06rActqbxJLY2Xkkq9vYcPBffB/yHszl0NYIp/5ko8WC3ecDYPU6bQiY6fjs72zTA==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/tty": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/tty/-/tty-1.0.0.tgz",
"integrity": "sha512-p/kjLnKYxEAB1MdYP8+5rKv9CsHzyA+0jg9BcGETzjQVKHHcroHDULRxDYUh+DC7qs6cpX8QdDQh9E+a6ydgsQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/url": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@frida/url/-/url-1.0.2.tgz",
"integrity": "sha512-ZKunbKJHMr8w2Eb/5K1avy0MzK1B998S17wYXNv3RmzBGxMm8S5T0F3qEpRxkU7/72P8m4izyQU87fWl+FjQsQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@frida/punycode": "^3.0.0",
"@frida/querystring": "^1.0.0"
}
},
"node_modules/@frida/util": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@frida/util/-/util-1.0.3.tgz",
"integrity": "sha512-htcG3uDiRXv89ERVNNYhfase39kJ2X75ZARfrYcYEtJLFEsSk0nemM1YnEIR4CjrHvdvkWHrwgKkS+acOyoNEg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/vm": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@frida/vm/-/vm-2.0.0.tgz",
"integrity": "sha512-7fsjLWscZT5odNIBtg6qbLNI+vAk1xmii6H5W2kaYkMYt0vRohQEcDSUWacA+eaWlu5SvMjZI82Yibj/3G9pJw==",
"dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.8",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
"integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/set-array": "^1.2.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/trace-mapping": "^0.3.24"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/set-array": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/source-map": {
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
"integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.25",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@types/frida-gum": {
"version": "19.0.0",
"resolved": "https://registry.npmjs.org/@types/frida-gum/-/frida-gum-19.0.0.tgz",
"integrity": "sha512-qViK1KwvPEAkajwSUv0wpZvZLiX8xO4JFFCh8dfYZfzSyOEfoE0KliCP/nJSKIKG6N3hXnPowrvPufjs5fLKAA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/node": {
"version": "17.0.45",
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz",
"integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==",
"dev": true,
"license": "MIT"
},
"node_modules/acorn": {
"version": "8.14.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
"dev": true,
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true,
"license": "MIT"
},
"node_modules/commander": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
"integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=16"
}
},
"node_modules/frida-compile": {
"version": "17.0.0",
"resolved": "https://registry.npmjs.org/frida-compile/-/frida-compile-17.0.0.tgz",
"integrity": "sha512-ixJRj14qLH/Z0ckFWd5fKeDMm0W2+2WDpSGnLRgpn0nuCQAbDHRCqVCWtPnV8uzPJmA6XOX0pujsMpYe9q9RRw==",
"dev": true,
"dependencies": {
"@frida/assert": "^3.0.1",
"@frida/base64-js": "^2.0.3",
"@frida/buffer": "^7.0.4",
"@frida/crosspath": "^3.0.0",
"@frida/crypto": "^1.0.1",
"@frida/diagnostics_channel": "^1.0.0",
"@frida/events": "^4.0.4",
"@frida/http": "^4.0.2",
"@frida/http-parser-js": "^1.0.0",
"@frida/https": "^1.0.0",
"@frida/ieee754": "^2.0.2",
"@frida/net": "^4.0.1",
"@frida/os": "^1.0.0",
"@frida/path": "^2.0.3",
"@frida/process": "^1.2.1",
"@frida/punycode": "^3.0.0",
"@frida/querystring": "^1.0.0",
"@frida/readable-stream": "^4.1.3",
"@frida/reserved-words": "^1.0.0",
"@frida/stream": "^1.0.2",
"@frida/string_decoder": "^2.0.0",
"@frida/terser": "^1.0.0",
"@frida/timers": "^3.0.0",
"@frida/tty": "^1.0.0",
"@frida/url": "^1.0.2",
"@frida/util": "^1.0.3",
"@frida/vm": "^2.0.0",
"commander": "^11.1.0",
"frida-fs": "^6.0.0",
"typed-emitter": "^2.1.0"
},
"bin": {
"frida-compile": "dist/cli.js"
}
},
"node_modules/frida-fs": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/frida-fs/-/frida-fs-6.0.0.tgz",
"integrity": "sha512-I0fnKupZh7fU2ixwCIjJnEqNdhfm/SC1ZYBMy58EmeqOWSbjw1Dpy99mJ7BJdbk2KNXJeaBZGxDYLtn0J9S+UA==",
"dev": true,
"license": "MIT"
},
"node_modules/frida-objc-bridge": {
"version": "8.0.4",
"resolved": "https://registry.npmjs.org/frida-objc-bridge/-/frida-objc-bridge-8.0.4.tgz",
"integrity": "sha512-AUzwq/+TFtblQLTI97UPX22pBcvyG2oUde9380DXbcJ0zXts4n9JDVONHUr03aBowa0Le+bdBoVdCs7jyyjvlg==",
"license": "LGPL-2.0 WITH WxWindows-exception-3.1"
},
"node_modules/http-parser-js": {
"version": "0.5.10",
"resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz",
"integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==",
"dev": true,
"license": "MIT"
},
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "BSD-3-Clause"
},
"node_modules/rxjs": {
"version": "7.8.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
"dev": true,
"license": "Apache-2.0",
"optional": true,
"dependencies": {
"tslib": "^2.1.0"
}
},
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dev": true,
"license": "MIT",
"dependencies": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"dev": true,
"license": "0BSD",
"optional": true
},
"node_modules/typed-emitter": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-2.1.0.tgz",
"integrity": "sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==",
"dev": true,
"license": "MIT",
"optionalDependencies": {
"rxjs": "*"
}
}
}
}
+16
View File
@@ -0,0 +1,16 @@
{
"name": "frida-osanalytics-agent",
"version": "1.0.0",
"description": "Agent used by Frida's Darwin backend on iOS/iPadOS/tvOS",
"scripts": {
"prepare": "npm run build",
"build": "frida-compile index.js -o osanalytics.js -S -c"
},
"devDependencies": {
"@types/frida-gum": "^19.0.0",
"frida-compile": "^17.0.0"
},
"dependencies": {
"frida-objc-bridge": "^8.0.4"
}
}
@@ -1,6 +1,5 @@
const LIBSYSTEM_KERNEL_PATH = '/usr/lib/system/libsystem_kernel.dylib';
const CORESYMBOLICATION_PATH = '/System/Library/PrivateFrameworks/CoreSymbolication.framework/CoreSymbolication';
const CRASH_REPORTER_SUPPORT_PATH = '/System/Library/PrivateFrameworks/CrashReporterSupport.framework/CrashReporterSupport';
import ObjC from 'frida-objc-bridge';
const YES = ptr(1);
const CSTypeRef = ['pointer', 'pointer'];
@@ -17,42 +16,45 @@ const complexFuncOptions = {
scheduling: 'cooperative',
exceptions: 'propagate'
};
const libsystemKernel = Process.getModuleByName('/usr/lib/system/libsystem_kernel.dylib');
const _pidForTask = new NativeFunction(
Module.getExportByName(LIBSYSTEM_KERNEL_PATH, 'pid_for_task'),
libsystemKernel.getExportByName('pid_for_task'),
'int',
['uint', 'pointer'],
simpleFuncOptions
);
const unlink = new NativeFunction(
Module.getExportByName(LIBSYSTEM_KERNEL_PATH, 'unlink'),
libsystemKernel.getExportByName('unlink'),
'int',
['pointer'],
simpleFuncOptions
);
const coreSymbolication = Process.getModuleByName('/System/Library/PrivateFrameworks/CoreSymbolication.framework/CoreSymbolication');
const CSSymbolicatorGetSymbolWithAddressAtTime = new NativeFunction(
Module.getExportByName(CORESYMBOLICATION_PATH, 'CSSymbolicatorGetSymbolWithAddressAtTime'),
coreSymbolication.getExportByName('CSSymbolicatorGetSymbolWithAddressAtTime'),
CSTypeRef,
[CSTypeRef, 'uint64', 'uint64'],
complexFuncOptions
);
const CSIsNull = new NativeFunction(
Module.getExportByName(CORESYMBOLICATION_PATH, 'CSIsNull'),
coreSymbolication.getExportByName('CSIsNull'),
'int',
[CSTypeRef],
simpleFuncOptions
);
const mappedMemoryRead = new NativeFunction(
Module.getExportByName(CORESYMBOLICATION_PATH, 'mapped_memory_read'),
coreSymbolication.getExportByName('mapped_memory_read'),
'uint',
['pointer', 'uint64', 'uint64', 'pointer'],
simpleFuncOptions
);
const mappedMemoryReadPointer = new NativeFunction(
Module.getExportByName(CORESYMBOLICATION_PATH, 'mapped_memory_read_pointer'),
coreSymbolication.getExportByName('mapped_memory_read_pointer'),
'uint',
['pointer', 'uint64', 'pointer'],
simpleFuncOptions
);
const crashReporterSupport = Process.getModuleByName('/System/Library/PrivateFrameworks/CrashReporterSupport.framework/CrashReporterSupport');
const {
AppleErrorReport,
@@ -67,7 +69,7 @@ const sessions = new Map();
let osaHookState = 'pending';
function initialize() {
const listener = Interceptor.attach(Module.getExportByName(CRASH_REPORTER_SUPPORT_PATH, 'CRCreateDirectoryStructure'), () => {
const listener = Interceptor.attach(crashReporterSupport.getExportByName('CRCreateDirectoryStructure'), () => {
applyInstrumentation();
listener.detach();
});
@@ -144,7 +146,7 @@ function applyInstrumentation() {
},
});
Interceptor.attach(Module.getExportByName(CORESYMBOLICATION_PATH, 'task_is_64bit'), {
Interceptor.attach(coreSymbolication.getExportByName('task_is_64bit'), {
onEnter(args) {
this.pid = pidForTask(args[0].toUInt32());
},
@@ -216,7 +218,7 @@ function applyInstrumentation() {
}
});
} else {
Interceptor.attach(Module.getExportByName(LIBSYSTEM_KERNEL_PATH, 'rename'), {
Interceptor.attach(libsystemKernel.getExportByName('rename'), {
onEnter(args) {
const newPath = args[1].readUtf8String();
const session = getSession(this.threadId, 'rename');
@@ -225,7 +227,7 @@ function applyInstrumentation() {
},
});
Interceptor.attach(Module.getExportByName(LIBSYSTEM_KERNEL_PATH, 'open_dprotected_np'), {
Interceptor.attach(libsystemKernel.getExportByName('open_dprotected_np'), {
onEnter(args) {
const path = args[0].readUtf8String();
this.isCrashLog = /\.ips$/.test(path);
@@ -237,7 +239,7 @@ function applyInstrumentation() {
},
});
Interceptor.attach(Module.getExportByName(LIBSYSTEM_KERNEL_PATH, 'write'), {
Interceptor.attach(libsystemKernel.getExportByName('write'), {
onEnter(args) {
const fd = args[0].toInt32();
this.buf = args[1];
@@ -266,7 +268,7 @@ function applyInstrumentation() {
});
}
Interceptor.attach(Module.getExportByName(CRASH_REPORTER_SUPPORT_PATH, 'OSAPreferencesGetBoolValue'), {
Interceptor.attach(crashReporterSupport.getExportByName('OSAPreferencesGetBoolValue'), {
onEnter(args) {
this.name = new ObjC.Object(args[0]).toString();
this.domain = new ObjC.Object(args[1]).toString();
+18
View File
@@ -0,0 +1,18 @@
reportcrash_js = custom_target('reportcrash.js',
input: [
'package.json',
'package-lock.json',
'index.js',
],
output: [
'reportcrash.js',
],
command: [
python,
compile_js_agent,
'@OUTPUT@',
'@PRIVATE_DIR@',
npm,
'@INPUT@',
],
)
+553
View File
@@ -0,0 +1,553 @@
{
"name": "frida-reportcrash-agent",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "frida-reportcrash-agent",
"version": "1.0.0",
"dependencies": {
"frida-objc-bridge": "^8.0.4"
},
"devDependencies": {
"@types/frida-gum": "^19.0.0",
"frida-compile": "^17.0.0"
}
},
"node_modules/@frida/assert": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@frida/assert/-/assert-3.0.2.tgz",
"integrity": "sha512-JXJq5SbXGrM5EkjrZKfRmB29zOoEOix02NC6A5TSJ+C1GE/X051EinJJsuOO2pEOx7KZwpvAHvS0WXW0+levKg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/base64-js": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@frida/base64-js/-/base64-js-2.0.3.tgz",
"integrity": "sha512-2w0F+1TynOTCZ/v7du9LdHPWwq0lJhazjo2fF9upMyQmA1zHetT14fLuQ1v/6T0qPgyeEGkiSrybstU8EsgeUA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/@frida/buffer": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/@frida/buffer/-/buffer-7.0.4.tgz",
"integrity": "sha512-RxQ1lZRRiCJj7nhcCiD8xeJx0NsLpGGnjqsmTg7jShGmbnVFMN5W7+J+3gqdPSQhc/IxNBIWc6zRXVp4+qnYHg==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT",
"dependencies": {
"base64-js": "^1.5.1",
"ieee754": "^1.2.1"
}
},
"node_modules/@frida/crosspath": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@frida/crosspath/-/crosspath-3.0.0.tgz",
"integrity": "sha512-bNdO1spIPD2P40XtK89N49oZpJhstdlnkJZcD4yJ17jrdkm9Ctu0sd9MIEX6Z8Tm8ydhVJBAOMEKl9/R27onAQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "^17.0.36"
},
"engines": {
"node": ">=14.9.0"
}
},
"node_modules/@frida/crypto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@frida/crypto/-/crypto-1.0.1.tgz",
"integrity": "sha512-WXTkVjESvX8TIVXIynJJv9BKSIdQP0Iis04StIXknkDi1ULdMlrypA9p5C4KW1H6GCkNsVnKbybpzsulYCTvag==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/diagnostics_channel": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/diagnostics_channel/-/diagnostics_channel-1.0.0.tgz",
"integrity": "sha512-mYX1jp/5Bpk24tHArJNx65iCk7qSuV8YJkdU0gFNVtJUXxfV8BG5WuPa4mL+ynxsbWWpsg/cwKZbLAepYKTdQQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/events": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/@frida/events/-/events-4.0.4.tgz",
"integrity": "sha512-qJVQ6VWHf9sjUKuiJzoCAC00frbpcwxeYfvQ+PP9LU/d70j+QvjWgYe98Qa3ekLaBU6r/AvWm8ThKCDUCLWrQQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.8.x"
}
},
"node_modules/@frida/http": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@frida/http/-/http-4.0.2.tgz",
"integrity": "sha512-cvkc7ex7GmVXVOWqtjXKBWUUbYEBgpNRKZbEEoMeI8KiIs8zejKwg+N7rx7296Ao+EP3+xcUr4wBVr3xLaUVfQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"http-parser-js": "^0.5.3"
}
},
"node_modules/@frida/http-parser-js": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/http-parser-js/-/http-parser-js-1.0.0.tgz",
"integrity": "sha512-2nMrNXt/OeTlWbqnE8AH4Sfz4I2+BGoN206dzKEyC/g2svtn83Xu+zuv/V3TkwrA27s26Mcy84ZwsXeNlqNxUQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/https": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/https/-/https-1.0.0.tgz",
"integrity": "sha512-OiqQ6qsALcWOktRLq07oJ0i6sH8eX6MXb/MdZS1qVKDRf6wchH4Pjn6fiLB+pt/OlYbggk+DOfpHwSdjTwuHMQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/ieee754": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@frida/ieee754/-/ieee754-2.0.2.tgz",
"integrity": "sha512-wlcUebnne4ENN7GDr5pTH598ZDLMVOsh0FjenxeVOe6u7ewZkz9gGRnLnZKJAm9kl5G6XhdxhI0cSXVQK/rQUw==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "BSD-3-Clause"
},
"node_modules/@frida/net": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@frida/net/-/net-4.0.2.tgz",
"integrity": "sha512-qQRe7hQ+ZfCcG/SE3P1TRqQ9bmuK/T7wPCYaT4z56rBPWAxsaQbQHpX4fR6OrFaSDr7X0xJLsTbdIp9hGhhLZg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/os": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@frida/os/-/os-1.0.2.tgz",
"integrity": "sha512-3ISAiGNiyIya3QN2EHBCz1wqP0enTdSxP99wUeroeh8+AQRmgoOr/5TRnrVry8pe378anay3fmV/tdUMMSkehQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/path": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@frida/path/-/path-2.0.3.tgz",
"integrity": "sha512-2RQy36QatoC846fzBhBhV8sXMsSOBGoYvwTHeaE1zUdz7F4RNScP4QEekTTooBYWYX/XjiF36KQpYAzc9OYFtg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/process": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@frida/process/-/process-1.2.1.tgz",
"integrity": "sha512-nvCu22DstFW2ttGFtOKekHM7vnjbZm+XgtvavOt427GNT6uV7k0JYK9tnMbcLMRWv57DG6udAmuJlWs8Paq1ag==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/punycode": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@frida/punycode/-/punycode-3.0.0.tgz",
"integrity": "sha512-XVSDY2KamDs1D5/fTVgHcOSNxdU4kTboxzqJMBbTjcQC7XScIT9c0EfbwKCq7Kci6gWQdsHSCr7lU+9Oc4KAdg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/querystring": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/querystring/-/querystring-1.0.0.tgz",
"integrity": "sha512-15m1fOZPmoO/vWlgPJrG/J9/BJDz6a2/JpVGpS8ynNzo+fBhTznaStX5nHxUs24mVTqh/OqLo0EiYJM5WWHXxg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/readable-stream": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/@frida/readable-stream/-/readable-stream-4.1.3.tgz",
"integrity": "sha512-ntGUFmi+CryRGRJIK13a/VST2Ad19uivbln8Xd92vKPAARq+6vMIASDyZIqyl5BLRccfiyCHdYgrgQ6RI5rUig==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/reserved-words": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/reserved-words/-/reserved-words-1.0.0.tgz",
"integrity": "sha512-2yG/XxJlsGlk/mm6eZTb4OAaQEhkTI2qaFfZFtAsrA/XuCpuMWkS4y/guyBlsRu4hAuhK2HPmNM8+OLLK1zM9Q==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/stream": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@frida/stream/-/stream-1.0.2.tgz",
"integrity": "sha512-4OuaC1ztmEKgTq3WeBhsy8Oq+AwW9n9cYnvLklcC9jwD93AEwgbWpecLlxJCVuALvTMdhKPg0nQVfyGYP/i9Bw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@frida/readable-stream": "^4.1.3"
}
},
"node_modules/@frida/string_decoder": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@frida/string_decoder/-/string_decoder-2.0.0.tgz",
"integrity": "sha512-in371tYZMHQiW9HF5MS3JDw6Ao6tyBoq34UWy2rzOswYyMG1rpizh85ofi/yVkxDiaqybEZefxzkVittpPGT6g==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/terser": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/terser/-/terser-1.0.0.tgz",
"integrity": "sha512-59h9WuNzD1Rx/zwoWqQ/FW/4Y/Q3R91Eng2hEwdHapqiTDvtKbZ08F6CynCR7ZVinrh4tLYsF46AtVPTz1ys9g==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"@jridgewell/source-map": "^0.3.2",
"acorn": "^8.5.0",
"commander": "^2.20.0",
"source-map-support": "~0.5.20"
},
"bin": {
"terser": "bin/terser"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@frida/terser/node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/timers": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@frida/timers/-/timers-3.0.0.tgz",
"integrity": "sha512-3b+0igv10aT8TMxefrTAd06rActqbxJLY2Xkkq9vYcPBffB/yHszl0NYIp/5ko8WC3ecDYPU6bQiY6fjs72zTA==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/tty": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/tty/-/tty-1.0.0.tgz",
"integrity": "sha512-p/kjLnKYxEAB1MdYP8+5rKv9CsHzyA+0jg9BcGETzjQVKHHcroHDULRxDYUh+DC7qs6cpX8QdDQh9E+a6ydgsQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/url": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@frida/url/-/url-1.0.2.tgz",
"integrity": "sha512-ZKunbKJHMr8w2Eb/5K1avy0MzK1B998S17wYXNv3RmzBGxMm8S5T0F3qEpRxkU7/72P8m4izyQU87fWl+FjQsQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@frida/punycode": "^3.0.0",
"@frida/querystring": "^1.0.0"
}
},
"node_modules/@frida/util": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@frida/util/-/util-1.0.3.tgz",
"integrity": "sha512-htcG3uDiRXv89ERVNNYhfase39kJ2X75ZARfrYcYEtJLFEsSk0nemM1YnEIR4CjrHvdvkWHrwgKkS+acOyoNEg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/vm": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@frida/vm/-/vm-2.0.0.tgz",
"integrity": "sha512-7fsjLWscZT5odNIBtg6qbLNI+vAk1xmii6H5W2kaYkMYt0vRohQEcDSUWacA+eaWlu5SvMjZI82Yibj/3G9pJw==",
"dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.8",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
"integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/set-array": "^1.2.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/trace-mapping": "^0.3.24"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/set-array": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/source-map": {
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
"integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.25",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@types/frida-gum": {
"version": "19.0.0",
"resolved": "https://registry.npmjs.org/@types/frida-gum/-/frida-gum-19.0.0.tgz",
"integrity": "sha512-qViK1KwvPEAkajwSUv0wpZvZLiX8xO4JFFCh8dfYZfzSyOEfoE0KliCP/nJSKIKG6N3hXnPowrvPufjs5fLKAA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/node": {
"version": "17.0.45",
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz",
"integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==",
"dev": true,
"license": "MIT"
},
"node_modules/acorn": {
"version": "8.14.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
"dev": true,
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true,
"license": "MIT"
},
"node_modules/commander": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
"integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=16"
}
},
"node_modules/frida-compile": {
"version": "17.0.0",
"resolved": "https://registry.npmjs.org/frida-compile/-/frida-compile-17.0.0.tgz",
"integrity": "sha512-ixJRj14qLH/Z0ckFWd5fKeDMm0W2+2WDpSGnLRgpn0nuCQAbDHRCqVCWtPnV8uzPJmA6XOX0pujsMpYe9q9RRw==",
"dev": true,
"dependencies": {
"@frida/assert": "^3.0.1",
"@frida/base64-js": "^2.0.3",
"@frida/buffer": "^7.0.4",
"@frida/crosspath": "^3.0.0",
"@frida/crypto": "^1.0.1",
"@frida/diagnostics_channel": "^1.0.0",
"@frida/events": "^4.0.4",
"@frida/http": "^4.0.2",
"@frida/http-parser-js": "^1.0.0",
"@frida/https": "^1.0.0",
"@frida/ieee754": "^2.0.2",
"@frida/net": "^4.0.1",
"@frida/os": "^1.0.0",
"@frida/path": "^2.0.3",
"@frida/process": "^1.2.1",
"@frida/punycode": "^3.0.0",
"@frida/querystring": "^1.0.0",
"@frida/readable-stream": "^4.1.3",
"@frida/reserved-words": "^1.0.0",
"@frida/stream": "^1.0.2",
"@frida/string_decoder": "^2.0.0",
"@frida/terser": "^1.0.0",
"@frida/timers": "^3.0.0",
"@frida/tty": "^1.0.0",
"@frida/url": "^1.0.2",
"@frida/util": "^1.0.3",
"@frida/vm": "^2.0.0",
"commander": "^11.1.0",
"frida-fs": "^6.0.0",
"typed-emitter": "^2.1.0"
},
"bin": {
"frida-compile": "dist/cli.js"
}
},
"node_modules/frida-fs": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/frida-fs/-/frida-fs-6.0.0.tgz",
"integrity": "sha512-I0fnKupZh7fU2ixwCIjJnEqNdhfm/SC1ZYBMy58EmeqOWSbjw1Dpy99mJ7BJdbk2KNXJeaBZGxDYLtn0J9S+UA==",
"dev": true,
"license": "MIT"
},
"node_modules/frida-objc-bridge": {
"version": "8.0.4",
"resolved": "https://registry.npmjs.org/frida-objc-bridge/-/frida-objc-bridge-8.0.4.tgz",
"integrity": "sha512-AUzwq/+TFtblQLTI97UPX22pBcvyG2oUde9380DXbcJ0zXts4n9JDVONHUr03aBowa0Le+bdBoVdCs7jyyjvlg==",
"license": "LGPL-2.0 WITH WxWindows-exception-3.1"
},
"node_modules/http-parser-js": {
"version": "0.5.10",
"resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz",
"integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==",
"dev": true,
"license": "MIT"
},
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "BSD-3-Clause"
},
"node_modules/rxjs": {
"version": "7.8.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
"dev": true,
"license": "Apache-2.0",
"optional": true,
"dependencies": {
"tslib": "^2.1.0"
}
},
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dev": true,
"license": "MIT",
"dependencies": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"dev": true,
"license": "0BSD",
"optional": true
},
"node_modules/typed-emitter": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-2.1.0.tgz",
"integrity": "sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==",
"dev": true,
"license": "MIT",
"optionalDependencies": {
"rxjs": "*"
}
}
}
}
+16
View File
@@ -0,0 +1,16 @@
{
"name": "frida-reportcrash-agent",
"version": "1.0.0",
"description": "Agent used by Frida's Darwin backend on iOS/iPadOS/tvOS",
"scripts": {
"prepare": "npm run build",
"build": "frida-compile index.js -o reportcrash.js -S -c"
},
"devDependencies": {
"@types/frida-gum": "^19.0.0",
"frida-compile": "^17.0.0"
},
"dependencies": {
"frida-objc-bridge": "^8.0.4"
}
}
+3 -3
View File
@@ -2,7 +2,7 @@ const POSIX_SPAWN_START_SUSPENDED = 0x0080;
applyJailbreakQuirks();
Interceptor.attach(Module.getExportByName('/usr/lib/system/libsystem_kernel.dylib', '__posix_spawn'), {
Interceptor.attach(Process.getModuleByName('/usr/lib/system/libsystem_kernel.dylib').getExportByName('__posix_spawn'), {
onEnter(args) {
const attrs = args[2].add(Process.pointerSize).readPointer();
@@ -42,7 +42,7 @@ function sabotageJbdCall(jbdCallImpl) {
}
function instrumentSubstrateBootstrapper(bootstrapper) {
Interceptor.attach(Module.getExportByName('/usr/lib/system/libdyld.dylib', 'dlopen'), {
Interceptor.attach(Process.getModuleByName('/usr/lib/system/libdyld.dylib').getExportByName('dlopen'), {
onEnter(args) {
this.path = args[0].readUtf8String();
},
@@ -66,7 +66,7 @@ function instrumentSubstrateExec(exec) {
}
function findJbdCallImpl() {
const impl = Module.findExportByName(null, 'jbd_call');
const impl = Module.findGlobalExportByName('jbd_call');
if (impl !== null)
return impl;
+16 -90
View File
@@ -1,98 +1,24 @@
namespace Frida {
public class DarwinHostSessionBackend : Object, HostSessionBackend {
private DarwinHostSessionProvider local_provider;
public async void start (Cancellable? cancellable) throws IOError {
assert (local_provider == null);
local_provider = new DarwinHostSessionProvider ();
provider_available (local_provider);
}
public async void stop (Cancellable? cancellable) throws IOError {
assert (local_provider != null);
provider_unavailable (local_provider);
yield local_provider.close (cancellable);
local_provider = null;
public sealed class DarwinHostSessionBackend : LocalHostSessionBackend {
protected override LocalHostSessionProvider make_provider () {
return new DarwinHostSessionProvider ();
}
}
public class DarwinHostSessionProvider : Object, HostSessionProvider {
public string id {
get { return "local"; }
}
public string name {
get { return "Local System"; }
}
public Variant? icon {
get { return _icon; }
}
private Variant? _icon;
public HostSessionProviderKind kind {
get { return HostSessionProviderKind.LOCAL; }
}
private DarwinHostSession host_session;
construct {
_icon = _try_extract_icon ();
}
public async void close (Cancellable? cancellable) throws IOError {
if (host_session == null)
return;
host_session.agent_session_detached.disconnect (on_agent_session_detached);
yield host_session.close (cancellable);
host_session = null;
}
public async HostSession create (HostSessionOptions? options, Cancellable? cancellable) throws Error, IOError {
if (host_session != null)
throw new Error.INVALID_OPERATION ("Already created");
public sealed class DarwinHostSessionProvider : LocalHostSessionProvider {
protected override LocalHostSession make_host_session (HostSessionOptions? options) throws Error {
var tempdir = new TemporaryDirectory ();
host_session = new DarwinHostSession (new DarwinHelperProcess (tempdir), tempdir);
host_session.agent_session_detached.connect (on_agent_session_detached);
return host_session;
return new DarwinHostSession (new DarwinHelperProcess (tempdir), tempdir);
}
public async void destroy (HostSession session, Cancellable? cancellable) throws Error, IOError {
if (session != host_session)
throw new Error.INVALID_ARGUMENT ("Invalid host session");
host_session.agent_session_detached.disconnect (on_agent_session_detached);
yield host_session.close (cancellable);
host_session = null;
}
public async AgentSession link_agent_session (HostSession host_session, AgentSessionId id, AgentMessageSink sink,
Cancellable? cancellable) throws Error, IOError {
if (host_session != this.host_session)
throw new Error.INVALID_ARGUMENT ("Invalid host session");
return yield this.host_session.link_agent_session (id, sink, cancellable);
}
public void unlink_agent_session (HostSession host_session, AgentSessionId id) {
if (host_session != this.host_session)
return;
this.host_session.unlink_agent_session (id);
}
private void on_agent_session_detached (AgentSessionId id, SessionDetachReason reason, CrashInfo crash) {
agent_session_detached (id, reason, crash);
protected override Variant? load_icon () {
return _try_extract_icon ();
}
public extern static Variant? _try_extract_icon ();
}
public class DarwinHostSession : BaseDBusHostSession {
public sealed class DarwinHostSession : LocalHostSession {
public DarwinHelper helper {
get;
construct;
@@ -410,7 +336,7 @@ namespace Frida {
}
#if IOS || TVOS
private class FruitController : Object, MappedAgentContainer {
private sealed class FruitController : Object, MappedAgentContainer {
public signal void spawn_added (HostSpawnInfo info);
public signal void spawn_removed (HostSpawnInfo info);
public signal void process_crashed (CrashInfo crash);
@@ -815,7 +741,7 @@ namespace Frida {
crash_deliveries.unset (delivery.pid);
}
private class CrashDelivery : Object {
private sealed class CrashDelivery : Object {
public signal void expired ();
public uint pid {
@@ -882,7 +808,7 @@ namespace Frida {
private delegate void FoundMappedAgentFunc (MappedAgent agent);
private class MappedAgent {
private sealed class MappedAgent {
public uint id {
get;
private set;
@@ -905,7 +831,7 @@ namespace Frida {
}
}
private class LaunchdAgent : InternalAgent {
private sealed class LaunchdAgent : InternalAgent {
public signal void app_launch_started (string identifier, uint pid);
public signal void app_launch_completed (string identifier, uint pid, GLib.Error? error);
public signal void spawn_preparation_started (HostSpawnInfo info);
@@ -1015,7 +941,7 @@ namespace Frida {
}
}
private class XpcProxyAgent : InternalAgent {
private sealed class XpcProxyAgent : InternalAgent {
public string identifier {
get;
construct;
@@ -1057,7 +983,7 @@ namespace Frida {
}
}
private class ReportCrashAgent : InternalAgent {
private sealed class ReportCrashAgent : InternalAgent {
public signal void crash_detected (uint pid);
public signal void crash_received (CrashInfo crash);
@@ -1289,7 +1215,7 @@ namespace Frida {
}
}
private class OSAnalyticsAgent : InternalAgent {
private sealed class OSAnalyticsAgent : InternalAgent {
public uint pid {
get;
construct;
+60 -33
View File
@@ -86,7 +86,7 @@
# define CORE_FOUNDATION "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
#endif
typedef struct _FridaHelperContext FridaHelperContext;
typedef struct _FridaDispatchContext FridaDispatchContext;
typedef struct _FridaSpawnInstance FridaSpawnInstance;
typedef guint FridaDyldFlavor;
typedef struct _FridaSpawnInstanceDyldData FridaSpawnInstanceDyldData;
@@ -106,7 +106,7 @@ typedef union _FridaDebugState FridaDebugState;
typedef int FridaConvertThreadStateDirection;
typedef guint FridaAslr;
struct _FridaHelperContext
struct _FridaDispatchContext
{
dispatch_queue_t dispatch_queue;
};
@@ -376,7 +376,7 @@ enum _FridaAslr
};
static FridaSpawnInstance * frida_spawn_instance_new (FridaDarwinHelperBackend * backend);
static void frida_spawn_instance_free (FridaSpawnInstance * instance);
static void frida_spawn_instance_close (FridaSpawnInstance * instance);
static void frida_spawn_instance_resume (FridaSpawnInstance * self);
static void frida_spawn_instance_on_server_cancel (void * context);
@@ -410,7 +410,7 @@ static void frida_configure_terminal_attributes (gint fd);
static FridaInjectInstance * frida_inject_instance_new (FridaDarwinHelperBackend * backend, guint id, guint pid);
static FridaInjectInstance * frida_inject_instance_clone (const FridaInjectInstance * instance, guint id);
static void frida_inject_instance_free (FridaInjectInstance * instance);
static void frida_inject_instance_close (FridaInjectInstance * instance);
static gboolean frida_inject_instance_task_did_not_exec (FridaInjectInstance * instance);
static gboolean frida_inject_instance_start_thread (FridaInjectInstance * self, GError ** error);
@@ -762,30 +762,30 @@ permission_denied:
}
void
_frida_darwin_helper_backend_create_context (FridaDarwinHelperBackend * self)
_frida_darwin_helper_backend_create_dispatch_context (FridaDarwinHelperBackend * self)
{
FridaHelperContext * ctx;
FridaDispatchContext * ctx;
ctx = g_slice_new (FridaHelperContext);
ctx = g_slice_new (FridaDispatchContext);
ctx->dispatch_queue = dispatch_queue_create ("re.frida.helper.queue", DISPATCH_QUEUE_SERIAL);
self->context = ctx;
self->dispatch_context = ctx;
}
void
_frida_darwin_helper_backend_destroy_context (FridaDarwinHelperBackend * self)
_frida_darwin_helper_backend_destroy_dispatch_context (FridaDarwinHelperBackend * self)
{
FridaHelperContext * ctx = self->context;
FridaDispatchContext * ctx = self->dispatch_context;
dispatch_release (ctx->dispatch_queue);
g_slice_free (FridaHelperContext, ctx);
g_slice_free (FridaDispatchContext, ctx);
}
void
_frida_darwin_helper_backend_schedule_on_dispatch_queue (FridaDarwinHelperBackend * self, FridaDarwinHelperBackendDispatchWorker worker, gpointer user_data)
{
FridaHelperContext * ctx = self->context;
FridaDispatchContext * ctx = self->dispatch_context;
dispatch_async (ctx->dispatch_queue, ^
{
@@ -934,7 +934,7 @@ any_failure:
{
if (instance->pid != 0)
kill (instance->pid, SIGKILL);
frida_spawn_instance_free (instance);
frida_spawn_instance_close (instance);
pid = 0;
@@ -1869,7 +1869,7 @@ void
_frida_darwin_helper_backend_prepare_spawn_instance_for_injection (FridaDarwinHelperBackend * self, void * opaque_instance, guint task, GError ** error)
{
FridaSpawnInstance * instance = opaque_instance;
FridaHelperContext * ctx = self->context;
FridaDispatchContext * ctx = self->dispatch_context;
const gchar * failed_operation;
kern_return_t kr;
mach_port_t self_task, child_thread;
@@ -2027,7 +2027,9 @@ _frida_darwin_helper_backend_prepare_spawn_instance_for_injection (FridaDarwinHe
}
}
modern_entry_address = gum_darwin_module_resolve_symbol_address (dyld, "__ZN5dyld44APIs19_libdyld_initializeEPKNS_16LibSystemHelpersE");
modern_entry_address = gum_darwin_module_resolve_symbol_address (dyld, "__ZN5dyld44APIs19_libdyld_initializeEv");
if (modern_entry_address == 0)
modern_entry_address = gum_darwin_module_resolve_symbol_address (dyld, "__ZN5dyld44APIs19_libdyld_initializeEPKNS_16LibSystemHelpersE");
instance->dyld_flavor = (modern_entry_address != 0) ? FRIDA_DYLD_V4_PLUS : FRIDA_DYLD_V3_MINUS;
if (instance->dyld_flavor == FRIDA_DYLD_V4_PLUS)
{
@@ -2113,7 +2115,12 @@ _frida_darwin_helper_backend_prepare_spawn_instance_for_injection (FridaDarwinHe
if (instance->dyld_flavor == FRIDA_DYLD_V4_PLUS)
{
GumAddress restart_with_dyld_in_cache = gum_darwin_module_resolve_symbol_address (dyld,
"__ZN5dyld422restartWithDyldInCacheEPKNS_10KernelArgsEPKN5dyld39MachOFileEPK15DyldSharedCachePv");
"__ZN5dyld422restartWithDyldInCacheEPKNS_10KernelArgsEPKN6mach_o6HeaderEPK15DyldSharedCachePv");
if (restart_with_dyld_in_cache == 0)
{
restart_with_dyld_in_cache = gum_darwin_module_resolve_symbol_address (dyld,
"__ZN5dyld422restartWithDyldInCacheEPKNS_10KernelArgsEPKN5dyld39MachOFileEPK15DyldSharedCachePv");
}
if (restart_with_dyld_in_cache == 0)
{
restart_with_dyld_in_cache = gum_darwin_module_resolve_symbol_address (dyld,
@@ -2200,9 +2207,9 @@ _frida_darwin_helper_backend_resume_spawn_instance (FridaDarwinHelperBackend * s
}
void
_frida_darwin_helper_backend_free_spawn_instance (FridaDarwinHelperBackend * self, void * instance)
_frida_darwin_helper_backend_close_spawn_instance (FridaDarwinHelperBackend * self, void * instance)
{
frida_spawn_instance_free (instance);
frida_spawn_instance_close (instance);
}
guint
@@ -2489,7 +2496,7 @@ mach_failure:
}
failure:
{
frida_inject_instance_free (instance);
frida_inject_instance_close (instance);
goto beach;
}
beach:
@@ -2599,7 +2606,7 @@ frida_inject_instance_start_thread (FridaInjectInstance * self, GError ** error)
mach_msg_type_number_t thread_state_count;
kern_return_t kr;
const gchar * failed_operation;
FridaHelperContext * ctx = self->backend->context;
FridaDispatchContext * ctx = self->backend->dispatch_context;
dispatch_source_t source;
thread_state = g_alloca (self->thread_state_count * sizeof (natural_t));
@@ -2646,7 +2653,7 @@ frida_inject_instance_on_thread_monitor_cancel (void * context)
FridaInjectInstance * self = context;
dispatch_release (g_steal_pointer (&self->thread_monitor_source));
frida_inject_instance_free (self);
frida_inject_instance_close (self);
}
static void
@@ -2705,7 +2712,7 @@ _frida_darwin_helper_backend_join_inject_instance_posix_thread (FridaDarwinHelpe
static void
frida_inject_instance_join_posix_thread (FridaInjectInstance * self, mach_port_t posix_thread)
{
FridaHelperContext * ctx = self->backend->context;
FridaDispatchContext * ctx = self->backend->dispatch_context;
mach_port_t self_task;
dispatch_source_t source;
@@ -2738,9 +2745,9 @@ _frida_darwin_helper_backend_get_pid_of_inject_instance (FridaDarwinHelperBacken
}
void
_frida_darwin_helper_backend_free_inject_instance (FridaDarwinHelperBackend * self, void * instance)
_frida_darwin_helper_backend_close_inject_instance (FridaDarwinHelperBackend * self, void * instance)
{
frida_inject_instance_free (instance);
frida_inject_instance_close (instance);
}
static FridaSpawnInstance *
@@ -2750,7 +2757,7 @@ frida_spawn_instance_new (FridaDarwinHelperBackend * backend)
guint i;
instance = g_slice_new0 (FridaSpawnInstance);
instance->backend = backend;
instance->backend = g_object_ref (backend);
instance->thread = MACH_PORT_NULL;
instance->server_port = MACH_PORT_NULL;
@@ -2773,11 +2780,13 @@ frida_spawn_instance_new (FridaDarwinHelperBackend * backend)
instance->page_pool[i].scratch_page = 0;
}
_frida_darwin_helper_backend_on_instance_created (backend, instance);
return instance;
}
static void
frida_spawn_instance_free (FridaSpawnInstance * instance)
frida_spawn_instance_close (FridaSpawnInstance * instance)
{
task_t self_task;
FridaExceptionPortSet * previous_ports;
@@ -2816,6 +2825,9 @@ frida_spawn_instance_free (FridaSpawnInstance * instance)
if (instance->dyld != NULL)
g_object_unref (instance->dyld);
_frida_darwin_helper_backend_on_instance_destroyed (instance->backend, instance);
g_object_unref (instance->backend);
g_slice_free (FridaSpawnInstance, instance);
}
@@ -2858,7 +2870,7 @@ frida_spawn_instance_on_server_cancel (void * context)
FridaSpawnInstance * self = context;
dispatch_release (g_steal_pointer (&self->server_recv_source));
frida_spawn_instance_free (self);
frida_spawn_instance_close (self);
}
static void
@@ -4114,6 +4126,8 @@ frida_inject_instance_new (FridaDarwinHelperBackend * backend, guint id, guint p
instance->backend = g_object_ref (backend);
_frida_darwin_helper_backend_on_instance_created (backend, instance);
return instance;
}
@@ -4143,11 +4157,13 @@ frida_inject_instance_clone (const FridaInjectInstance * instance, guint id)
g_object_ref (clone->backend);
_frida_darwin_helper_backend_on_instance_created (clone->backend, clone);
return clone;
}
static void
frida_inject_instance_free (FridaInjectInstance * instance)
frida_inject_instance_close (FridaInjectInstance * instance)
{
FridaAgentContext * agent_context = instance->agent_context;
task_t self_task;
@@ -4187,6 +4203,7 @@ frida_inject_instance_free (FridaInjectInstance * instance)
if (instance->task != MACH_PORT_NULL)
mach_port_deallocate (self_task, instance->task);
_frida_darwin_helper_backend_on_instance_destroyed (instance->backend, instance);
g_object_unref (instance->backend);
g_slice_free (FridaInjectInstance, instance);
@@ -4292,6 +4309,7 @@ frida_agent_context_init (FridaAgentContext * self, const FridaAgentDetails * de
static gboolean
frida_agent_context_init_functions (FridaAgentContext * self, GumDarwinModuleResolver * resolver, GumDarwinMapper * mapper, GError ** error)
{
gboolean success = FALSE;
GumDarwinModule * module;
module = gum_darwin_module_resolver_find_module_by_name (resolver, "/usr/lib/system/libsystem_kernel.dylib");
@@ -4303,6 +4321,8 @@ frida_agent_context_init_functions (FridaAgentContext * self, GumDarwinModuleRes
FRIDA_AGENT_CONTEXT_RESOLVE (mach_msg_receive);
FRIDA_AGENT_CONTEXT_RESOLVE (mach_port_destroy);
FRIDA_AGENT_CONTEXT_RESOLVE (thread_terminate);
g_object_unref (module);
module = NULL;
module = gum_darwin_module_resolver_find_module_by_name (resolver, "/usr/lib/system/libsystem_pthread.dylib");
if (module == NULL)
@@ -4315,6 +4335,8 @@ frida_agent_context_init_functions (FridaAgentContext * self, GumDarwinModuleRes
FRIDA_AGENT_CONTEXT_TRY_RESOLVE (pthread_threadid_np);
FRIDA_AGENT_CONTEXT_RESOLVE (pthread_detach);
FRIDA_AGENT_CONTEXT_RESOLVE (pthread_self);
g_object_unref (module);
module = NULL;
if (mapper == NULL)
{
@@ -4324,9 +4346,12 @@ frida_agent_context_init_functions (FridaAgentContext * self, GumDarwinModuleRes
FRIDA_AGENT_CONTEXT_RESOLVE (dlopen);
FRIDA_AGENT_CONTEXT_RESOLVE (dlsym);
FRIDA_AGENT_CONTEXT_RESOLVE (dlclose);
g_object_unref (module);
module = NULL;
}
return TRUE;
success = TRUE;
goto beach;
no_libc:
{
@@ -4334,7 +4359,7 @@ no_libc:
FRIDA_ERROR,
FRIDA_ERROR_NOT_SUPPORTED,
"Unable to attach to processes without Apple's libc (for now)");
goto failure;
goto beach;
}
missing_symbol:
{
@@ -4342,11 +4367,13 @@ missing_symbol:
FRIDA_ERROR,
FRIDA_ERROR_NOT_SUPPORTED,
"Unexpected error while resolving functions");
goto failure;
goto beach;
}
failure:
beach:
{
return FALSE;
g_clear_object (&module);
return success;
}
}
+64 -31
View File
@@ -20,7 +20,8 @@ namespace Frida {
protected delegate void DispatchWorker ();
protected delegate void LaunchCompletionHandler (owned StdioPipes? pipes, owned Error? error);
public void * context;
private MainContext main_context;
public void * dispatch_context;
public Gee.HashMap<uint, void *> spawn_instances = new Gee.HashMap<uint, void *> ();
private Gee.HashMap<uint, OutputStream> stdin_streams = new Gee.HashMap<uint, OutputStream> ();
@@ -32,6 +33,9 @@ namespace Frida {
private Gee.HashMap<void *, uint> inject_cleaner_by_instance = new Gee.HashMap<void *, uint> ();
private Gee.HashMap<uint, uint> inject_expiry_timers = new Gee.HashMap<uint, uint> ();
private Gee.Set<void *> instances = new Gee.HashSet<void *> ();
private SourceFunc? on_last_instance_destroyed = null;
public uint next_id = 1;
private PolicySoftener policy_softener;
@@ -40,7 +44,8 @@ namespace Frida {
private Cancellable io_cancellable = new Cancellable ();
construct {
_create_context ();
main_context = MainContext.ref_thread_default ();
_create_dispatch_context ();
dtrace_agent = DTraceAgent.try_open ();
if (dtrace_agent != null) {
@@ -63,11 +68,7 @@ namespace Frida {
}
~DarwinHelperBackend () {
foreach (var instance in spawn_instances.values)
_free_spawn_instance (instance);
foreach (var instance in inject_instances.values)
_free_inject_instance (instance);
_destroy_context ();
_destroy_dispatch_context ();
}
public async void close (Cancellable? cancellable) throws IOError {
@@ -77,11 +78,24 @@ namespace Frida {
pending.complete ();
foreach (var entry in inject_cleaner_by_instance.entries) {
_free_inject_instance (entry.key);
_close_inject_instance (entry.key);
Source.remove (entry.value);
}
inject_cleaner_by_instance.clear ();
foreach (var instance in spawn_instances.values)
_close_spawn_instance (instance);
spawn_instances.clear ();
bool any_pending = false;
lock (instances) {
any_pending = !instances.is_empty;
if (any_pending)
on_last_instance_destroyed = close.callback;
}
if (any_pending)
yield;
if (dtrace_agent != null) {
dtrace_agent.spawn_added.disconnect (on_dtrace_agent_spawn_added);
dtrace_agent.spawn_removed.disconnect (on_dtrace_agent_spawn_removed);
@@ -139,11 +153,11 @@ namespace Frida {
Error error = null;
_launch (identifier, options, (p, e) => {
Idle.add (() => {
schedule_on_frida_thread (() => {
pipes = p;
error = e;
launch.callback ();
return false;
return Source.REMOVE;
});
});
@@ -187,7 +201,7 @@ namespace Frida {
inject_cleaner_by_instance.unset (instance, out source_id);
Source.remove (source_id);
_free_inject_instance (instance);
_close_inject_instance (instance);
}
policy_softener.forget (pid);
@@ -205,7 +219,7 @@ namespace Frida {
void * instance;
if (spawn_instances.unset (pid, out instance))
_free_spawn_instance (instance);
_close_spawn_instance (instance);
child_dead (pid);
}
@@ -293,7 +307,7 @@ namespace Frida {
void * instance;
if (spawn_instances.unset (pid, out instance)) {
_resume_spawn_instance (instance);
_free_spawn_instance (instance);
_close_spawn_instance (instance);
} else {
resume_with_validation (pid);
}
@@ -412,7 +426,7 @@ namespace Frida {
} catch (GLib.Error e) {
if (instance_created_here) {
spawn_instances.unset (pid);
_free_spawn_instance (spawn_instance);
_close_spawn_instance (spawn_instance);
}
throw_api_error (e);
@@ -495,21 +509,21 @@ namespace Frida {
}
public void _on_spawn_instance_ready (uint pid) {
Idle.add (() => {
schedule_on_frida_thread (() => {
spawn_instance_ready (pid);
return false;
return Source.REMOVE;
});
}
public void _on_spawn_instance_error (uint pid, Error error) {
Idle.add (() => {
schedule_on_frida_thread (() => {
spawn_instance_error (pid, error);
return false;
return Source.REMOVE;
});
}
public void _on_mach_thread_dead (uint id, void * posix_thread) {
Idle.add (() => {
schedule_on_frida_thread (() => {
var instance = inject_instances[id];
assert (instance != null);
@@ -518,14 +532,14 @@ namespace Frida {
else
_destroy_inject_instance (id);
return false;
return Source.REMOVE;
});
}
public void _on_posix_thread_dead (uint id) {
Idle.add (() => {
schedule_on_frida_thread (() => {
_destroy_inject_instance (id);
return false;
return Source.REMOVE;
});
}
@@ -545,7 +559,7 @@ namespace Frida {
private void schedule_inject_instance_cleanup (void * instance) {
var cleanup_source = new TimeoutSource (50);
cleanup_source.set_callback (() => {
_free_inject_instance (instance);
_close_inject_instance (instance);
var removed = inject_cleaner_by_instance.unset (instance);
assert (removed);
@@ -601,6 +615,19 @@ namespace Frida {
policy_softener.forget (pid);
}
public void _on_instance_created (void * instance) {
lock (instances)
instances.add (instance);
}
public void _on_instance_destroyed (void * instance) {
lock (instances) {
instances.remove (instance);
if (on_last_instance_destroyed != null && instances.is_empty)
schedule_on_frida_thread ((owned) on_last_instance_destroyed);
}
}
private void on_dtrace_agent_spawn_added (HostSpawnInfo info) {
spawn_added (info);
}
@@ -611,11 +638,17 @@ namespace Frida {
private async void flush_dispatch_queue () {
_schedule_on_dispatch_queue (() => {
Idle.add (flush_dispatch_queue.callback);
schedule_on_frida_thread (flush_dispatch_queue.callback);
});
yield;
}
private void schedule_on_frida_thread (owned SourceFunc function) {
var source = new IdleSource ();
source.set_callback ((owned) function);
source.attach (main_context);
}
public extern static PipeEndpoints make_pipe_endpoints (uint local_task, uint remote_pid, uint remote_task) throws Error;
public extern static void make_pipe_endpoint_from_socket (uint pid, uint task, GLib.Socket sock, out string address)
throws Error;
@@ -626,8 +659,8 @@ namespace Frida {
public extern static bool is_mmap_available ();
public extern static MappedLibraryBlob mmap (uint task, Bytes blob) throws Error;
protected extern void _create_context ();
protected extern void _destroy_context ();
protected extern void _create_dispatch_context ();
protected extern void _destroy_dispatch_context ();
protected extern void _schedule_on_dispatch_queue (DispatchWorker worker);
protected extern uint _spawn (string path, HostSpawnOptions options, out StdioPipes? pipes) throws Error;
@@ -642,7 +675,7 @@ namespace Frida {
protected extern void * _create_spawn_instance (uint pid);
protected extern void _prepare_spawn_instance_for_injection (void * instance, uint task) throws Error;
protected extern void _resume_spawn_instance (void * instance);
protected extern void _free_spawn_instance (void * instance);
protected extern void _close_spawn_instance (void * instance);
protected extern uint _inject_into_task (uint pid, uint task, string path_or_name, MappedLibraryBlob? blob, string entrypoint, string data) throws Error;
protected extern void _demonitor (void * instance);
@@ -650,10 +683,10 @@ namespace Frida {
protected extern void _recreate_injectee_thread (void * instance, uint pid, uint task) throws Error;
protected extern void _join_inject_instance_posix_thread (void * instance, void * posix_thread);
protected extern uint _get_pid_of_inject_instance (void * instance);
protected extern void _free_inject_instance (void * instance);
protected extern void _close_inject_instance (void * instance);
}
public class DTraceAgent : Object {
public sealed class DTraceAgent : Object {
public signal void spawn_added (HostSpawnInfo info);
public signal void spawn_removed (HostSpawnInfo info);
@@ -812,7 +845,7 @@ namespace Frida {
}
}
private class PendingLaunch : Object {
private sealed class PendingLaunch : Object {
public signal void completed ();
public string identifier {
@@ -856,7 +889,7 @@ namespace Frida {
}
}
public class StdioPipes : Object {
public sealed class StdioPipes : Object {
public int input {
get;
construct;
+1 -1
View File
@@ -1,5 +1,5 @@
namespace Frida {
public class DarwinHelperBackend : Object, DarwinHelper {
public sealed class DarwinHelperBackend : Object, DarwinHelper {
public signal void idle ();
public signal void child_dead (uint pid);
public signal void spawn_instance_ready (uint pid);
+2 -2
View File
@@ -1,5 +1,5 @@
namespace Frida {
public class DarwinHelperProcess : Object, DarwinHelper {
public sealed class DarwinHelperProcess : Object, DarwinHelper {
public uint pid {
get {
return (uint) process_pid;
@@ -473,7 +473,7 @@ namespace Frida {
}
}
private class ResourceStore {
private sealed class ResourceStore {
public HelperFile helper {
get;
private set;
+1 -1
View File
@@ -22,7 +22,7 @@ namespace Frida {
public extern void _start_run_loop ();
public extern void _stop_run_loop ();
public class DarwinHelperService : Object, DarwinRemoteHelper {
public sealed class DarwinHelperService : Object, DarwinRemoteHelper {
public string parent_address {
get;
construct;
+2 -2
View File
@@ -1,5 +1,5 @@
namespace Frida {
public class Fruitjector : Object, Injector {
public sealed class Fruitjector : Object, Injector {
public signal void injected (uint id, uint pid, bool has_mapped_module, DarwinModuleDetails mapped_module);
public DarwinHelper helper {
@@ -117,7 +117,7 @@ namespace Frida {
}
}
public class AgentResource : Object {
public sealed class AgentResource : Object {
public string name {
get;
construct;
+4 -4
View File
@@ -6,7 +6,7 @@ namespace Frida {
public abstract void forget (uint pid);
}
public class NullPolicySoftener : Object, PolicySoftener {
public sealed class NullPolicySoftener : Object, PolicySoftener {
public void soften (uint pid) throws Error {
}
@@ -164,7 +164,7 @@ namespace Frida {
}
}
public class InternalIOSTVOSPolicySoftener : IOSTVOSPolicySoftener {
public sealed class InternalIOSTVOSPolicySoftener : IOSTVOSPolicySoftener {
private static bool enabled = false;
public static void enable () {
@@ -184,7 +184,7 @@ namespace Frida {
private extern static void _soften (uint pid) throws Error;
}
public class ElectraPolicySoftener : IOSTVOSPolicySoftener {
public sealed class ElectraPolicySoftener : IOSTVOSPolicySoftener {
private const string LIBJAILBREAK_PATH = "/usr/lib/libjailbreak.dylib";
private Module libjailbreak;
@@ -237,7 +237,7 @@ namespace Frida {
private extern static int _internal_jb_entitle_now (void * jbd_call, uint connection, uint pid);
}
public class Unc0verPolicySoftener : IOSTVOSPolicySoftener {
public sealed class Unc0verPolicySoftener : IOSTVOSPolicySoftener {
private const string SUBSTITUTED_PATH = "/usr/libexec/substituted";
private uint connection;
+5 -5
View File
@@ -69,7 +69,7 @@ namespace Frida.AXML {
}
}
public class ElementTree : Object {
public sealed class ElementTree : Object {
public string name {
get;
set;
@@ -135,7 +135,7 @@ namespace Frida.AXML {
}
}
public class ResourceValue : Object {
public sealed class ResourceValue : Object {
private uint16 size;
private uint8 unused;
private ResourceType type;
@@ -173,7 +173,7 @@ namespace Frida.AXML {
}
}
public class Attribute : Object {
public sealed class Attribute : Object {
private uint32 namespace;
private uint32 name;
private uint32 unused;
@@ -238,7 +238,7 @@ namespace Frida.AXML {
}
}
private class ResourceMap {
private sealed class ResourceMap {
private Gee.ArrayList<uint32> resources = new Gee.ArrayList<uint32> ();
public ResourceMap.with_stream (DataInputStream input, uint32 size) throws IOError {
@@ -247,7 +247,7 @@ namespace Frida.AXML {
}
}
private class StringPool {
private sealed class StringPool {
private uint32 flags;
private Gee.ArrayList<string> strings = new Gee.ArrayList<string> ();
+9 -9
View File
@@ -1,6 +1,6 @@
[CCode (gir_namespace = "FridaDroidy", gir_version = "1.0")]
namespace Frida.Droidy {
public class DeviceTracker : Object {
public sealed class DeviceTracker : Object {
public signal void device_attached (DeviceDetails details);
public signal void device_detached (string serial);
@@ -149,7 +149,7 @@ namespace Frida.Droidy {
}
}
public class DeviceDetails : Object {
public sealed class DeviceDetails : Object {
public string serial {
get;
construct;
@@ -205,7 +205,7 @@ namespace Frida.Droidy {
}
}
public class ShellSession : Object {
public sealed class ShellSession : Object {
public signal void output (StdioPipe pipe, Bytes bytes);
public signal void closed ();
@@ -594,7 +594,7 @@ namespace Frida.Droidy {
STDERR
}
public class ShellCommandResult : Object {
public sealed class ShellCommandResult : Object {
public uint8 status {
get;
construct;
@@ -686,7 +686,7 @@ namespace Frida.Droidy {
}
}
public class FileMetadata : Object {
public sealed class FileMetadata : Object {
public uint32 mode {
get;
set;
@@ -700,7 +700,7 @@ namespace Frida.Droidy {
}
}
public class JDWPTracker : Object {
public sealed class JDWPTracker : Object {
public signal void debugger_attached (uint pid);
public signal void debugger_detached (uint pid);
@@ -768,7 +768,7 @@ namespace Frida.Droidy {
}
}
public class Client : Object {
public sealed class Client : Object {
public signal void closed ();
public signal void message (string payload);
@@ -791,7 +791,7 @@ namespace Frida.Droidy {
}
private const uint16 ADB_SERVER_DEFAULT_PORT = 5037;
private const uint16 MAX_MESSAGE_LENGTH = 1024;
private const size_t MAX_MESSAGE_LENGTH = 65536;
public static async Client open (Cancellable? cancellable = null) throws Error, IOError {
SocketConnectable? connectable = null;
@@ -1154,7 +1154,7 @@ namespace Frida.Droidy {
}
}
public class SyncSession : Object {
public sealed class SyncSession : Object {
public Client client {
get;
construct;
+74 -4
View File
@@ -1,5 +1,5 @@
namespace Frida {
public class DroidyHostSessionBackend : Object, HostSessionBackend {
public sealed class DroidyHostSessionBackend : Object, HostSessionBackend {
private Droidy.DeviceTracker tracker;
private Gee.HashMap<string, DroidyHostSessionProvider> providers = new Gee.HashMap<string, DroidyHostSessionProvider> ();
@@ -86,7 +86,7 @@ namespace Frida {
}
}
public class DroidyHostSessionProvider : Object, HostSessionProvider, HostChannelProvider {
public sealed class DroidyHostSessionProvider : Object, HostSessionProvider, HostChannelProvider {
public string id {
get { return device_details.serial; }
}
@@ -158,6 +158,36 @@ namespace Frida {
return yield this.host_session.link_agent_session (id, sink, cancellable);
}
public void unlink_agent_session (HostSession host_session, AgentSessionId id) {
if (host_session != this.host_session)
return;
this.host_session.unlink_agent_session (id);
}
public async IOStream link_channel (HostSession host_session, ChannelId id, Cancellable? cancellable)
throws Error, IOError {
if (host_session != this.host_session)
throw new Error.INVALID_ARGUMENT ("Invalid host session");
return this.host_session.link_channel (id);
}
public void unlink_channel (HostSession host_session, ChannelId id) {
if (host_session != this.host_session)
return;
this.host_session.unlink_channel (id);
}
public async ServiceSession link_service_session (HostSession host_session, ServiceSessionId id, Cancellable? cancellable)
throws Error, IOError {
throw new Error.NOT_SUPPORTED ("Services are not supported by this backend");
}
public void unlink_service_session (HostSession host_session, ServiceSessionId id) {
}
private void on_agent_session_detached (AgentSessionId id, SessionDetachReason reason, CrashInfo crash) {
agent_session_detached (id, reason, crash);
}
@@ -182,7 +212,7 @@ namespace Frida {
}
}
public class DroidyHostSession : Object, HostSession {
public sealed class DroidyHostSession : Object, HostSession {
public Droidy.DeviceDetails device_details {
get;
construct;
@@ -211,6 +241,8 @@ namespace Frida {
private Gee.HashMap<AgentSessionId?, AgentSessionEntry> agent_sessions =
new Gee.HashMap<AgentSessionId?, AgentSessionEntry> (AgentSessionId.hash, AgentSessionId.equal);
private ChannelRegistry channel_registry = new ChannelRegistry ();
private Cancellable io_cancellable = new Cancellable ();
private const double MIN_SERVER_CHECK_INTERVAL = 5.0;
@@ -223,6 +255,10 @@ namespace Frida {
);
}
construct {
channel_registry.channel_closed.connect (on_channel_closed);
}
public async void close (Cancellable? cancellable) throws IOError {
if (remote_server_request != null) {
var server = yield try_get_remote_server (cancellable);
@@ -832,6 +868,15 @@ namespace Frida {
return session;
}
public void unlink_agent_session (AgentSessionId id) {
AgentSessionEntry? entry = agent_sessions[id];
if (entry == null || entry.sink_registration_id == 0)
return;
entry.connection.unregister_object (entry.sink_registration_id);
entry.sink_registration_id = 0;
}
public async InjectorPayloadId inject_library_file (uint pid, string path, string entrypoint, string data,
Cancellable? cancellable) throws Error, IOError {
var server = yield get_remote_server (cancellable);
@@ -852,6 +897,31 @@ namespace Frida {
}
}
public async ChannelId open_channel (string address, Cancellable? cancellable) throws Error, IOError {
var stream = yield channel_provider.open_channel (address, cancellable);
var id = ChannelId.generate ();
channel_registry.register (id, stream);
return id;
}
public IOStream link_channel (ChannelId id) throws Error {
return channel_registry.link (id);
}
public void unlink_channel (ChannelId id) {
channel_registry.unlink (id);
}
private void on_channel_closed (ChannelId id) {
channel_closed (id);
}
public async ServiceSessionId open_service (string address, Cancellable? cancellable) throws Error, IOError {
throw new Error.NOT_SUPPORTED ("Services are not supported by this backend");
}
private void on_gadget_entry_detached (GadgetEntry entry, SessionDetachReason reason) {
AgentSessionId id = entry.local_session_id;
var no_crash = CrashInfo.empty ();
@@ -1217,7 +1287,7 @@ namespace Frida {
}
}
public class HelperClient : Object, AsyncInitable {
public sealed class HelperClient : Object, AsyncInitable {
public signal void closed ();
public string device_serial {
+2 -2
View File
@@ -6,7 +6,7 @@ namespace Frida.Droidy.Injector {
return yield session.run (cancellable);
}
public class GadgetDetails : Object {
public sealed class GadgetDetails : Object {
public uint pid {
get;
construct;
@@ -31,7 +31,7 @@ namespace Frida.Droidy.Injector {
}
}
private class Session : Object {
private sealed class Session : Object {
public InputStream gadget {
get;
construct;
+57 -57
View File
@@ -1,6 +1,6 @@
[CCode (gir_namespace = "FridaJDWP", gir_version = "1.0")]
namespace Frida.JDWP {
public class Client : GLib.Object, AsyncInitable {
public sealed class Client : GLib.Object, AsyncInitable {
public signal void closed ();
public signal void events_received (Events events);
@@ -593,7 +593,7 @@ namespace Frida.JDWP {
public abstract string to_string ();
}
public class Byte : Value {
public sealed class Byte : Value {
public uint8 val {
get;
construct;
@@ -608,7 +608,7 @@ namespace Frida.JDWP {
}
}
public class Char : Value {
public sealed class Char : Value {
public string val {
get;
construct;
@@ -623,7 +623,7 @@ namespace Frida.JDWP {
}
}
public class Double : Value {
public sealed class Double : Value {
public double val {
get;
construct;
@@ -638,7 +638,7 @@ namespace Frida.JDWP {
}
}
public class Float : Value {
public sealed class Float : Value {
public float val {
get;
construct;
@@ -653,7 +653,7 @@ namespace Frida.JDWP {
}
}
public class Int : Value {
public sealed class Int : Value {
public int32 val {
get;
construct;
@@ -668,7 +668,7 @@ namespace Frida.JDWP {
}
}
public class Long : Value {
public sealed class Long : Value {
public int64 val {
get;
construct;
@@ -698,7 +698,7 @@ namespace Frida.JDWP {
}
}
public class Short : Value {
public sealed class Short : Value {
public int16 val {
get;
construct;
@@ -713,7 +713,7 @@ namespace Frida.JDWP {
}
}
public class Void : Value {
public sealed class Void : Value {
public Void () {
GLib.Object (tag: ValueTag.VOID);
}
@@ -723,7 +723,7 @@ namespace Frida.JDWP {
}
}
public class Boolean : Value {
public sealed class Boolean : Value {
public bool val {
get;
construct;
@@ -738,43 +738,43 @@ namespace Frida.JDWP {
}
}
public class Array : Object {
public sealed class Array : Object {
public Array (ObjectID val) {
GLib.Object (tag: ValueTag.ARRAY, val: val);
}
}
public class ClassObject : Object {
public sealed class ClassObject : Object {
public ClassObject (ObjectID val) {
GLib.Object (tag: ValueTag.CLASS_OBJECT, val: val);
}
}
public class ThreadGroup : Object {
public sealed class ThreadGroup : Object {
public ThreadGroup (ObjectID val) {
GLib.Object (tag: ValueTag.THREAD_GROUP, val: val);
}
}
public class ClassLoader : Object {
public sealed class ClassLoader : Object {
public ClassLoader (ObjectID val) {
GLib.Object (tag: ValueTag.CLASS_LOADER, val: val);
}
}
public class String : Object {
public sealed class String : Object {
public String (ObjectID val) {
GLib.Object (tag: ValueTag.STRING, val: val);
}
}
public class Thread : Object {
public sealed class Thread : Object {
public Thread (ObjectID val) {
GLib.Object (tag: ValueTag.THREAD, val: val);
}
}
public class ClassInfo : GLib.Object {
public sealed class ClassInfo : GLib.Object {
public TaggedReferenceTypeID ref_type {
get;
construct;
@@ -815,7 +815,7 @@ namespace Frida.JDWP {
}
}
public class MethodInfo : GLib.Object {
public sealed class MethodInfo : GLib.Object {
public MethodID id {
get;
construct;
@@ -992,7 +992,7 @@ namespace Frida.JDWP {
}
}
public class Location : GLib.Object {
public sealed class Location : GLib.Object {
public TaggedReferenceTypeID declaring {
get;
construct;
@@ -1071,7 +1071,7 @@ namespace Frida.JDWP {
ALL = 2,
}
public class Events : GLib.Object {
public sealed class Events : GLib.Object {
public SuspendPolicy suspend_policy {
get;
construct;
@@ -1119,7 +1119,7 @@ namespace Frida.JDWP {
public abstract string to_string ();
}
public class SingleStepEvent : Event {
public sealed class SingleStepEvent : Event {
public ThreadID thread {
get;
construct;
@@ -1155,7 +1155,7 @@ namespace Frida.JDWP {
}
}
public class BreakpointEvent : Event {
public sealed class BreakpointEvent : Event {
public ThreadID thread {
get;
construct;
@@ -1191,7 +1191,7 @@ namespace Frida.JDWP {
}
}
public class FramePopEvent : Event {
public sealed class FramePopEvent : Event {
public override string to_string () {
return "FramePopEvent()";
}
@@ -1201,7 +1201,7 @@ namespace Frida.JDWP {
}
}
public class ExceptionEvent : Event {
public sealed class ExceptionEvent : Event {
public ThreadID thread {
get;
construct;
@@ -1254,7 +1254,7 @@ namespace Frida.JDWP {
}
}
public class UserDefinedEvent : Event {
public sealed class UserDefinedEvent : Event {
public override string to_string () {
return "UserDefinedEvent()";
}
@@ -1264,7 +1264,7 @@ namespace Frida.JDWP {
}
}
public class ThreadStartEvent : Event {
public sealed class ThreadStartEvent : Event {
public ThreadID thread {
get;
construct;
@@ -1292,7 +1292,7 @@ namespace Frida.JDWP {
}
}
public class ThreadDeathEvent : Event {
public sealed class ThreadDeathEvent : Event {
public ThreadID thread {
get;
construct;
@@ -1320,7 +1320,7 @@ namespace Frida.JDWP {
}
}
public class ClassPrepareEvent : Event {
public sealed class ClassPrepareEvent : Event {
public ThreadID thread {
get;
construct;
@@ -1373,7 +1373,7 @@ namespace Frida.JDWP {
}
}
public class ClassUnloadEvent : Event {
public sealed class ClassUnloadEvent : Event {
public string signature {
get;
construct;
@@ -1398,7 +1398,7 @@ namespace Frida.JDWP {
}
}
public class ClassLoadEvent : Event {
public sealed class ClassLoadEvent : Event {
public override string to_string () {
return "ClassLoadEvent()";
}
@@ -1435,7 +1435,7 @@ namespace Frida.JDWP {
}
}
public class FieldAccessEvent : FieldEvent {
public sealed class FieldAccessEvent : FieldEvent {
public FieldAccessEvent (EventRequestID request, ThreadID thread, Location location, TaggedReferenceTypeID ref_type,
FieldID field, TaggedObjectID object) {
GLib.Object (
@@ -1471,7 +1471,7 @@ namespace Frida.JDWP {
}
}
public class FieldModificationEvent : FieldEvent {
public sealed class FieldModificationEvent : FieldEvent {
public Value value_to_be {
get;
construct;
@@ -1516,7 +1516,7 @@ namespace Frida.JDWP {
}
}
public class ExceptionCatchEvent : Event {
public sealed class ExceptionCatchEvent : Event {
public override string to_string () {
return "ExceptionCatchEvent()";
}
@@ -1538,7 +1538,7 @@ namespace Frida.JDWP {
}
}
public class MethodEntryEvent : MethodEvent {
public sealed class MethodEntryEvent : MethodEvent {
public MethodEntryEvent (EventRequestID request, ThreadID thread, Location location) {
GLib.Object (
kind: EventKind.METHOD_ENTRY,
@@ -1564,7 +1564,7 @@ namespace Frida.JDWP {
}
}
public class MethodExitEvent : MethodEvent {
public sealed class MethodExitEvent : MethodEvent {
public MethodExitEvent (EventRequestID request, ThreadID thread, Location location) {
GLib.Object (
kind: EventKind.METHOD_EXIT,
@@ -1590,7 +1590,7 @@ namespace Frida.JDWP {
}
}
public class MethodExitWithReturnValueEvent : MethodEvent {
public sealed class MethodExitWithReturnValueEvent : MethodEvent {
public Value retval {
get;
construct;
@@ -1641,7 +1641,7 @@ namespace Frida.JDWP {
}
}
public class MonitorContendedEnterEvent : MonitorEvent {
public sealed class MonitorContendedEnterEvent : MonitorEvent {
public MonitorContendedEnterEvent (EventRequestID request, ThreadID thread, TaggedObjectID object, Location location) {
GLib.Object (
kind: EventKind.MONITOR_CONTENDED_ENTER,
@@ -1670,7 +1670,7 @@ namespace Frida.JDWP {
}
}
public class MonitorContendedEnteredEvent : MonitorEvent {
public sealed class MonitorContendedEnteredEvent : MonitorEvent {
public MonitorContendedEnteredEvent (EventRequestID request, ThreadID thread, TaggedObjectID object, Location location) {
GLib.Object (
kind: EventKind.MONITOR_CONTENDED_ENTERED,
@@ -1699,7 +1699,7 @@ namespace Frida.JDWP {
}
}
public class MonitorWaitEvent : MonitorEvent {
public sealed class MonitorWaitEvent : MonitorEvent {
public int64 timeout {
get;
construct;
@@ -1736,7 +1736,7 @@ namespace Frida.JDWP {
}
}
public class MonitorWaitedEvent : MonitorEvent {
public sealed class MonitorWaitedEvent : MonitorEvent {
public bool timed_out {
get;
construct;
@@ -1774,7 +1774,7 @@ namespace Frida.JDWP {
}
}
public class VMStartEvent : Event {
public sealed class VMStartEvent : Event {
public ThreadID thread {
get;
construct;
@@ -1799,7 +1799,7 @@ namespace Frida.JDWP {
}
}
public class VMDeathEvent : Event {
public sealed class VMDeathEvent : Event {
public VMDeathEvent (EventRequestID request) {
GLib.Object (kind: EventKind.VM_DEATH, request: request);
}
@@ -1814,7 +1814,7 @@ namespace Frida.JDWP {
}
}
public class VMDisconnectedEvent : Event {
public sealed class VMDisconnectedEvent : Event {
public override string to_string () {
return "VMDisconnectedEvent()";
}
@@ -1828,7 +1828,7 @@ namespace Frida.JDWP {
internal abstract void serialize (PacketBuilder builder);
}
public class CountModifier : EventModifier {
public sealed class CountModifier : EventModifier {
public int32 count {
get;
construct;
@@ -1845,7 +1845,7 @@ namespace Frida.JDWP {
}
}
public class ThreadOnlyModifier : EventModifier {
public sealed class ThreadOnlyModifier : EventModifier {
public ThreadID thread {
get;
construct;
@@ -1862,7 +1862,7 @@ namespace Frida.JDWP {
}
}
public class ClassOnlyModifier : EventModifier {
public sealed class ClassOnlyModifier : EventModifier {
public ReferenceTypeID clazz {
get;
construct;
@@ -1879,7 +1879,7 @@ namespace Frida.JDWP {
}
}
public class ClassMatchModifier : EventModifier {
public sealed class ClassMatchModifier : EventModifier {
public string class_pattern {
get;
construct;
@@ -1896,7 +1896,7 @@ namespace Frida.JDWP {
}
}
public class ClassExcludeModifier : EventModifier {
public sealed class ClassExcludeModifier : EventModifier {
public string class_pattern {
get;
construct;
@@ -1913,7 +1913,7 @@ namespace Frida.JDWP {
}
}
public class LocationOnlyModifier : EventModifier {
public sealed class LocationOnlyModifier : EventModifier {
public Location location {
get;
construct;
@@ -1929,7 +1929,7 @@ namespace Frida.JDWP {
}
}
public class ExceptionOnlyModifier : EventModifier {
public sealed class ExceptionOnlyModifier : EventModifier {
public ReferenceTypeID exception_or_null {
get;
construct;
@@ -1962,7 +1962,7 @@ namespace Frida.JDWP {
}
}
public class FieldOnlyModifier : EventModifier {
public sealed class FieldOnlyModifier : EventModifier {
public ReferenceTypeID declaring {
get;
construct;
@@ -1988,7 +1988,7 @@ namespace Frida.JDWP {
}
}
public class StepModifier : EventModifier {
public sealed class StepModifier : EventModifier {
public ThreadID thread {
get;
construct;
@@ -2032,7 +2032,7 @@ namespace Frida.JDWP {
OUT = 2,
}
public class InstanceOnlyModifier : EventModifier {
public sealed class InstanceOnlyModifier : EventModifier {
public ObjectID instance {
get;
construct;
@@ -2049,7 +2049,7 @@ namespace Frida.JDWP {
}
}
public class SourceNameMatchModifier : EventModifier {
public sealed class SourceNameMatchModifier : EventModifier {
public string source_name_pattern {
get;
construct;
@@ -2149,7 +2149,7 @@ namespace Frida.JDWP {
REPLY = (1 << 7),
}
private class CommandBuilder : PacketBuilder {
private sealed class CommandBuilder : PacketBuilder {
public CommandBuilder (uint32 id, CommandSet command_set, uint8 command, IDSizes id_sizes) {
base (id, 0, id_sizes);
@@ -2354,7 +2354,7 @@ namespace Frida.JDWP {
}
}
private class PacketReader {
private sealed class PacketReader {
public size_t available_bytes {
get {
return end - cursor;
@@ -2574,7 +2574,7 @@ namespace Frida.JDWP {
}
}
private class IDSizes {
private sealed class IDSizes {
private bool valid;
private int field_id_size = -1;
private int method_id_size = -1;
+1 -1
View File
@@ -1,5 +1,5 @@
namespace Frida {
public class FileMonitor : Object {
public sealed class FileMonitor : Object {
public signal void change (string file_path, string? other_file_path, FileMonitorEvent event);
public string path {
+4 -4
View File
@@ -408,7 +408,7 @@ namespace Frida {
protected extern InputStream _get_fifo_for_inject_instance (void * instance);
protected extern void _free_inject_instance (void * instance, UnloadPolicy unload_policy);
public class ResourceStore {
public sealed class ResourceStore {
public TemporaryDirectory tempdir {
get;
private set;
@@ -439,7 +439,7 @@ namespace Frida {
}
}
public class AgentDescriptor : Object {
public sealed class AgentDescriptor : Object {
public string name {
get;
construct;
@@ -553,7 +553,7 @@ namespace Frida {
}
}
private class RemoteModule {
private sealed class RemoteModule {
private Gum.Address base_address;
private Gum.ElfModule module;
@@ -587,7 +587,7 @@ namespace Frida {
}
}
private class RemoteThreadSession : Object {
private sealed class RemoteThreadSession : Object {
public signal void ended (UnloadPolicy unload_policy);
public uint id {
+7 -72
View File
@@ -1,82 +1,17 @@
namespace Frida {
public class FreebsdHostSessionBackend : Object, HostSessionBackend {
private FreebsdHostSessionProvider local_provider;
public async void start (Cancellable? cancellable) throws IOError {
assert (local_provider == null);
local_provider = new FreebsdHostSessionProvider ();
provider_available (local_provider);
}
public async void stop (Cancellable? cancellable) throws IOError {
assert (local_provider != null);
provider_unavailable (local_provider);
yield local_provider.close (cancellable);
local_provider = null;
public sealed class FreebsdHostSessionBackend : LocalHostSessionBackend {
protected override LocalHostSessionProvider make_provider () {
return new FreebsdHostSessionProvider ();
}
}
public class FreebsdHostSessionProvider : Object, HostSessionProvider {
public string id {
get { return "local"; }
}
public string name {
get { return "Local System"; }
}
public Variant? icon {
get { return null; }
}
public HostSessionProviderKind kind {
get { return HostSessionProviderKind.LOCAL; }
}
private FreebsdHostSession host_session;
public async void close (Cancellable? cancellable) throws IOError {
if (host_session == null)
return;
host_session.agent_session_detached.disconnect (on_agent_session_detached);
yield host_session.close (cancellable);
host_session = null;
}
public async HostSession create (HostSessionOptions? options, Cancellable? cancellable) throws Error, IOError {
if (host_session != null)
throw new Error.INVALID_OPERATION ("Already created");
host_session = new FreebsdHostSession ();
host_session.agent_session_detached.connect (on_agent_session_detached);
return host_session;
}
public async void destroy (HostSession session, Cancellable? cancellable) throws Error, IOError {
if (session != host_session)
throw new Error.INVALID_ARGUMENT ("Invalid host session");
host_session.agent_session_detached.disconnect (on_agent_session_detached);
yield host_session.close (cancellable);
host_session = null;
}
public async AgentSession link_agent_session (HostSession host_session, AgentSessionId id, AgentMessageSink sink,
Cancellable? cancellable) throws Error, IOError {
if (host_session != this.host_session)
throw new Error.INVALID_ARGUMENT ("Invalid host session");
return yield this.host_session.link_agent_session (id, sink, cancellable);
}
private void on_agent_session_detached (AgentSessionId id, SessionDetachReason reason, CrashInfo crash) {
agent_session_detached (id, reason, crash);
public sealed class FreebsdHostSessionProvider : LocalHostSessionProvider {
protected override LocalHostSession make_host_session (HostSessionOptions? options) throws Error {
return new FreebsdHostSession ();
}
}
public class FreebsdHostSession : BaseDBusHostSession {
public sealed class FreebsdHostSession : LocalHostSession {
private AgentContainer system_session_container;
private AgentDescriptor agent_desc;
+156 -65
View File
@@ -24,22 +24,34 @@ namespace Frida {
}
}
public class DeviceManager : Object {
public sealed class DeviceManager : Object {
public signal void added (Device device);
public signal void removed (Device device);
public signal void changed ();
public delegate bool Predicate (Device device);
private Promise<bool> start_request;
private Promise<bool> stop_request;
private Promise<bool>? start_request;
private Promise<bool>? stop_request;
private HostSessionService service = null;
private HostSessionService? service;
private Gee.ArrayList<Device> devices = new Gee.ArrayList<Device> ();
private Gee.ArrayList<DeviceObserverEntry> on_device_added = new Gee.ArrayList<DeviceObserverEntry> ();
private Cancellable io_cancellable = new Cancellable ();
public DeviceManager () {
service = new HostSessionService.with_default_backends ();
}
public DeviceManager.with_nonlocal_backends_only () {
service = new HostSessionService.with_nonlocal_backends_only ();
}
public DeviceManager.with_socket_backend_only () {
service = new HostSessionService.with_socket_backend_only ();
}
public async void close (Cancellable? cancellable = null) throws IOError {
yield stop_service (cancellable);
}
@@ -340,7 +352,6 @@ namespace Frida {
}
private async void start_service () {
service = new HostSessionService.with_default_backends ();
try {
service.provider_available.connect (on_provider_available);
service.provider_unavailable.connect (on_provider_unavailable);
@@ -349,12 +360,7 @@ namespace Frida {
start_request.resolve (true);
} catch (IOError e) {
service.provider_available.disconnect (on_provider_available);
service.provider_unavailable.disconnect (on_provider_unavailable);
service = null;
start_request.reject (e);
start_request = null;
}
}
@@ -414,19 +420,18 @@ namespace Frida {
} catch (GLib.Error e) {
cancellable.set_error_if_cancelled ();
}
}
foreach (var device in devices.to_array ())
yield device._do_close (APPLICATION_REQUESTED, true, cancellable);
devices.clear ();
foreach (var device in devices.to_array ())
yield device._do_close (APPLICATION_REQUESTED, true, cancellable);
devices.clear ();
if (service != null) {
yield service.stop (cancellable);
service.provider_available.disconnect (on_provider_available);
service.provider_unavailable.disconnect (on_provider_unavailable);
service = null;
}
service = null;
stop_request.resolve (true);
} catch (IOError e) {
stop_request.reject (e);
@@ -457,7 +462,7 @@ namespace Frida {
}
}
public class DeviceList : Object {
public sealed class DeviceList : Object {
private Gee.List<Device> items;
internal DeviceList (Gee.List<Device> items) {
@@ -473,7 +478,7 @@ namespace Frida {
}
}
public class Device : Object {
public sealed class Device : Object {
public signal void spawn_added (Spawn spawn);
public signal void spawn_removed (Spawn spawn);
public signal void child_added (Child child);
@@ -540,7 +545,6 @@ namespace Frida {
private Gee.HashSet<Promise<Session>> pending_attach_requests = new Gee.HashSet<Promise<Session>> ();
private Gee.HashMap<AgentSessionId?, Promise<bool>> pending_detach_requests =
new Gee.HashMap<AgentSessionId?, Promise<bool>> (AgentSessionId.hash, AgentSessionId.equal);
private Gee.Set<Service> services = new Gee.HashSet<Service> ();
private Bus _bus;
public delegate bool ProcessPredicate (Process process);
@@ -1227,11 +1231,16 @@ namespace Frida {
public async IOStream open_channel (string address, Cancellable? cancellable = null) throws Error, IOError {
check_open ();
var channel_provider = provider as HostChannelProvider;
if (channel_provider == null)
throw new Error.NOT_SUPPORTED ("Channels are not supported by this device");
var host_session = yield get_host_session (cancellable);
return yield channel_provider.open_channel (address, cancellable);
ChannelId id;
try {
id = yield host_session.open_channel (address, cancellable);
} catch (GLib.Error e) {
throw_dbus_error (e);
}
return yield provider.link_channel (host_session, id, cancellable);
}
public IOStream open_channel_sync (string address, Cancellable? cancellable = null) throws Error, IOError {
@@ -1251,15 +1260,18 @@ namespace Frida {
public async Service open_service (string address, Cancellable? cancellable = null) throws Error, IOError {
check_open ();
var service_provider = provider as HostServiceProvider;
if (service_provider == null)
throw new Error.NOT_SUPPORTED ("Services are not supported by this device");
var host_session = yield get_host_session (cancellable);
var service = yield service_provider.open_service (address, cancellable);
service.close.connect (on_service_closed);
services.add (service);
ServiceSessionId id;
try {
id = yield host_session.open_service (address, cancellable);
} catch (GLib.Error e) {
throw_dbus_error (e);
}
return service;
var service_session = yield provider.link_service_session (host_session, id, cancellable);
return new Service (service_session);
}
public Service open_service_sync (string address, Cancellable? cancellable = null) throws Error, IOError {
@@ -1276,10 +1288,6 @@ namespace Frida {
}
}
private void on_service_closed (Service service) {
services.remove (service);
}
public async void unpair (Cancellable? cancellable = null) throws Error, IOError {
check_open ();
@@ -1378,10 +1386,6 @@ namespace Frida {
close_request = new Promise<bool> ();
try {
foreach (var service in services.to_array ())
yield service.cancel (cancellable);
services.clear ();
while (!pending_detach_requests.is_empty) {
var iterator = pending_detach_requests.entries.iterator ();
iterator.next ();
@@ -1535,7 +1539,7 @@ namespace Frida {
}
}
public class RemoteDeviceOptions : Object {
public sealed class RemoteDeviceOptions : Object {
public TlsCertificate? certificate {
get;
set;
@@ -1558,7 +1562,7 @@ namespace Frida {
}
}
public class ApplicationList : Object {
public sealed class ApplicationList : Object {
private Gee.List<Application> items;
internal ApplicationList (Gee.List<Application> items) {
@@ -1574,7 +1578,7 @@ namespace Frida {
}
}
public class Application : Object {
public sealed class Application : Object {
public string identifier {
get;
construct;
@@ -1600,7 +1604,7 @@ namespace Frida {
}
}
public class ProcessList : Object {
public sealed class ProcessList : Object {
private Gee.List<Process> items;
internal ProcessList (Gee.List<Process> items) {
@@ -1616,7 +1620,7 @@ namespace Frida {
}
}
public class Process : Object {
public sealed class Process : Object {
public uint pid {
get;
construct;
@@ -1637,7 +1641,7 @@ namespace Frida {
}
}
public class ProcessMatchOptions : Object {
public sealed class ProcessMatchOptions : Object {
public int timeout {
get;
set;
@@ -1651,7 +1655,7 @@ namespace Frida {
}
}
public class SpawnOptions : Object {
public sealed class SpawnOptions : Object {
public string[]? argv {
get;
set;
@@ -1685,7 +1689,7 @@ namespace Frida {
}
}
public class SpawnList : Object {
public sealed class SpawnList : Object {
private Gee.List<Spawn> items;
internal SpawnList (Gee.List<Spawn> items) {
@@ -1701,7 +1705,7 @@ namespace Frida {
}
}
public class Spawn : Object {
public sealed class Spawn : Object {
public uint pid {
get;
construct;
@@ -1725,7 +1729,7 @@ namespace Frida {
}
}
public class ChildList : Object {
public sealed class ChildList : Object {
private Gee.List<Child> items;
internal ChildList (Gee.List<Child> items) {
@@ -1741,7 +1745,7 @@ namespace Frida {
}
}
public class Child : Object {
public sealed class Child : Object {
public uint pid {
get;
construct;
@@ -1805,7 +1809,7 @@ namespace Frida {
}
}
public class Crash : Object {
public sealed class Crash : Object {
public uint pid {
get;
construct;
@@ -1854,22 +1858,19 @@ namespace Frida {
}
}
public class Bus : Object {
public sealed class Bus : Object {
public signal void detached ();
public signal void message (string json, Bytes? data);
public weak Device device {
get;
construct;
}
private weak Device device;
private Promise<BusSession>? attach_request;
private BusSession? active_session;
private Cancellable io_cancellable = new Cancellable ();
internal Bus (Device device) {
Object (device: device);
this.device = device;
}
public bool is_detached () {
@@ -1989,13 +1990,71 @@ namespace Frida {
}
}
public interface Service : Object {
public sealed class Service : Object {
public signal void close ();
public signal void message (Variant message);
public abstract bool is_closed ();
private ServiceSession? session;
private bool disposed = false;
public abstract async void activate (Cancellable? cancellable = null) throws Error, IOError;
internal Service (ServiceSession session) {
this.session = session;
session.close.connect (on_close);
session.message.connect (on_message);
}
public override void dispose () {
if (!disposed) {
disposed = true;
MainContext context = get_main_context ();
if (context.is_owner ()) {
abandon ();
} else {
var source = new IdleSource ();
source.set_callback (() => {
abandon ();
return false;
});
source.attach (context);
}
}
base.dispose ();
}
~Service () {
forget_session ();
}
private void abandon () {
var s = session;
if (s != null) {
forget_session ();
s.cancel.begin (null);
}
}
private void forget_session () {
session.close.disconnect (on_close);
session.message.disconnect (on_message);
session = null;
}
public bool is_closed () {
return session == null;
}
public async void activate (Cancellable? cancellable = null) throws Error, IOError {
check_open ();
try {
yield session.activate (cancellable);
} catch (GLib.Error e) {
throw_dbus_error (e);
}
}
public void activate_sync (Cancellable? cancellable = null) throws Error, IOError {
create<ActivateTask> ().execute (cancellable);
@@ -2007,7 +2066,17 @@ namespace Frida {
}
}
public abstract async void cancel (Cancellable? cancellable = null) throws IOError;
public async void cancel (Cancellable? cancellable = null) throws IOError {
if (session == null)
return;
try {
yield session.cancel (cancellable);
} catch (GLib.Error e) {
if (e is IOError.CANCELLED)
cancellable.set_error_if_cancelled ();
}
}
public void cancel_sync (Cancellable? cancellable = null) throws IOError {
try {
@@ -2023,7 +2092,15 @@ namespace Frida {
}
}
public abstract async Variant request (Variant parameters, Cancellable? cancellable = null) throws Error, IOError;
public async Variant request (Variant parameters, Cancellable? cancellable = null) throws Error, IOError {
check_open ();
try {
return yield session.request (parameters, cancellable);
} catch (GLib.Error e) {
throw_dbus_error (e);
}
}
public Variant request_sync (Variant parameters, Cancellable? cancellable = null) throws Error, IOError {
var task = create<RequestTask> () as RequestTask;
@@ -2039,6 +2116,20 @@ namespace Frida {
}
}
private void check_open () throws Error {
if (session == null)
throw new Error.INVALID_OPERATION ("Session is gone");
}
private void on_close () {
forget_session ();
close ();
}
private void on_message (Variant v) {
message (v);
}
private T create<T> () {
return Object.new (typeof (T), parent: this);
}
@@ -2051,7 +2142,7 @@ namespace Frida {
}
}
public class Session : Object, AgentMessageSink {
public sealed class Session : Object, AgentMessageSink {
public signal void detached (SessionDetachReason reason, Crash? crash);
public uint pid {
@@ -3019,7 +3110,7 @@ namespace Frida {
}
}
public class Script : Object {
public sealed class Script : Object {
public signal void destroyed ();
public signal void message (string json, Bytes? data);
@@ -3256,7 +3347,7 @@ namespace Frida {
}
}
public class PortalMembership : Object {
public sealed class PortalMembership : Object {
private uint id;
private Session session;
+52 -10
View File
@@ -1,6 +1,6 @@
[CCode (gir_namespace = "FridaFruity", gir_version = "1.0")]
namespace Frida.Fruity {
public class LinuxFruitFinder : Object, FruitFinder {
public sealed class LinuxFruitFinder : Object, FruitFinder {
public string? udid_from_iface (string ifname) throws Error {
var net = "/sys/class/net";
@@ -34,7 +34,7 @@ namespace Frida.Fruity {
}
}
public class LinuxPairingBrowser : Object, PairingBrowser {
public sealed class LinuxPairingBrowser : Object, PairingBrowser {
private Resolved.Manager? resolved;
private Source? timer;
@@ -177,12 +177,14 @@ namespace Frida.Fruity {
Linux.Network.IfAddrs ifaddrs;
Linux.Network.getifaddrs (out ifaddrs);
for (unowned Linux.Network.IfAddrs candidate = ifaddrs; candidate != null; candidate = candidate.ifa_next) {
unowned Posix.SockAddr? address = candidate.ifa_addr;
if (address == null || address.sa_family != Posix.AF_INET6)
continue;
if (candidate.ifa_name != ifname)
continue;
if (candidate.ifa_addr.sa_family != Posix.AF_INET6)
continue;
return (InetSocketAddress)
SocketAddress.from_native ((void *) candidate.ifa_addr, sizeof (Posix.SockAddrIn6));
return (InetSocketAddress) SocketAddress.from_native ((void *) address, sizeof (Posix.SockAddrIn6));
}
throw new Error.NOT_SUPPORTED ("Unable to resolve interface address");
@@ -198,6 +200,8 @@ namespace Frida.Fruity {
namespace Network {
public async void wait_until_interfaces_ready (Gee.Collection<string> interface_names, Cancellable? cancellable)
throws Error, IOError {
var wait_cancellable = new Cancellable ();
try {
var connection = yield GLib.Bus.get (BusType.SYSTEM, cancellable);
@@ -213,6 +217,22 @@ namespace Frida.Fruity {
return;
}
var main_context = MainContext.get_thread_default ();
var timeout_source = new TimeoutSource.seconds (5);
timeout_source.set_callback (() => {
wait_cancellable.cancel ();
return Source.REMOVE;
});
timeout_source.attach (main_context);
var cancel_source = new CancellableSource (cancellable);
cancel_source.set_callback (() => {
wait_cancellable.cancel ();
return Source.REMOVE;
});
cancel_source.attach (main_context);
var remaining = interface_names.size + 1;
NotifyCompleteFunc on_complete = () => {
@@ -223,10 +243,10 @@ namespace Frida.Fruity {
foreach (var name in interface_names) {
if (nm != null) {
NetworkManager.wait_until_interface_ready.begin (name, nm, connection, cancellable,
NetworkManager.wait_until_interface_ready.begin (name, nm, connection, wait_cancellable,
on_complete);
} else {
Networkd.wait_until_interface_ready.begin (name, netd, connection, cancellable,
Networkd.wait_until_interface_ready.begin (name, netd, connection, wait_cancellable,
on_complete);
}
}
@@ -236,11 +256,17 @@ namespace Frida.Fruity {
on_complete ();
return Source.REMOVE;
});
source.attach (MainContext.get_thread_default ());
source.attach (main_context);
yield;
cancel_source.destroy ();
timeout_source.destroy ();
} catch (GLib.Error e) {
}
if (wait_cancellable.is_cancelled ())
throw new Error.TIMED_OUT ("Unexpectedly timed out while waiting for interfaces to become ready");
}
private async bool system_has_service (string name, DBusConnection connection, Cancellable? cancellable) throws GLib.Error {
@@ -274,16 +300,25 @@ namespace Frida.Fruity {
wait_until_interface_ready.callback ();
});
var cancel_source = new CancellableSource (cancellable);
cancel_source.set_callback (wait_until_interface_ready.callback);
cancel_source.attach (MainContext.get_thread_default ());
while (!cancellable.is_cancelled ()) {
uint32 state, reason;
device_proxy.get_cached_property ("StateReason").get ("(uu)", out state, out reason);
if (state == DEVICE_STATE_ACTIVATED)
break;
if (state == DEVICE_STATE_DISCONNECTED && reason != DEVICE_STATE_REASON_NONE)
if (state == DEVICE_STATE_DISCONNECTED &&
reason != DEVICE_STATE_REASON_NONE &&
reason != DEVICE_STATE_REASON_CARRIER) {
break;
}
yield;
}
cancel_source.destroy ();
device_proxy.disconnect (handler);
} catch (GLib.Error e) {
}
@@ -307,6 +342,7 @@ namespace Frida.Fruity {
private const uint32 DEVICE_STATE_ACTIVATED = 100;
private const uint32 DEVICE_STATE_REASON_NONE = 0;
private const uint32 DEVICE_STATE_REASON_CARRIER = 40;
}
namespace Networkd {
@@ -325,6 +361,10 @@ namespace Frida.Fruity {
wait_until_interface_ready.callback ();
});
var cancel_source = new CancellableSource (cancellable);
cancel_source.set_callback (wait_until_interface_ready.callback);
cancel_source.attach (MainContext.get_thread_default ());
while (!cancellable.is_cancelled ()) {
string operational_state;
link_proxy.get_cached_property ("OperationalState").get ("s", out operational_state);
@@ -333,6 +373,8 @@ namespace Frida.Fruity {
yield;
}
cancel_source.destroy ();
link_proxy.disconnect (handler);
} catch (GLib.Error e) {
}
+41 -5
View File
@@ -129,6 +129,8 @@ namespace Frida.Fruity {
private ConnectionType _connection_type;
private string _udid;
private string _name;
private string _auth_state;
private Bytes? _remote_unlock_host_key;
private Promise<Tunnel>? tunnel_request;
@@ -153,6 +155,18 @@ namespace Frida.Fruity {
var reader = new XpcObjectReader (device_info);
_name = reader.read_member ("name").get_string_value ();
reader.end_member ();
_auth_state = reader.read_member ("authState").read_member ("rawCase").get_string_value ();
reader
.end_member ()
.end_member ();
if (reader.has_member ("remoteUnlockHostKey")) {
_remote_unlock_host_key = new Bytes (reader.read_member ("remoteUnlockHostKey").get_data_value ());
reader.end_member ();
} else {
_remote_unlock_host_key = null;
}
}
private void on_state_changed (Object obj, ParamSpec pspec) {
@@ -224,7 +238,9 @@ namespace Frida.Fruity {
tunnel_request = new Promise<Tunnel> ();
try {
var tunnel = new MacOSTunnel (pairing_device);
yield ensure_paired (cancellable);
var tunnel = new MacOSTunnel (pairing_device, _remote_unlock_host_key);
yield tunnel.attach (cancellable);
tunnel_request.resolve (tunnel);
@@ -237,6 +253,17 @@ namespace Frida.Fruity {
throw_api_error (e);
}
}
private async void ensure_paired (Cancellable? cancellable) throws Error, IOError {
if (_auth_state == "authenticated")
return;
var r = new PairingdRequest ("RemotePairing.InitiatePairingCommand");
r.body.set_bool ("requireNonInteractive", false);
var response = yield pairing_device.request (r.message, cancellable);
var reader = new XpcObjectReader (response);
reader.check_nserror (() => Error.PERMISSION_DENIED);
}
}
public sealed class MacOSTunnel : Object, Tunnel {
@@ -252,6 +279,12 @@ namespace Frida.Fruity {
}
}
public Bytes? remote_unlock_host_key {
get {
return _remote_unlock_host_key;
}
}
public Darwin.Xpc.Uuid? assertion_identifier {
get {
return _assertion_identifier;
@@ -259,13 +292,15 @@ namespace Frida.Fruity {
}
private XpcClient pairing_device;
private Bytes? _remote_unlock_host_key;
private Darwin.Xpc.Uuid? _assertion_identifier;
private InetAddress? tunnel_device_address;
private DiscoveryService? _discovery;
private int64 _opened_at = -1;
public MacOSTunnel (XpcClient pairing_device) {
public MacOSTunnel (XpcClient pairing_device, Bytes? remote_unlock_host_key) {
this.pairing_device = pairing_device;
_remote_unlock_host_key = remote_unlock_host_key;
}
public async void close (Cancellable? cancellable) throws IOError {
@@ -285,6 +320,7 @@ namespace Frida.Fruity {
_opened_at = get_monotonic_time ();
var reader = new XpcObjectReader (response);
reader.check_nserror (() => Error.NOT_SUPPORTED);
reader.read_member ("response");
_assertion_identifier = (Darwin.Xpc.Uuid) reader
@@ -395,7 +431,7 @@ namespace Frida.Fruity {
return new PcbList (pcbs);
}
public class PcbList {
public sealed class PcbList {
private uint8[] pcbs;
internal PcbList (owned uint8[] pcbs) {
@@ -406,7 +442,7 @@ namespace Frida.Fruity {
return new Iterator (this);
}
public class Iterator {
public sealed class Iterator {
private PcbList list;
private InetItem * cursor;
@@ -445,7 +481,7 @@ namespace Frida.Fruity {
}
}
public class Item {
public sealed class Item {
public SocketFamily family {
get {
return ((pcb.version_flag & Darwin.XNU.InetVersionFlags.IPV6) != 0)
+1 -1
View File
@@ -1,6 +1,6 @@
[CCode (gir_namespace = "FridaFruity", gir_version = "1.0")]
namespace Frida.Fruity {
public class WindowsPairingBrowser : Object, PairingBrowser {
public sealed class WindowsPairingBrowser : Object, PairingBrowser {
private Gee.Map<string, Monitor> monitors = new Gee.HashMap<string, Monitor> ();
private MainContext main_context = MainContext.ref_thread_default ();
+330 -88
View File
@@ -8,6 +8,8 @@ namespace Frida.Fruity {
private Gee.List<Backend> backends = new Gee.ArrayList<Backend> ();
private Gee.Map<string, Device> devices = new Gee.HashMap<string, Device> ();
private PairingStore pairing_store = new PairingStore ();
private enum State {
CREATED,
STARTING,
@@ -18,11 +20,11 @@ namespace Frida.Fruity {
private delegate void NotifyCompleteFunc ();
construct {
add_backend (new UsbmuxBackend ());
add_backend (new UsbmuxBackend (pairing_store));
#if MACOS
add_backend (new MacOSCoreDeviceBackend ());
#else
add_backend (new PortableCoreDeviceBackend ());
add_backend (new PortableCoreDeviceBackend (pairing_store));
#endif
}
@@ -184,35 +186,47 @@ namespace Frida.Fruity {
default = new Gee.TreeSet<Transport> (compare_transports);
}
private Gee.Queue<UsbmuxLockdownServiceRequest> usbmux_lockdown_service_requests =
new Gee.ArrayQueue<UsbmuxLockdownServiceRequest> ();
private LockdownClient? cached_usbmux_lockdown_client;
private const string[] LOCKDOWN_SERVICES_WITHOUT_ESCROW_BAG_SUPPORT = {
"com.apple.accessibility.axAuditDaemon.remoteserver",
"com.apple.afc",
"com.apple.companion_proxy",
"com.apple.crashreportcopymobile",
"com.apple.GPUTools.MobileService",
"com.apple.idamd",
"com.apple.PurpleReverseProxy.Conn",
"com.apple.streaming_zip_conduit",
"com.apple.webinspector",
};
internal void close () {
transports.clear ();
}
public UsbmuxDevice? find_usbmux_device () {
var transport = transports.first_match (t => t.usbmux_device != null && t.connection_type == USB);
if (transport == null)
transport = transports.first_match (t => t.usbmux_device != null);
return (transport != null) ? transport.usbmux_device : null;
var t = transports.first_match (t => t.usbmux_device != null);
return (t != null) ? t.usbmux_device : null;
}
public UsbmuxDevice get_usbmux_device () throws Error {
var d = find_usbmux_device ();
if (d == null)
private UsbmuxTransport get_usbmux_transport () throws Error {
var t = transports.first_match (t => t is UsbmuxTransport);
if (t == null)
throw new Error.NOT_SUPPORTED ("USB connection not available");
return d;
return (UsbmuxTransport) t;
}
public async Tunnel? find_tunnel (Cancellable? cancellable) throws Error, IOError {
var usbmux_device = find_usbmux_device ();
foreach (var transport in transports) {
var transports_to_try = new Gee.ArrayList<Transport> ();
transports_to_try.add_all_iterator (transports.filter (t => t.usbmux_device == null));
transports_to_try.add_all_iterator (transports.filter (t => t.usbmux_device != null));
foreach (var transport in transports_to_try) {
Tunnel? tunnel = yield transport.find_tunnel (usbmux_device, cancellable);
if (tunnel != null)
return tunnel;
}
return null;
}
@@ -247,6 +261,9 @@ namespace Frida.Fruity {
checkin.set_string ("Request", "RSDCheckin");
checkin.set_string ("Label", "Xcode");
checkin.set_string ("ProtocolVersion", "2");
unowned Bytes? key = tunnel.remote_unlock_host_key;
if (key != null && lockdown_service_supports_escrow_bag (service_name))
checkin.set_bytes ("EscrowBag", key);
try {
yield service.query (checkin, cancellable);
@@ -268,54 +285,16 @@ namespace Frida.Fruity {
return stream;
}
if (service_name == "") {
var client = yield open_usbmux_lockdown_client (cancellable);
return client.service.stream;
}
var request = new UsbmuxLockdownServiceRequest (service_name, cancellable);
bool first_request = usbmux_lockdown_service_requests.is_empty;
usbmux_lockdown_service_requests.offer (request);
if (first_request)
process_usbmux_lockdown_service_requests.begin ();
return yield request.promise.future.wait_async (cancellable);
return yield get_usbmux_transport ().open_lockdown_service (service_name, cancellable);
}
private async void process_usbmux_lockdown_service_requests () {
UsbmuxLockdownServiceRequest? req;
bool already_invalidated = false;
while ((req = usbmux_lockdown_service_requests.peek ()) != null) {
try {
if (cached_usbmux_lockdown_client == null)
cached_usbmux_lockdown_client = yield open_usbmux_lockdown_client (req.cancellable);
var stream = yield cached_usbmux_lockdown_client.start_service (req.service_name, req.cancellable);
req.promise.resolve (stream);
} catch (GLib.Error e) {
if (e is LockdownError.CONNECTION_CLOSED && cached_usbmux_lockdown_client != null &&
!already_invalidated) {
cached_usbmux_lockdown_client = null;
already_invalidated = true;
continue;
}
req.promise.reject ((e is LockdownError.INVALID_SERVICE)
? (Error) new Error.NOT_SUPPORTED ("%s", e.message)
: (Error) new Error.TRANSPORT ("%s", e.message));
}
usbmux_lockdown_service_requests.poll ();
}
}
private async LockdownClient open_usbmux_lockdown_client (Cancellable? cancellable) throws Error, IOError {
try {
var client = yield LockdownClient.open (get_usbmux_device (), cancellable);
yield client.start_session (cancellable);
return client;
} catch (LockdownError e) {
throw new Error.NOT_SUPPORTED ("%s", e.message);
// FIXME: Replace with `element in array`-check once Vala compiler bug has been fixed so generated C code is warning-free.
private static bool lockdown_service_supports_escrow_bag (string name) {
foreach (unowned string s in LOCKDOWN_SERVICES_WITHOUT_ESCROW_BAG_SUPPORT) {
if (s == name)
return false;
}
return true;
}
public async IOStream open_channel (string address, Cancellable? cancellable) throws Error, IOError {
@@ -428,17 +407,6 @@ namespace Frida.Fruity {
score++;
return score;
}
private class UsbmuxLockdownServiceRequest {
public string service_name;
public Cancellable? cancellable;
public Promise<IOStream> promise = new Promise<IOStream> ();
public UsbmuxLockdownServiceRequest (string service_name, Cancellable? cancellable) {
this.service_name = service_name;
this.cancellable = cancellable;
}
}
}
public class TcpChannel {
@@ -496,6 +464,10 @@ namespace Frida.Fruity {
get;
}
public abstract Bytes? remote_unlock_host_key {
get;
}
public abstract async void close (Cancellable? cancellable) throws IOError;
public abstract async IOStream open_tcp_connection (uint16 port, Cancellable? cancellable) throws Error, IOError;
}
@@ -509,6 +481,11 @@ namespace Frida.Fruity {
}
private sealed class UsbmuxBackend : Object, Backend {
public PairingStore pairing_store {
get;
construct;
}
public bool available {
get {
return usbmux != null;
@@ -525,6 +502,10 @@ namespace Frida.Fruity {
private Cancellable io_cancellable = new Cancellable ();
public UsbmuxBackend (PairingStore pairing_store) {
Object (pairing_store: pairing_store);
}
public async void start (Cancellable? cancellable) throws IOError {
start_request = new Promise<bool> ();
start_cancellable = new Cancellable ();
@@ -641,7 +622,7 @@ namespace Frida.Fruity {
}
private async void add_transport (UsbmuxDevice device) {
var transport = new UsbmuxTransport (device);
var transport = new UsbmuxTransport (device, pairing_store);
transports[device] = transport;
string? name = null;
@@ -707,6 +688,11 @@ namespace Frida.Fruity {
construct;
}
public PairingStore pairing_store {
get;
construct;
}
public ConnectionType connection_type {
get {
return device.connection_type;
@@ -740,16 +726,218 @@ namespace Frida.Fruity {
internal string _name;
internal Variant? _icon;
public UsbmuxTransport (UsbmuxDevice device) {
Object (device: device);
private Promise<Tunnel?>? tunnel_request;
private Gee.Queue<UsbmuxLockdownServiceRequest> lockdown_service_requests =
new Gee.ArrayQueue<UsbmuxLockdownServiceRequest> ();
private LockdownClient? cached_lockdown_client;
public UsbmuxTransport (UsbmuxDevice device, PairingStore store) {
Object (device: device, pairing_store: store);
}
public async Tunnel? find_tunnel (UsbmuxDevice? device, Cancellable? cancellable) throws Error, IOError {
return null;
while (tunnel_request != null) {
try {
return yield tunnel_request.future.wait_async (cancellable);
} catch (Error e) {
throw e;
} catch (IOError e) {
cancellable.set_error_if_cancelled ();
}
}
tunnel_request = new Promise<Tunnel> ();
try {
IOStream? stream = null;
try {
stream = yield open_lockdown_service ("com.apple.internal.devicecompute.CoreDeviceProxy", cancellable);
} catch (Error e) {
if (!(e is Error.NOT_SUPPORTED))
throw e;
}
UsbmuxTunnel? tunnel = null;
if (stream != null) {
tunnel = new UsbmuxTunnel (stream, pairing_store);
tunnel.lost.connect (on_tunnel_lost);
try {
yield tunnel.open (cancellable);
} catch (Error e) {
if (e is Error.NOT_SUPPORTED)
tunnel = null;
else
throw e;
}
}
tunnel_request.resolve (tunnel);
return tunnel;
} catch (GLib.Error e) {
tunnel_request.reject (e);
tunnel_request = null;
throw_api_error (e);
}
}
private void on_tunnel_lost () {
tunnel_request = null;
}
public async IOStream open_lockdown_service (string service_name, Cancellable? cancellable) throws Error, IOError {
if (service_name == "") {
var client = yield open_usbmux_lockdown_client (cancellable);
return client.service.stream;
}
var request = new UsbmuxLockdownServiceRequest (service_name, cancellable);
bool first_request = lockdown_service_requests.is_empty;
lockdown_service_requests.offer (request);
if (first_request)
process_lockdown_service_requests.begin ();
return yield request.promise.future.wait_async (cancellable);
}
private async void process_lockdown_service_requests () {
UsbmuxLockdownServiceRequest? req;
bool already_invalidated = false;
while ((req = lockdown_service_requests.peek ()) != null) {
try {
if (cached_lockdown_client == null)
cached_lockdown_client = yield open_usbmux_lockdown_client (req.cancellable);
var stream = yield cached_lockdown_client.start_service (req.service_name, req.cancellable);
req.promise.resolve (stream);
} catch (GLib.Error e) {
if (e is LockdownError.CONNECTION_CLOSED && cached_lockdown_client != null &&
!already_invalidated) {
cached_lockdown_client = null;
already_invalidated = true;
continue;
}
req.promise.reject ((e is LockdownError.INVALID_SERVICE)
? (Error) new Error.NOT_SUPPORTED ("%s", e.message)
: (Error) new Error.TRANSPORT ("%s", e.message));
}
lockdown_service_requests.poll ();
}
}
private async LockdownClient open_usbmux_lockdown_client (Cancellable? cancellable) throws Error, IOError {
try {
var client = yield LockdownClient.open (device, cancellable);
yield client.start_session (cancellable);
return client;
} catch (LockdownError e) {
throw new Error.NOT_SUPPORTED ("%s", e.message);
}
}
private class UsbmuxLockdownServiceRequest {
public string service_name;
public Cancellable? cancellable;
public Promise<IOStream> promise = new Promise<IOStream> ();
public UsbmuxLockdownServiceRequest (string service_name, Cancellable? cancellable) {
this.service_name = service_name;
this.cancellable = cancellable;
}
}
}
private sealed class UsbmuxTunnel : Object, Tunnel {
public signal void lost ();
public IOStream stream {
get;
construct;
}
public PairingStore pairing_store {
get;
construct;
}
public DiscoveryService discovery {
get {
return _discovery_service;
}
}
public int64 opened_at {
get {
return _opened_at;
}
}
public Bytes? remote_unlock_host_key {
get {
return null;
}
}
private UsbNcmDriver? ncm;
private TcpTunnelConnection? tunnel_connection;
private DiscoveryService? _discovery_service;
private int64 _opened_at = -1;
public UsbmuxTunnel (IOStream stream, PairingStore store) {
Object (stream: stream, pairing_store: store);
}
public async void open (Cancellable? cancellable) throws Error, IOError {
var tc = yield TcpTunnelConnection.open_stream (stream, cancellable);
tunnel_connection = tc;
tunnel_connection.closed.connect (on_tunnel_connection_close);
_opened_at = get_monotonic_time ();
var rsd_endpoint = (InetSocketAddress) Object.new (typeof (InetSocketAddress),
address: tc.remote_address,
port: tc.remote_rsd_port,
scope_id: tc.tunnel_netstack.scope_id
);
var rsd_connection = yield tc.tunnel_netstack.open_tcp_connection (rsd_endpoint, cancellable);
var disco = yield DiscoveryService.open (rsd_connection, cancellable);
tunnel_connection = tc;
_discovery_service = disco;
}
public async void close (Cancellable? cancellable) throws IOError {
_discovery_service.close ();
yield tunnel_connection.close (cancellable);
if (ncm != null)
ncm.close ();
}
public async IOStream open_tcp_connection (uint16 port, Cancellable? cancellable) throws Error, IOError {
var netstack = tunnel_connection.tunnel_netstack;
var endpoint = (InetSocketAddress) Object.new (typeof (InetSocketAddress),
address: tunnel_connection.remote_address,
port: port,
scope_id: netstack.scope_id
);
return yield netstack.open_tcp_connection (endpoint, cancellable);
}
private void on_tunnel_connection_close () {
lost ();
}
}
private sealed class PortableCoreDeviceBackend : Object, Backend, UsbDeviceBackend {
public PairingStore pairing_store {
get;
construct;
}
public bool supports_modeswitch {
get {
return LibUSB.has_capability (HAS_HOTPLUG) != 0;
@@ -783,8 +971,6 @@ namespace Frida.Fruity {
private Gee.Map<string, PortableCoreDeviceNetworkTransport> network_transports =
new Gee.HashMap<string, PortableCoreDeviceNetworkTransport> ();
private PairingStore pairing_store = new PairingStore ();
private MainContext main_context;
private Cancellable io_cancellable = new Cancellable ();
@@ -804,6 +990,10 @@ namespace Frida.Fruity {
private delegate void NotifyCompleteFunc ();
public PortableCoreDeviceBackend (PairingStore pairing_store) {
Object (pairing_store: pairing_store);
}
construct {
main_context = MainContext.ref_thread_default ();
@@ -1002,6 +1192,11 @@ namespace Frida.Fruity {
}
unowned string udid = usb_device.udid;
// iPhones before iOS 17 on Windows are sometimes misdetected with an empty udid -> skip those devices
if (udid.length == 0)
return;
var transport = usb_transports.first_match (t => t.udid == udid);
bool may_need_time_to_settle = state != STARTING && (transport == null || transport.modeswitch_in_progress);
@@ -1370,7 +1565,8 @@ namespace Frida.Fruity {
supported_by_os = ios_major_version >= 17;
}
} catch (LockdownError e) {
throw new Error.PERMISSION_DENIED ("%s", e.message);
if (!(e is LockdownError.NOT_PAIRED))
throw new Error.PERMISSION_DENIED ("%s", e.message);
}
}
@@ -1454,13 +1650,15 @@ namespace Frida.Fruity {
Linux.Network.IfAddrs ifaddrs;
Linux.Network.getifaddrs (out ifaddrs);
for (unowned Linux.Network.IfAddrs candidate = ifaddrs; candidate != null; candidate = candidate.ifa_next) {
if (candidate.ifa_addr.sa_family != Posix.AF_INET6)
unowned Posix.SockAddr? address = candidate.ifa_addr;
if (address == null || address.sa_family != Posix.AF_INET6)
continue;
if (!ncm_interfaces.contains (candidate.ifa_name))
continue;
device_ifaddrs.add ((InetSocketAddress) SocketAddress.from_native ((void *) candidate.ifa_addr, sizeof (Posix.SockAddrIn6)));
device_ifaddrs.add ((InetSocketAddress) SocketAddress.from_native ((void *) address,
sizeof (Posix.SockAddrIn6)));
}
if (device_ifaddrs.is_empty && !ncm_interfaces.is_empty)
throw new Error.NOT_SUPPORTED ("no IPv6 address on NCM network interface");
@@ -1529,36 +1727,65 @@ namespace Frida.Fruity {
public signal void response_received (Bytes response, InetSocketAddress sender);
public NetworkStack netstack;
public UdpSocket sock;
public DatagramBasedSource response_source;
private Cancellable? io_cancellable;
private UdpSocket sock;
private DatagramBased sock_datagram;
private Bytes remoted_mdns_request;
private InetSocketAddress mdns_address;
private TimeoutSource retransmit_source;
private DatagramBasedSource response_source;
public ActiveMulticastDnsProbe (InetSocketAddress ifaddr, MainContext main_context, Cancellable? cancellable)
throws Error, IOError {
var local_ip = ifaddr.get_address ();
netstack = new SystemNetworkStack (local_ip, ifaddr.scope_id);
io_cancellable = cancellable;
sock = netstack.create_udp_socket ();
sock.bind ((InetSocketAddress) Object.new (typeof (InetSocketAddress),
address: local_ip,
scope_id: netstack.scope_id
));
DatagramBased sock_datagram = sock.datagram_based;
sock_datagram = sock.datagram_based;
var remoted_mdns_request = make_remoted_mdns_request ();
var mdns_address = (InetSocketAddress) Object.new (typeof (InetSocketAddress),
remoted_mdns_request = make_remoted_mdns_request ();
mdns_address = (InetSocketAddress) Object.new (typeof (InetSocketAddress),
address: new InetAddress.from_string ("ff02::fb"),
port: 5353,
scope_id: netstack.scope_id
);
Udp.send_to (remoted_mdns_request.get_data (), mdns_address, sock_datagram, cancellable);
retransmit_source = new TimeoutSource (250);
retransmit_source.set_callback (on_retransmit_tick);
retransmit_source.attach (main_context);
response_source = sock_datagram.create_source (IN, cancellable);
response_source.set_callback (on_socket_readable);
response_source.attach (main_context);
transmit_request ();
}
public void cancel () {
response_source.destroy ();
retransmit_source.destroy ();
}
private void transmit_request () throws Error, IOError {
Udp.send_to (remoted_mdns_request.get_data (), mdns_address, sock_datagram, io_cancellable);
}
private bool on_retransmit_tick () {
try {
transmit_request ();
} catch (GLib.Error e) {
}
return Source.CONTINUE;
}
private bool on_socket_readable () {
@@ -1675,10 +1902,17 @@ namespace Frida.Fruity {
}
}
public Bytes? remote_unlock_host_key {
get {
return _remote_unlock_host_key;
}
}
private UsbNcmDriver? ncm;
private TunnelConnection? tunnel_connection;
private DiscoveryService? _discovery_service;
private int64 _opened_at = -1;
private Bytes? _remote_unlock_host_key;
public PortableUsbTunnel (UsbDevice device, NcmPeer peer, PairingStore store) {
Object (
@@ -1707,11 +1941,11 @@ namespace Frida.Fruity {
);
var pairing_transport = new XpcPairingTransport (yield netstack.open_tcp_connection (tunnel_endpoint, cancellable));
var pairing_service = yield PairingService.open (pairing_transport, pairing_store, cancellable);
TunnelConnection tc = yield pairing_service.open_tunnel (ncm_peer.ip, netstack, cancellable);
tc.closed.connect (on_tunnel_connection_close);
_opened_at = get_monotonic_time ();
_remote_unlock_host_key = pairing_service.established_peer.remote_unlock_host_key;
var rsd_endpoint = (InetSocketAddress) Object.new (typeof (InetSocketAddress),
address: tc.remote_address,
@@ -1880,9 +2114,16 @@ namespace Frida.Fruity {
}
}
public Bytes? remote_unlock_host_key {
get {
return _remote_unlock_host_key;
}
}
private TunnelConnection? tunnel_connection;
private DiscoveryService? _discovery_service;
private int64 _opened_at = -1;
private Bytes? _remote_unlock_host_key;
private const uint PAIRING_CONNECTION_TIMEOUT = 2000;
@@ -1905,6 +2146,7 @@ namespace Frida.Fruity {
TunnelConnection tc = yield pairing_service.open_tunnel (endpoint.get_address (), netstack, cancellable);
_opened_at = get_monotonic_time ();
_remote_unlock_host_key = pairing_service.established_peer.remote_unlock_host_key;
var rsd_endpoint = (InetSocketAddress) Object.new (typeof (InetSocketAddress),
address: tc.remote_address,
@@ -1947,7 +2189,7 @@ namespace Frida.Fruity {
public abstract string? udid_from_iface (string ifname) throws Error;
}
public class NullFruitFinder : Object, FruitFinder {
public sealed class NullFruitFinder : Object, FruitFinder {
public string? udid_from_iface (string ifname) throws Error {
return null;
}
@@ -1972,7 +2214,7 @@ namespace Frida.Fruity {
public abstract async void stop (Cancellable? cancellable) throws IOError;
}
public class NullPairingBrowser : Object, PairingBrowser {
public sealed class NullPairingBrowser : Object, PairingBrowser {
public async void start (Cancellable? cancellable) throws IOError {
}
+1 -1
View File
@@ -1,6 +1,6 @@
[CCode (gir_namespace = "FridaFruity", gir_version = "1.0")]
namespace Frida.Fruity {
public class DnsPacketReader {
public sealed class DnsPacketReader {
private BufferReader reader;
public DnsPacketReader (Bytes packet) {
+10 -10
View File
@@ -1,6 +1,6 @@
[CCode (gir_namespace = "FridaFruity", gir_version = "1.0")]
namespace Frida.Fruity {
public class DeviceInfoService : Object, AsyncInitable {
public sealed class DeviceInfoService : Object, AsyncInitable {
public HostChannelProvider channel_provider {
get;
construct;
@@ -75,7 +75,7 @@ namespace Frida.Fruity {
return name;
}
public class ProcessInfo : Object {
public sealed class ProcessInfo : Object {
public uint pid {
get;
set;
@@ -108,7 +108,7 @@ namespace Frida.Fruity {
}
}
public class ApplicationListingService : Object, AsyncInitable {
public sealed class ApplicationListingService : Object, AsyncInitable {
public HostChannelProvider channel_provider {
get;
construct;
@@ -211,7 +211,7 @@ namespace Frida.Fruity {
return result;
}
public class ApplicationInfo : Object {
public sealed class ApplicationInfo : Object {
public ApplicationType app_type {
get;
set;
@@ -306,7 +306,7 @@ namespace Frida.Fruity {
}
}
public class ProcessControlService : Object, AsyncInitable {
public sealed class ProcessControlService : Object, AsyncInitable {
public HostChannelProvider channel_provider {
get;
construct;
@@ -346,7 +346,7 @@ namespace Frida.Fruity {
}
}
public class DTXConnection : Object, DTXTransport {
public sealed class DTXConnection : Object, DTXTransport {
public IOStream stream {
get;
construct;
@@ -847,7 +847,7 @@ namespace Frida.Fruity {
}
}
private class DTXControlChannel : DTXChannel {
private sealed class DTXControlChannel : DTXChannel {
public DTXControlChannel (DTXTransport transport) {
Object (code: 0, transport: transport);
}
@@ -1161,7 +1161,7 @@ namespace Frida.Fruity {
}
}
public class DTXArgumentListBuilder {
public sealed class DTXArgumentListBuilder {
private PrimitiveBuilder blob = new PrimitiveBuilder ();
public DTXArgumentListBuilder () {
@@ -1227,7 +1227,7 @@ namespace Frida.Fruity {
private const size_t PRIMITIVE_DICTIONARY_HEADER_SIZE = 16;
private class PrimitiveReader {
private sealed class PrimitiveReader {
public size_t available_bytes {
get {
return end - cursor;
@@ -1317,7 +1317,7 @@ namespace Frida.Fruity {
}
}
private class PrimitiveBuilder {
private sealed class PrimitiveBuilder {
public size_t offset {
get {
return cursor;
+168 -72
View File
@@ -1,5 +1,5 @@
namespace Frida {
public class FruityHostSessionBackend : Object, HostSessionBackend {
public sealed class FruityHostSessionBackend : Object, HostSessionBackend {
private Fruity.DeviceMonitor device_monitor = new Fruity.DeviceMonitor ();
private Gee.Map<Fruity.Device, FruityHostSessionProvider> providers =
new Gee.HashMap<Fruity.Device, FruityHostSessionProvider> ();
@@ -42,7 +42,7 @@ namespace Frida {
}
}
public class FruityHostSessionProvider : Object, HostSessionProvider, HostChannelProvider, HostServiceProvider, Pairable {
public sealed class FruityHostSessionProvider : Object, HostSessionProvider, HostChannelProvider, Pairable {
public Fruity.Device device {
get;
construct;
@@ -108,6 +108,43 @@ namespace Frida {
return yield this.host_session.link_agent_session (id, sink, cancellable);
}
public void unlink_agent_session (HostSession host_session, AgentSessionId id) {
if (host_session != this.host_session)
return;
this.host_session.unlink_agent_session (id);
}
public async IOStream link_channel (HostSession host_session, ChannelId id, Cancellable? cancellable)
throws Error, IOError {
if (host_session != this.host_session)
throw new Error.INVALID_ARGUMENT ("Invalid host session");
return this.host_session.link_channel (id);
}
public void unlink_channel (HostSession host_session, ChannelId id) {
if (host_session != this.host_session)
return;
this.host_session.unlink_channel (id);
}
public async ServiceSession link_service_session (HostSession host_session, ServiceSessionId id, Cancellable? cancellable)
throws Error, IOError {
if (host_session != this.host_session)
throw new Error.INVALID_ARGUMENT ("Invalid host session");
return this.host_session.link_service_session (id);
}
public void unlink_service_session (HostSession host_session, ServiceSessionId id) {
if (host_session != this.host_session)
return;
this.host_session.unlink_service_session (id);
}
private void on_agent_session_detached (AgentSessionId id, SessionDetachReason reason, CrashInfo crash) {
agent_session_detached (id, reason, crash);
}
@@ -116,37 +153,6 @@ namespace Frida {
return yield device.open_channel (address, cancellable);
}
public async Service open_service (string address, Cancellable? cancellable) throws Error, IOError {
string[] tokens = address.split (":", 2);
unowned string protocol = tokens[0];
unowned string service_name = tokens[1];
if (protocol == "plist") {
var stream = yield device.open_lockdown_service (service_name, cancellable);
return new PlistService (stream);
}
if (protocol == "dtx") {
var connection = yield Fruity.DTXConnection.obtain (device, cancellable);
return new DTXService (service_name, connection);
}
if (protocol == "xpc") {
var tunnel = yield device.find_tunnel (cancellable);
if (tunnel == null)
throw new Error.NOT_SUPPORTED ("RemoteXPC not supported by device");
var service_info = tunnel.discovery.get_service (service_name);
var stream = yield tunnel.open_tcp_connection (service_info.port, cancellable);
return new XpcService (new Fruity.XpcConnection (stream));
}
throw new Error.NOT_SUPPORTED ("Unsupported service address");
}
private async void unpair (Cancellable? cancellable) throws Error, IOError {
try {
var client = yield device.get_lockdown_client (cancellable);
@@ -159,7 +165,7 @@ namespace Frida {
}
}
public class FruityHostSession : Object, HostSession {
public sealed class FruityHostSession : Object, HostSession {
public Fruity.Device device {
get;
construct;
@@ -179,6 +185,10 @@ namespace Frida {
private Gee.HashMap<AgentSessionId?, AgentSessionEntry> agent_sessions =
new Gee.HashMap<AgentSessionId?, AgentSessionEntry> (AgentSessionId.hash, AgentSessionId.equal);
private ChannelRegistry channel_registry = new ChannelRegistry ();
private ServiceSessionRegistry service_session_registry = new ServiceSessionRegistry ();
private Cancellable io_cancellable = new Cancellable ();
private const double MIN_SERVER_CHECK_INTERVAL = 5.0;
@@ -196,6 +206,11 @@ namespace Frida {
Object (device: device);
}
construct {
channel_registry.channel_closed.connect (on_channel_closed);
service_session_registry.session_closed.connect (on_service_session_closed);
}
public async void close (Cancellable? cancellable) throws IOError {
if (remote_server_request != null) {
try {
@@ -999,6 +1014,15 @@ namespace Frida {
return session;
}
public void unlink_agent_session (AgentSessionId id) {
AgentSessionEntry? entry = agent_sessions[id];
if (entry == null || entry.sink_registration_id == 0)
return;
entry.connection.unregister_object (entry.sink_registration_id);
entry.sink_registration_id = 0;
}
public async InjectorPayloadId inject_library_file (uint pid, string path, string entrypoint, string data,
Cancellable? cancellable) throws Error, IOError {
var server = yield get_remote_server (cancellable);
@@ -1019,6 +1043,79 @@ namespace Frida {
}
}
public async ChannelId open_channel (string address, Cancellable? cancellable) throws Error, IOError {
var stream = yield device.open_channel (address, cancellable);
var id = ChannelId.generate ();
channel_registry.register (id, stream);
return id;
}
public IOStream link_channel (ChannelId id) throws Error {
return channel_registry.link (id);
}
public void unlink_channel (ChannelId id) {
channel_registry.unlink (id);
}
private void on_channel_closed (ChannelId id) {
channel_closed (id);
}
private void on_service_session_closed (ServiceSessionId id) {
service_session_closed (id);
}
public async ServiceSessionId open_service (string address, Cancellable? cancellable) throws Error, IOError {
var session = yield do_open_service (address, cancellable);
var id = ServiceSessionId.generate ();
service_session_registry.register (id, session);
return id;
}
private async ServiceSession do_open_service (string address, Cancellable? cancellable) throws Error, IOError {
string[] tokens = address.split (":", 2);
unowned string protocol = tokens[0];
unowned string service_name = tokens[1];
if (protocol == "plist") {
var stream = yield device.open_lockdown_service (service_name, cancellable);
return new PlistServiceSession (stream);
}
if (protocol == "dtx") {
var connection = yield Fruity.DTXConnection.obtain (device, cancellable);
return new DTXServiceSession (service_name, connection);
}
if (protocol == "xpc") {
var tunnel = yield device.find_tunnel (cancellable);
if (tunnel == null)
throw new Error.NOT_SUPPORTED ("RemoteXPC not supported by device");
var service_info = tunnel.discovery.get_service (service_name);
var stream = yield tunnel.open_tcp_connection (service_info.port, cancellable);
return new XpcServiceSession (new Fruity.XpcConnection (stream));
}
throw new Error.NOT_SUPPORTED ("Unsupported service address");
}
public ServiceSession link_service_session (ServiceSessionId id) throws Error {
return service_session_registry.link (id);
}
public void unlink_service_session (ServiceSessionId id) {
service_session_registry.unlink (id);
}
private void add_lldb_session (LLDBSession session) {
lldb_sessions[session.process.pid] = session;
@@ -1554,22 +1651,16 @@ namespace Frida {
}
}
private sealed class PlistService : Object, Service {
private sealed class PlistServiceSession : Object, ServiceSession {
public IOStream stream {
get;
construct;
}
private State state = INACTIVE;
private Fruity.PlistServiceClient client;
private bool client_closed = false;
private enum State {
INACTIVE,
ACTIVE,
}
public PlistService (IOStream stream) {
public PlistServiceSession (IOStream stream) {
Object (stream: stream);
}
@@ -1578,8 +1669,8 @@ namespace Frida {
client.closed.connect (on_client_closed);
}
public bool is_closed () {
return client_closed;
~PlistServiceSession () {
client.closed.disconnect (on_client_closed);
}
public async void activate (Cancellable? cancellable) throws Error, IOError {
@@ -1587,14 +1678,8 @@ namespace Frida {
}
private void ensure_active () throws Error {
if (state == INACTIVE) {
state = ACTIVE;
if (client_closed) {
close ();
throw new Error.INVALID_OPERATION ("Service is closed");
}
}
if (client_closed)
throw new Error.INVALID_OPERATION ("Service is closed");
}
public async void cancel (Cancellable? cancellable) throws IOError {
@@ -1603,6 +1688,8 @@ namespace Frida {
client_closed = true;
yield client.close (cancellable);
close ();
}
public async Variant request (Variant parameters, Cancellable? cancellable = null) throws Error, IOError {
@@ -1757,7 +1844,7 @@ namespace Frida {
}
}
private sealed class DTXService : Object, Service {
private sealed class DTXServiceSession : Object, ServiceSession {
public string identifier {
get;
construct;
@@ -1777,7 +1864,7 @@ namespace Frida {
ACTIVE,
}
public DTXService (string identifier, Fruity.DTXConnection connection) {
public DTXServiceSession (string identifier, Fruity.DTXConnection connection) {
Object (identifier: identifier, connection: connection);
}
@@ -1785,8 +1872,8 @@ namespace Frida {
connection.notify["state"].connect (on_connection_state_changed);
}
public bool is_closed () {
return connection_closed;
~DTXServiceSession () {
connection.notify["state"].disconnect (on_connection_state_changed);
}
public async void activate (Cancellable? cancellable) throws Error, IOError {
@@ -1794,14 +1881,12 @@ namespace Frida {
}
private void ensure_active () throws Error {
if (connection_closed)
throw new Error.INVALID_OPERATION ("Service is closed");
if (state == INACTIVE) {
state = ACTIVE;
if (connection_closed) {
close ();
throw new Error.INVALID_OPERATION ("Service is closed");
}
channel = connection.make_channel (identifier);
channel.invocation.connect (on_channel_invocation);
channel.notification.connect (on_channel_notification);
@@ -1812,7 +1897,13 @@ namespace Frida {
if (connection_closed)
return;
connection_closed = true;
channel = null;
if (channel != null) {
channel.invocation.disconnect (on_channel_invocation);
channel.notification.disconnect (on_channel_notification);
channel = null;
}
close ();
}
@@ -2026,7 +2117,7 @@ namespace Frida {
}
}
private sealed class XpcService : Object, Service {
private sealed class XpcServiceSession : Object, ServiceSession {
public Fruity.XpcConnection connection {
get;
construct;
@@ -2040,7 +2131,7 @@ namespace Frida {
ACTIVE,
}
public XpcService (Fruity.XpcConnection connection) {
public XpcServiceSession (Fruity.XpcConnection connection) {
Object (connection: connection);
}
@@ -2049,8 +2140,11 @@ namespace Frida {
connection.message.connect (on_message);
}
public bool is_closed () {
return connection_closed;
~XpcServiceSession () {
connection.close.disconnect (on_close);
connection.message.disconnect (on_message);
connection.cancel ();
}
public async void activate (Cancellable? cancellable) throws Error, IOError {
@@ -2058,20 +2152,21 @@ namespace Frida {
}
private void ensure_active () throws Error {
if (connection_closed)
throw new Error.INVALID_OPERATION ("Service is closed");
if (state == INACTIVE) {
state = ACTIVE;
if (connection_closed) {
close ();
throw new Error.INVALID_OPERATION ("Service is closed");
}
connection.activate ();
}
}
public async void cancel (Cancellable? cancellable) throws IOError {
connection.cancel ();
if (state == ACTIVE)
connection.cancel ();
else if (!connection_closed)
on_close (null);
}
public async Variant request (Variant parameters, Cancellable? cancellable = null) throws Error, IOError {
@@ -2095,6 +2190,7 @@ namespace Frida {
private void on_close (Error? error) {
connection_closed = true;
close ();
}
+8 -5
View File
@@ -6,7 +6,7 @@ namespace Frida.Fruity.Injector {
return yield session.run (cancellable);
}
public class GadgetDetails : Object {
public sealed class GadgetDetails : Object {
public uint16 port {
get;
construct;
@@ -21,7 +21,7 @@ namespace Frida.Fruity.Injector {
UNSUPPORTED
}
private class Session : Object {
private sealed class Session : Object {
public Gum.DarwinModule module {
get;
construct;
@@ -825,7 +825,9 @@ namespace Frida.Fruity.Injector {
yield restore_main_thread_state (cancellable);
uint64? libdyld_initialize = dyld_symbols["__ZN5dyld44APIs19_libdyld_initializeEPKNS_16LibSystemHelpersE"];
uint64? libdyld_initialize = dyld_symbols["__ZN5dyld44APIs19_libdyld_initializeEv"];
if (libdyld_initialize == null)
libdyld_initialize = dyld_symbols["__ZN5dyld44APIs19_libdyld_initializeEPKNS_16LibSystemHelpersE"];
if (libdyld_initialize != null)
yield ensure_libsystem_initialized_for_dyld_v4_and_above (libdyld_initialize, dyld_symbols, cancellable);
else
@@ -848,9 +850,10 @@ namespace Frida.Fruity.Injector {
uint64? notify_objc_init = dyld_symbols["__ZN5dyld412RuntimeState14notifyObjCInitEPKNS_6LoaderE"];
uint64 initializer = (notify_objc_init != null) ? notify_objc_init : libdyld_initialize;
GDB.Breakpoint init_breakpoint = yield lldb.add_breakpoint (SOFT, initializer, 4, cancellable);
GDB.Breakpoint? restart_breakpoint = null;
uint64? restart_with_dyld_in_cache = dyld_symbols["__ZN5dyld422restartWithDyldInCacheEPKNS_10KernelArgsEPKN5dyld39MachOFileEPK15DyldSharedCachePv"];
uint64? restart_with_dyld_in_cache = dyld_symbols["__ZN5dyld422restartWithDyldInCacheEPKNS_10KernelArgsEPKN6mach_o6HeaderEPK15DyldSharedCachePv"];
if (restart_with_dyld_in_cache == null)
restart_with_dyld_in_cache = dyld_symbols["__ZN5dyld422restartWithDyldInCacheEPKNS_10KernelArgsEPKN5dyld39MachOFileEPK15DyldSharedCachePv"];
if (restart_with_dyld_in_cache == null)
restart_with_dyld_in_cache = dyld_symbols["__ZN5dyld422restartWithDyldInCacheEPKNS_10KernelArgsEPKN5dyld39MachOFileEPv"];
if (restart_with_dyld_in_cache != null)
+2 -2
View File
@@ -1,6 +1,6 @@
[CCode (gir_namespace = "FridaFruity", gir_version = "1.0")]
namespace Frida.Fruity {
public class InstallationProxyClient : Object, AsyncInitable {
public sealed class InstallationProxyClient : Object, AsyncInitable {
public Device device {
get;
construct;
@@ -193,7 +193,7 @@ namespace Frida.Fruity {
}
}
public class ApplicationDetails : Object {
public sealed class ApplicationDetails : Object {
public string identifier {
get;
construct;
+11 -11
View File
@@ -22,7 +22,7 @@ namespace Frida.Fruity {
}
}
public class NSNumber : NSObject {
public sealed class NSNumber : NSObject {
public Kind kind {
get;
private set;
@@ -108,7 +108,7 @@ namespace Frida.Fruity {
}
}
public class NSString : NSObject {
public sealed class NSString : NSObject {
public string str {
get;
private set;
@@ -134,7 +134,7 @@ namespace Frida.Fruity {
}
}
public class NSData : NSObject {
public sealed class NSData : NSObject {
public Bytes bytes {
get;
private set;
@@ -160,7 +160,7 @@ namespace Frida.Fruity {
}
}
public class NSDictionary : NSObject {
public sealed class NSDictionary : NSObject {
public int size {
get {
return storage.size;
@@ -221,7 +221,7 @@ namespace Frida.Fruity {
}
}
public class NSDictionaryRaw : NSObject {
public sealed class NSDictionaryRaw : NSObject {
public int size {
get {
return storage.size;
@@ -255,7 +255,7 @@ namespace Frida.Fruity {
}
}
public class NSArray : NSObject {
public sealed class NSArray : NSObject {
public int length {
get {
return storage.size;
@@ -279,7 +279,7 @@ namespace Frida.Fruity {
}
}
public class NSDate : NSObject {
public sealed class NSDate : NSObject {
public double time {
get;
private set;
@@ -298,7 +298,7 @@ namespace Frida.Fruity {
}
}
public class NSError : NSObject {
public sealed class NSError : NSObject {
public NSString domain {
get;
private set;
@@ -321,7 +321,7 @@ namespace Frida.Fruity {
}
}
public class DTTapMessage : NSObject {
public sealed class DTTapMessage : NSObject {
public NSDictionary plist {
get;
private set;
@@ -658,7 +658,7 @@ namespace Frida.Fruity {
return new DTTapMessage ((NSDictionary) decode_value (instance.get_uid ("DTTapMessagePlist"), ctx));
}
private class EncodingContext {
private sealed class EncodingContext {
public PlistArray objects;
private Gee.HashMap<string, PlistUid> classes = new Gee.HashMap<string, PlistUid> ();
@@ -709,7 +709,7 @@ namespace Frida.Fruity {
}
}
private class DecodingContext {
private sealed class DecodingContext {
public PlistArray objects;
public DecodingContext (PlistArray objects) {
+10 -10
View File
@@ -1,6 +1,6 @@
[CCode (gir_namespace = "FridaLLDB", gir_version = "1.0")]
namespace Frida.LLDB {
public class Client : GDB.Client {
public sealed class Client : GDB.Client {
public Process? process {
get {
return _process;
@@ -438,7 +438,7 @@ namespace Frida.LLDB {
}
}
public class LaunchOptions : Object {
public sealed class LaunchOptions : Object {
public string[] env {
get;
set;
@@ -457,7 +457,7 @@ namespace Frida.LLDB {
}
}
public class Process : Object {
public sealed class Process : Object {
public uint pid {
get;
set;
@@ -556,7 +556,7 @@ namespace Frida.LLDB {
ARM64E = 2,
}
public class Thread : GDB.Thread {
public sealed class Thread : GDB.Thread {
private const uint PAGE_SIZE = 16384U;
private const uint32 THREAD_MAGIC = 0x54485244U;
@@ -656,7 +656,7 @@ namespace Frida.LLDB {
return address & ~((uint64) (PAGE_SIZE - 1));
}
public class Snapshot {
public sealed class Snapshot {
public uint handle {
get;
private set;
@@ -667,7 +667,7 @@ namespace Frida.LLDB {
}
}
public class Frame {
public sealed class Frame {
public uint64 address {
get;
private set;
@@ -695,7 +695,7 @@ namespace Frida.LLDB {
}
}
public class Module : Object {
public sealed class Module : Object {
public uint64 load_address {
get;
construct;
@@ -719,7 +719,7 @@ namespace Frida.LLDB {
);
}
public class Segment {
public sealed class Segment {
public string name;
public uint64 vmaddr;
@@ -730,7 +730,7 @@ namespace Frida.LLDB {
}
}
public class Exception : GDB.Exception {
public sealed class Exception : GDB.Exception {
public MachExceptionType metype {
get;
construct;
@@ -896,7 +896,7 @@ namespace Frida.LLDB {
}
}
public class AppleDyldFields : Object {
public sealed class AppleDyldFields : Object {
public uint64 all_image_info {
get;
construct;
+1 -1
View File
@@ -1,6 +1,6 @@
[CCode (gir_namespace = "FridaFruity", gir_version = "1.0")]
namespace Frida.Fruity {
public class LockdownClient : Object {
public sealed class LockdownClient : Object {
public signal void closed ();
public PlistServiceClient service {
Loaded 100 of 223 files, more files were not shown because too many files have changed in this diff. Show more