Compare commits

...
145 Commits
Author SHA1 Message Date
Ole André Vadla Ravnås 78ff6e5b08 subprojects: Prepare for release 2024-07-23 10:14:56 +02:00
Ole André Vadla Ravnås 6537809897 subprojects: Bump outdated 2024-07-23 10:11:56 +02:00
Ole André Vadla Ravnås ead2ff6701 submodules: Bump releng 2024-07-23 10:11:56 +02:00
xiofee d55232fe52 fruity: Fix crash when enumerating network interfaces on Windows (#538)
Some don't have a unicast address, and need to be ignored.
2024-07-23 10:11:26 +02:00
Ole André Vadla Ravnås dab3b91f9e subprojects: Prepare for release 2024-07-22 11:49:03 +02:00
Ole André Vadla Ravnås 71f7b2f16a subprojects: Bump outdated 2024-07-22 11:37:45 +02:00
Ole André Vadla Ravnås 4cf806641f submodules: Bump releng 2024-07-22 11:37:44 +02:00
Ole André Vadla Ravnås e34a533a35 fruity: Handle devices without tunnel support on non-macOS
In the portable CoreDevice backend.
2024-07-22 11:28:23 +02:00
Ole André Vadla Ravnås 6b56c88295 fruity: Use UsbmuxDevice from USB transport if present
So we can reach the loopback interface, and for better performance.
2024-07-19 23:10:15 +02:00
Ole André Vadla Ravnås d810111f1e fruity: Expose name from USB transport if present
It has a more descriptive name in case of UsbmuxTransport.
2024-07-19 23:09:42 +02:00
Ole André Vadla Ravnås 3d17ad39da subprojects: Prepare for release 2024-07-17 22:43:10 +02:00
Ole André Vadla Ravnås 429607e7e3 xpc-client: Wire up cancellable in request()
As we can't cancel the request itself, we have to cancel the connection.
2024-07-17 22:34:24 +02:00
Ole André Vadla Ravnås 6ef660718a subprojects: Bump outdated 2024-07-17 22:10:01 +02:00
Ole André Vadla Ravnås cf61fda141 subprojects: Prepare for release 2024-07-16 15:24:54 +02:00
Ole André Vadla Ravnås b272dda27d subprojects: Bump outdated 2024-07-16 15:20:35 +02:00
Ole André Vadla Ravnås 300d176e85 ci: Re-enable tests on macOS 2024-07-16 15:14:43 +02:00
Ole André Vadla Ravnås e7f045bbe9 darwin: Await ObjC init on macOS Sequoia and iOS 18
By making use of notifyObjCInit() if available.
2024-07-16 11:45:16 +02:00
Ole André Vadla Ravnås 0b6abfeb7c darwin: Handle dyld restart on macOS Sequoia and iOS 18 2024-07-16 11:12:02 +02:00
Ole André Vadla Ravnås c17c6e31bc tests: Avoid relying on executable name on Darwin 2024-07-16 11:06:55 +02:00
Ole André Vadla Ravnås 0825aab1d0 fruity: Improve CoreDevice pairing support
- Fix support for multiple pairing relationships.
- Keep the in-memory peer store up-to-date, so new pairing relationships
  don't require a process restart to be able to match them up with
  pairing services on the network.
2024-07-15 14:41:03 +02:00
Ole André Vadla Ravnås be65296610 ncm: Fix a stylistic inconsistency 2024-07-15 13:24:16 +02:00
Ole André Vadla Ravnås 0a6002a3ce ncm: Avoid using a broken kernel NCM driver
Where only one of the two network interfaces exist, i.e. the tethering
interface.
2024-07-15 13:03:49 +02:00
Ole André Vadla Ravnås a3deb22999 ncm: Detach all drivers before changing configuration
We would previously only try to detach for the data interface, which
makes no sense if that interface is on a different configuration.
2024-07-15 12:54:14 +02:00
Ole André Vadla Ravnås 5aeb800a7a subprojects: Prepare for release 2024-07-13 00:34:04 +02:00
Ole André Vadla Ravnås a01f5dcd3d subprojects: Bump outdated 2024-07-13 00:06:51 +02:00
Ole André Vadla Ravnås 23b15b5f4b ncm: Switch USB device configuration if needed 2024-07-12 15:31:43 +02:00
Ole André Vadla Ravnås f1fdd980aa fruity: Add support for networked devices on Windows
By making use of DnsServiceBrowse() if the OS supports it -- which means
Windows 10 and newer.
2024-07-12 15:29:15 +02:00
Ole André Vadla Ravnås 05a68332f6 network-stack: Fix TcpConnection use-after-free
When lwIP notifies us about the PCB being closed or an error, we must
clear its user data so any future callbacks don't end up using the
TcpConnection after it's gone.
2024-07-12 00:06:17 +02:00
Ole André Vadla Ravnås 13521724f7 fruity: Remove commented-out variable 2024-07-11 23:57:55 +02:00
Ole André Vadla Ravnås 6c700a511e fruity: Split out DnsPacketReader 2024-07-11 23:14:01 +02:00
Ole André Vadla Ravnås 02ccafe516 fruity: Move LinuxPairingBrowser to ResolveService
Which is simpler and avoids some roundtrips to systemd-resolved.
2024-07-11 23:09:08 +02:00
Ole André Vadla Ravnås fb672d7a0b ci: Move the macOS x86_64 job to macos-latest
As the macos-11 runner is gone.

Also skip running tests on macOS entirely for now, as a stopgap until
__CFInitialize() has been dealt with.
2024-07-11 15:13:14 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 81fbfe2ab5 fruity: Add support for networked devices on Linux
By making use of systemd-resolved for mDNS-SD lookups.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-11 15:09:12 +02:00
Ole André Vadla Ravnås 3aef106ec2 fruity: Fix the LWIP.NetworkInterface bindings
Where we would end up passing in a copy of the struct and have e.g.
neighbor discovery timers make use of dangling pointers.
2024-07-11 15:09:12 +02:00
Ole André Vadla Ravnås 370f1836a7 dtx: Fix teardown of DTXConnection vs. DTXChannel
So channels never make use of the connection once it's gone.
2024-07-11 15:09:12 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 70bb82bb5d fruity: Remove forgotten .pcap debug output
Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-11 15:09:12 +02:00
Ole André Vadla Ravnås dc43be94c5 buffer: Add BufferReader 2024-07-11 15:09:12 +02:00
Ole André Vadla Ravnås 7c7367b010 buffer: Add content validation to read_fixed_string()
To support parsing untrusted data.
2024-07-11 15:09:12 +02:00
Ole André Vadla Ravnås a9073c07eb buffer: Add content validation to read_string()
To support parsing untrusted data.
2024-07-11 15:09:12 +02:00
Ole André Vadla Ravnås fd5a274680 subprojects: Prepare for release 2024-07-08 14:27:06 +02:00
Ole André Vadla Ravnås d3f949a51c subprojects: Bump outdated 2024-07-08 14:25:06 +02:00
Ole André Vadla Ravnås 6d3ea5f589 fruity: Clean up OS-specific bits 2024-07-08 14:24:29 +02:00
Ole André Vadla Ravnås 3f6b41dc8c fruity: Handle libusb failing to initialize
Which may happen due to insufficient privileges, stripped down
environments such as containers, etc.
2024-07-08 10:26:46 +02:00
Ole André Vadla Ravnås 2c23afacfd subprojects: Prepare for release 2024-07-06 00:07:28 +02:00
Ole André Vadla Ravnås 51bf048d5b subprojects: Bump outdated 2024-07-06 00:06:32 +02:00
Ole André Vadla RavnåsandHåvard Sørbø be6a2b305c socket: Fix Host header logic in negotiate_connection()
Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-06 00:04:35 +02:00
Ole André Vadla Ravnås 5625a08fd9 device: Fix property getters for id and name
When Device is created with a custom value for either.

Due to typos the getters ended up recursing until stack overflow.
2024-07-05 23:35:47 +02:00
Ole André Vadla Ravnås 684739a1e6 subprojects: Prepare for release 2024-07-05 15:32:45 +02:00
Ole André Vadla RavnåsandHåvard Sørbø e0c36e6826 fruity: Retry RSD port lookup on failure
Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-05 15:31:42 +02:00
Ole André Vadla RavnåsandHåvard Sørbø eeb0c7a50a fruity: Fix gadget upload when no usbmux connection is available
By listening on all interfaces, not just loopback, so we can connect to
it across the tunnel.

Also switch to IPv6 while at it.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-05 15:22:40 +02:00
Ole André Vadla RavnåsandHåvard Sørbø f2dc84324a fruity: Skip fetching dyld symbols if libSystem is initialized
We only need them for early instrumentation.

This means we can attach to a running app not spawned by Frida, even on
latest iOS versions where dyld restarts.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-05 14:22:26 +02:00
Ole André Vadla RavnåsandHåvard Sørbø b9d07f0bfb fruity: Wire up MacOSCoreDeviceTransport event handling
Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-05 13:55:34 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 8b54716bfc fruity: Ensure provider name doesn't mutate
In case of a transport departing and taking the string storage with it.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-05 13:51:59 +02:00
Ole André Vadla Ravnås 68bfde7ae0 xpc-object-reader: Add get_uuid_value() 2024-07-05 13:50:57 +02:00
Ole André Vadla RavnåsandHåvard Sørbø bcdcc090b6 device: Refactor construction and property wiring
We can compute some of the properties from the provider.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-05 13:50:19 +02:00
Ole André Vadla Ravnås 2a1a80abd9 fruity: Tweak ordering of system parameters 2024-07-05 10:44:44 +02:00
ea6307d60b fruity: Add os.build and hardware to system parameters (#534)
Co-authored-by: Ole André Vadla Ravnås <[email protected]>
Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-05 10:10:17 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 2bf45ececd fruity: Await ObjC runtime initialization on iOS >= 18
By making use of notifyObjCInit() if available.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-04 15:20:51 +02:00
Ole André Vadla RavnåsandHåvard Sørbø d6b502eb3e fruity: Add support for dyld restart on iOS >= 18
Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-04 14:56:51 +02:00
Ole André Vadla Ravnås 0de45afe2f meson: Auto-disable external device backends for 32-bit host machines 2024-07-04 13:49:25 +02:00
Ole André Vadla Ravnås 7262e55468 macos: Replace logging with TODOs in the CoreDevice transport 2024-07-04 13:36:01 +02:00
Ole André Vadla RavnåsandHåvard Sørbø def974818f socket: Support IPv6 addresses in negotiate_connection()
Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-04 12:51:58 +02:00
Ole André Vadla Ravnås d5312d288f pipe: Fix tvOS build regression
We need to make sure we include the Mach headers before CoreFoundation
does, so our version availability overrides are used.
2024-07-04 11:16:06 +02:00
Ole André Vadla Ravnås 7e9fb1e1c6 subprojects: Bump outdated 2024-07-03 23:20:05 +02:00
Ole André Vadla RavnåsandHåvard Sørbø e415a2ec83 fruity: Fix the macOS CoreDevice connection type logic
Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-03 14:20:35 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 248127623f tests: Add manual XPC application launching test
Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-03 13:45:09 +02:00
Ole André Vadla RavnåsandHåvard Sørbø f246b4e17d xpc-service: Support type-annotating request parameters
Represented using a `(type, value)` tuple.

This means uint64 and UUID values can be passed in.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-03 13:42:48 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 7c4633358b fruity: Improve open_channel() to support tcp:service-name
Useful for e.g. `com.apple.coredevice.openstdiosocket`.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-03 13:35:08 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 85d063ab9b fruity: Revive HostChannelProvider implementation
Removed by accident in 08e5d37348.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-03 13:33:25 +02:00
Ole André Vadla RavnåsandHåvard Sørbø a6650efecb xpc: Make add_uuid_value() expect a raw UUID
Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-03 13:31:54 +02:00
Ole André Vadla RavnåsandHåvard Sørbø d382734bca value: Remove unused UUID functionality
Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-03 13:30:29 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 08e5d37348 fruity: Rework to support userspace NCM
To support systems without a compatible NCM driver, such as contemporary
Linux kernels, Windows, etc.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-03 11:20:16 +02:00
Ole André Vadla Ravnås 6317446c37 xpc-client: Add post() 2024-07-03 11:14:41 +02:00
Ole André Vadla Ravnås 7048e851b0 xpc-client: Handle closure in open state 2024-07-03 11:14:41 +02:00
Ole André Vadla Ravnås 7d22da8d3d meson: Summarize backends and more of the features 2024-07-03 11:14:41 +02:00
Ole André Vadla Ravnås 1f164564ef meson: Auto-disable external device backends on non-desktop 2024-07-03 11:14:41 +02:00
Ole André Vadla Ravnås 47a2e6728b submodules: Bump releng 2024-07-03 11:14:36 +02:00
Ole André Vadla Ravnås b19333420c web-service: Listen on dynamic interfaces last
So that specifying e.g. 0.0.0.0 takes precedence and won't cause start()
to fail.
2024-07-03 10:47:09 +02:00
Ole André Vadla Ravnås 29ec9f0c98 tunnel-interface-observer: Fix confusing variable name
The tunnel isn't only for development tools.
2024-07-03 10:43:02 +02:00
Ole André Vadla Ravnås cbcb7f37bf gadget: Integrate TunnelInterfaceObserver
So we listen on Apple's CoreDevice tunnel network interfaces on iOS and
tvOS.
2024-07-02 22:50:09 +02:00
Ole André Vadla Ravnås f53230bd7a control-service: Integrate TunnelInterfaceObserver
So we listen on Apple's CoreDevice tunnel network interfaces on iOS and
tvOS.
2024-07-02 22:50:09 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 39486a5331 netif: Add TunnelInterfaceObserver for iOS and tvOS
For observing Apple's CoreDevice tunnel network interfaces. Intended for
ControlService (frida-server) and frida-gadget to be able to listen on
such interfaces as they arrive and depart.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-02 22:50:05 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 67f6895e13 base: Add an iterable CFArray wrapper
Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-02 22:26:15 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 1b80ce0779 vapi: Improve the CoreFoundation bindings
Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-02 22:26:15 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 9bd3c3974f web-service: Support dynamic network interfaces
By providing a DynamicInterfaceObserver with the desired behavior.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-02 22:26:12 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 055fe8744a socket: Remove the partial NECP integration
It's not a good fit for keeping track of network interfaces.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-07-02 14:00:35 +02:00
Ole André Vadla RavnåsandHåvard Sørbø a0f7df8d0e socket: Sketch a partial NECP integration
In pursuit of notifications when network interfaces arrive and depart.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-06-28 14:14:01 +02:00
Ole André Vadla Ravnås 4b5fe35b00 devkit: Also install frida-core.gir 2024-06-07 09:54:32 +02:00
Håvard Sørbø 9330f02ca5 xpc-service: Fix handling of request() with arrays (#532)
Where we forgot to call begin/end to actually generate an array, and
would end up generating an invalid XPC object.
2024-06-06 22:46:35 +02:00
Ole André Vadla Ravnås 5d23227efc subprojects: Prepare for release 2024-06-04 14:14:40 +02:00
Ole André Vadla Ravnås 300a55b75c subprojects: Bump outdated 2024-06-04 14:12:37 +02:00
Ole André Vadla Ravnås f2e071ed78 subprojects: Prepare for release 2024-06-04 13:41:11 +02:00
Ole André Vadla Ravnås bc7f73b492 subprojects: Bump outdated 2024-06-04 13:38:40 +02:00
f91a3c92fe darwin: Avoid thread_set_state() during injection (#530)
So we don't get killed by the system on e.g. macOS >= 14.5.

We can create the thread in running state. There is no need to keep it
suspended until we have created the dispatch source.

Co-authored-by: Håvard Sørbø <[email protected]>
Co-authored-by: Ole André Vadla Ravnås <[email protected]>
2024-06-04 13:36:31 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 6eacc889cd fruity: Perform RSDCheckin on services that need it
In this way we retain backwards-compatibility for open_channel() of
lockdown services when a CoreDevice tunnel is available.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-06-04 12:27:57 +02:00
Ole André Vadla RavnåsandHåvard Sørbø d21ba21aea fruity: Stop caching the LockdownClient
To avoid issues with multiple consumers.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-06-04 11:34:55 +02:00
Ole André Vadla Ravnås cfcdc26d29 subprojects: Prepare for release 2024-05-31 22:52:22 +02:00
Ole André Vadla Ravnås 69555bbbb6 subprojects: Bump outdated 2024-05-31 22:50:47 +02:00
Ole André Vadla Ravnås d2d014c081 subprojects: Prepare for release 2024-05-31 15:42:49 +02:00
Ole André Vadla Ravnås 8f9c30953b subprojects: Bump outdated 2024-05-31 15:41:33 +02:00
Ole André Vadla Ravnås 2396ad5717 fruity: Remove temporary debug helpers
Useful during bring-up, but not so much anymore.
2024-05-31 14:14:27 +02:00
Ole André Vadla Ravnås ded45c9c93 fruity: Remove the xpc-test program
It has served its purpose. We now have tests that can be run instead.
2024-05-31 14:10:28 +02:00
Ole André Vadla Ravnås 8d375b5e46 fruity: Avoid leaking Posix types into the public API 2024-05-31 14:08:52 +02:00
Ole André Vadla Ravnås 1722429383 subprojects: Bump outdated 2024-05-31 06:45:37 +02:00
Ole André Vadla Ravnås ffd23574a9 submodules: Bump releng 2024-05-31 06:45:36 +02:00
Ole André Vadla Ravnås 5a8bd3fbaf meson: Add new Fruity private requirements to .pc 2024-05-31 00:06:55 +02:00
Ole André Vadla Ravnås 56605717ad meson: Fix build when glib-networking is a subproject 2024-05-30 23:15:15 +02:00
Ole André Vadla Ravnås d8a7c7d3fb subprojects: Bump outdated 2024-05-30 21:58:55 +02:00
Ole André Vadla Ravnås 39725e427b ci: Fix apt-get steps in the native and cross jobs
Need to update the database before installing.
2024-05-30 21:58:13 +02:00
Ole André Vadla Ravnås 7fe3a00543 subprojects: Bump outdated 2024-05-30 21:50:35 +02:00
Ole André Vadla Ravnås 41c31ba0a0 subprojects: Bump outdated 2024-05-30 21:42:28 +02:00
Ole André Vadla Ravnås c8e1ebdb7c ci: Allow Corellium test steps to fail for now
Until we figure out the stability issue.
2024-05-30 21:28:33 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 3a678a3553 meson: Fix build when connectivity deps are subprojects
Co-authored-by: Håvard Sørbø <[email protected]>
2024-05-30 21:28:33 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 2048115cb3 meson: Change connectivity option default to enabled
So fallbacks trigger, and we build with the same features irrespective
of whether we build with a Frida SDK present.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-05-30 21:28:33 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 82a68e55cc fruity: Add RemoteXPC support
With two platform integrations:

- macOS: where we use Apple's tunnel, by talking to remotepairingd and
  creating an assertion to ensure the tunnel is up and stays up for as
  long as we need it. The challenging part here was figuring out the
  device-side RemoteServiceDiscovery (RSD) port inside the tunnel, as
  it appears no API exposes it. Our solution is to ask the kernel for
  a list of TCP sockets, and picking out the ones where the foreign
  address is the device-side IPv6 address inside the tunnel, **and**
  where the process that created the socket is remoted. This seems to
  consistenly result in us finding a single socket, connected to the RSD
  port, but we try all of them in case this behavior ends up changing.
- Linux: where we open our own tunnel, assuming the iDevice has been
  mode-switched (e.g. by usbmuxd), and the Linux CDC NCM driver has been
  patched something along the lines of:
  https://lore.kernel.org/all/[email protected]/T/

We don't yet have a platform integration for Windows, as Apple's
software doesn't currently set up a tunnel. The official driver also
appears to keep the USB device busy, meaning we can't easily trigger
a mode-switch. This is an area that needs more research.

Another area that needs future improvement is that we only support
cabled connectivity on macOS. This should be easy to improve on once we
have updated frida-server and frida-gadget so they listen on tunnel
interfaces whenever they appear.

Kudos to @doronz88 for figuring out most of the protocol bits that we
needed.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-05-30 21:28:33 +02:00
Ole André Vadla RavnåsandHåvard Sørbø e0d6c29c41 meson: Add wrap for lwip
Co-authored-by: Håvard Sørbø <[email protected]>
2024-05-30 21:28:33 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 1f820ae2ac meson: Add wrap for ngtcp2
Co-authored-by: Håvard Sørbø <[email protected]>
2024-05-30 21:28:33 +02:00
Ole André Vadla RavnåsandHåvard Sørbø c0bc5f5bd9 base: Add helpers for handling JSON and GLib.Variant
Co-authored-by: Håvard Sørbø <[email protected]>
2024-05-30 21:28:33 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 7ab0cf75ea fruity: Fix spawn() on jailed iOS 17
The jailed equivalent of 827eee33cc.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-05-30 21:28:33 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 2175cc756a dtx: Use more appropriate GValue setter for NSObject
Co-authored-by: Håvard Sørbø <[email protected]>
2024-05-30 21:28:33 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 90d60683dd dtx: Make DTXArgumentList elements visible to consumers
Co-authored-by: Håvard Sørbø <[email protected]>
2024-05-30 21:28:33 +02:00
Ole André Vadla RavnåsandHåvard Sørbø cf09ba46e4 dtx: Allow notification payload to be of any type
The value is not always an NSDictionary, e.g. in case of a DTTapMessage.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-05-30 21:28:33 +02:00
Ole André Vadla RavnåsandHåvard Sørbø ed9fcb10c1 dtx: Fix channel code interpretation for inbound invokes
Co-authored-by: Håvard Sørbø <[email protected]>
2024-05-30 21:28:33 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 333ca2f852 dtx: Bump max message size to 128 MB
Screenshots can be quite large, and we might in theory be asked to fetch
large files.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-05-30 21:28:33 +02:00
Ole André Vadla RavnåsandHåvard Sørbø c9e541cc0e keyed-archive: Add support for decoding DTTapMessage
And its subclasses.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-05-30 21:28:33 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 3e86270d77 keyed-archive: Add support for encoding NSArray
Co-authored-by: Håvard Sørbø <[email protected]>
2024-05-30 21:28:33 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 8a21929415 keyed-archive: Add NSArray.add_object()
Co-authored-by: Håvard Sørbø <[email protected]>
2024-05-30 21:28:33 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 4865ea07eb keyed-archive: Add support for decoding NSData
Co-authored-by: Håvard Sørbø <[email protected]>
2024-05-30 21:28:33 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 28f7895704 keyed-archive: Improve NSNumber support
So boolean/float/double values are treated distinctly from int64.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-05-30 21:28:33 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 859d6cd7de plist: Fix support for float and double in to_binary()
Co-authored-by: Håvard Sørbø <[email protected]>
2024-05-30 21:28:33 +02:00
Ole André Vadla Ravnås b71c861b1d subprojects: Bump outdated 2024-05-30 20:51:53 +02:00
Ole André Vadla Ravnås b486936b33 submodules: Bump releng 2024-05-30 20:51:53 +02:00
Ole André Vadla Ravnås 5b587f587f base: Add Numeric.int64_{hash,equal}() 2024-05-29 23:18:13 +02:00
Ole André Vadla Ravnås 39e2c7bf81 subprojects: Prepare for release 2024-05-21 12:50:31 +02:00
Ole André Vadla Ravnås 2b82c21df1 subprojects: Bump outdated 2024-05-21 12:48:55 +02:00
Ole André Vadla Ravnås e45989dbdf subprojects: Prepare for release 2024-05-20 22:54:26 +02:00
Ole André Vadla Ravnås 204b16a4b7 compat: Escape spaces in depfile paths
Quoting isn't supported, so we should be escaping the spaces instead.
2024-05-20 22:50:29 +02:00
Ole André Vadla Ravnås d9f33a918e meson: Find DbgHelp and SymSrv using Gum's variables 2024-05-20 22:41:48 +02:00
Ole André Vadla Ravnås 082b100ab9 subprojects: Bump outdated 2024-05-20 22:40:31 +02:00
Ole André Vadla Ravnås 20cdf64312 meson: Fix vapidir exported in our .pc 2024-05-20 22:39:15 +02:00
Ole André Vadla Ravnås 0bb558e2a1 meson: Refactor the (un)installed variables logic 2024-05-20 22:37:59 +02:00
Ole André Vadla Ravnås 04f22126a7 subprojects: Prepare for release 2024-05-18 23:04:59 +02:00
Ole André Vadla Ravnås 59deab2ea9 subprojects: Bump outdated 2024-05-18 22:57:58 +02:00
Ole André Vadla Ravnås 1b9e347650 submodules: Bump releng 2024-05-18 22:57:58 +02:00
Ole André Vadla Ravnås 5e149a3f2d compat: Forward yielding built-in options when subproject
So that the parent project's machine-neutral built-in options such as
`prefix` are used.
2024-05-18 22:50:57 +02:00
78 changed files with 14323 additions and 1135 deletions

No files matched your search

+9 -4
View File
@@ -18,7 +18,7 @@ jobs:
include:
- { id: windows-x86_64, runner: '"windows-latest"' }
- { id: windows-x86, runner: '"windows-latest"' }
- { id: macos-x86_64, runner: '"macos-11"' }
- { id: macos-x86_64, runner: '"macos-latest"' }
- { id: macos-arm64, runner: '"macos-latest"' }
- { id: linux-x86_64, runner: '"ubuntu-latest"' }
- { id: linux-x86, runner: '"ubuntu-latest"' }
@@ -42,7 +42,9 @@ jobs:
run: sudo security authorizationdb write system.privilege.taskport allow
- name: Install gcc-multilib
if: matrix.id == 'linux-x86'
run: sudo apt-get install gcc-multilib lib32stdc++-11-dev
run: |
sudo apt-get update
sudo apt-get install gcc-multilib lib32stdc++-11-dev
- name: Build
if: ${{ startsWith(matrix.id, 'windows-') }}
run: |
@@ -66,7 +68,6 @@ jobs:
name: core-devkit-${{ matrix.id }}
path: build/src/devkit/
- name: Test
if: matrix.id != 'macos-arm64'
run: make test
cross:
@@ -87,7 +88,9 @@ jobs:
with:
submodules: recursive
- name: Install toolchain
run: sudo apt-get install ${{ matrix.pkg }}
run: |
sudo apt-get update
sudo apt-get install ${{ matrix.pkg }}
- name: Build
run: |
./configure ${{ matrix.opts }} ${{ env.FRIDA_CORE_OPTIONS }}
@@ -177,6 +180,7 @@ jobs:
tar -C /tmp/pkg -czf /tmp/runner.tar.gz .
- name: Test on Corellium iOS device
if: matrix.id == 'ios-arm64'
continue-on-error: true
uses: frida/corellium-action@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
@@ -192,6 +196,7 @@ jobs:
./frida-tests
- name: Test on Corellium Android device
if: matrix.id == 'android-arm64'
continue-on-error: true
uses: frida/corellium-action@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
+7 -5
View File
@@ -432,7 +432,7 @@ def compile(privdir: Path, state: State):
path = Path(raw_path)
if not path.is_absolute():
path = Path(os.path.relpath(workdir / path, top_builddir))
input_entries.append(quote(path.as_posix()))
input_entries.append(escape_depfile_path(path.as_posix()))
depfile_lines.append(f"{output_relpath}: {' '.join(input_entries)}")
(state.builddir / DEPFILE_FILENAME).write_text("\n".join(depfile_lines), encoding="utf-8")
@@ -480,6 +480,10 @@ def option_should_be_forwarded(k: "OptionKey",
return False
if not str(v.value):
return False
if not is_for_child and role == "subproject" and k.subproject in {"", our_project_id}:
if not coredata.BUILTIN_OPTIONS[k.as_root()].yielding:
return k.subproject == our_project_id
return True
if k.module == "python":
if k.name == "install_env" and v.value == "prefix":
@@ -519,10 +523,8 @@ def scrub_windows_devenv_dirs_from_path(raw_path: str, env: Mapping[str, str]) -
return ";".join(clean_entries)
def quote(path: str) -> str:
if " " not in path:
return path
return "\"" + path.replace ("\"", "\\\"") + "\""
def escape_depfile_path(path: str) -> str:
return path.replace(" ", "\\ ")
def query_releng_location(role: Role) -> Path:
+135 -9
View File
@@ -428,21 +428,28 @@ namespace Frida {
return *((double *) &bits);
}
public string read_string (size_t offset) {
public string read_string (size_t offset) throws Error {
string * start = (string *) get_pointer (offset, sizeof (char));
size_t max_length = size - offset;
string * val = (string *) get_pointer (offset, sizeof (char));
string * end = memchr (val, 0, max_length);
assert (end != null);
size_t size = end - val;
return val->substring (0, (long) size);
string * end = memchr (start, 0, max_length);
if (end == null)
throw new Error.PROTOCOL ("Missing null character");
size_t size = end - start;
string val = start->substring (0, (long) size);
if (!val.validate ())
throw new Error.PROTOCOL ("Invalid UTF-8 string");
return val;
}
[CCode (cname = "memchr", cheader_filename = "string.h")]
private extern static string * memchr (string * s, int c, size_t n);
public string read_fixed_string (size_t offset, size_t size) {
string * val = (string *) get_pointer (offset, size);
return val->substring (0, (long) size);
public string read_fixed_string (size_t offset, size_t size) throws Error {
string * start = (string *) get_pointer (offset, size);
string val = start->substring (0, (long) size);
if (!val.validate ())
throw new Error.PROTOCOL ("Invalid UTF-8 string");
return val;
}
public unowned Buffer write_string (size_t offset, string val) {
@@ -458,4 +465,123 @@ namespace Frida {
return data + offset;
}
}
public class BufferReader {
public size_t available {
get {
return buffer.bytes.get_size () - offset;
}
}
private Buffer buffer;
private size_t offset = 0;
public BufferReader (Buffer buf) {
buffer = buf;
}
public uint64 read_pointer (size_t offset) throws Error {
var pointer_size = buffer.pointer_size;
check_available (pointer_size);
var ptr = buffer.read_pointer (offset);
offset += pointer_size;
return ptr;
}
public int8 read_int8 () throws Error {
check_available (sizeof (int8));
var val = buffer.read_int8 (offset);
offset += sizeof (int8);
return val;
}
public uint8 read_uint8 () throws Error {
check_available (sizeof (uint8));
var val = buffer.read_uint8 (offset);
offset += sizeof (uint8);
return val;
}
public int16 read_int16 () throws Error {
check_available (sizeof (int16));
var val = buffer.read_int16 (offset);
offset += sizeof (int16);
return val;
}
public uint16 read_uint16 () throws Error {
check_available (sizeof (uint16));
var val = buffer.read_uint16 (offset);
offset += sizeof (uint16);
return val;
}
public int32 read_int32 () throws Error {
check_available (sizeof (int32));
var val = buffer.read_int32 (offset);
offset += sizeof (int32);
return val;
}
public uint32 read_uint32 () throws Error {
check_available (sizeof (uint32));
var val = buffer.read_uint32 (offset);
offset += sizeof (uint32);
return val;
}
public int64 read_int64 () throws Error {
check_available (sizeof (int64));
var val = buffer.read_int64 (offset);
offset += sizeof (int64);
return val;
}
public uint64 read_uint64 () throws Error {
check_available (sizeof (uint64));
var val = buffer.read_uint64 (offset);
offset += sizeof (uint64);
return val;
}
public float read_float () throws Error {
check_available (sizeof (float));
var val = buffer.read_float (offset);
offset += sizeof (float);
return val;
}
public double read_double () throws Error {
check_available (sizeof (double));
var val = buffer.read_double (offset);
offset += sizeof (double);
return val;
}
public string read_string () throws Error {
check_available (1);
var val = buffer.read_string (offset);
offset += val.length + 1;
return val;
}
public string read_fixed_string (size_t size) throws Error {
check_available (size);
var val = buffer.read_fixed_string (offset, size);
offset += size;
return val;
}
public Bytes read_bytes (size_t size) throws Error {
check_available (size);
var val = buffer.bytes[offset:offset + size];
offset += size;
return val;
}
private void check_available (size_t n) throws Error {
if (available < n)
throw new Error.PROTOCOL ("Malformed buffer: truncated");
}
}
}
+34
View File
@@ -0,0 +1,34 @@
namespace Frida {
public class CFArray<T> {
private CoreFoundation.Array handle;
public static CFArray<T> wrap<T> (void * handle) {
return new CFArray<T> ((CoreFoundation.Array) handle);
}
private CFArray (CoreFoundation.Array handle) {
this.handle = handle;
}
public Iterator<T> iterator () {
return new Iterator<T> (handle);
}
public class Iterator<T> {
public CoreFoundation.Array handle;
private CoreFoundation.Index i = 0;
private CoreFoundation.Index length;
internal Iterator (CoreFoundation.Array arr) {
handle = arr;
length = arr.length;
}
public unowned T? next_value () {
if (i == length)
return null;
return handle[i++];
}
}
}
}
+51
View File
@@ -0,0 +1,51 @@
#include "frida-darwin.h"
gpointer
_frida_dispatch_retain (gpointer object)
{
dispatch_retain (object);
return object;
}
void
_frida_xpc_connection_set_event_handler (xpc_connection_t connection, FridaXpcHandler handler, gpointer user_data)
{
xpc_connection_set_event_handler (connection, ^(xpc_object_t object)
{
handler (object, user_data);
});
}
void
_frida_xpc_connection_send_message_with_reply (xpc_connection_t connection, xpc_object_t message, dispatch_queue_t replyq,
FridaXpcHandler handler, gpointer user_data, GDestroyNotify notify)
{
xpc_connection_send_message_with_reply (connection, message, replyq, ^(xpc_object_t object)
{
handler (object, user_data);
if (notify != NULL)
notify (user_data);
});
}
gchar *
_frida_xpc_object_to_string (xpc_object_t object)
{
gchar * result;
char * str;
str = xpc_copy_description (object);
result = g_strdup (str);
free (str);
return result;
}
gboolean
_frida_xpc_dictionary_apply (xpc_object_t dict, FridaXpcDictionaryApplier applier, gpointer user_data)
{
return xpc_dictionary_apply (dict, ^bool (const char * key, xpc_object_t val)
{
return applier (key, val, user_data);
});
}
+22
View File
@@ -0,0 +1,22 @@
#ifndef __FRIDA_DARWIN_H__
#define __FRIDA_DARWIN_H__
#ifdef HAVE_MACOS
#include <glib.h>
#include <xpc/xpc.h>
typedef void (* FridaXpcHandler) (xpc_object_t object, gpointer user_data);
typedef gboolean (* FridaXpcDictionaryApplier) (const gchar * key, xpc_object_t val, gpointer user_data);
gpointer _frida_dispatch_retain (gpointer object);
void _frida_xpc_connection_set_event_handler (xpc_connection_t connection, FridaXpcHandler handler, gpointer user_data);
void _frida_xpc_connection_send_message_with_reply (xpc_connection_t connection, xpc_object_t message, dispatch_queue_t replyq,
FridaXpcHandler handler, gpointer user_data, GDestroyNotify notify);
gchar * _frida_xpc_object_to_string (xpc_object_t object);
gboolean _frida_xpc_dictionary_apply (xpc_object_t dict, FridaXpcDictionaryApplier applier, gpointer user_data);
#endif
#endif
+20
View File
@@ -9,9 +9,22 @@ base_sources = [
'socket.vala',
'socket-glue.c',
'buffer.vala',
'value.vala',
]
extra_vala_args = []
if host_os == 'macos'
base_sources += [
'xpc.vala',
'frida-darwin.c',
]
endif
if host_os_family == 'darwin'
base_sources += 'corefoundation.vala'
endif
extra_deps = []
if host_os_family != 'windows'
extra_vala_args += '--pkg=gio-unix-2.0'
@@ -22,6 +35,13 @@ base_vala_args = [gum_vala_args, '--pkg=gio-2.0', '--pkg=json-glib-1.0']
if nice_dep.found()
base_vala_args += '--pkg=nice'
endif
if host_os_family == 'darwin'
base_vala_args += [
'--pkg=corefoundation',
'--pkg=darwin-gcd',
'--pkg=darwin-xpc',
]
endif
base = static_library('frida-base-' + api_version, base_sources,
c_args: frida_component_cflags,
+2 -15
View File
@@ -774,25 +774,12 @@ namespace Frida {
protected extern void _handle_transport_packet (uint8[] data);
protected int _emit_transport_packet (uint8[] data) {
var v = OutputVector ();
v.buffer = data;
v.size = data.length;
OutputVector[] vectors = { v };
var m = OutputMessage ();
m.vectors = vectors;
m.num_vectors = vectors.length;
OutputMessage[] messages = { m };
try {
transport_socket.send_messages (messages, 0, 0, io_cancellable);
Udp.send (data, transport_socket, io_cancellable);
return 0;
} catch (GLib.Error e) {
return -1;
}
return 0;
}
protected void _on_sctp_socket_events_changed () {
+11
View File
@@ -2079,6 +2079,17 @@ namespace Frida {
}
namespace Numeric {
public uint int64_hash (int64? val) {
uint64 v = (uint64) val.abs ();
return (uint) ((v >> 32) ^ (v & 0xffffffffU));
}
public bool int64_equal (int64? val_a, int64? val_b) {
int64 a = val_a;
int64 b = val_b;
return a == b;
}
public uint uint64_hash (uint64? val) {
uint64 v = val;
return (uint) ((v >> 32) ^ (v & 0xffffffffU));
+175 -55
View File
@@ -44,6 +44,59 @@ namespace Frida {
public extern void enable_nodelay (Socket socket);
}
namespace Udp {
public size_t recv (uint8[] data, DatagramBased source, Cancellable? cancellable, out InetSocketAddress remote_address)
throws Error, IOError {
var v = InputVector ();
v.buffer = data;
v.size = data.length;
InputVector[] vectors = { v };
var m = InputMessage ();
remote_address = null;
m.address = &remote_address;
m.vectors = vectors;
m.num_vectors = vectors.length;
InputMessage[] messages = { m };
try {
source.receive_messages (messages, 0, 0, cancellable);
} catch (GLib.Error e) {
throw new Error.TRANSPORT ("%s", e.message);
}
return messages[0].bytes_received;
}
public void send (uint8[] data, DatagramBased sink, Cancellable? cancellable) throws Error, IOError {
send_to (data, null, sink, cancellable);
}
public void send_to (uint8[] data, InetSocketAddress? dest_addr, DatagramBased sink, Cancellable? cancellable)
throws Error, IOError {
var v = OutputVector ();
v.buffer = data;
v.size = data.length;
OutputVector[] vectors = { v };
var m = OutputMessage ();
m.address = dest_addr;
m.vectors = vectors;
m.num_vectors = vectors.length;
OutputMessage[] messages = { m };
try {
sink.send_messages (messages, 0, 0, cancellable);
} catch (GLib.Error e) {
throw new Error.TRANSPORT ("%s", e.message);
}
}
}
public class EndpointParameters : Object {
public string? address {
get;
@@ -99,11 +152,17 @@ namespace Frida {
var request = new StringBuilder.sized (256);
request.append ("GET /ws HTTP/1.1\r\n");
string protocol = (transport == TLS) ? "wss" : "ws";
string canonical_host = canonicalize_host (host);
string uri = protocol + "://" + canonical_host + "/ws";
var msg = new Soup.Message ("GET", uri);
NetworkAddress addr;
try {
addr = NetworkAddress.parse (host, 0);
} catch (GLib.Error e) {
throw new Error.INVALID_ARGUMENT ("%s", e.message);
}
uint16 port = addr.get_port ();
var uri = Uri.build (UriFlags.NONE, protocol, null, addr.get_hostname (), (port != 0) ? port : -1, "/ws", null, null);
var msg = new Soup.Message.from_uri ("GET", uri);
Soup.websocket_client_prepare_handshake (msg, origin, null, null);
msg.request_headers.replace ("Host", canonical_host);
msg.request_headers.replace ("Host", make_host_header_value (uri));
msg.request_headers.replace ("User-Agent", "Frida/" + _version_string ());
msg.request_headers.foreach ((name, val) => {
request.append (name + ": " + val + "\r\n");
@@ -167,13 +226,12 @@ namespace Frida {
return connection;
}
private string canonicalize_host (string raw_host) {
if (raw_host.has_suffix (":80") || raw_host.has_suffix (":443")) {
string[] tokens = raw_host.split (":", 2);
return tokens[0];
}
return raw_host;
private string make_host_header_value (Uri uri) {
unowned string host = uri.get_host ();
if (!Hostname.is_ip_address (host))
return host;
var inet_addr = new InetAddress.from_string (host);
return (inet_addr.get_family () == IPV6) ? @"[$host]" : host;
}
public class WebService : Object {
@@ -195,14 +253,20 @@ namespace Frida {
default = FAIL;
}
public DynamicInterfaceObserver? dynamic_interface_observer {
get;
construct;
}
public SocketAddress? listen_address {
get {
return _listen_address;
}
}
private Soup.Server? server;
private Soup.Server? main_server;
private SocketAddress? _listen_address;
private Gee.Map<string, Soup.Server> dynamic_interface_servers = new Gee.HashMap<string, Soup.Server> ();
private Cancellable io_cancellable = new Cancellable ();
@@ -210,11 +274,12 @@ namespace Frida {
private MainContext? dbus_context;
public WebService (EndpointParameters endpoint_params, WebServiceFlavor flavor,
PortConflictBehavior on_port_conflict = FAIL) {
PortConflictBehavior on_port_conflict = FAIL, DynamicInterfaceObserver? dynif_observer = null) {
Object (
endpoint_params: endpoint_params,
flavor: flavor,
on_port_conflict: on_port_conflict
on_port_conflict: on_port_conflict,
dynamic_interface_observer: dynif_observer
);
}
@@ -250,23 +315,11 @@ namespace Frida {
}
private async SocketAddress do_start (Cancellable? cancellable) throws Error, IOError {
server = (Soup.Server) Object.new (typeof (Soup.Server),
"tls-certificate", endpoint_params.certificate);
server.add_websocket_handler ("/ws", endpoint_params.origin, null, on_websocket_opened);
if (endpoint_params.asset_root != null)
server.add_handler (null, on_asset_request);
main_server = create_server ();
SocketAddress? first_effective_address = null;
SocketConnectable connectable = (flavor == CONTROL)
? parse_control_address (endpoint_params.address, endpoint_params.port)
: parse_cluster_address (endpoint_params.address, endpoint_params.port);
Soup.ServerListenOptions listen_options = (endpoint_params.certificate != null)
? Soup.ServerListenOptions.HTTPS
: 0;
SocketAddress? first_effective_address = null;
var enumerator = connectable.enumerate ();
while (true) {
SocketAddress? address;
@@ -281,29 +334,10 @@ namespace Frida {
SocketAddress? effective_address = null;
InetSocketAddress? inet_address = address as InetSocketAddress;
if (inet_address != null) {
uint16 start_port = inet_address.get_port ();
uint16 candidate_port = start_port;
do {
try {
server.listen (inet_address, listen_options);
effective_address = inet_address;
} catch (GLib.Error e) {
if (e is IOError.ADDRESS_IN_USE && on_port_conflict == PICK_NEXT) {
candidate_port++;
if (candidate_port == start_port)
throw new Error.ADDRESS_IN_USE ("Unable to bind to any port");
if (candidate_port == 0)
candidate_port = 1024;
inet_address = new InetSocketAddress (inet_address.get_address (),
candidate_port);
} else {
throw_listen_error (e);
}
}
} while (effective_address == null);
effective_address = listen_on_inet_address (inet_address, main_server);
} else {
try {
server.listen (address, listen_options);
main_server.listen (address, compute_listen_options ());
effective_address = address;
} catch (GLib.Error e) {
throw_listen_error (e);
@@ -317,9 +351,85 @@ namespace Frida {
if (first_effective_address == null)
throw new Error.NOT_SUPPORTED ("Unable to resolve listening address");
if (dynamic_interface_observer != null) {
dynamic_interface_observer.interface_attached.connect (on_dynamic_interface_attached);
dynamic_interface_observer.interface_detached.connect (on_dynamic_interface_detached);
dynamic_interface_observer.start ();
}
return first_effective_address;
}
private void on_dynamic_interface_attached (string name, InetAddress ip) {
uint16 port = endpoint_params.port;
if (port == 0)
port = (flavor == CONTROL) ? DEFAULT_CONTROL_PORT : DEFAULT_CLUSTER_PORT;
var server = create_server ();
try {
listen_on_inet_address (new InetSocketAddress (ip, port), server);
} catch (Error e) {
return;
}
dynamic_interface_servers[name] = server;
}
private void on_dynamic_interface_detached (string name, InetAddress ip) {
Soup.Server server;
if (dynamic_interface_servers.unset (name, out server))
destroy_server (server);
}
private Soup.Server create_server () {
var server = (Soup.Server) Object.new (typeof (Soup.Server),
"tls-certificate", endpoint_params.certificate);
server.add_websocket_handler ("/ws", endpoint_params.origin, null, on_websocket_opened);
if (endpoint_params.asset_root != null)
server.add_handler (null, on_asset_request);
return server;
}
private void destroy_server (Soup.Server server) {
if (endpoint_params.asset_root != null)
server.remove_handler ("/");
server.remove_handler ("/ws");
server.disconnect ();
}
private Soup.ServerListenOptions compute_listen_options () {
return (endpoint_params.certificate != null)
? Soup.ServerListenOptions.HTTPS
: 0;
}
private InetSocketAddress listen_on_inet_address (InetSocketAddress address, Soup.Server server) throws Error {
InetSocketAddress candidate_address = address;
uint16 start_port = address.get_port ();
uint16 candidate_port = start_port;
do {
try {
server.listen (candidate_address, compute_listen_options ());
return candidate_address;
} catch (GLib.Error e) {
if (e is IOError.ADDRESS_IN_USE && on_port_conflict == PICK_NEXT) {
candidate_port++;
if (candidate_port == start_port)
throw new Error.ADDRESS_IN_USE ("Unable to bind to any port");
if (candidate_port == 0)
candidate_port = 1024;
candidate_address = new InetSocketAddress (candidate_address.get_address (),
candidate_port);
} else {
throw_listen_error (e);
}
}
} while (true);
}
[NoReturn]
private static void throw_listen_error (GLib.Error e) throws Error {
if (e is IOError.ADDRESS_IN_USE)
@@ -341,14 +451,17 @@ namespace Frida {
}
private void do_stop () {
if (server == null)
return;
foreach (var server in dynamic_interface_servers.values)
destroy_server (server);
dynamic_interface_servers.clear ();
if (endpoint_params.asset_root != null)
server.remove_handler ("/");
server.remove_handler ("/ws");
if (dynamic_interface_observer != null) {
dynamic_interface_observer.interface_attached.disconnect (on_dynamic_interface_attached);
dynamic_interface_observer.interface_detached.disconnect (on_dynamic_interface_detached);
}
server.disconnect ();
if (main_server != null)
destroy_server (main_server);
}
private void on_websocket_opened (Soup.Server server, Soup.ServerMessage msg, string path,
@@ -662,6 +775,13 @@ namespace Frida {
PICK_NEXT
}
public interface DynamicInterfaceObserver : Object {
public signal void interface_attached (string name, InetAddress ip);
public signal void interface_detached (string name, InetAddress ip);
public abstract void start ();
}
public extern static unowned string _version_string ();
private class WebConnection : IOStream {
+386
View File
@@ -0,0 +1,386 @@
namespace Frida {
public interface ObjectBuilder : Object {
public abstract unowned ObjectBuilder begin_dictionary ();
public abstract unowned ObjectBuilder set_member_name (string name);
public abstract unowned ObjectBuilder end_dictionary ();
public abstract unowned ObjectBuilder begin_array ();
public abstract unowned ObjectBuilder end_array ();
public abstract unowned ObjectBuilder add_null_value ();
public abstract unowned ObjectBuilder add_bool_value (bool val);
public abstract unowned ObjectBuilder add_int64_value (int64 val);
public abstract unowned ObjectBuilder add_uint64_value (uint64 val);
public abstract unowned ObjectBuilder add_data_value (Bytes val);
public abstract unowned ObjectBuilder add_string_value (string val);
public abstract unowned ObjectBuilder add_raw_value (Bytes val);
public abstract Bytes build ();
}
public interface ObjectReader : Object {
public abstract bool has_member (string name) throws Error;
public abstract unowned ObjectReader read_member (string name) throws Error;
public abstract unowned ObjectReader end_member ();
public abstract uint count_elements () throws Error;
public abstract unowned ObjectReader read_element (uint index) throws Error;
public abstract unowned ObjectReader end_element () throws Error;
public abstract bool get_bool_value () throws Error;
public abstract uint8 get_uint8_value () throws Error;
public abstract uint16 get_uint16_value () throws Error;
public abstract int64 get_int64_value () throws Error;
public abstract uint64 get_uint64_value () throws Error;
public abstract Bytes get_data_value () throws Error;
public abstract unowned string get_string_value () throws Error;
public abstract unowned string get_uuid_value () throws Error;
}
public class VariantReader : Object, ObjectReader {
public Variant root_object {
get {
return scopes.peek_head ().val;
}
}
public Variant current_object {
get {
return scopes.peek_tail ().val;
}
}
private Gee.Deque<Scope> scopes = new Gee.ArrayQueue<Scope> ();
public VariantReader (Variant v) {
push_scope (v);
}
public bool has_member (string name) throws Error {
var scope = peek_scope ();
if (scope.dict == null)
throw new Error.PROTOCOL ("Dictionary expected, but at %s", scope.val.print (true));
return scope.dict.contains (name);
}
public unowned ObjectReader read_member (string name) throws Error {
var scope = peek_scope ();
if (scope.dict == null)
throw new Error.PROTOCOL ("Dictionary expected, but at %s", scope.val.print (true));
Variant? v = scope.dict.lookup_value (name, null);
if (v == null)
throw new Error.PROTOCOL ("Key '%s' not found in dictionary: %s", name, scope.val.print (true));
push_scope (v);
return this;
}
public unowned ObjectReader end_member () {
pop_scope ();
return this;
}
public uint count_elements () throws Error {
var scope = peek_scope ();
scope.check_array ();
return (uint) scope.val.n_children ();
}
public unowned ObjectReader read_element (uint index) throws Error {
var scope = peek_scope ();
scope.check_array ();
push_scope (scope.val.get_child_value (index).get_variant ());
return this;
}
public unowned ObjectReader end_element () throws Error {
pop_scope ();
return this;
}
public bool get_bool_value () throws Error {
return peek_scope ().get_value (VariantType.BOOLEAN).get_boolean ();
}
public uint8 get_uint8_value () throws Error {
return peek_scope ().get_value (VariantType.BYTE).get_byte ();
}
public uint16 get_uint16_value () throws Error {
return peek_scope ().get_value (VariantType.UINT16).get_uint16 ();
}
public int64 get_int64_value () throws Error {
return peek_scope ().get_value (VariantType.INT64).get_int64 ();
}
public uint64 get_uint64_value () throws Error {
return peek_scope ().get_value (VariantType.UINT64).get_uint64 ();
}
public Bytes get_data_value () throws Error {
return peek_scope ().get_value (new VariantType.array (VariantType.BYTE)).get_data_as_bytes ();
}
public unowned string get_string_value () throws Error {
return peek_scope ().get_value (VariantType.STRING).get_string ();
}
public unowned string get_uuid_value () throws Error {
return peek_scope ().get_value (VariantType.STRING).get_string (); // TODO: Use a tuple to avoid ambiguity.
}
private void push_scope (Variant v) {
scopes.offer_tail (new Scope (v));
}
private Scope peek_scope () {
return scopes.peek_tail ();
}
private Scope pop_scope () {
return scopes.poll_tail ();
}
private class Scope {
public Variant val;
public VariantDict? dict;
public bool is_array = false;
public Scope (Variant v) {
val = v;
VariantType t = v.get_type ();
if (t.equal (VariantType.VARDICT))
dict = new VariantDict (v);
else if (t.is_subtype_of (VariantType.ARRAY))
is_array = true;
}
public Variant get_value (VariantType expected_type) throws Error {
if (!val.get_type ().equal (expected_type)) {
throw new Error.PROTOCOL ("Expected type '%s', got '%s'",
(string) expected_type.peek_string (),
(string) val.get_type ().peek_string ());
}
return val;
}
public void check_array () throws Error {
if (!is_array)
throw new Error.PROTOCOL ("Array expected, but at %s", val.print (true));
}
}
}
public class JsonObjectBuilder : Object, ObjectBuilder {
private Json.Builder builder = new Json.Builder ();
private Gee.Map<string, Bytes> raw_values = new Gee.HashMap<string, Bytes> ();
public unowned ObjectBuilder begin_dictionary () {
builder.begin_object ();
return this;
}
public unowned ObjectBuilder set_member_name (string name) {
builder.set_member_name (name);
return this;
}
public unowned ObjectBuilder end_dictionary () {
builder.end_object ();
return this;
}
public unowned ObjectBuilder begin_array () {
builder.begin_array ();
return this;
}
public unowned ObjectBuilder end_array () {
builder.end_array ();
return this;
}
public unowned ObjectBuilder add_null_value () {
builder.add_null_value ();
return this;
}
public unowned ObjectBuilder add_bool_value (bool val) {
builder.add_boolean_value (val);
return this;
}
public unowned ObjectBuilder add_int64_value (int64 val) {
builder.add_int_value (val);
return this;
}
public unowned ObjectBuilder add_uint64_value (uint64 val) {
builder.add_int_value ((int64) val);
return this;
}
public unowned ObjectBuilder add_data_value (Bytes val) {
builder.add_string_value (Base64.encode (val.get_data ()));
return this;
}
public unowned ObjectBuilder add_string_value (string val) {
builder.add_string_value (val);
return this;
}
public unowned ObjectBuilder add_raw_value (Bytes val) {
string uuid = Uuid.string_random ();
builder.add_string_value (uuid);
raw_values[uuid] = val;
return this;
}
public Bytes build () {
string json = Json.to_string (builder.get_root (), false);
foreach (var e in raw_values.entries) {
unowned string uuid = e.key;
Bytes val = e.value;
unowned string raw_str = (string) val.get_data ();
string str = raw_str[:(long) val.get_size ()];
json = json.replace ("\"" + uuid + "\"", str);
}
return new Bytes (json.data);
}
}
public class JsonObjectReader : Object, ObjectReader {
private Json.Reader reader;
public JsonObjectReader (string json) throws Error {
try {
reader = new Json.Reader (Json.from_string (json));
} catch (GLib.Error e) {
throw new Error.INVALID_ARGUMENT ("%s", e.message);
}
}
public bool has_member (string name) throws Error {
bool result = reader.read_member (name);
reader.end_member ();
return result;
}
public unowned ObjectReader read_member (string name) throws Error {
if (!reader.read_member (name))
throw_dict_access_error ();
return this;
}
public unowned ObjectReader end_member () {
reader.end_member ();
return this;
}
[NoReturn]
private void throw_dict_access_error () throws Error {
GLib.Error e = reader.get_error ();
reader.end_member ();
throw new Error.PROTOCOL ("%s", e.message);
}
public uint count_elements () throws Error {
int n = reader.count_elements ();
if (n == -1)
throw_array_access_error ();
return n;
}
public unowned ObjectReader read_element (uint index) throws Error {
if (!reader.read_element (index)) {
GLib.Error e = reader.get_error ();
reader.end_element ();
throw new Error.PROTOCOL ("%s", e.message);
}
return this;
}
public unowned ObjectReader end_element () throws Error {
reader.end_element ();
return this;
}
[NoReturn]
private void throw_array_access_error () throws Error {
GLib.Error e = reader.get_error ();
reader.end_element ();
throw new Error.PROTOCOL ("%s", e.message);
}
public bool get_bool_value () throws Error {
bool v = reader.get_boolean_value ();
if (!v)
maybe_throw_value_access_error ();
return v;
}
public uint8 get_uint8_value () throws Error {
int64 v = get_int64_value ();
if (v < 0 || v > uint8.MAX)
throw new Error.PROTOCOL ("Invalid uint8");
return (uint8) v;
}
public uint16 get_uint16_value () throws Error {
int64 v = get_int64_value ();
if (v < 0 || v > uint16.MAX)
throw new Error.PROTOCOL ("Invalid uint16");
return (uint16) v;
}
public int64 get_int64_value () throws Error {
int64 v = reader.get_int_value ();
if (v == 0)
maybe_throw_value_access_error ();
return v;
}
public uint64 get_uint64_value () throws Error {
int64 v = get_int64_value ();
if (v < 0)
throw new Error.PROTOCOL ("Invalid uint64");
return v;
}
public Bytes get_data_value () throws Error {
return new Bytes (Base64.decode (get_string_value ()));
}
public unowned string get_string_value () throws Error {
unowned string? v = reader.get_string_value ();
if (v == null)
maybe_throw_value_access_error ();
return v;
}
public unowned string get_uuid_value () throws Error {
return get_string_value ();
}
private void maybe_throw_value_access_error () throws Error {
GLib.Error? e = reader.get_error ();
if (e == null)
return;
reader.end_member ();
throw new Error.PROTOCOL ("%s", e.message);
}
}
}
+260
View File
@@ -0,0 +1,260 @@
namespace Frida {
public class XpcClient : Object {
public signal void message (Darwin.Xpc.Object obj);
public State state {
get {
return _state;
}
}
public Darwin.Xpc.Connection connection {
get;
construct;
}
public Darwin.GCD.DispatchQueue queue {
get;
construct;
}
private State _state;
private string? close_reason;
private MainContext main_context;
public enum State {
OPEN,
CLOSING,
CLOSED,
}
public static XpcClient make_for_mach_service (string name, Darwin.GCD.DispatchQueue queue) {
return new XpcClient (Darwin.Xpc.Connection.create_mach_service (name, queue, 0), queue);
}
public XpcClient (Darwin.Xpc.Connection connection, Darwin.GCD.DispatchQueue queue) {
Object (connection: connection, queue: queue);
}
construct {
main_context = MainContext.ref_thread_default ();
connection.set_event_handler (on_event);
connection.activate ();
}
public override void dispose () {
if (close_reason != null) {
change_state (CLOSED);
} else {
change_state (CLOSING);
this.ref ();
connection.cancel ();
}
base.dispose ();
}
public async Darwin.Xpc.Object request (Darwin.Xpc.Object message, Cancellable? cancellable) throws Error, IOError {
Darwin.Xpc.Object? reply = null;
connection.send_message_with_reply (message, queue, r => {
schedule_on_frida_thread (() => {
reply = r;
request.callback ();
return Source.REMOVE;
});
});
var cancel_source = new CancellableSource (cancellable);
cancel_source.set_callback (() => {
connection.cancel ();
return Source.REMOVE;
});
cancel_source.attach (main_context);
yield;
cancel_source.destroy ();
if (reply.type == Darwin.Xpc.Error.TYPE) {
var e = (Darwin.Xpc.Error) reply;
throw new Error.NOT_SUPPORTED ("%s", e.get_string (Darwin.Xpc.Error.KEY_DESCRIPTION));
}
return reply;
}
public void post (Darwin.Xpc.Object message) throws Error, IOError {
connection.send_message (message);
}
private void change_state (State new_state) {
_state = new_state;
notify_property ("state");
}
private void on_event (Darwin.Xpc.Object obj) {
schedule_on_frida_thread (() => {
if (obj.type == Darwin.Xpc.Error.TYPE) {
var e = (Darwin.Xpc.Error) obj;
close_reason = e.get_string (Darwin.Xpc.Error.KEY_DESCRIPTION);
switch (state) {
case OPEN:
change_state (CLOSED);
break;
case CLOSING:
change_state (CLOSED);
unref ();
break;
case CLOSED:
assert_not_reached ();
}
} else {
message (obj);
}
return Source.REMOVE;
});
}
private void schedule_on_frida_thread (owned SourceFunc function) {
var source = new IdleSource ();
source.set_callback ((owned) function);
source.attach (main_context);
}
}
public class XpcObjectReader {
public Darwin.Xpc.Object root_object {
get {
return scopes.peek_head ().object;
}
}
public Darwin.Xpc.Object current_object {
get {
return scopes.peek_tail ().object;
}
}
private Gee.Deque<Scope> scopes = new Gee.ArrayQueue<Scope> ();
public XpcObjectReader (Darwin.Xpc.Object obj) {
push_scope (obj);
}
public bool has_member (string name) throws Error {
return peek_scope ().get_dictionary ().get_value (name) != null;
}
public bool try_read_member (string name) throws Error {
var scope = peek_scope ();
var dict = scope.get_dictionary ();
var val = dict.get_value (name);
if (val == null)
return false;
push_scope (val);
return true;
}
public unowned XpcObjectReader read_member (string name) throws Error {
var scope = peek_scope ();
var dict = scope.get_dictionary ();
var val = dict.get_value (name);
if (val == null)
throw new Error.PROTOCOL ("Key '%s' not found in dictionary: %s", name, scope.object.to_string ());
push_scope (val);
return this;
}
public unowned XpcObjectReader end_member () {
pop_scope ();
return this;
}
public size_t count_elements () throws Error {
return peek_scope ().get_array ().count;
}
public unowned XpcObjectReader read_element (size_t index) throws Error {
push_scope (peek_scope ().get_array ().get_value (index));
return this;
}
public unowned XpcObjectReader end_element () throws Error {
pop_scope ();
return this;
}
public bool get_bool_value () throws Error {
return peek_scope ().get_object<Darwin.Xpc.Bool> (Darwin.Xpc.Bool.TYPE).get_value ();
}
public int64 get_int64_value () throws Error {
return peek_scope ().get_object<Darwin.Xpc.Int64> (Darwin.Xpc.Int64.TYPE).get_value ();
}
public uint64 get_uint64_value () throws Error {
return peek_scope ().get_object<Darwin.Xpc.UInt64> (Darwin.Xpc.UInt64.TYPE).get_value ();
}
public unowned string get_string_value () throws Error {
return peek_scope ().get_object<Darwin.Xpc.String> (Darwin.Xpc.String.TYPE).get_string_ptr ();
}
public unowned uint8[] get_uuid_value () throws Error {
return peek_scope ().get_object<Darwin.Xpc.Uuid> (Darwin.Xpc.Uuid.TYPE).get_bytes ()[:16];
}
public unowned string get_error_description () throws Error {
var error = peek_scope ().get_object<Darwin.Xpc.Error> (Darwin.Xpc.Error.TYPE);
return error.get_string (Darwin.Xpc.Error.KEY_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);
}
private void push_scope (Darwin.Xpc.Object obj) {
scopes.offer_tail (new Scope (obj));
}
private Scope peek_scope () {
return scopes.peek_tail ();
}
private Scope pop_scope () {
return scopes.poll_tail ();
}
private class Scope {
public Darwin.Xpc.Object object;
private unowned Darwin.Xpc.Type type;
public Scope (Darwin.Xpc.Object obj) {
object = obj;
type = obj.type;
}
public unowned T get_object<T> (Darwin.Xpc.Type expected_type) throws Error {
if (type != expected_type)
throw new Error.PROTOCOL ("Expected type '%s', got '%s'", expected_type.name, type.name);
return object;
}
public unowned Darwin.Xpc.Array get_array () throws Error {
return get_object<Darwin.Xpc.Array> (Darwin.Xpc.Array.TYPE);
}
public unowned Darwin.Xpc.Dictionary get_dictionary () throws Error {
return get_object<Darwin.Xpc.Dictionary> (Darwin.Xpc.Dictionary.TYPE);
}
}
}
}
+2 -1
View File
@@ -1497,7 +1497,8 @@ namespace Frida.Gadget {
var endpoint_params = new EndpointParameters (interaction.address, interaction.port,
parse_certificate (interaction.certificate, location), interaction.origin, auth_service, asset_root);
service = new WebService (endpoint_params, CONTROL, interaction.on_port_conflict);
service = new WebService (endpoint_params, WebServiceFlavor.CONTROL, interaction.on_port_conflict,
new TunnelInterfaceObserver ());
service.incoming.connect (on_incoming_connection);
yield service.start (io_cancellable);
}
+1 -1
View File
@@ -60,7 +60,7 @@ raw_gadget = shared_library('frida-gadget-raw', gadget_sources,
link_depends: extra_link_depends,
vs_module_defs: 'frida-gadget.def',
override_options: ['b_asneeded=true'],
dependencies: [gio_dep, gee_dep, json_glib_dep, gum_dep, gumjs_dep, base_dep, tls_provider_dep, payload_dep] + platform_deps,
dependencies: [gio_dep, gee_dep, json_glib_dep, gum_dep, gumjs_dep, base_dep, netif_dep, tls_provider_dep, payload_dep] + platform_deps,
)
operations = [
+1
View File
@@ -2,6 +2,7 @@ if host_os == 'android'
subdir('selinux')
endif
subdir('base')
subdir('netif')
subdir('pipe')
subdir('payload')
if have_local_backend
+28
View File
@@ -0,0 +1,28 @@
netif_sources = [
'tunnel-interface-observer.vala',
]
extra_vala_args = []
extra_link_args = []
if host_os in ['ios', 'tvos']
extra_vala_args += [
'--pkg=corefoundation',
'--pkg=darwin-gcd',
'--pkg=darwin-systemconfiguration',
]
extra_link_args += '-Wl,-framework,SystemConfiguration'
endif
netif = static_library('frida-netif', netif_sources,
c_args: frida_component_cflags,
vala_args: [base_vala_args, extra_vala_args],
dependencies: [base_dep, gee_dep],
)
netif_dep = declare_dependency(
include_directories: include_directories('.'),
link_args: extra_link_args,
link_with: netif,
dependencies: base_dep,
)
+92
View File
@@ -0,0 +1,92 @@
public class Frida.TunnelInterfaceObserver : Object, DynamicInterfaceObserver {
#if IOS || TVOS
private Gee.Map<string, InetAddress> interfaces = new Gee.HashMap<string, InetAddress> ();
private Darwin.SystemConfiguration.DynamicStore? store;
private Darwin.GCD.DispatchQueue event_queue =
new Darwin.GCD.DispatchQueue ("re.frida.endpoint-enumerator", Darwin.GCD.DispatchQueueAttr.SERIAL);
private MainContext? main_context;
public override void dispose () {
if (store != null) {
store.set_dispatch_queue (null);
store = null;
ref ();
event_queue.dispatch_async (do_dispose);
}
base.dispose ();
}
private void do_dispose () {
unref ();
}
public void start () {
main_context = MainContext.ref_thread_default ();
Darwin.SystemConfiguration.DynamicStoreContext context = { 0, };
context.info = this;
store = new Darwin.SystemConfiguration.DynamicStore (null, CoreFoundation.String.make ("Frida"),
on_interfaces_changed_wrapper, context);
var pattern = CoreFoundation.String.make ("State:/Network/Interface/utun.*/IPv6");
var patterns = new CoreFoundation.Array (null, ((CoreFoundation.Type[]) &pattern)[:1]);
store.set_notification_keys (null, patterns);
store.set_dispatch_queue (event_queue);
handle_interface_changes (store.copy_key_list (pattern));
}
private static void on_interfaces_changed_wrapper (Darwin.SystemConfiguration.DynamicStore store,
CoreFoundation.Array changed_keys, void * info) {
unowned TunnelInterfaceObserver enumerator = (TunnelInterfaceObserver) info;
enumerator.on_interfaces_changed (changed_keys);
}
private void on_interfaces_changed (CoreFoundation.Array changed_keys) {
schedule_on_frida_thread (() => {
if (store != null)
handle_interface_changes (changed_keys);
return Source.REMOVE;
});
}
private void handle_interface_changes (CoreFoundation.Array changed_keys) {
var addresses_str = CoreFoundation.String.make ("Addresses");
foreach (var key in CFArray.wrap<CoreFoundation.String> (changed_keys)) {
string name = key.to_string ().split ("/")[3];
InetAddress? address = null;
var val = (CoreFoundation.Dictionary) store.copy_value (key);
if (val != null) {
foreach (var raw_address in CFArray.wrap<CoreFoundation.String> (val[addresses_str])) {
var str = raw_address.to_string ();
bool is_reserved_ipv6_range = str.has_prefix ("fc") || str.has_prefix ("fd");
bool is_tunnel = is_reserved_ipv6_range && str.has_suffix ("::1");
if (is_tunnel) {
address = new InetAddress.from_string (str);
break;
}
}
if (address != null && !interfaces.has_key (name)) {
interfaces[name] = address;
interface_attached (name, address);
}
} else {
if (interfaces.unset (name, out address))
interface_detached (name, address);
}
}
}
private void schedule_on_frida_thread (owned SourceFunc function) {
var source = new IdleSource ();
source.set_callback ((owned) function);
source.attach (main_context);
}
#else
public void start () {
}
#endif
}
+2 -2
View File
@@ -1,7 +1,7 @@
#include "pipe-glue.h"
#include "frida-tvos.h"
#include "pipe-glue.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
+98 -14
View File
@@ -92,6 +92,12 @@ else
host_arch = host_machine.cpu_family()
host_abi = host_arch
endif
if cc.sizeof('void *') == 8
host_cpu_mode = '64'
else
host_cpu_mode = '32'
endif
host_docks_mobile_devices = host_os in ['windows', 'macos', 'linux', 'freebsd'] and host_cpu_mode == '64'
gumjs_archs = {
'x86': 'ia32',
'x86_64': 'x64',
@@ -156,12 +162,6 @@ if host_os_family == 'darwin'
endif
endif
if cc.sizeof('void *') == 8
host_cpu_mode = '64'
else
host_cpu_mode = '32'
endif
if host_os_family == 'darwin' and host_arch == 'arm64'
host_is_modern = host_abi == 'arm64e'
else
@@ -348,14 +348,27 @@ else
endif
have_local_backend = get_option('local_backend').allowed()
have_fruity_backend = get_option('fruity_backend').allowed()
have_droidy_backend = get_option('droidy_backend').allowed()
have_fruity_backend = get_option('fruity_backend') \
.disable_auto_if(not host_docks_mobile_devices) \
.allowed()
have_droidy_backend = get_option('droidy_backend') \
.disable_auto_if(not host_docks_mobile_devices) \
.allowed()
have_socket_backend = get_option('socket_backend').allowed()
have_barebone_backend = quickjs_dep.found()
have_barebone_backend = get_option('barebone_backend') \
.disable_if(not quickjs_dep.found()) \
.disable_auto_if(not host_docks_mobile_devices) \
.allowed()
have_compiler_backend = get_option('compiler_backend') \
.disable_if(not have_local_backend, error_message: 'compiler backend requires the local backend for script execution') \
.disable_auto_if(host_os == 'watchos') \
.allowed()
if get_option('compiler_snapshot').auto()
# Generating our snapshot with V8's CPU simulator takes a very long time.
generate_compiler_snapshot = meson.can_run_host_binaries()
else
generate_compiler_snapshot = get_option('compiler_snapshot').enabled()
endif
build_gadget = get_option('gadget') \
.disable_auto_if(meson.is_subproject()) \
@@ -413,7 +426,7 @@ else
endif
uninstalled_girdir = meson.current_build_dir() / 'src'
vapidir = get_option('datadir') / 'vala' / 'vapi'
vapidir = get_option('prefix') / get_option('datadir') / 'vala' / 'vapi'
gum_vala_args = [
'--pkg=frida-gum-1.0',
@@ -437,6 +450,43 @@ backend_deps_private = []
backend_reqs_private = []
backend_libs_private = []
openssl_options = [
'cli=disabled',
]
if host_os_family == 'windows' and cc.get_argument_syntax() != 'msvc'
openssl_options += 'asm=disabled'
endif
openssl_dep = dependency('openssl',
required: have_fruity_backend or get_option('connectivity').enabled(),
modules: cc.get_argument_syntax() == 'msvc' ? ['OpenSSL::SSL'] : [],
default_options: openssl_options,
)
if have_fruity_backend
foreach dep : ['libnghttp2', 'libngtcp2', 'libngtcp2_crypto_quictls', 'libusb-1.0']
backend_deps_private += dependency(dep)
backend_reqs_private += dep
endforeach
lwip_options = [
'ipv4=disabled',
'ipv6=enabled',
'dns=disabled',
'arp=disabled',
'ethernet=enabled',
'tcp_mss=1360',
'tcp_snd_buf=65535',
'tcp_wnd=65535',
]
if optimize_for_prod
lwip_options += 'lwip_debug=disabled'
else
lwip_options += 'lwip_debug=enabled'
endif
backend_deps_private += dependency('lwip', default_options: lwip_options)
backend_reqs_private += 'lwip'
endif
if quickjs_dep.found()
backend_deps_private += quickjs_dep
backend_reqs_private += 'quickjs'
@@ -456,8 +506,19 @@ else
termux_elf_cleaner = []
endif
tls_provider_dep = dependency('gioopenssl', required: get_option('connectivity'))
tls_provider_dep = dependency('gioopenssl', required: get_option('connectivity'), default_options: [
'gnutls=disabled',
'openssl=enabled',
'libproxy=disabled',
'gnome_proxy=disabled',
'tests=false',
])
tls_provider_vala_args = []
if tls_provider_dep.found()
tls_provider_vala_args += [
'--pkg=gioopenssl',
'--vapidir=' + tls_provider_dep.get_variable('vapidir'),
]
cdata.set('HAVE_GIOOPENSSL', 1)
vala_flags += ['--define=HAVE_GIOOPENSSL']
backend_deps_private += tls_provider_dep
@@ -473,7 +534,6 @@ nice_dep = dependency('nice', required: get_option('connectivity'), default_opti
'introspection=disabled',
])
if nice_dep.found()
openssl_dep = dependency('openssl')
usrsctp_dep = dependency('usrsctp', default_options: [
'sctp_inet=false',
'sctp_inet6=false',
@@ -489,7 +549,6 @@ if nice_dep.found()
cdata.set('HAVE_SCONN_LEN', 1)
endif
else
openssl_dep = []
usrsctp_dep = []
endif
@@ -627,8 +686,9 @@ if cc.get_id() == 'gcc' and cc.compiles('#if __GNUC__ >= 5\n#error NOTNEEDED\n#e
add_project_arguments('-w', language: 'c')
endif
vapidir = meson.current_source_dir() / 'vapi'
vala_flags += [
'--vapidir=' + meson.current_source_dir() / 'vapi',
'--vapidir=' + vapidir,
'--pkg', 'config',
]
@@ -641,11 +701,13 @@ if host_abi != host_arch
vala_flags += ['--define=' + host_abi.to_upper()]
endif
add_project_arguments(vala_flags, language: 'vala')
add_project_arguments('-I' + vapidir, language: 'c')
native_vala_flags = [
'--vapidir=' + meson.current_source_dir() / 'vapi',
]
add_project_arguments(native_vala_flags, language: 'vala', native: true)
add_project_arguments('-I' + vapidir, language: 'c', native: true)
subdir('compat')
subdir('tools')
@@ -664,9 +726,31 @@ if build_tests
subdir('tests')
endif
summary(
{
'local': have_local_backend,
'fruity': have_fruity_backend,
'droidy': have_droidy_backend,
'socket': have_socket_backend,
'barebone': have_barebone_backend,
'compiler': have_compiler_backend,
},
section: 'Backends',
bool_yn: true,
)
summary(
{
'compat': compat_summary,
'assets': get_option('assets'),
'mapper': have_mapper,
'connectivity': tls_provider_dep.found(),
'compiler_snapshot': generate_compiler_snapshot,
'gadget': build_gadget,
'server': build_server,
'portal': build_portal,
'inject': build_inject,
'tests': build_tests,
},
section: 'Features',
bool_yn: true,
)
+1 -11
View File
@@ -101,16 +101,6 @@ option('agent_emulated_legacy',
description: 'Prebuilt agent to embed for use on legacy emulated targets'
)
option('agent_dbghelp_prefix',
type: 'string',
description: 'Location of DbgHelp binaries to embed alongside agent (Windows only)'
)
option('agent_symsrv_prefix',
type: 'string',
description: 'Location of SymSrv binaries to embed alongside agent (Windows only)'
)
option('gadget',
type: 'feature',
value: 'auto',
@@ -137,7 +127,7 @@ option('inject',
option('connectivity',
type: 'feature',
value: 'auto',
value: 'enabled',
description: 'Internet connectivity features (TLS and ICE support)'
)
+1 -1
View File
@@ -20,7 +20,7 @@ if tls_provider_dep.found()
endif
raw_portal = executable('frida-portal-raw', portal_sources,
vala_args: [core_vala_args, '--pkg=posix'],
vala_args: [core_vala_args, tls_provider_vala_args, '--pkg=posix'],
link_args: extra_link_args,
link_depends: extra_link_depends,
dependencies: [core_dep] + extra_deps,
+1 -1
Submodule releng updated: 56b262207c...f7ba343c9a.
+4 -2
View File
@@ -327,8 +327,10 @@ def parse_api(api_version, toplevel_code, core_vapi, core_header, base_vapi, bas
if stripped_line == "}":
ignoring = False
else:
if stripped_line.startswith("public abstract") or stripped_line.startswith("public class Promise") \
or stripped_line.startswith("public interface Future"):
if stripped_line.startswith("public abstract") \
or stripped_line.startswith("public class Promise") \
or stripped_line.startswith("public interface Future") \
or stripped_line.startswith("public class CF"):
ignoring = True
elif stripped_line.startswith("public enum") or stripped_line.startswith("public errordomain"):
name = re.match(r"^public (?:enum|errordomain) (\w+) ", stripped_line).group(1)
+15 -15
View File
@@ -90,17 +90,25 @@ else
endif
uninstalled_vapidir = uninstalled_incdir
uninstalled_variables = {
'frida_includedir': uninstalled_incdir,
'frida_girdir': uninstalled_girdir,
'frida_vapidir': uninstalled_vapidir,
}
installed_variables = {
'frida_includedir': '${includedir}',
'frida_girdir': girdir,
'frida_vapidir': vapidir,
}
core_public_dep = declare_dependency(
sources: [core_public_h, core_public_gir, core_public_vapi_stamp, core_public_extra_headers],
include_directories: include_directories('.'),
link_args: backend_libs_private,
link_with: core_public_lib,
dependencies: core_deps,
variables: {
'frida_includedir': uninstalled_incdir,
'frida_girdir': uninstalled_girdir,
'frida_vapidir': uninstalled_vapidir,
},
variables: uninstalled_variables,
)
pkg = import('pkgconfig')
@@ -115,16 +123,8 @@ pkg.generate(
libraries: core_public_lib,
libraries_private: backend_libs_private,
extra_cflags: ['-I${frida_includedir}'],
variables: {
'frida_includedir': '${includedir}',
'frida_girdir': girdir,
'frida_vapidir': vapidir,
},
uninstalled_variables: {
'frida_includedir': uninstalled_incdir,
'frida_girdir': uninstalled_girdir,
'frida_vapidir': uninstalled_vapidir,
},
variables: installed_variables,
uninstalled_variables: uninstalled_variables,
)
meson.override_dependency(f'frida-core-@api_version@', core_public_dep)
+1 -7
View File
@@ -3,13 +3,7 @@ compiler_sources = files(
)
if have_compiler_backend
if get_option('compiler_snapshot').auto()
# Generating our snapshot with V8's CPU simulator takes a very long time.
use_snapshot = meson.can_run_host_binaries()
else
use_snapshot = get_option('compiler_snapshot').enabled()
endif
compiler_mksnapshot = use_snapshot ? v8_mksnapshot : ''
compiler_mksnapshot = generate_compiler_snapshot ? v8_mksnapshot : ''
compiler_agent = custom_target('frida-compiler-agent',
input: [
+2 -1
View File
@@ -89,7 +89,8 @@ namespace Frida {
host_session.agent_session_detached.connect (on_agent_session_detached);
host_session.uninjected.connect (notify_uninjected);
service = new WebService (endpoint_params, CONTROL);
service = new WebService (endpoint_params, WebServiceFlavor.CONTROL, PortConflictBehavior.FAIL,
new TunnelInterfaceObserver ());
service.incoming.connect (on_server_connection);
broker_service.incoming.connect (on_broker_service_connection);
+83 -9
View File
@@ -183,6 +183,7 @@ struct _FridaSpawnInstance
GumAddress modern_entry_address;
/* V4+ */
GumAddress notify_objc_init;
GumAddress info_ptr_address;
/* V3- */
@@ -428,6 +429,8 @@ static void frida_agent_context_emit_mach_stub_code (FridaAgentContext * self, g
static void frida_agent_context_emit_pthread_stub_code (FridaAgentContext * self, guint8 * code, GumDarwinModuleResolver * resolver,
GumDarwinMapper * mapper);
static gboolean frida_convert_thread_state_for_task (mach_port_t task, thread_state_flavor_t flavor, gconstpointer in_state,
mach_msg_type_number_t in_state_count, gpointer out_state, mach_msg_type_number_t * out_state_count, GError ** error);
static mach_port_t frida_obtain_thread_port_for_thread_id (mach_port_t task, uint64_t thread_id);
static kern_return_t frida_get_thread_state (mach_port_t thread, thread_state_flavor_t flavor, gpointer state,
mach_msg_type_number_t * count);
@@ -2028,6 +2031,10 @@ _frida_darwin_helper_backend_prepare_spawn_instance_for_injection (FridaDarwinHe
instance->dyld_flavor = (modern_entry_address != 0) ? FRIDA_DYLD_V4_PLUS : FRIDA_DYLD_V3_MINUS;
if (instance->dyld_flavor == FRIDA_DYLD_V4_PLUS)
{
instance->notify_objc_init = gum_darwin_module_resolve_symbol_address (dyld, "__ZN5dyld412RuntimeState14notifyObjCInitEPKNS_6LoaderE");
if (instance->notify_objc_init != 0)
modern_entry_address = instance->notify_objc_init;
instance->modern_entry_address = modern_entry_address;
legacy_entry_address = 0;
@@ -2106,7 +2113,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");
if (restart_with_dyld_in_cache == 0)
{
restart_with_dyld_in_cache = gum_darwin_module_resolve_symbol_address (dyld,
"__ZN5dyld422restartWithDyldInCacheEPKNS_10KernelArgsEPKN5dyld39MachOFileEPv");
}
if (restart_with_dyld_in_cache != 0)
frida_spawn_instance_set_nth_breakpoint (instance, i++, restart_with_dyld_in_cache, FRIDA_BREAKPOINT_REPEAT_NEVER);
}
@@ -2583,16 +2595,24 @@ static gboolean
frida_inject_instance_start_thread (FridaInjectInstance * self, GError ** error)
{
gboolean success = FALSE;
thread_state_t thread_state;
mach_msg_type_number_t thread_state_count;
kern_return_t kr;
const gchar * failed_operation;
FridaHelperContext * ctx = self->backend->context;
dispatch_source_t source;
kr = thread_create (self->task, &self->thread);
CHECK_MACH_RESULT (kr, ==, KERN_SUCCESS, "thread_create");
thread_state = g_alloca (self->thread_state_count * sizeof (natural_t));
thread_state_count = self->thread_state_count;
kr = frida_set_thread_state (self->thread, self->thread_state_flavor, self->thread_state_data, self->thread_state_count);
CHECK_MACH_RESULT (kr, ==, KERN_SUCCESS, "set_thread_state");
if (!frida_convert_thread_state_for_task (self->task, self->thread_state_flavor, self->thread_state_data, self->thread_state_count,
thread_state, &thread_state_count, error))
{
return FALSE;
}
kr = thread_create_running (self->task, self->thread_state_flavor, thread_state, thread_state_count, &self->thread);
CHECK_MACH_RESULT (kr, ==, KERN_SUCCESS, "thread_create");
source = dispatch_source_create (DISPATCH_SOURCE_TYPE_MACH_SEND, self->thread, DISPATCH_MACH_SEND_DEAD, ctx->dispatch_queue);
self->thread_monitor_source = source;
@@ -2601,9 +2621,6 @@ frida_inject_instance_start_thread (FridaInjectInstance * self, GError ** error)
dispatch_source_set_event_handler_f (source, frida_inject_instance_on_mach_thread_dead);
dispatch_resume (source);
kr = thread_resume (self->thread);
CHECK_MACH_RESULT (kr, ==, KERN_SUCCESS, "thread_resume");
success = TRUE;
goto beach;
@@ -3078,9 +3095,15 @@ frida_spawn_instance_handle_breakpoint (FridaSpawnInstance * self, FridaBreakpoi
if (self->dyld_flavor == FRIDA_DYLD_V4_PLUS)
{
if (pc == self->modern_entry_address)
self->breakpoint_phase = FRIDA_BREAKPOINT_SET_LIBDYLD_INITIALIZE_CALLER_BREAKPOINT;
{
self->breakpoint_phase = (pc == self->notify_objc_init)
? FRIDA_BREAKPOINT_LIBSYSTEM_INITIALIZED
: FRIDA_BREAKPOINT_SET_LIBDYLD_INITIALIZE_CALLER_BREAKPOINT;
}
else
{
return frida_spawn_instance_handle_dyld_restart (self);
}
}
else
{
@@ -3346,6 +3369,7 @@ frida_spawn_instance_handle_dyld_restart (FridaSpawnInstance * self)
GumAddress * info_ptr;
struct dyld_all_image_infos * info = NULL;
GumDarwinModule * dyld = NULL;
gssize delta;
info_ptr = (GumAddress *) gum_darwin_read (self->task, self->info_ptr_address, sizeof (GumAddress), NULL);
if (info_ptr == NULL)
@@ -3360,7 +3384,11 @@ frida_spawn_instance_handle_dyld_restart (FridaSpawnInstance * self)
if (dyld == NULL)
goto beach;
self->modern_entry_address = GUM_ADDRESS (info->dyldImageLoadAddress) + (self->modern_entry_address - self->dyld->base_address);
delta = (gssize) info->dyldImageLoadAddress - (gssize) self->dyld->base_address;
self->modern_entry_address += delta;
if (self->notify_objc_init != 0)
self->notify_objc_init += delta;
g_object_unref (self->dyld);
self->dyld = g_steal_pointer (&dyld);
@@ -5072,6 +5100,52 @@ frida_agent_context_emit_arm64_pthread_stub_body (FridaAgentContext * self, Frid
#endif
static gboolean
frida_convert_thread_state_for_task (mach_port_t task, thread_state_flavor_t flavor, gconstpointer in_state,
mach_msg_type_number_t in_state_count, gpointer out_state, mach_msg_type_number_t * out_state_count,
GError ** error)
{
gboolean success = FALSE;
kern_return_t kr;
const gchar * failed_operation;
thread_act_array_t threads = NULL;
mach_msg_type_number_t thread_count = 0;
kr = task_threads (task, &threads, &thread_count);
CHECK_MACH_RESULT (kr, ==, KERN_SUCCESS, "task_threads");
kr = frida_convert_thread_state (threads[0], FRIDA_CONVERT_THREAD_STATE_OUT, flavor, in_state, in_state_count,
out_state, out_state_count);
CHECK_MACH_RESULT (kr, ==, KERN_SUCCESS, "thread_convert_thread_state");
success = TRUE;
goto beach;
mach_failure:
{
g_set_error (error,
FRIDA_ERROR,
FRIDA_ERROR_NOT_SUPPORTED,
"Unexpected error while converting thread state for task (%s returned '%s')",
failed_operation, mach_error_string (kr));
goto beach;
}
beach:
{
mach_msg_type_number_t i;
if (threads != NULL)
{
for (i = 0; i != thread_count; i++)
mach_port_deallocate (mach_task_self (), threads[i]);
vm_deallocate (mach_task_self (), (vm_address_t) threads, thread_count * sizeof (thread_t));
}
return success;
}
}
static mach_port_t
frida_obtain_thread_port_for_thread_id (mach_port_t task, uint64_t thread_id)
{
+1
View File
@@ -1,4 +1,5 @@
devkit_outputs = [
'frida-core.gir',
'frida-core.h',
static_lib_prefix + 'frida-core' + static_lib_suffix,
'frida-core-example.c',
+4 -4
View File
@@ -86,7 +86,7 @@ namespace Frida {
}
}
public class DroidyHostSessionProvider : Object, HostSessionProvider, ChannelProvider {
public class DroidyHostSessionProvider : Object, HostSessionProvider, HostChannelProvider {
public string id {
get { return device_details.serial; }
}
@@ -162,7 +162,7 @@ namespace Frida {
agent_session_detached (id, reason, crash);
}
public async IOStream open_channel (string address, Cancellable? cancellable = null) throws Error, IOError {
public async IOStream open_channel (string address, Cancellable? cancellable) throws Error, IOError {
if (address.contains (":")) {
Droidy.Client client = null;
try {
@@ -188,7 +188,7 @@ namespace Frida {
construct;
}
public weak ChannelProvider channel_provider {
public weak HostChannelProvider channel_provider {
get;
construct;
}
@@ -216,7 +216,7 @@ namespace Frida {
private const double MIN_SERVER_CHECK_INTERVAL = 5.0;
private const string GADGET_APP_ID = "re.frida.Gadget";
public DroidyHostSession (Droidy.DeviceDetails device_details, ChannelProvider channel_provider) {
public DroidyHostSession (Droidy.DeviceDetails device_details, HostChannelProvider channel_provider) {
Object (
device_details: device_details,
channel_provider: channel_provider
+2 -2
View File
@@ -37,12 +37,12 @@ def main(argv):
shutil.copy(agent, embedded_agent)
if agent_dbghelp_prefix is not None:
shutil.copy(agent_dbghelp_prefix / f"dbghelp-{flavor}.dll", embedded_dbghelp)
shutil.copy(agent_dbghelp_prefix / flavor / "dbghelp.dll", embedded_dbghelp)
else:
embedded_dbghelp.write_bytes(b"")
if agent_symsrv_prefix is not None:
shutil.copy(agent_symsrv_prefix / f"symsrv-{flavor}.dll", embedded_symsrv)
shutil.copy(agent_symsrv_prefix / flavor / "symsrv.dll", embedded_symsrv)
else:
embedded_symsrv.write_bytes(b"")
else:
+133 -31
View File
@@ -242,7 +242,7 @@ namespace Frida {
opts["keepalive_interval"] = interval;
}
var device = new Device (this, id, name, HostSessionProviderKind.REMOTE, socket_device.provider, raw_options);
var device = new Device (this, socket_device.provider, id, name, raw_options);
devices.add (device);
added (device);
changed ();
@@ -358,7 +358,7 @@ namespace Frida {
}
private void on_provider_available (HostSessionProvider provider) {
var device = new Device (this, provider.id, provider.name, provider.kind, provider);
var device = new Device (this, provider);
devices.add (device);
foreach (var observer in on_device_added.to_array ())
@@ -483,13 +483,19 @@ namespace Frida {
public signal void lost ();
public string id {
get;
construct;
get {
if (_id != null)
return _id;
return provider.id;
}
}
public string name {
get;
construct;
get {
if (_name != null)
return _name;
return provider.name;
}
}
public Variant? icon {
@@ -498,8 +504,18 @@ namespace Frida {
}
public DeviceType dtype {
get;
construct;
get {
switch (provider.kind) {
case HostSessionProviderKind.LOCAL:
return DeviceType.LOCAL;
case HostSessionProviderKind.REMOTE:
return DeviceType.REMOTE;
case HostSessionProviderKind.USB:
return DeviceType.USB;
default:
assert_not_reached ();
}
}
}
public Bus bus {
@@ -518,7 +534,8 @@ namespace Frida {
construct;
}
public delegate bool ProcessPredicate (Process process);
private string? _id;
private string? _name;
private HostSessionOptions? host_session_options;
private Promise<HostSession>? host_session_request;
@@ -530,34 +547,21 @@ 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;
internal Device (DeviceManager? manager, string id, string name, HostSessionProviderKind kind, HostSessionProvider provider,
HostSessionOptions? options = null) {
DeviceType dtype;
switch (kind) {
case HostSessionProviderKind.LOCAL:
dtype = DeviceType.LOCAL;
break;
case HostSessionProviderKind.REMOTE:
dtype = DeviceType.REMOTE;
break;
case HostSessionProviderKind.USB:
dtype = DeviceType.USB;
break;
default:
assert_not_reached ();
}
public delegate bool ProcessPredicate (Process process);
internal Device (DeviceManager? manager, HostSessionProvider provider, string? id = null, string? name = null,
HostSessionOptions? options = null) {
Object (
id: id,
name: name,
icon: provider.icon,
dtype: dtype,
manager: manager,
provider: provider,
manager: manager
icon: provider.icon
);
_id = id;
_name = name;
host_session_options = options;
}
@@ -1228,7 +1232,7 @@ namespace Frida {
public async IOStream open_channel (string address, Cancellable? cancellable = null) throws Error, IOError {
check_open ();
var channel_provider = provider as ChannelProvider;
var channel_provider = provider as HostChannelProvider;
if (channel_provider == null)
throw new Error.NOT_SUPPORTED ("Channels are not supported by this device");
@@ -1249,6 +1253,38 @@ 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 service = yield service_provider.open_service (address, cancellable);
service.close.connect (on_service_closed);
services.add (service);
return service;
}
public Service open_service_sync (string address, Cancellable? cancellable = null) throws Error, IOError {
var task = create<OpenServiceTask> ();
task.address = address;
return task.execute (cancellable);
}
private class OpenServiceTask : DeviceTask<Service> {
public string address;
protected override async Service perform_operation () throws Error, IOError {
return yield parent.open_service (address, cancellable);
}
}
private void on_service_closed (Service service) {
services.remove (service);
}
public async void unpair (Cancellable? cancellable = null) throws Error, IOError {
check_open ();
@@ -1357,6 +1393,10 @@ 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 ();
@@ -1964,6 +2004,68 @@ namespace Frida {
}
}
public interface Service : Object {
public signal void close ();
public signal void message (Variant message);
public abstract bool is_closed ();
public abstract async void activate (Cancellable? cancellable = null) throws Error, IOError;
public void activate_sync (Cancellable? cancellable = null) throws Error, IOError {
create<ActivateTask> ().execute (cancellable);
}
private class ActivateTask : ServiceTask<void> {
protected override async void perform_operation () throws Error, IOError {
yield parent.activate (cancellable);
}
}
public abstract async void cancel (Cancellable? cancellable = null) throws IOError;
public void cancel_sync (Cancellable? cancellable = null) throws IOError {
try {
create<CancelTask> ().execute (cancellable);
} catch (Error e) {
assert_not_reached ();
}
}
private class CancelTask : ServiceTask<void> {
protected override async void perform_operation () throws IOError {
yield parent.cancel (cancellable);
}
}
public abstract async Variant request (Variant parameters, Cancellable? cancellable = null) throws Error, IOError;
public Variant request_sync (Variant parameters, Cancellable? cancellable = null) throws Error, IOError {
var task = create<RequestTask> () as RequestTask;
task.parameters = parameters;
return task.execute (cancellable);
}
private class RequestTask : ServiceTask<Variant> {
public Variant parameters;
protected override async Variant perform_operation () throws Error, IOError {
return yield parent.request (parameters, cancellable);
}
}
private T create<T> () {
return Object.new (typeof (T), parent: this);
}
private abstract class ServiceTask<T> : AsyncTask<T> {
public weak Service parent {
get;
construct;
}
}
}
public class Session : Object, AgentMessageSink {
public signal void detached (SessionDetachReason reason, Crash? crash);
@@ -40,7 +40,8 @@ static const FridaFruityModel fruity_models[] =
};
void
_frida_fruity_host_session_backend_extract_details_for_device (gint product_id, const char * udid, char ** name, GVariant ** icon, GError ** error)
_frida_fruity_usbmux_backend_extract_details_for_device (gint product_id, const char * udid, char ** name, GVariant ** icon,
GError ** error)
{
const FridaFruityModel * model;
guint i;
+266
View File
@@ -0,0 +1,266 @@
[CCode (gir_namespace = "FridaFruity", gir_version = "1.0")]
namespace Frida.Fruity {
public class LinuxFruitFinder : Object, FruitFinder {
public string? udid_from_iface (string ifname) throws Error {
var net = "/sys/class/net";
var directory = File.new_build_filename (net, ifname);
if (!directory.query_exists ())
return null;
try {
var info = directory.query_info ("standard::*", 0);
if (!info.get_is_symlink ())
return null;
var dev_path = Path.build_filename (net, info.get_symlink_target ());
var iface = File.new_build_filename (dev_path, "..", "..", "interface");
if (!iface.query_exists ())
return null;
var iface_stream = new DataInputStream (iface.read ());
string iface_name = iface_stream.read_line ();
if (iface_name != "NCM Control" && iface_name != "AppleUSBEthernet")
return null;
var serial = File.new_build_filename (dev_path, "..", "..", "..", "serial");
if (!serial.query_exists ())
return null;
var serial_stream = new DataInputStream (serial.read ());
return serial_stream.read_line ();
} catch (GLib.Error e) {
throw new Error.NOT_SUPPORTED ("%s", e.message);
}
}
}
public class LinuxPairingBrowser : Object, PairingBrowser {
private Resolved.Manager? resolved;
private Source? timer;
private Cancellable io_cancellable = new Cancellable ();
private const size_t IF_NAMESIZE = 16;
public async void start (Cancellable? cancellable) throws IOError {
try {
var connection = yield GLib.Bus.get (BusType.SYSTEM, cancellable);
resolved = yield connection.get_proxy (Resolved.SERVICE_NAME, Resolved.SERVICE_PATH, DO_NOT_LOAD_PROPERTIES,
cancellable);
try {
yield resolve_services (MDNS_IPV6 | NO_NETWORK, cancellable);
schedule_next_poll ();
} catch (Error e) {
handle_poll_timer_tick.begin ();
}
} catch (GLib.Error e) {
}
}
public async void stop (Cancellable? cancellable) throws IOError {
if (timer != null) {
timer.destroy ();
timer = null;
}
io_cancellable.cancel ();
}
private void schedule_next_poll () {
timer = new TimeoutSource.seconds (5);
timer.set_callback (() => {
timer = null;
handle_poll_timer_tick.begin ();
return Source.REMOVE;
});
timer.attach (MainContext.get_thread_default ());
}
private async void handle_poll_timer_tick () {
try {
yield resolve_services (MDNS_IPV6, io_cancellable);
schedule_next_poll ();
} catch (GLib.Error e) {
if (!(e is IOError.CANCELLED))
schedule_next_poll ();
}
}
private async void resolve_services (Resolved.Flags flags, Cancellable? cancellable) throws Error, IOError {
Resolved.RRItem[] items;
uint64 ptr_flags;
try {
yield resolved.resolve_record (Resolved.ANY_INTERFACE, PairingService.DNS_SD_NAME, DnsRecordClass.IN,
DnsRecordType.PTR, flags, cancellable, out items, out ptr_flags);
} catch (GLib.Error e) {
throw (Error) parse_error (e);
}
var promises = new Gee.ArrayQueue<Promise<PairingServiceDetails?>> ();
foreach (var item in items) {
var pr = new DnsPacketReader (new Bytes (item.data));
DnsPtrRecord ptr = pr.read_ptr ();
var promise = new Promise<PairingServiceDetails> ();
resolve_service.begin (ptr, item.ifindex, flags, cancellable, promise);
promises.offer (promise);
}
Promise<PairingServiceDetails?>? p;
while ((p = promises.poll ()) != null) {
try {
yield p.future.wait_async (cancellable);
} catch (Error e) {
}
}
}
private async void resolve_service (DnsPtrRecord ptr, int32 ifindex, Resolved.Flags flags, Cancellable? cancellable,
Promise<PairingServiceDetails?> promise) {
try {
PairingServiceDetails? service = yield do_resolve_service (ptr, ifindex, flags, cancellable);
promise.resolve (service);
} catch (GLib.Error e) {
promise.reject (e);
}
}
private async PairingServiceDetails? do_resolve_service (DnsPtrRecord ptr, int32 ifindex, Resolved.Flags flags,
Cancellable? cancellable) throws Error, IOError {
Resolved.SrvItem[] srv_items;
Variant txt_items;
string canonical_name;
string canonical_type;
string canonical_domain;
uint64 srv_flags;
try {
yield resolved.resolve_service (ifindex, "", "", ptr.name, Posix.AF_INET6, flags, cancellable,
out srv_items, out txt_items, out canonical_name, out canonical_type, out canonical_domain,
out srv_flags);
} catch (GLib.Error e) {
throw (Error) parse_error (e);
}
var txt_record = new Gee.ArrayList<string> ();
foreach (var raw_item in txt_items) {
string item = ((string *) raw_item.get_data ())->substring (0, (long) raw_item.get_size ());
if (!item.validate ())
throw new Error.PROTOCOL ("Invalid TXT item");
txt_record.add (item);
}
var meta = PairingServiceMetadata.from_txt_record (txt_record);
var ip = new InetAddress.from_bytes (srv_items[0].addresses[0].ip, IPV6);
var service = new PairingServiceDetails () {
identifier = meta.identifier,
auth_tag = meta.auth_tag,
endpoint = (InetSocketAddress) Object.new (typeof (InetSocketAddress),
address: ip,
port: srv_items[0].port,
scope_id: ip.get_is_link_local () ? ifindex : 0
),
interface_address = resolve_interface_address (ifindex),
};
service_discovered (service);
return service;
}
private static InetSocketAddress resolve_interface_address (int32 ifindex) throws Error {
char ifname_buf[IF_NAMESIZE];
unowned string? ifname = Linux.Network.if_indextoname (ifindex, (string) ifname_buf);
if (ifname == null)
throw new Error.INVALID_ARGUMENT ("Unable to resolve interface name");
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_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));
}
throw new Error.NOT_SUPPORTED ("Unable to resolve interface address");
}
private static GLib.Error parse_error (GLib.Error e) {
if (e is Error || e is IOError.CANCELLED)
return e;
return new Error.TRANSPORT ("%s", e.message);
}
}
namespace Resolved {
public const string SERVICE_NAME = "org.freedesktop.resolve1";
public const string SERVICE_PATH = "/org/freedesktop/resolve1";
public const int32 ANY_INTERFACE = 0;
[DBus (name = "org.freedesktop.resolve1.Manager")]
public interface Manager : Object {
public abstract async void resolve_record (int32 ifindex, string name, uint16 klass, uint16 type, uint64 flags,
Cancellable? cancellable, out RRItem[] items, out uint64 result_flags) throws GLib.Error;
public abstract async void resolve_service (int32 ifindex, string name, string type, string domain, int32 family,
uint64 flags, Cancellable? cancellable, out SrvItem[] srv_items,
[DBus (signature = "aay")] out Variant txt_items, out string canonical_name, out string canonical_type,
out string canonical_domain, out uint64 result_flags) throws GLib.Error;
}
[Flags]
public enum Flags {
DNS = 1 << 0,
LLMNR_IPV4 = 1 << 1,
LLMNR_IPV6 = 1 << 2,
MDNS_IPV4 = 1 << 3,
MDNS_IPV6 = 1 << 4,
NO_CNAME = 1 << 5,
NO_TXT = 1 << 6,
NO_ADDRESS = 1 << 7,
NO_SEARCH = 1 << 8,
AUTHENTICATED = 1 << 9,
NO_VALIDATE = 1 << 10,
NO_SYNTHESIZE = 1 << 11,
NO_CACHE = 1 << 12,
NO_ZONE = 1 << 13,
NO_TRUST_ANCHOR = 1 << 14,
NO_NETWORK = 1 << 15,
REQUIRE_PRIMARY = 1 << 16,
CLAMP_TTL = 1 << 17,
CONFIDENTIAL = 1 << 18,
SYNTHETIC = 1 << 19,
FROM_CACHE = 1 << 20,
FROM_ZONE = 1 << 21,
FROM_TRUST_ANCHOR = 1 << 22,
FROM_NETWORK = 1 << 23,
NO_STALE = 1 << 24,
RELAX_SINGLE_LABEL = 1 << 25,
}
public struct RRItem {
public int32 ifindex;
public uint16 klass;
public uint16 type;
public uint8[] data;
}
public struct SrvItem {
public uint16 priority;
public uint16 weight;
public uint16 port;
public string name;
public SrvAddress[] addresses;
public string canonical_name;
}
public struct SrvAddress {
public int32 ifindex;
public int32 family;
public uint8[] ip;
}
}
}
+585
View File
@@ -0,0 +1,585 @@
[CCode (gir_namespace = "FridaFruity", gir_version = "1.0")]
namespace Frida.Fruity {
public sealed class MacOSCoreDeviceBackend : Object, Backend {
private Gee.Map<string, MacOSCoreDeviceTransport> transports = new Gee.HashMap<string, MacOSCoreDeviceTransport> ();
private Promise<bool> all_current_devices_listed = new Promise<bool> ();
private Promise<bool> browse_request = new Promise<bool> ();
private XpcClient? pairingd;
private Darwin.GCD.DispatchQueue queue =
new Darwin.GCD.DispatchQueue ("re.frida.fruity.remotepairing", Darwin.GCD.DispatchQueueAttr.SERIAL);
public async void start (Cancellable? cancellable) throws IOError {
pairingd = XpcClient.make_for_mach_service ("com.apple.CoreDevice.remotepairingd", queue);
pairingd.notify["state"].connect (on_state_changed);
pairingd.message.connect (on_message);
do_browse.begin ();
try {
yield all_current_devices_listed.future.wait_async (cancellable);
} catch (Error e) {
}
}
private async void do_browse () {
try {
var r = new PairingdRequest ("RemotePairing.BrowseRequest");
r.body.set_bool ("currentDevicesOnly", false);
yield pairingd.request (r.message, null);
browse_request.resolve (true);
} catch (GLib.Error e) {
browse_request.reject (e);
}
}
public async void stop (Cancellable? cancellable) throws IOError {
}
private void on_state_changed (Object obj, ParamSpec pspec) {
if (pairingd.state == CLOSED && !all_current_devices_listed.future.ready) {
all_current_devices_listed.reject (
new Error.TRANSPORT ("Connection closed while waiting for initial device list"));
}
}
private void on_message (Darwin.Xpc.Object obj) {
var reader = new XpcObjectReader (obj);
try {
reader.read_member ("mangledTypeName");
if (reader.get_string_value () == "RemotePairing.ServiceEvent") {
reader
.end_member ()
.read_member ("value");
if (reader.try_read_member ("deviceFound")) {
reader
.read_member ("_0")
.read_member ("deviceInfo");
var udid = reader.read_member ("udid").get_string_value ();
reader.end_member ();
if (transports.has_key (udid))
return;
var device_info = (Darwin.Xpc.Dictionary) reader.current_object;
var pairing_device = new XpcClient (device_info.create_connection ("endpoint"), queue);
on_device_found (udid, pairing_device, device_info);
} else if (reader.try_read_member ("allCurrentDevicesListed")) {
all_current_devices_listed.resolve (true);
}
}
} catch (Error e) {
}
}
private void on_device_found (string udid, XpcClient pairing_device, Darwin.Xpc.Dictionary device_info) throws Error {
var transport = new MacOSCoreDeviceTransport (udid, pairing_device, device_info);
transport.closed.connect (on_transport_closed);
transports[udid] = transport;
transport_attached (transport);
}
private void on_transport_closed (MacOSCoreDeviceTransport transport) {
transport_detached (transport);
transports.unset (transport.udid);
}
}
public sealed class MacOSCoreDeviceTransport : Object, Transport {
public signal void closed ();
public XpcClient pairing_device {
get;
construct;
}
public ConnectionType connection_type {
get {
return _connection_type;
}
}
public string udid {
get {
return _udid;
}
}
public string? name {
get {
return _name;
}
}
public Variant? icon {
get {
return null;
}
}
public UsbmuxDevice? usbmux_device {
get {
return null;
}
}
private ConnectionType _connection_type;
private string _udid;
private string _name;
private Promise<Tunnel>? tunnel_request;
private Cancellable io_cancellable = new Cancellable ();
public MacOSCoreDeviceTransport (string udid, XpcClient pairing_device, Darwin.Xpc.Dictionary device_info) throws Error {
Object (pairing_device: pairing_device);
_udid = udid;
update_device_info (device_info);
}
construct {
pairing_device.notify["state"].connect (on_state_changed);
pairing_device.message.connect (on_message);
}
private void update_device_info (Darwin.Xpc.Dictionary device_info) throws Error {
_connection_type = (device_info.get_value ("untrustedRSDDeviceInfo") != null)
? ConnectionType.USB
: ConnectionType.NETWORK;
var reader = new XpcObjectReader (device_info);
_name = reader.read_member ("name").get_string_value ();
reader.end_member ();
}
private void on_state_changed (Object obj, ParamSpec pspec) {
if (pairing_device.state == CLOSED) {
io_cancellable.cancel ();
closed ();
}
}
private void on_message (Darwin.Xpc.Object obj) {
var reader = new XpcObjectReader (obj);
try {
reader.read_member ("mangledTypeName");
if (reader.get_string_value () == "RemotePairing.ServiceEvent") {
reader
.end_member ()
.read_member ("value");
if (reader.try_read_member ("deviceFound")) {
reader
.read_member ("_0")
.read_member ("deviceInfo");
var device_info = (Darwin.Xpc.Dictionary)
reader.get_object_value (Darwin.Xpc.Dictionary.TYPE);
update_device_info (device_info);
} else if (reader.try_read_member ("tunnelUsageAssertionsInvalidated")) {
reader.read_member ("assertionIdentifiers");
var ids = new Gee.ArrayList<Bytes> ();
size_t n = reader.count_elements ();
for (size_t i = 0; i != n; i++) {
reader.read_element (i);
ids.add (new Bytes (reader.get_uuid_value ()));
reader.end_element ();
}
on_tunnel_usage_assertions_invalidated.begin (ids);
}
}
} catch (Error e) {
}
}
private async void on_tunnel_usage_assertions_invalidated (Gee.List<Bytes> ids) {
if (tunnel_request == null)
return;
try {
var tunnel = (MacOSTunnel) yield tunnel_request.future.wait_async (io_cancellable);
unowned uint8[] tunnel_assertion_id = tunnel.assertion_identifier.get_bytes ();
foreach (var id in ids) {
if (Memory.cmp (id.get_data (), tunnel_assertion_id, id.get_size ()) == 0) {
tunnel_request = null;
return;
}
}
} catch (GLib.Error e) {
}
}
public async Tunnel? find_tunnel (UsbmuxDevice? device, Cancellable? cancellable) throws Error, IOError {
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 {
var tunnel = new MacOSTunnel (pairing_device);
yield tunnel.attach (cancellable);
tunnel_request.resolve (tunnel);
return tunnel;
} catch (GLib.Error e) {
tunnel_request.reject (e);
tunnel_request = null;
throw_api_error (e);
}
}
}
public sealed class MacOSTunnel : Object, Tunnel {
public DiscoveryService discovery {
get {
return _discovery;
}
}
public Darwin.Xpc.Uuid? assertion_identifier {
get {
return _assertion_identifier;
}
}
private XpcClient pairing_device;
private Darwin.Xpc.Uuid? _assertion_identifier;
private InetAddress? tunnel_device_address;
private DiscoveryService? _discovery;
public MacOSTunnel (XpcClient pairing_device) {
this.pairing_device = pairing_device;
}
public async void close (Cancellable? cancellable) throws IOError {
var r = new PairingdRequest ("RemotePairing.ReleaseAssertionRequest");
r.body.set_value ("assertionIdentifier", _assertion_identifier);
try {
yield pairing_device.request (r.message, cancellable);
} catch (Error e) {
}
}
public async void attach (Cancellable? cancellable) throws Error, IOError {
var r = new PairingdRequest ("RemotePairing.CreateAssertionCommand");
r.body.set_int64 ("flags", 0);
var response = yield pairing_device.request (r.message, cancellable);
var reader = new XpcObjectReader (response);
reader.read_member ("response");
_assertion_identifier = (Darwin.Xpc.Uuid) reader
.read_member ("assertionIdentifier")
.get_object_value (Darwin.Xpc.Uuid.TYPE);
reader.end_member ();
string tunnel_ip_address = reader
.read_member ("info")
.read_member ("tunnelIPAddress")
.get_string_value ();
tunnel_device_address = new InetAddress.from_string (tunnel_ip_address);
_discovery = yield locate_discovery_service (tunnel_device_address, cancellable);
}
public async IOStream open_tcp_connection (uint16 port, Cancellable? cancellable) throws Error, IOError {
SocketConnection connection;
try {
var service_address = new InetSocketAddress (tunnel_device_address, port);
var client = new SocketClient ();
connection = yield client.connect_async (service_address, cancellable);
} catch (GLib.Error e) {
if (e is IOError.CONNECTION_REFUSED)
throw new Error.SERVER_NOT_RUNNING ("%s", e.message);
throw new Error.TRANSPORT ("%s", e.message);
}
Tcp.enable_nodelay (connection.socket);
return connection;
}
private static async DiscoveryService locate_discovery_service (InetAddress tunnel_device_address, Cancellable? cancellable)
throws Error, IOError {
var main_context = MainContext.get_thread_default ();
var path_buf = new char[4096];
unowned string path = (string) path_buf;
uint delays[] = { 0, 50, 250 };
for (uint attempts = 0; attempts != delays.length; attempts++) {
uint delay = delays[attempts];
if (delay != 0) {
var timeout_source = new TimeoutSource (delay);
timeout_source.set_callback (locate_discovery_service.callback);
timeout_source.attach (main_context);
var cancel_source = new CancellableSource (cancellable);
cancel_source.set_callback (locate_discovery_service.callback);
cancel_source.attach (main_context);
yield;
cancel_source.destroy ();
timeout_source.destroy ();
if (cancellable.is_cancelled ())
break;
}
foreach (var item in XNU.query_active_tcp_connections ()) {
if (item.family != IPV6)
continue;
if (!item.foreign_address.equal (tunnel_device_address))
continue;
if (Darwin.XNU.proc_pidpath (item.effective_pid, path_buf) <= 0)
continue;
if (path != "/usr/libexec/remoted")
continue;
try {
var connectable = new InetSocketAddress (tunnel_device_address, item.foreign_port);
var sc = new SocketClient ();
SocketConnection connection = yield sc.connect_async (connectable, cancellable);
Tcp.enable_nodelay (connection.socket);
return yield DiscoveryService.open (connection, cancellable);
} catch (GLib.Error e) {
}
}
}
throw new Error.NOT_SUPPORTED ("Unable to detect RSD port");
}
}
private sealed class PairingdRequest {
public Darwin.Xpc.Dictionary message = new Darwin.Xpc.Dictionary ();
public Darwin.Xpc.Dictionary body = new Darwin.Xpc.Dictionary ();
public PairingdRequest (string name) {
message.set_string ("mangledTypeName", name);
message.set_value ("value", body);
}
}
namespace XNU {
public PcbList query_active_tcp_connections () {
size_t size = 0;
Darwin.XNU.sysctlbyname ("net.inet.tcp.pcblist_n", null, &size);
var pcbs = new uint8[size];
Darwin.XNU.sysctlbyname ("net.inet.tcp.pcblist_n", pcbs, &size);
return new PcbList (pcbs);
}
public class PcbList {
private uint8[] pcbs;
internal PcbList (owned uint8[] pcbs) {
this.pcbs = (owned) pcbs;
}
public Iterator iterator () {
return new Iterator (this);
}
public class Iterator {
private PcbList list;
private InetItem * cursor;
internal Iterator (PcbList list) {
this.list = list;
var gen = (Darwin.XNU.InetPcbGeneration *) list.pcbs;
cursor = (InetItem *) ((uint8 *) list.pcbs + gen->length);
}
public Item? next_value () {
InetPcb * pcb = null;
while (true) {
if (cursor->length == 24)
return null;
switch (cursor->kind) {
case InetItemKind.PCB:
pcb = (InetPcb *) cursor;
break;
case InetItemKind.SOCKET:
var item = new Item (*pcb, *((InetSocket *) cursor));
advance ();
return item;
}
advance ();
}
}
private void advance () {
uint32 l = cursor->length;
if (l % 8 != 0)
l += 8 - (l % 8);
cursor = (InetItem *) ((uint8 *) cursor + l);
}
}
public class Item {
public SocketFamily family {
get {
return ((pcb.version_flag & Darwin.XNU.InetVersionFlags.IPV6) != 0)
? SocketFamily.IPV6
: SocketFamily.IPV4;
}
}
public InetAddress local_address {
get {
if (cached_local_address == null)
cached_local_address = parse_address (pcb.local_address);
return cached_local_address;
}
}
public uint16 local_port {
get {
return uint16.from_big_endian (pcb.local_port);
}
}
public InetAddress foreign_address {
get {
if (cached_foreign_address == null)
cached_foreign_address = parse_address (pcb.foreign_address);
return cached_foreign_address;
}
}
public uint16 foreign_port {
get {
return uint16.from_big_endian (pcb.foreign_port);
}
}
public int32 effective_pid {
get {
return sock.effective_pid;
}
}
private InetPcb pcb;
private InetSocket sock;
private InetAddress? cached_local_address;
private InetAddress? cached_foreign_address;
public Item (InetPcb pcb, InetSocket sock) {
this.pcb = pcb;
this.sock = sock;
}
private InetAddress parse_address (uint8[] bytes) {
if ((pcb.version_flag & Darwin.XNU.InetVersionFlags.IPV6) != 0)
return new InetAddress.from_bytes (bytes, IPV6);
var addr = (Darwin.XNU.InetAddr4in6 *) bytes;
return new InetAddress.from_bytes ((uint8[]) &addr->addr4.s_addr, IPV4);
}
}
}
[SimpleType]
public struct InetItem {
public uint32 length;
public uint32 kind;
}
public enum InetItemKind {
SOCKET = 0x001,
PCB = 0x010,
}
[SimpleType]
public struct InetPcb {
public uint32 length;
public uint32 kind;
public uint64 inpp;
public uint16 foreign_port;
public uint16 local_port;
public uint32 per_protocol_pcb_low;
public uint32 per_protocol_pcb_high;
public uint32 generation_count_low;
public uint32 generation_count_high;
public int flags;
public uint32 flow;
public uint8 version_flag;
public uint8 ip_ttl;
public uint8 ip_protocol;
public uint8 padding;
public uint8 foreign_address[16];
public uint8 local_address[16];
public InetDepend4 depend4;
public InetDepend6 depend6;
public uint32 flowhash;
public uint32 flags2;
}
[SimpleType]
public struct InetSocket {
public uint32 length;
public uint32 kind;
public uint64 so;
public int16 type;
public uint16 options_low;
public uint16 options_high;
public int16 linger;
public int16 state;
public uint16 pcb[4];
public uint16 protocol_low;
public uint16 protocol_high;
public uint16 family_low;
public uint16 family_high;
public int16 qlen;
public int16 incqlen;
public int16 qlimit;
public int16 timeo;
public uint16 error;
public int32 pgid;
public uint32 oobmark;
public uint32 uid;
public int32 last_pid;
public int32 effective_pid;
public uint64 gencnt;
public uint32 flags;
public uint32 flags1;
public int32 usecount;
public int32 retaincnt;
public uint32 filter_flags;
}
[SimpleType]
public struct InetDepend4 {
public uint8 ip_tos;
}
[SimpleType]
public struct InetDepend6 {
public uint8 hlim;
public int checksum;
public uint16 interface_index;
public int16 hops;
}
}
}
@@ -3,7 +3,7 @@
#include "frida-base.h"
void
_frida_fruity_host_session_backend_extract_details_for_device (gint product_id, const char * udid, char ** name, GVariant ** icon,
_frida_fruity_usbmux_backend_extract_details_for_device (gint product_id, const char * udid, char ** name, GVariant ** icon,
GError ** error)
{
*name = g_strdup ("iOS Device");
@@ -2,8 +2,12 @@
#include "../windows/icon-helpers.h"
#include <setupapi.h>
#include <devguid.h>
#include <iphlpapi.h>
#include <setupapi.h>
#include <windns.h>
typedef struct _FridaPairingBrowserBackend FridaPairingBrowserBackend;
typedef struct _FridaMobileDeviceInfo FridaMobileDeviceInfo;
typedef struct _FridaImageDeviceInfo FridaImageDeviceInfo;
@@ -13,8 +17,18 @@ typedef struct _FridaFindImageDeviceContext FridaFindImageDeviceContext;
typedef struct _FridaDeviceInfo FridaDeviceInfo;
typedef struct _FridaDnsApi FridaDnsApi;
typedef gboolean (* FridaEnumerateDeviceFunc) (const FridaDeviceInfo * device_info, gpointer user_data);
struct _FridaPairingBrowserBackend
{
FridaFruityWindowsPairingBrowserResultCallback callback;
gpointer callback_target;
DNS_SERVICE_CANCEL browse_handle;
};
struct _FridaMobileDeviceInfo
{
WCHAR * location;
@@ -49,6 +63,14 @@ struct _FridaDeviceInfo
PSP_DEVINFO_DATA device_info_data;
};
struct _FridaDnsApi
{
DNS_STATUS (WINAPI * browse) (DNS_SERVICE_BROWSE_REQUEST * request, DNS_SERVICE_CANCEL * cancel);
DNS_STATUS (WINAPI * browse_cancel) (DNS_SERVICE_CANCEL * cancel_handle);
};
static void WINAPI frida_fruity_windows_pairing_browser_on_browse_results (void * query_context, DNS_QUERY_RESULT * query_results);
static FridaMobileDeviceInfo * find_mobile_device_by_udid (const WCHAR * udid);
static FridaImageDeviceInfo * find_image_device_by_location (const WCHAR * location);
@@ -68,10 +90,110 @@ static WCHAR * frida_read_registry_string (HKEY key, WCHAR * value_name);
static WCHAR * frida_read_registry_multi_string (HKEY key, WCHAR * value_name);
static gpointer frida_read_registry_value (HKEY key, WCHAR * value_name, DWORD expected_type);
static FridaDnsApi * frida_try_get_dns_api (void);
static GUID GUID_APPLE_USB = { 0xF0B32BE3, 0x6678, 0x4879, { 0x92, 0x30, 0x0E4, 0x38, 0x45, 0xD8, 0x05, 0xEE } };
void
_frida_fruity_host_session_backend_extract_details_for_device (gint product_id, const char * udid, char ** name, GVariant ** icon,
_frida_fruity_windows_pairing_browser_enumerate_network_interfaces (FridaFruityWindowsPairingBrowserNetifFoundFunc func,
gpointer func_target)
{
IP_ADAPTER_ADDRESSES * adapters;
ULONG buffer_size, result;
IP_ADAPTER_ADDRESSES_LH * adapter;
if (frida_try_get_dns_api () == NULL)
return;
buffer_size = 32768;
adapters = g_malloc (buffer_size);
do
{
result = GetAdaptersAddresses (AF_INET6, 0, NULL, adapters, &buffer_size);
if (result != ERROR_BUFFER_OVERFLOW)
break;
adapters = g_realloc (adapters, buffer_size);
}
while (result == ERROR_BUFFER_OVERFLOW);
if (result != ERROR_SUCCESS)
goto beach;
for (adapter = adapters; adapter != NULL; adapter = adapter->Next)
{
SOCKET_ADDRESS * raw_addr;
GInetSocketAddress * addr;
if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK)
continue;
if (adapter->FirstUnicastAddress == NULL)
continue;
raw_addr = &adapter->FirstUnicastAddress->Address;
addr = G_INET_SOCKET_ADDRESS (g_socket_address_new_from_native (raw_addr->lpSockaddr, raw_addr->iSockaddrLength));
func (adapter->IfIndex, adapter->AdapterName, addr, func_target);
}
beach:
g_free (adapters);
}
void *
_frida_fruity_windows_pairing_browser_monitor_create_backend (gulong interface_index,
FridaFruityWindowsPairingBrowserResultCallback callback, gpointer callback_target)
{
FridaPairingBrowserBackend * backend;
FridaDnsApi * api;
DNS_SERVICE_BROWSE_REQUEST r = { 0, };
api = frida_try_get_dns_api ();
if (api == NULL)
return NULL;
backend = g_slice_new0 (FridaPairingBrowserBackend);
backend->callback = callback;
backend->callback_target = callback_target;
r.Version = DNS_QUERY_REQUEST_VERSION2;
r.InterfaceIndex = interface_index;
r.QueryName = G_PASTE (L, FRIDA_FRUITY_PAIRING_SERVICE_DNS_SD_NAME);
r.pBrowseCallbackV2 = frida_fruity_windows_pairing_browser_on_browse_results;
r.pQueryContext = backend;
if (api->browse (&r, &backend->browse_handle) != DNS_REQUEST_PENDING)
{
g_slice_free (FridaPairingBrowserBackend, backend);
return NULL;
}
return backend;
}
void
_frida_fruity_windows_pairing_browser_monitor_destroy_backend (void * opaque_backend)
{
FridaPairingBrowserBackend * backend = opaque_backend;
if (backend == NULL)
return;
frida_try_get_dns_api ()->browse_cancel (&backend->browse_handle);
g_slice_free (FridaPairingBrowserBackend, backend);
}
static void WINAPI
frida_fruity_windows_pairing_browser_on_browse_results (void * query_context, DNS_QUERY_RESULT * query_results)
{
FridaPairingBrowserBackend * backend = query_context;
backend->callback (query_results, backend->callback_target);
}
void
_frida_fruity_usbmux_backend_extract_details_for_device (gint product_id, const char * udid, char ** name, GVariant ** icon,
GError ** error)
{
gboolean result = FALSE;
@@ -426,3 +548,30 @@ beach:
return buffer;
}
static FridaDnsApi *
frida_try_get_dns_api (void)
{
static gsize api_value = 0;
if (g_once_init_enter (&api_value))
{
HMODULE mod;
FARPROC browse;
FridaDnsApi * api = NULL;
mod = GetModuleHandleW (L"dnsapi.dll");
browse = GetProcAddress (mod, "DnsServiceBrowse");
if (browse != NULL)
{
api = g_slice_new (FridaDnsApi);
api->browse = (gpointer) browse;
api->browse_cancel = (gpointer) GetProcAddress (mod, "DnsServiceBrowseCancel");
}
g_once_init_leave (&api_value, GPOINTER_TO_SIZE (api) + 1);
}
return GSIZE_TO_POINTER (api_value - 1);
}
+102
View File
@@ -0,0 +1,102 @@
[CCode (gir_namespace = "FridaFruity", gir_version = "1.0")]
namespace Frida.Fruity {
public class WindowsPairingBrowser : Object, PairingBrowser {
private Gee.Map<string, Monitor> monitors = new Gee.HashMap<string, Monitor> ();
private MainContext main_context = MainContext.ref_thread_default ();
public async void start (Cancellable? cancellable) throws IOError {
_enumerate_network_interfaces ((index, name, address) => {
var monitor = new Monitor (this, index, address);
monitors[name] = monitor;
});
}
public async void stop (Cancellable? cancellable) throws IOError {
monitors.clear ();
}
private void on_result (WinDns.QueryResult * result, InetSocketAddress interface_address) {
try {
PairingServiceDetails service = parse_result (result, interface_address);
var source = new IdleSource ();
source.set_callback (() => {
service_discovered (service);
return Source.REMOVE;
});
source.attach (main_context);
} catch (GLib.Error e) {
}
}
private static PairingServiceDetails parse_result (WinDns.QueryResult * res,
InetSocketAddress interface_address) throws GLib.Error {
PairingServiceMetadata? meta = null;
InetAddress? ip = null;
uint16 port = 0;
for (WinDns.Record * r = res->query_records; r != null; r = r->next) {
switch (r->type) {
case TEXT:
WinDns.TxtData * txt = &r->txt;
var txt_record = new Gee.ArrayList<string> ();
foreach (unowned string16 str in txt->strings)
txt_record.add (str.to_utf8 ());
meta = PairingServiceMetadata.from_txt_record (txt_record);
break;
case AAAA:
ip = new InetAddress.from_bytes (r->aaaa.ip.data, IPV6);
break;
case SRV:
port = r->srv.port;
break;
default:
break;
}
}
if (meta == null || ip == null || port == 0)
throw new Error.PROTOCOL ("Incomplete result");
return new PairingServiceDetails () {
identifier = meta.identifier,
auth_tag = meta.auth_tag,
endpoint = (InetSocketAddress) Object.new (typeof (InetSocketAddress),
address: ip,
port: port,
scope_id: ip.get_is_link_local () ? interface_address.get_scope_id () : 0
),
interface_address = interface_address,
};
}
private class Monitor {
private weak WindowsPairingBrowser parent;
private InetSocketAddress interface_address;
private void * backend;
public Monitor (WindowsPairingBrowser parent, ulong interface_index, InetSocketAddress interface_address) {
this.parent = parent;
this.interface_address = interface_address;
backend = _create_backend (interface_index, on_result);
}
~Monitor () {
_destroy_backend (backend);
}
private void on_result (void * result) {
parent.on_result (result, interface_address);
}
public extern static void * _create_backend (ulong interface_index, ResultCallback callback);
public extern static void _destroy_backend (void * backend);
}
public extern static void _enumerate_network_interfaces (NetifFoundFunc func);
public delegate void NetifFoundFunc (ulong index, string identifier, owned InetSocketAddress address);
public delegate void ResultCallback (void * result);
}
}
File diff suppressed because it is too large. Load diff
+174
View File
@@ -0,0 +1,174 @@
[CCode (gir_namespace = "FridaFruity", gir_version = "1.0")]
namespace Frida.Fruity {
public class DnsPacketReader {
private BufferReader reader;
public DnsPacketReader (Bytes packet) {
reader = new BufferReader (new Buffer (packet, BIG_ENDIAN));
}
public DnsPtrRecord read_ptr () throws Error {
var rr = read_record ();
if (rr.key.type != PTR)
throw new Error.PROTOCOL ("Expected a PTR record");
if (rr.key.klass != IN)
throw new Error.PROTOCOL ("Expected a PTR record of class IN");
var subreader = new DnsPacketReader (rr.data);
var name = subreader.read_name ();
return new DnsPtrRecord () {
key = rr.key,
ttl = rr.ttl,
data = rr.data,
name = name,
};
}
public DnsTxtRecord read_txt () throws Error {
var rr = read_record ();
if (rr.key.type != TXT)
throw new Error.PROTOCOL ("Expected a TXT record");
if (rr.key.klass != IN)
throw new Error.PROTOCOL ("Expected a TXT record of class IN");
var entries = new Gee.ArrayList<string> ();
var subreader = new DnsPacketReader (rr.data);
while (subreader.reader.available != 0) {
string text = subreader.read_string ();
entries.add (text);
}
return new DnsTxtRecord () {
key = rr.key,
ttl = rr.ttl,
data = rr.data,
entries = entries.to_array (),
};
}
public DnsAaaaRecord read_aaaa () throws Error {
var rr = read_record ();
if (rr.key.type != AAAA)
throw new Error.PROTOCOL ("Expected an AAAA record");
if (rr.key.klass != IN)
throw new Error.PROTOCOL ("Expected an AAAA record of class IN");
var subreader = new DnsPacketReader (rr.data);
var raw_address = subreader.reader.read_bytes (16);
var address = new InetAddress.from_bytes (raw_address.get_data (), IPV6);
return new DnsAaaaRecord () {
key = rr.key,
ttl = rr.ttl,
data = rr.data,
address = address,
};
}
public DnsSrvRecord read_srv () throws Error {
var rr = read_record ();
if (rr.key.type != SRV)
throw new Error.PROTOCOL ("Expected a SRV record");
if (rr.key.klass != IN)
throw new Error.PROTOCOL ("Expected a SRV record of class IN");
var subreader = new DnsPacketReader (rr.data);
var priority = subreader.reader.read_uint16 ();
var weight = subreader.reader.read_uint16 ();
var port = subreader.reader.read_uint16 ();
var name = subreader.read_name ();
return new DnsSrvRecord () {
key = rr.key,
ttl = rr.ttl,
data = rr.data,
priority = priority,
weight = weight,
port = port,
name = name,
};
}
public DnsResourceRecord read_record () throws Error {
var key = read_key ();
var ttl = reader.read_uint32 ();
var size = reader.read_uint16 ();
var data = reader.read_bytes (size);
return new DnsResourceRecord () {
key = key,
ttl = ttl,
data = data,
};
}
public DnsResourceKey read_key () throws Error {
var name = read_name ();
var type = reader.read_uint16 ();
var klass = reader.read_uint16 ();
return new DnsResourceKey () {
name = name,
type = type,
klass = klass,
};
}
public string read_name () throws Error {
var name = new StringBuilder.sized (256);
while (true) {
size_t size = reader.read_uint8 ();
if (size == 0)
break;
if (size > 63)
throw new Error.PROTOCOL ("Invalid DNS name length");
var label = reader.read_fixed_string (size);
if (name.len != 0)
name.append_c ('.');
name.append (label);
}
return name.str;
}
public string read_string () throws Error {
size_t size = reader.read_uint8 ();
return reader.read_fixed_string (size);
}
}
public class DnsPtrRecord : DnsResourceRecord {
public string name;
}
public class DnsTxtRecord : DnsResourceRecord {
public string[] entries;
}
public class DnsAaaaRecord : DnsResourceRecord {
public InetAddress address;
}
public class DnsSrvRecord : DnsResourceRecord {
public uint16 priority;
public uint16 weight;
public uint16 port;
public string name;
}
public class DnsResourceRecord {
public DnsResourceKey key;
public uint32 ttl;
public Bytes data;
}
public class DnsResourceKey {
public string name;
public DnsRecordType type;
public DnsRecordClass klass;
}
public enum DnsRecordType {
PTR = 12,
TXT = 16,
AAAA = 28,
SRV = 33,
}
public enum DnsRecordClass {
IN = 1,
}
}
+168 -153
View File
@@ -1,18 +1,18 @@
[CCode (gir_namespace = "FridaFruity", gir_version = "1.0")]
namespace Frida.Fruity {
public class DeviceInfoService : Object, AsyncInitable {
public ChannelProvider channel_provider {
public HostChannelProvider channel_provider {
get;
construct;
}
private DTXChannel channel;
private DeviceInfoService (ChannelProvider channel_provider) {
private DeviceInfoService (HostChannelProvider channel_provider) {
Object (channel_provider: channel_provider);
}
public static async DeviceInfoService open (ChannelProvider channel_provider, Cancellable? cancellable = null)
public static async DeviceInfoService open (HostChannelProvider channel_provider, Cancellable? cancellable = null)
throws Error, IOError {
var service = new DeviceInfoService (channel_provider);
@@ -74,21 +74,53 @@ namespace Frida.Fruity {
return "/private" + name;
return name;
}
public class ProcessInfo : Object {
public uint pid {
get;
set;
}
public string name {
get;
set;
}
public string real_app_name {
get;
set;
}
public bool is_application {
get;
set;
}
public bool foreground_running {
get;
set;
}
public DateTime? start_date {
get;
set;
}
}
}
public class ApplicationListingService : Object, AsyncInitable {
public ChannelProvider channel_provider {
public HostChannelProvider channel_provider {
get;
construct;
}
private DTXChannel channel;
private ApplicationListingService (ChannelProvider channel_provider) {
private ApplicationListingService (HostChannelProvider channel_provider) {
Object (channel_provider: channel_provider);
}
public static async ApplicationListingService open (ChannelProvider channel_provider, Cancellable? cancellable = null)
public static async ApplicationListingService open (HostChannelProvider channel_provider, Cancellable? cancellable = null)
throws Error, IOError {
var service = new ApplicationListingService (channel_provider);
@@ -178,21 +210,115 @@ namespace Frida.Fruity {
return result;
}
public class ApplicationInfo : Object {
public ApplicationType app_type {
get;
set;
}
public string display_name {
get;
set;
}
public string bundle_identifier {
get;
set;
}
public string bundle_path {
get;
set;
}
public string? version {
get;
set;
}
public bool placeholder {
get;
set;
}
public bool restricted {
get;
set;
}
public string? executable_name {
get;
set;
}
public string[]? app_extension_uuids {
get;
set;
}
public string? plugin_uuid {
get;
set;
}
public string? plugin_identifier {
get;
set;
}
public string? container_bundle_identifier {
get;
set;
}
public string? container_bundle_path {
get;
set;
}
}
public enum ApplicationType {
SYSTEM = 1,
USER,
PLUGIN_KIT;
public static ApplicationType from_nick (string nick) throws Error {
return Marshal.enum_from_nick<ApplicationType> (nick);
}
public string to_nick () {
return Marshal.enum_to_nick<ApplicationType> (this);
}
internal static ApplicationType from_dtx (string type) {
if (type == "System")
return SYSTEM;
if (type == "User")
return USER;
if (type == "PluginKit")
return PLUGIN_KIT;
assert_not_reached ();
}
}
}
public class ProcessControlService : Object, AsyncInitable {
public ChannelProvider channel_provider {
public HostChannelProvider channel_provider {
get;
construct;
}
private DTXChannel channel;
private ProcessControlService (ChannelProvider channel_provider) {
private ProcessControlService (HostChannelProvider channel_provider) {
Object (channel_provider: channel_provider);
}
public static async ProcessControlService open (ChannelProvider channel_provider, Cancellable? cancellable = null)
public static async ProcessControlService open (HostChannelProvider channel_provider, Cancellable? cancellable = null)
throws Error, IOError {
var service = new ProcessControlService (channel_provider);
@@ -220,132 +346,6 @@ namespace Frida.Fruity {
}
}
public class ProcessInfo : Object {
public uint pid {
get;
set;
}
public string name {
get;
set;
}
public string real_app_name {
get;
set;
}
public bool is_application {
get;
set;
}
public bool foreground_running {
get;
set;
}
public DateTime? start_date {
get;
set;
}
}
public class ApplicationInfo : Object {
public ApplicationType app_type {
get;
set;
}
public string display_name {
get;
set;
}
public string bundle_identifier {
get;
set;
}
public string bundle_path {
get;
set;
}
public string? version {
get;
set;
}
public bool placeholder {
get;
set;
}
public bool restricted {
get;
set;
}
public string? executable_name {
get;
set;
}
public string[]? app_extension_uuids {
get;
set;
}
public string? plugin_uuid {
get;
set;
}
public string? plugin_identifier {
get;
set;
}
public string? container_bundle_identifier {
get;
set;
}
public string? container_bundle_path {
get;
set;
}
}
public enum ApplicationType {
SYSTEM = 1,
USER,
PLUGIN_KIT;
public static ApplicationType from_nick (string nick) throws Error {
return Marshal.enum_from_nick<ApplicationType> (nick);
}
public string to_nick () {
return Marshal.enum_to_nick<ApplicationType> (this);
}
internal static ApplicationType from_dtx (string type) {
if (type == "System")
return SYSTEM;
if (type == "User")
return USER;
if (type == "PluginKit")
return PLUGIN_KIT;
assert_not_reached ();
}
}
public class DTXConnection : Object, DTXTransport {
public IOStream stream {
get;
@@ -363,7 +363,7 @@ namespace Frida.Fruity {
CLOSED
}
private static Gee.HashMap<ChannelProvider, Future<DTXConnection>> connections;
private static Gee.HashMap<HostChannelProvider, Future<DTXConnection>> connections;
private State _state = OPEN;
@@ -383,19 +383,21 @@ namespace Frida.Fruity {
private const uint32 DTX_FRAGMENT_MAGIC = 0x1f3d5b79U;
private const uint MAX_BUFFERED_COUNT = 100;
private const size_t MAX_BUFFERED_SIZE = 30 * 1024 * 1024;
private const size_t MAX_MESSAGE_SIZE = 1024 * 1024;
private const size_t MAX_MESSAGE_SIZE = 128 * 1024 * 1024;
private const size_t MAX_FRAGMENT_SIZE = 128 * 1024;
private const string REMOTESERVER_ENDPOINT_MODERN = "lockdown:com.apple.instruments.remoteserver.DVTSecureSocketProxy";
private const string REMOTESERVER_ENDPOINT_17PLUS = "lockdown:com.apple.instruments.dtservicehub";
private const string REMOTESERVER_ENDPOINT_14PLUS = "lockdown:com.apple.instruments.remoteserver.DVTSecureSocketProxy";
private const string REMOTESERVER_ENDPOINT_LEGACY = "lockdown:com.apple.instruments.remoteserver?tls=handshake-only";
private const string[] REMOTESERVER_ENDPOINT_CANDIDATES = {
REMOTESERVER_ENDPOINT_MODERN,
REMOTESERVER_ENDPOINT_17PLUS,
REMOTESERVER_ENDPOINT_14PLUS,
REMOTESERVER_ENDPOINT_LEGACY,
};
public static async DTXConnection obtain (ChannelProvider channel_provider, Cancellable? cancellable)
public static async DTXConnection obtain (HostChannelProvider channel_provider, Cancellable? cancellable)
throws Error, IOError {
if (connections == null)
connections = new Gee.HashMap<ChannelProvider, Future<DTXConnection>> ();
connections = new Gee.HashMap<HostChannelProvider, Future<DTXConnection>> ();
while (connections.has_key (channel_provider)) {
var future = connections[channel_provider];
@@ -442,7 +444,7 @@ namespace Frida.Fruity {
throw api_error;
}
public static async void close_all (ChannelProvider channel_provider, Cancellable? cancellable) throws IOError {
public static async void close_all (HostChannelProvider channel_provider, Cancellable? cancellable) throws IOError {
if (connections == null)
return;
@@ -502,6 +504,14 @@ namespace Frida.Fruity {
process_incoming_fragments.begin ();
}
public override void dispose () {
foreach (var channel in channels.values)
channel.transport = null;
channels.clear ();
base.dispose ();
}
private async void close (Cancellable? cancellable) throws IOError {
io_cancellable.cancel ();
@@ -705,7 +715,9 @@ namespace Frida.Fruity {
int32 channel_code = message.channel_code;
bool is_notification = false;
if (message.type == RESULT && channel_code < 0) {
if (message.type == INVOKE) {
channel_code = -channel_code;
} else if (message.type == RESULT && channel_code < 0) {
channel_code = -channel_code;
is_notification = true;
}
@@ -866,7 +878,7 @@ namespace Frida.Fruity {
public class DTXChannel : Object {
public signal void invocation (string method_name, DTXArgumentList args, DTXMessageTransportFlags transport_flags);
public signal void notification (NSDictionary dict);
public signal void notification (NSObject obj);
public signal void barrier ();
public int32 code {
@@ -874,9 +886,9 @@ namespace Frida.Fruity {
construct;
}
public weak DTXTransport transport {
public weak DTXTransport? transport {
get;
construct;
set;
}
public State state {
@@ -899,7 +911,7 @@ namespace Frida.Fruity {
}
public override void dispose () {
transport.remove_channel (this);
close ();
base.dispose ();
}
@@ -911,6 +923,11 @@ namespace Frida.Fruity {
var error = new Error.TRANSPORT ("Channel closed");
foreach (var request in pending_responses.values.to_array ())
request.reject (error);
if (transport != null) {
transport.remove_channel (this);
transport = null;
}
}
public async NSObject? invoke (string method_name, DTXArgumentListBuilder? args, Cancellable? cancellable)
@@ -1016,10 +1033,8 @@ namespace Frida.Fruity {
}
internal void handle_notification (DTXMessage message) throws Error {
NSDictionary? dict = NSKeyedArchive.decode (message.payload_data) as NSDictionary;
if (dict == null)
throw new Error.PROTOCOL ("Malformed notification payload");
notification (dict);
var payload = NSKeyedArchive.decode (message.payload_data);
notification (payload);
}
internal void handle_barrier (DTXMessage message) throws Error {
@@ -1062,7 +1077,7 @@ namespace Frida.Fruity {
}
public class DTXArgumentList {
private Value[] elements;
public Value[] elements;
private DTXArgumentList (owned Value[] elements) {
this.elements = (owned) elements;
@@ -1101,7 +1116,7 @@ namespace Frida.Fruity {
NSObject? obj = NSKeyedArchive.decode (buf);
if (obj != null) {
var gval = Value (Type.from_instance (obj));
gval.set_instance (obj);
gval.set_boxed (obj);
elements += (owned) gval;
} else {
var gval = Value (typeof (NSObject));
File diff suppressed because it is too large. Load diff
+2
View File
@@ -50,9 +50,11 @@ frida_fetch_dyld_symbols (char * output_buffer, const void * dyld_load_address)
const char * name = strings + sym->n_un.n_strx;
if (frida_str_contains (name, "libdyld_initialize") ||
frida_str_contains (name, "notifyObjCInit") ||
frida_str_contains (name, "restartWithDyldInCache") ||
frida_str_equals (name, "_gProcessInfo") ||
frida_str_equals (name, "__ZN5dyld412gProcessInfoE") ||
frida_str_equals (name, "__ZL12sProcessInfo") ||
frida_str_contains (name, "launchWithClosure") ||
frida_str_contains (name, "initializeMainExecutable") ||
frida_str_contains (name, "registerThreadHelpers") ||
+7 -7
View File
@@ -5,11 +5,15 @@ frida_listen (int rx_buffer_size, const FridaUploadApi * api)
{
uint8_t error_code;
int fd;
struct sockaddr_in addr;
struct sockaddr_in6 addr = {
.sin6_family = AF_INET6,
.sin6_addr = IN6ADDR_ANY_INIT,
.sin6_port = 0,
};
socklen_t addr_len;
int res;
fd = api->socket (AF_INET, SOCK_STREAM, 0);
fd = api->socket (AF_INET6, SOCK_STREAM, 0);
if (fd == -1)
goto socket_failed;
@@ -17,10 +21,6 @@ frida_listen (int rx_buffer_size, const FridaUploadApi * api)
if (res == -1)
goto setsockopt_failed;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
addr.sin_port = 0;
addr_len = sizeof (addr);
res = api->bind (fd, (const struct sockaddr *) &addr, addr_len);
@@ -35,7 +35,7 @@ frida_listen (int rx_buffer_size, const FridaUploadApi * api)
if (res == -1)
goto listen_failed;
return ((uint64_t) fd << 16) | ntohs (addr.sin_port);
return ((uint64_t) fd << 16) | ntohs (addr.sin6_port);
socket_failed:
{
+116 -93
View File
@@ -1,6 +1,6 @@
[CCode (gir_namespace = "FridaFruityInjector", gir_version = "1.0")]
namespace Frida.Fruity.Injector {
public static async GadgetDetails inject (owned Gum.DarwinModule module, LLDB.Client lldb, ChannelProvider channel_provider,
public static async GadgetDetails inject (owned Gum.DarwinModule module, LLDB.Client lldb, HostChannelProvider channel_provider,
Cancellable? cancellable) throws Error, IOError {
var session = new Session (module, lldb, channel_provider);
return yield session.run (cancellable);
@@ -32,7 +32,7 @@ namespace Frida.Fruity.Injector {
construct;
}
public ChannelProvider channel_provider {
public HostChannelProvider channel_provider {
get;
construct;
}
@@ -64,13 +64,12 @@ namespace Frida.Fruity.Injector {
private LLDB.AppleDyldFields? dyld_fields;
private uint64 dyld_base;
private Gee.Map<string, uint64?>? dyld_symbols;
private bool libsystem_initialized;
private size_t module_size;
public Session (Gum.DarwinModule module, LLDB.Client lldb, ChannelProvider channel_provider) {
public Session (Gum.DarwinModule module, LLDB.Client lldb, HostChannelProvider channel_provider) {
Object (
module: module,
lldb: lldb,
@@ -160,7 +159,6 @@ namespace Frida.Fruity.Injector {
return true;
}, cancellable);
}
dyld_symbols = yield fetch_dyld_symbols (cancellable);
return null;
}
@@ -629,22 +627,24 @@ namespace Frida.Fruity.Injector {
/* Compiled from helpers/upload-listener.c */
private const uint8[] UPLOAD_LISTENER_CODE = {
0xff, 0x43, 0x01, 0xd1, 0xf6, 0x57, 0x02, 0xa9, 0xf4, 0x4f, 0x03, 0xa9, 0xfd, 0x7b, 0x04, 0xa9, 0xfd, 0x03, 0x01,
0x91, 0xf3, 0x03, 0x01, 0xaa, 0xe0, 0x1f, 0x00, 0xb9, 0x28, 0x00, 0x40, 0xf9, 0x40, 0x00, 0x80, 0x52, 0x21, 0x00,
0x80, 0x52, 0x02, 0x00, 0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0x1f, 0x04, 0x00, 0x31, 0x80, 0x05, 0x00, 0x54, 0xf4,
0x03, 0x00, 0xaa, 0x68, 0x06, 0x40, 0xf9, 0xe3, 0x73, 0x00, 0x91, 0xe1, 0xff, 0x9f, 0x52, 0x42, 0x00, 0x82, 0x52,
0x84, 0x00, 0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0x1f, 0x04, 0x00, 0x31, 0xa0, 0x04, 0x00, 0x54, 0x48, 0x00, 0x80,
0x52, 0xe8, 0x27, 0x00, 0x39, 0xe8, 0x0f, 0x80, 0x52, 0x08, 0x20, 0xa0, 0x72, 0xe8, 0x0f, 0x00, 0xb9, 0xff, 0x17,
0x00, 0x79, 0x08, 0x02, 0x80, 0x52, 0xe8, 0x07, 0x00, 0xb9, 0x68, 0x0a, 0x40, 0xf9, 0xe1, 0x23, 0x00, 0x91, 0xe0,
0x03, 0x14, 0xaa, 0x02, 0x02, 0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0x1f, 0x04, 0x00, 0x31, 0x00, 0x03, 0x00, 0x54,
0x68, 0x12, 0x40, 0xf9, 0xe1, 0x23, 0x00, 0x91, 0xe2, 0x13, 0x00, 0x91, 0xe0, 0x03, 0x14, 0xaa, 0x00, 0x01, 0x3f,
0xff, 0x83, 0x01, 0xd1, 0xf6, 0x57, 0x03, 0xa9, 0xf4, 0x4f, 0x04, 0xa9, 0xfd, 0x7b, 0x05, 0xa9, 0xfd, 0x43, 0x01,
0x91, 0xf3, 0x03, 0x01, 0xaa, 0x08, 0x00, 0x00, 0x90, 0x08, 0xb1, 0x04, 0x91, 0xa0, 0xc3, 0x1d, 0xb8, 0x00, 0x01,
0xc0, 0x3d, 0xe0, 0x07, 0x80, 0x3d, 0x00, 0xc1, 0xc0, 0x3c, 0xe0, 0xc3, 0x81, 0x3c, 0x28, 0x00, 0x40, 0xf9, 0xc0,
0x03, 0x80, 0x52, 0x21, 0x00, 0x80, 0x52, 0x02, 0x00, 0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0x1f, 0x04, 0x00, 0x31,
0xc0, 0x04, 0x00, 0x54, 0xf4, 0x03, 0x00, 0xaa, 0x68, 0x06, 0x40, 0xf9, 0xa3, 0x93, 0x00, 0xd1, 0xe1, 0xff, 0x9f,
0x52, 0x42, 0x00, 0x82, 0x52, 0x84, 0x00, 0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0x1f, 0x04, 0x00, 0x31, 0xe0, 0x03,
0x00, 0x54, 0x88, 0x03, 0x80, 0x52, 0xe8, 0x0f, 0x00, 0xb9, 0x68, 0x0a, 0x40, 0xf9, 0xe1, 0x43, 0x00, 0x91, 0xe0,
0x03, 0x14, 0xaa, 0x82, 0x03, 0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0x1f, 0x04, 0x00, 0x31, 0x00, 0x03, 0x00, 0x54,
0x68, 0x12, 0x40, 0xf9, 0xe1, 0x43, 0x00, 0x91, 0xe2, 0x33, 0x00, 0x91, 0xe0, 0x03, 0x14, 0xaa, 0x00, 0x01, 0x3f,
0xd6, 0x1f, 0x04, 0x00, 0x31, 0x60, 0x02, 0x00, 0x54, 0x68, 0x0e, 0x40, 0xf9, 0xe0, 0x03, 0x14, 0xaa, 0x21, 0x00,
0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0x1f, 0x04, 0x00, 0x31, 0xe0, 0x01, 0x00, 0x54, 0x88, 0x7e, 0x40, 0x93, 0xe9,
0x17, 0x40, 0x79, 0x29, 0x09, 0xc0, 0x5a, 0x35, 0x7d, 0x10, 0x53, 0x15, 0xbd, 0x70, 0xb3, 0x0d, 0x00, 0x00, 0x14,
0x27, 0x40, 0x79, 0x29, 0x09, 0xc0, 0x5a, 0x35, 0x7d, 0x10, 0x53, 0x15, 0xbd, 0x70, 0xb3, 0x0d, 0x00, 0x00, 0x14,
0x15, 0x20, 0xe0, 0xd2, 0x0b, 0x00, 0x00, 0x14, 0x15, 0x40, 0xe0, 0xd2, 0x06, 0x00, 0x00, 0x14, 0x15, 0x60, 0xe0,
0xd2, 0x04, 0x00, 0x00, 0x14, 0x15, 0x80, 0xe0, 0xd2, 0x02, 0x00, 0x00, 0x14, 0x15, 0xa0, 0xe0, 0xd2, 0x68, 0x42,
0x40, 0xf9, 0xe0, 0x03, 0x14, 0xaa, 0x00, 0x01, 0x3f, 0xd6, 0xe0, 0x03, 0x15, 0xaa, 0xfd, 0x7b, 0x44, 0xa9, 0xf4,
0x4f, 0x43, 0xa9, 0xf6, 0x57, 0x42, 0xa9, 0xff, 0x43, 0x01, 0x91, 0xc0, 0x03, 0x5f, 0xd6
0x40, 0xf9, 0xe0, 0x03, 0x14, 0xaa, 0x00, 0x01, 0x3f, 0xd6, 0xe0, 0x03, 0x15, 0xaa, 0xfd, 0x7b, 0x45, 0xa9, 0xf4,
0x4f, 0x44, 0xa9, 0xf6, 0x57, 0x43, 0xa9, 0xff, 0x83, 0x01, 0x91, 0xc0, 0x03, 0x5f, 0xd6, 0x00, 0x1e, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00
};
/* Compiled from helpers/upload-receiver.c */
@@ -810,7 +810,7 @@ namespace Frida.Fruity.Injector {
return total;
}
private uint64 resolve_dyld_symbol (string name, string nick) throws Error {
private static uint64 resolve_dyld_symbol (string name, string nick, Gee.Map<string, uint64?> dyld_symbols) throws Error {
uint64? val = dyld_symbols[name];
if (val == null)
throw new Error.UNSUPPORTED ("Unsupported iOS version (%s not found)", nick);
@@ -821,13 +821,15 @@ namespace Frida.Fruity.Injector {
if (libsystem_initialized)
return;
var dyld_symbols = yield fetch_dyld_symbols (cancellable);
yield restore_main_thread_state (cancellable);
uint64? libdyld_initialize = dyld_symbols["__ZN5dyld44APIs19_libdyld_initializeEPKNS_16LibSystemHelpersE"];
if (libdyld_initialize != null)
yield ensure_libsystem_initialized_for_dyld_v4_and_above (libdyld_initialize, cancellable);
yield ensure_libsystem_initialized_for_dyld_v4_and_above (libdyld_initialize, dyld_symbols, cancellable);
else
yield ensure_libsystem_initialized_for_dyld_v3_and_below (cancellable);
yield ensure_libsystem_initialized_for_dyld_v3_and_below (dyld_symbols, cancellable);
yield save_main_thread_state (cancellable);
@@ -836,15 +838,21 @@ namespace Frida.Fruity.Injector {
}
private async void ensure_libsystem_initialized_for_dyld_v4_and_above (uint64 libdyld_initialize,
Cancellable? cancellable) throws GLib.Error {
uint64? process_info_ptr = dyld_symbols["_gProcessInfo"];
Gee.Map<string, uint64?> dyld_symbols, Cancellable? cancellable) throws GLib.Error {
uint64? process_info_ptr = dyld_symbols["__ZL12sProcessInfo"];
if (process_info_ptr == null)
process_info_ptr = dyld_symbols["__ZN5dyld412gProcessInfoE"];
if (process_info_ptr == null)
process_info_ptr = dyld_symbols["_gProcessInfo"];
GDB.Breakpoint init_breakpoint = yield lldb.add_breakpoint (SOFT, libdyld_initialize, 4, cancellable);
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_10KernelArgsEPKN5dyld39MachOFileEPv"];
uint64? 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)
restart_breakpoint = yield lldb.add_breakpoint (SOFT, restart_with_dyld_in_cache, 4, cancellable);
@@ -854,12 +862,18 @@ namespace Frida.Fruity.Injector {
if (hit_breakpoint == null)
throw new Error.UNSUPPORTED ("Unexpected exception");
if (restart_breakpoint != null)
yield restart_breakpoint.remove (cancellable);
yield init_breakpoint.remove (cancellable);
if (hit_breakpoint == restart_breakpoint) {
if (process_info_ptr == null)
throw new Error.UNSUPPORTED ("Missing gProcessInfo");
uint64 process_info = yield lldb.read_pointer (process_info_ptr, cancellable);
uint64 dyld_image_load_address = yield lldb.read_pointer (process_info + 0x20, cancellable);
initializer = dyld_image_load_address + (initializer - dyld_base);
var rebased_symbols = new Gee.HashMap<string, uint64?> ();
foreach (var e in dyld_symbols.entries)
rebased_symbols[e.key] = dyld_image_load_address + (e.value - dyld_base);
@@ -867,13 +881,12 @@ namespace Frida.Fruity.Injector {
dyld_base = dyld_image_load_address;
dyld_symbols = rebased_symbols;
yield restart_breakpoint.remove (cancellable);
yield init_breakpoint.remove (cancellable);
uint64 real_libdyld_initialize = dyld_symbols["__ZN5dyld44APIs19_libdyld_initializeEPKNS_16LibSystemHelpersE"];
init_breakpoint = yield lldb.add_breakpoint (SOFT, real_libdyld_initialize, 4, cancellable);
init_breakpoint = yield lldb.add_breakpoint (SOFT, initializer, 4, cancellable);
exception = (LLDB.Exception) yield lldb.continue_until_exception (cancellable);
yield init_breakpoint.remove (cancellable);
hit_breakpoint = exception.breakpoint;
if (hit_breakpoint == null)
throw new Error.UNSUPPORTED ("Unexpected exception");
@@ -882,7 +895,10 @@ namespace Frida.Fruity.Injector {
}
assert (hit_breakpoint == init_breakpoint);
yield init_breakpoint.remove (cancellable);
bool done_because_we_hit_notify_objc_init = initializer != libdyld_initialize;
if (done_because_we_hit_notify_objc_init)
return;
uint64 dyld_size = dyld_symbols["dyld_size"];
uint64 frame_here = exception.context["fp"];
@@ -911,7 +927,8 @@ namespace Frida.Fruity.Injector {
yield caller_breakpoint.remove (cancellable);
}
private async void ensure_libsystem_initialized_for_dyld_v3_and_below (Cancellable? cancellable) throws GLib.Error {
private async void ensure_libsystem_initialized_for_dyld_v3_and_below (Gee.Map<string, uint64?> dyld_symbols,
Cancellable? cancellable) throws GLib.Error {
GDB.Breakpoint? modern_breakpoint = null;
uint64 launch_with_closure = 0;
@@ -931,7 +948,8 @@ namespace Frida.Fruity.Injector {
modern_breakpoint = yield lldb.add_breakpoint (SOFT, run_initializers_call, 4, cancellable);
}
uint64 initialize_main_executable = resolve_dyld_symbol ("__ZN4dyld24initializeMainExecutableEv", "initializeMainExecutable");
uint64 initialize_main_executable = resolve_dyld_symbol ("__ZN4dyld24initializeMainExecutableEv",
"initializeMainExecutable", dyld_symbols);
GDB.Breakpoint legacy_breakpoint = yield lldb.add_breakpoint (SOFT, initialize_main_executable, 4, cancellable);
var exception = yield lldb.continue_until_exception (cancellable);
@@ -946,7 +964,7 @@ namespace Frida.Fruity.Injector {
yield modern_breakpoint.remove (cancellable);
if (hit_breakpoint == legacy_breakpoint)
yield initialize_libsystem_from_legacy_codepath (cancellable);
yield initialize_libsystem_from_legacy_codepath (dyld_symbols, cancellable);
else
assert (hit_breakpoint == modern_breakpoint);
}
@@ -987,7 +1005,8 @@ namespace Frida.Fruity.Injector {
throw new Error.UNSUPPORTED ("Unable to probe dyld v3 internals; please file a bug");
}
private async void initialize_libsystem_from_legacy_codepath (Cancellable? cancellable) throws GLib.Error {
private async void initialize_libsystem_from_legacy_codepath (Gee.Map<string, uint64?> dyld_symbols,
Cancellable? cancellable) throws GLib.Error {
uint64 code = jit_page;
var code_builder_pac = lldb.make_buffer_builder ();
@@ -1053,8 +1072,8 @@ namespace Frida.Fruity.Injector {
code_builder.write_pointer (error_buf_literal_offset, helpers + error_buffer_offset);
yield lldb.write_byte_array (code, code_builder.build (), cancellable);
uint64 register_thread_helpers =
resolve_dyld_symbol ("__ZL21registerThreadHelpersPKN4dyld16LibSystemHelpersE", "registerThreadHelpers");
uint64 register_thread_helpers = resolve_dyld_symbol ("__ZL21registerThreadHelpersPKN4dyld16LibSystemHelpersE",
"registerThreadHelpers", dyld_symbols);
yield invoke_remote_function (register_thread_helpers, {
helpers
}, null, cancellable);
@@ -1073,8 +1092,8 @@ namespace Frida.Fruity.Injector {
ExceptionHandler? strcmp_handler = null;
var dlopen = dyld_symbols.has_key ("_dlopen_internal")
? resolve_dyld_symbol ("_dlopen_internal", "dlopen")
: resolve_dyld_symbol ("_dlopen", "dlopen");
? resolve_dyld_symbol ("_dlopen_internal", "dlopen", dyld_symbols)
: resolve_dyld_symbol ("_dlopen", "dlopen", dyld_symbols);
yield invoke_remote_function (dlopen, {
libsystem_string,
9,
@@ -1181,67 +1200,71 @@ namespace Frida.Fruity.Injector {
private const uint8[] SYMBOL_FETCHER_CODE = {
0xff, 0x03, 0x02, 0xd1, 0xfc, 0x6f, 0x02, 0xa9, 0xfa, 0x67, 0x03, 0xa9, 0xf8, 0x5f, 0x04, 0xa9, 0xf6, 0x57, 0x05,
0xa9, 0xf4, 0x4f, 0x06, 0xa9, 0xfd, 0x7b, 0x07, 0xa9, 0xfd, 0xc3, 0x01, 0x91, 0xf4, 0x03, 0x01, 0xaa, 0xe0, 0x07,
0x00, 0xf9, 0x13, 0x00, 0x80, 0xd2, 0x19, 0x00, 0x80, 0xd2, 0x35, 0x80, 0x00, 0x91, 0x3a, 0x10, 0x40, 0xb9, 0xd6,
0x22, 0x00, 0x30, 0x1f, 0x20, 0x03, 0xd5, 0xd7, 0x22, 0x00, 0x10, 0x1f, 0x20, 0x03, 0xd5, 0x1a, 0x04, 0x00, 0x34,
0x00, 0xf9, 0x13, 0x00, 0x80, 0xd2, 0x19, 0x00, 0x80, 0xd2, 0x35, 0x80, 0x00, 0x91, 0x3a, 0x10, 0x40, 0xb9, 0x16,
0x00, 0x00, 0x90, 0xd6, 0x3e, 0x13, 0x91, 0x17, 0x00, 0x00, 0x90, 0xf7, 0x5a, 0x13, 0x91, 0x1a, 0x04, 0x00, 0x34,
0xa8, 0x02, 0x40, 0xb9, 0x1f, 0x09, 0x00, 0x71, 0xa0, 0x01, 0x00, 0x54, 0x1f, 0x2d, 0x00, 0x71, 0xa0, 0x01, 0x00,
0x54, 0x1f, 0x65, 0x00, 0x71, 0x81, 0x01, 0x00, 0x54, 0xb8, 0x22, 0x00, 0x91, 0xe0, 0x03, 0x18, 0xaa, 0xe1, 0x03,
0x16, 0xaa, 0xa3, 0x00, 0x00, 0x94, 0x80, 0x01, 0x00, 0x34, 0xb3, 0xa2, 0x41, 0xa9, 0xe8, 0x0b, 0x00, 0xf9, 0x04,
0x16, 0xaa, 0xaa, 0x00, 0x00, 0x94, 0x80, 0x01, 0x00, 0x34, 0xb3, 0xa2, 0x41, 0xa9, 0xe8, 0x0b, 0x00, 0xf9, 0x04,
0x00, 0x00, 0x14, 0xfc, 0x03, 0x15, 0xaa, 0x02, 0x00, 0x00, 0x14, 0xfb, 0x03, 0x15, 0xaa, 0xa8, 0x06, 0x40, 0xb9,
0xb5, 0x02, 0x08, 0x8b, 0x5a, 0x07, 0x00, 0x51, 0x7a, 0xfd, 0xff, 0x35, 0x09, 0x00, 0x00, 0x14, 0xe0, 0x03, 0x18,
0xaa, 0xe1, 0x03, 0x17, 0xaa, 0x94, 0x00, 0x00, 0x94, 0x00, 0xff, 0xff, 0x34, 0xa8, 0x0e, 0x40, 0xf9, 0xa9, 0x16,
0xaa, 0xe1, 0x03, 0x17, 0xaa, 0x9b, 0x00, 0x00, 0x94, 0x00, 0xff, 0xff, 0x34, 0xa8, 0x0e, 0x40, 0xf9, 0xa9, 0x16,
0x40, 0xf9, 0x19, 0x01, 0x09, 0xcb, 0xf4, 0xff, 0xff, 0x17, 0x88, 0x02, 0x13, 0xcb, 0x28, 0x03, 0x08, 0x8b, 0x89,
0x0b, 0x40, 0xb9, 0x13, 0x01, 0x09, 0x8b, 0x89, 0x13, 0x40, 0xb9, 0x19, 0x01, 0x09, 0x8b, 0x16, 0x17, 0x00, 0x10,
0x1f, 0x20, 0x03, 0xd5, 0xe8, 0x07, 0x40, 0xf9, 0xe8, 0x0f, 0x00, 0xf9, 0x35, 0x01, 0x80, 0x52, 0x78, 0x0b, 0x40,
0xb9, 0x68, 0x0f, 0x40, 0xb9, 0x1f, 0x03, 0x08, 0x6b, 0xc0, 0x09, 0x00, 0x54, 0xf7, 0x03, 0x18, 0x2a, 0xe8, 0xee,
0x7c, 0xd3, 0x68, 0x6a, 0x68, 0xb8, 0x3c, 0x03, 0x08, 0x8b, 0xe0, 0x03, 0x1c, 0xaa, 0xe1, 0x03, 0x16, 0xaa, 0x61,
0x00, 0x00, 0x94, 0x60, 0x06, 0x00, 0x37, 0xe0, 0x03, 0x1c, 0xaa, 0x41, 0x15, 0x00, 0x70, 0x1f, 0x20, 0x03, 0xd5,
0x5c, 0x00, 0x00, 0x94, 0xc0, 0x05, 0x00, 0x37, 0xe0, 0x03, 0x1c, 0xaa, 0x61, 0x15, 0x00, 0x50, 0x1f, 0x20, 0x03,
0xd5, 0x6f, 0x00, 0x00, 0x94, 0x20, 0x05, 0x00, 0x37, 0xe0, 0x03, 0x1c, 0xaa, 0x41, 0x15, 0x00, 0x10, 0x1f, 0x20,
0x03, 0xd5, 0x6a, 0x00, 0x00, 0x94, 0x80, 0x04, 0x00, 0x37, 0xe0, 0x03, 0x1c, 0xaa, 0x61, 0x15, 0x00, 0x50, 0x1f,
0x20, 0x03, 0xd5, 0x4d, 0x00, 0x00, 0x94, 0xe0, 0x03, 0x00, 0x37, 0xe0, 0x03, 0x1c, 0xaa, 0x61, 0x15, 0x00, 0x10,
0x1f, 0x20, 0x03, 0xd5, 0x48, 0x00, 0x00, 0x94, 0x40, 0x03, 0x00, 0x37, 0xe0, 0x03, 0x1c, 0xaa, 0x81, 0x15, 0x00,
0x30, 0x1f, 0x20, 0x03, 0xd5, 0x43, 0x00, 0x00, 0x94, 0xa0, 0x02, 0x00, 0x37, 0xe0, 0x03, 0x1c, 0xaa, 0x81, 0x15,
0x00, 0x70, 0x1f, 0x20, 0x03, 0xd5, 0x5e, 0x00, 0x00, 0x94, 0x00, 0x02, 0x00, 0x37, 0xe0, 0x03, 0x1c, 0xaa, 0x21,
0x15, 0x00, 0x70, 0x1f, 0x20, 0x03, 0xd5, 0x59, 0x00, 0x00, 0x94, 0x60, 0x01, 0x00, 0x37, 0xe0, 0x03, 0x1c, 0xaa,
0xc1, 0x14, 0x00, 0x70, 0x1f, 0x20, 0x03, 0xd5, 0x34, 0x00, 0x00, 0x94, 0xc0, 0x00, 0x00, 0x37, 0xe0, 0x03, 0x1c,
0xaa, 0xc1, 0x14, 0x00, 0x50, 0x1f, 0x20, 0x03, 0xd5, 0x2f, 0x00, 0x00, 0x94, 0x40, 0x02, 0x00, 0x34, 0xba, 0x00,
0x00, 0x34, 0xe8, 0x0f, 0x40, 0xf9, 0x49, 0x01, 0x80, 0x52, 0x09, 0x15, 0x00, 0x38, 0xe8, 0x0f, 0x00, 0xf9, 0x68,
0x12, 0x17, 0x8b, 0x08, 0x05, 0x40, 0xf9, 0x81, 0x02, 0x08, 0x8b, 0xe0, 0x63, 0x00, 0x91, 0x4d, 0x00, 0x00, 0x94,
0xe8, 0x0f, 0x40, 0xf9, 0x15, 0x15, 0x00, 0x38, 0xe8, 0x0f, 0x00, 0xf9, 0xe0, 0x63, 0x00, 0x91, 0xe1, 0x03, 0x1c,
0xaa, 0x5e, 0x00, 0x00, 0x94, 0x5a, 0x07, 0x00, 0x11, 0x18, 0x07, 0x00, 0x11, 0xb1, 0xff, 0xff, 0x17, 0xe1, 0x23,
0x41, 0xa9, 0x49, 0x01, 0x80, 0x52, 0x09, 0x15, 0x00, 0x38, 0xe8, 0x0f, 0x00, 0xf9, 0xe0, 0x63, 0x00, 0x91, 0x3e,
0x00, 0x00, 0x94, 0xe8, 0x0f, 0x40, 0xf9, 0x29, 0x01, 0x80, 0x52, 0x09, 0x15, 0x00, 0x38, 0xe8, 0x0f, 0x00, 0xf9,
0x21, 0x11, 0x00, 0x70, 0x1f, 0x20, 0x03, 0xd5, 0xe0, 0x63, 0x00, 0x91, 0x4d, 0x00, 0x00, 0x94, 0xe8, 0x0f, 0x40,
0xf9, 0xe9, 0x07, 0x40, 0xf9, 0x00, 0x01, 0x09, 0xcb, 0x1f, 0x01, 0x00, 0x39, 0xfd, 0x7b, 0x47, 0xa9, 0xf4, 0x4f,
0x46, 0xa9, 0xf6, 0x57, 0x45, 0xa9, 0xf8, 0x5f, 0x44, 0xa9, 0xfa, 0x67, 0x43, 0xa9, 0xfc, 0x6f, 0x42, 0xa9, 0xff,
0x03, 0x02, 0x91, 0xc0, 0x03, 0x5f, 0xd6, 0xf6, 0x57, 0xbd, 0xa9, 0xf4, 0x4f, 0x01, 0xa9, 0xfd, 0x7b, 0x02, 0xa9,
0xfd, 0x83, 0x00, 0x91, 0xf4, 0x03, 0x01, 0xaa, 0xf3, 0x03, 0x00, 0xaa, 0x35, 0x00, 0x40, 0x39, 0x68, 0x02, 0x40,
0x39, 0x28, 0x01, 0x00, 0x34, 0x1f, 0x01, 0x15, 0x6b, 0xa1, 0x00, 0x00, 0x54, 0xe0, 0x03, 0x13, 0xaa, 0xe1, 0x03,
0x14, 0xaa, 0x13, 0x00, 0x00, 0x94, 0x80, 0x00, 0x00, 0x37, 0x73, 0x06, 0x00, 0x91, 0xf7, 0xff, 0xff, 0x17, 0x13,
0x00, 0x80, 0xd2, 0x7f, 0x02, 0x00, 0xf1, 0xe0, 0x07, 0x9f, 0x1a, 0xfd, 0x7b, 0x42, 0xa9, 0xf4, 0x4f, 0x41, 0xa9,
0xf6, 0x57, 0xc3, 0xa8, 0xc0, 0x03, 0x5f, 0xd6, 0x08, 0x14, 0x40, 0x38, 0x29, 0x14, 0x40, 0x38, 0x1f, 0x01, 0x00,
0x71, 0x00, 0x11, 0x49, 0x7a, 0x80, 0xff, 0xff, 0x54, 0x1f, 0x01, 0x09, 0x6b, 0xe0, 0x17, 0x9f, 0x1a, 0xc0, 0x03,
0x5f, 0xd6, 0x28, 0x00, 0x40, 0x39, 0xa8, 0x00, 0x00, 0x34, 0x21, 0x04, 0x00, 0x91, 0x09, 0x14, 0x40, 0x38, 0x3f,
0x01, 0x08, 0x6b, 0x60, 0xff, 0xff, 0x54, 0x1f, 0x01, 0x00, 0x71, 0xe0, 0x17, 0x9f, 0x1a, 0xc0, 0x03, 0x5f, 0xd6,
0x09, 0x00, 0x80, 0x52, 0x08, 0x00, 0x40, 0xf9, 0x8a, 0x07, 0x80, 0x52, 0xab, 0x0a, 0x00, 0x10, 0x1f, 0x20, 0x03,
0xd5, 0x5f, 0x11, 0x00, 0x31, 0x80, 0x01, 0x00, 0x54, 0x2c, 0x24, 0xca, 0x9a, 0x8c, 0x0d, 0x00, 0x72, 0x2d, 0x01,
0x00, 0x12, 0xa0, 0x19, 0x40, 0x7a, 0x29, 0x15, 0x9f, 0x1a, 0x89, 0x00, 0x00, 0x36, 0x8c, 0x1d, 0x40, 0x92, 0x6c,
0x69, 0x6c, 0x38, 0x0c, 0x15, 0x00, 0x38, 0x4a, 0x11, 0x00, 0x51, 0xf4, 0xff, 0xff, 0x17, 0x69, 0x00, 0x00, 0x37,
0x09, 0x06, 0x80, 0x52, 0x09, 0x15, 0x00, 0x38, 0x08, 0x00, 0x00, 0xf9, 0xc0, 0x03, 0x5f, 0xd6, 0x08, 0x00, 0x40,
0xf9, 0x29, 0x00, 0x40, 0x39, 0x89, 0x00, 0x00, 0x34, 0x21, 0x04, 0x00, 0x91, 0x09, 0x15, 0x00, 0x38, 0xfc, 0xff,
0xff, 0x17, 0x08, 0x00, 0x00, 0xf9, 0xc0, 0x03, 0x5f, 0xd6, 0x6c, 0x69, 0x62, 0x64, 0x79, 0x6c, 0x64, 0x5f, 0x69,
0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x00, 0x72, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x57, 0x69,
0x74, 0x68, 0x44, 0x79, 0x6c, 0x64, 0x49, 0x6e, 0x43, 0x61, 0x63, 0x68, 0x65, 0x00, 0x5f, 0x67, 0x50, 0x72, 0x6f,
0x63, 0x65, 0x73, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x00, 0x5f, 0x5f, 0x5a, 0x4e, 0x35, 0x64, 0x79, 0x6c, 0x64, 0x34,
0x31, 0x32, 0x67, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x45, 0x00, 0x6c, 0x61, 0x75,
0x6e, 0x63, 0x68, 0x57, 0x69, 0x74, 0x68, 0x43, 0x6c, 0x6f, 0x73, 0x75, 0x72, 0x65, 0x00, 0x69, 0x6e, 0x69, 0x74,
0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x4d, 0x61, 0x69, 0x6e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c,
0x65, 0x00, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x48, 0x65, 0x6c,
0x70, 0x65, 0x72, 0x73, 0x00, 0x5f, 0x64, 0x6c, 0x6f, 0x70, 0x65, 0x6e, 0x00, 0x5f, 0x73, 0x74, 0x72, 0x63, 0x6d,
0x70, 0x00, 0x64, 0x6f, 0x4d, 0x6f, 0x64, 0x49, 0x6e, 0x69, 0x74, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x73, 0x00, 0x64, 0x6f, 0x47, 0x65, 0x74, 0x44, 0x4f, 0x46, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x00,
0x64, 0x79, 0x6c, 0x64, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x00, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x5f, 0x5f,
0x4c, 0x49, 0x4e, 0x4b, 0x45, 0x44, 0x49, 0x54, 0x00, 0x00, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
0x0b, 0x40, 0xb9, 0x13, 0x01, 0x09, 0x8b, 0x89, 0x13, 0x40, 0xb9, 0x19, 0x01, 0x09, 0x8b, 0xe8, 0x07, 0x40, 0xf9,
0xe8, 0x0f, 0x00, 0xf9, 0x16, 0x00, 0x00, 0x90, 0xd6, 0x72, 0x0f, 0x91, 0x35, 0x01, 0x80, 0x52, 0x78, 0x0b, 0x40,
0xb9, 0x68, 0x0f, 0x40, 0xb9, 0x1f, 0x03, 0x08, 0x6b, 0xc0, 0x0a, 0x00, 0x54, 0x77, 0x52, 0x38, 0x8b, 0xe8, 0x02,
0x40, 0xb9, 0x3c, 0x03, 0x08, 0x8b, 0xe0, 0x03, 0x1c, 0xaa, 0xe1, 0x03, 0x16, 0xaa, 0x6a, 0x00, 0x00, 0x94, 0xa0,
0x07, 0x00, 0x37, 0xe0, 0x03, 0x1c, 0xaa, 0x01, 0x00, 0x00, 0x90, 0x21, 0xbc, 0x0f, 0x91, 0x65, 0x00, 0x00, 0x94,
0x00, 0x07, 0x00, 0x37, 0xe0, 0x03, 0x1c, 0xaa, 0x01, 0x00, 0x00, 0x90, 0x21, 0xf8, 0x0f, 0x91, 0x60, 0x00, 0x00,
0x94, 0x60, 0x06, 0x00, 0x37, 0xe0, 0x03, 0x1c, 0xaa, 0x01, 0x00, 0x00, 0x90, 0x21, 0x54, 0x10, 0x91, 0x72, 0x00,
0x00, 0x94, 0xc0, 0x05, 0x00, 0x37, 0xe0, 0x03, 0x1c, 0xaa, 0x01, 0x00, 0x00, 0x90, 0x21, 0x8c, 0x10, 0x91, 0x6d,
0x00, 0x00, 0x94, 0x20, 0x05, 0x00, 0x37, 0xe0, 0x03, 0x1c, 0xaa, 0x01, 0x00, 0x00, 0x90, 0x21, 0xf4, 0x10, 0x91,
0x68, 0x00, 0x00, 0x94, 0x80, 0x04, 0x00, 0x37, 0xe0, 0x03, 0x1c, 0xaa, 0x01, 0x00, 0x00, 0x90, 0x21, 0x40, 0x11,
0x91, 0x4c, 0x00, 0x00, 0x94, 0xe0, 0x03, 0x00, 0x37, 0xe0, 0x03, 0x1c, 0xaa, 0x01, 0x00, 0x00, 0x90, 0x21, 0x88,
0x11, 0x91, 0x47, 0x00, 0x00, 0x94, 0x40, 0x03, 0x00, 0x37, 0xe0, 0x03, 0x1c, 0xaa, 0x01, 0x00, 0x00, 0x90, 0x21,
0xec, 0x11, 0x91, 0x42, 0x00, 0x00, 0x94, 0xa0, 0x02, 0x00, 0x37, 0xe0, 0x03, 0x1c, 0xaa, 0x01, 0x00, 0x00, 0x90,
0x21, 0x44, 0x12, 0x91, 0x5c, 0x00, 0x00, 0x94, 0x00, 0x02, 0x00, 0x37, 0xe0, 0x03, 0x1c, 0xaa, 0x01, 0x00, 0x00,
0x90, 0x21, 0x64, 0x12, 0x91, 0x57, 0x00, 0x00, 0x94, 0x60, 0x01, 0x00, 0x37, 0xe0, 0x03, 0x1c, 0xaa, 0x01, 0x00,
0x00, 0x90, 0x21, 0x84, 0x12, 0x91, 0x33, 0x00, 0x00, 0x94, 0xc0, 0x00, 0x00, 0x37, 0xe0, 0x03, 0x1c, 0xaa, 0x01,
0x00, 0x00, 0x90, 0x21, 0xd0, 0x12, 0x91, 0x2e, 0x00, 0x00, 0x94, 0x20, 0x02, 0x00, 0x34, 0xba, 0x00, 0x00, 0x34,
0xe8, 0x0f, 0x40, 0xf9, 0x49, 0x01, 0x80, 0x52, 0x09, 0x15, 0x00, 0x38, 0xe8, 0x0f, 0x00, 0xf9, 0xe8, 0x06, 0x40,
0xf9, 0x81, 0x02, 0x08, 0x8b, 0xe0, 0x63, 0x00, 0x91, 0x4c, 0x00, 0x00, 0x94, 0xe8, 0x0f, 0x40, 0xf9, 0x15, 0x15,
0x00, 0x38, 0xe8, 0x0f, 0x00, 0xf9, 0xe0, 0x63, 0x00, 0x91, 0xe1, 0x03, 0x1c, 0xaa, 0x5d, 0x00, 0x00, 0x94, 0x5a,
0x07, 0x00, 0x11, 0x18, 0x07, 0x00, 0x11, 0xa9, 0xff, 0xff, 0x17, 0xe1, 0x23, 0x41, 0xa9, 0x49, 0x01, 0x80, 0x52,
0x09, 0x15, 0x00, 0x38, 0xe8, 0x0f, 0x00, 0xf9, 0xe0, 0x63, 0x00, 0x91, 0x3d, 0x00, 0x00, 0x94, 0xe8, 0x0f, 0x40,
0xf9, 0x29, 0x01, 0x80, 0x52, 0x09, 0x15, 0x00, 0x38, 0xe8, 0x0f, 0x00, 0xf9, 0x01, 0x00, 0x00, 0x90, 0x21, 0x14,
0x13, 0x91, 0xe0, 0x63, 0x00, 0x91, 0x4c, 0x00, 0x00, 0x94, 0xe8, 0x0f, 0x40, 0xf9, 0xe9, 0x07, 0x40, 0xf9, 0x00,
0x01, 0x09, 0xcb, 0x1f, 0x01, 0x00, 0x39, 0xfd, 0x7b, 0x47, 0xa9, 0xf4, 0x4f, 0x46, 0xa9, 0xf6, 0x57, 0x45, 0xa9,
0xf8, 0x5f, 0x44, 0xa9, 0xfa, 0x67, 0x43, 0xa9, 0xfc, 0x6f, 0x42, 0xa9, 0xff, 0x03, 0x02, 0x91, 0xc0, 0x03, 0x5f,
0xd6, 0xf6, 0x57, 0xbd, 0xa9, 0xf4, 0x4f, 0x01, 0xa9, 0xfd, 0x7b, 0x02, 0xa9, 0xfd, 0x83, 0x00, 0x91, 0xf3, 0x03,
0x01, 0xaa, 0xf4, 0x03, 0x00, 0xaa, 0x35, 0x00, 0x40, 0x39, 0x96, 0x02, 0x40, 0x39, 0x36, 0x01, 0x00, 0x34, 0xdf,
0x02, 0x15, 0x6b, 0xa1, 0x00, 0x00, 0x54, 0xe0, 0x03, 0x14, 0xaa, 0xe1, 0x03, 0x13, 0xaa, 0x12, 0x00, 0x00, 0x94,
0x60, 0x00, 0x00, 0x37, 0x94, 0x06, 0x00, 0x91, 0xf7, 0xff, 0xff, 0x17, 0xdf, 0x02, 0x00, 0x71, 0xe0, 0x07, 0x9f,
0x1a, 0xfd, 0x7b, 0x42, 0xa9, 0xf4, 0x4f, 0x41, 0xa9, 0xf6, 0x57, 0xc3, 0xa8, 0xc0, 0x03, 0x5f, 0xd6, 0x08, 0x14,
0x40, 0x38, 0x29, 0x14, 0x40, 0x38, 0x1f, 0x01, 0x00, 0x71, 0x00, 0x11, 0x49, 0x7a, 0x80, 0xff, 0xff, 0x54, 0x1f,
0x01, 0x09, 0x6b, 0xe0, 0x17, 0x9f, 0x1a, 0xc0, 0x03, 0x5f, 0xd6, 0x28, 0x00, 0x40, 0x39, 0xa8, 0x00, 0x00, 0x34,
0x21, 0x04, 0x00, 0x91, 0x09, 0x14, 0x40, 0x38, 0x3f, 0x01, 0x08, 0x6b, 0x60, 0xff, 0xff, 0x54, 0x1f, 0x01, 0x00,
0x71, 0xe0, 0x17, 0x9f, 0x1a, 0xc0, 0x03, 0x5f, 0xd6, 0x09, 0x00, 0x80, 0x52, 0x08, 0x00, 0x40, 0xf9, 0x8a, 0x07,
0x80, 0x52, 0x0b, 0x00, 0x00, 0x90, 0x6b, 0xc1, 0x13, 0x91, 0x5f, 0x11, 0x00, 0x31, 0x80, 0x01, 0x00, 0x54, 0x2c,
0x24, 0xca, 0x9a, 0x8c, 0x0d, 0x40, 0x92, 0x2d, 0x01, 0x00, 0x12, 0x9f, 0x01, 0x00, 0x71, 0xa0, 0x19, 0x40, 0x7a,
0x29, 0x15, 0x9f, 0x1a, 0x69, 0x00, 0x00, 0x36, 0x6c, 0x69, 0x6c, 0x38, 0x0c, 0x15, 0x00, 0x38, 0x4a, 0x11, 0x00,
0x51, 0xf4, 0xff, 0xff, 0x17, 0x69, 0x00, 0x00, 0x37, 0x09, 0x06, 0x80, 0x52, 0x09, 0x15, 0x00, 0x38, 0x08, 0x00,
0x00, 0xf9, 0xc0, 0x03, 0x5f, 0xd6, 0x08, 0x00, 0x40, 0xf9, 0x29, 0x00, 0x40, 0x39, 0x89, 0x00, 0x00, 0x34, 0x21,
0x04, 0x00, 0x91, 0x09, 0x15, 0x00, 0x38, 0xfc, 0xff, 0xff, 0x17, 0x08, 0x00, 0x00, 0xf9, 0xc0, 0x03, 0x5f, 0xd6,
0x6c, 0x69, 0x62, 0x64, 0x79, 0x6c, 0x64, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x00,
0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x4f, 0x62, 0x6a, 0x43, 0x49, 0x6e, 0x69, 0x74, 0x00, 0x72, 0x65, 0x73, 0x74,
0x61, 0x72, 0x74, 0x57, 0x69, 0x74, 0x68, 0x44, 0x79, 0x6c, 0x64, 0x49, 0x6e, 0x43, 0x61, 0x63, 0x68, 0x65, 0x00,
0x5f, 0x67, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x00, 0x5f, 0x5f, 0x5a, 0x4e, 0x35,
0x64, 0x79, 0x6c, 0x64, 0x34, 0x31, 0x32, 0x67, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x49, 0x6e, 0x66, 0x6f,
0x45, 0x00, 0x5f, 0x5f, 0x5a, 0x4c, 0x31, 0x32, 0x73, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x49, 0x6e, 0x66,
0x6f, 0x00, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x57, 0x69, 0x74, 0x68, 0x43, 0x6c, 0x6f, 0x73, 0x75, 0x72, 0x65,
0x00, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x4d, 0x61, 0x69, 0x6e, 0x45, 0x78, 0x65, 0x63,
0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x00, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x68, 0x72, 0x65,
0x61, 0x64, 0x48, 0x65, 0x6c, 0x70, 0x65, 0x72, 0x73, 0x00, 0x5f, 0x64, 0x6c, 0x6f, 0x70, 0x65, 0x6e, 0x00, 0x5f,
0x73, 0x74, 0x72, 0x63, 0x6d, 0x70, 0x00, 0x64, 0x6f, 0x4d, 0x6f, 0x64, 0x49, 0x6e, 0x69, 0x74, 0x46, 0x75, 0x6e,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x00, 0x64, 0x6f, 0x47, 0x65, 0x74, 0x44, 0x4f, 0x46, 0x53, 0x65, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x73, 0x00, 0x64, 0x79, 0x6c, 0x64, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x00, 0x5f, 0x5f, 0x54, 0x45,
0x58, 0x54, 0x00, 0x5f, 0x5f, 0x4c, 0x49, 0x4e, 0x4b, 0x45, 0x44, 0x49, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
};
+15 -35
View File
@@ -1,37 +1,33 @@
[CCode (gir_namespace = "FridaFruity", gir_version = "1.0")]
namespace Frida.Fruity {
public class InstallationProxyClient : Object, AsyncInitable {
public LockdownClient lockdown {
public Device device {
get;
construct;
}
private PlistServiceClient service;
private InstallationProxyClient (LockdownClient lockdown) {
Object (lockdown: lockdown);
private InstallationProxyClient (Device device) {
Object (device: device);
}
public static async InstallationProxyClient open (LockdownClient lockdown, Cancellable? cancellable = null) throws InstallationProxyError, IOError {
var client = new InstallationProxyClient (lockdown);
public static async InstallationProxyClient open (Device device, Cancellable? cancellable = null) throws Error, IOError {
var client = new InstallationProxyClient (device);
try {
yield client.init_async (Priority.DEFAULT, cancellable);
} catch (GLib.Error e) {
throw_local_error (e);
throw_api_error (e);
}
return client;
}
private async bool init_async (int io_priority, Cancellable? cancellable) throws InstallationProxyError, IOError {
try {
var stream = yield lockdown.start_service ("com.apple.mobile.installation_proxy", cancellable);
private async bool init_async (int io_priority, Cancellable? cancellable) throws Error, IOError {
var stream = yield device.open_lockdown_service ("com.apple.mobile.installation_proxy", cancellable);
service = new PlistServiceClient (stream);
} catch (LockdownError e) {
throw new InstallationProxyError.PROTOCOL ("%s", e.message);
}
service = new PlistServiceClient (stream);
return true;
}
@@ -40,8 +36,7 @@ namespace Frida.Fruity {
yield service.close (cancellable);
}
public async Gee.ArrayList<ApplicationDetails> browse (Cancellable? cancellable = null)
throws InstallationProxyError, IOError {
public async Gee.ArrayList<ApplicationDetails> browse (Cancellable? cancellable = null) throws Error, IOError {
try {
var result = new Gee.ArrayList<ApplicationDetails> ();
@@ -75,7 +70,7 @@ namespace Frida.Fruity {
}
public async Gee.HashMap<string, ApplicationDetails> lookup (PlistDict query, Cancellable? cancellable = null)
throws InstallationProxyError, IOError {
throws Error, IOError {
try {
var result = new Gee.HashMap<string, ApplicationDetails> ();
@@ -189,28 +184,13 @@ namespace Frida.Fruity {
return new ApplicationDetails (identifier, name, version, build, path, containers, debuggable);
}
private static void throw_local_error (GLib.Error e) throws InstallationProxyError, IOError {
if (e is InstallationProxyError)
throw (InstallationProxyError) e;
if (e is IOError)
throw (IOError) e;
assert_not_reached ();
private static Error error_from_service (PlistServiceError e) {
return new Error.PROTOCOL ("%s", e.message);
}
private static InstallationProxyError error_from_service (PlistServiceError e) {
return new InstallationProxyError.PROTOCOL ("%s", e.message);
private static Error error_from_plist (PlistError e) {
return new Error.PROTOCOL ("Unexpected response: %s", e.message);
}
private static InstallationProxyError error_from_plist (PlistError e) {
return new InstallationProxyError.PROTOCOL ("Unexpected response: %s", e.message);
}
}
public errordomain InstallationProxyError {
INVALID_ARGUMENT,
PROTOCOL
}
public class ApplicationDetails : Object {
+174 -2
View File
@@ -23,6 +23,11 @@ namespace Frida.Fruity {
}
public class NSNumber : NSObject {
public Kind kind {
get;
private set;
}
public bool boolean {
get;
private set;
@@ -33,14 +38,44 @@ namespace Frida.Fruity {
private set;
}
public double number {
get;
private set;
}
public enum Kind {
BOOLEAN,
INTEGER,
FLOAT,
DOUBLE,
}
public NSNumber.from_boolean (bool val) {
kind = BOOLEAN;
boolean = val;
integer = val ? 1 : 0;
number = val ? 1.0 : 0.0;
}
public NSNumber.from_integer (int64 val) {
kind = INTEGER;
boolean = (val != 0) ? true : false;
integer = val;
number = val;
}
public NSNumber.from_float (float val) {
kind = FLOAT;
boolean = (val != 0.0f) ? true : false;
integer = (int64) val;
number = val;
}
public NSNumber.from_double (double val) {
kind = DOUBLE;
boolean = (val != 0.0) ? true : false;
integer = (int64) val;
number = val;
}
public override uint hash () {
@@ -51,7 +86,21 @@ namespace Frida.Fruity {
var other_number = other as NSNumber;
if (other_number == null)
return false;
return other_number.integer == integer;
if (other_number.kind != kind)
return false;
switch (kind) {
case BOOLEAN:
return other_number.boolean == boolean;
case INTEGER:
return other_number.integer == integer;
case FLOAT:
case DOUBLE:
return other_number.number == number;
}
return false;
}
public override string to_string () {
@@ -85,6 +134,32 @@ namespace Frida.Fruity {
}
}
public class NSData : NSObject {
public Bytes bytes {
get;
private set;
}
public NSData (Bytes bytes) {
this.bytes = bytes;
}
public override uint hash () {
return bytes.hash ();
}
public override bool is_equal_to (NSObject other) {
var other_data = other as NSData;
if (other_data == null)
return false;
return other_data.bytes.compare (bytes) == 0;
}
public override string to_string () {
return "NSData";
}
}
public class NSDictionary : NSObject {
public int size {
get {
@@ -198,6 +273,10 @@ namespace Frida.Fruity {
public NSArray (Gee.ArrayList<NSObject>? storage = null) {
this.storage = (storage != null) ? storage : new Gee.ArrayList<NSObject> (NSObject.equal_func);
}
public void add_object (NSObject obj) {
storage.add (obj);
}
}
public class NSDate : NSObject {
@@ -242,11 +321,23 @@ namespace Frida.Fruity {
}
}
public class DTTapMessage : NSObject {
public NSDictionary plist {
get;
private set;
}
public DTTapMessage (NSDictionary plist) {
this.plist = plist;
}
}
namespace NSKeyedArchive {
private Gee.HashMap<Type, EncodeFunc> encoders;
private Gee.HashMap<string, DecodeFunc> decoders;
private const string[] DICTIONARY_CLASS = { "NSDictionary", "NSObject" };
private const string[] ARRAY_CLASS = { "NSArray", "NSObject" };
[CCode (has_target = false)]
private delegate PlistUid EncodeFunc (NSObject instance, EncodingContext ctx);
@@ -319,9 +410,18 @@ namespace Frida.Fruity {
if (t == typeof (int64))
return new NSNumber.from_integer (val.get_int64 ());
if (t == typeof (float))
return new NSNumber.from_float (val.get_float ());
if (t == typeof (double))
return new NSNumber.from_double (val.get_double ());
if (t == typeof (string))
return new NSString (val.get_string ());
if (t == typeof (Bytes))
return new NSData ((Bytes) val.get_boxed ());
if (t == typeof (PlistDict)) {
var instance = (PlistDict) val.get_object ();
var klass = objects.get_dict ((int) instance.get_uid ("$class").uid);
@@ -354,6 +454,7 @@ namespace Frida.Fruity {
encoders[typeof (NSNumber)] = encode_number;
encoders[typeof (NSString)] = encode_string;
encoders[typeof (NSDictionary)] = encode_dictionary;
encoders[typeof (NSArray)] = encode_array;
}
private static void ensure_decoders_registered () {
@@ -365,11 +466,41 @@ namespace Frida.Fruity {
decoders["NSArray"] = decode_array;
decoders["NSDate"] = decode_date;
decoders["NSError"] = decode_error;
decoders["DTTapMessage"] = decode_tap_message;
decoders["DTSysmonTapMessage"] = decode_tap_message;
decoders["DTActivityTraceTapMessage"] = decode_tap_message;
decoders["DTTapStatusMessage"] = decode_tap_message;
decoders["DTTapHeartbeatMessage"] = decode_tap_message;
decoders["DTKTraceTapMessage"] = decode_tap_message;
}
private static PlistUid encode_number (NSObject instance, EncodingContext ctx) {
int64 val = ((NSNumber) instance).integer;
var n = (NSNumber) instance;
switch (n.kind) {
case BOOLEAN:
return encode_boolean (n.boolean, ctx);
case INTEGER:
return encode_integer (n.integer, ctx);
case FLOAT:
return encode_float (n.integer, ctx);
case DOUBLE:
return encode_double (n.integer, ctx);
}
assert_not_reached ();
}
private static PlistUid encode_boolean (bool val, EncodingContext ctx) {
var uid = ctx.find_existing_object (e => e.holds (typeof (bool)) && e.get_boolean () == val);
if (uid != null)
return uid;
var objects = ctx.objects;
uid = new PlistUid (objects.length);
objects.add_boolean (val);
return uid;
}
private static PlistUid encode_integer (int64 val, EncodingContext ctx) {
var uid = ctx.find_existing_object (e => e.holds (typeof (int64)) && e.get_int64 () == val);
if (uid != null)
return uid;
@@ -380,6 +511,28 @@ namespace Frida.Fruity {
return uid;
}
private static PlistUid encode_float (float val, EncodingContext ctx) {
var uid = ctx.find_existing_object (e => e.holds (typeof (float)) && e.get_float () == val);
if (uid != null)
return uid;
var objects = ctx.objects;
uid = new PlistUid (objects.length);
objects.add_float (val);
return uid;
}
private static PlistUid encode_double (double val, EncodingContext ctx) {
var uid = ctx.find_existing_object (e => e.holds (typeof (double)) && e.get_double () == val);
if (uid != null)
return uid;
var objects = ctx.objects;
uid = new PlistUid (objects.length);
objects.add_double (val);
return uid;
}
private static PlistUid encode_string (NSObject instance, EncodingContext ctx) {
string str = ((NSString) instance).str;
@@ -451,6 +604,21 @@ namespace Frida.Fruity {
}
}
private static PlistUid encode_array (NSObject instance, EncodingContext ctx) {
NSArray array = (NSArray) instance;
var object = new PlistDict ();
var uid = ctx.add_object (object);
var objs = new PlistArray ();
foreach (var element in array.elements)
objs.add_uid (encode_value (element, ctx));
object.set_array ("NS.objects", objs);
object.set_uid ("$class", ctx.get_class (ARRAY_CLASS));
return uid;
}
private static NSObject decode_array (PlistDict instance, DecodingContext ctx) throws Error, PlistError {
var objs = instance.get_array ("NS.objects");
@@ -486,6 +654,10 @@ namespace Frida.Fruity {
return new NSError (domain, code, (NSDictionary) user_info);
}
private static NSObject decode_tap_message (PlistDict instance, DecodingContext ctx) throws Error, PlistError {
return new DTTapMessage ((NSDictionary) decode_value (instance.get_uid ("DTTapMessagePlist"), ctx));
}
private class EncodingContext {
public PlistArray objects;
+26 -41
View File
@@ -1,18 +1,14 @@
[CCode (gir_namespace = "FridaFruity", gir_version = "1.0")]
namespace Frida.Fruity {
public class LockdownClient : Object, AsyncInitable {
public class LockdownClient : Object {
public signal void closed ();
public DeviceDetails device_details {
public PlistServiceClient service {
get;
construct;
}
public IOStream stream {
get { return service.stream; }
}
private PlistServiceClient service;
private UsbmuxDevice? usbmux_device;
private Plist? pair_record;
private string? host_id;
private string? system_buid;
@@ -22,29 +18,20 @@ namespace Frida.Fruity {
private const uint16 LOCKDOWN_PORT = 62078;
private LockdownClient (DeviceDetails device_details) {
Object (device_details: device_details);
public LockdownClient (IOStream stream) {
Object (service: new PlistServiceClient (stream));
}
public static async LockdownClient open (DeviceDetails device_details, Cancellable? cancellable = null)
construct {
service.closed.connect (on_service_closed);
}
public static async LockdownClient open (UsbmuxDevice device, Cancellable? cancellable = null)
throws LockdownError, IOError {
var client = new LockdownClient (device_details);
try {
yield client.init_async (Priority.DEFAULT, cancellable);
} catch (GLib.Error e) {
throw_local_error (e);
}
return client;
}
private async bool init_async (int io_priority, Cancellable? cancellable) throws LockdownError, IOError {
var device = device_details;
try {
var usbmux = yield UsbmuxClient.open (cancellable);
Plist pair_record;
try {
pair_record = yield usbmux.read_pair_record (device.udid, cancellable);
} catch (UsbmuxError e) {
@@ -52,6 +39,10 @@ namespace Frida.Fruity {
throw new LockdownError.NOT_PAIRED ("Not paired");
throw e;
}
string? host_id = null;
string? system_buid = null;
TlsCertificate? tls_certificate = null;
try {
host_id = pair_record.get_string ("HostID");
system_buid = pair_record.get_string ("SystemBUID");
@@ -64,15 +55,19 @@ namespace Frida.Fruity {
yield usbmux.connect_to_port (device.id, LOCKDOWN_PORT, cancellable);
service = new PlistServiceClient (usbmux.connection);
service.closed.connect (on_service_closed);
var client = new LockdownClient (usbmux.connection);
client.usbmux_device = device;
client.pair_record = pair_record;
client.host_id = host_id;
client.system_buid = system_buid;
client.tls_certificate = tls_certificate;
yield query_type (cancellable);
yield client.query_type (cancellable);
return client;
} catch (UsbmuxError e) {
throw new LockdownError.UNSUPPORTED ("%s", e.message);
}
return true;
}
public async void close (Cancellable? cancellable = null) throws IOError {
@@ -182,7 +177,7 @@ namespace Frida.Fruity {
bool enable_encryption = response.has ("EnableServiceSSL") && response.get_boolean ("EnableServiceSSL");
var client = yield UsbmuxClient.open (cancellable);
yield client.connect_to_port (device_details.id, (uint16) response.get_integer ("Port"), cancellable);
yield client.connect_to_port (usbmux_device.id, (uint16) response.get_integer ("Port"), cancellable);
SocketConnection raw_connection = client.connection;
IOStream stream = raw_connection;
@@ -242,7 +237,7 @@ namespace Frida.Fruity {
try {
var usbmux = yield UsbmuxClient.open (cancellable);
yield usbmux.delete_pair_record (device_details.udid, cancellable);
yield usbmux.delete_pair_record (usbmux_device.udid, cancellable);
} catch (UsbmuxError e) {
if (!(e is UsbmuxError.INVALID_ARGUMENT))
throw new LockdownError.PROTOCOL ("%s", e.message);
@@ -269,16 +264,6 @@ namespace Frida.Fruity {
return request;
}
private static void throw_local_error (GLib.Error e) throws LockdownError, IOError {
if (e is LockdownError)
throw (LockdownError) e;
if (e is IOError)
throw (IOError) e;
assert_not_reached ();
}
private static LockdownError error_from_service (PlistServiceError e) {
return new LockdownError.PROTOCOL ("%s", e.message);
}
+330
View File
@@ -0,0 +1,330 @@
[CCode (gir_namespace = "FridaFruity", gir_version = "1.0")]
namespace Frida.Fruity {
internal sealed class UsbNcmDriver : Object, AsyncInitable {
public UsbDevice device {
get;
construct;
}
public VirtualNetworkStack netstack {
get {
return _netstack;
}
}
public InetAddress? remote_ipv6_address {
get {
return _remote_ipv6_address;
}
}
private uint8 data_iface;
private int data_altsetting;
private uint8 rx_address;
private uint8 tx_address;
private VirtualNetworkStack? _netstack;
private uint16 next_outgoing_sequence = 1;
private InetAddress? _remote_ipv6_address;
private Cancellable io_cancellable = new Cancellable ();
private enum UsbDescriptorType {
INTERFACE = 0x04,
}
private enum UsbCommSubclass {
NCM = 0x0d,
}
private enum UsbDataSubclass {
UNDEFINED = 0x00,
}
private enum UsbCdcDescriptorSubtype {
ETHERNET = 0x0f,
}
private enum EtherType {
IPV6 = 0x86dd,
}
private enum IPV6NextHeader {
UDP = 0x11,
}
public static async UsbNcmDriver open (UsbDevice device, Cancellable? cancellable = null) throws Error, IOError {
var driver = new UsbNcmDriver (device);
try {
yield driver.init_async (Priority.DEFAULT, cancellable);
} catch (GLib.Error e) {
throw_api_error (e);
}
return driver;
}
private UsbNcmDriver (UsbDevice device) {
Object (device: device);
}
private async bool init_async (int io_priority, Cancellable? cancellable) throws Error, IOError {
unowned LibUSB.Device raw_device = device.raw_device;
unowned LibUSB.DeviceHandle handle = device.handle;
var dev_desc = LibUSB.DeviceDescriptor (raw_device);
LibUSB.ConfigDescriptor current_config;
Usb.check (raw_device.get_active_config_descriptor (out current_config), "Failed to get active config descriptor");
int desired_config_value = -1;
bool found_cdc_header = false;
bool found_data_interface = false;
uint8 mac_address_index = 0;
for (uint8 config_value = dev_desc.bNumConfigurations; config_value != 0; config_value--) {
LibUSB.ConfigDescriptor config;
Usb.check (raw_device.get_config_descriptor_by_value (config_value, out config),
"Failed to get config descriptor");
foreach (var iface in config.@interface) {
foreach (var setting in iface.altsetting) {
if (setting.bInterfaceClass == LibUSB.ClassCode.COMM &&
setting.bInterfaceSubClass == UsbCommSubclass.NCM) {
try {
parse_cdc_header (setting.extra, out mac_address_index);
found_cdc_header = true;
} catch (Error e) {
break;
}
} else if (setting.bInterfaceClass == LibUSB.ClassCode.DATA &&
setting.bInterfaceSubClass == UsbDataSubclass.UNDEFINED &&
setting.endpoint.length == 2) {
found_data_interface = true;
data_iface = setting.bInterfaceNumber;
data_altsetting = setting.bAlternateSetting;
foreach (var ep in setting.endpoint) {
if ((ep.bEndpointAddress & LibUSB.EndpointDirection.MASK) ==
LibUSB.EndpointDirection.IN) {
rx_address = ep.bEndpointAddress;
} else {
tx_address = ep.bEndpointAddress;
}
}
}
}
}
if (found_cdc_header || found_data_interface) {
desired_config_value = config_value;
break;
}
}
if (!found_cdc_header || !found_data_interface)
throw new Error.NOT_SUPPORTED ("%s", make_user_error_message ("No USB CDC-NCM interface found"));
uint8 mac_address[6];
string mac_address_str = yield device.read_string_descriptor (mac_address_index, device.default_language_id,
cancellable);
if (mac_address_str.length != 12)
throw new Error.PROTOCOL ("Invalid MAC address");
for (uint i = 0; i != 6; i++) {
uint v;
mac_address_str.substring (i * 2, 2).scanf ("%02X", out v);
mac_address[i] = (uint8) v;
}
if (current_config.bConfigurationValue != desired_config_value) {
foreach (var iface in current_config.@interface) {
unowned LibUSB.InterfaceDescriptor setting = iface.altsetting[0];
var res = handle.kernel_driver_active (setting.bInterfaceNumber);
if (res == 1)
handle.detach_kernel_driver (setting.bInterfaceNumber);
}
Usb.check (handle.set_configuration (desired_config_value), "Failed to set configuration");
}
try {
Usb.check (handle.claim_interface (data_iface), "Failed to claim USB interface");
} catch (Error e) {
throw new Error.PERMISSION_DENIED ("%s",
make_user_error_message (@"Unable to claim USB CDC-NCM interface ($(e.message))"));
}
Usb.check (handle.set_interface_alt_setting (data_iface, data_altsetting),
"Failed to set USB interface alt setting");
_netstack = new VirtualNetworkStack (new Bytes (mac_address), null, 1500);
_netstack.outgoing_datagram.connect (on_netif_outgoing_datagram);
process_incoming_datagrams.begin ();
return true;
}
private string make_user_error_message (string message) {
#if WINDOWS
return message + "; use https://zadig.akeo.ie to switch from Apple's official driver onto Microsoft's WinUSB " +
"driver, so libusb can access it";
#else
return message;
#endif
}
public void close () {
io_cancellable.cancel ();
_netstack.stop ();
}
private async void process_incoming_datagrams () {
var data = new uint8[64 * 1024];
while (true) {
try {
size_t n = yield device.bulk_transfer (rx_address, data, uint.MAX, io_cancellable);
handle_ncm_frame (data[:n]);
} catch (GLib.Error e) {
return;
}
}
}
private void handle_ncm_frame (uint8[] data) throws GLib.Error {
var input = new DataInputStream (new MemoryInputStream.from_data (data));
input.byte_order = LITTLE_ENDIAN;
uint8 raw_signature[4 + 1];
unowned string signature = (string) raw_signature;
size_t bytes_read;
input.read_all (raw_signature[:4], out bytes_read);
if (signature != "NCMH")
throw new Error.PROTOCOL ("Invalid NTH16 signature");
input.skip (6);
var ndp_index = input.read_uint16 ();
do {
input.seek (ndp_index, SET);
input.read_all (raw_signature[:4], out bytes_read);
if (signature != "NCM0")
throw new Error.PROTOCOL ("Invalid NDP16 signature");
input.skip (2);
var next_ndp_index = input.read_uint16 ();
while (true) {
var datagram_index = input.read_uint16 ();
var datagram_length = input.read_uint16 ();
if (datagram_index == 0 || datagram_length == 0)
break;
int64 previous_offset = input.tell ();
input.seek (datagram_index, SET);
var datagram_buf = new uint8[datagram_length];
input.read_all (datagram_buf, out bytes_read);
input.seek (previous_offset, SET);
var datagram = new Bytes.take ((owned) datagram_buf);
if (_remote_ipv6_address == null) {
_remote_ipv6_address = try_infer_remote_address_from_datagram (datagram);
if (_remote_ipv6_address != null)
notify_property ("remote-ipv6-address");
}
_netstack.handle_incoming_datagram (datagram);
}
ndp_index = next_ndp_index;
} while (ndp_index != 0);
}
private async void on_netif_outgoing_datagram (Bytes datagram) {
uint16 transfer_header_length = 12;
uint16 ndp_header_length = 16;
uint16 alignment_padding_length = 2;
uint16 datagram_start_index = transfer_header_length + ndp_header_length + alignment_padding_length;
uint16 datagram_length = (uint16) datagram.length;
uint16 sentinel_start_index = 0;
uint16 sentinel_size = 0;
uint16 sequence = next_outgoing_sequence++;
uint16 block_length = datagram_start_index + datagram_length;
uint16 ndp_index = transfer_header_length;
uint16 next_ndp_index = 0;
uint16 alignment_padding_value = 0;
var frame = new BufferBuilder (LITTLE_ENDIAN)
.append_string ("NCMH", StringTerminator.NONE)
.append_uint16 (transfer_header_length)
.append_uint16 (sequence)
.append_uint16 (block_length)
.append_uint16 (ndp_index)
.append_string ("NCM0", StringTerminator.NONE)
.append_uint16 (ndp_header_length)
.append_uint16 (next_ndp_index)
.append_uint16 (datagram_start_index)
.append_uint16 (datagram_length)
.append_uint16 (sentinel_start_index)
.append_uint16 (sentinel_size)
.append_uint16 (alignment_padding_value)
.append_bytes (datagram)
.build ();
try {
yield device.bulk_transfer (tx_address, frame.get_data (), uint.MAX, io_cancellable);
} catch (GLib.Error e) {
}
}
private static void parse_cdc_header (uint8[] header, out uint8 mac_address_index) throws Error {
var input = new DataInputStream (new MemoryInputStream.from_data (header));
input.set_byte_order (LITTLE_ENDIAN);
try {
for (int offset = 0; offset != header.length;) {
uint8 length = input.read_byte ();
if (length < 3)
throw new Error.PROTOCOL ("Invalid descriptor length");
uint8 descriptor_type = input.read_byte ();
if (descriptor_type != (LibUSB.RequestType.CLASS | UsbDescriptorType.INTERFACE))
throw new Error.PROTOCOL ("Invalid descriptor type");
uint8 descriptor_subtype = input.read_byte ();
if (descriptor_subtype == UsbCdcDescriptorSubtype.ETHERNET) {
mac_address_index = input.read_byte ();
return;
}
input.skip (length - 3);
offset += length;
}
} catch (IOError e) {
throw new Error.PROTOCOL ("%s", e.message);
}
throw new Error.PROTOCOL ("CDC Ethernet descriptor not found");
}
private static InetAddress? try_infer_remote_address_from_datagram (Bytes datagram) {
if (datagram.get_size () < 0x3e)
return null;
var buf = new Buffer (datagram, BIG_ENDIAN);
var ethertype = (EtherType) buf.read_uint16 (12);
if (ethertype != IPV6)
return null;
var next_header = (IPV6NextHeader) buf.read_uint8 (20);
if (next_header != UDP)
return null;
return new InetAddress.from_bytes (datagram[22:22 + 16].get_data (), IPV6);
}
}
}
File diff suppressed because it is too large. Load diff
+245
View File
@@ -0,0 +1,245 @@
[CCode (gir_namespace = "FridaFruity", gir_version = "1.0")]
namespace Frida.Fruity {
public class OpackBuilder {
protected BufferBuilder builder = new BufferBuilder (LITTLE_ENDIAN);
private Gee.Deque<Scope> scopes = new Gee.ArrayQueue<Scope> ();
public OpackBuilder () {
push_scope (new Scope (ROOT));
}
public unowned OpackBuilder begin_dictionary () {
begin_value ();
size_t type_offset = builder.offset;
builder.append_uint8 (0x00);
push_scope (new CollectionScope (type_offset));
return this;
}
public unowned OpackBuilder set_member_name (string name) {
return add_string_value (name);
}
public unowned OpackBuilder end_dictionary () {
CollectionScope scope = pop_scope ();
size_t n = scope.num_values / 2;
if (n < 0xf) {
builder.write_uint8 (scope.type_offset, 0xe0 | n);
} else {
builder
.write_uint8 (scope.type_offset, 0xef)
.append_uint8 (0x03);
}
return this;
}
public unowned OpackBuilder add_string_value (string val) {
begin_value ();
size_t len = val.length;
if (len > uint32.MAX) {
builder
.append_uint8 (0x6f)
.append_string (val, StringTerminator.NUL);
return this;
}
if (len <= 0x20)
builder.append_uint8 ((uint8) (0x40 + len));
else if (len <= uint8.MAX)
builder.append_uint8 (0x61).append_uint8 ((uint8) len);
else if (len <= uint16.MAX)
builder.append_uint8 (0x62).append_uint16 ((uint16) len);
else if (len <= 0xffffff)
builder.append_uint8 (0x63).append_uint8 ((uint8) (len & 0xff)).append_uint16 ((uint16) (len >> 8));
else
builder.append_uint8 (0x64).append_uint32 ((uint32) len);
builder.append_string (val, StringTerminator.NONE);
return this;
}
public unowned OpackBuilder add_data_value (Bytes val) {
begin_value ();
size_t size = val.get_size ();
if (size <= 0x20)
builder.append_uint8 ((uint8) (0x70 + size));
else if (size <= uint8.MAX)
builder.append_uint8 (0x91).append_uint8 ((uint8) size);
else if (size <= uint16.MAX)
builder.append_uint8 (0x92).append_uint16 ((uint16) size);
else if (size <= 0xffffff)
builder.append_uint8 (0x93).append_uint8 ((uint8) (size & 0xff)).append_uint16 ((uint16) (size >> 8));
else
builder.append_uint8 (0x94).append_uint32 ((uint32) size);
builder.append_bytes (val);
return this;
}
private unowned OpackBuilder begin_value () {
peek_scope ().num_values++;
return this;
}
public Bytes build () {
return builder.build ();
}
private void push_scope (Scope scope) {
scopes.offer_tail (scope);
}
private Scope peek_scope () {
return scopes.peek_tail ();
}
private T pop_scope<T> () {
return (T) scopes.poll_tail ();
}
private class Scope {
public Kind kind;
public size_t num_values = 0;
public enum Kind {
ROOT,
COLLECTION,
}
public Scope (Kind kind) {
this.kind = kind;
}
}
private class CollectionScope : Scope {
public size_t type_offset;
public CollectionScope (size_t type_offset) {
base (COLLECTION);
this.type_offset = type_offset;
}
}
}
public class OpackParser {
private BufferReader reader;
[Flags]
private enum ValueFlags {
ALLOW_TERMINATOR = 1 << 0,
}
public static Variant parse (Bytes opack) throws Error {
var parser = new OpackParser (opack);
return parser.read_value ();
}
private OpackParser (Bytes opack) {
reader = new BufferReader (new Buffer (opack, LITTLE_ENDIAN));
}
private Variant? read_value (ValueFlags flags = 0) throws Error {
uint8 v = reader.read_uint8 ();
uint8 top = v >> 4;
uint8 bottom = v & 0b1111;
switch (top) {
case 0:
switch (bottom) {
case 3:
if ((flags & ValueFlags.ALLOW_TERMINATOR) == 0)
throw new Error.PROTOCOL ("Unexpected OPACK terminator");
return null;
}
throw new Error.NOT_SUPPORTED ("Unsupported OPACK type 0x%02x", v);
case 3:
switch (bottom) {
case 0: return (int64) reader.read_int8 ();
case 1: return (int64) reader.read_int16 ();
case 2: return (int64) reader.read_int32 ();
case 3: return (int64) reader.read_int64 ();
}
throw new Error.NOT_SUPPORTED ("Unsupported OPACK type 0x%02x", v);
case 4:
case 5:
case 6:
return read_string (v - 0x40);
case 7:
case 8:
case 9:
return read_data (v - 0x70);
case 0xe:
return read_dictionary (bottom);
default:
throw new Error.NOT_SUPPORTED ("Unsupported OPACK type 0x%02x", v);
}
}
private Variant read_string (size_t len) throws Error {
if (len == 0x2f)
return reader.read_string ();
len = read_variable_length (len);
return reader.read_fixed_string (len);
}
private Variant read_data (size_t len) throws Error {
len = read_variable_length (len);
var bytes = reader.read_bytes (len);
return Variant.new_from_data (new VariantType.array (VariantType.BYTE), bytes.get_data (), true, bytes);
}
private size_t read_variable_length (size_t len) throws Error {
if (len <= 0x20)
return len;
switch (len) {
case 0x21:
return reader.read_uint8 ();
case 0x22:
return reader.read_uint16 ();
case 0x23:
uint32 bottom = reader.read_uint8 ();
uint32 top = reader.read_uint16 ();
return top << 8 | bottom;
case 0x24:
return reader.read_uint32 ();
default:
throw new Error.NOT_SUPPORTED ("Unsupported OPACK length: 0x%zx", len);
}
}
private Variant read_dictionary (size_t n) throws Error {
var builder = new VariantBuilder (VariantType.VARDICT);
bool has_terminator = n == 0xf;
size_t i = 0;
while (true) {
if (!has_terminator && i == n)
break;
var key = read_value (has_terminator ? ValueFlags.ALLOW_TERMINATOR : 0);
if (key == null)
break;
if (!key.is_of_type (VariantType.STRING))
throw new Error.PROTOCOL ("Unsupported OPACK dictionary key type");
var val = read_value ();
builder.add_value (new Variant.dict_entry (key, new Variant.variant (val)));
i++;
}
return builder.end ();
}
}
}
+12
View File
@@ -1573,6 +1573,12 @@ namespace Frida.Fruity {
if (t == typeof (int64))
return (uint) v.get_int64 ();
if (t == typeof (float))
return (uint) v.get_float ();
if (t == typeof (double))
return (uint) v.get_double ();
if (t == typeof (string))
return str_hash (v.get_string ());
@@ -1598,6 +1604,12 @@ namespace Frida.Fruity {
if (t == typeof (int64))
return a.get_int64 () == b.get_int64 ();
if (t == typeof (float))
return a.get_float () == b.get_float ();
if (t == typeof (double))
return a.get_double () == b.get_double ();
if (t == typeof (string))
return a.get_string () == b.get_string ();
+18 -39
View File
@@ -1,38 +1,33 @@
[CCode (gir_namespace = "FridaFruity", gir_version = "1.0")]
namespace Frida.Fruity {
public class SpringboardServicesClient : Object, AsyncInitable {
public LockdownClient lockdown {
public Device device {
get;
construct;
}
private PlistServiceClient service;
private SpringboardServicesClient (LockdownClient lockdown) {
Object (lockdown: lockdown);
private SpringboardServicesClient (Device device) {
Object (device: device);
}
public static async SpringboardServicesClient open (LockdownClient lockdown,
Cancellable? cancellable = null) throws SpringboardServicesError, IOError {
var client = new SpringboardServicesClient (lockdown);
public static async SpringboardServicesClient open (Device device, Cancellable? cancellable = null) throws Error, IOError {
var client = new SpringboardServicesClient (device);
try {
yield client.init_async (Priority.DEFAULT, cancellable);
} catch (GLib.Error e) {
throw_local_error (e);
throw_api_error (e);
}
return client;
}
private async bool init_async (int io_priority, Cancellable? cancellable) throws SpringboardServicesError, IOError {
try {
var stream = yield lockdown.start_service ("com.apple.springboardservices", cancellable);
private async bool init_async (int io_priority, Cancellable? cancellable) throws Error, IOError {
var stream = yield device.open_lockdown_service ("com.apple.springboardservices", cancellable);
service = new PlistServiceClient (stream);
} catch (LockdownError e) {
throw new SpringboardServicesError.PROTOCOL ("%s", e.message);
}
service = new PlistServiceClient (stream);
return true;
}
@@ -41,15 +36,14 @@ namespace Frida.Fruity {
yield service.close (cancellable);
}
public async Bytes get_icon_png_data (string bundle_id,
Cancellable? cancellable = null) throws SpringboardServicesError, IOError {
public async Bytes get_icon_png_data (string bundle_id, Cancellable? cancellable = null) throws Error, IOError {
try {
var request = make_request ("getIconPNGData");
request.set_string ("bundleId", bundle_id);
var response = yield service.query (request, cancellable);
if (response.has ("Error"))
throw new SpringboardServicesError.INVALID_ARGUMENT ("%s", response.get_string ("Error"));
throw new Error.INVALID_ARGUMENT ("%s", response.get_string ("Error"));
return response.get_bytes ("pngData");
} catch (PlistServiceError e) {
@@ -59,8 +53,8 @@ namespace Frida.Fruity {
}
}
public async Gee.HashMap<string, Bytes> get_icon_png_data_batch (string[] bundle_ids,
Cancellable? cancellable = null) throws SpringboardServicesError, IOError {
public async Gee.HashMap<string, Bytes> get_icon_png_data_batch (string[] bundle_ids, Cancellable? cancellable = null)
throws Error, IOError {
try {
foreach (unowned string bundle_id in bundle_ids) {
var request = make_request ("getIconPNGData");
@@ -73,7 +67,7 @@ namespace Frida.Fruity {
do {
foreach (Plist response in yield service.read_messages (0, cancellable)) {
if (response.has ("Error")) {
throw new SpringboardServicesError.INVALID_ARGUMENT ("%s",
throw new Error.INVALID_ARGUMENT ("%s",
response.get_string ("Error"));
}
@@ -98,27 +92,12 @@ namespace Frida.Fruity {
return request;
}
private static void throw_local_error (GLib.Error e) throws SpringboardServicesError, IOError {
if (e is SpringboardServicesError)
throw (SpringboardServicesError) e;
if (e is IOError)
throw (IOError) e;
assert_not_reached ();
private static Error error_from_service (PlistServiceError e) {
return new Error.PROTOCOL ("%s", e.message);
}
private static SpringboardServicesError error_from_service (PlistServiceError e) {
return new SpringboardServicesError.PROTOCOL ("%s", e.message);
private static Error error_from_plist (PlistError e) {
return new Error.PROTOCOL ("Unexpected response: %s", e.message);
}
private static SpringboardServicesError error_from_plist (PlistError e) {
return new SpringboardServicesError.PROTOCOL ("Unexpected response: %s", e.message);
}
}
public errordomain SpringboardServicesError {
INVALID_ARGUMENT,
PROTOCOL
}
}
+290
View File
@@ -0,0 +1,290 @@
[CCode (gir_namespace = "FridaFruity", gir_version = "1.0")]
namespace Frida.Fruity {
internal sealed class UsbDevice : Object, AsyncInitable {
public LibUSB.Device? raw_device {
get {
return _raw_device;
}
}
public LibUSB.DeviceHandle? handle {
get {
return _handle;
}
}
public string udid {
get {
return _udid;
}
}
public uint16 default_language_id {
get {
return _default_language_id;
}
}
private LibUSB.Device? _raw_device;
private LibUSB.DeviceHandle? _handle;
private string _udid;
private uint16 _default_language_id;
private enum AppleSpecificRequest {
GET_MODE = 0x45,
SET_MODE = 0x52,
}
private const string MODE_INITIAL_UNTETHERED = "3:3:3:0"; // => 5:3:3:0
private const string MODE_INITIAL_TETHERED = "4:4:3:4"; // => 5:4:3:4
public static async UsbDevice open (LibUSB.Device raw_device, Cancellable? cancellable = null) throws Error, IOError {
var device = new UsbDevice (raw_device);
try {
yield device.init_async (Priority.DEFAULT, cancellable);
} catch (GLib.Error e) {
throw_api_error (e);
}
return device;
}
private UsbDevice (LibUSB.Device raw_device) {
Object ();
_raw_device = raw_device;
}
private async bool init_async (int io_priority, Cancellable? cancellable) throws Error, IOError {
Usb.check (_raw_device.open (out _handle), "Failed to open USB device");
Bytes language_ids_response = yield read_string_descriptor_bytes (0, 0, cancellable);
if (language_ids_response.get_size () < sizeof (uint16))
throw new Error.PROTOCOL ("Invalid language IDs response");
Buffer language_ids = new Buffer (language_ids_response, LITTLE_ENDIAN);
_default_language_id = language_ids.read_uint16 (0);
var dev_desc = LibUSB.DeviceDescriptor (_raw_device);
string serial_number = yield read_string_descriptor (dev_desc.iSerialNumber, _default_language_id, cancellable);
_udid = udid_from_serial_number (serial_number);
return true;
}
public void close () {
_handle = null;
_raw_device = null;
}
public async bool maybe_modeswitch (Cancellable? cancellable) throws Error, IOError {
var response = yield control_transfer (
LibUSB.RequestRecipient.DEVICE | LibUSB.RequestType.VENDOR | LibUSB.EndpointDirection.IN,
AppleSpecificRequest.GET_MODE,
0,
0,
4,
1000,
cancellable);
string mode = parse_mode (response);
bool is_initial_mode = mode == MODE_INITIAL_UNTETHERED || mode == MODE_INITIAL_TETHERED;
if (!is_initial_mode)
return false;
response = yield control_transfer (
LibUSB.RequestRecipient.DEVICE | LibUSB.RequestType.VENDOR | LibUSB.EndpointDirection.IN,
AppleSpecificRequest.SET_MODE,
0,
3,
1,
1000,
cancellable);
if (response.get_size () != 1 || response[0] != 0x00)
return false;
return true;
}
private static string parse_mode (Bytes mode) throws Error {
if (mode.get_size () != 4)
throw new Error.PROTOCOL ("Invalid mode response");
unowned uint8[] m = mode.get_data ();
return "%u:%u:%u:%u".printf (m[0], m[1], m[2], m[3]);
}
private static string udid_from_serial_number (string serial) {
if (serial.length == 24)
return serial.substring (0, 8) + "-" + serial.substring (8);
return serial;
}
public async string read_string_descriptor (uint8 index, uint16 language_id, Cancellable? cancellable)
throws Error, IOError {
var response = yield read_string_descriptor_bytes (index, language_id, cancellable);
try {
var input = new DataInputStream (new MemoryInputStream.from_bytes (response));
input.byte_order = LITTLE_ENDIAN;
size_t size = response.get_size ();
if (size % sizeof (unichar2) != 0)
throw new Error.PROTOCOL ("Invalid string descriptor");
size_t n = size / sizeof (unichar2);
var chars = new unichar2[n];
for (size_t i = 0; i != n; i++)
chars[i] = input.read_uint16 ();
unowned string16 str = (string16) chars;
return str.to_utf8 ((long) n);
} catch (GLib.Error e) {
throw new Error.PROTOCOL ("%s", e.message);
}
}
public async Bytes read_string_descriptor_bytes (uint8 index, uint16 language_id, Cancellable? cancellable)
throws Error, IOError {
var response = yield control_transfer (
LibUSB.RequestRecipient.DEVICE | LibUSB.RequestType.STANDARD | LibUSB.EndpointDirection.IN,
LibUSB.StandardRequest.GET_DESCRIPTOR,
(LibUSB.DescriptorType.STRING << 8) | index,
language_id,
1024,
1000,
cancellable);
try {
var input = new DataInputStream (new MemoryInputStream.from_bytes (response));
input.byte_order = LITTLE_ENDIAN;
uint8 length = input.read_byte ();
if (length < 2)
throw new Error.PROTOCOL ("Invalid string descriptor length");
uint8 type = input.read_byte ();
if (type != LibUSB.DescriptorType.STRING)
throw new Error.PROTOCOL ("Invalid string descriptor type");
size_t remainder = response.get_size () - 2;
length -= 2;
if (length > remainder)
throw new Error.PROTOCOL ("Invalid string descriptor length");
return response[2:2 + length];
} catch (GLib.Error e) {
throw new Error.PROTOCOL ("%s", e.message);
}
}
public async Bytes control_transfer (uint8 request_type, uint8 request, uint16 val, uint16 index, uint16 length,
uint timeout, Cancellable? cancellable) throws Error, IOError {
var transfer = new LibUSB.Transfer ();
var ready_closure = new TransferReadyClosure (control_transfer.callback);
var buffer = new uint8[sizeof (LibUSB.ControlSetup) + length];
LibUSB.Transfer.fill_control_setup (buffer, request_type, request, val, index, length);
transfer.fill_control_transfer (_handle, buffer, on_transfer_ready, ready_closure, timeout);
var cancel_source = new CancellableSource (cancellable);
cancel_source.set_callback (() => {
transfer.cancel ();
return Source.REMOVE;
});
cancel_source.attach (MainContext.get_thread_default ());
try {
Usb.check (transfer.submit (), "Failed to submit control transfer");
yield;
} finally {
cancel_source.destroy ();
}
Usb.check_transfer (transfer.status, "Control transfer failed");
return new Bytes (((uint8[]) transfer.control_get_data ())[:transfer.actual_length]);
}
public async size_t bulk_transfer (uint8 endpoint, uint8[] buffer, uint timeout, Cancellable? cancellable)
throws Error, IOError {
var transfer = new LibUSB.Transfer ();
var ready_closure = new TransferReadyClosure (bulk_transfer.callback);
transfer.fill_bulk_transfer (_handle, endpoint, buffer, on_transfer_ready, ready_closure, timeout);
var cancel_source = new CancellableSource (cancellable);
cancel_source.set_callback (() => {
transfer.cancel ();
return Source.REMOVE;
});
cancel_source.attach (MainContext.get_thread_default ());
try {
Usb.check (transfer.submit (), "Failed to submit bulk transfer");
yield;
} finally {
cancel_source.destroy ();
}
Usb.check_transfer (transfer.status, "Bulk transfer failed");
return transfer.actual_length;
}
private static void on_transfer_ready (LibUSB.Transfer transfer) {
TransferReadyClosure * closure = transfer.user_data;
closure->schedule ();
}
private class TransferReadyClosure {
private SourceFunc? handler;
private MainContext main_context;
public TransferReadyClosure (owned SourceFunc handler) {
this.handler = (owned) handler;
main_context = MainContext.ref_thread_default ();
}
public void schedule () {
var source = new IdleSource ();
source.set_callback (() => {
handler ();
handler = null;
return Source.REMOVE;
});
source.attach (main_context);
}
}
}
namespace Usb {
internal static void check (LibUSB.Error error, string prefix) throws Error {
if (error >= LibUSB.Error.SUCCESS)
return;
string message = @"$prefix: $(error.get_description ())";
switch (error) {
case ACCESS:
throw new Error.PERMISSION_DENIED ("%s", message);
case NOT_FOUND:
throw new Error.INVALID_OPERATION ("%s", message);
case TIMEOUT:
throw new Error.TIMED_OUT ("%s", message);
default:
throw new Error.TRANSPORT ("%s", message);
}
}
internal static void check_transfer (LibUSB.TransferStatus status, string prefix) throws Error, IOError {
if (status == COMPLETED)
return;
string message = @"$prefix: $(status.to_string ())";
switch (status) {
case TIMED_OUT:
throw new Error.TIMED_OUT ("%s", message);
case CANCELLED:
throw new IOError.CANCELLED ("%s", message);
default:
throw new Error.TRANSPORT ("%s", message);
}
}
}
}
+29 -65
View File
@@ -1,13 +1,16 @@
[CCode (gir_namespace = "FridaFruity", gir_version = "1.0")]
namespace Frida.Fruity {
public class UsbmuxClient : Object, AsyncInitable {
public signal void device_attached (DeviceDetails details);
public signal void device_detached (DeviceId id);
public signal void device_attached (UsbmuxDevice device);
public signal void device_detached (UsbmuxDevice device);
public SocketConnection? connection {
get;
private set;
}
private Gee.Map<uint, UsbmuxDevice> devices = new Gee.HashMap<uint, UsbmuxDevice> ();
private InputStream? input;
private OutputStream? output;
private Cancellable io_cancellable = new Cancellable ();
@@ -132,11 +135,12 @@ namespace Frida.Fruity {
}
}
public async void connect_to_port (DeviceId device_id, uint16 port, Cancellable? cancellable = null) throws UsbmuxError, IOError {
public async void connect_to_port (uint device_id, uint16 port, Cancellable? cancellable = null)
throws UsbmuxError, IOError {
assert (is_processing_messages);
var request = create_request ("Connect");
request.set_integer ("DeviceID", device_id.raw_value);
request.set_integer ("DeviceID", device_id);
request.set_integer ("PortNumber", port.to_big_endian ());
var response = yield query (request, MODE_SWITCH, cancellable);
@@ -160,9 +164,9 @@ namespace Frida.Fruity {
}
}
public async Plist read_pair_record (Udid udid, Cancellable? cancellable = null) throws UsbmuxError, IOError {
public async Plist read_pair_record (string udid, Cancellable? cancellable = null) throws UsbmuxError, IOError {
var request = create_request ("ReadPairRecord");
request.set_string ("PairRecordID", udid.raw_value);
request.set_string ("PairRecordID", udid);
var response = yield query (request, REGULAR, cancellable);
try {
@@ -175,9 +179,9 @@ namespace Frida.Fruity {
}
}
public async void delete_pair_record (Udid udid, Cancellable? cancellable = null) throws UsbmuxError, IOError {
public async void delete_pair_record (string udid, Cancellable? cancellable = null) throws UsbmuxError, IOError {
var request = create_request ("DeletePairRecord");
request.set_string ("PairRecordID", udid.raw_value);
request.set_string ("PairRecordID", udid);
var response = yield query (request, REGULAR, cancellable);
check_pair_response (response, "DeletePairRecord");
@@ -276,28 +280,26 @@ namespace Frida.Fruity {
if (props.has ("ConnectionType") && props.get_string ("ConnectionType") == "Network")
connection_type = NETWORK;
var device_id = DeviceId ((uint) body.get_integer ("DeviceID"));
var device_id = (uint) body.get_integer ("DeviceID");
ProductId product_id;
if (connection_type == USB)
product_id = ProductId ((int) props.get_integer ("ProductID"));
else
product_id = ProductId (-1);
int product_id = (connection_type == USB) ? (int) props.get_integer ("ProductID") : -1;
string raw_udid = props.get_string ("SerialNumber");
if (raw_udid.length == 24)
raw_udid = raw_udid[:8] + "-" + raw_udid[8:];
var udid = Udid (raw_udid);
string udid = props.get_string ("SerialNumber");
if (udid.length == 24)
udid = udid[:8] + "-" + udid[8:];
InetSocketAddress? network_address = null;
if (connection_type == NETWORK)
network_address = parse_network_address (props.get_bytes ("NetworkAddress"));
var details =
new DeviceDetails (connection_type, device_id, product_id, udid, network_address);
device_attached (details);
var device =
new UsbmuxDevice (connection_type, device_id, product_id, udid, network_address);
devices[device_id] = device;
device_attached (device);
} else if (message_type == "Detached") {
device_detached (DeviceId ((uint) body.get_integer ("DeviceID")));
UsbmuxDevice? device;
if (devices.unset ((uint) body.get_integer ("DeviceID"), out device))
device_detached (device);
} else {
throw new UsbmuxError.PROTOCOL ("Unexpected message type: %s", message_type);
}
@@ -546,23 +548,23 @@ namespace Frida.Fruity {
PROTOCOL
}
public class DeviceDetails : Object {
public class UsbmuxDevice : Object {
public ConnectionType connection_type {
get;
construct;
}
public DeviceId id {
public uint id {
get;
construct;
}
public ProductId product_id {
public int product_id {
get;
construct;
}
public Udid udid {
public string udid {
get;
construct;
}
@@ -572,7 +574,7 @@ namespace Frida.Fruity {
construct;
}
public DeviceDetails (ConnectionType connection_type, DeviceId id, ProductId product_id, Udid udid,
public UsbmuxDevice (ConnectionType connection_type, uint id, int product_id, string udid,
InetSocketAddress? network_address) {
Object (
connection_type: connection_type,
@@ -583,42 +585,4 @@ namespace Frida.Fruity {
);
}
}
public enum ConnectionType {
USB,
NETWORK
}
public struct DeviceId {
public uint raw_value {
get;
private set;
}
public DeviceId (uint raw_value) {
this.raw_value = raw_value;
}
}
public struct ProductId {
public int raw_value {
get;
private set;
}
public ProductId (int raw_value) {
this.raw_value = raw_value;
}
}
public struct Udid {
public string raw_value {
get;
private set;
}
public Udid (string raw_value) {
this.raw_value = raw_value;
}
}
}
+3768
View File
File diff suppressed because it is too large. Load diff
+7 -3
View File
@@ -177,12 +177,16 @@ namespace Frida {
}
}
public interface ChannelProvider : Object {
public interface HostChannelProvider : Object {
public abstract async IOStream open_channel (string address, Cancellable? cancellable = null) throws Error, IOError;
}
public interface HostServiceProvider : Object {
public abstract async Service open_service (string address, Cancellable? cancellable = null) throws Error, IOError;
}
public interface Pairable : Object {
public abstract async void unpair (Cancellable? cancellable) throws Error, IOError;
public abstract async void unpair (Cancellable? cancellable = null) throws Error, IOError;
}
public interface HostSessionBackend : Object {
@@ -1537,7 +1541,7 @@ namespace Frida {
#if HAVE_FRUITY_BACKEND || HAVE_DROIDY_BACKEND
internal async DBusConnection establish_direct_connection (TransportBroker broker, AgentSessionId id,
ChannelProvider channel_provider, Cancellable? cancellable) throws Error, IOError {
HostChannelProvider channel_provider, Cancellable? cancellable) throws Error, IOError {
uint16 port;
string token;
try {
+47 -7
View File
@@ -470,8 +470,8 @@ if have_local_backend
agent_legacy,
agent_emulated_modern,
agent_emulated_legacy,
get_option('agent_dbghelp_prefix'),
get_option('agent_symsrv_prefix'),
gum_dep.get_variable('frida_dbghelp_prefix'),
gum_dep.get_variable('frida_symsrv_prefix'),
],
depends: agent_depends,
)
@@ -481,6 +481,8 @@ endif
if have_fruity_backend
backend_sources += [
'fruity' / 'fruity-host-session.vala',
'fruity' / 'device-monitor.vala',
'fruity' / 'xpc.vala',
'fruity' / 'dtx.vala',
'fruity' / 'lockdown.vala',
'fruity' / 'installation-proxy.vala',
@@ -488,16 +490,53 @@ if have_fruity_backend
'fruity' / 'lldb.vala',
'fruity' / 'injector.vala',
'fruity' / 'usbmux.vala',
'fruity' / 'dns.vala',
'fruity' / 'keyed-archive.vala',
'fruity' / 'plist.vala',
'fruity' / 'plist-service.vala',
'fruity' / 'opack.vala',
'fruity' / 'network-stack.vala',
'fruity' / 'usb.vala',
'fruity' / 'ncm.vala',
]
if host_os_family == 'windows'
backend_sources += 'fruity' / 'device-monitor-windows.vala'
elif host_os == 'macos'
backend_sources += 'fruity' / 'device-monitor-macos.vala'
elif host_os == 'linux'
backend_sources += 'fruity' / 'device-monitor-linux.vala'
endif
if host_os_family == 'windows'
backend_sources += 'fruity' / 'device-monitor-windows.c'
elif host_os_family == 'darwin'
backend_sources += 'fruity' / 'device-monitor-darwin.m'
else
backend_sources += 'fruity' / 'device-monitor-unix.c'
endif
backend_deps += openssl_dep
backend_vala_args += [
'--pkg=libnghttp2',
'--pkg=libngtcp2',
'--pkg=libngtcp2_crypto_quictls',
'--pkg=libusb-1.0',
'--pkg=lwip',
'--pkg=openssl',
]
if host_os_family == 'windows'
backend_sources += 'fruity' / 'fruity-host-session-windows.c'
backend_vala_args += '--pkg=windows-windns'
elif host_os_family == 'darwin'
backend_sources += 'fruity' / 'fruity-host-session-darwin.m'
else
backend_sources += 'fruity' / 'fruity-host-session-unix.c'
backend_vala_args += [
'--pkg=darwin-xnu',
'--pkg=darwin-xpc',
'--pkg=darwin-gcd',
'--pkg=corefoundation',
]
endif
if host_os_family == 'linux'
backend_vala_args += '--pkg=linux'
endif
endif
@@ -530,7 +569,7 @@ subdir('compiler')
core_sources = base_sources + backend_sources + compiler_sources
internal_libs = [base, pipe] + backend_libs
internal_deps = [base_dep, pipe_dep]
internal_deps = [base_dep, netif_dep, pipe_dep]
if host_os_family == 'windows'
gio_platform_vala_args = ['--pkg=gio-windows-2.0']
@@ -556,6 +595,7 @@ core_deps += backend_deps_private
core_vala_args = [
backend_vala_args,
base_vala_args,
'--pkg=gio-2.0',
gio_platform_vala_args,
'--pkg=json-glib-1.0',
+2 -4
View File
@@ -61,8 +61,7 @@ namespace Frida {
}
construct {
_device = new Device (null, "portal", "Portal", HostSessionProviderKind.LOCAL,
new PortalHostSessionProvider (this));
_device = new Device (null, new PortalHostSessionProvider (this));
cluster_service = new WebService (cluster_params, CLUSTER);
cluster_service.incoming.connect (on_incoming_cluster_connection);
@@ -930,9 +929,8 @@ namespace Frida {
}
public string name {
get { return _name; }
get { return "Portal"; }
}
private string _name = "Portal";
public Variant? icon {
get { return _icon; }
+1 -1
View File
@@ -1,6 +1,6 @@
[wrap-git]
url = https://github.com/frida/frida-gum.git
revision = 16.2.2
revision = 16.4.7
depth = 1
[provide]
+1 -1
View File
@@ -1,6 +1,6 @@
[wrap-git]
url = https://github.com/frida/libnice.git
revision = a0f43f0ea5755ce0374613b0a157be33a9f7d82e
revision = e12567b0a16a0c2eb5dfe5e0782baba8496772ff
depth = 1
[provide]
+8
View File
@@ -0,0 +1,8 @@
[wrap-git]
url = https://github.com/frida/libusb.git
revision = be4d8ec1012f35ff6ce9474ed8d7c3ec4182ac55
depth = 1
[provide]
dependency_names = libusb-1.0
+8
View File
@@ -0,0 +1,8 @@
[wrap-git]
url = https://github.com/frida/lwip.git
revision = 9f64c40cac2e77eddf6b3913961fdd056d307716
depth = 1
[provide]
dependency_names = lwip
+8
View File
@@ -0,0 +1,8 @@
[wrap-git]
url = https://github.com/frida/ngtcp2.git
revision = cc5cf523615b7fa7a9340234c7eec3c3645ae969
depth = 1
[provide]
dependency_names = libngtcp2, libngtcp2_crypto_quictls
+1 -1
View File
@@ -1,6 +1,6 @@
[wrap-git]
url = https://github.com/frida/openssl.git
revision = 95d037b2acc432039da4f506d25b6a01577d8bc5
revision = ca4781aaf7910b623d3ae21c6a017e7e9ca6936c
depth = 1
[provide]
+2 -4
View File
@@ -72,10 +72,8 @@ frida_test_process_backend_filename_of (void * handle)
image_count = _dyld_image_count ();
for (image_idx = 0; image_idx != image_count; image_idx++)
{
const gchar * image_path = _dyld_get_image_name (image_idx);
if (g_str_has_suffix (image_path, "/frida-tests"))
return g_strdup (image_path);
if (_dyld_get_image_header (image_idx)->filetype == MH_EXECUTE)
return g_strdup (_dyld_get_image_name (image_idx));
}
g_assert_not_reached ();
+177 -15
View File
@@ -60,6 +60,16 @@ namespace Frida.HostSessionTest {
var h = new Harness ((h) => Fruity.Manual.lockdown.begin (h as Harness));
h.run ();
});
GLib.Test.add_func ("/HostSession/Fruity/Manual/Xpc/list", () => {
var h = new Harness ((h) => Fruity.Manual.Xpc.list.begin (h as Harness));
h.run ();
});
GLib.Test.add_func ("/HostSession/Fruity/Manual/Xpc/launch", () => {
var h = new Harness ((h) => Fruity.Manual.Xpc.launch.begin (h as Harness));
h.run ();
});
#endif
#if HAVE_DROIDY_BACKEND
@@ -3517,16 +3527,17 @@ namespace Frida.HostSessionTest {
#endif
Variant? icon = prov.icon;
assert_nonnull (icon);
var dict = new VariantDict (icon);
int64 width, height;
assert_true (dict.lookup ("width", "x", out width));
assert_true (dict.lookup ("height", "x", out height));
assert_true (width == 16);
assert_true (height == 16);
VariantIter image;
assert_true (dict.lookup ("image", "ay", out image));
assert_true (image.n_children () == width * height * 4);
if (icon != null) {
var dict = new VariantDict (icon);
int64 width, height;
assert_true (dict.lookup ("width", "x", out width));
assert_true (dict.lookup ("height", "x", out height));
assert_true (width == 16);
assert_true (height == 16);
VariantIter image;
assert_true (dict.lookup ("image", "ay", out image));
assert_true (image.n_children () == width * height * 4);
}
try {
Cancellable? cancellable = null;
@@ -3626,6 +3637,9 @@ namespace Frida.HostSessionTest {
namespace Manual {
private const string DEVICE_ID = "<device-id>";
private const string APP_ID = "<app-id>";
private static async void lockdown (Harness h) {
if (!GLib.Test.slow ()) {
stdout.printf ("<skipping, run in slow mode with iOS device connected> ");
@@ -3635,15 +3649,13 @@ namespace Frida.HostSessionTest {
h.disable_timeout ();
var device_id = "<device-id>";
var app_id = "<app-id>";
string? target_name = null;
uint target_pid = 0;
var device_manager = new DeviceManager ();
try {
var device = yield device_manager.get_device_by_id (device_id);
var device = yield device_manager.get_device_by_id (DEVICE_ID);
device.output.connect ((pid, fd, data) => {
var chars = data.get_data ();
@@ -3663,9 +3675,21 @@ namespace Frida.HostSessionTest {
var timer = new Timer ();
printerr ("device.query_system_parameters()");
timer.reset ();
var p = yield device.query_system_parameters ();
printerr (" => got parameters, took %u ms\n", (uint) (timer.elapsed () * 1000.0));
var iter = HashTableIter<string, Variant> (p);
string k;
Variant v;
while (iter.next (out k, out v))
printerr ("%s: %s\n", k, v.print (false));
printerr ("device.enumerate_applications()");
timer.reset ();
var apps = yield device.enumerate_applications ();
var opts = new ApplicationQueryOptions ();
opts.scope = FULL;
var apps = yield device.enumerate_applications (opts);
printerr (" => got %d apps, took %u ms\n", apps.size (), (uint) (timer.elapsed () * 1000.0));
if (GLib.Test.verbose ()) {
var length = apps.size ();
@@ -3688,7 +3712,7 @@ namespace Frida.HostSessionTest {
} else {
printerr ("device.spawn()");
timer.reset ();
pid = yield device.spawn (app_id);
pid = yield device.spawn (APP_ID);
printerr (" => pid=%u, took %u ms\n", pid, (uint) (timer.elapsed () * 1000.0));
}
@@ -3738,9 +3762,147 @@ namespace Frida.HostSessionTest {
printerr ("\nFAIL: %s\n\n", e.message);
}
try {
yield device_manager.close ();
} catch (IOError e) {
assert_not_reached ();
}
h.done ();
}
namespace Xpc {
private static async void list (Harness h) {
if (!GLib.Test.slow ()) {
stdout.printf ("<skipping, run in slow mode with iOS device connected> ");
h.done ();
return;
}
var device_manager = new DeviceManager ();
try {
var timer = new Timer ();
var device = yield device_manager.get_device_by_id (DEVICE_ID);
printerr ("[*] Got device in %u ms\n", (uint) (timer.elapsed () * 1000.0));
timer.reset ();
var appservice = yield device.open_service ("xpc:com.apple.coredevice.appservice");
printerr ("[*] Opened service in %u ms\n", (uint) (timer.elapsed () * 1000.0));
var parameters = new HashTable<string, Variant> (str_hash, str_equal);
parameters["CoreDevice.featureIdentifier"] = "com.apple.coredevice.feature.listprocesses";
parameters["CoreDevice.action"] = new HashTable<string, Variant> (str_hash, str_equal);
parameters["CoreDevice.input"] = new HashTable<string, Variant> (str_hash, str_equal);
timer.reset ();
var response = yield appservice.request (parameters);
printerr ("[*] Made request in %u ms\n", (uint) (timer.elapsed () * 1000.0));
printerr ("Got response: %s\n", response.print (true));
} catch (GLib.Error e) {
printerr ("\nFAIL: %s\n\n", e.message);
yield;
}
h.done ();
}
private static async void launch (Harness h) {
if (!GLib.Test.slow ()) {
stdout.printf ("<skipping, run in slow mode with iOS device connected> ");
h.done ();
return;
}
var device_manager = new DeviceManager ();
try {
var timer = new Timer ();
var device = yield device_manager.get_device_by_id (DEVICE_ID);
printerr ("[*] Got device in %u ms\n", (uint) (timer.elapsed () * 1000.0));
timer.reset ();
var appservice = yield device.open_service ("xpc:com.apple.coredevice.appservice");
printerr ("[*] Opened service in %u ms\n", (uint) (timer.elapsed () * 1000.0));
var stdio_stream = yield device.open_channel ("tcp:com.apple.coredevice.openstdiosocket");
uint8 stdio_uuid[16];
size_t n;
yield stdio_stream.get_input_stream ().read_all_async (stdio_uuid, Priority.DEFAULT, null, out n);
var parameters = new HashTable<string, Variant> (str_hash, str_equal);
parameters["CoreDevice.featureIdentifier"] = "com.apple.coredevice.feature.launchapplication";
parameters["CoreDevice.action"] = new HashTable<string, Variant> (str_hash, str_equal);
var standard_input = Variant.new_from_data<void> (new VariantType ("ay"), stdio_uuid, true);
var standard_output = standard_input;
var standard_error = standard_output;
var input = new Variant.parsed (@"""{
'applicationSpecifier': <{
'bundleIdentifier': <{
'_0': <'$APP_ID'>
}>
}>,
'options': <{
'arguments': <@av []>,
'environmentVariables': <@a{sv} {}>,
'standardIOUsesPseudoterminals': <true>,
'startStopped': <false>,
'terminateExisting': <true>,
'user': <{
'active': <true>
}>,
'platformSpecificOptions': <
b'<?xml version="1.0" encoding="UTF-8"?><plist version="1.0"><dict/></plist>'
>
}>,
'standardIOIdentifiers': <{
'standardInput': <('uuid', %@ay)>,
'standardOutput': <('uuid', %@ay)>,
'standardError': <('uuid', %@ay)>
}>
}""",
standard_input,
standard_output,
standard_error);
printerr ("input: %s\n", input.print (true));
parameters["CoreDevice.input"] = input;
timer.reset ();
var response = yield appservice.request (parameters);
printerr ("[*] Made request in %u ms\n", (uint) (timer.elapsed () * 1000.0));
printerr ("Got response: %s\n", response.print (true));
process_stdio.begin (stdio_stream);
// Wait forever...
h.disable_timeout ();
yield;
} catch (GLib.Error e) {
printerr ("\nFAIL: %s\n\n", e.message);
yield;
}
h.done ();
}
private async void process_stdio (IOStream stream) {
try {
var input = new DataInputStream (stream.get_input_stream ());
while (true) {
var line = yield input.read_line_async ();
if (line == null) {
printerr ("process_stdio: EOF\n");
break;
}
printerr ("process_stdio got line: %s\n", line);
}
} catch (GLib.Error e) {
printerr ("process_stdio: %s\n", e.message);
}
}
}
}
namespace Plist {
+145
View File
@@ -0,0 +1,145 @@
[CCode (cheader_filename = "CoreFoundation/CoreFoundation.h", cprefix = "CF", gir_namespace = "CoreFoundation", gir_version = "1.0")]
namespace CoreFoundation {
[Compact]
[CCode (cname = "struct __CFArray")]
public class Array : Type {
[CCode (cname = "CFArrayCreate")]
public Array (Allocator? allocator, [CCode (array_length_type = "CFIndex")] Type[] values,
ArrayCallBacks callbacks = ArrayCallBacks.DEFAULT);
public Index length {
[CCode (cname = "CFArrayGetCount")]
get;
}
[CCode (cname = "CFArrayGetValueAtIndex")]
public void * @get (Index i);
}
public struct ArrayCallBacks {
[CCode (cname = "kCFTypeArrayCallBacks")]
public static ArrayCallBacks DEFAULT;
public Index version;
public ArrayRetainCallBack retain;
public ArrayReleaseCallBack release;
public ArrayCopyDescriptionCallBack copyDescription;
public ArrayEqualCallBack equal;
}
public delegate void * ArrayRetainCallBack (Allocator allocator, void * value);
public delegate void ArrayReleaseCallBack (Allocator allocator, void * value);
public delegate String ArrayCopyDescriptionCallBack (void * value);
public delegate bool ArrayEqualCallBack (void * value1, void * value2);
[Compact]
[CCode (cname = "struct __CFArray")]
public class MutableArray : Array {
[CCode (cname = "CFArrayRemoveAllValues")]
public void clear ();
[CCode (cname = "CFArrayAppendValue")]
public void add (void * value);
}
[Compact]
[CCode (cname = "struct __CFDictionary")]
public class Dictionary : Type {
[CCode (cname = "CFDictionaryGetCount")]
public Index count ();
[CCode (cname = "CFDictionaryGetValue")]
public void * @get (void * key);
public string get_string_value (string key) {
return ((String) @get (String.make (key))).to_string ();
}
}
[Compact]
[CCode (cname = "struct __CFDictionary")]
public class MutableDictionary : Dictionary {
[CCode (cname = "CFDictionaryRemoveAllValues")]
public void clear ();
[CCode (cname = "CFDictionaryAddValue")]
public void add (void * key, void * value);
[CCode (cname = "CFDictionaryRemoveValue")]
public void remove (void * key);
}
[Compact]
[CCode (cname = "const struct __CFString")]
public class String : Type {
public Index length {
get { return _length (); }
}
public static String make (string str) {
return from_cstring (null, str, StringEncoding.UTF8);
}
public string to_string () {
var max_length = max_size_for_encoding (length, StringEncoding.UTF8) + 1;
var buffer = new char[max_length];
to_cstring (buffer, max_length, StringEncoding.UTF8);
return (string) buffer;
}
[CCode (cname = "CFStringCreateWithCString")]
private static String from_cstring (Allocator? allocator, uint8 * c_str, StringEncoding encoding);
[CCode (cname = "CFStringGetCString")]
private bool to_cstring (uint8 * buffer, Index buffer_size, StringEncoding encoding);
[CCode (cname = "CFStringGetLength")]
private Index _length ();
[CCode (cname = "CFStringGetMaximumSizeForEncoding")]
private static Index max_size_for_encoding (Index length, StringEncoding encoding);
}
[CCode (cname = "CFStringEncoding", cprefix = "kCFStringEncoding", has_type_id = false)]
public enum StringEncoding {
MacRoman,
WindowsLatin1,
ISOLatin1,
NextStepLatin,
ASCII,
Unicode,
UTF8,
NonLossyASCII,
UTF16,
UTF16BE,
UTF16LE,
UTF32,
UTF32BE,
UTF32LE,
}
[Compact]
[CCode (cname = "const void", ref_function = "CFRetain", unref_function = "CFRelease")]
public class Type {
[CCode (cname = "CFShow")]
public void show ();
public string to_string () {
return description ().to_string ();
}
[CCode (cname = "CFCopyDescription")]
private String description ();
}
[Compact]
[CCode (cname = "CFAllocatorRef")]
public class Allocator {
[CCode (cname = "CFAllocatorGetDefault")]
public static Allocator get_default ();
}
[CCode (cname = "CFIndex", has_type_id = false)]
public struct Index : long {
}
}
+30
View File
@@ -0,0 +1,30 @@
[CCode (cheader_filename = "dispatch/dispatch.h", gir_namespace = "Darwin", gir_version = "1.0")]
namespace Darwin.GCD {
[Compact]
[CCode (cname = "void", ref_function = "_frida_dispatch_retain", unref_function = "dispatch_release",
cheader_filename = "frida-darwin.h")]
public class DispatchQueue {
[CCode (cname = "dispatch_queue_create")]
public DispatchQueue (string label, DispatchQueueAttr attr);
[CCode (cname = "dispatch_async_f")]
public void dispatch_async ([CCode (delegate_target_pos = 0.9)] DispatchFunction work);
[CCode (cname = "dispatch_sync_f")]
public void dispatch_sync ([CCode (delegate_target_pos = 0.9)] DispatchFunction work);
}
[CCode (cname = "dispatch_function_t")]
public delegate void DispatchFunction ();
[Compact]
[CCode (cname = "dispatch_queue_attr_t", cprefix = "DISPATCH_QUEUE_")]
public class DispatchQueueAttr {
public static DispatchQueueAttr SERIAL;
public static DispatchQueueAttr SERIAL_INACTIVE;
public static DispatchQueueAttr CONCURRENT;
public static DispatchQueueAttr CONCURRENT_INACTIVE;
public static DispatchQueueAttr SERIAL_WITH_AUTORELEASE_POOL;
public static DispatchQueueAttr CONCURRENT_WITH_AUTORELEASE_POOL;
}
}
+12
View File
@@ -0,0 +1,12 @@
#ifndef __DARWIN_SYSTEMCONFIGURATION_H__
#define __DARWIN_SYSTEMCONFIGURATION_H__
#ifndef HAVE_MACOS
# include <os/availability.h>
# undef API_UNAVAILABLE
# define API_UNAVAILABLE(...)
#endif
#include <SystemConfiguration/SystemConfiguration.h>
#endif
+43
View File
@@ -0,0 +1,43 @@
[CCode (cheader_filename = "darwin-systemconfiguration.h", cprefix = "SC", gir_namespace = "Darwin", gir_version = "1.0")]
namespace Darwin.SystemConfiguration {
[Compact]
[CCode (cname = "struct __SCDynamicStore")]
public class DynamicStore : CoreFoundation.Type {
[CCode (cname = "SCDynamicStoreCreate")]
public DynamicStore (CoreFoundation.Allocator? allocator, CoreFoundation.String name, DynamicStoreCallBack callout,
DynamicStoreContext context);
[CCode (cname = "SCDynamicStoreSetNotificationKeys")]
public bool set_notification_keys (CoreFoundation.Array? keys, CoreFoundation.Array? patterns);
[CCode (cname = "SCDynamicStoreSetDispatchQueue")]
public bool set_dispatch_queue (Darwin.GCD.DispatchQueue? queue);
[CCode (cname = "SCDynamicStoreCopyKeyList")]
public CoreFoundation.Array copy_key_list (CoreFoundation.String pattern);
[CCode (cname = "SCDynamicStoreCopyValue")]
public CoreFoundation.Type? copy_value (CoreFoundation.String key);
[CCode (cname = "SCDynamicStoreCopyMultiple")]
public CoreFoundation.Dictionary copy_multiple (CoreFoundation.Array? keys, CoreFoundation.Array? patterns = null);
}
[CCode (has_target = false)]
public delegate void DynamicStoreCallBack (DynamicStore store, CoreFoundation.Array changed_keys, void * info);
public struct DynamicStoreContext {
public CoreFoundation.Index version;
public void * info;
public RetainFunc? retain;
public ReleaseFunc? release;
public CopyDescriptionFunc? copyDescription;
}
[CCode (has_target = false)]
public delegate void * RetainFunc (void * info);
[CCode (has_target = false)]
public delegate void ReleaseFunc (void * info);
[CCode (has_target = false)]
public delegate CoreFoundation.String CopyDescriptionFunc (void * info);
}
+104
View File
@@ -0,0 +1,104 @@
[CCode (lower_case_cprefix = "", gir_namespace = "Darwin", gir_version = "1.0")]
namespace Darwin.XNU {
[CCode (cname = "kern_return_t", cheader_filename = "mach/mach_error.h", cprefix = "KERN_", has_type_id = false)]
public enum KernReturn {
SUCCESS,
INVALID_ADDRESS,
PROTECTION_FAILURE,
NO_SPACE,
INVALID_ARGUMENT,
FAILURE,
RESOURCE_SHORTAGE,
NOT_RECEIVER,
NO_ACCESS,
MEMORY_FAILURE,
MEMORY_ERROR,
ALREADY_IN_SET,
NOT_IN_SET,
NAME_EXISTS,
ABORTED,
INVALID_NAME,
INVALID_TASK,
INVALID_RIGHT,
INVALID_VALUE,
UREFS_OVERFLOW,
INVALID_CAPABILITY,
RIGHT_EXISTS,
INVALID_HOST,
MEMORY_PRESENT,
MEMORY_DATA_MOVED,
MEMORY_RESTART_COPY,
INVALID_PROCESSOR_SET,
POLICY_LIMIT,
INVALID_POLICY,
INVALID_OBJECT,
ALREADY_WAITING,
DEFAULT_SET,
EXCEPTION_PROTECTED,
INVALID_LEDGER,
INVALID_MEMORY_CONTROL,
INVALID_SECURITY,
NOT_DEPRESSED,
TERMINATED,
LOCK_SET_DESTROYED,
LOCK_UNSTABLE,
LOCK_OWNED,
LOCK_OWNED_SELF,
SEMAPHORE_DESTROYED,
RPC_SERVER_TERMINATED,
RPC_TERMINATE_ORPHAN,
RPC_CONTINUE_ORPHAN,
NOT_SUPPORTED,
NODE_DOWN,
NOT_WAITING,
OPERATION_TIMED_OUT,
CODESIGN_ERROR,
POLICY_STATIC,
INSUFFICIENT_BUFFER_SIZE,
DENIED,
MISSING_KC,
INVALID_KC,
NOT_FOUND,
RETURN_MAX,
}
[CCode (cheader_filename = "mach/mach_error.h")]
public static unowned string mach_error_string (KernReturn kr);
[CCode (cname = "mach_port_t", has_type_id = false)]
public struct MachPort : uint {
[CCode (cname = "MACH_PORT_NULL")]
public const MachPort NULL;
}
[CCode (cheader_filename = "libproc.h")]
public int proc_pidpath (int pid, char[] buffer);
[CCode (cheader_filename = "sys/sysctl.h")]
public int sysctlbyname (string name, void * oldp, size_t * oldlenp, void * newp = null, size_t newlen = 0);
[CCode (cname = "struct xinpgen", cheader_filename = "netinet/in_pcb.h")]
public struct InetPcbGeneration {
[CCode (cname = "xig_len")]
public int32 length;
[CCode (cname = "xig_count")]
public uint count;
[CCode (cname = "xig_gen")]
public uint64 generation_count;
[CCode (cname = "xig_sogen")]
public uint64 socket_generation_count;
}
[CCode (cname = "struct in_addr_4in6", cheader_filename = "netinet/in_pcb.h")]
public struct InetAddr4in6 {
[CCode (cname = "ia46_addr4")]
public Posix.InAddr addr4;
}
[CCode (cprefix = "INP_", cheader_filename = "netinet/in_pcb.h")]
public enum InetVersionFlags {
IPV4,
IPV6,
V4MAPPEDV6,
}
}
+161
View File
@@ -0,0 +1,161 @@
[CCode (cheader_filename = "xpc/xpc.h", lower_case_cprefix = "xpc_", gir_namespace = "Darwin", gir_version = "1.0")]
namespace Darwin.Xpc {
[Compact]
[CCode (cname = "gpointer", ref_function = "xpc_retain", unref_function = "xpc_release")]
public class Connection {
public static Connection create (string? name, GCD.DispatchQueue targetq);
public static Connection create_mach_service (string? name, GCD.DispatchQueue targetq, uint64 flags = 0);
[CCode (cname = "_frida_xpc_connection_set_event_handler", cheader_filename = "frida-darwin.h")]
public void set_event_handler (Handler handler);
public void activate ();
public void cancel ();
public void send_message (Object message);
[CCode (cname = "_frida_xpc_connection_send_message_with_reply", cheader_filename = "frida-darwin.h")]
public void send_message_with_reply (Object message, GCD.DispatchQueue replyq, owned Handler handler);
}
[CCode (cname = "FridaXpcHandler")]
public delegate void Handler (Object object);
[Compact]
[CCode (cname = "gpointer", ref_function = "xpc_retain", unref_function = "xpc_release")]
public class Object {
public Type type {
[CCode (cname = "xpc_get_type")]
get;
}
[CCode (cname = "_frida_xpc_object_to_string", cheader_filename = "frida-darwin.h")]
public string to_string ();
}
[Compact]
[CCode (cname = "gpointer")]
public class Type {
public string name {
get;
}
}
[Compact]
[CCode (cname = "gpointer")]
public class Bool : Object {
[CCode (cname = "XPC_TYPE_BOOL")]
public static Type TYPE;
[CCode (cname = "xpc_bool_create")]
public Bool (bool val);
public bool get_value ();
}
[Compact]
[CCode (cname = "gpointer")]
public class Int64 : Object {
[CCode (cname = "XPC_TYPE_INT64")]
public static Type TYPE;
[CCode (cname = "xpc_int64_create")]
public Int64 (int64 val);
public int64 get_value ();
}
[Compact]
[CCode (cname = "gpointer")]
public class UInt64 : Object {
[CCode (cname = "XPC_TYPE_UINT64")]
public static Type TYPE;
[CCode (cname = "xpc_uint64_create")]
public UInt64 (uint64 val);
public uint64 get_value ();
}
[Compact]
[CCode (cname = "gpointer")]
public class String : Object {
[CCode (cname = "XPC_TYPE_STRING")]
public static Type TYPE;
[CCode (cname = "xpc_string_create")]
public String (string val);
public unowned string get_string_ptr ();
}
[Compact]
[CCode (cname = "gpointer")]
public class Uuid : Object {
[CCode (cname = "XPC_TYPE_UUID")]
public static Type TYPE;
[CCode (array_length = false)]
public unowned uint8[] get_bytes ();
}
[Compact]
[CCode (cname = "gpointer")]
public class Array : Object {
[CCode (cname = "XPC_TYPE_ARRAY")]
public static Type TYPE;
public size_t count {
get;
}
[CCode (cname = "xpc_array_create_empty")]
public Array ();
public unowned Object? get_value (size_t index);
public void set_value (size_t index, Object val);
}
[Compact]
[CCode (cname = "gpointer")]
public class Dictionary : Object {
[CCode (cname = "XPC_TYPE_DICTIONARY")]
public static Type TYPE;
[CCode (cname = "xpc_dictionary_create_empty")]
public Dictionary ();
public bool get_bool (string key);
public void set_bool (string key, bool val);
public int64 get_int64 (string key);
public void set_int64 (string key, int64 val);
public uint64 get_uint64 (string key);
public void set_uint64 (string key, uint64 val);
public unowned string? get_string (string key);
public void set_string (string key, string val);
public unowned Dictionary? get_dictionary (string key);
public unowned Object? get_value (string key);
public void set_value (string key, Object val);
[CCode (cname = "_frida_xpc_dictionary_apply", cheader_filename = "frida-darwin.h")]
public bool apply (DictionaryApplier applier);
public Connection? create_connection (string key);
}
[CCode (cname = "FridaXpcDictionaryApplier")]
public delegate bool DictionaryApplier (string key, Object val);
[Compact]
[CCode (cname = "gpointer")]
public class Error : Dictionary {
[CCode (cname = "XPC_TYPE_ERROR")]
public static Type TYPE;
public const string KEY_DESCRIPTION;
}
}
+358
View File
@@ -0,0 +1,358 @@
[CCode (cheader_filename = "nghttp2/nghttp2.h", cprefix = "nghttp2_", gir_namespace = "NGHttp2", gir_version = "1.0")]
namespace NGHttp2 {
[Compact]
[CCode (cname = "nghttp2_session", cprefix = "nghttp2_session_", free_function = "nghttp2_session_del")]
public class Session {
[CCode (cname = "nghttp2_session_client_new2")]
public static int make_client (out Session session, SessionCallbacks callbacks, void * user_data, Option? option = null);
[CCode (cname = "nghttp2_submit_settings")]
public int submit_settings (uint8 flags, SettingsEntry[] entries);
[CCode (cname = "nghttp2_submit_window_update")]
public int submit_window_update (uint8 flags, int32 stream_id, int32 window_size_increment);
public int set_local_window_size (uint8 flags, int32 stream_id, int32 window_size);
[CCode (cname = "nghttp2_submit_request")]
public int32 submit_request (PrioritySpec? pri_spec, NV[] nvs, DataProvider? data_prd, void * stream_user_data);
[CCode (cname = "nghttp2_submit_headers")]
public int32 submit_headers (uint8 flags, int32 stream_id, PrioritySpec? pri_spec, NV[] nvs, void * stream_user_data);
[CCode (cname = "nghttp2_submit_data")]
public int submit_data (uint8 flags, int32 stream_id, DataProvider data_prd);
public int send ();
public ssize_t mem_recv (uint8[] input);
public bool want_read ();
public bool want_write ();
public int consume_connection (size_t size);
}
[Compact]
[CCode (cname = "nghttp2_session_callbacks", cprefix = "nghttp2_session_callbacks_",
free_function = "nghttp2_session_callbacks_del")]
public class SessionCallbacks {
[CCode (cname = "nghttp2_session_callbacks_new")]
public static int make (out SessionCallbacks callbacks);
public void set_send_callback (SendCallback callback);
public void set_on_frame_recv_callback (OnFrameRecvCallback callback);
public void set_on_data_chunk_recv_callback (OnDataChunkRecvCallback callback);
public void set_before_frame_send_callback (BeforeFrameSendCallback callback);
public void set_on_frame_send_callback (OnFrameSendCallback callback);
public void set_on_frame_not_send_callback (OnFrameNotSendCallback callback);
public void set_on_stream_close_callback (OnStreamCloseCallback callback);
public void set_on_begin_frame_callback (OnBeginFrameCallback callback);
[CCode (cname = "nghttp2_session_callbacks_set_error_callback2")]
public void set_error_callback (ErrorCallback callback);
}
[CCode (cname = "nghttp2_send_callback", has_target = false)]
public delegate ssize_t SendCallback (Session session, [CCode (array_length_type = "size_t")] uint8[] data, int flags,
void * user_data);
[CCode (cname = "nghttp2_on_frame_recv_callback", has_target = false)]
public delegate int OnFrameRecvCallback (Session session, Frame frame, void * user_data);
[CCode (cname = "nghttp2_on_data_chunk_recv_callback", has_target = false)]
public delegate int OnDataChunkRecvCallback (Session session, uint8 flags, int32 stream_id,
[CCode (array_length_type = "size_t")] uint8[] data, void * user_data);
[CCode (cname = "nghttp2_before_frame_send_callback", has_target = false)]
public delegate int BeforeFrameSendCallback (Session session, Frame frame, void * user_data);
[CCode (cname = "nghttp2_on_frame_send_callback", has_target = false)]
public delegate int OnFrameSendCallback (Session session, Frame frame, void * user_data);
[CCode (cname = "nghttp2_on_frame_not_send_callback", has_target = false)]
public delegate int OnFrameNotSendCallback (Session session, Frame frame, ErrorCode lib_error_code, void * user_data);
[CCode (cname = "nghttp2_on_stream_close_callback", has_target = false)]
public delegate int OnStreamCloseCallback (Session session, int32 stream_id, uint32 error_code, void * user_data);
[CCode (cname = "nghttp2_on_begin_frame_callback", has_target = false)]
public delegate int OnBeginFrameCallback (Session session, FrameHd hd, void * user_data);
[CCode (cname = "nghttp2_error_callback2", has_target = false)]
public delegate int ErrorCallback (Session session, ErrorCode code, [CCode (array_length_type = "size_t")] char[] msg,
void * user_data);
[CCode (cname = "nghttp2_frame")]
public struct Frame {
public FrameHd hd;
public DataFrame data;
public HeadersFrame headers;
public PriorityFrame priority;
public RstStreamFrame rst_stream;
public SettingsFrame settings;
public PushPromiseFrame push_promise;
public PingFrame ping;
public GoawayFrame goaway;
public WindowUpdateFrame window_update;
public ExtensionFrame ext;
}
[CCode (cname = "nghttp2_frame_type", cprefix = "NGHTTP2_", has_type_id = false)]
public enum FrameType {
DATA,
HEADERS,
PRIORITY,
RST_STREAM,
SETTINGS,
PUSH_PROMISE,
PING,
GOAWAY,
WINDOW_UPDATE,
CONTINUATION,
ALTSVC,
ORIGIN,
PRIORITY_UPDATE,
}
[CCode (cname = "nghttp2_frame_hd")]
public struct FrameHd {
public size_t length;
public int32 stream_id;
public FrameType type;
public uint8 flags;
public uint8 reserved;
}
[CCode (cname = "nghttp2_data")]
public struct DataFrame {
public FrameHd hd;
public size_t padlen;
}
[CCode (cname = "nghttp2_headers")]
public struct HeadersFrame {
public FrameHd hd;
public size_t padlen;
public PrioritySpec pri_spec;
public NV * nva;
public size_t nvlen;
public HeadersCategory cat;
}
[CCode (cname = "nghttp2_headers_category", cprefix = "NGHTTP2_HCAT_", has_type_id = false)]
public enum HeadersCategory {
REQUEST,
RESPONSE,
PUSH_RESPONSE,
HEADERS,
}
[CCode (cname = "nghttp2_priority")]
public struct PriorityFrame {
public FrameHd hd;
public PrioritySpec pri_spec;
}
[CCode (cname = "nghttp2_rst_stream")]
public struct RstStreamFrame {
public FrameHd hd;
public uint32 error_code;
}
[CCode (cname = "nghttp2_settings")]
public struct SettingsFrame {
public FrameHd hd;
public size_t niv;
public SettingsEntry * iv;
}
[CCode (cname = "nghttp2_push_promise")]
public struct PushPromiseFrame {
public FrameHd hd;
public size_t padlen;
public NV * nva;
public size_t nvlen;
public int32 promised_stream_id;
public uint8 reserved;
}
[CCode (cname = "nghttp2_ping")]
public struct PingFrame {
public FrameHd hd;
public uint8[] opaque_data;
}
[CCode (cname = "nghttp2_goaway")]
public struct GoawayFrame {
public FrameHd hd;
public int32 last_stream_id;
public uint32 error_code;
public uint8 * opaque_data;
public size_t opaque_data_len;
public uint8 reserved;
}
[CCode (cname = "nghttp2_window_update")]
public struct WindowUpdateFrame {
public FrameHd hd;
public int32 window_size_increment;
public uint8 reserved;
}
[CCode (cname = "nghttp2_extension")]
public struct ExtensionFrame {
public FrameHd hd;
public void * payload;
}
[Compact]
[CCode (cname = "nghttp2_option", cprefix = "nghttp2_option_", free_function = "nghttp2_option_del")]
public class Option {
[CCode (cname = "nghttp2_option_new")]
public static int make (out Option option);
public void set_no_auto_window_update (bool val);
public void set_peer_max_concurrent_streams (uint32 val);
public void set_no_recv_client_magic (bool val);
public void set_no_http_messaging (bool val);
public void set_no_http_semantics (bool val);
public void set_max_reserved_remote_streams (uint32 val);
public void set_user_recv_extension_type (uint8 type);
public void set_builtin_recv_extension_type (uint8 type);
public void set_no_auto_ping_ack (bool val);
public void set_max_send_header_block_length (size_t val);
public void set_max_deflate_dynamic_table_size (size_t val);
public void set_no_closed_streams (bool val);
public void set_max_outbound_ack (size_t val);
public void set_max_settings (size_t val);
public void set_server_fallback_rfc7540_priorities (bool val);
public void set_no_rfc9113_leading_and_trailing_ws_validation (bool val);
}
[CCode (cname = "nghttp2_settings_entry")]
public struct SettingsEntry {
public SettingsId settings_id;
public uint32 value;
}
[CCode (cname = "nghttp2_settings_id", cprefix = "NGHTTP2_SETTINGS_", has_type_id = false)]
public enum SettingsId {
HEADER_TABLE_SIZE,
ENABLE_PUSH,
MAX_CONCURRENT_STREAMS,
INITIAL_WINDOW_SIZE,
MAX_FRAME_SIZE,
MAX_HEADER_LIST_SIZE,
ENABLE_CONNECT_PROTOCOL,
NO_RFC7540_PRIORITIES,
}
[CCode (cname = "nghttp2_priority_spec")]
public struct PrioritySpec {
public int32 stream_id;
public int32 weight;
public uint8 exclusive;
}
[CCode (cname = "nghttp2_nv")]
public struct NV {
public uint8 * name;
public uint8 * value;
public size_t namelen;
public size_t valuelen;
public NVFlag flags;
}
[CCode (cname = "nghttp2_nv_flag", cprefix = "NGHTTP2_NV_FLAG_", has_type_id = false)]
[Flags]
public enum NVFlag {
NONE,
NO_INDEX,
NO_COPY_NAME,
NO_COPY_VALUE,
}
[CCode (cname = "nghttp2_data_provider")]
public struct DataProvider {
public DataSource source;
public DataSourceReadCallback read_callback;
}
[CCode (cname = "nghttp2_data_source")]
public struct DataSource {
public void * ptr;
}
[CCode (cname = "nghttp2_data_source_read_callback", has_target = false)]
public delegate ssize_t DataSourceReadCallback (Session session, int32 stream_id,
[CCode (array_length_type = "size_t")] uint8[] buf, ref uint32 data_flags, DataSource source, void * user_data);
[CCode (cname = "nghttp2_strerror")]
public unowned string strerror (ssize_t result);
[CCode (cname = "nghttp2_error", cprefix = "NGHTTP2_ERR_", has_type_id = false)]
public enum ErrorCode {
INVALID_ARGUMENT,
BUFFER_ERROR,
UNSUPPORTED_VERSION,
WOULDBLOCK,
PROTO,
INVALID_FRAME,
EOF,
DEFERRED,
STREAM_ID_NOT_AVAILABLE,
STREAM_CLOSED,
STREAM_CLOSING,
STREAM_SHUT_WR,
INVALID_STREAM_ID,
INVALID_STREAM_STATE,
DEFERRED_DATA_EXIST,
START_STREAM_NOT_ALLOWED,
GOAWAY_ALREADY_SENT,
INVALID_HEADER_BLOCK,
INVALID_STATE,
TEMPORAL_CALLBACK_FAILURE,
FRAME_SIZE_ERROR,
HEADER_COMP,
FLOW_CONTROL,
INSUFF_BUFSIZE,
PAUSE,
TOO_MANY_INFLIGHT_SETTINGS,
PUSH_DISABLED,
DATA_EXIST,
SESSION_CLOSING,
HTTP_HEADER,
HTTP_MESSAGING,
REFUSED_STREAM,
INTERNAL,
CANCEL,
SETTINGS_EXPECTED,
TOO_MANY_SETTINGS,
FATAL,
NOMEM,
CALLBACK_FAILURE,
BAD_CLIENT_MAGIC,
FLOODED,
}
[CCode (cname = "nghttp2_flag", cprefix = "NGHTTP2_FLAG_", has_type_id = false)]
[Flags]
public enum Flag {
NONE,
END_STREAM,
END_HEADERS,
ACK,
PADDED,
PRIORITY,
}
[CCode (cname = "nghttp2_data_flag", cprefix = "NGHTTP2_DATA_FLAG_", has_type_id = false)]
[Flags]
public enum DataFlag {
NONE,
EOF,
NO_END_STREAM,
NO_COPY,
}
}
+535
View File
@@ -0,0 +1,535 @@
[CCode (cheader_filename = "ngtcp2/ngtcp2.h", lower_case_cprefix = "ngtcp2_", gir_namespace = "NGTcp2", gir_version = "1.0")]
namespace NGTcp2 {
[Compact]
[CCode (cname = "ngtcp2_conn", cprefix = "ngtcp2_conn_", free_function = "ngtcp2_conn_del")]
public class Connection {
[CCode (cname = "ngtcp2_conn_client_new")]
public static int make_client (out Connection conn, ConnectionID dcid, ConnectionID scid, Path path,
ProtocolVersion client_chosen_version, Callbacks callbacks, Settings settings, TransportParams params,
MemoryAllocator? mem, void * user_data);
public void set_tls_native_handle (void * tls_native_handle);
public void set_keep_alive_timeout (Duration timeout);
public Timestamp get_expiry ();
public int handle_expiry (Timestamp ts);
[CCode (cname = "ngtcp2_conn_read_pkt")]
public int read_packet (Path path, PacketInfo * pi, uint8[] pkt, Timestamp ts);
public int open_bidi_stream (out int64 stream_id, void * stream_user_data);
public ssize_t write_stream (Path * path, PacketInfo * pi, uint8[] dest, ssize_t * pdatalen, WriteStreamFlags flags,
int64 stream_id, uint8[]? data, Timestamp ts);
public ssize_t writev_stream (Path * path, PacketInfo * pi, uint8[] dest, ssize_t * pdatalen, WriteStreamFlags flags,
int64 stream_id, IOVector[] datav, Timestamp ts);
public ssize_t write_datagram (Path * path, PacketInfo * pi, uint8[] dest, int * paccepted, uint32 flags, uint64 dgram_id,
uint8[] data, Timestamp ts);
public ssize_t writev_datagram (Path * path, PacketInfo * pi, uint8[] dest, int * paccepted, uint32 flags, uint64 dgram_id,
IOVector[] datav, Timestamp ts);
public uint64 get_max_data_left ();
public uint64 get_max_stream_data_left (int64 stream_id);
}
public unowned string strerror (int liberr);
[CCode (cname = "int", cprefix = "NGTCP2_ERR_", has_type_id = false)]
public enum ErrorCode {
INVALID_ARGUMENT,
NOBUF,
PROTO,
INVALID_STATE,
ACK_FRAME,
STREAM_ID_BLOCKED,
STREAM_IN_USE,
STREAM_DATA_BLOCKED,
FLOW_CONTROL,
CONNECTION_ID_LIMIT,
STREAM_LIMIT,
FINAL_SIZE,
CRYPTO,
PKT_NUM_EXHAUSTED,
REQUIRED_TRANSPORT_PARAM,
MALFORMED_TRANSPORT_PARAM,
FRAME_ENCODING,
DECRYPT,
STREAM_SHUT_WR,
STREAM_NOT_FOUND,
STREAM_STATE,
RECV_VERSION_NEGOTIATION,
CLOSING,
DRAINING,
TRANSPORT_PARAM,
DISCARD_PKT,
CONN_ID_BLOCKED,
INTERNAL,
CRYPTO_BUFFER_EXCEEDED,
WRITE_MORE,
RETRY,
DROP_CONN,
AEAD_LIMIT_REACHED,
NO_VIABLE_PATH,
VERSION_NEGOTIATION,
HANDSHAKE_TIMEOUT,
VERSION_NEGOTIATION_FAILURE,
IDLE_CLOSE,
FATAL,
NOMEM,
CALLBACK_FAILURE,
}
[CCode (cname = "ngtcp2_cid", has_destroy_function = false)]
public struct ConnectionID {
public size_t datalen;
public uint8 data[MAX_CIDLEN];
}
[CCode (cname = "ngtcp2_connection_id_status_type", cprefix = "NGTCP2_CONNECTION_ID_STATUS_TYPE_", has_type_id = false)]
public enum ConnectionIdStatusType {
ACTIVATE,
DEACTIVATE,
}
[CCode (cname = "ngtcp2_path", has_destroy_function = false)]
public struct Path {
public Address local;
public Address remote;
public void * user_data;
}
[CCode (cname = "ngtcp2_path_validation_result", cprefix = "NGTCP2_PATH_VALIDATION_RESULT_", has_type_id = false)]
public enum PathValidationResult {
SUCCESS,
FAILURE,
ABORTED,
}
[CCode (cname = "uint32_t", cprefix = "NGTCP2_PROTO_VER_", has_type_id = false)]
public enum ProtocolVersion {
V1,
V2,
MIN,
MAX,
}
[CCode (cname = "ngtcp2_pkt_info", has_destroy_function = false)]
public struct PacketInfo {
public uint8 ecn;
}
[CCode (cname = "ngtcp2_pkt_hd", has_destroy_function = false)]
public struct PacketHeader {
public ConnectionID dcid;
public ConnectionID scid;
public int64 pkt_num;
[CCode (array_length_cname = "tokenlen")]
public uint8[]? token;
public size_t pkt_numlen;
public size_t len;
public uint32 version;
public uint8 type;
public uint8 flags;
}
[CCode (cname = "ngtcp2_pkt_stateless_reset", has_destroy_function = false)]
public struct PacketStatelessReset {
public uint8 stateless_reset_token[STATELESS_RESET_TOKENLEN];
[CCode (array_length_cname = "randlen")]
public uint8[] rand;
}
[Flags]
[CCode (cname = "uint32_t", cprefix = "NGTCP2_WRITE_STREAM_FLAG_", has_type_id = false)]
public enum WriteStreamFlags {
NONE,
MORE,
FIN,
}
[CCode (cname = "NGTCP2_MAX_CIDLEN")]
public const size_t MAX_CIDLEN;
[CCode (cname = "NGTCP2_MIN_INITIAL_DCIDLEN")]
public const size_t MIN_INITIAL_DCIDLEN;
[CCode (cname = "NGTCP2_STATELESS_RESET_TOKENLEN")]
public const size_t STATELESS_RESET_TOKENLEN;
[CCode (cname = "ngtcp2_vec", has_destroy_function = false)]
public struct IOVector {
[CCode (array_length_cname = "len")]
public unowned uint8[] base;
}
[CCode (cname = "ngtcp2_sa_family", cprefix = "NGTCP2_AF_", has_type_id = false)]
public enum SocketAddressFamily {
INET,
INET6,
}
[SimpleType]
[CCode (cname = "ngtcp2_in_port")]
public struct InternetPort : uint16 {
}
[CCode (cname = "ngtcp2_sockaddr", has_destroy_function = false)]
public struct SocketAddress {
public SocketAddressFamily sa_family;
public uint8 sa_data[14];
}
[CCode (cname = "ngtcp2_in_addr", has_destroy_function = false)]
public struct InternetAddress {
public uint32 s_addr;
}
[CCode (cname = "ngtcp2_sockaddr_in", has_destroy_function = false)]
public struct SocketAddressInternet {
public SocketAddressFamily sin_family;
public InternetPort sin_port;
public InternetAddress sin_addr;
public uint8 sin_zero[8];
}
[CCode (cname = "ngtcp2_in6_addr", has_destroy_function = false)]
public struct Internet6Address {
public uint8 in6_addr[16];
}
[CCode (cname = "ngtcp2_sockaddr_in6", has_destroy_function = false)]
public struct SocketAddressInternet6 {
public SocketAddressFamily sin6_family;
public InternetPort sin6_port;
public uint32 sin6_flowinfo;
public Internet6Address sin6_addr;
public uint32 sin6_scope_id;
}
[SimpleType]
[CCode (cname = "ngtcp2_socklen")]
public struct SocketLength : uint32 {
}
[CCode (cname = "ngtcp2_addr", has_destroy_function = false)]
public struct Address {
[CCode (array_length_cname = "addrlen")]
public uint8[] addr;
}
[CCode (cname = "ngtcp2_preferred_addr", has_destroy_function = false)]
public struct PreferredAddress {
public ConnectionID cid;
public SocketAddressInternet ipv4;
public SocketAddressInternet6 ipv6;
public uint8 ipv4_present;
public uint8 ipv6_present;
public uint8 stateless_reset_token[STATELESS_RESET_TOKENLEN];
}
[CCode (cname = "ngtcp2_version_info", has_destroy_function = false)]
public struct VersionInfo {
public uint32 chosen_version;
[CCode (array_length_cname = "available_versionslen")]
public uint8[] available_versions;
}
[CCode (cname = "ngtcp2_encryption_level", cprefix = "NGTCP2_ENCRYPTION_LEVEL_", has_type_id = false)]
public enum EncryptionLevel {
INITIAL,
HANDSHAKE,
1RTT,
0RTT,
}
[CCode (cname = "ngtcp2_token_type", cprefix = "NGTCP2_TOKEN_TYPE_", has_type_id = false)]
public enum TokenType {
UNKNOWN,
RETRY,
NEW_TOKEN,
}
[CCode (cname = "ngtcp2_rand_ctx", has_destroy_function = false)]
public struct RNGContext {
public void * native_handle;
}
[CCode (cname = "ngtcp2_crypto_aead", has_destroy_function = false)]
public struct CryptoAead {
public void * native_handle;
public size_t max_overhead;
}
[CCode (cname = "ngtcp2_crypto_cipher", has_destroy_function = false)]
public struct CryptoCipher {
public void * native_handle;
}
[CCode (cname = "ngtcp2_crypto_aead_ctx", has_destroy_function = false)]
public struct CryptoAeadCtx {
public void * native_handle;
}
[CCode (cname = "ngtcp2_crypto_cipher_ctx", has_destroy_function = false)]
public struct CryptoCipherCtx {
public void * native_handle;
}
[CCode (cname = "ngtcp2_cc_algo", cprefix = "NGTCP2_CC_ALGO_", has_type_id = false)]
public enum CongestionControlAlgorithm {
RENO,
CUBIC,
BBR,
}
[SimpleType]
[CCode (cname = "ngtcp2_tstamp")]
public struct Timestamp : uint64 {
}
[CCode (cname = "NGTCP2_SECONDS")]
public const uint64 SECONDS;
[CCode (cname = "NGTCP2_MILLISECONDS")]
public const uint64 MILLISECONDS;
[CCode (cname = "NGTCP2_MICROSECONDS")]
public const uint64 MICROSECONDS;
[CCode (cname = "NGTCP2_NANOSECONDS")]
public const uint64 NANOSECONDS;
[SimpleType]
[CCode (cname = "ngtcp2_duration")]
public struct Duration : uint64 {
}
[CCode (cname = "ngtcp2_callbacks", has_destroy_function = false)]
public struct Callbacks {
public ClientInitial? client_initial;
public RecvClientInitial? recv_client_initial;
public RecvCryptoData recv_crypto_data;
public HandshakeCompleted? handshake_completed;
public RecvVersionNegotiation? recv_version_negotiation;
public Encrypt encrypt;
public Decrypt decrypt;
public HpMask hp_mask;
public RecvStreamData? recv_stream_data;
public AckedStreamDataOffset? acked_stream_data_offset;
public StreamOpen? stream_open;
public StreamClose? stream_close;
public RecvStatelessReset? recv_stateless_reset;
public RecvRetry? recv_retry;
public ExtendMaxStreams? extend_max_local_streams_bidi;
public ExtendMaxStreams? extend_max_local_streams_uni;
public Rand? rand;
public GetNewConnectionId get_new_connection_id;
public RemoveConnectionId? remove_connection_id;
public UpdateKey update_key;
public PathValidation? path_validation;
public SelectPreferredAddr? select_preferred_addr;
public StreamReset? stream_reset;
public ExtendMaxStreams? extend_max_remote_streams_bidi;
public ExtendMaxStreams? extend_max_remote_streams_uni;
public ExtendMaxStreamData? extend_max_stream_data;
public ConnectionIdStatus? dcid_status;
public HandshakeConfirmed? handshake_confirmed;
public RecvNewToken? recv_new_token;
public DeleteCryptoAeadCtx delete_crypto_aead_ctx;
public DeleteCryptoCipherCtx delete_crypto_cipher_ctx;
public RecvDatagram? recv_datagram;
public AckDatagram? ack_datagram;
public LostDatagram? lost_datagram;
public GetPathChallengeData get_path_challenge_data;
public StreamStopSending? stream_stop_sending;
public VersionNegotiation version_negotiation;
public RecvKey recv_rx_key;
public RecvKey recv_tx_key;
public TlsEarlyDataRejected? tls_early_data_rejected;
}
[CCode (cname = "ngtcp2_client_initial", has_target = false)]
public delegate int ClientInitial (Connection conn, void * user_data);
[CCode (cname = "ngtcp2_recv_client_initial", has_target = false)]
public delegate int RecvClientInitial (Connection conn, ConnectionID dcid, void * user_data);
[CCode (cname = "ngtcp2_recv_crypto_data", has_target = false)]
public delegate int RecvCryptoData (Connection conn, EncryptionLevel encryption_level, uint64 offset,
[CCode (array_length_type = "size_t")] uint8[] data, void * user_data);
[CCode (cname = "ngtcp2_handshake_completed", has_target = false)]
public delegate int HandshakeCompleted (Connection conn, void * user_data);
[CCode (cname = "ngtcp2_recv_version_negotiation", has_target = false)]
public delegate int RecvVersionNegotiation (Connection conn, PacketHeader hd, [CCode (array_length_type = "size_t")] uint32[] sv,
void * user_data);
[CCode (cname = "ngtcp2_encrypt", has_target = false)]
public delegate int Encrypt ([CCode (array_length = false)] uint8[] dest, CryptoAead aead, CryptoAeadCtx aead_ctx,
[CCode (array_length_type = "size_t")] uint8[] plaintext,
[CCode (array_length_type = "size_t")] uint8[] nonce,
[CCode (array_length_type = "size_t")] uint8[] aad);
[CCode (cname = "ngtcp2_decrypt", has_target = false)]
public delegate int Decrypt ([CCode (array_length = false)] uint8[] dest, CryptoAead aead, CryptoAeadCtx aead_ctx,
[CCode (array_length_type = "size_t")] uint8[] ciphertext,
[CCode (array_length_type = "size_t")] uint8[] nonce,
[CCode (array_length_type = "size_t")] uint8[] aad);
[CCode (cname = "ngtcp2_hp_mask", has_target = false)]
public delegate int HpMask ([CCode (array_length = false)] uint8[] dest, CryptoCipher hp, CryptoCipherCtx hp_ctx,
[CCode (array_length = false)] uint8[] sample);
[CCode (cname = "ngtcp2_recv_stream_data", has_target = false)]
public delegate int RecvStreamData (Connection conn, uint32 flags, int64 stream_id, uint64 offset,
[CCode (array_length_type = "size_t")] uint8[] data, void * user_data, void * stream_user_data);
[CCode (cname = "ngtcp2_acked_stream_data_offset", has_target = false)]
public delegate int AckedStreamDataOffset (Connection conn, int64 stream_id, uint64 offset, uint64 datalen, void * user_data,
void * stream_user_data);
[CCode (cname = "ngtcp2_stream_open", has_target = false)]
public delegate int StreamOpen (Connection conn, int64 stream_id, void * user_data);
[CCode (cname = "ngtcp2_stream_close", has_target = false)]
public delegate int StreamClose (Connection conn, uint32 flags, int64 stream_id, uint64 app_error_code, void * user_data,
void * stream_user_data);
[CCode (cname = "ngtcp2_recv_stateless_reset", has_target = false)]
public delegate int RecvStatelessReset (Connection conn, PacketStatelessReset sr, void * user_data);
[CCode (cname = "ngtcp2_recv_retry", has_target = false)]
public delegate int RecvRetry (Connection conn, PacketHeader hd, void * user_data);
[CCode (cname = "ngtcp2_extend_max_streams", has_target = false)]
public delegate int ExtendMaxStreams (Connection conn, uint64 max_streams, void * user_data);
[CCode (cname = "ngtcp2_extend_max_stream_data", has_target = false)]
public delegate int ExtendMaxStreamData (Connection conn, int64 stream_id, uint64 max_data, void * user_data,
void * stream_user_data);
[CCode (cname = "ngtcp2_rand", has_target = false)]
public delegate void Rand ([CCode (array_length_type = "size_t")] uint8[] dest, RNGContext rand_ctx);
[CCode (cname = "ngtcp2_get_new_connection_id", has_target = false)]
public delegate int GetNewConnectionId (Connection conn, out ConnectionID cid, [CCode (array_length = false)] uint8[] token,
size_t cidlen, void * user_data);
[CCode (cname = "ngtcp2_remove_connection_id", has_target = false)]
public delegate int RemoveConnectionId (Connection conn, ConnectionID cid, void * user_data);
[CCode (cname = "ngtcp2_update_key", has_target = false)]
public delegate int UpdateKey (Connection conn,
[CCode (array_length = false)] uint8[] rx_secret,
[CCode (array_length = false)] uint8[] tx_secret,
CryptoAeadCtx rx_aead_ctx, [CCode (array_length = false)] uint8[] rx_iv,
CryptoAeadCtx tx_aead_ctx, [CCode (array_length = false)] uint8[] tx_iv,
[CCode (array_length_pos = 9.1)] uint8[] current_rx_secret,
[CCode (array_length_pos = 9.1)] uint8[] current_tx_secret,
void * user_data);
[CCode (cname = "ngtcp2_path_validation", has_target = false)]
public delegate int PathValidation (Connection conn, uint32 flags, Path path, Path old_path, PathValidationResult res,
void * user_data);
[CCode (cname = "ngtcp2_select_preferred_addr", has_target = false)]
public delegate int SelectPreferredAddr (Connection conn, Path dest, PreferredAddress paddr, void * user_data);
[CCode (cname = "ngtcp2_stream_reset", has_target = false)]
public delegate int StreamReset (Connection conn, int64 stream_id, uint64 final_size, uint64 app_error_code, void * user_data,
void * stream_user_data);
[CCode (cname = "ngtcp2_connection_id_status", has_target = false)]
public delegate int ConnectionIdStatus (Connection conn, ConnectionIdStatusType type, uint64 seq, ConnectionID cid,
[CCode (array_length = false)] uint8[] token, void * user_data);
[CCode (cname = "ngtcp2_handshake_confirmed", has_target = false)]
public delegate int HandshakeConfirmed (Connection conn, void * user_data);
[CCode (cname = "ngtcp2_recv_new_token", has_target = false)]
public delegate int RecvNewToken (Connection conn, [CCode (array_length_type = "size_t")] uint8[] token, void * user_data);
[CCode (cname = "ngtcp2_delete_crypto_aead_ctx", has_target = false)]
public delegate void DeleteCryptoAeadCtx (Connection conn, CryptoAeadCtx aead_ctx, void * user_data);
[CCode (cname = "ngtcp2_delete_crypto_cipher_ctx", has_target = false)]
public delegate void DeleteCryptoCipherCtx (Connection conn, CryptoCipherCtx cipher_ctx, void * user_data);
[CCode (cname = "ngtcp2_recv_datagram", has_target = false)]
public delegate int RecvDatagram (Connection conn, uint32 flags, [CCode (array_length_type = "size_t")] uint8[] data,
void * user_data);
[CCode (cname = "ngtcp2_ack_datagram", has_target = false)]
public delegate int AckDatagram (Connection conn, uint64 dgram_id, void * user_data);
[CCode (cname = "ngtcp2_lost_datagram", has_target = false)]
public delegate int LostDatagram (Connection conn, uint64 dgram_id, void * user_data);
[CCode (cname = "ngtcp2_get_path_challenge_data", has_target = false)]
public delegate int GetPathChallengeData (Connection conn, [CCode (array_length = false)] uint8[] data, void * user_data);
[CCode (cname = "ngtcp2_stream_stop_sending", has_target = false)]
public delegate int StreamStopSending (Connection conn, int64 stream_id, uint64 app_error_code, void * user_data,
void * stream_user_data);
[CCode (cname = "ngtcp2_version_negotiation", has_target = false)]
public delegate int VersionNegotiation (Connection conn, uint32 version, ConnectionID client_dcid, void * user_data);
[CCode (cname = "ngtcp2_recv_key", has_target = false)]
public delegate int RecvKey (Connection conn, EncryptionLevel level, void * user_data);
[CCode (cname = "ngtcp2_tls_early_data_rejected", has_target = false)]
public delegate int TlsEarlyDataRejected (Connection conn, void * user_data);
[CCode (cname = "ngtcp2_settings", has_destroy_function = false)]
public struct Settings {
[CCode (cname = "ngtcp2_settings_default")]
public Settings.make_default ();
public QlogWrite? qlog_write;
public CongestionControlAlgorithm cc_algo;
public Timestamp initial_ts;
public Duration initial_rtt;
public Printf? log_printf;
public size_t max_tx_udp_payload_size;
[CCode (array_length_cname = "tokenlen")]
public uint8[]? token;
public TokenType token_type;
public RNGContext rand_ctx;
public uint64 max_window;
public uint64 max_stream_window;
public size_t ack_thresh;
public bool no_tx_udp_payload_size_shaping;
public Duration handshake_timeout;
[CCode (array_length_cname = "preferred_versionslen")]
public ProtocolVersion[]? preferred_versions;
[CCode (array_length_cname = "available_versionslen")]
public ProtocolVersion[]? available_versions;
public uint32 original_version;
public bool no_pmtud;
public uint32 initial_pkt_num;
}
[CCode (cname = "ngtcp2_qlog_write", has_target = false)]
public delegate void QlogWrite (void * user_data, uint32 flags, [CCode (array_length_type = "size_t")] uint8[] data);
[CCode (cname = "ngtcp2_printf", has_target = false)]
public delegate void Printf (void * user_data, string format, ...);
[CCode (cname = "ngtcp2_transport_params", has_destroy_function = false)]
public struct TransportParams {
[CCode (cname = "ngtcp2_transport_params_default")]
public TransportParams.make_default ();
public PreferredAddress preferred_addr;
public ConnectionID original_dcid;
public ConnectionID initial_scid;
public ConnectionID retry_scid;
public uint64 initial_max_stream_data_bidi_local;
public uint64 initial_max_stream_data_bidi_remote;
public uint64 initial_max_stream_data_uni;
public uint64 initial_max_data;
public uint64 initial_max_streams_bidi;
public uint64 initial_max_streams_uni;
public Duration max_idle_timeout;
public uint64 max_udp_payload_size;
public uint64 active_connection_id_limit;
public uint64 ack_delay_exponent;
public Duration max_ack_delay;
public uint64 max_datagram_frame_size;
public bool stateless_reset_token_present;
public bool disable_active_migration;
public bool original_dcid_present;
public bool initial_scid_present;
public bool retry_scid_present;
public bool preferred_addr_present;
public uint8 stateless_reset_token[STATELESS_RESET_TOKENLEN];
public bool grease_quic_bit;
public VersionInfo version_info;
public bool version_info_present;
}
[CCode (cname = "ngtcp2_mem", has_destroy_function = false)]
public struct MemoryAllocator {
public void * user_data;
public Malloc malloc;
public Free free;
public Calloc calloc;
public Realloc realloc;
}
[CCode (cname = "ngtcp2_malloc", has_target = false)]
public delegate void * Malloc (size_t size, void * user_data);
[CCode (cname = "ngtcp2_free", has_target = false)]
public delegate void Free (void * ptr, void * user_data);
[CCode (cname = "ngtcp2_calloc", has_target = false)]
public delegate void * Calloc (size_t nmemb, size_t size, void * user_data);
[CCode (cname = "ngtcp2_realloc", has_target = false)]
public delegate void * Realloc (void * ptr, size_t size, void * user_data);
}
+28
View File
@@ -0,0 +1,28 @@
[CCode (cheader_filename = "ngtcp2/ngtcp2_crypto.h", lower_case_cprefix = "ngtcp2_crypto_", gir_namespace = "NGTcp2Crypto", gir_version = "1.0")]
namespace NGTcp2.Crypto {
[CCode (cheader_filename = "ngtcp2/ngtcp2_crypto_quictls.h")]
namespace Quictls {
public int configure_client_context (OpenSSL.SSLContext ssl_ctx);
}
[CCode (cname = "ngtcp2_crypto_conn_ref", has_destroy_function = false)]
public struct ConnectionRef {
public GetConnection get_conn;
public void * user_data;
}
[CCode (cname = "ngtcp2_crypto_get_conn", has_target = false)]
public delegate unowned Connection GetConnection (ConnectionRef conn_ref);
public ClientInitial client_initial_cb;
public RecvCryptoData recv_crypto_data_cb;
public Encrypt encrypt_cb;
public Decrypt decrypt_cb;
public HpMask hp_mask_cb;
public RecvRetry recv_retry_cb;
public UpdateKey update_key_cb;
public DeleteCryptoAeadCtx delete_crypto_aead_ctx_cb;
public DeleteCryptoCipherCtx delete_crypto_cipher_ctx_cb;
public GetPathChallengeData get_path_challenge_data_cb;
public VersionNegotiation version_negotiation_cb;
}
+291
View File
@@ -0,0 +1,291 @@
[CCode (gir_namespace = "LWIP", gir_version = "1.0")]
namespace LWIP {
[CCode (cheader_filename = "lwip/tcpip.h", lower_case_cprefix = "tcpip_")]
namespace Runtime {
public void init (InitDoneFunc init_done);
[CCode (cname = "tcpip_callback")]
public ErrorCode schedule (WorkFunc work);
[CCode (cname = "tcpip_init_done_fn")]
public delegate void InitDoneFunc ();
[CCode (cname = "tcpip_callback_fn")]
public delegate void WorkFunc ();
}
[CCode (cheader_filename = "lwip/netif.h", cname = "struct netif", cprefix = "netif_")]
public struct NetworkInterface {
public static void add_noaddr (ref NetworkInterface netif, void * state, NetworkInterfaceInitFunc init,
NetworkInterfaceInputFunc input = NetworkInterface.default_input_handler);
public void remove ();
public void set_up ();
public void set_down ();
public void set_link_up ();
public void set_link_down ();
public void ip6_addr_set (int8 addr_idx, IP6Address address);
public void create_ip6_linklocal_address (bool from_mac_48bit);
public ErrorCode add_ip6_address (IP6Address address, int8 * chosen_index = null);
public void ip6_addr_set_state (int8 addr_index, IP6AddressState state);
[CCode (cname = "netif_input")]
public static ErrorCode default_input_handler (PacketBuffer pbuf, ref NetworkInterface netif);
public IP6Address ip6_addr[IPV6_NUM_ADDRESSES];
public NetworkInterfaceInputFunc input;
public NetworkInterfaceLinkOutputFunc linkoutput;
public NetworkInterfaceOutputIP6Func output_ip6;
public void * state;
public uint16 mtu;
public uint8 hwaddr[MAX_HWADDR_LEN];
public uint8 hwaddr_len;
public NetworkInterfaceFlags flags;
public uint8 num;
public const uint8 MAX_HWADDR_LEN;
}
[CCode (cname = "netif_init_fn", has_target = false)]
public delegate ErrorCode NetworkInterfaceInitFunc (ref NetworkInterface netif);
[CCode (cname = "netif_input_fn", has_target = false)]
public delegate ErrorCode NetworkInterfaceInputFunc (PacketBuffer pbuf, ref NetworkInterface netif);
[CCode (cname = "netif_linkoutput_fn", has_target = false)]
public delegate ErrorCode NetworkInterfaceLinkOutputFunc (ref NetworkInterface netif, PacketBuffer pbuf);
[CCode (cname = "netif_output_ip6_fn", has_target = false)]
public delegate ErrorCode NetworkInterfaceOutputIP6Func (ref NetworkInterface netif, PacketBuffer pbuf, IP6Address address);
[Flags]
[CCode (cheader_filename = "lwip/netif.h", cprefix = "NETIF_FLAG_")]
public enum NetworkInterfaceFlags {
UP,
BROADCAST,
LINK_UP,
ETHARP,
ETHERNET,
IGMP,
MLD6,
}
[CCode (cheader_filename = "lwip/prot/ethernet.h", lower_case_cprefix = "ETH_")]
namespace Ethernet {
public const uint8 HWADDR_LEN;
namespace IPv6 {
[CCode (cheader_filename = "lwip/ethip6.h", cname = "ethip6_output")]
public ErrorCode output (ref NetworkInterface netif, PacketBuffer pbuf, IP6Address address);
}
}
public const uint IPV6_NUM_ADDRESSES;
[CCode (cheader_filename = "lwip/ip6_addr.h", cname = "ip6_addr_t", cprefix = "ip6_addr_")]
public struct IP6Address {
[CCode (cname = "ip6addr_aton")]
public static IP6Address parse (string str);
[CCode (cname = "ip6addr_ntoa_r")]
public unowned string? to_string (char[] buf);
public uint32 addr[4];
public uint8 zone;
}
[Flags]
[CCode (cheader_filename = "lwip/ip6_addr.h", cname = "u8_t", cprefix = "IP6_ADDR_", has_type_id = false)]
public enum IP6AddressState {
INVALID,
TENTATIVE,
TENTATIVE_1,
TENTATIVE_2,
TENTATIVE_3,
TENTATIVE_4,
TENTATIVE_5,
TENTATIVE_6,
TENTATIVE_7,
VALID,
PREFERRED,
DEPRECATED,
DUPLICATED,
}
[CCode (cheader_filename = "lwip/ip_addr.h", cname = "u8_t", cprefix = "IPADDR_TYPE_", has_type_id = false)]
public enum IPAddressType {
V4,
V6,
ANY,
}
[CCode (cheader_filename = "lwip/mld6.h", cname = "struct netif", cprefix = "netif_")]
namespace IP6MulticastListenerDiscovery {
[CCode (cname = "mld6_joingroup")]
public ErrorCode join_group (IP6Address src_addr, IP6Address group_addr);
[CCode (cname = "mld6_joingroup_netif")]
public ErrorCode join_group_netif (ref NetworkInterface netif, IP6Address group_addr);
[CCode (cname = "mld6_leavegroup")]
public ErrorCode leave_group (IP6Address src_addr, IP6Address group_addr);
[CCode (cname = "mld6_leavegroup_netif")]
public ErrorCode leave_group_netif (ref NetworkInterface netif, IP6Address group_addr);
}
[Compact]
[CCode (cheader_filename = "lwip/pbuf.h", cname = "struct pbuf", cprefix = "pbuf_")]
public class PacketBuffer {
public static PacketBuffer alloc (Layer layer, uint16 length, Type type);
public PacketBuffer? next;
[CCode (array_length_cname = "len")]
public uint8[] payload;
public uint16 tot_len;
[CCode (array_length = false)]
public unowned uint8[] get_contiguous (uint8[] buffer, uint16 len, uint16 offset = 0);
public ErrorCode take (uint8[] data);
[CCode (cname = "pbuf_layer", cprefix = "PBUF_", has_type_id = false)]
public enum Layer {
TRANSPORT,
IP,
LINK,
RAW_TX,
RAW,
}
[CCode (cname = "pbuf_type", cprefix = "PBUF_", has_type_id = false)]
public enum Type {
RAM,
ROM,
REF,
POOL,
}
}
[Compact]
[CCode (cheader_filename = "lwip/tcp.h", cname = "struct tcp_pcb", cprefix = "tcp_")]
public class TcpPcb {
[CCode (cname = "tcp_new_ip_type")]
public static unowned TcpPcb make (IPAddressType type);
[CCode (cname = "tcp_arg")]
public void set_user_data (void * user_data);
[CCode (cname = "tcp_recv")]
public void set_recv_callback (RecvFunc f);
[CCode (cname = "tcp_sent")]
public void set_sent_callback (SentFunc f);
[CCode (cname = "tcp_err")]
public void set_error_callback (ErrorFunc f);
public void nagle_disable ();
public void nagle_enable ();
public void abort ();
public ErrorCode close ();
public ErrorCode shutdown (bool shut_rx, bool shut_tx);
public void bind_netif (NetworkInterface * netif);
public ErrorCode connect (IP6Address address, uint16 port, ConnectedFunc connected);
[CCode (cname = "tcp_recved")]
public void notify_received (uint16 len);
[CCode (cname = "tcp_sndbuf")]
public uint16 query_available_send_buffer_space ();
public ErrorCode write (uint8[] data, WriteFlags flags = 0);
public ErrorCode output ();
[CCode (cname = "tcp_recv_fn", has_target = false)]
public delegate ErrorCode RecvFunc (void * user_data, TcpPcb pcb, owned PacketBuffer? pbuf, ErrorCode err);
[CCode (cname = "tcp_sent_fn", has_target = false)]
public delegate ErrorCode SentFunc (void * user_data, TcpPcb pcb, uint16 len);
[CCode (cname = "tcp_err_fn", has_target = false)]
public delegate void ErrorFunc (void * user_data, ErrorCode err);
[CCode (cname = "tcp_connected_fn", has_target = false)]
public delegate ErrorCode ConnectedFunc (void * user_data, TcpPcb pcb, ErrorCode err);
[Flags]
[CCode (cname = "u8_t", cprefix = "TCP_WRITE_FLAG_", has_type_id = false)]
public enum WriteFlags {
COPY,
MORE,
}
}
[Compact]
[CCode (cheader_filename = "lwip/udp.h", cname = "struct udp_pcb", cprefix = "udp_")]
public class UdpPcb {
[CCode (cname = "udp_new_ip_type")]
public static unowned UdpPcb make (IPAddressType type);
public void remove ();
[CCode (cname = "udp_recv")]
public void set_recv_callback (RecvFunc f);
public ErrorCode bind (IP6Address? ipaddr = null, uint16 port = 0);
public void bind_netif (NetworkInterface * netif);
public ErrorCode connect (IP6Address ipaddr, uint16 port);
public ErrorCode send (PacketBuffer pbuf);
public ErrorCode sendto (PacketBuffer pbuf, IP6Address dst_ip, uint16 dst_port);
[CCode (cname = "tcp_recv_fn", instance_pos = 0)]
public delegate void RecvFunc (UdpPcb pcb, owned PacketBuffer? pbuf, IP6Address addr, uint16 port);
public IP6Address local_ip;
public IP6Address remote_ip;
public uint8 netif_idx;
public uint8 so_options;
public uint8 tos;
public uint8 ttl;
public uint8 flags;
public uint16 local_port;
public uint16 remote_port;
public uint8 mcast_ifindex;
public uint8 mcast_ttl;
}
[CCode (cheader_filename = "lwip/err.h", cname = "err_t", cprefix = "ERR_", lower_case_cprefix = "err_", has_type_id = false)]
public enum ErrorCode {
OK,
MEM,
BUF,
TIMEOUT,
RTE,
INPROGRESS,
VAL,
WOULDBLOCK,
USE,
ALREADY,
ISCONN,
CONN,
IF,
ABRT,
RST,
CLSD,
ARG;
public int to_errno ();
}
}
+539 -1
View File
@@ -1 +1,539 @@
// Placeholder to satisfy Meson assumptions.
[CCode (lower_case_cprefix = "OPENSSL_", gir_namespace = "OpenSSL", gir_version = "1.0")]
namespace OpenSSL {
[Compact]
[CCode (cname = "SSL_CTX", cprefix = "SSL_CTX_")]
public class SSLContext {
public SSLContext (SSLMethod meth);
[CCode (cname = "SSL_CTX_use_certificate")]
public int use_certificate (X509 cert);
[CCode (cname = "SSL_CTX_use_PrivateKey")]
public int use_private_key (Envelope.Key key);
}
[Compact]
[CCode (cname = "SSL", cprefix = "SSL_")]
public class SSL {
public SSL (SSLContext ctx);
public void set_app_data (void * data);
public void set_connect_state ();
public void set_accept_state ();
public int set_alpn_protos (uint8[] protos);
public void set_quic_transport_version (int version);
}
[Compact]
[CCode (cname = "SSL_METHOD", cprefix = "SSL_METHOD_", free_function = "")]
public class SSLMethod {
[CCode (cname = "TLS_method")]
public static unowned SSLMethod tls ();
[CCode (cname = "TLS_server_method")]
public static unowned SSLMethod tls_server ();
[CCode (cname = "TLS_client_method")]
public static unowned SSLMethod tls_client ();
[CCode (cname = "DTLS_method")]
public static unowned SSLMethod dtls ();
[CCode (cname = "DTLS_server_method")]
public static unowned SSLMethod dtls_server ();
[CCode (cname = "DTLS_client_method")]
public static unowned SSLMethod dtls_client ();
}
[CCode (lower_case_cprefix = "TLSEXT_TYPE_")]
namespace TLSExtensionType {
public const int quic_transport_parameters;
}
[Compact]
[CCode (cname = "X509", cprefix = "X509_")]
public class X509 {
public X509 ();
[CCode (cname = "X509_get_serialNumber")]
public unowned ASN1.Integer get_serial_number ();
[CCode (cname = "X509_getm_notBefore")]
public unowned ASN1.Time get_not_before ();
[CCode (cname = "X509_getm_notAfter")]
public unowned ASN1.Time get_not_after ();
public unowned Name get_subject_name ();
public int set_issuer_name (Name name);
public int set_pubkey (Envelope.Key key);
public int sign_ctx (Envelope.MessageDigestContext ctx);
[CCode (cname = "X509_get_X509_PUBKEY")]
public unowned X509PublicKey get_public_key ();
[CCode (cname = "i2d_X509_bio", instance_pos = 2)]
public int to_der (BasicIO sink);
[CCode (cname = "PEM_write_bio_X509", instance_pos = 2)]
public int to_pem (BasicIO sink);
[Compact]
[CCode (cname = "X509_NAME", cprefix = "X509_NAME_")]
public class Name {
public int add_entry_by_txt (string field, ASN1.MultiByteStringType type, uint8[] bytes, int loc = -1, int set = 0);
}
}
[Compact]
[CCode (cname = "X509_PUBKEY", cprefix = "X509_PUBKEY_", free_function = "")]
public class X509PublicKey {
[CCode (cname = "i2d_X509_PUBKEY_bio", instance_pos = 2)]
public int to_der (BasicIO sink);
[CCode (cname = "PEM_write_bio_X509_PUBKEY", instance_pos = 2)]
public int to_pem (BasicIO sink);
}
[Compact]
[CCode (cname = "BIO", cprefix = "BIO_")]
public class BasicIO {
public BasicIO (BasicIOMethod method);
[CCode (cname = "BIO_new_mem_buf")]
public BasicIO.from_static_memory_buffer (uint8[] buf);
public long get_mem_data ([CCode (array_length = false)] out unowned uint8[] data);
}
[Compact]
[CCode (cname = "BIO_METHOD", cprefix = "BIO_METHOD_", free_function = "")]
public class BasicIOMethod {
[CCode (cname = "BIO_s_mem")]
public static unowned BasicIOMethod memory ();
}
[CCode (cheader_filename = "openssl/asn1.h")]
namespace ASN1 {
[Compact]
[CCode (cname = "ASN1_INTEGER", cprefix = "ASN1_INTEGER_")]
public class Integer {
public int set_int64 (int64 v);
public int set_uint64 (uint64 v);
}
[Compact]
[CCode (cname = "ASN1_TIME", cprefix = "ASN1_TIME_")]
public class Time {
[CCode (cname = "X509_gmtime_adj")]
public unowned Time adjust (long delta);
}
[CCode (cname = "int", cprefix = "MBSTRING_", has_type_id = false)]
public enum MultiByteStringType {
UTF8,
[CCode (cname = "MBSTRING_ASC")]
ASCII,
}
}
[CCode (cheader_filename = "openssl/evp.h")]
namespace Envelope {
[Compact]
[CCode (cname = "EVP_PKEY_CTX", cprefix = "EVP_PKEY_", free_function = "EVP_PKEY_CTX_free")]
public class KeyContext {
[CCode (cname = "EVP_PKEY_CTX_new")]
public KeyContext.for_key (Key key, Engine? engine = null);
[CCode (cname = "EVP_PKEY_CTX_new_id")]
public KeyContext.for_key_type (KeyType type, Engine? engine = null);
public int keygen_init ();
public int keygen (ref Key pkey);
public int derive_init ();
public int derive_set_peer (Key peer);
public int derive ([CCode (array_length = false)] uint8[]? key, ref size_t keylen);
}
[Compact]
[CCode (cname = "EVP_PKEY", cprefix = "EVP_PKEY_", copy_function = "EVP_PKEY_dup")]
public class Key {
[CCode (cname = "d2i_PUBKEY_bio")]
public Key.from_der (BasicIO source, Key ** a = null);
[CCode (cname = "EVP_PKEY_new_raw_public_key")]
public Key.from_raw_public_key (KeyType type, Engine? engine, uint8[] pub);
[CCode (cname = "EVP_PKEY_new_raw_private_key")]
public Key.from_raw_private_key (KeyType type, Engine? engine, uint8[] priv);
public int get_raw_public_key ([CCode (array_length = false)] uint8[]? pub, ref size_t len);
public int get_raw_private_key ([CCode (array_length = false)] uint8[]? priv, ref size_t len);
[CCode (cname = "i2d_PUBKEY_bio", instance_pos = 2)]
public int to_der (BasicIO sink);
[CCode (cname = "PEM_write_bio_PUBKEY", instance_pos = 2)]
public int to_pem (BasicIO sink);
}
[Compact]
[CCode (cname = "EVP_PKEY_CTX", cprefix = "EVP_PKEY_CTX_")]
public class PublicKeyContext {
}
[CCode (cname = "int", cprefix = "EVP_PKEY_", has_type_id = false)]
public enum KeyType {
NONE,
RSA,
RSA2,
RSA_PSS,
DSA,
DSA1,
DSA2,
DSA3,
DSA4,
DH,
DHX,
EC,
SM2,
HMAC,
CMAC,
SCRYPT,
TLS1_PRF,
HKDF,
POLY1305,
SIPHASH,
X25519,
ED25519,
X448,
ED448,
KEYMGMT,
}
[Compact]
[CCode (cheader_filename = "openssl/kdf.h", cname = "EVP_KDF", cprefix = "EVP_KDF_")]
public class KeyDerivationFunction {
public static KeyDerivationFunction? fetch (LibraryContext? ctx, string algorithm, string? properties = null);
}
[Compact]
[CCode (cheader_filename = "openssl/kdf.h", cname = "EVP_KDF_CTX", cprefix = "EVP_KDF_",
free_function = "EVP_KDF_CTX_free")]
public class KeyDerivationContext {
[CCode (cname = "EVP_KDF_CTX_new")]
public KeyDerivationContext (KeyDerivationFunction kdf);
public int derive (uint8[] key, [CCode (array_length = false)] Param[] params);
}
[CCode (cheader_filename = "openssl/core_names.h", lower_case_cprefix = "OSSL_KDF_NAME_")]
namespace KeyDerivationAlgorithm {
public const string HKDF;
public const string TLS1_3_KDF;
public const string PBKDF1;
public const string PBKDF2;
public const string SCRYPT;
public const string SSHKDF;
public const string SSKDF;
public const string TLS1_PRF;
public const string X942KDF_ASN1;
public const string X942KDF_CONCAT;
public const string X963KDF;
public const string KBKDF;
public const string KRB5KDF;
}
[CCode (cheader_filename = "openssl/core_names.h", lower_case_cprefix = "OSSL_KDF_PARAM_")]
namespace KeyDerivationParameter {
public const string SECRET;
public const string KEY;
public const string SALT;
public const string PASSWORD;
public const string PREFIX;
public const string LABEL;
public const string DATA;
public const string DIGEST;
public const string CIPHER;
public const string MAC;
public const string MAC_SIZE;
public const string PROPERTIES;
public const string ITER;
public const string MODE;
public const string PKCS5;
public const string UKM;
public const string CEK_ALG;
public const string SCRYPT_N;
public const string SCRYPT_R;
public const string SCRYPT_P;
public const string SCRYPT_MAXMEM;
public const string INFO;
public const string SEED;
public const string SSHKDF_XCGHASH;
public const string SSHKDF_SESSION_ID;
public const string SSHKDF_TYPE;
public const string SIZE;
public const string CONSTANT;
public const string PKCS12_ID;
public const string KBKDF_USE_L;
public const string KBKDF_USE_SEPARATOR;
public const string X942_ACVPINFO;
public const string X942_PARTYUINFO;
public const string X942_PARTYVINFO;
public const string X942_SUPP_PUBINFO;
public const string X942_SUPP_PRIVINFO;
public const string X942_USE_KEYBITS;
}
[Compact]
[CCode (cname = "EVP_CIPHER_CTX", cprefix = "EVP_CIPHER_CTX_")]
public class CipherContext {
public CipherContext ();
public int reset ();
public int ctrl (CipherCtrlType type, int arg, void * ptr);
[CCode (cname = "EVP_EncryptInit")]
public int encrypt_init (Cipher cipher,
[CCode (array_length = false)] uint8[] key,
[CCode (array_length = false)] uint8[] iv);
[CCode (cname = "EVP_EncryptUpdate")]
public int encrypt_update ([CCode (array_length = false)] uint8[] output, ref int outlen, uint8[] input);
[CCode (cname = "EVP_EncryptFinal")]
public int encrypt_final ([CCode (array_length = false)] uint8[] output, ref int outlen);
[CCode (cname = "EVP_DecryptInit")]
public int decrypt_init (Cipher cipher,
[CCode (array_length = false)] uint8[] key,
[CCode (array_length = false)] uint8[] iv);
[CCode (cname = "EVP_DecryptUpdate")]
public int decrypt_update ([CCode (array_length = false)] uint8[] output, ref int outlen, uint8[] input);
[CCode (cname = "EVP_DecryptFinal")]
public int decrypt_final ([CCode (array_length = false)] uint8[] output, ref int outlen);
}
[Compact]
[CCode (cname = "EVP_CIPHER", cprefix = "EVP_CIPHER_")]
public class Cipher {
public static Cipher? fetch (LibraryContext? ctx, string algorithm, string? properties = null);
}
[CCode (cheader_filename = "openssl/evp.h", cname = "int", cprefix = "EVP_CTRL_", has_type_id = false)]
public enum CipherCtrlType {
INIT,
SET_KEY_LENGTH,
GET_RC2_KEY_BITS,
SET_RC2_KEY_BITS,
GET_RC5_ROUNDS,
SET_RC5_ROUNDS,
RAND_KEY,
PBE_PRF_NID,
COPY,
AEAD_SET_IVLEN,
AEAD_GET_TAG,
AEAD_SET_TAG,
AEAD_SET_IV_FIXED,
GCM_SET_IVLEN,
GCM_GET_TAG,
GCM_SET_TAG,
GCM_SET_IV_FIXED,
GCM_IV_GEN,
CCM_SET_IVLEN,
CCM_GET_TAG,
CCM_SET_TAG,
CCM_SET_IV_FIXED,
CCM_SET_L,
CCM_SET_MSGLEN,
AEAD_TLS1_AAD,
AEAD_SET_MAC_KEY,
GCM_SET_IV_INV,
TLS1_1_MULTIBLOCK_AAD,
TLS1_1_MULTIBLOCK_ENCRYPT,
TLS1_1_MULTIBLOCK_DECRYPT,
TLS1_1_MULTIBLOCK_MAX_BUFSIZE,
SSL3_MASTER_SECRET,
SET_SBOX,
SBOX_USED,
KEY_MESH,
BLOCK_PADDING_MODE,
SET_PIPELINE_OUTPUT_BUFS,
SET_PIPELINE_INPUT_BUFS,
SET_PIPELINE_INPUT_LENS,
GET_IVLEN,
SET_SPEED,
PROCESS_UNPROTECTED,
GET_WRAP_CIPHER,
TLSTREE,
}
[Compact]
[CCode (cname = "EVP_MD_CTX", cprefix = "EVP_MD_CTX_")]
public class MessageDigestContext {
public MessageDigestContext ();
[CCode (cname = "EVP_DigestSignInit")]
public int digest_sign_init (PublicKeyContext ** pctx, MessageDigest? type, Engine? engine = null, Key? key = null);
[CCode (cname = "EVP_DigestSignUpdate")]
public int digest_sign_update (uint8[] data);
[CCode (cname = "EVP_DigestSignFinal")]
public int digest_sign_final ([CCode (array_length = false)] uint8[]? sigret, ref size_t siglen);
[CCode (cname = "EVP_DigestSign")]
public int digest_sign ([CCode (array_length = false)] uint8[]? sigret, ref size_t siglen, uint8[] tbs);
}
[Compact]
[CCode (cname = "EVP_MD", cprefix = "EVP_MD_")]
public class MessageDigest {
public static MessageDigest fetch (LibraryContext? ctx, string algorithm, string? properties = null);
}
[Compact]
[CCode (cname = "EVP_MAC_CTX", cprefix = "EVP_MAC_CTX_")]
public class MessageAuthCodeContext {
public MessageAuthCodeContext (MessageAuthCode mac);
[CCode (cname = "EVP_MAC_init")]
public int init (uint8[] key, [CCode (array_length = false)] Param[]? params = null);
[CCode (cname = "EVP_MAC_update")]
public int update (uint8[] data);
[CCode (cname = "EVP_MAC_final")]
public int final ([CCode (array_length_pos = 2)] uint8[]? outdata, out size_t outlen);
}
[Compact]
[CCode (cname = "EVP_MAC", cprefix = "EVP_MAC_")]
public class MessageAuthCode {
public static MessageAuthCode fetch (LibraryContext? ctx, string algorithm, string? properties = null);
}
[CCode (cheader_filename = "openssl/core_names.h", lower_case_cprefix = "OSSL_MAC_PARAM_")]
namespace MessageAuthParameter {
public const string KEY;
public const string IV;
public const string CUSTOM;
public const string SALT;
public const string XOF;
public const string DIGEST_NOINIT;
public const string DIGEST_ONESHOT;
public const string C_ROUNDS;
public const string D_ROUNDS;
public const string CIPHER;
public const string DIGEST;
public const string PROPERTIES;
public const string SIZE;
public const string BLOCK_SIZE;
public const string TLS_DATA_SIZE;
}
}
[Compact]
[CCode (cheader_filename = "openssl/engine.h", cname = "ENGINE")]
public class Engine {
}
[Compact]
[CCode (cheader_filename = "openssl/types.h", cname = "OSSL_LIB_CTX")]
public class LibraryContext {
}
[CCode (cheader_filename = "openssl/core.h", cname = "OSSL_PARAM", has_copy_function = false, has_destroy_function = false)]
public struct Param {
public unowned string? key;
public ParamDataType data_type;
[CCode (array_length_cname = "data_size")]
public unowned uint8[]? data;
public size_t return_size;
}
[CCode (cheader_filename = "openssl/core.h", cname = "guint", cprefix = "OSSL_PARAM_", has_type_id = false)]
public enum ParamDataType {
INTEGER,
UNSIGNED_INTEGER,
REAL,
UTF8_STRING,
OCTET_STRING,
UTF8_PTR,
OCTET_PTR,
}
[CCode (cheader_filename = "openssl/core.h", cname = "size_t", cprefix = "OSSL_PARAM_", has_type_id = false)]
public enum ParamReturnSize {
UNMODIFIED,
}
[CCode (cheader_filename = "openssl/objects.h", lower_case_cprefix = "SN_")]
namespace ShortName {
public const string sha256;
public const string sha384;
public const string sha512;
public const string siphash;
public const string chacha20_poly1305;
}
[CCode (cheader_filename = "openssl/rand.h")]
namespace Rng {
[CCode (cname = "RAND_bytes")]
public int generate (uint8[] buf);
}
[Compact]
[CCode (cname = "BN_CTX", cprefix = "BN_CTX_")]
public class BigNumberContext {
[CCode (cname = "BN_CTX_secure_new")]
public BigNumberContext.secure ();
}
[Compact]
[CCode (cname = "BIGNUM", cprefix = "BN_")]
public class BigNumber {
public BigNumber ();
[CCode (cname = "BN_native2bn")]
public BigNumber.from_native (uint8[] data, BigNumber * ret = null);
[CCode (cname = "BN_bin2bn")]
public BigNumber.from_big_endian (uint8[] data, BigNumber * ret = null);
public static BigNumber get_rfc2409_prime_768 (BigNumber * ret = null);
public static BigNumber get_rfc2409_prime_1024 (BigNumber * ret = null);
public static BigNumber get_rfc3526_prime_1536 (BigNumber * ret = null);
public static BigNumber get_rfc3526_prime_2048 (BigNumber * ret = null);
public static BigNumber get_rfc3526_prime_3072 (BigNumber * ret = null);
public static BigNumber get_rfc3526_prime_4096 (BigNumber * ret = null);
public static BigNumber get_rfc3526_prime_6144 (BigNumber * ret = null);
public static BigNumber get_rfc3526_prime_8192 (BigNumber * ret = null);
public bool is_zero ();
public static int add (BigNumber r, BigNumber a, BigNumber b);
public static int sub (BigNumber r, BigNumber a, BigNumber b);
public static int mul (BigNumber r, BigNumber a, BigNumber b, BigNumberContext ctx);
public static int mod (BigNumber rem, BigNumber m, BigNumber d, BigNumberContext ctx);
public static int mod_exp (BigNumber r, BigNumber a, BigNumber p, BigNumber m, BigNumberContext ctx);
public int num_bits ();
public int num_bytes ();
[CCode (cname = "BN_bn2bin")]
public int to_big_endian ([CCode (array_length = false)] uint8[] to);
[CCode (cname = "BN_bn2binpad")]
public int to_big_endian_padded (uint8[] to);
[CCode (cname = "BN_bn2dec")]
public char * to_string ();
[CCode (cname = "BN_bn2hex")]
public char * to_hex_string ();
}
[CCode (cheader_filename = "openssl/crypto.h", lower_case_cprefix = "CRYPTO_")]
namespace Crypto {
public int memcmp (void * a, void * b, size_t len);
}
[CCode (lower_case_cprefix = "ERR_")]
namespace Error {
public ulong get_error ();
public void error_string_n (ulong e, char[] buf);
}
public void free (void * addr);
}
+96
View File
@@ -0,0 +1,96 @@
[CCode (cheader_filename = "windns.h", gir_namespace = "Windows", gir_version = "1.0")]
namespace WinDns {
[CCode (cname = "DNS_QUERY_RESULT")]
public struct QueryResult {
[CCode (cname = "Version")]
public ulong version;
[CCode (cname = "QueryStatus")]
public long query_status;
[CCode (cname = "QueryOptions")]
public uint64 query_options;
[CCode (cname = "pQueryRecords")]
public Record * query_records;
[CCode (cname = "Reserved")]
public void * reserved;
}
[CCode (cname = "DNS_RECORDW")]
public struct Record {
[CCode (cname = "pNext")]
public Record * next;
[CCode (cname = "pName")]
public unowned string16 name;
[CCode (cname = "wType")]
public RecordType type;
[CCode (cname = "wDataLength")]
public uint16 data_length;
[CCode (cname = "Flags.DW")]
public uint32 flags;
[CCode (cname = "dwTtl")]
public uint32 ttl;
[CCode (cname = "dwReserved")]
public uint32 reserved;
[CCode (cname = "Data.A")]
public AData a;
[CCode (cname = "Data.PTR")]
public PtrData ptr;
[CCode (cname = "Data.TXT")]
public TxtData txt;
[CCode (cname = "Data.AAAA")]
public AaaaData aaaa;
[CCode (cname = "Data.SRV")]
public SrvData srv;
}
[CCode (cname = "WORD", cprefix = "DNS_TYPE_", has_type_id = false)]
public enum RecordType {
A,
PTR,
TEXT,
AAAA,
SRV,
}
[CCode (cname = "DNS_A_DATA")]
public struct AData {
[CCode (cname = "IpAddress")]
public uint32 ip;
}
[CCode (cname = "DNS_PTR_DATAW")]
public struct PtrData {
[CCode (cname = "pNameHost")]
public unowned string16 name;
}
[CCode (cname = "DNS_TXT_DATAW")]
public struct TxtData {
[CCode (cname = "pStringArray", array_length_cname = "dwStringCount")]
public unowned string16[] strings;
}
[CCode (cname = "DNS_AAAA_DATA")]
public struct AaaaData {
[CCode (cname = "Ip6Address")]
public IP6Address ip;
}
[CCode (cname = "DNS_SRV_DATAW")]
public struct SrvData {
[CCode (cname = "pNameTarget")]
public unowned string16 name_target;
[CCode (cname = "wPriority")]
public uint16 priority;
[CCode (cname = "wWeight")]
public uint16 weight;
[CCode (cname = "wPort")]
public uint16 port;
}
[CCode (cname = "IP6_ADDRESS")]
public struct IP6Address {
[CCode (cname = "IP6Byte")]
public uint8 data[16];
}
}