Compare commits

...
110 Commits
Author SHA1 Message Date
Ole André Vadla Ravnås 4e3b670677 subprojects: Prepare for release 2025-08-12 10:15:42 +02:00
Ole André Vadla Ravnås 393637ced2 subprojects: Bump outdated 2025-08-12 09:48:31 +02:00
Ole André Vadla Ravnås 7457b7d355 subprojects: Prepare for release 2025-08-02 09:42:45 +02:00
Ole André Vadla Ravnås 1d80fc635e subprojects: Bump outdated 2025-08-02 08:53:27 +02:00
Abc Xyz 02a6884000 freebsd: Add support for x86 (32-bit) (#1188) 2025-08-02 08:52:39 +02:00
Cheng Yang 820b9f0284 platform: Add support for visionOS 2025-08-02 08:41:15 +02:00
Ole André Vadla Ravnås 5364736d8c subprojects: Bump outdated 2025-08-01 20:21:02 +02:00
Ole André Vadla Ravnås 9134ee1562 submodules: Bump releng 2025-08-01 20:21:01 +02:00
Ole André Vadla Ravnås 85e99cfbd1 gadget: Fix compilation on tvOS and watchOS 2025-08-01 18:17:40 +02:00
Ole André Vadla Ravnås bd1cbc2813 gadget: Fix compilation on non-arm64 Darwin 2025-08-01 18:17:22 +02:00
Ole André Vadla Ravnås a9b4bc7abd subprojects: Bump outdated 2025-08-01 15:48:35 +02:00
Ole André Vadla Ravnås f00ed7357f submodules: Bump releng 2025-08-01 15:48:34 +02:00
Ole André Vadla Ravnås e117570aca android: Bump frida-java-bridge in system-server
To pick up the improved ART offset lookup fix by @AeonLucid.

See frida/frida-java-bridge#366 for details.
2025-08-01 15:29:01 +02:00
Ole André Vadla Ravnås d7bdd776c3 gadget: Fix compilation on non-Darwin 2025-08-01 10:09:13 +02:00
03d861ca80 fruity: Support iOS 26 through dual-mapping
Where we implement the breakpoint protocol expected by Gum's latest
Darwin backend on systems with debugger mappings.

Co-authored-by: Alex Soler <[email protected]>
Co-authored-by: Håvard Sørbø <[email protected]>
Co-authored-by: Ole André Vadla Ravnås <[email protected]>
2025-07-31 20:50:07 +02:00
Francesco Tamagni c047e64c00 fruity: Support injection on palera1n 2025-07-31 19:43:37 +02:00
Ole André Vadla Ravnås 5192ac381f buffer: Fix BufferReader.read_pointer()
No offset should be passed to it.
2025-07-31 19:42:40 +02:00
Ole André Vadla Ravnås 9450f3fa31 barebone: Handle MMU being disabled
We should refine this further, so we re-query the page size later.
2025-07-29 00:29:41 +02:00
Ole André Vadla Ravnås b7157aa45c barebone: Add support for the uint type
In the NativeFunction and NativeCallback APIs.
2025-07-29 00:29:35 +02:00
Ole André Vadla Ravnås d9dfde5748 subprojects: Prepare for release 2025-07-24 11:16:39 +02:00
Ole André Vadla Ravnås 6fdb9b3834 subprojects: Bump outdated 2025-07-24 11:15:07 +02:00
Ole André Vadla Ravnås 92aae264f0 cloak: Plug leak in ThreadCountCloaker.dispose()
Where we were failing to chain up to GObject.dispose().
2025-07-24 11:13:12 +02:00
AeonLucid 5b850e49b2 cloak: Support Art::GetOsThreadStat on Android
The issue is similar to #500, where Zygote is waiting for the process to
become single-threaded before continuing, otherwise it crashes.

For a while this has been changed to use art::GetOsThreadStat, so the
old fix no longer works.
2025-07-24 11:13:12 +02:00
Ole André Vadla Ravnås a6e60f4de6 barebone: Bump @types/frida-gum to 19.0.1 2025-07-24 10:47:16 +02:00
Ole André Vadla Ravnås aac44b8748 compiler: Bump @types/frida-gum to 19.0.1 2025-07-24 10:45:34 +02:00
Ole André Vadla Ravnås f052966d2b android: Bump frida-java-bridge in system-server
To pick up the improved ART offset lookup fix by @AeonLucid.

See frida/frida-java-bridge#362 for details.
2025-07-24 10:37:37 +02:00
Ole André Vadla Ravnås af5c6744ab subprojects: Prepare for release 2025-07-21 15:06:16 +02:00
Ole André Vadla Ravnås 11c3c4cbc0 subprojects: Bump outdated 2025-07-21 15:04:37 +02:00
Ole André Vadla Ravnås ddf42a869a android: Bump frida-java-bridge in system-server
Pick up ART offset lookup fix by @AeonLucid.

See frida/frida-java-bridge#361 for details.
2025-07-21 14:51:52 +02:00
Ole André Vadla Ravnås de4ea7e25a subprojects: Prepare for release 2025-07-18 10:32:18 +02:00
Ole André Vadla Ravnås 9032c83b1e subprojects: Bump outdated 2025-07-18 10:28:26 +02:00
Ole André Vadla Ravnås 6ea09653c4 submodules: Bump releng 2025-07-18 10:28:25 +02:00
Ole André Vadla Ravnås 681c6f0011 android: Bump frida-java-bridge in system-server
Update frida-java-bridge to include fix for incorrect ART
class spec offset detection. This prevents crashes caused by
libart.so being updated independently of the SDK version,
which previously led to offset mismatches.

The fix uses runtime detection via known classes instead of
SDK heuristics, improving reliability across Android updates.
2025-07-18 10:25:19 +02:00
Ole André Vadla Ravnås 5175be48be buffer: Expose BufferReader.offset 2025-07-16 08:28:10 +02:00
Ole André Vadla Ravnås 96ec48e5db barebone: Clear PXN on tables in protect_pages() 2025-07-12 11:02:04 +02:00
Ole André Vadla Ravnås 950e75556c barebone: Improve portability of uint64 constants 2025-07-12 11:01:57 +02:00
Ole André Vadla Ravnås 774b81fe15 buffer: Add helper for constructing large Bytes
This works around a Vala limitation where array lengths are represented
using 32-bit signed integers, which restricts the size of arrays that
can be passed to GLib.Bytes.
2025-07-08 19:57:54 +02:00
Ole André Vadla Ravnås c9d2899f9a buffer: Add Buffer.write_bytes() 2025-07-08 14:22:16 +02:00
Ole André Vadla Ravnås 82a02e112a buffer: Add Buffer.read_bytes() 2025-07-08 14:22:11 +02:00
Ole André Vadla Ravnås 001873a0e9 buffer: Add Buffer.write_int64() 2025-07-08 14:22:05 +02:00
Ole André Vadla Ravnås a56f94305c buffer: Add Buffer.write_uint16() 2025-07-08 14:21:59 +02:00
Ole André Vadla Ravnås 4f6614fe9c buffer: Add Buffer.write_int16() 2025-07-08 14:21:54 +02:00
Ole André Vadla Ravnås f62261b807 buffer: Add Buffer.write_uint8() 2025-07-08 14:21:48 +02:00
Ole André Vadla Ravnås e83804fd3e buffer: Add Buffer.write_int8() 2025-07-08 14:21:41 +02:00
Ole André Vadla Ravnås 3c5c49031c buffer: Fix a stylistic inconsistency 2025-07-08 14:21:37 +02:00
Ole André Vadla Ravnås b2debc767a meson: Add devkit_symbol_scope option
Introduce the combo option `devkit_symbol_scope` with the values
`prefixed` (default) and `original`.  It mirrors the
`--dep-symbol-scope` flag in mkdevkit.py and lets projects control
how the generated devkits treat third-party symbols at configure
time.

* `prefixed`  – add the “_frida_” prefix to avoid clashes with the
  consumer’s own copies of the same libraries (current behaviour)
* `original`  – keep upstream symbol names untouched

The default remains `prefixed`, so existing builds are unchanged.
2025-07-06 19:23:59 +02:00
Ole André Vadla Ravnås 8681999deb submodules: Bump releng 2025-07-06 19:23:09 +02:00
Håvard Sørbø 25efd44d81 barebone: Support R_AARCH64_PREL32 relocations 2025-07-06 13:28:56 +02:00
Ole André Vadla Ravnås b04f69ead9 buffer: Add Buffer.write_int32() 2025-07-06 13:28:38 +02:00
Ole André Vadla Ravnås 63c66f4630 barebone: Add target-function allocator
This introduces a new configuration file (JSON) pointed to by the
FRIDA_BAREBONE_CONFIG environment variable. The file can now describe
three allocator modes:

  * "physical"         – allocate from a fixed physical base
  * "target-functions" – call alloc/free functions on the target
  * "none"             – no allocator configured

Example (target-functions):

    {
      "allocator": {
        "mode": "target-functions",
        "alloc_function": "0xfffffff007a3c278",
        "free_function":  "0xfffffff007a3c338"
      }
    }

BREAKING: The following environment variables are removed. Use the
equivalent JSON instead.

  * FRIDA_BAREBONE_ADDRESS   → "connection.host" / "connection.port"
  * FRIDA_BAREBONE_HEAP_BASE → "allocator.mode": "physical"

Both connection and allocator sections are optional; defaults are
unchanged.
2025-07-06 13:11:55 +02:00
Ole André Vadla Ravnås fec7b84263 barebone: Drop landing_zone from Machine.invoke()
No need for it as we can simply use PC.
2025-07-06 13:11:44 +02:00
Ole André Vadla Ravnås 5bcf41ef07 gadget: Remove redundant Json.Serializable methods
These methods are no longer needed, as json-glib-1.0.vapi now correctly
marks them as non-abstract.
2025-07-06 13:11:11 +02:00
Ole André Vadla Ravnås a7b95c4d89 gadget: Fix config casts
They should not be dynamic casts, since we know the type.
2025-07-06 13:05:16 +02:00
Ole André Vadla Ravnås faf4b24f2b barebone: Implement CModule
Only supporting construction from an ELF blob, for now.
2025-07-03 20:57:27 +02:00
Ole André Vadla Ravnås dbadfb617c rust-module: Split out ELF and console logic 2025-07-03 20:57:27 +02:00
Ole André Vadla RavnåsandHåvard Sørbø a22a3ea7d1 barebone: Implement Memory.protect()
Only supported on arm64 for now.

Co-authored-by: Håvard Sørbø <[email protected]>
2025-07-03 20:57:27 +02:00
Ole André Vadla RavnåsandHåvard Sørbø a5a934c05f barebone: Add support for void and size_t types
In the NativeFunction and NativeCallback APIs.

Co-authored-by: Håvard Sørbø <[email protected]>
2025-07-03 20:57:27 +02:00
Ole André Vadla RavnåsandHåvard Sørbø e7fe9d7c16 barebone: Add Arm64Machine.execute()
Useful for experimentation.

Co-authored-by: Håvard Sørbø <[email protected]>
2025-07-03 20:57:27 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 42869f7fb1 rust-module: Explicitly make ELF executable
Needed on SPRR targets, where allocations are `rw-` by default.

We should improve this so we only apply it to executable segments.

Co-authored-by: Håvard Sørbø <[email protected]>
2025-07-03 20:57:27 +02:00
Ole André Vadla RavnåsandHåvard Sørbø ef2638f57d barebone: Add support for SPRR
Co-authored-by: Håvard Sørbø <[email protected]>
2025-07-03 20:57:27 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 619865e19a barebone: Avoid inserting into PXN tables on arm64
As we won't be able to make such allocations executable.

Co-authored-by: Håvard Sørbø <[email protected]>
2025-07-03 20:57:27 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 660782101c gdb: Fix read_register() for CPSR
The response may not be pointer-sized.

Co-authored-by: Håvard Sørbø <[email protected]>
2025-07-03 19:27:02 +02:00
683dcf59cd fruity: Spray Gadget's r-x pages before uploading
To turn them into debugger mappings. This is only needed on newer
hardware generations, and only on iOS >= 26, but for now we do it
on all of them.

Co-authored-by: Francesco Tamagni <[email protected]>
Co-authored-by: Håvard Sørbø <[email protected]>
Co-authored-by: Murphy <[email protected]>
2025-07-03 19:08:32 +02:00
7ed356fe63 gdb: Add spray_pages()
For efficiently tainting a range of pages before first-time use.

Useful on e.g. iOS targets where debugger mappings are enforced.

Co-authored-by: Francesco Tamagni <[email protected]>
Co-authored-by: Håvard Sørbø <[email protected]>
Co-authored-by: Murphy <[email protected]>
2025-07-03 19:02:39 +02:00
Ole André Vadla Ravnås 27e2d4b96e control-service: Fix build w/o the local backend 2025-07-03 18:59:48 +02:00
Ole André Vadla Ravnås d05515c6f1 subprojects: Prepare for release 2025-07-03 16:10:12 +02:00
Ole André Vadla Ravnås 97742e01f5 subprojects: Bump outdated 2025-07-03 16:09:14 +02:00
Francesco Tamagni f354fcafe4 fruity: Get away with killing prewarmed target
Killing a prewarmed process at spawn time results in a "connection
closed" error. This change catches it so it's possible to go on and
spawn a fresh instance.
2025-07-03 14:59:16 +02:00
Ole André Vadla Ravnås dca42cfa11 subprojects: Prepare for release 2025-07-03 12:56:59 +02:00
Ole André Vadla Ravnås aecfdb92a3 subprojects: Bump outdated 2025-07-03 12:55:43 +02:00
Ole André Vadla Ravnås 4f5badfeff rust-module: Ensure C ABI entrypoints survive GC
Newer Rust toolchains use --gc-sections, stripping unused sections.
Refactor make_linker_script() to scan the Rust source for symbols
intended to be visible, and emit KEEP(*(.text.<symbol>)) directives
so those entrypoints are retained.
2025-07-03 02:19:21 +02:00
Ole André Vadla Ravnås b2e64a69c1 subprojects: Prepare for release 2025-07-02 12:59:06 +02:00
Ole André Vadla Ravnås 147b1c1e73 subprojects: Bump outdated 2025-07-02 12:56:11 +02:00
Francesco Tamagni e9d4e56b9c gadget: Avoid Interceptor during config detection
By iterating modules on Darwin using Gum.Darwin.ModuleResolver instead
of relying on the module registry which attempts to use Interceptor
before the configuration had a chance to specify the `code_signing`
policy.
2025-07-02 12:54:35 +02:00
Francesco Tamagni 1e4f398fb2 fruity: Inject on enforced debugger mapping
Add support for injecting the gadget on iOS targets where debugger
mappings are enforced and we can't flip the memory protection back to
executable from inside the target process.

In that case, the Gadget configuration will have `code_signing` set to
`required` for now, until Interceptor is ready for enforced debugger
mappings too.
2025-07-02 12:54:35 +02:00
Ole André Vadla Ravnås 4dcce299d0 subprojects: Prepare for release 2025-07-02 00:09:13 +02:00
Ole André Vadla Ravnås 474199c1e7 subprojects: Bump outdated 2025-07-02 00:08:31 +02:00
Ole André Vadla Ravnås 6ff8d931e0 package-manager: Fix broken #if on Windows 2025-07-02 00:07:44 +02:00
Ole André Vadla Ravnås 4b25d3b987 subprojects: Prepare for release 2025-07-01 23:40:01 +02:00
Ole André Vadla Ravnås 0f98678051 subprojects: Bump outdated 2025-07-01 23:38:55 +02:00
Henrik Grimler 52948f6c4f meson: Clarify Vala build system gotcha (#1182)
The Vala README only mentions autotools instructions, and when Vala is
compiled that way the -frida suffix is not added to the version string,
and the frida-core check for Vala fails.

Therefore, clarify that Vala needs to be built from source with Meson.
2025-07-01 21:33:05 +02:00
Ole André Vadla Ravnås ae7a3725d3 meson: Add missing libc Vala defines
Needed by the latest PackageManager.
2025-07-01 21:15:39 +02:00
Ole André Vadla Ravnås 62234b16ae package-manager: Refactor the installation logic 2025-07-01 21:07:35 +02:00
Ole André Vadla Ravnås 1000cba56b package-manager: Fix the has_install_script logic
Should also take `preinstall` and `postinstall` into account.
2025-07-01 21:07:35 +02:00
Ole André Vadla Ravnås 40004affdb package-manager: Improve optional package handling 2025-07-01 21:07:35 +02:00
Ole André Vadla Ravnås a836182ac9 package-manager: Add install() option for role
To achieve the equivalent of npm install's --save-* switches.
2025-07-01 21:07:35 +02:00
Ole André Vadla Ravnås 600d2bf948 package-manager: Add install() option for omits
To achieve the equivalent of npm install's --omit=x switch.
2025-07-01 21:07:35 +02:00
Ole André Vadla Ravnås 466705f0da package-manager: Handle file mode when extracting
On non-Windows systems.
2025-07-01 21:07:35 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 18ad19554a package-manager: Improve resolution and hoisting
To mimic npm's behavior more closely.

Co-authored-by: Håvard Sørbø <[email protected]>
2025-07-01 21:07:35 +02:00
Ole André Vadla Ravnås 58c8062f93 subprojects: Prepare for release 2025-06-27 15:59:50 +02:00
Kyle Bouchard a6be95d8ae agent: Disable Exceptor for the emulated realm
Exceptor needs to hook signal() and sigaction(), but they are in libc,
leading to gum_mprotect() aborting because it cannot change libc's
'r--' mapping.

I tested it on AVDs with Android 14 and 15 and it prevents the crash
observed in the upstream version when using frida-server or
frida-inject.
2025-06-27 15:58:12 +02:00
Ole André Vadla Ravnås db258f0d35 subprojects: Bump outdated 2025-06-27 15:50:28 +02:00
Francesco Tamagni bea95d0045 buffer: Fix max_length in read_fixed_string
So it is constrained both within the requested size and the buffer's
size.
2025-06-26 12:25:01 +02:00
Ole André Vadla Ravnås 57d2a83548 subprojects: Prepare for release 2025-06-23 18:44:25 +02:00
Ole André Vadla Ravnås 4474490f9b subprojects: Bump outdated 2025-06-23 18:41:09 +02:00
Ole André Vadla Ravnås a9ba854aa7 package-manager: Fix the dev logic 2025-06-22 10:22:42 +02:00
Ole André Vadla Ravnås 47c265b3df package-manager: Only bump if explicitly requested 2025-06-20 21:37:31 +02:00
Ole André Vadla Ravnås 36200d4c17 subprojects: Prepare for release 2025-06-20 15:45:32 +02:00
Ole André Vadla Ravnås bd1f855f4a subprojects: Bump outdated 2025-06-20 15:44:10 +02:00
Ole André Vadla RavnåsandHåvard Sørbø d752b63d3f package-manager: Improve manifest handling
To get us closer to npm's behavior.

Co-authored-by: Håvard Sørbø <[email protected]>
2025-06-20 15:43:29 +02:00
Ole André Vadla Ravnås a66e35d457 package-manager: Improve progress reporting 2025-06-20 11:46:30 +02:00
Ole André Vadla Ravnås 931270de32 package-manager: Refactor a little bit 2025-06-20 11:45:50 +02:00
Ole André Vadla Ravnås 90d54afbf4 promise: Add Future.then() and Future.get_result() 2025-06-20 10:58:00 +02:00
Ole André Vadla Ravnås 0a75b51e7b package-manager: Fix dependency install deadlock
A deadlock could occur when a package's sub-dependency was also a
dependency of another package higher up in the installation stack.
The sub-dependency would wait for the higher-level package to be
physically installed, but that package would not complete its own
installation until its sub-dependencies were resolved, creating a
circular wait.

Refactor the installation logic to first perform the physical
installation of a package. Once the package is on disk, a promise
tracking its physical presence is resolved. Only then does the process
recurse to install the package's own dependencies. This ensures that
any other part of the installation process waiting for this specific
package can proceed, breaking the cycle.
2025-06-20 10:17:38 +02:00
Ole André Vadla Ravnås 20d5d121b7 subprojects: Prepare for release 2025-06-20 01:13:54 +02:00
Ole André Vadla Ravnås dc71534220 subprojects: Bump outdated 2025-06-20 01:12:26 +02:00
Ole André Vadla Ravnås 35afee9b4a package-manager: Handle tarballs with root entries
Like if there's a directory entry for "package/", or somehow any files
at the root level.
2025-06-20 01:11:39 +02:00
Ole André Vadla Ravnås 7b130e6eba package-manager: Fix handling of scoped specs 2025-06-20 01:11:39 +02:00
Ole André Vadla Ravnås d28c46c332 package-manager: Fix a stylistic inconsistency 2025-06-20 01:11:39 +02:00
Ole André Vadla Ravnås ab103a73ca package-manager: Simplify substring logic 2025-06-20 01:11:39 +02:00
58 changed files with 4367 additions and 1445 deletions

No files matched your search

+5 -5
View File
@@ -1400,12 +1400,12 @@ namespace Frida.Agent {
if (nb_api.unload_library == null)
parameters.append ("|eternal|sticky");
/*
* Disable ExitMonitor to work around a bug in Android's libndk_translation.so on Android 11.
* We need to avoid modifying libc.so ranges that the translator potentially depends on, to
* avoid blowing up when Interceptor's CPU cache flush results in the translated code being
* discarded, which seems like an edge-case the translator doesn't handle.
* Disable Exceptor and ExitMonitor to work around a bug in Android's libndk_translation.so
* on Android 11. We need to avoid modifying libc.so ranges that the translator potentially
* depends on, to avoid blowing up when Interceptor's CPU cache flush results in the translated
* code being discarded, which seems like an edge-case the translator doesn't handle.
*/
parameters.append ("|exit-monitor:off");
parameters.append ("|exceptor:off|exit-monitor:off");
emulated_bridge_state = new BridgeState (parameters.str);
+12
View File
@@ -0,0 +1,12 @@
#include "frida-base.h"
GBytes *
frida_make_bytes_with_owner (GType t_type,
GBoxedCopyFunc t_dup_func,
GDestroyNotify t_destroy_func,
void * data,
gsize size,
gpointer owner)
{
return g_bytes_new_with_free_func (data, size, t_destroy_func, owner);
}
+95 -33
View File
@@ -356,10 +356,20 @@ namespace Frida {
return *((int8 *) get_pointer (offset, sizeof (int8)));
}
public unowned Buffer write_int8 (size_t offset, int8 val) {
*((int8 *) get_pointer (offset, sizeof (int8))) = val;
return this;
}
public uint8 read_uint8 (size_t offset) {
return *get_pointer (offset, sizeof (uint8));
}
public unowned Buffer write_uint8 (size_t offset, uint8 val) {
*((uint8 *) get_pointer (offset, sizeof (uint8))) = val;
return this;
}
public int16 read_int16 (size_t offset) {
int16 val = *((int16 *) get_pointer (offset, sizeof (int16)));
return (byte_order == BIG_ENDIAN)
@@ -367,6 +377,14 @@ namespace Frida {
: int16.from_little_endian (val);
}
public unowned Buffer write_int16 (size_t offset, int16 val) {
int16 target_val = (byte_order == BIG_ENDIAN)
? val.to_big_endian ()
: val.to_little_endian ();
*((int16 *) get_pointer (offset, sizeof (int16))) = target_val;
return this;
}
public uint16 read_uint16 (size_t offset) {
uint16 val = *((uint16 *) get_pointer (offset, sizeof (uint16)));
return (byte_order == BIG_ENDIAN)
@@ -374,6 +392,14 @@ namespace Frida {
: uint16.from_little_endian (val);
}
public unowned Buffer write_uint16 (size_t offset, uint16 val) {
uint16 target_val = (byte_order == BIG_ENDIAN)
? val.to_big_endian ()
: val.to_little_endian ();
*((uint16 *) get_pointer (offset, sizeof (uint16))) = target_val;
return this;
}
public int32 read_int32 (size_t offset) {
int32 val = *((int32 *) get_pointer (offset, sizeof (int32)));
return (byte_order == BIG_ENDIAN)
@@ -381,6 +407,14 @@ namespace Frida {
: int32.from_little_endian (val);
}
public unowned Buffer write_int32 (size_t offset, int32 val) {
int32 target_val = (byte_order == BIG_ENDIAN)
? val.to_big_endian ()
: val.to_little_endian ();
*((int32 *) get_pointer (offset, sizeof (int32))) = target_val;
return this;
}
public uint32 read_uint32 (size_t offset) {
uint32 val = *((uint32 *) get_pointer (offset, sizeof (uint32)));
return (byte_order == BIG_ENDIAN)
@@ -403,6 +437,14 @@ namespace Frida {
: int64.from_little_endian (val);
}
public unowned Buffer write_int64 (size_t offset, int64 val) {
int64 target_val = (byte_order == BIG_ENDIAN)
? val.to_big_endian ()
: val.to_little_endian ();
*((int64 *) get_pointer (offset, sizeof (int64))) = target_val;
return this;
}
public uint64 read_uint64 (size_t offset) {
uint64 val = *((uint64 *) get_pointer (offset, sizeof (uint64)));
return (byte_order == BIG_ENDIAN)
@@ -446,7 +488,7 @@ namespace Frida {
public string read_fixed_string (size_t offset, size_t size) throws Error {
string * start = (string *) get_pointer (offset, size);
size_t max_length = size - offset;
size_t max_length = size_t.min (size, this.size - offset);
string * end = memchr (start, 0, max_length);
size_t n;
if (end != null)
@@ -465,6 +507,18 @@ namespace Frida {
return this;
}
public Bytes read_bytes (size_t offset, size_t size) {
var data = new uint8[size + 1];
Memory.copy (data, get_pointer (offset, size), size);
return new Bytes.take ((owned) data);
}
public unowned Buffer write_bytes (size_t offset, Bytes bytes) {
size_t size = bytes.get_size ();
Memory.copy (get_pointer (offset, size), bytes.get_data (), size);
return this;
}
private uint8 * get_pointer (size_t offset, size_t n) {
size_t minimum_size = offset + n;
assert (size >= minimum_size);
@@ -474,121 +528,127 @@ namespace Frida {
}
public sealed class BufferReader {
public size_t offset {
get {
return _offset;
}
}
public size_t available {
get {
return buffer.bytes.get_size () - offset;
return buffer.bytes.get_size () - _offset;
}
}
private Buffer buffer;
private size_t offset = 0;
private size_t _offset = 0;
public BufferReader (Buffer buf) {
buffer = buf;
}
public uint64 read_pointer (size_t offset) throws Error {
public uint64 read_pointer () throws Error {
var pointer_size = buffer.pointer_size;
check_available (pointer_size);
var ptr = buffer.read_pointer (offset);
offset += 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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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;
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;
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;
var val = buffer.bytes[_offset:_offset + size];
_offset += size;
return val;
}
public unowned BufferReader skip (size_t n) throws Error {
check_available (n);
offset += n;
_offset += n;
return this;
}
@@ -597,4 +657,6 @@ namespace Frida {
throw new Error.PROTOCOL ("Malformed buffer: truncated");
}
}
public extern Bytes make_bytes_with_owner<T> (void * data, size_t size, owned T? owner = null);
}
+1
View File
@@ -13,6 +13,7 @@ base_sources = [
'socket.vala',
'socket-glue.c',
'buffer.vala',
'buffer-glue.c',
'value.vala',
]
+52 -12
View File
@@ -46,7 +46,8 @@ namespace Frida {
}
private GLib.Error? _error;
private Gee.ArrayQueue<CompletionFuncEntry> on_complete;
private Gee.ArrayQueue<CompletionFuncEntry>? on_complete;
private Gee.ArrayQueue<ThenHandlerEntry<T>>? on_then;
public async T wait_async (Cancellable? cancellable) throws Frida.Error, IOError {
if (_ready)
@@ -74,7 +75,21 @@ namespace Frida {
return get_result ();
}
private T get_result () throws Frida.Error, IOError {
public void then (owned FutureCompletionHandler<T> handler) {
if (_ready) {
schedule (() => {
handler (this);
return Source.REMOVE;
});
return;
}
if (on_then == null)
on_then = new Gee.ArrayQueue<ThenHandlerEntry<T>> ();
on_then.offer (new ThenHandlerEntry<T> ((owned) handler));
}
public T get_result () throws Frida.Error, IOError {
if (error != null) {
if (error is Frida.Error)
throw (Frida.Error) error;
@@ -111,19 +126,32 @@ namespace Frida {
internal void transition_to_ready () {
_ready = true;
if (on_complete != null && !on_complete.is_empty) {
var source = new IdleSource ();
source.set_priority (Priority.HIGH);
source.set_callback (() => {
CompletionFuncEntry? entry;
while ((entry = on_complete.poll ()) != null)
entry.func ();
on_complete = null;
return false;
if (on_complete != null || on_then != null) {
schedule (() => {
if (on_complete != null) {
CompletionFuncEntry? entry;
while ((entry = on_complete.poll ()) != null)
entry.func ();
on_complete = null;
}
if (on_then != null) {
ThenHandlerEntry? entry;
while ((entry = on_then.poll ()) != null)
entry.handler (this);
on_then = null;
}
return Source.REMOVE;
});
source.attach (MainContext.get_thread_default ());
}
}
private static void schedule (owned SourceFunc function) {
var source = new IdleSource ();
source.set_callback ((owned) function);
source.attach (MainContext.get_thread_default ());
}
}
private class CompletionFuncEntry {
@@ -133,6 +161,14 @@ namespace Frida {
this.func = (owned) func;
}
}
private class ThenHandlerEntry<T> {
public FutureCompletionHandler<T> handler;
public ThenHandlerEntry (owned FutureCompletionHandler<T> handler) {
this.handler = (owned) handler;
}
}
}
public interface Future<T> : Object {
@@ -140,5 +176,9 @@ namespace Frida {
public abstract T? value { get; }
public abstract GLib.Error? error { get; }
public abstract async T wait_async (Cancellable? cancellable) throws Frida.Error, IOError;
public abstract void then (owned FutureCompletionHandler<T> handler);
public abstract T get_result () throws Frida.Error, IOError;
}
public delegate void FutureCompletionHandler<T> (Future<T> future);
}
+1 -1
View File
@@ -30,7 +30,7 @@ _frida_query_windows_computer_name (void)
return g_utf16_to_utf8 (buffer, -1, NULL, NULL, NULL);
}
#elif defined (HAVE_IOS) || defined (HAVE_TVOS)
#elif defined (HAVE_IOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
#include <CoreFoundation/CoreFoundation.h>
#include <dlfcn.h>
+16
View File
@@ -749,6 +749,19 @@ namespace Frida {
}
}
[DBus (name = "re.frida.GadgetSession17")]
public interface GadgetSession : Object {
public abstract async void break_and_resume (Cancellable? cancellable) throws GLib.Error;
public abstract async void break_and_detach (Cancellable? cancellable) throws GLib.Error;
}
public enum GadgetBreakpointAction {
INVOKE_RETURN,
RESUME,
DETACH,
PAGE_PLAN,
}
[DBus (name = "re.frida.Channel17")]
public interface Channel : Object {
public abstract async void close (Cancellable? cancellable) throws GLib.Error;
@@ -1952,6 +1965,8 @@ namespace Frida {
id = "watchos";
#elif TVOS
id = "tvos";
#elif XROS
id = "xros";
#elif ANDROID
id = "android";
#elif FREEBSD
@@ -2119,6 +2134,7 @@ namespace Frida {
public const string AGENT_SESSION = "/re/frida/AgentSession";
public const string AGENT_CONTROLLER = "/re/frida/AgentController";
public const string AGENT_MESSAGE_SINK = "/re/frida/AgentMessageSink";
public const string GADGET_SESSION = "/re/frida/GadgetSession";
public const string CHANNEL = "/re/frida/Channel";
public const string SERVICE = "/re/frida/Service";
public const string TRANSPORT_BROKER = "/re/frida/TransportBroker";
+166 -1
View File
@@ -1,9 +1,25 @@
#if defined (HAVE_TVOS) || defined (HAVE_WATCHOS)
# include <Availability.h>
# undef __TVOS_PROHIBITED
# define __TVOS_PROHIBITED
# undef __WATCHOS_PROHIBITED
# define __WATCHOS_PROHIBITED
#endif
#include "frida-gadget.h"
#include "frida-base.h"
#import <Foundation/Foundation.h>
#include <gum/gumdarwin.h>
#include <mach-o/loader.h>
#include <objc/runtime.h>
#include <pthread.h>
static void frida_on_breakpoints_steal_attempt (GumInvocationContext * ic, gpointer user_data);
static GumInvocationListener * frida_dont_steal_my_breakpoints;
gchar *
frida_gadget_environment_detect_bundle_id (void)
{
@@ -27,7 +43,7 @@ frida_gadget_environment_detect_bundle_name (void)
gchar *
frida_gadget_environment_detect_documents_dir (void)
{
#if defined (HAVE_IOS) || defined (HAVE_TVOS)
#if defined (HAVE_IOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
@autoreleasepool
{
NSArray<NSString *> * paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
@@ -51,3 +67,152 @@ frida_gadget_environment_set_thread_name (const gchar * name)
/* For now only implemented on i/macOS as Fruity.Injector relies on it there. */
pthread_setname_np (name);
}
void
frida_gadget_environment_detect_darwin_location_fields (GumAddress our_address, gchar ** executable_name, gchar ** our_path,
GumMemoryRange ** our_range)
{
mach_port_t task;
GumDarwinModuleResolver * resolver;
GPtrArray * modules;
guint i;
task = mach_task_self ();
resolver = gum_darwin_module_resolver_new (task, NULL);
if (resolver == NULL)
return;
gum_darwin_module_resolver_fetch_modules (resolver, &modules, NULL);
for (i = 0; i != modules->len; i++)
{
GumModule * module;
const GumMemoryRange * range;
module = g_ptr_array_index (modules, i);
range = gum_module_get_range (module);
if (*executable_name == NULL)
{
gum_mach_header_t * header = GSIZE_TO_POINTER (range->base_address);
if (header->filetype == MH_EXECUTE)
*executable_name = g_strdup (gum_module_get_name (module));
}
if (our_address >= range->base_address && our_address < range->base_address + range->size)
{
if (*our_path == NULL)
*our_path = g_strdup (gum_module_get_path (module));
if (*our_range == NULL)
*our_range = gum_memory_range_copy (range);
}
if (*executable_name != NULL && *our_path != NULL && *our_range != NULL)
break;
}
g_ptr_array_unref (modules);
g_object_unref (resolver);
}
void
frida_gadget_environment_ensure_debugger_breakpoints_only (void)
{
task_set_exception_ports (
mach_task_self (),
EXC_MASK_ALL & ~EXC_MASK_BREAKPOINT,
MACH_PORT_NULL,
EXCEPTION_DEFAULT,
THREAD_STATE_NONE
);
if (gum_process_get_code_signing_policy () == GUM_CODE_SIGNING_OPTIONAL &&
frida_dont_steal_my_breakpoints == NULL &&
gum_darwin_is_debugger_mapping_enforced ())
{
gpointer exceptions_set, exceptions_swap;
GumInterceptor * interceptor;
exceptions_set = &task_set_exception_ports;
exceptions_swap = &task_swap_exception_ports;
frida_dont_steal_my_breakpoints = gum_make_call_listener (frida_on_breakpoints_steal_attempt,
NULL, NULL, NULL);
interceptor = gum_interceptor_obtain ();
gum_interceptor_attach (interceptor, exceptions_set, frida_dont_steal_my_breakpoints,
NULL, GUM_ATTACH_FLAGS_NONE);
gum_interceptor_attach (interceptor, exceptions_swap, frida_dont_steal_my_breakpoints,
NULL, GUM_ATTACH_FLAGS_NONE);
g_object_unref (interceptor);
}
}
void
frida_gadget_environment_allow_stolen_breakpoints (void)
{
GumInterceptor * interceptor;
if (frida_dont_steal_my_breakpoints == NULL)
return;
interceptor = gum_interceptor_obtain ();
gum_interceptor_detach (interceptor, frida_dont_steal_my_breakpoints);
g_object_unref (frida_dont_steal_my_breakpoints);
frida_dont_steal_my_breakpoints = NULL;
g_object_unref (interceptor);
}
static void
frida_on_breakpoints_steal_attempt (GumInvocationContext * ic, gpointer user_data)
{
exception_mask_t exception_mask;
exception_mask = GPOINTER_TO_SIZE (gum_invocation_context_get_nth_argument (ic, 1));
exception_mask &= ~EXC_MASK_BREAKPOINT;
gum_invocation_context_replace_nth_argument (ic, 1, GSIZE_TO_POINTER (exception_mask));
}
void
frida_gadget_environment_break_and_resume (void)
{
#ifdef HAVE_ARM64
asm volatile (
"mov x1, #1337\n\t"
"mov x2, #1337\n\t"
"mov x3, %0\n\t"
"brk #1337\n\t"
:
: "r" ((gsize) FRIDA_GADGET_BREAKPOINT_ACTION_RESUME)
: "x1", "x2", "x3"
);
#else
g_assert_not_reached ();
#endif
}
void
frida_gadget_environment_break_and_detach (void)
{
#ifdef HAVE_ARM64
asm volatile (
"mov x1, #1337\n\t"
"mov x2, #1337\n\t"
"mov x3, %0\n\t"
"brk #1337\n\t"
:
: "r" ((gsize) FRIDA_GADGET_BREAKPOINT_ACTION_DETACH)
: "x1", "x2", "x3"
);
#else
g_assert_not_reached ();
#endif
}
+46 -84
View File
@@ -24,12 +24,6 @@ namespace Frida.Gadget {
default = Gum.CodeSigningPolicy.OPTIONAL;
}
private ObjectClass klass = (ObjectClass) typeof (Config).class_ref ();
public Json.Node serialize_property (string property_name, GLib.Value value, GLib.ParamSpec pspec) {
return default_serialize_property (property_name, value, pspec);
}
public bool deserialize_property (string property_name, out Value value, ParamSpec pspec, Json.Node property_node) {
if (property_name == "interaction" && property_node.get_node_type () == Json.NodeType.OBJECT) {
var interaction_node = property_node.get_object ();
@@ -77,20 +71,6 @@ namespace Frida.Gadget {
value = Value (pspec.value_type);
return false;
}
public unowned ParamSpec? find_property (string name) {
return klass.find_property (name);
}
public new Value get_property (ParamSpec pspec) {
var val = Value (pspec.value_type);
base.get_property (pspec.name, ref val);
return val;
}
public new void set_property (ParamSpec pspec, Value value) {
base.set_property (pspec.name, value);
}
}
private sealed class ScriptInteraction : Object, Json.Serializable {
@@ -112,12 +92,6 @@ namespace Frida.Gadget {
default = Script.ChangeBehavior.IGNORE;
}
private ObjectClass klass = (ObjectClass) typeof (ScriptInteraction).class_ref ();
public Json.Node serialize_property (string property_name, GLib.Value value, GLib.ParamSpec pspec) {
return default_serialize_property (property_name, value, pspec);
}
public bool deserialize_property (string property_name, out Value value, ParamSpec pspec, Json.Node property_node) {
if (property_name == "parameters" && property_node.get_node_type () == Json.NodeType.OBJECT) {
var v = Value (typeof (Json.Node));
@@ -129,20 +103,6 @@ namespace Frida.Gadget {
value = Value (pspec.value_type);
return false;
}
public unowned ParamSpec? find_property (string name) {
return klass.find_property (name);
}
public new Value get_property (ParamSpec pspec) {
var val = Value (pspec.value_type);
base.get_property (pspec.name, ref val);
return val;
}
public new void set_property (ParamSpec pspec, Value value) {
base.set_property (pspec.name, value);
}
}
private sealed class ScriptDirectoryInteraction : Object {
@@ -183,12 +143,6 @@ namespace Frida.Gadget {
default = Script.ChangeBehavior.IGNORE;
}
private ObjectClass klass = (ObjectClass) typeof (ScriptConfig).class_ref ();
public Json.Node serialize_property (string property_name, GLib.Value value, GLib.ParamSpec pspec) {
return default_serialize_property (property_name, value, pspec);
}
public bool deserialize_property (string property_name, out Value value, ParamSpec pspec, Json.Node property_node) {
if (property_name == "parameters" && property_node.get_node_type () == Json.NodeType.OBJECT) {
var v = Value (typeof (Json.Node));
@@ -200,20 +154,6 @@ namespace Frida.Gadget {
value = Value (pspec.value_type);
return false;
}
public unowned ParamSpec? find_property (string name) {
return klass.find_property (name);
}
public new Value get_property (ParamSpec pspec) {
var val = Value (pspec.value_type);
base.get_property (pspec.name, ref val);
return val;
}
public new void set_property (ParamSpec pspec, Value value) {
base.set_property (pspec.name, value);
}
}
private sealed class ProcessFilter : Object {
@@ -299,8 +239,6 @@ namespace Frida.Gadget {
default = make_empty_json_object ();
}
private ObjectClass klass = (ObjectClass) typeof (ConnectInteraction).class_ref ();
public bool deserialize_property (string property_name, out Value value, ParamSpec pspec, Json.Node property_node) {
if (property_name == "parameters" && property_node.get_node_type () == Json.NodeType.OBJECT) {
var v = Value (typeof (Json.Node));
@@ -312,20 +250,6 @@ namespace Frida.Gadget {
value = Value (pspec.value_type);
return false;
}
public unowned ParamSpec? find_property (string name) {
return klass.find_property (name);
}
public new Value get_property (ParamSpec pspec) {
var val = Value (pspec.value_type);
base.get_property (pspec.name, ref val);
return val;
}
public new void set_property (ParamSpec pspec, Value value) {
base.set_property (pspec.name, value);
}
}
private sealed class Location : Object {
@@ -481,6 +405,12 @@ namespace Frida.Gadget {
interceptor = Gum.Interceptor.obtain ();
interceptor.begin_transaction ();
#if DARWIN
if (mapped_range != null)
Environment.ensure_debugger_breakpoints_only ();
#endif
exceptor = Gum.Exceptor.obtain ();
try {
@@ -700,6 +630,11 @@ namespace Frida.Gadget {
controller = null;
exceptor = null;
#if DARWIN
Environment.allow_stolen_breakpoints ();
#endif
interceptor = null;
}
}
@@ -759,7 +694,7 @@ namespace Frida.Gadget {
}
try {
return Json.gobject_from_data (typeof (Config), config_data) as Config;
return (Config) Json.gobject_from_data (typeof (Config), config_data);
} catch (GLib.Error e) {
throw new Error.INVALID_ARGUMENT ("Invalid config: %s", e.message);
}
@@ -767,7 +702,7 @@ namespace Frida.Gadget {
private Config parse_config (string config_data) throws Error {
try {
return Json.gobject_from_data (typeof (Config), config_data) as Config;
return (Config) Json.gobject_from_data (typeof (Config), config_data);
} catch (GLib.Error e) {
throw new Error.INVALID_ARGUMENT ("Invalid config: %s", e.message);
}
@@ -775,21 +710,20 @@ namespace Frida.Gadget {
private Location detect_location (Gum.MemoryRange? mapped_range) {
string? executable_name = null;
string? executable_path = null;
Gum.MemoryRange? executable_range = null;
string? our_path = null;
Gum.MemoryRange? our_range = mapped_range;
Gum.Address our_address = Gum.Address.from_pointer (Gum.strip_code_pointer ((void *) detect_location));
#if DARWIN
Environment.detect_darwin_location_fields (our_address, ref executable_name, ref our_path, ref our_range);
#else
var index = 0;
Gum.Process.enumerate_modules ((details) => {
var range = details.range;
if (index == 0) {
executable_name = details.name;
executable_path = details.path;
executable_range = details.range;
}
if (mapped_range != null)
@@ -805,6 +739,7 @@ namespace Frida.Gadget {
return true;
});
#endif
assert (our_range != null);
@@ -1234,7 +1169,7 @@ namespace Frida.Gadget {
}
try {
return Json.gobject_from_data (typeof (ScriptConfig), data) as ScriptConfig;
return (ScriptConfig) Json.gobject_from_data (typeof (ScriptConfig), data);
} catch (GLib.Error e) {
throw new Error.INVALID_ARGUMENT ("Invalid config: %s", e.message);
}
@@ -1748,7 +1683,7 @@ namespace Frida.Gadget {
}
}
private class ControlChannel : Object, Peer, HostSession {
private class ControlChannel : Object, Peer, HostSession, GadgetSession {
public weak ControlServer parent {
get;
construct;
@@ -1779,6 +1714,9 @@ namespace Frida.Gadget {
HostSession host_session = this;
registrations.add (connection.register_object (Frida.ObjectPath.HOST_SESSION, host_session));
GadgetSession gadget_session = this;
registrations.add (connection.register_object (Frida.ObjectPath.GADGET_SESSION, gadget_session));
AuthenticationService null_auth = new NullAuthenticationService ();
registrations.add (connection.register_object (Frida.ObjectPath.AUTHENTICATION_SERVICE, null_auth));
} catch (IOError e) {
@@ -1941,6 +1879,22 @@ namespace Frida.Gadget {
throw new Error.NOT_SUPPORTED ("Unable to open services when embedded");
}
public async void break_and_resume (Cancellable? cancellable) throws Error, IOError {
#if DARWIN
Environment.break_and_resume ();
#else
throw new Error.NOT_SUPPORTED ("This API is only applicable on Darwin");
#endif
}
public async void break_and_detach (Cancellable? cancellable) throws Error, IOError {
#if DARWIN
Environment.break_and_detach ();
#else
throw new Error.NOT_SUPPORTED ("This API is only applicable on Darwin");
#endif
}
private void validate_pid (uint pid) throws Error {
if (pid != this_process.pid)
throw new Error.NOT_SUPPORTED ("Unable to act on other processes when embedded");
@@ -2176,6 +2130,14 @@ namespace Frida.Gadget {
private extern bool has_objc_class (string name);
private extern void set_thread_name (string name);
#if DARWIN
private extern void detect_darwin_location_fields (Gum.Address our_address, ref string? executable_name,
ref string? our_path, ref Gum.MemoryRange? our_range);
private extern void ensure_debugger_breakpoints_only ();
private extern void allow_stolen_breakpoints ();
private extern void break_and_resume ();
private extern void break_and_detach ();
#endif
}
private extern void log_info (string message);
+68 -33
View File
@@ -44,11 +44,17 @@ namespace Frida {
#if ANDROID
public sealed class ThreadCountCloaker : Object {
private GetOsThreadStat * get_os_thread_stat_slot;
private static GetOsThreadStat old_get_os_thread_stat_impl;
private ReadFunc * read_slot;
private static ReadFunc old_read_impl;
private static string expected_magic = "%u (".printf (Posix.getpid ());
[CCode (has_target = false)]
private delegate ssize_t GetOsThreadStat (Posix.pid_t tid, void * buf, size_t count);
[CCode (has_target = false)]
private delegate ssize_t ReadFunc (int fd, void * buf, size_t count);
@@ -56,39 +62,64 @@ namespace Frida {
var art = Gum.Process.find_module_by_name ("libart.so");
if (art != null) {
art.enumerate_imports (imp => {
if (imp.name == "read") {
if (imp.name == "_ZN3art15GetOsThreadStatEiPcm" || imp.name == "_ZN3art15GetOsThreadStatEiPcj") {
get_os_thread_stat_slot = (GetOsThreadStat *) imp.slot;
} else if (imp.name == "read") {
read_slot = (ReadFunc *) imp.slot;
return false;
}
return true;
});
if (read_slot != null)
old_read_impl = update_read_slot (on_read);
if (get_os_thread_stat_slot != null) {
old_get_os_thread_stat_impl = (GetOsThreadStat) update_slot ((void **) get_os_thread_stat_slot,
(void *) on_get_os_thread_stat);
}
if (read_slot != null) {
old_read_impl = (ReadFunc) update_slot ((void **) read_slot, (void *) on_read);
}
}
}
~ThreadCountCloaker () {
if (read_slot != null)
update_read_slot (old_read_impl);
public override void dispose () {
if (get_os_thread_stat_slot != null) {
update_slot ((void **) get_os_thread_stat_slot, (void *) old_get_os_thread_stat_impl);
}
if (read_slot != null) {
update_slot ((void **) read_slot, (void *) old_read_impl);
}
base.dispose ();
}
private ReadFunc update_read_slot (ReadFunc new_impl) {
private static void * update_slot (void ** orig, void * new_impl) {
Gum.PageProtection old_prot = READ;
Gum.Memory.query_protection (read_slot, out old_prot);
Gum.Memory.query_protection (orig, out old_prot);
bool is_writable = (old_prot & Gum.PageProtection.WRITE) != 0;
if (!is_writable)
Gum.mprotect (read_slot, sizeof (void *), old_prot | WRITE);
Gum.mprotect (orig, sizeof (void *), old_prot | WRITE);
ReadFunc old_impl = *read_slot;
*read_slot = new_impl;
void * old_impl = *orig;
*orig = new_impl;
if (!is_writable)
Gum.mprotect (read_slot, sizeof (void *), old_prot);
Gum.mprotect (orig, sizeof (void *), old_prot);
return old_impl;
}
private static ssize_t on_get_os_thread_stat (Posix.pid_t tid, void * buf, size_t count) {
ssize_t n = old_get_os_thread_stat_impl (tid, buf, count);
if (tid == Posix.getpid ()) {
try {
n = adjust_thread_count (buf, n, count);
} catch (FileError e) {
}
}
return n;
}
private static ssize_t on_read (int fd, void * buf, size_t count) {
var n = old_read_impl (fd, buf, count);
if (n <= 0)
@@ -101,32 +132,36 @@ namespace Frida {
if (!file_descriptor_is_proc_self_stat (fd))
return n;
unowned string raw_str = (string) buf;
string str = raw_str.substring (0, n);
MatchInfo info;
if (!/^(\d+ \(.+\)(?: [^ ]+){17}) \d+ (.+)/s.match (str, 0, out info))
return n;
string fields_before = info.fetch (1);
string fields_after = info.fetch (2);
// We cannot simply use the value we got from the kernel and subtract the number of cloaked threads,
// as there's a chance the total may have changed in the last moment.
uint num_uncloaked_threads = query_num_uncloaked_threads ();
string adjusted_str = "%s %u %s".printf (fields_before, num_uncloaked_threads, fields_after);
var adjusted_length = adjusted_str.length;
if (adjusted_length > count)
return n;
Memory.copy (buf, adjusted_str, adjusted_length);
n = adjusted_length;
n = adjust_thread_count (buf, n, count);
} catch (FileError e) {
}
return n;
}
private static ssize_t adjust_thread_count (void * buf, ssize_t n, size_t count) throws FileError {
unowned string raw_str = (string) buf;
string str = raw_str.substring (0, n);
MatchInfo info;
if (!/^(\d+ \(.+\)(?: [^ ]+){17}) \d+ (.+)/s.match (str, 0, out info))
return n;
string fields_before = info.fetch (1);
string fields_after = info.fetch (2);
// We cannot simply use the value we got from the kernel and subtract the number of cloaked threads,
// as there's a chance the total may have changed in the last moment.
uint num_uncloaked_threads = query_num_uncloaked_threads ();
string adjusted_str = "%s %u %s".printf (fields_before, num_uncloaked_threads, fields_after);
var adjusted_length = adjusted_str.length;
if (adjusted_length > count)
return n;
Memory.copy (buf, adjusted_str, adjusted_length);
return adjusted_length;
}
private static bool file_content_might_be_from_proc_self_stat (void * content, ssize_t size) {
if (size < expected_magic.length)
return false;
+10 -5
View File
@@ -12,9 +12,11 @@ if not meson.get_compiler('vala').version().endswith('-frida')
error('''Incompatible Vala compiler detected.
Frida currently relies on features not yet upstream. Grab the Frida-optimized
Vala compiler from:
Vala sources from:
https://github.com/frida/vala''')
https://github.com/frida/vala
and compile them with Meson.''')
endif
c_languages = ['c', 'cpp']
@@ -269,12 +271,14 @@ if host_os == 'linux'
#endif
'''
if cc.compiles(glibc_src, name: 'compiling for glibc')
cdata.set('HAVE_GLIBC', 1)
libc = 'glibc'
elif cc.compiles(uclibc_src, name: 'compiling for uClibc')
cdata.set('HAVE_UCLIBC', 1)
libc = 'uclibc'
else
cdata.set('HAVE_MUSL', 1)
libc = 'musl'
endif
cdata.set('HAVE_' + libc.to_upper(), 1)
vala_flags += '--define=' + libc.to_upper()
endif
if get_option('b_sanitize') == 'address'
@@ -654,6 +658,7 @@ if get_option('devkits').length() != 0
mkdevkit = [python, releng / 'mkdevkit.py']
uninstalled_dir = meson.global_build_root() / 'meson-uninstalled'
devkit_options = [
'--dep-symbol-scope', get_option('devkit_symbol_scope'),
'--cc', '>>>', cc.cmd_array(), '<<<',
'--c-args', '>>>', get_option('c_args'), '<<<',
'--pkg-config', '>>>', find_program('pkg-config'), '<<<',
+9
View File
@@ -150,6 +150,15 @@ option('devkits',
description: 'Devkits to build'
)
option('devkit_symbol_scope',
type: 'combo',
choices: ['prefixed', 'original'],
value: 'prefixed',
description : 'How devkit generation treats third-party symbols:\n'
+ ' - prefixed: add the \'_frida_\' prefix\n'
+ ' - original: keep symbols exactly as upstream\n'
)
option('tests',
type: 'feature',
value: 'auto',
+1 -1
Submodule releng updated: e10baa39a2...2b34e1c008.
+1 -1
View File
@@ -6,7 +6,7 @@ server_sources = [
if host_os_family == 'darwin'
server_sources += ['server-darwin.m']
endif
if host_os in ['ios', 'tvos']
if host_os in ['ios', 'tvos', 'xros']
server_sources += [
'server-ios-tvos.c',
]
+2 -2
View File
@@ -1,7 +1,7 @@
#include "server-glue.h"
#include "frida-core.h"
#if defined (HAVE_IOS) || defined (HAVE_TVOS)
#if defined (HAVE_IOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
# include "server-ios-tvos.h"
#endif
#ifdef HAVE_ANDROID
@@ -54,7 +54,7 @@ frida_server_environment_set_verbose_logging_enabled (gboolean enabled)
void
frida_server_environment_configure (void)
{
#if defined (HAVE_IOS) || defined (HAVE_TVOS)
#if defined (HAVE_IOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
_frida_server_ios_tvos_configure ();
#endif
+99 -23
View File
@@ -14,59 +14,79 @@ namespace Frida.Barebone {
get;
}
public abstract size_t size {
get;
}
public abstract async void deallocate (Cancellable? cancellable) throws Error, IOError;
}
public sealed class SimpleAllocator : Object, Allocator {
public sealed class NullAllocator : Object, Allocator {
public size_t page_size {
get { return _page_size; }
get {
return _page_size;
}
}
private size_t _page_size;
public NullAllocator (size_t page_size) {
this._page_size = page_size;
}
public async Allocation allocate (size_t size, size_t alignment, Cancellable? cancellable) throws Error, IOError {
throw new Error.NOT_SUPPORTED ("To enable this feature, specify an allocator in your FRIDA_BAREBONE_CONFIG");
}
}
public sealed class PhysicalAllocator : Object, Allocator {
public size_t page_size {
get {
return _page_size;
}
}
private Machine machine;
private size_t _page_size;
private uint64 base_pa;
private uint64 cursor;
public SimpleAllocator (Machine machine, size_t page_size, uint64 base_pa) {
public PhysicalAllocator (Machine machine, size_t page_size, PhysicalAllocatorConfig config) {
this.machine = machine;
this._page_size = page_size;
this.base_pa = base_pa;
this.cursor = base_pa;
this.cursor = config.physical_base;
}
public async Allocation allocate (size_t size, size_t alignment, Cancellable? cancellable) throws Error, IOError {
if (base_pa == 0) {
uint64 example_base;
if ("corellium" in machine.gdb.features)
example_base = 0x0800000000 + ((2048 - 3) * 1024 * 1024);
else
example_base = 0x0040000000 + (128 * 1024 * 1024);
throw new Error.NOT_SUPPORTED ("To enable this feature, set FRIDA_BAREBONE_HEAP_BASE to the physical " +
"base address to use, e.g. 0x%" + uint64.FORMAT_MODIFIER + "x", example_base);
}
uint64 address_pa = cursor;
size_t vm_size = round_size_up (size, page_size);
size_t vm_size = round_size_up (size, _page_size);
cursor += vm_size;
uint num_pages = (uint) (vm_size / page_size);
uint num_pages = (uint) (vm_size / _page_size);
Allocation page_allocation = yield machine.allocate_pages (address_pa, num_pages, cancellable);
return new SimpleAllocation (page_allocation);
return new PhysicalAllocation (page_allocation);
}
private class SimpleAllocation : Object, Allocation {
private class PhysicalAllocation : Object, Allocation {
public uint64 virtual_address {
get { return page_allocation.virtual_address; }
get {
return page_allocation.virtual_address;
}
}
public size_t size {
get {
return page_allocation.size;
}
}
private Allocation page_allocation;
public SimpleAllocation (Allocation page_allocation) {
this.page_allocation = page_allocation;
public PhysicalAllocation (Allocation allocation) {
page_allocation = allocation;
}
public async void deallocate (Cancellable? cancellable) throws Error, IOError {
@@ -75,4 +95,60 @@ namespace Frida.Barebone {
}
}
}
public sealed class TargetFunctionsAllocator : Object, Allocator {
public size_t page_size {
get {
return _page_size;
}
}
private Machine machine;
private size_t _page_size;
private TargetFunctionsAllocatorConfig config;
public TargetFunctionsAllocator (Machine machine, size_t page_size, TargetFunctionsAllocatorConfig config) {
this.machine = machine;
this._page_size = page_size;
this.config = config;
}
public async Allocation allocate (size_t size, size_t alignment, Cancellable? cancellable) throws Error, IOError {
uint64 address = yield machine.invoke (config.alloc_function, { size }, cancellable);
// TODO: Handle alignment.
return new TargetAllocation (address, size, machine, config);
}
private class TargetAllocation : Object, Allocation {
public uint64 virtual_address {
get {
return _virtual_address;
}
}
public size_t size {
get {
return _size;
}
}
private uint64 _virtual_address;
public size_t _size;
private Machine machine;
private TargetFunctionsAllocatorConfig config;
public TargetAllocation (uint64 address, size_t size, Machine m, TargetFunctionsAllocatorConfig c) {
_virtual_address = address;
_size = size;
machine = m;
config = c;
}
public async void deallocate (Cancellable? cancellable) throws Error, IOError {
yield machine.invoke (config.free_function, { _virtual_address, size }, cancellable);
}
}
}
}
+6 -2
View File
@@ -36,6 +36,11 @@ namespace Frida.Barebone {
throw_not_supported ();
}
public async void protect_pages (uint64 virtual_address, size_t size, Gum.PageProtection prot,
Cancellable? cancellable) throws Error, IOError {
throw_not_supported ();
}
public async Gee.List<uint64?> scan_ranges (Gee.List<Gum.MemoryRange?> ranges, MatchPattern pattern, uint max_matches,
Cancellable? cancellable) throws Error, IOError {
throw_not_supported ();
@@ -45,8 +50,7 @@ namespace Frida.Barebone {
throw_not_supported ();
}
public async uint64 invoke (uint64 impl, uint64[] args, uint64 landing_zone, Cancellable? cancellable)
throws Error, IOError {
public async uint64 invoke (uint64 impl, uint64[] args, Cancellable? cancellable) throws Error, IOError {
throw_not_supported ();
}
+416 -26
View File
@@ -25,6 +25,13 @@ namespace Frida.Barebone {
private const uint64 INT6_MASK = 0x3fULL;
private const uint64 INT48_MASK = 0xffffffffffffULL;
private const uint64 TABLE_PXN_BIT = 1ULL << 59;
private const uint64 UXN_BIT = 1ULL << 54;
private const uint64 PXN_BIT = 1ULL << 53;
private const uint64 AP1_BIT = 1ULL << 7;
private const uint64 AP0_BIT = 1ULL << 6;
public Arm64Machine (GDB.Client gdb) {
Object (gdb: gdb);
}
@@ -55,7 +62,7 @@ namespace Frida.Barebone {
yield set_addressing_mode (gdb, PHYSICAL, cancellable);
try {
yield collect_ranges_in_table (p.tt1, p.first_level, p.upper_bits, p.granule, result, cancellable);
yield collect_ranges_in_table (p.tt1, p.first_level, p.upper_bits, p, result, cancellable);
} finally {
set_addressing_mode.begin (gdb, VIRTUAL, null);
}
@@ -63,30 +70,30 @@ namespace Frida.Barebone {
return result;
}
private async void collect_ranges_in_table (uint64 table_address, uint level, uint64 upper_bits, Granule granule,
private async void collect_ranges_in_table (uint64 table_address, uint level, uint64 upper_bits, MMUParameters p,
Gee.List<RangeDetails> ranges, Cancellable? cancellable) throws Error, IOError {
uint max_entries = compute_max_entries (level, granule);
uint max_entries = compute_max_entries (level, p);
Buffer entries = yield gdb.read_buffer (table_address, max_entries * Descriptor.SIZE, cancellable);
uint shift = address_shift_at_level (level, granule);
uint shift = address_shift_at_level (level, p.granule);
for (uint i = 0; i != max_entries; i++) {
uint64 raw_descriptor = entries.read_uint64 (i * Descriptor.SIZE);
Descriptor desc = Descriptor.parse (raw_descriptor, level, granule);
Descriptor desc = Descriptor.parse (raw_descriptor, level, p.granule);
if (desc.kind == INVALID)
continue;
uint64 address = upper_bits | ((uint64) i << shift);
if (desc.kind == BLOCK) {
size_t size = 1 << num_block_bits_at_level (level, granule);
Gum.PageProtection prot = protection_from_flags (desc.flags);
size_t size = 1 << num_block_bits_at_level (level, p.granule);
Gum.PageProtection prot = protection_from_flags (desc.flags, p);
ranges.add (new RangeDetails (address, desc.target_address, size, prot, MappingType.UNKNOWN));
continue;
}
yield collect_ranges_in_table (desc.target_address, level + 1, address, granule, ranges, cancellable);
yield collect_ranges_in_table (desc.target_address, level + 1, address, p, ranges, cancellable);
}
}
@@ -152,9 +159,10 @@ namespace Frida.Barebone {
yield set_addressing_mode (gdb, PHYSICAL, cancellable);
try {
Allocation? allocation = yield maybe_insert_descriptor_in_table (physical_address, num_pages, p.tt1,
p.first_level, p.upper_bits, p.granule, cancellable);
p.first_level, p.upper_bits, p, cancellable);
if (allocation == null)
throw new Error.NOT_SUPPORTED ("Unable to insert page table mapping; please file a bug");
return allocation;
} finally {
set_addressing_mode.begin (gdb, VIRTUAL, null);
@@ -162,10 +170,10 @@ namespace Frida.Barebone {
}
private async Allocation? maybe_insert_descriptor_in_table (uint64 physical_address, uint num_pages,
uint64 table_address, uint level, uint64 upper_bits, Granule granule, Cancellable? cancellable)
uint64 table_address, uint level, uint64 upper_bits, MMUParameters p, Cancellable? cancellable)
throws Error, IOError {
uint max_entries = compute_max_entries (level, granule);
uint shift = address_shift_at_level (level, granule);
uint max_entries = compute_max_entries (level, p);
uint shift = address_shift_at_level (level, p.granule);
uint64 first_available_va = 0;
uint64 first_available_slot = 0;
@@ -184,13 +192,15 @@ namespace Frida.Barebone {
uint table_index = chunk_offset + i;
uint64 address = upper_bits | ((uint64) table_index << shift);
Descriptor desc = Descriptor.parse (raw_descriptor, level, granule);
Descriptor desc = Descriptor.parse (raw_descriptor, level, p.granule);
if (level < 3) {
if (desc.kind != TABLE)
continue;
if ((desc.flags & DescriptorFlags.PXNTABLE) != 0)
continue;
Allocation? allocation = yield maybe_insert_descriptor_in_table (physical_address,
num_pages, desc.target_address, level + 1, address, granule, cancellable);
num_pages, desc.target_address, level + 1, address, p, cancellable);
if (allocation != null)
return allocation;
continue;
@@ -215,17 +225,197 @@ namespace Frida.Barebone {
if (num_available_slots != num_pages)
return null;
Gum.PageProtection page_prot = Gum.PageProtection.READ | Gum.PageProtection.WRITE;
if (!p.sprr_enabled)
page_prot |= Gum.PageProtection.EXECUTE;
var builder = gdb.make_buffer_builder ();
for (uint i = 0; i != num_available_slots; i++) {
uint64 cur_physical_address = physical_address + (i * granule);
uint64 new_descriptor = cur_physical_address | 0x40000000000403ULL;
uint64 cur_physical_address = physical_address + (i * p.granule);
uint64 base_descriptor = cur_physical_address | 0x403ULL;
uint64 new_descriptor = apply_protection_bits (base_descriptor, page_prot, p);
builder.append_uint64 (new_descriptor);
}
Bytes new_descriptors = builder.build ();
Bytes old_descriptors = yield gdb.read_byte_array (first_available_slot, new_descriptors.get_size (), cancellable);
yield gdb.write_byte_array (first_available_slot, new_descriptors, cancellable);
return new DescriptorAllocation (first_available_va, first_available_slot, old_descriptors, gdb);
size_t size = num_pages * p.granule;
return new DescriptorAllocation (first_available_va, size, first_available_slot, old_descriptors, gdb);
}
public async void protect_pages (uint64 virtual_address, size_t size, Gum.PageProtection prot, Cancellable? cancellable)
throws Error, IOError {
MMUParameters p = yield MMUParameters.load (gdb, cancellable);
yield set_addressing_mode (gdb, PHYSICAL, cancellable);
try {
uint64 page_mask = p.granule - 1;
uint64 aligned_va = virtual_address & ~page_mask;
uint64 aligned_end = (virtual_address + size + page_mask) & ~page_mask;
uint num_pages = (uint) ((aligned_end - aligned_va) / p.granule);
yield perform_protect_pages (aligned_va, num_pages, prot, p, cancellable);
} finally {
set_addressing_mode.begin (gdb, VIRTUAL, null);
}
}
private async void perform_protect_pages (uint64 start_va, uint num_pages, Gum.PageProtection prot, MMUParameters p,
Cancellable? cancellable) throws Error, IOError {
var table_cache = new TableWalkCache ();
uint pages_processed = 0;
var processed_tables = new Gee.HashSet<uint64?> (Numeric.uint64_hash, Numeric.uint64_equal);
bool need_exec = (prot & Gum.PageProtection.EXECUTE) != 0;
while (pages_processed != num_pages) {
uint64 current_va = start_va + (uint64) pages_processed * p.granule;
uint64 table_pa = yield find_level3_table (current_va, p, table_cache, cancellable);
if (need_exec && !processed_tables.contains (table_pa)) {
yield clear_pxn_table_bits_for_va (current_va, p, table_cache, cancellable);
processed_tables.add (table_pa);
}
uint level3_shift = address_shift_at_level (3, p.granule);
uint64 level3_mask = (1ULL << level3_shift) - 1;
uint64 table_base_va = current_va & ~level3_mask;
uint64 table_end_va = table_base_va + (1ULL << level3_shift);
uint64 remaining_va = start_va + num_pages * p.granule;
uint64 batch_end_va = uint64.min (remaining_va, table_end_va);
uint batch_size = (uint) ((batch_end_va - current_va) / p.granule);
yield protect_pages_in_table (current_va, batch_size, prot, table_pa, p, cancellable);
pages_processed += batch_size;
}
}
private async void protect_pages_in_table (uint64 current_va, uint batch_size, Gum.PageProtection prot,
uint64 table_pa, MMUParameters p, Cancellable? cancellable) throws Error, IOError {
uint index_bits = num_address_bits_at_level (3, p);
uint index_shift = inpage_bits_for_granule (p.granule);
uint index_mask = (1U << index_bits) - 1;
uint64 first_index = (current_va >> index_shift) & index_mask;
uint64 first_slot_pa = table_pa + (first_index * Descriptor.SIZE);
Buffer descriptors = yield gdb.read_buffer (first_slot_pa, batch_size * Descriptor.SIZE, cancellable);
bool any_changed = false;
for (uint i = 0; i != batch_size; i++) {
uint64 raw_desc = descriptors.read_uint64 (i * Descriptor.SIZE);
uint64 new_desc = apply_protection_bits (raw_desc, prot, p);
if (new_desc != raw_desc) {
descriptors.write_uint64 (i * Descriptor.SIZE, new_desc);
any_changed = true;
}
}
if (any_changed)
yield gdb.write_byte_array (first_slot_pa, descriptors.bytes, cancellable);
}
private async uint64 find_level3_table (uint64 va, MMUParameters p, TableWalkCache cache, Cancellable? cancellable)
throws Error, IOError {
TableWalkResult? cached = cache.lookup (va, p);
if (cached != null)
return yield walk_to_level3 (va, cached.table_pa, cached.level, p, cache, cancellable);
return yield walk_to_level3 (va, p.tt1, p.first_level, p, cache, cancellable);
}
private async uint64 walk_to_level3 (uint64 va, uint64 start_table_pa, uint start_level, MMUParameters p,
TableWalkCache cache, Cancellable? cancellable) throws Error, IOError {
uint64 table_pa = start_table_pa;
uint level = start_level;
while (level != 3) {
cache.store (va, level, table_pa, p);
uint shift = address_shift_at_level (level, p.granule);
uint entries = compute_max_entries (level, p);
uint index = (uint) ((va >> shift) & (entries - 1));
uint64 slot_pa = table_pa + ((uint64) index * Descriptor.SIZE);
Buffer d_buf = yield gdb.read_buffer (slot_pa, Descriptor.SIZE, cancellable);
uint64 raw = d_buf.read_uint64 (0);
Descriptor desc = Descriptor.parse (raw, level, p.granule);
if (desc.kind != TABLE)
throw new Error.NOT_SUPPORTED ("Walk failed at level %u", level);
table_pa = desc.target_address;
level++;
}
return table_pa;
}
private async void clear_pxn_table_bits_for_va (uint64 va, MMUParameters p, TableWalkCache cache, Cancellable? cancellable)
throws Error, IOError {
uint64 table_pa = p.tt1;
for (uint level = p.first_level; level != 3; level++) {
uint entries = compute_max_entries (level, p);
uint shift = address_shift_at_level (level, p.granule);
uint index = (uint) ((va >> shift) & (entries - 1));
uint64 slot_pa = table_pa + (index * Descriptor.SIZE);
Buffer d_buf = yield gdb.read_buffer (slot_pa, Descriptor.SIZE, cancellable);
uint64 raw_desc = d_buf.read_uint64 (0);
Descriptor desc = Descriptor.parse (raw_desc, level, p.granule);
if (desc.kind != TABLE)
break;
if ((raw_desc & TABLE_PXN_BIT) != 0) {
uint64 new_desc = raw_desc & ~TABLE_PXN_BIT;
d_buf.write_uint64 (0, new_desc);
yield gdb.write_byte_array (slot_pa, d_buf.bytes, cancellable);
}
table_pa = desc.target_address;
}
}
private class TableWalkCache {
private Gee.Map<uint64?, TableWalkResult> cache =
new Gee.HashMap<uint64?, TableWalkResult> (Numeric.uint64_hash, Numeric.uint64_equal);
public TableWalkResult? lookup (uint64 va, MMUParameters p) {
for (int level = 2; level >= (int) p.first_level; level--) {
uint64 cache_key = compute_cache_key (va, (uint) level, p);
TableWalkResult? result = cache[cache_key];
if (result != null)
return result;
}
return null;
}
public void store (uint64 va, uint level, uint64 table_pa, MMUParameters p) {
if (level >= 3)
return;
uint64 cache_key = compute_cache_key (va, level, p);
cache[cache_key] = new TableWalkResult () {
table_pa = table_pa,
level = level
};
}
private uint64 compute_cache_key (uint64 va, uint level, MMUParameters p) {
uint shift = address_shift_at_level (level + 1, p.granule);
return (va >> shift) << shift;
}
}
private class TableWalkResult {
public uint64 table_pa;
public uint level;
}
public async Gee.List<uint64?> scan_ranges (Gee.List<Gum.MemoryRange?> ranges, MatchPattern pattern, uint max_matches,
@@ -354,14 +544,17 @@ namespace Frida.Barebone {
case ABS64:
relocated.write_uint64 ((size_t) r.address, base_va + r.symbol.address + r.addend);
break;
case PREL32:
var diff = (int64) (base_va + r.symbol.address + r.addend) - (int64) (base_va + r.address);
relocated.write_int32 ((size_t) r.address, (int32) diff);
break;
default:
throw new Error.NOT_SUPPORTED ("Unsupported relocation type: %s",
Marshal.enum_to_nick<Gum.ElfArm64Relocation> (type));
}
}
public async uint64 invoke (uint64 impl, uint64[] args, uint64 landing_zone, Cancellable? cancellable)
throws Error, IOError {
public async uint64 invoke (uint64 impl, uint64[] args, Cancellable? cancellable) throws Error, IOError {
if (args.length > 8)
throw new Error.NOT_SUPPORTED ("Unsupported number of arguments; please open a PR");
@@ -377,6 +570,7 @@ namespace Frida.Barebone {
regs["pc"] = impl;
uint64 landing_zone = saved_regs["pc"].get_uint64 ();
regs["x30"] = landing_zone;
uint64 sp = saved_regs["sp"].get_uint64 ();
@@ -406,6 +600,35 @@ namespace Frida.Barebone {
return retval;
}
public async void execute (uint64 start, uint64 end, Cancellable? cancellable) throws Error, IOError {
bool was_running = gdb.state != STOPPED;
if (was_running)
yield gdb.stop (cancellable);
GDB.Thread thread = gdb.exception.thread;
Gee.Map<string, Variant> saved_regs = yield thread.read_registers (cancellable);
var regs = new Gee.HashMap<string, Variant> ();
regs.set_all (saved_regs);
regs["pc"] = start;
yield thread.write_registers (regs, cancellable);
GDB.Breakpoint bp = yield gdb.add_breakpoint (SOFT, end, 4, cancellable);
GDB.Exception ex = null;
do {
ex = yield gdb.continue_until_exception (cancellable);
} while (ex.breakpoint != bp || ex.thread.id != thread.id);
// TODO: Improve GDB.Client to guarantee a single GDB.Thread instance per ID.
yield bp.remove (cancellable);
yield thread.write_registers (saved_regs, cancellable);
if (was_running)
yield gdb.continue (cancellable);
}
public async CallFrame load_call_frame (GDB.Thread thread, uint arity, Cancellable? cancellable) throws Error, IOError {
var regs = yield thread.read_registers (cancellable);
@@ -689,6 +912,10 @@ namespace Frida.Barebone {
public uint first_level;
public uint64 upper_bits;
public uint64 tt1;
public uint t1sz;
public bool sprr_enabled;
public uint64 sprr_perm;
public static async MMUParameters load (GDB.Client gdb, Cancellable? cancellable) throws Error, IOError {
GDB.Exception? exception = gdb.exception;
@@ -716,6 +943,10 @@ namespace Frida.Barebone {
parameters.upper_bits |= 1ULL << (63 - i);
parameters.tt1 = regs.ttbr1 & INT48_MASK;
parameters.t1sz = t1sz;
parameters.sprr_enabled = (regs.sprr_config & 1) != 0;
parameters.sprr_perm = regs.sprr_perm;
return parameters;
}
@@ -724,6 +955,8 @@ namespace Frida.Barebone {
private class MMURegisters {
public uint64 tcr;
public uint64 ttbr1;
public uint64 sprr_config;
public uint64 sprr_perm;
public static async MMURegisters read (GDB.Thread thread, Cancellable? cancellable) throws Error, IOError {
var regs = new MMURegisters ();
@@ -741,10 +974,19 @@ namespace Frida.Barebone {
regs.tcr = val;
else if (name == "ttbr1_el1")
regs.ttbr1 = val;
else if (name == "sprr_config_el1")
regs.sprr_config = val;
else if (name == "sprr_el1br1_el1")
regs.sprr_perm = val;
}
} else {
regs.tcr = yield thread.read_register ("tcr_el1", cancellable);
regs.ttbr1 = yield thread.read_register ("ttbr1_el1", cancellable);
try {
regs.sprr_config = yield thread.read_register ("sprr_config_el1", cancellable);
regs.sprr_perm = yield thread.read_register ("sprr_el1br1_el1", cancellable);
} catch (Error e) {
}
}
return regs;
@@ -850,16 +1092,27 @@ namespace Frida.Barebone {
private class DescriptorAllocation : Object, Allocation {
public uint64 virtual_address {
get { return base_va; }
get {
return base_va;
}
}
public size_t size {
get {
return _size;
}
}
private uint64 base_va;
private size_t _size;
private uint64 first_slot;
private Bytes? old_descriptors;
private GDB.Client gdb;
public DescriptorAllocation (uint64 base_va, uint64 first_slot, Bytes old_descriptors, GDB.Client gdb) {
public DescriptorAllocation (uint64 base_va, size_t size, uint64 first_slot, Bytes old_descriptors,
GDB.Client gdb) {
this.base_va = base_va;
this._size = size;
this.first_slot = first_slot;
this.old_descriptors = old_descriptors;
this.gdb = gdb;
@@ -908,11 +1161,23 @@ namespace Frida.Barebone {
assert_not_reached ();
}
private static uint compute_max_entries (uint level, Granule granule) {
return 1 << num_address_bits_at_level (level, granule);
private static uint compute_max_entries (uint level, MMUParameters p) {
return 1 << num_address_bits_at_level (level, p);
}
private static uint num_address_bits_at_level (uint level, Granule granule) {
private static uint num_address_bits_at_level (uint level, MMUParameters p) {
if (level == p.first_level) {
uint available_address_bits = 64 - p.t1sz - inpage_bits_for_granule (p.granule);
uint consumed_by_lower_levels = 0;
for (uint l = level + 1; l <= 3; l++)
consumed_by_lower_levels += unclipped_address_bits_at_level (l, p.granule);
return available_address_bits - consumed_by_lower_levels;
} else {
return unclipped_address_bits_at_level (level, p.granule);
}
}
private static uint unclipped_address_bits_at_level (uint level, Granule granule) {
switch (granule) {
case 4K:
return 9;
@@ -932,7 +1197,7 @@ namespace Frida.Barebone {
private static uint address_shift_at_level (uint level, Granule granule) {
uint shift = inpage_bits_for_granule (granule);
for (int l = 2; l != (int) level - 1; l--)
shift += num_address_bits_at_level (l, granule);
shift += unclipped_address_bits_at_level (l, granule);
return shift;
}
@@ -949,7 +1214,45 @@ namespace Frida.Barebone {
}
}
private static Gum.PageProtection protection_from_flags (DescriptorFlags flags) {
private static Gum.PageProtection protection_from_flags (DescriptorFlags flags, MMUParameters p) {
if (p.sprr_enabled) {
uint idx = 0;
if ((flags & DescriptorFlags.AP_READ_ONLY) != 0)
idx |= 1 << 3;
if ((flags & DescriptorFlags.AP_ALLOW_APPLICATION) != 0)
idx |= 1 << 2;
if ((flags & DescriptorFlags.UXN) != 0)
idx |= 1 << 1;
if ((flags & DescriptorFlags.PXN) != 0)
idx |= 1 << 0;
uint perm = (uint) ((p.sprr_perm >> (idx * 4)) & 0xf);
Gum.PageProtection prot;
switch (perm & 3) {
case 0:
prot = 0;
break;
case 1:
prot = READ | EXECUTE;
if ((perm >> 2) == 2)
prot = EXECUTE;
break;
case 2:
prot = READ;
break;
case 3:
prot = READ | WRITE;
if ((perm >> 2) == 1)
prot = 0;
break;
default:
assert_not_reached ();
}
return prot;
}
Gum.PageProtection prot = READ;
if ((flags & DescriptorFlags.PXN) == 0)
prot |= EXECUTE;
@@ -958,6 +1261,93 @@ namespace Frida.Barebone {
return prot;
}
private static uint64 apply_protection_bits (uint64 descriptor, Gum.PageProtection prot, MMUParameters p) throws Error {
uint64 result = descriptor;
if (p.sprr_enabled) {
uint target_sprr_index = find_sprr_index_for_permissions (prot, p);
result = apply_sprr_index_to_descriptor (result, target_sprr_index);
} else {
result = apply_non_sprr_protection_bits (result, prot);
}
return result;
}
private static uint64 apply_non_sprr_protection_bits (uint64 descriptor, Gum.PageProtection prot) {
uint64 result = descriptor;
bool want_exec = (prot & Gum.PageProtection.EXECUTE) != 0;
bool want_write = (prot & Gum.PageProtection.WRITE) != 0;
if (want_exec)
result &= ~(UXN_BIT | PXN_BIT);
else
result |= (UXN_BIT | PXN_BIT);
if (want_write) {
result &= ~(AP1_BIT | AP0_BIT);
} else {
result |= AP1_BIT;
result &= ~AP0_BIT;
}
return result;
}
private static uint find_sprr_index_for_permissions (Gum.PageProtection prot, MMUParameters p) throws Error {
bool want_read = (prot & Gum.PageProtection.READ) != 0;
bool want_write = (prot & Gum.PageProtection.WRITE) != 0;
bool want_exec = (prot & Gum.PageProtection.EXECUTE) != 0;
for (uint i = 0; i != 16; i++) {
uint perm = (uint) ((p.sprr_perm >> (i * 4)) & 0xf);
bool slot_allows_read = false;
bool slot_allows_write = false;
bool slot_allows_exec = false;
switch (perm & 3) {
case 0:
break;
case 1:
slot_allows_exec = true;
if ((perm >> 2) != 2)
slot_allows_read = true;
break;
case 2:
slot_allows_read = true;
break;
case 3:
slot_allows_read = true;
slot_allows_write = ((perm >> 2) != 1);
break;
}
if (slot_allows_read == want_read && slot_allows_write == want_write && slot_allows_exec == want_exec)
return i;
}
throw new Error.INVALID_ARGUMENT ("No suitable SPRR slot found for protection 0x%x", prot);
}
private static uint64 apply_sprr_index_to_descriptor (uint64 descriptor, uint sprr_index) {
uint64 result = descriptor;
result &= ~(AP1_BIT | AP0_BIT | UXN_BIT | PXN_BIT);
if ((sprr_index & 0x8) != 0)
result |= AP1_BIT;
if ((sprr_index & 0x4) != 0)
result |= AP0_BIT;
if ((sprr_index & 0x2) != 0)
result |= UXN_BIT;
if ((sprr_index & 0x1) != 0)
result |= PXN_BIT;
return result;
}
private static Gum.PageProtection protection_from_corellium_pt_details (string details) {
Gum.PageProtection prot = READ;
if (!("pXN" in details))
+6 -2
View File
@@ -31,6 +31,11 @@ namespace Frida.Barebone {
throw_not_supported ();
}
public async void protect_pages (uint64 virtual_address, size_t size, Gum.PageProtection prot,
Cancellable? cancellable) throws Error, IOError {
throw_not_supported ();
}
public async Gee.List<uint64?> scan_ranges (Gee.List<Gum.MemoryRange?> ranges, MatchPattern pattern,
uint max_matches, Cancellable? cancellable) throws Error, IOError {
throw_not_supported ();
@@ -40,8 +45,7 @@ namespace Frida.Barebone {
throw_not_supported ();
}
public async uint64 invoke (uint64 impl, uint64[] args, uint64 landing_zone, Cancellable? cancellable)
throws Error, IOError {
public async uint64 invoke (uint64 impl, uint64[] args, Cancellable? cancellable) throws Error, IOError {
throw_not_supported ();
}
+6 -2
View File
@@ -32,6 +32,11 @@ namespace Frida.Barebone {
throw_not_supported ();
}
public async void protect_pages (uint64 virtual_address, size_t size, Gum.PageProtection prot,
Cancellable? cancellable) throws Error, IOError {
throw_not_supported ();
}
public async Gee.List<uint64?> scan_ranges (Gee.List<Gum.MemoryRange?> ranges, MatchPattern pattern, uint max_matches,
Cancellable? cancellable) throws Error, IOError {
throw_not_supported ();
@@ -41,8 +46,7 @@ namespace Frida.Barebone {
throw_not_supported ();
}
public async uint64 invoke (uint64 impl, uint64[] args, uint64 landing_zone, Cancellable? cancellable)
throws Error, IOError {
public async uint64 invoke (uint64 impl, uint64[] args, Cancellable? cancellable) throws Error, IOError {
throw_not_supported ();
}
+6 -2
View File
@@ -34,6 +34,11 @@ namespace Frida.Barebone {
throw_not_supported ();
}
public async void protect_pages (uint64 virtual_address, size_t size, Gum.PageProtection prot,
Cancellable? cancellable) throws Error, IOError {
throw_not_supported ();
}
public async Gee.List<uint64?> scan_ranges (Gee.List<Gum.MemoryRange?> ranges, MatchPattern pattern, uint max_matches,
Cancellable? cancellable) throws Error, IOError {
throw_not_supported ();
@@ -43,8 +48,7 @@ namespace Frida.Barebone {
throw_not_supported ();
}
public async uint64 invoke (uint64 impl, uint64[] args, uint64 landing_zone, Cancellable? cancellable)
throws Error, IOError {
public async uint64 invoke (uint64 impl, uint64[] args, Cancellable? cancellable) throws Error, IOError {
throw_not_supported ();
}
+41 -36
View File
@@ -2,26 +2,8 @@ namespace Frida {
public sealed class BareboneHostSessionBackend : Object, HostSessionBackend {
private BareboneHostSessionProvider? provider;
private const uint16 DEFAULT_PORT = 3333;
public async void start (Cancellable? cancellable) throws IOError {
SocketConnectable? connectable = null;
unowned string? address = Environment.get_variable ("FRIDA_BAREBONE_ADDRESS");
if (address != null) {
try {
connectable = NetworkAddress.parse (address, DEFAULT_PORT);
} catch (GLib.Error e) {
}
}
if (connectable == null)
connectable = new InetSocketAddress (new InetAddress.loopback (SocketFamily.IPV4), DEFAULT_PORT);
uint64 heap_base_pa = 0;
unowned string? heap_base_preference = Environment.get_variable ("FRIDA_BAREBONE_HEAP_BASE");
if (heap_base_preference != null)
heap_base_pa = uint64.parse (heap_base_preference, 16);
provider = new BareboneHostSessionProvider (connectable, heap_base_pa);
provider = new BareboneHostSessionProvider ();
provider_available (provider);
}
@@ -49,22 +31,8 @@ namespace Frida {
}
}
public SocketConnectable connectable {
get;
construct;
}
public uint64 heap_base_pa {
get;
construct;
}
private BareboneHostSession? host_session;
public BareboneHostSessionProvider (SocketConnectable connectable, uint64 heap_base_pa) {
Object (connectable: connectable, heap_base_pa: heap_base_pa);
}
public async void close (Cancellable? cancellable) throws IOError {
if (host_session != null) {
yield host_session.close (cancellable);
@@ -76,6 +44,27 @@ namespace Frida {
if (host_session != null)
throw new Error.INVALID_OPERATION ("Already created");
Barebone.Config config;
unowned string? config_path = Environment.get_variable ("FRIDA_BAREBONE_CONFIG");
if (config_path != null) {
try {
var config_data = yield FS.read_all_text (File.new_for_path (config_path), cancellable);
config = (Barebone.Config) Json.gobject_from_data (typeof (Barebone.Config), config_data);
} catch (GLib.Error e) {
throw new Error.INVALID_ARGUMENT ("Unable to load %s: %s", config_path, e.message);
}
} else {
config = new Barebone.Config ();
}
SocketConnectable connectable;
try {
Barebone.ConnectionConfig c = config.connection;
connectable = NetworkAddress.parse (c.host, c.port);
} catch (GLib.Error e) {
throw new Error.INVALID_ARGUMENT ("Unable to load %s: %s", config_path, e.message);
}
IOStream stream;
try {
var client = new SocketClient ();
@@ -109,10 +98,26 @@ namespace Frida {
break;
}
var page_size = yield machine.query_page_size (cancellable);
size_t page_size;
try {
page_size = yield machine.query_page_size (cancellable);
} catch (Error e) {
page_size = 0;
}
// TODO: Locate and use kernel's allocator when possible.
Barebone.Allocator allocator = new Barebone.SimpleAllocator (machine, page_size, heap_base_pa);
Barebone.Allocator allocator;
Barebone.AllocatorConfig ac = config.allocator;
if (ac is Barebone.NoAllocatorConfig) {
allocator = new Barebone.NullAllocator (page_size);
} else if (ac is Barebone.PhysicalAllocatorConfig) {
allocator = new Barebone.PhysicalAllocator (machine, page_size,
(Barebone.PhysicalAllocatorConfig) ac);
} else if (ac is Barebone.TargetFunctionsAllocatorConfig) {
allocator = new Barebone.TargetFunctionsAllocator (machine, page_size,
(Barebone.TargetFunctionsAllocatorConfig) ac);
} else {
assert_not_reached ();
}
var interceptor = new Barebone.Interceptor (machine, allocator);
+63
View File
@@ -0,0 +1,63 @@
[CCode (gir_namespace = "FridaBarebone", gir_version = "1.0")]
namespace Frida.Barebone {
private sealed class CModule : Object {
public signal void console_output (string message);
public Gee.List<Export> exports {
get;
default = new Gee.ArrayList<Export> ();
}
public class Export {
public string name;
public uint64 address;
internal Export (string name, uint64 address) {
this.name = name;
this.address = address;
}
}
private Gum.ElfModule elf;
private Allocation allocation;
private Callback console_log_callback;
public async CModule.from_blob (Bytes blob, Machine machine, Allocator allocator, Cancellable? cancellable)
throws Error, IOError {
try {
elf = new Gum.ElfModule.from_blob (blob);
} catch (Gum.Error e) {
throw new Error.NOT_SUPPORTED ("%s", e.message);
}
allocation = yield inject_elf (elf, machine, allocator, cancellable);
uint64 base_va = allocation.virtual_address;
uint64 console_log_trap = 0;
elf.enumerate_symbols (e => {
if (e.name == "")
return true;
if (e.name[0] == '_') {
if (e.name == "_console_log")
console_log_trap = base_va + e.address;
return true;
}
exports.add (new Export (e.name, base_va + e.address));
return true;
});
if (console_log_trap != 0) {
var handler = new ConsoleLogHandler (machine.gdb);
handler.output.connect (on_console_output);
console_log_callback = yield new Callback (console_log_trap, handler, machine, cancellable);
}
}
private void on_console_output (string message) {
console_output (message);
}
}
}
+185
View File
@@ -0,0 +1,185 @@
[CCode (gir_namespace = "FridaBarebone", gir_version = "1.0")]
namespace Frida.Barebone {
/**
* Barebone backend configuration. This is specified via the FRIDA_BAREBONE_CONFIG environment
* variable, which should point to the filesystem path of a JSON-encoded configuration file.
*
* Example JSON configurations:
*
* 1. Using all defaults:
* {
* "connection": {
* "host": "127.0.0.1",
* "port": 3333
* },
* "allocator": {
* "mode": "none"
* }
* }
*
* 2. Using a physical memory allocator:
* {
* "connection": {
* "host": "127.0.0.1",
* "port": 9000
* },
* "allocator": {
* "mode": "physical",
* "physical_base": "0x8ec9b4000"
* }
* }
*
* 3. Using target-specific allocation functions:
* {
* "connection": {
* "host": "127.0.0.1",
* "port": 9000
* },
* "allocator": {
* "mode": "target-functions",
* "alloc_function": "0xfffffff007a3c278",
* "free_function": "0xfffffff007a3c338"
* }
* }
*/
public sealed class Config : Object, Json.Serializable {
public ConnectionConfig connection {
get;
set;
default = new ConnectionConfig ();
}
public AllocatorConfig allocator {
get;
set;
default = new NoAllocatorConfig ();
}
public bool deserialize_property (string property_name, out Value value, ParamSpec pspec, Json.Node property_node) {
if (property_name == "allocator" && property_node.get_node_type () == Json.NodeType.OBJECT) {
var obj_node = property_node.get_object ();
string? mode = obj_node.get_string_member ("mode");
Type t = 0;
switch (mode) {
case "none":
t = typeof (NoAllocatorConfig);
break;
case "physical":
t = typeof (PhysicalAllocatorConfig);
break;
case "target-functions":
t = typeof (TargetFunctionsAllocatorConfig);
break;
default:
break;
}
if (t != 0) {
var obj = (AllocatorConfig) Json.gobject_deserialize (t, property_node);
if (obj != null && obj.is_valid) {
var v = Value (t);
v.set_object (obj);
value = v;
return true;
}
}
}
value = Value (pspec.value_type);
return false;
}
}
public sealed class ConnectionConfig : Object {
public string host {
get;
set;
default = "127.0.0.1";
}
public uint16 port {
get;
set;
default = 3333;
}
}
public abstract class AllocatorConfig : Object {
public abstract bool is_valid {
get;
}
}
public sealed class NoAllocatorConfig : AllocatorConfig {
public override bool is_valid {
get {
return true;
}
}
}
public sealed class PhysicalAllocatorConfig : AllocatorConfig, Json.Serializable {
public override bool is_valid {
get {
return true;
}
}
public uint64 physical_base {
get;
set;
}
public bool deserialize_property (string property_name, out Value value, ParamSpec pspec, Json.Node property_node) {
if (try_deserialize_address ("physical_base", property_node, out value))
return true;
value = Value (pspec.value_type);
return false;
}
}
public sealed class TargetFunctionsAllocatorConfig : AllocatorConfig, Json.Serializable {
public override bool is_valid {
get {
return alloc_function != 0 && free_function != 0;
}
}
public uint64 alloc_function {
get;
set;
}
public uint64 free_function {
get;
set;
}
public bool deserialize_property (string property_name, out Value value, ParamSpec pspec, Json.Node property_node) {
if (try_deserialize_address ("alloc_function", property_node, out value))
return true;
if (try_deserialize_address ("free_function", property_node, out value))
return true;
value = Value (pspec.value_type);
return false;
}
}
private bool try_deserialize_address (string name, Json.Node node, out Value val) {
val = Value (typeof (uint64));
if (node.get_value_type () != typeof (string))
return false;
uint64 v;
if (!uint64.try_parse (node.get_string (), out v, null, 16))
return false;
val = v;
return true;
}
}
+31
View File
@@ -0,0 +1,31 @@
[CCode (gir_namespace = "FridaBarebone", gir_version = "1.0")]
namespace Frida.Barebone {
private class ConsoleLogHandler : Object, CallbackHandler {
public signal void output (string message);
public uint arity {
get { return 2; }
}
private GDB.Client gdb;
public ConsoleLogHandler (GDB.Client gdb) {
this.gdb = gdb;
}
public async uint64 handle_invocation (uint64[] args, CallFrame frame, Cancellable? cancellable)
throws Error, IOError {
var message = args[0];
var len = (long) args[1];
Bytes str_bytes = yield gdb.read_byte_array (message, len, cancellable);
unowned uint8[] str_data = str_bytes.get_data ();
unowned string str_raw = (string) str_data;
string str = str_raw.substring (0, len);
output (str);
return 0;
}
}
}
+27
View File
@@ -0,0 +1,27 @@
[CCode (gir_namespace = "FridaBarebone", gir_version = "1.0")]
namespace Frida.Barebone {
public async Allocation inject_elf (Gum.ElfModule elf, Machine machine, Allocator allocator, Cancellable? cancellable)
throws Error, IOError {
size_t vm_size = (size_t) elf.mapped_size;
size_t page_size = yield machine.query_page_size (cancellable);
uint num_pages = (uint) (vm_size / page_size);
if (vm_size % page_size != 0)
num_pages++;
var allocation = yield allocator.allocate (num_pages * page_size, page_size, cancellable);
try {
uint64 base_va = allocation.virtual_address;
Bytes relocated_image = machine.relocate (elf, base_va);
yield machine.gdb.write_byte_array (base_va, relocated_image, cancellable);
yield machine.protect_pages (base_va, vm_size, READ | EXECUTE, cancellable);
} catch (GLib.Error e) {
yield allocation.deallocate (cancellable);
throw_api_error (e);
}
return allocation;
}
}
+4 -2
View File
@@ -22,6 +22,9 @@ namespace Frida.Barebone {
public abstract async Allocation allocate_pages (uint64 physical_address, uint num_pages, Cancellable? cancellable)
throws Error, IOError;
public abstract async void protect_pages (uint64 virtual_address, size_t size, Gum.PageProtection prot,
Cancellable? cancellable) throws Error, IOError;
public abstract async Gee.List<uint64?> scan_ranges (Gee.List<Gum.MemoryRange?> ranges, MatchPattern pattern,
uint max_matches, Cancellable? cancellable) throws Error, IOError;
@@ -65,8 +68,7 @@ namespace Frida.Barebone {
public abstract void apply_relocation (Gum.ElfRelocationDetails r, uint64 base_va, Buffer relocated) throws Error;
public abstract async uint64 invoke (uint64 impl, uint64[] args, uint64 landing_zone, Cancellable? cancellable)
throws Error, IOError;
public abstract async uint64 invoke (uint64 impl, uint64[] args, Cancellable? cancellable) throws Error, IOError;
public abstract async CallFrame load_call_frame (GDB.Thread thread, uint arity, Cancellable? cancellable)
throws Error, IOError;
+4
View File
@@ -1,12 +1,16 @@
backend_sources += files(
'barebone-host-session.vala',
'config.vala',
'script.vala',
'machine.vala',
'allocator.vala',
'callback.vala',
'memory-scanner.vala',
'interceptor.vala',
'c-module.vala',
'rust-module.vala',
'console.vala',
'elf.vala',
'arch-x86' / 'machine.vala',
'arch-x86_64' / 'machine.vala',
'arch-arm' / 'machine.vala',
+4 -4
View File
@@ -8,7 +8,7 @@
"name": "frida-barebone-script-runtime",
"version": "1.0.0",
"devDependencies": {
"@types/frida-gum": "^19.0.0",
"@types/frida-gum": "^19.0.1",
"esbuild": "^0.25.5",
"typescript": "^5.8.3"
}
@@ -439,9 +439,9 @@
}
},
"node_modules/@types/frida-gum": {
"version": "19.0.0",
"resolved": "https://registry.npmjs.org/@types/frida-gum/-/frida-gum-19.0.0.tgz",
"integrity": "sha512-qViK1KwvPEAkajwSUv0wpZvZLiX8xO4JFFCh8dfYZfzSyOEfoE0KliCP/nJSKIKG6N3hXnPowrvPufjs5fLKAA==",
"version": "19.0.1",
"resolved": "https://registry.npmjs.org/@types/frida-gum/-/frida-gum-19.0.1.tgz",
"integrity": "sha512-mp8BpWWkQFJH86ZN5uXZuDiA7KY/+jDknrw0a06x0/+F5ucPwctHrCuV6iT+LLCp/GyICc36ssedF33B1WoLsw==",
"dev": true,
"license": "MIT"
},
+1 -1
View File
@@ -9,7 +9,7 @@
"watch": "tsc -w"
},
"devDependencies": {
"@types/frida-gum": "^19.0.0",
"@types/frida-gum": "^19.0.1",
"esbuild": "^0.25.5",
"typescript": "^5.8.3"
}
+36 -53
View File
@@ -84,23 +84,11 @@ namespace Frida.Barebone {
throw new Error.NOT_SUPPORTED ("%s", e.message);
}
size_t vm_size = (size_t) elf.mapped_size;
allocation = yield inject_elf (elf, machine, allocator, cancellable);
size_t page_size = yield machine.query_page_size (cancellable);
uint num_pages = (uint) (vm_size / page_size);
if (vm_size % page_size != 0)
num_pages++;
var gdb = machine.gdb;
allocation = yield allocator.allocate (num_pages * page_size, page_size, cancellable);
uint64 base_va = allocation.virtual_address;
Bytes relocated_image = machine.relocate (elf, base_va);
yield gdb.write_byte_array (base_va, relocated_image, cancellable);
uint64 console_log_trap = 0;
elf.enumerate_dynamic_symbols (e => {
elf.enumerate_symbols (e => {
if (e.name == "")
return true;
@@ -116,38 +104,14 @@ namespace Frida.Barebone {
});
if (console_log_trap != 0) {
console_log_callback = yield new Callback (console_log_trap, new ConsoleLogHandler (this, gdb),
machine, cancellable);
var handler = new ConsoleLogHandler (machine.gdb);
handler.output.connect (on_console_output);
console_log_callback = yield new Callback (console_log_trap, handler, machine, cancellable);
}
}
private class ConsoleLogHandler : Object, CallbackHandler {
public uint arity {
get { return 2; }
}
private weak RustModule parent;
private GDB.Client gdb;
public ConsoleLogHandler (RustModule parent, GDB.Client gdb) {
this.parent = parent;
this.gdb = gdb;
}
public async uint64 handle_invocation (uint64[] args, CallFrame frame, Cancellable? cancellable)
throws Error, IOError {
var message = args[0];
var len = (long) args[1];
Bytes str_bytes = yield gdb.read_byte_array (message, len, cancellable);
unowned uint8[] str_data = str_bytes.get_data ();
unowned string str_raw = (string) str_data;
string str = str_raw.substring (0, len);
parent.console_output (str);
return 0;
}
private void on_console_output (string message) {
console_output (message);
}
private const string CRATE_NAME = "rustmodule";
@@ -201,7 +165,7 @@ namespace Frida.Barebone {
.resolve_relative_path (CRATE_NAME);
}
yield write_text_file (workdir, "module.lds", make_linker_script (symbols), cancellable);
yield write_text_file (workdir, "module.lds", make_linker_script (code, symbols), cancellable);
} catch (GLib.Error e) {
throw new Error.PERMISSION_DENIED ("%s", e.message);
}
@@ -270,8 +234,8 @@ namespace Frida.Barebone {
return rs.str;
}
private static string make_linker_script (Gee.Map<string, uint64?> symbols) {
var script = new StringBuilder.sized (256);
private static string make_linker_script (string code, Gee.Map<string, uint64?> symbols) {
var script = new StringBuilder.sized (512);
foreach (var e in symbols.entries) {
unowned string name = e.key;
@@ -282,15 +246,16 @@ namespace Frida.Barebone {
.append_printf ("0x%" + uint64.FORMAT_MODIFIER + "x;\n", address);
}
script.append (prettify_text_asset (BASE_LINKER_SCRIPT));
return script.str;
}
private const string BASE_LINKER_SCRIPT = """
script.append ("""
SECTIONS {
.text : {
*(.text*);
""");
foreach (string name in extract_extern_c_symbols (code))
script.append_printf (" KEEP(*(.text.%s))\n", name);
script.append ("""
_console_log = .;
. += 8;
}
@@ -307,7 +272,25 @@ namespace Frida.Barebone {
*(.bss*)
}
}
""";
""");
return prettify_text_asset (script.str);
}
private static Gee.List<string> extract_extern_c_symbols (string code) {
var names = new Gee.ArrayList<string> ();
var export_pattern = /\#\[\s*no_mangle\s*\]\s*pub\s+(?:unsafe\s+)?extern\s*"C"\s+fn\s+([A-Za-z_]\w*)\s*\(/;
try {
MatchInfo info;
for (export_pattern.match (code, 0, out info); info.matches (); info.next ())
names.add (info.fetch (1));
} catch (RegexError e) {
}
return names;
}
private const string BUILTINS = """
#![no_main]
+29
View File
@@ -304,6 +304,13 @@ Object.defineProperties(Process, {
});
const marshalers: { [type: string]: Marshaler } = {
void: {
fromNative(v) {
},
toNative(v) {
throw new Error("invalid operation");
}
},
pointer: {
fromNative(v) {
return new BNativePointer(v);
@@ -338,6 +345,28 @@ const marshalers: { [type: string]: Marshaler } = {
return BigInt(v);
}
},
uint: {
fromNative(v) {
return Number(v);
},
toNative(v) {
if (typeof v !== "number") {
throw new Error("expected an integer");
}
return BigInt(v);
}
},
size_t: {
fromNative(v) {
return new BUInt64(v);
},
toNative(v) {
if (typeof v === "number") {
return BigInt(v);
}
return v.$v;
}
},
};
function getMarshalerFor(t: NativeFunctionReturnType | NativeFunctionArgumentType): Marshaler {
+114 -9
View File
@@ -42,8 +42,6 @@ namespace Frida {
private Gee.Queue<QuickJS.Value?> tick_callbacks = new Gee.ArrayQueue<QuickJS.Value?> ();
private Barebone.Allocation? cached_landing_zone; // TODO: Deallocate on teardown.
private Gee.Set<Barebone.Callback> native_callbacks = new Gee.HashSet<Barebone.Callback> ();
private static QuickJS.ClassID cpu_context_class;
@@ -56,6 +54,9 @@ namespace Frida {
private static QuickJS.ClassExoticMethods invocation_args_exotic_methods;
private static QuickJS.ClassID invocation_retval_class;
private static QuickJS.ClassID c_module_class;
private Gee.Set<Barebone.CModule> c_modules = new Gee.HashSet<Barebone.CModule> ();
private static QuickJS.ClassID rust_module_class;
private Gee.Set<Barebone.RustModule> rust_modules = new Gee.HashSet<Barebone.RustModule> ();
@@ -155,6 +156,7 @@ namespace Frida {
var memory_obj = ctx.make_object ();
add_cfunc (memory_obj, "alloc", on_memory_alloc, 1);
add_cfunc (memory_obj, "protect", on_memory_protect, 3);
add_cfunc (memory_obj, "scan", on_memory_scan, 4);
add_cfunc (memory_obj, "scanSync", on_memory_scan_sync, 3);
global.set_property_str (ctx, "Memory", memory_obj);
@@ -206,6 +208,17 @@ namespace Frida {
ir.class_name = "InvocationReturnValue";
rt.make_class (QuickJS.make_class_id (ref invocation_retval_class), ir);
QuickJS.ClassDef cm;
cm.class_name = "CModule";
cm.finalizer = on_c_module_finalize;
rt.make_class (QuickJS.make_class_id (ref c_module_class), cm);
var cm_proto = ctx.make_object ();
add_cfunc (cm_proto, "dispose", on_c_module_dispose, 0);
ctx.set_class_proto (c_module_class, cm_proto);
var cm_ctor = ctx.make_cfunction2 (on_c_module_construct, cm.class_name, 1, constructor, 0);
cm_ctor.set_constructor (ctx, cm_proto);
global.set_property_str (ctx, "CModule", cm_ctor);
QuickJS.ClassDef rm;
rm.class_name = "RustModule";
rm.finalizer = on_rust_module_finalize;
@@ -672,11 +685,7 @@ namespace Frida {
private async void do_invoke (uint64 impl, uint64[] args, Promise<uint64?> promise) {
try {
if (cached_landing_zone == null)
cached_landing_zone = yield services.allocator.allocate (4, 1, io_cancellable);
uint64 retval = yield services.machine.invoke (impl, args, cached_landing_zone.virtual_address,
io_cancellable);
uint64 retval = yield services.machine.invoke (impl, args, io_cancellable);
promise.resolve (retval);
} catch (GLib.Error e) {
@@ -1124,6 +1133,41 @@ namespace Frida {
}
}
private static QuickJS.Value on_memory_protect (QuickJS.Context ctx, QuickJS.Value this_val, QuickJS.Value[] argv) {
BareboneScript * script = ctx.get_opaque ();
uint64 address;
if (!script->unparse_native_pointer (argv[0], out address))
return QuickJS.Exception;
uint size;
if (!script->unparse_uint (argv[1], out size))
return QuickJS.Exception;
Gum.PageProtection prot;
if (!script->unparse_page_protection (argv[2], out prot))
return QuickJS.Exception;
var promise = new Promise<bool?> ();
script->do_memory_protect.begin (address, size, prot, promise);
bool? result = script->process_events_until_ready (promise);
if (result == null)
return QuickJS.Exception;
return ctx.make_bool (result);
}
private async void do_memory_protect (uint64 address, size_t size, Gum.PageProtection prot, Promise<bool?> promise) {
try {
yield services.machine.protect_pages (address, size, prot, io_cancellable);
promise.resolve (true);
} catch (GLib.Error e) {
promise.resolve (false);
}
}
private static QuickJS.Value on_memory_scan (QuickJS.Context ctx, QuickJS.Value this_val, QuickJS.Value[] argv) {
BareboneScript * script = ctx.get_opaque ();
@@ -1791,6 +1835,67 @@ namespace Frida {
return QuickJS.Undefined;
}
private static QuickJS.Value on_c_module_construct (QuickJS.Context ctx, QuickJS.Value new_target,
QuickJS.Value[] argv) {
BareboneScript * script = ctx.get_opaque ();
Bytes blob;
if (!script->unparse_bytes (argv[0], out blob))
return QuickJS.Exception;
var promise = new Promise<Barebone.CModule> ();
script->load_c_module.begin (blob, promise);
Barebone.CModule? mod = script->process_events_until_ready (promise);
if (mod == null)
return QuickJS.Exception;
var proto = new_target.get_property (ctx, script->prototype_key);
var wrapper = ctx.make_object_with_proto_and_class (proto, c_module_class);
ctx.free_value (proto);
wrapper.set_opaque (mod);
script->c_modules.add (mod);
foreach (var e in mod.exports)
wrapper.set_property_str (ctx, e.name, script->make_native_pointer (e.address));
mod.console_output.connect (script->on_console_output);
return wrapper;
}
private async void load_c_module (Bytes blob, Promise<Barebone.CModule> promise) {
try {
var mod = yield new Barebone.CModule.from_blob (blob, services.machine, services.allocator, io_cancellable);
promise.resolve (mod);
} catch (GLib.Error e) {
promise.reject (e);
}
}
private static void on_c_module_finalize (QuickJS.Runtime rt, QuickJS.Value val) {
Barebone.CModule * mod = val.get_opaque (c_module_class);
if (mod == null)
return;
BareboneScript * script = rt.get_opaque ();
script->c_modules.remove (mod);
}
private static QuickJS.Value on_c_module_dispose (QuickJS.Context ctx, QuickJS.Value this_val, QuickJS.Value[] argv) {
Barebone.CModule * mod = this_val.get_opaque (c_module_class);
if (mod != null) {
this_val.set_opaque (null);
BareboneScript * script = ctx.get_opaque ();
script->c_modules.remove (mod);
}
return QuickJS.Undefined;
}
private static QuickJS.Value on_rust_module_construct (QuickJS.Context ctx, QuickJS.Value new_target,
QuickJS.Value[] argv) {
BareboneScript * script = ctx.get_opaque ();
@@ -1860,7 +1965,7 @@ namespace Frida {
foreach (var e in mod.exports)
wrapper.set_property_str (ctx, e.name, script->make_native_pointer (e.address));
mod.console_output.connect (script->on_rust_module_console_output);
mod.console_output.connect (script->on_console_output);
return wrapper;
}
@@ -1898,7 +2003,7 @@ namespace Frida {
return QuickJS.Undefined;
}
private void on_rust_module_console_output (string message) {
private void on_console_output (string message) {
var builder = new Json.Builder ();
builder
.begin_object ()
+4 -4
View File
@@ -33,7 +33,7 @@
"@frida/url": "^1.0.2",
"@frida/util": "^1.0.3",
"@frida/vm": "^2.0.0",
"@types/frida-gum": "19.0.0",
"@types/frida-gum": "19.0.1",
"@types/node": "18.19.103",
"frida-fs": "7.0.0"
}
@@ -248,9 +248,9 @@
"license": "MIT"
},
"node_modules/@types/frida-gum": {
"version": "19.0.0",
"resolved": "https://registry.npmjs.org/@types/frida-gum/-/frida-gum-19.0.0.tgz",
"integrity": "sha512-qViK1KwvPEAkajwSUv0wpZvZLiX8xO4JFFCh8dfYZfzSyOEfoE0KliCP/nJSKIKG6N3hXnPowrvPufjs5fLKAA==",
"version": "19.0.1",
"resolved": "https://registry.npmjs.org/@types/frida-gum/-/frida-gum-19.0.1.tgz",
"integrity": "sha512-mp8BpWWkQFJH86ZN5uXZuDiA7KY/+jDknrw0a06x0/+F5ucPwctHrCuV6iT+LLCp/GyICc36ssedF33B1WoLsw==",
"license": "MIT"
},
"node_modules/@types/node": {
+1 -1
View File
@@ -29,7 +29,7 @@
"@frida/url": "^1.0.2",
"@frida/util": "^1.0.3",
"@frida/vm": "^2.0.0",
"@types/frida-gum": "19.0.0",
"@types/frida-gum": "19.0.1",
"@types/node": "18.19.103",
"frida-fs": "7.0.0"
}
+1 -1
View File
@@ -192,7 +192,7 @@ namespace Frida {
}
private void on_server_connection (IOStream connection, SocketAddress remote_address, DynamicInterface? dynamic_iface) {
#if IOS || TVOS
#if HAVE_LOCAL_BACKEND && (IOS || TVOS)
/*
* We defer the launchd injection until the first connection is established in order
* to avoid bootloops on unsupported jailbreaks.
+8 -8
View File
@@ -80,7 +80,7 @@
goto bsd_failure; \
}
#if defined (HAVE_IOS) || defined (HAVE_TVOS)
#if defined (HAVE_IOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
# define CORE_FOUNDATION "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation"
#else
# define CORE_FOUNDATION "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
@@ -390,7 +390,7 @@ static gboolean frida_spawn_instance_is_libc_initialized (FridaSpawnInstance * s
static void frida_spawn_instance_set_libc_initialized (FridaSpawnInstance * self);
static kern_return_t frida_spawn_instance_create_dyld_data (FridaSpawnInstance * self);
static void frida_spawn_instance_destroy_dyld_data (FridaSpawnInstance * self);
#if defined (HAVE_IOS) || defined (HAVE_TVOS)
#if defined (HAVE_IOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
static gboolean frida_pick_ios_tvos_bootstrapper (GumModule * module, gpointer user_data);
#endif
static void frida_spawn_instance_unset_helpers (FridaSpawnInstance * self);
@@ -971,7 +971,7 @@ invalid_pid:
}
}
#if defined (HAVE_IOS) || defined (HAVE_TVOS)
#if defined (HAVE_IOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
#import "springboard.h"
@@ -2669,7 +2669,7 @@ frida_inject_instance_on_mach_thread_dead (void * context)
self->agent_context->posix_thread = MACH_PORT_NULL;
#if defined (HAVE_IOS) || defined (HAVE_TVOS)
#if defined (HAVE_IOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
port_might_be_guarded = gum_darwin_check_xnu_version (7938, 0, 0);
#else
port_might_be_guarded = FALSE;
@@ -3284,7 +3284,7 @@ next_phase:
return TRUE;
case FRIDA_BREAKPOINT_DLOPEN_BOOTSTRAPPER:
#if defined (HAVE_IOS) || defined (HAVE_TVOS)
#if defined (HAVE_IOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
if (self->bootstrapper_name != 0)
{
frida_spawn_instance_set_libc_initialized (self);
@@ -3577,7 +3577,7 @@ frida_spawn_instance_create_dyld_data (FridaSpawnInstance * self)
if (!gum_darwin_query_ptrauth_support (self->task, &ptrauth_support))
return KERN_FAILURE;
#if defined (HAVE_IOS) || defined (HAVE_TVOS)
#if defined (HAVE_IOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
gum_darwin_enumerate_modules (self->task, frida_pick_ios_tvos_bootstrapper, &data);
#endif
@@ -3655,7 +3655,7 @@ frida_spawn_instance_destroy_dyld_data (FridaSpawnInstance * self)
self->dyld_data = 0;
}
#if defined (HAVE_IOS) || defined (HAVE_TVOS)
#if defined (HAVE_IOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
static gboolean
frida_pick_ios_tvos_bootstrapper (GumModule * module, gpointer user_data)
@@ -5449,7 +5449,7 @@ frida_set_hardware_single_step (gpointer debug_state, GumDarwinUnifiedThreadStat
static gboolean
frida_is_hardware_breakpoint_support_working (void)
{
#if defined (HAVE_IOS) || defined (HAVE_TVOS)
#if defined (HAVE_IOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
static gsize cached_result = 0;
if (g_once_init_enter (&cached_result))
+1 -1
View File
@@ -1,6 +1,6 @@
#include "frida-helper-backend.h"
#if defined (HAVE_IOS) || defined (HAVE_TVOS)
#if defined (HAVE_IOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
# include "policyd.h"
# include "substituted-client.h"
# include "substituted2-client.h"
+12 -12
View File
@@ -16,11 +16,11 @@
# endif
#endif
#if defined (HAVE_IOS) || defined (HAVE_TVOS)
#if defined (HAVE_IOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
# import "springboard.h"
#endif
#if defined (HAVE_WATCHOS) || defined (HAVE_TVOS)
#if defined (HAVE_WATCHOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
# import <Foundation/Foundation.h>
#endif
@@ -35,7 +35,7 @@ struct _FridaEnumerateApplicationsOperation
{
FridaScope scope;
GHashTable * process_by_identifier;
#if defined (HAVE_IOS) || defined (HAVE_TVOS)
#if defined (HAVE_IOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
FridaSpringboardApi * api;
#endif
@@ -45,14 +45,14 @@ struct _FridaEnumerateApplicationsOperation
struct _FridaEnumerateProcessesOperation
{
FridaScope scope;
#if defined (HAVE_IOS) || defined (HAVE_TVOS)
#if defined (HAVE_IOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
FridaSpringboardApi * api;
#endif
GArray * result;
};
#if defined (HAVE_IOS) || defined (HAVE_TVOS)
#if defined (HAVE_IOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
static void frida_collect_application_info_from_id_cstring (const gchar * identifier, FridaEnumerateApplicationsOperation * op);
static void frida_collect_application_info_from_id_nsstring (NSString * identifier, FridaEnumerateApplicationsOperation * op);
#endif
@@ -60,13 +60,13 @@ static void frida_collect_application_info_from_id_nsstring (NSString * identifi
static void frida_collect_process_info_from_pid (guint pid, FridaEnumerateProcessesOperation * op);
static void frida_collect_process_info_from_kinfo (struct kinfo_proc * process, FridaEnumerateProcessesOperation * op);
#if defined (HAVE_MACOS) || defined (HAVE_IOS) || defined (HAVE_TVOS)
#if defined (HAVE_MACOS) || defined (HAVE_IOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
static void frida_add_app_id (GHashTable * parameters, NSString * identifier);
#endif
#if defined (HAVE_MACOS)
static void frida_add_app_icons (GHashTable * parameters, NSImage * image);
#elif defined (HAVE_IOS) || defined (HAVE_TVOS)
#elif defined (HAVE_IOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
static void frida_add_app_metadata (GHashTable * parameters, NSString * identifier, FridaSpringboardApi * api);
static void frida_add_app_state (GHashTable * parameters, guint pid, FridaSpringboardApi * api);
static void frida_add_app_icons (GHashTable * parameters, NSString * identifier);
@@ -100,7 +100,7 @@ frida_system_enumerate_applications (FridaApplicationQueryOptions * options, int
return NULL;
}
#elif defined (HAVE_IOS) || defined (HAVE_TVOS)
#elif defined (HAVE_IOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
void
frida_system_get_frontmost_application (FridaFrontmostQueryOptions * options, FridaHostApplicationInfo * result, GError ** error)
@@ -306,7 +306,7 @@ frida_system_enumerate_processes (FridaProcessQueryOptions * options, int * resu
NSAutoreleasePool * pool;
op.scope = frida_process_query_options_get_scope (options);
#if defined (HAVE_IOS) || defined (HAVE_TVOS)
#if defined (HAVE_IOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
op.api = _frida_get_springboard_api ();
#endif
@@ -395,7 +395,7 @@ frida_collect_process_info_from_kinfo (struct kinfo_proc * process, FridaEnumera
frida_add_app_icons (info.parameters, app.icon);
}
}
#elif defined (HAVE_IOS) || defined (HAVE_TVOS)
#elif defined (HAVE_IOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
{
FridaSpringboardApi * api = op->api;
NSString * identifier;
@@ -469,7 +469,7 @@ frida_temporary_directory_get_system_tmp (void)
}
}
#if defined (HAVE_MACOS) || defined (HAVE_IOS) || defined (HAVE_TVOS)
#if defined (HAVE_MACOS) || defined (HAVE_IOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
static void
frida_add_app_id (GHashTable * parameters, NSString * identifier)
@@ -541,7 +541,7 @@ frida_add_app_icons (GHashTable * parameters, NSImage * image)
g_hash_table_insert (parameters, g_strdup ("icons"), g_variant_ref_sink (g_variant_builder_end (&builder)));
}
#elif defined (HAVE_IOS) || defined (HAVE_TVOS)
#elif defined (HAVE_IOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
static void
frida_add_app_metadata (GHashTable * parameters, NSString * identifier, FridaSpringboardApi * api)
+1 -1
View File
@@ -58,7 +58,7 @@ def main(argv):
for asset in {embedded_agent, embedded_dbghelp, embedded_symsrv}:
asset.write_bytes(b"")
embedded_assets += [asset]
elif host_os in {"macos", "ios", "watchos", "tvos"}:
elif host_os in {"macos", "ios", "watchos", "tvos", "xros"}:
embedded_agent = priv_dir / "frida-agent.dylib"
if agent_modern is not None and agent_legacy is not None:
subprocess.run(lipo + [agent_modern, agent_legacy, "-create", "-output", embedded_agent],
+1 -1
View File
@@ -36,7 +36,7 @@ def main(argv):
embedded_helper = priv_dir / f"frida-helper-{missing_arch}.exe"
embedded_helper.write_bytes(b"")
embedded_assets += [embedded_helper]
elif host_os in {"macos", "ios", "watchos", "tvos"}:
elif host_os in {"macos", "ios", "watchos", "tvos", "xros"}:
embedded_helper = priv_dir / "frida-helper"
if helper_modern is not None and helper_legacy is not None:
+41 -6
View File
@@ -1626,7 +1626,9 @@ frida_run_to_entrypoint (pid_t pid, GError ** error)
ret = frida_get_regs (pid, &regs);
CHECK_OS_RESULT (ret, ==, 0, "frida_get_regs");
#if defined (HAVE_I386) && GLIB_SIZEOF_VOID_P == 8
#if defined (HAVE_I386) && GLIB_SIZEOF_VOID_P == 4
regs.r_eip = entrypoint;
#elif defined (HAVE_I386) && GLIB_SIZEOF_VOID_P == 8
regs.r_rip = entrypoint;
#elif defined (HAVE_ARM64)
regs.elr = entrypoint;
@@ -1823,7 +1825,33 @@ frida_remote_call (pid_t pid, GumAddress func, const GumAddress * args, gint arg
ret = frida_get_regs (pid, &regs);
CHECK_OS_RESULT (ret, ==, 0, "frida_get_regs");
#if defined (HAVE_I386) && GLIB_SIZEOF_VOID_P == 8
#if defined (HAVE_I386) && GLIB_SIZEOF_VOID_P == 4
regs.r_esp -= FRIDA_RED_ZONE_SIZE;
regs.r_esp -= (regs.r_esp - (args_length * 4)) % FRIDA_STACK_ALIGNMENT;
regs.r_eip = func;
if (args_length != 0)
{
guintptr * stack_args;
stack_args = g_newa (guintptr, args_length);
for (i = 0; i != args_length; i++)
stack_args[i] = args[i];
regs.r_esp -= args_length * sizeof (guintptr);
if (!frida_remote_write (pid, regs.r_esp, stack_args, args_length * sizeof (guintptr), error))
goto propagate_error;
}
{
guintptr dummy_return_address = FRIDA_DUMMY_RETURN_ADDRESS;
regs.r_esp -= 4;
if (!frida_remote_write (pid, regs.r_esp, &dummy_return_address, sizeof (dummy_return_address), error))
goto propagate_error;
}
#elif defined (HAVE_I386) && GLIB_SIZEOF_VOID_P == 8
regs.r_rsp -= FRIDA_RED_ZONE_SIZE;
regs.r_rsp -= (regs.r_rsp - (MAX (args_length - 6, 0) * 8)) % FRIDA_STACK_ALIGNMENT;
@@ -1905,7 +1933,9 @@ frida_remote_call (pid_t pid, GumAddress func, const GumAddress * args, gint arg
ret = frida_get_regs (pid, &regs);
CHECK_OS_RESULT (ret, ==, 0, "frida_get_regs");
#if defined (HAVE_I386) && GLIB_SIZEOF_VOID_P == 8
#if defined (HAVE_I386) && GLIB_SIZEOF_VOID_P == 4
*retval = regs.r_eax;
#elif defined (HAVE_I386) && GLIB_SIZEOF_VOID_P == 8
*retval = regs.r_rax;
#elif defined (HAVE_ARM64)
*retval = regs.x[0];
@@ -1924,7 +1954,7 @@ os_failure:
failed_operation, g_strerror (errno));
return FALSE;
}
#if defined (HAVE_I386) && GLIB_SIZEOF_VOID_P == 8
#ifdef HAVE_I386
propagate_error:
{
return FALSE;
@@ -1943,7 +1973,10 @@ frida_remote_exec (pid_t pid, GumAddress remote_address, GumAddress remote_stack
ret = frida_get_regs (pid, &regs);
CHECK_OS_RESULT (ret, ==, 0, "frida_get_regs");
#if defined (HAVE_I386) && GLIB_SIZEOF_VOID_P == 8
#if defined (HAVE_I386) && GLIB_SIZEOF_VOID_P == 4
regs.r_eip = remote_address;
regs.r_esp = remote_stack;
#elif defined (HAVE_I386) && GLIB_SIZEOF_VOID_P == 8
regs.r_rip = remote_address;
regs.r_rsp = remote_stack;
#elif defined (HAVE_ARM64)
@@ -1967,7 +2000,9 @@ frida_remote_exec (pid_t pid, GumAddress remote_address, GumAddress remote_stack
ret = frida_get_regs (pid, &regs);
CHECK_OS_RESULT (ret, ==, 0, "frida_get_regs");
#if defined (HAVE_I386) && GLIB_SIZEOF_VOID_P == 8
#if defined (HAVE_I386) && GLIB_SIZEOF_VOID_P == 4
*result = regs.r_eax;
#elif defined (HAVE_I386) && GLIB_SIZEOF_VOID_P == 8
*result = regs.r_rax;
#elif defined (HAVE_ARM64)
*result = regs.x[0];
+82
View File
@@ -0,0 +1,82 @@
[CCode (gir_namespace = "FridaFruity", gir_version = "1.0")]
namespace Frida.DebuggerMappings {
internal async void spray_pages (GDB.Client gdb, uint64 address, size_t size, size_t page_size, Cancellable? cancellable)
throws Error, IOError {
int n_pages = (int) (size / page_size);
if (n_pages == 0)
throw new Error.INVALID_ARGUMENT ("Expected one or more pages");
var builder = gdb.make_packet_builder_sized (64);
Future<bool>? last_write = null;
for (int i = 0; i < n_pages; i += 2) {
bool is_last = (i + 2 >= n_pages);
uint64 last_byte_addr = address + ((uint64) i * page_size) + page_size - 1;
size_t write_count = is_last ? 1 : 2;
builder
.append_c ('M')
.append_address (last_byte_addr)
.append_c (',')
.append_size (write_count)
.append_c (':')
.append_escaped ((write_count == 2) ? "0000" : "00");
var request = new Promise<bool> ();
gdb.perform_execute.begin (builder.build (), cancellable, request);
builder.reset ();
if (is_last)
last_write = request.future;
}
yield last_write.wait_async (cancellable);
}
internal async void handle_page_plan (GDB.Client gdb, uint64 address, size_t size, size_t page_size, Cancellable? cancellable)
throws Error, IOError {
var plan = new BufferReader (yield gdb.read_buffer (address, size, cancellable));
var n_blocks = plan.read_uint32 ();
if (n_blocks == 0)
return;
var builder = gdb.make_packet_builder_sized (64);
Future<bool>? last_write = null;
for (uint32 i = 0; i != n_blocks; i++) {
uint64 start = plan.read_pointer ();
uint32 count = plan.read_uint32 ();
for (size_t j = 0; j < count; j += 2) {
bool is_last = (j + 2 >= count) && (i == n_blocks - 1);
uint64 last_byte_addr = start + ((uint64) j * page_size) + page_size - 1;
size_t write_count = size_t.min (2, count - j);
builder
.append_c ('M')
.append_address (last_byte_addr)
.append_c (',')
.append_size (write_count)
.append_c (':')
.append_hexbyte (plan.read_uint8 ());
if (write_count == 2)
builder.append_hexbyte (plan.read_uint8 ());
var request = new Promise<bool> ();
gdb.perform_execute.begin (builder.build (), cancellable, request);
builder.reset ();
if (is_last)
last_write = request.future;
}
}
yield last_write.wait_async (cancellable);
}
}
+203 -19
View File
@@ -808,14 +808,17 @@ namespace Frida {
var lldb = yield start_lldb_service (cancellable);
var process = yield lldb.launch (argv, launch_options, cancellable);
if (process.observed_state == ALREADY_RUNNING) {
yield lldb.kill (cancellable);
try {
yield lldb.kill (cancellable);
} catch (Error e) {
}
yield lldb.close (cancellable);
lldb = yield start_lldb_service (cancellable);
process = yield lldb.launch (argv, launch_options, cancellable);
}
var session = new LLDBSession (lldb, process, gadget_path, device);
var session = new LLDBSession (lldb, process, gadget_path, ExceptionHandlingStatus.LIMITED, device);
add_lldb_session (session);
return process.pid;
@@ -833,8 +836,13 @@ namespace Frida {
public async void resume (uint pid, Cancellable? cancellable) throws Error, IOError {
var session = lldb_sessions[pid];
if (session != null) {
yield session.resume (cancellable);
return;
foreach (var entry in gadget_entries.values) {
if (entry.pid == pid) {
yield entry.resume (cancellable);
return;
}
}
assert_not_reached ();
}
var server = yield get_remote_server (cancellable);
@@ -867,7 +875,7 @@ namespace Frida {
var lldb = yield start_lldb_service (cancellable);
var process = yield lldb.attach_by_pid (pid, cancellable);
lldb_session = new LLDBSession (lldb, process, null, device);
lldb_session = new LLDBSession (lldb, process, null, ExceptionHandlingStatus.FULL, device);
yield lldb_session.kill (cancellable);
yield lldb_session.close (cancellable);
} catch (Error e) {
@@ -903,7 +911,7 @@ namespace Frida {
string? gadget_path = null;
lldb_session = new LLDBSession (lldb, process, gadget_path, device);
lldb_session = new LLDBSession (lldb, process, gadget_path, ExceptionHandlingStatus.LIMITED, device);
add_lldb_session (lldb_session);
var gadget_details = yield lldb_session.query_gadget_details (cancellable);
@@ -955,7 +963,7 @@ namespace Frida {
}
var local_session_id = AgentSessionId.generate ();
var gadget_entry = new GadgetEntry (local_session_id, host_session, connection);
var gadget_entry = new GadgetEntry (local_session_id, host_session, connection, pid);
gadget_entry.detached.connect (on_gadget_entry_detached);
gadget_entries[local_session_id] = gadget_entry;
agent_sessions[local_session_id] = new AgentSessionEntry (remote_session_id, connection);
@@ -1139,9 +1147,22 @@ namespace Frida {
}
private void on_gadget_entry_detached (GadgetEntry entry, SessionDetachReason reason) {
detach_entry.begin (entry, reason);
}
private async void detach_entry (GadgetEntry entry, SessionDetachReason reason) throws Error, IOError {
AgentSessionId id = entry.local_session_id;
var no_crash = CrashInfo.empty ();
var lldb_session = lldb_sessions[entry.pid];
if (lldb_session != null) {
remove_lldb_session (lldb_session);
if (reason == SessionDetachReason.APPLICATION_REQUESTED)
yield entry.detach_lldb (lldb_session, io_cancellable);
else
yield lldb_session.close (io_cancellable);
}
gadget_entries.unset (id);
agent_sessions.unset (id);
@@ -1375,6 +1396,7 @@ namespace Frida {
private class LLDBSession : Object {
public signal void closed ();
public signal void detached ();
public signal void output (Bytes bytes);
public LLDB.Client lldb {
@@ -1397,14 +1419,27 @@ namespace Frida {
construct;
}
private Promise<Fruity.Injector.GadgetDetails>? gadget_request;
public ExceptionHandlingStatus exception_handling_status {
get;
construct;
}
public LLDBSession (LLDB.Client lldb, LLDB.Process process, string? gadget_path,
private Promise<Fruity.Injector.GadgetDetails>? gadget_request;
private ulong? exception_handler;
private string? main_thread_id;
private bool resumed = false;
private Cancellable io_cancellable = new Cancellable ();
private const size_t PAGE_SIZE = 0x4000;
public LLDBSession (LLDB.Client lldb, LLDB.Process process, string? gadget_path, ExceptionHandlingStatus ehs,
HostChannelProvider channel_provider) {
Object (
lldb: lldb,
process: process,
gadget_path: gadget_path,
exception_handling_status: ehs,
channel_provider: channel_provider
);
}
@@ -1415,20 +1450,90 @@ namespace Frida {
}
~LLDBSession () {
detach_exception_handler ();
lldb.closed.disconnect (on_lldb_closed);
lldb.console_output.disconnect (on_lldb_console_output);
}
public async void close (Cancellable? cancellable) throws IOError {
io_cancellable.cancel ();
detach_exception_handler ();
yield lldb.close (cancellable);
}
public async void resume (Cancellable? cancellable) throws Error, IOError {
yield lldb.detach (cancellable);
private async void handle_exception (GDB.Exception exception) throws Error, IOError {
var e = (Frida.LLDB.Exception) exception;
var sig = (LLDB.Signal) e.signum;
var medata = e.medata;
if (sig == SIGTRAP && e.metype == EXC_BREAKPOINT && medata.size == 2) {
uint64 x1 = e.context["x1"];
uint64 x2 = e.context["x2"];
var action = (GadgetBreakpointAction) e.context["x3"];
if (x1 == x2 == 1337) {
uint64 pc = e.context["pc"];
var thread = e.thread;
yield thread.write_register ("pc", pc + 4, io_cancellable);
switch (action) {
case RESUME: {
resumed = true;
yield lldb.continue (io_cancellable);
return;
}
case DETACH: {
yield lldb.detach (io_cancellable);
detached ();
break;
}
case PAGE_PLAN: {
var plan_size = (size_t) e.context["x4"];
var plan_address = e.context["x5"];
yield DebuggerMappings.handle_page_plan (lldb, plan_address, plan_size,
PAGE_SIZE, io_cancellable);
yield thread.write_register ("x0", 0x1337, io_cancellable);
if (resumed)
yield lldb.continue (io_cancellable);
else
yield continue_gadget_threads (io_cancellable);
return;
}
default:
break;
}
}
}
detach_exception_handler ();
yield lldb.close (io_cancellable);
}
private async void continue_gadget_threads (Cancellable? cancellable) throws Error, IOError {
var gadget_threads = new Gee.ArrayList<LLDB.Thread> ();
yield lldb.enumerate_threads (thread => {
if (thread.id != main_thread_id)
gadget_threads.add (thread);
return true;
}, cancellable);
yield lldb.continue_specific_threads (gadget_threads, cancellable);
}
public async void kill (Cancellable? cancellable) throws Error, IOError {
yield lldb.kill (cancellable);
detach_exception_handler ();
if (exception_handling_status == FULL)
yield lldb.kill (cancellable);
else
yield lldb.close (cancellable);
}
public async Fruity.Injector.GadgetDetails query_gadget_details (Cancellable? cancellable) throws Error, IOError {
@@ -1461,13 +1566,26 @@ namespace Frida {
: Gum.PtrauthSupport.UNSUPPORTED;
var module = new Gum.DarwinModule.from_file (path, Gum.CpuType.ARM64, ptrauth_support);
var details = yield Fruity.Injector.inject ((owned) module, lldb, channel_provider, cancellable);
Fruity.Injector.Transaction transaction =
yield Fruity.Injector.inject ((owned) module, lldb, channel_provider, cancellable);
Fruity.Injector.GadgetDetails gadget = transaction.gadget;
main_thread_id = transaction.main_thread_id;
gadget_request.resolve (details);
exception_handler = lldb.notify["exception"].connect ((obj, pspec) => {
var exception = lldb.exception;
if (exception != null)
handle_exception.begin (exception);
});
return details;
yield transaction.commit (cancellable);
gadget_request.resolve (gadget);
return gadget;
} catch (GLib.Error e) {
var api_error = new Error.NOT_SUPPORTED ("%s", e.message);
var api_error = (e is Error)
? (Error) e
: new Error.NOT_SUPPORTED ("%s", e.message);
gadget_request.reject (api_error);
gadget_request = null;
@@ -1476,6 +1594,13 @@ namespace Frida {
}
}
private void detach_exception_handler () {
if (exception_handler != null) {
lldb.disconnect (exception_handler);
exception_handler = null;
}
}
private void on_lldb_closed () {
closed ();
}
@@ -1485,6 +1610,11 @@ namespace Frida {
}
}
private enum ExceptionHandlingStatus {
FULL,
LIMITED,
}
private class GadgetEntry : Object {
public signal void detached (SessionDetachReason reason);
@@ -1503,13 +1633,20 @@ namespace Frida {
construct;
}
private Promise<bool>? close_request;
public uint pid {
get;
construct;
}
public GadgetEntry (AgentSessionId local_session_id, HostSession host_session, DBusConnection connection) {
private Promise<bool>? close_request;
private Promise<bool>? detach_request;
public GadgetEntry (AgentSessionId local_session_id, HostSession host_session, DBusConnection connection, uint pid) {
Object (
local_session_id: local_session_id,
host_session: host_session,
connection: connection
connection: connection,
pid: pid
);
}
@@ -1550,6 +1687,48 @@ namespace Frida {
close_request.resolve (true);
}
public async void resume (Cancellable? cancellable) throws Error, IOError {
try {
GadgetSession session = yield connection.get_proxy (null, ObjectPath.GADGET_SESSION,
DO_NOT_LOAD_PROPERTIES, cancellable);
yield session.break_and_resume (cancellable);
} catch (GLib.Error e) {
throw_dbus_error (e);
}
}
public async void detach_lldb (LLDBSession lldb_session, Cancellable? cancellable) throws Error, IOError {
while (detach_request != null) {
try {
yield detach_request.future.wait_async (cancellable);
return;
} catch (Error e) {
assert_not_reached ();
} catch (IOError e) {
cancellable.set_error_if_cancelled ();
}
}
detach_request = new Promise<bool> ();
try {
GadgetSession session = yield connection.get_proxy (null, ObjectPath.GADGET_SESSION,
DO_NOT_LOAD_PROPERTIES, cancellable);
lldb_session.detached.connect (on_lldb_session_detached);
yield session.break_and_detach (cancellable);
yield detach_request.future.wait_async (cancellable);
} catch (GLib.Error e) {
detach_request.reject (e);
throw_dbus_error (e);
} finally {
lldb_session.detached.disconnect (on_lldb_session_detached);
detach_request = null;
}
}
private void on_connection_closed (DBusConnection connection, bool remote_peer_vanished, GLib.Error? error) {
if (close_request == null) {
close_request = new Promise<bool> ();
@@ -1562,6 +1741,11 @@ namespace Frida {
private void on_session_detached (AgentSessionId id, SessionDetachReason reason) {
detached (reason);
}
private void on_lldb_session_detached () {
if (detach_request != null)
detach_request.resolve (true);
}
}
private class AgentSessionEntry {
+11 -5
View File
@@ -24,17 +24,21 @@ struct _FridaUploadApi
int (* listen) (int socket, int backlog);
int (* getsockname) (int socket, struct sockaddr * restrict address, socklen_t * restrict address_len);
int (* accept) (int socket, struct sockaddr * restrict address, socklen_t * restrict address_len);
int (* close) (int fd);
ssize_t (* read) (int fd, void * buf, size_t n);
ssize_t (* write) (int fd, const void *buf, size_t n);
int (* getpagesize) (void);
int (* mprotect) (void * addr, size_t len, int prot);
void (* sys_icache_invalidate) (void * start, size_t len);
void (* sys_dcache_flush) (void * start, size_t len);
mach_port_t (* _mach_task_self) (void);
kern_return_t (* mach_vm_allocate) (vm_map_t target, mach_vm_address_t * address, mach_vm_size_t size, int flags);
kern_return_t (* mach_vm_deallocate) (vm_map_t target, mach_vm_address_t address, mach_vm_size_t size);
kern_return_t (* vm_remap) (vm_map_t target_task, vm_address_t * target_address, vm_size_t size, vm_address_t mask, int flags,
vm_map_t src_task, vm_address_t src_address, boolean_t copy, vm_prot_t * cur_protection, vm_prot_t * max_protection,
vm_inherit_t inheritance);
void * (* dlopen) (const char * path, int mode);
void * (* dlsym) (void * handle, const char * symbol);
int (* mprotect) (void * addr, size_t len, int prot);
int (* close) (int fd);
int * (* get_errno_storage) (void);
};
@@ -46,18 +50,20 @@ struct _FridaUploadApi
listen, \
getsockname, \
accept, \
close, \
read, \
write, \
getpagesize, \
mprotect, \
sys_icache_invalidate, \
sys_dcache_flush, \
dlsym (RTLD_DEFAULT, "mach_task_self"), \
mach_vm_allocate, \
mach_vm_deallocate, \
vm_remap, \
dlopen, \
dlsym, \
mprotect, \
close, \
__error \
__error, \
}
#define FRIDA_RX_BUFFER_SIZE (1024 * 1024)
+1 -1
View File
@@ -67,7 +67,7 @@ failure:
if (fd != -1)
api->close (fd);
return ((uint64_t) error_code << 56);
return ((uint64_t) error_code << 57);
}
}
+34 -1
View File
@@ -258,6 +258,7 @@ int64_t
frida_receive (int listener_fd, uint64_t session_id_top, uint64_t session_id_bottom, const char * apple[], const FridaUploadApi * api)
{
int result = 0;
mach_port_t task;
bool expecting_client;
int res;
struct sockaddr_in addr;
@@ -265,6 +266,8 @@ frida_receive (int listener_fd, uint64_t session_id_top, uint64_t session_id_bot
int client_fd;
uint32_t ACK_MAGIC = 0xac4ac4ac;
task = api->_mach_task_self ();
expecting_client = true;
do
@@ -307,16 +310,33 @@ frida_receive (int listener_fd, uint64_t session_id_top, uint64_t session_id_bot
{
uint64_t address;
uint32_t size;
vm_address_t writable_address;
vm_prot_t cur_prot, max_prot;
size_t n;
FRIDA_READ_VALUE (address);
FRIDA_READ_VALUE (size);
success = frida_read_chunk (client_fd, (void *) address, size, &n, api);
writable_address = 0;
success = api->vm_remap (task, &writable_address, size, 0, VM_FLAGS_ANYWHERE, task, address, FALSE, &cur_prot, &max_prot,
VM_INHERIT_NONE) == 0;
if (!success)
break;
success = api->mprotect ((void *) writable_address, size, VM_PROT_READ | VM_PROT_WRITE) == 0;
if (!success)
goto unmap_writable;
success = frida_read_chunk (client_fd, (void *) writable_address, size, &n, api);
if (!success)
goto unmap_writable;
api->sys_icache_invalidate ((void *) address, n);
api->sys_dcache_flush ((void *) address, n);
unmap_writable:
api->mach_vm_deallocate (task, writable_address, size);
break;
}
case FRIDA_UPLOAD_COMMAND_APPLY_THREADED:
@@ -449,6 +469,19 @@ next_client:
beach:
api->close (listener_fd);
#ifndef BUILDING_TEST_PROGRAM
asm volatile (
"mov x0, %0\n\t"
"mov x1, #1337\n\t"
"mov x2, #1337\n\t"
"mov x3, #0\n\t"
"brk #1337\n\t"
:
: "r" ((uint64_t) result)
: "x0", "x1", "x2", "x3"
);
#endif
return result;
}
+359 -296
View File
@@ -1,11 +1,45 @@
[CCode (gir_namespace = "FridaFruityInjector", gir_version = "1.0")]
namespace Frida.Fruity.Injector {
public static async GadgetDetails inject (owned Gum.DarwinModule module, LLDB.Client lldb, HostChannelProvider channel_provider,
public static async Transaction 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);
}
public sealed class Transaction : Object {
public GadgetDetails gadget {
get;
construct;
}
public string main_thread_id;
private bool is_early_instrumentation;
private LLDB.Client lldb;
internal Transaction (GadgetDetails gadget, bool is_early_instrumentation, string main_thread_id, LLDB.Client lldb) {
Object (gadget: gadget);
this.is_early_instrumentation = is_early_instrumentation;
this.main_thread_id = main_thread_id;
this.lldb = lldb;
}
public async void commit (Cancellable? cancellable) throws Error, IOError {
if (is_early_instrumentation) {
var gadget_threads = new Gee.ArrayList<LLDB.Thread> ();
yield lldb.enumerate_threads (thread => {
if (thread.id != main_thread_id)
gadget_threads.add (thread);
return true;
}, cancellable);
yield lldb.continue_specific_threads (gadget_threads, cancellable);
} else {
yield lldb.continue (cancellable);
}
}
}
public sealed class GadgetDetails : Object {
public uint16 port {
get;
@@ -17,10 +51,6 @@ namespace Frida.Fruity.Injector {
}
}
public errordomain Error {
UNSUPPORTED
}
private sealed class Session : Object {
public Gum.DarwinModule module {
get;
@@ -77,36 +107,26 @@ namespace Frida.Fruity.Injector {
);
}
public async GadgetDetails run (Cancellable? cancellable) throws Error, IOError {
public async Transaction run (Cancellable? cancellable) throws Error, IOError {
try {
bool is_early_instrumentation;
var existing_gadget = yield setup (cancellable);
if (existing_gadget != null) {
yield lldb.detach (cancellable);
return existing_gadget;
is_early_instrumentation = false;
return new Transaction (existing_gadget, is_early_instrumentation, main_thread.id, lldb);
}
bool is_early_instrumentation = !libsystem_initialized;
is_early_instrumentation = !libsystem_initialized;
yield ensure_libsystem_initialized (cancellable);
var result = yield inject_module (cancellable);
var gadget = yield inject_module (cancellable);
yield teardown (cancellable);
if (is_early_instrumentation) {
var gadget_threads = new Gee.ArrayList<LLDB.Thread> ();
yield lldb.enumerate_threads (thread => {
if (thread.id != main_thread.id)
gadget_threads.add (thread);
return true;
}, cancellable);
yield lldb.continue_specific_threads (gadget_threads, cancellable);
} else {
yield lldb.detach (cancellable);
}
return result;
return new Transaction (gadget, is_early_instrumentation, main_thread.id, lldb);
} catch (GLib.Error e) {
throw new Error.UNSUPPORTED ("%s", e.message);
throw new Error.NOT_SUPPORTED ("%s", e.message);
}
}
@@ -151,7 +171,9 @@ namespace Frida.Fruity.Injector {
dyld_base = yield lldb.read_pointer (dyld_fields.dyld_load_address, cancellable);
} else {
yield lldb.enumerate_modules (m => {
if (m.pathname == "/usr/lib/dyld" || m.pathname == "/binpack/lib/dyld") {
if (m.pathname == "/usr/lib/dyld" ||
m.pathname == "/binpack/lib/dyld" ||
m.pathname == "/cores/usr/lib/dyld") {
dyld_base = m.load_address;
return false;
}
@@ -185,7 +207,10 @@ namespace Frida.Fruity.Injector {
private async GadgetDetails inject_module (Cancellable? cancellable) throws GLib.Error {
module_size = compute_virtual_size (module);
module.base_address = yield lldb.allocate (module_size, "rw", cancellable);
module.base_address = yield lldb.allocate (module_size, "rx", cancellable);
yield DebuggerMappings.spray_pages (lldb, module.base_address, (size_t) module.segments.index (0).vm_size,
page_size, cancellable);
unowned Gum.DarwinModuleImage image = module.image;
unowned uint8[] image_data = ((uint8[]) image.data)[0:image.size];
@@ -221,7 +246,7 @@ namespace Frida.Fruity.Injector {
case TEXT_ABSOLUTE32:
break;
default:
pending_error = new Error.UNSUPPORTED ("Unsupported rebase type: %u", rebase.type);
pending_error = new Error.NOT_SUPPORTED ("Unsupported rebase type: %u", rebase.type);
return false;
}
@@ -250,7 +275,7 @@ namespace Frida.Fruity.Injector {
case MAIN_EXECUTABLE:
case FLAT_LOOKUP:
case WEAK_LOOKUP:
pending_error = new Error.UNSUPPORTED ("Unsupported bind ordinal: %d",
pending_error = new Error.NOT_SUPPORTED ("Unsupported bind ordinal: %d",
bind.library_ordinal);
return false;
default:
@@ -273,7 +298,7 @@ namespace Frida.Fruity.Injector {
threaded_items.add_region (bind.segment.vm_address + slide + bind.offset);
break;
default:
pending_error = new Error.UNSUPPORTED ("Unsupported bind type: %u", bind.type);
pending_error = new Error.NOT_SUPPORTED ("Unsupported bind type: %u", bind.type);
return false;
}
@@ -308,7 +333,7 @@ namespace Frida.Fruity.Injector {
bool is_weak = (bind.symbol_flags & Gum.DarwinBindSymbolFlags.WEAK_IMPORT) != 0;
if (is_weak || is_dyld_stub_binder (module_name, symbol_name))
return true;
pending_error = new Error.UNSUPPORTED ("Unable to resolve symbol: %s", bind.symbol_name);
pending_error = new Error.NOT_SUPPORTED ("Unable to resolve symbol: %s", bind.symbol_name);
return false;
}
@@ -375,17 +400,19 @@ namespace Frida.Fruity.Injector {
.append_pointer (symbols.listen)
.append_pointer (symbols.getsockname)
.append_pointer (symbols.accept)
.append_pointer (symbols.close)
.append_pointer (symbols.read)
.append_pointer (symbols.write)
.append_pointer (symbols.getpagesize)
.append_pointer (symbols.mprotect)
.append_pointer (symbols.sys_icache_invalidate)
.append_pointer (symbols.sys_dcache_flush)
.append_pointer (symbols._mach_task_self)
.append_pointer (symbols.mach_vm_allocate)
.append_pointer (symbols.mach_vm_deallocate)
.append_pointer (symbols.vm_remap)
.append_pointer (symbols.dlopen)
.append_pointer (symbols.dlsym)
.append_pointer (symbols.mprotect)
.append_pointer (symbols.close)
.append_pointer (symbols.get_errno_storage);
apple_strv_builder.build (args);
@@ -400,12 +427,12 @@ namespace Frida.Fruity.Injector {
upload_api
}, null, cancellable);
uint8 error_code = (uint8) ((listen_result >> 56) & 0xff);
uint32 listener_fd = (uint32) ((listen_result >> 16) & 0xffffffffU);
uint16 listener_port = (uint16) (listen_result & 0xffff);
uint8 error_code = (uint8) ((listen_result >> 56) & 0xff);
uint32 listener_fd = (uint32) ((listen_result >> 16) & 0xffffffffU);
uint16 listener_port = (uint16) (listen_result & 0xffff);
if (error_code != 0)
throw new Error.UNSUPPORTED ("Unable to listen on TCP (error_code=%u)", error_code);
throw new Error.NOT_SUPPORTED ("Unable to listen on TCP (error_code=%u)", error_code);
yield lldb.write_byte_array (code, new Bytes.static (UPLOAD_RECEIVER_CODE), cancellable);
@@ -425,7 +452,7 @@ namespace Frida.Fruity.Injector {
upload_api
}, null, cancellable);
if (receive_result <= 0)
throw new Error.UNSUPPORTED ("Unable to start gadget: %" + int64.FORMAT_MODIFIER + "d", receive_result);
throw new Error.NOT_SUPPORTED ("Unable to start gadget: %" + int64.FORMAT_MODIFIER + "d", receive_result);
return (uint16) receive_result;
}
@@ -565,17 +592,19 @@ namespace Frida.Fruity.Injector {
public uint64 listen;
public uint64 getsockname;
public uint64 accept;
public uint64 close;
public uint64 read;
public uint64 write;
public uint64 getpagesize;
public uint64 mprotect;
public uint64 sys_icache_invalidate;
public uint64 sys_dcache_flush;
public uint64 _mach_task_self;
public uint64 mach_vm_allocate;
public uint64 mach_vm_deallocate;
public uint64 vm_remap;
public uint64 dlopen;
public uint64 dlsym;
public uint64 mprotect;
public uint64 close;
public uint64 get_errno_storage;
private const string LIBSYSTEM = "/usr/lib/libSystem.B.dylib";
@@ -588,17 +617,19 @@ namespace Frida.Fruity.Injector {
.add (LIBSYSTEM, "_listen")
.add (LIBSYSTEM, "_getsockname")
.add (LIBSYSTEM, "_accept")
.add (LIBSYSTEM, "_close")
.add (LIBSYSTEM, "_read")
.add (LIBSYSTEM, "_write")
.add (LIBSYSTEM, "_getpagesize")
.add (LIBSYSTEM, "_mprotect")
.add (LIBSYSTEM, "_sys_icache_invalidate")
.add (LIBSYSTEM, "_sys_dcache_flush")
.add (LIBSYSTEM, "_mach_task_self")
.add (LIBSYSTEM, "_mach_vm_allocate")
.add (LIBSYSTEM, "_mach_vm_deallocate")
.add (LIBSYSTEM, "_vm_remap")
.add (LIBSYSTEM, "_dlopen")
.add (LIBSYSTEM, "_dlsym")
.add (LIBSYSTEM, "_mprotect")
.add (LIBSYSTEM, "_close")
.add (LIBSYSTEM, "___error")
;
}
@@ -610,17 +641,19 @@ namespace Frida.Fruity.Injector {
listen = symbols.get (LIBSYSTEM, "_listen");
getsockname = symbols.get (LIBSYSTEM, "_getsockname");
accept = symbols.get (LIBSYSTEM, "_accept");
close = symbols.get (LIBSYSTEM, "_close");
read = symbols.get (LIBSYSTEM, "_read");
write = symbols.get (LIBSYSTEM, "_write");
getpagesize = symbols.get (LIBSYSTEM, "_getpagesize");
mprotect = symbols.get (LIBSYSTEM, "_mprotect");
sys_icache_invalidate = symbols.get (LIBSYSTEM, "_sys_icache_invalidate");
sys_dcache_flush = symbols.get (LIBSYSTEM, "_sys_dcache_flush");
_mach_task_self = symbols.get (LIBSYSTEM, "_mach_task_self");
mach_vm_allocate = symbols.get (LIBSYSTEM, "_mach_vm_allocate");
mach_vm_deallocate = symbols.get (LIBSYSTEM, "_mach_vm_deallocate");
vm_remap = symbols.get (LIBSYSTEM, "_vm_remap");
dlopen = symbols.get (LIBSYSTEM, "_dlopen");
dlsym = symbols.get (LIBSYSTEM, "_dlsym");
mprotect = symbols.get (LIBSYSTEM, "_mprotect");
close = symbols.get (LIBSYSTEM, "_close");
get_errno_storage = symbols.get (LIBSYSTEM, "___error");
}
}
@@ -638,9 +671,9 @@ namespace Frida.Fruity.Injector {
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,
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,
0x27, 0x40, 0x79, 0x29, 0x09, 0xc0, 0x5a, 0x29, 0x7d, 0x10, 0x53, 0x35, 0x41, 0x08, 0xaa, 0x0d, 0x00, 0x00, 0x14,
0x15, 0x40, 0xe0, 0xd2, 0x0b, 0x00, 0x00, 0x14, 0x15, 0x80, 0xe0, 0xd2, 0x06, 0x00, 0x00, 0x14, 0x15, 0xc0, 0xe0,
0xd2, 0x04, 0x00, 0x00, 0x14, 0x15, 0x00, 0xe1, 0xd2, 0x02, 0x00, 0x00, 0x14, 0x15, 0x40, 0xe1, 0xd2, 0x68, 0x1a,
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,
@@ -650,144 +683,153 @@ namespace Frida.Fruity.Injector {
/* Compiled from helpers/upload-receiver.c */
private const uint8[] UPLOAD_RECEIVER_CODE = {
0xfc, 0x6f, 0xba, 0xa9, 0xfa, 0x67, 0x01, 0xa9, 0xf8, 0x5f, 0x02, 0xa9, 0xf6, 0x57, 0x03, 0xa9, 0xf4, 0x4f, 0x04,
0xa9, 0xfd, 0x7b, 0x05, 0xa9, 0xfd, 0x43, 0x01, 0x91, 0xff, 0x03, 0x03, 0xd1, 0xfa, 0x03, 0x04, 0xaa, 0xfb, 0x03,
0x03, 0xaa, 0xf7, 0x03, 0x02, 0xaa, 0xf8, 0x03, 0x01, 0xaa, 0xf9, 0x03, 0x00, 0xaa, 0xbf, 0xc3, 0x19, 0xb8, 0x88,
0x95, 0x98, 0x52, 0x48, 0x89, 0xb5, 0x72, 0xa8, 0x03, 0x18, 0xb8, 0x13, 0x02, 0x80, 0x52, 0xb3, 0x43, 0x18, 0xb8,
0x48, 0x17, 0x40, 0xf9, 0xa1, 0xe3, 0x01, 0xd1, 0xa2, 0xf3, 0x01, 0xd1, 0xe0, 0x03, 0x19, 0xaa, 0x00, 0x01, 0x3f,
0xd6, 0x1f, 0x04, 0x00, 0x31, 0xe1, 0x00, 0x00, 0x54, 0x48, 0x47, 0x40, 0xf9, 0x00, 0x01, 0x3f, 0xd6, 0x08, 0x00,
0x40, 0xb9, 0x1f, 0x11, 0x00, 0x71, 0xa0, 0xfe, 0xff, 0x54, 0xd7, 0x01, 0x00, 0x14, 0xf6, 0x03, 0x00, 0xaa, 0xa1,
0x43, 0x02, 0xd1, 0x02, 0x02, 0x80, 0x52, 0x53, 0x02, 0x00, 0x94, 0xa8, 0x27, 0x77, 0xa9, 0x1f, 0x00, 0x00, 0x71,
0x00, 0x11, 0x58, 0xfa, 0x20, 0x01, 0x57, 0xfa, 0x60, 0x00, 0x00, 0x54, 0x65, 0x02, 0x00, 0x94, 0xe8, 0xff, 0xff,
0x17, 0x58, 0x02, 0x00, 0x94, 0x20, 0x39, 0x00, 0x34, 0xa8, 0x23, 0x00, 0xd1, 0x1a, 0x01, 0x10, 0xf8, 0xa8, 0x33,
0x00, 0xd1, 0x19, 0x01, 0x10, 0xb8, 0xbb, 0x83, 0x11, 0xf8, 0xa1, 0x47, 0x02, 0xd1, 0xe0, 0x03, 0x16, 0xaa, 0x22,
0x00, 0x80, 0x52, 0x41, 0x02, 0x00, 0x94, 0xe0, 0x37, 0x00, 0x34, 0xa8, 0xf3, 0x56, 0x38, 0x10, 0x05, 0x00, 0x51,
0x1f, 0x1a, 0x00, 0x71, 0x68, 0x37, 0x00, 0x54, 0x1f, 0x1a, 0x00, 0xf1, 0x10, 0x92, 0x9f, 0x9a, 0xb1, 0x38, 0x00,
0x10, 0x1f, 0x20, 0x03, 0xd5, 0x30, 0x7a, 0xb0, 0xb8, 0x11, 0x00, 0x00, 0x10, 0x30, 0x02, 0x10, 0x8b, 0x00, 0x02,
0x1f, 0xd6, 0xa1, 0x83, 0x01, 0xd1, 0xe0, 0x03, 0x16, 0xaa, 0x02, 0x01, 0x80, 0x52, 0x30, 0x02, 0x00, 0x94, 0xc0,
0x35, 0x00, 0x34, 0xa1, 0xa3, 0x02, 0xd1, 0xe0, 0x03, 0x16, 0xaa, 0x82, 0x00, 0x80, 0x52, 0x2b, 0x02, 0x00, 0x94,
0x20, 0x35, 0x00, 0x36, 0xa1, 0x03, 0x5a, 0xf8, 0xa2, 0x83, 0x55, 0xb8, 0xa3, 0x83, 0x02, 0xd1, 0xe0, 0x03, 0x16,
0xaa, 0xe4, 0x03, 0x1a, 0xaa, 0xbb, 0x01, 0x00, 0x94, 0xf7, 0x03, 0x00, 0xaa, 0x48, 0x23, 0x40, 0xf9, 0x36, 0x02,
0x00, 0x94, 0x48, 0x27, 0x40, 0xf9, 0x34, 0x02, 0x00, 0x94, 0x57, 0xfb, 0x07, 0x37, 0x9c, 0x01, 0x00, 0x14, 0xa1,
0x83, 0x01, 0xd1, 0xe0, 0x03, 0x16, 0xaa, 0x02, 0x01, 0x80, 0x52, 0x19, 0x02, 0x00, 0x94, 0xe0, 0x32, 0x00, 0x34,
0xa1, 0x83, 0x02, 0xd1, 0xe0, 0x03, 0x16, 0xaa, 0x02, 0x01, 0x80, 0x52, 0x14, 0x02, 0x00, 0x94, 0x40, 0x32, 0x00,
0x34, 0xa1, 0xa3, 0x02, 0xd1, 0xe0, 0x03, 0x16, 0xaa, 0x42, 0x00, 0x80, 0x52, 0x0f, 0x02, 0x00, 0x94, 0xa0, 0x31,
0x00, 0x34, 0xf5, 0x03, 0x00, 0x91, 0xa8, 0x83, 0x55, 0x78, 0x08, 0x71, 0x1d, 0x53, 0x08, 0x3d, 0x00, 0x11, 0x08,
0x3d, 0x7c, 0x92, 0xe9, 0x03, 0x00, 0x91, 0x37, 0x01, 0x08, 0xcb, 0xff, 0x02, 0x00, 0x91, 0xa8, 0x83, 0x55, 0x78,
0x02, 0xf1, 0x7d, 0xd3, 0xe0, 0x03, 0x16, 0xaa, 0xe1, 0x03, 0x17, 0xaa, 0x01, 0x02, 0x00, 0x94, 0xc0, 0x2f, 0x00,
0x34, 0xa1, 0xc3, 0x02, 0xd1, 0xe0, 0x03, 0x16, 0xaa, 0x42, 0x00, 0x80, 0x52, 0xfc, 0x01, 0x00, 0x94, 0x20, 0x2f,
0x00, 0x34, 0xa8, 0x03, 0x55, 0x78, 0x09, 0x71, 0x1d, 0x53, 0x29, 0x3d, 0x00, 0x11, 0x29, 0x3d, 0x7c, 0x92, 0xea,
0x03, 0x00, 0x91, 0x58, 0x01, 0x09, 0xcb, 0x1f, 0x03, 0x00, 0x91, 0x02, 0xf1, 0x7d, 0xd3, 0xe0, 0x03, 0x16, 0xaa,
0xe1, 0x03, 0x18, 0xaa, 0xf0, 0x01, 0x00, 0x94, 0xa0, 0x2d, 0x00, 0x34, 0x14, 0x00, 0x80, 0xd2, 0xba, 0x03, 0x5a,
0xf8, 0xbb, 0x03, 0x56, 0xf8, 0xbc, 0x03, 0x55, 0x78, 0x9f, 0x02, 0x1c, 0xeb, 0x40, 0x27, 0x00, 0x54, 0x19, 0x7b,
0x74, 0xf8, 0x33, 0x03, 0x40, 0xf9, 0xf3, 0x01, 0xf0, 0xb7, 0x68, 0xfe, 0x6b, 0xd3, 0x69, 0xaa, 0x40, 0x92, 0x6a,
0xaa, 0x6a, 0x93, 0x4a, 0x31, 0x55, 0x92, 0x09, 0x1d, 0x48, 0xb3, 0x28, 0x01, 0x0a, 0xaa, 0x69, 0x7e, 0x40, 0x92,
0x7f, 0x02, 0x41, 0xf2, 0xea, 0x03, 0x9a, 0x9a, 0x08, 0x01, 0x89, 0x9a, 0x49, 0x01, 0x1b, 0x8b, 0x20, 0x01, 0x08,
0x8b, 0x53, 0x01, 0xf8, 0xb6, 0x04, 0x00, 0x00, 0x14, 0x68, 0x3e, 0x40, 0x92, 0xe0, 0x7a, 0x68, 0xf8, 0xd3, 0x00,
0xf8, 0xb6, 0x61, 0xca, 0x71, 0xd3, 0x63, 0xc2, 0x70, 0xd3, 0x62, 0xbe, 0x60, 0xd3, 0xe4, 0x03, 0x19, 0xaa, 0xb6,
0x01, 0x00, 0x94, 0x68, 0xf6, 0x73, 0xd3, 0x20, 0x03, 0x00, 0xf9, 0x39, 0x4f, 0x28, 0x8b, 0xa8, 0xfc, 0xff, 0x35,
0x94, 0x06, 0x00, 0x91, 0xe0, 0xff, 0xff, 0x17, 0xa1, 0x83, 0x02, 0xd1, 0xe0, 0x03, 0x16, 0xaa, 0x02, 0x01, 0x80,
0x52, 0xc6, 0x01, 0x00, 0x94, 0x80, 0x28, 0x00, 0x34, 0xa1, 0xa3, 0x02, 0xd1, 0xe0, 0x03, 0x16, 0xaa, 0x02, 0x01,
0x80, 0x52, 0xc1, 0x01, 0x00, 0x94, 0xe0, 0x27, 0x00, 0x34, 0xa1, 0xc3, 0x02, 0xd1, 0xe0, 0x03, 0x16, 0xaa, 0x02,
0x01, 0x80, 0x52, 0xbc, 0x01, 0x00, 0x94, 0x40, 0x27, 0x00, 0x34, 0xb9, 0xf3, 0x75, 0xa9, 0xa8, 0x03, 0x55, 0xf8,
0xa8, 0x83, 0x10, 0xf8, 0x48, 0x2b, 0x40, 0xf9, 0x00, 0x01, 0x3f, 0xd6, 0xbf, 0x03, 0x1a, 0xf8, 0x48, 0x2f, 0x40,
0xf9, 0xa1, 0x83, 0x01, 0xd1, 0xa9, 0x43, 0x00, 0xd1, 0x20, 0x01, 0x10, 0xb8, 0x22, 0x00, 0xa0, 0x52, 0x23, 0x00,
0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0x14, 0x00, 0x80, 0x52, 0x13, 0x00, 0x80, 0xd2, 0xb8, 0x03, 0x5a, 0xf8, 0x35,
0x83, 0x00, 0x91, 0x37, 0x00, 0x80, 0x52, 0x28, 0x13, 0x40, 0xb9, 0x9f, 0x02, 0x08, 0x6b, 0x60, 0x0c, 0x00, 0x54,
0xa8, 0x02, 0x40, 0xb9, 0x09, 0xfd, 0x9f, 0x52, 0xe9, 0xff, 0xaf, 0x72, 0x09, 0x01, 0x09, 0x0b, 0x3f, 0x2d, 0x00,
0x71, 0xe9, 0x22, 0xc9, 0x1a, 0x2a, 0x10, 0x81, 0x52, 0x29, 0x01, 0x0a, 0x0a, 0x24, 0x99, 0x40, 0x7a, 0x04, 0x09,
0x4c, 0x7a, 0x01, 0x01, 0x00, 0x54, 0xa8, 0x0a, 0x40, 0xb9, 0xa0, 0x02, 0x08, 0x8b, 0x48, 0x37, 0x40, 0xf9, 0x21,
0x01, 0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0x00, 0x7b, 0x33, 0xf8, 0x73, 0x06, 0x00, 0x91, 0xa8, 0x06, 0x40, 0xb9,
0xb5, 0x02, 0x08, 0x8b, 0x94, 0x06, 0x00, 0x11, 0xe8, 0xff, 0xff, 0x17, 0xa1, 0x83, 0x01, 0xd1, 0xe0, 0x03, 0x16,
0xaa, 0x02, 0x01, 0x80, 0x52, 0x8c, 0x01, 0x00, 0x94, 0x40, 0x21, 0x00, 0x34, 0xa1, 0x83, 0x02, 0xd1, 0xe0, 0x03,
0x16, 0xaa, 0x82, 0x00, 0x80, 0x52, 0x87, 0x01, 0x00, 0x94, 0xa0, 0x20, 0x00, 0x34, 0xa1, 0xa3, 0x02, 0xd1, 0xe0,
0x03, 0x16, 0xaa, 0x82, 0x00, 0x80, 0x52, 0x82, 0x01, 0x00, 0x94, 0x00, 0x20, 0x00, 0x36, 0x48, 0x3f, 0x40, 0xf9,
0xa0, 0x03, 0x5a, 0xf8, 0xa1, 0x03, 0x56, 0xb8, 0xa2, 0x83, 0x55, 0xb8, 0x00, 0x01, 0x3f, 0xd6, 0xe0, 0xe6, 0xff,
0x34, 0xf9, 0x00, 0x00, 0x14, 0xa1, 0x83, 0x01, 0xd1, 0xe0, 0x03, 0x16, 0xaa, 0x02, 0x01, 0x80, 0x52, 0x76, 0x01,
0x00, 0x94, 0x80, 0x1e, 0x00, 0x34, 0xa1, 0xc3, 0x02, 0xd1, 0xe0, 0x03, 0x16, 0xaa, 0x82, 0x00, 0x80, 0x52, 0x71,
0x01, 0x00, 0x94, 0xe0, 0x1d, 0x00, 0x34, 0x13, 0x00, 0x80, 0x52, 0xb4, 0x03, 0x5a, 0xf8, 0xa8, 0x03, 0x55, 0xb8,
0x7f, 0x02, 0x08, 0x6b, 0xe0, 0xe4, 0xff, 0x54, 0xbf, 0xff, 0x35, 0xa9, 0x88, 0x5a, 0x73, 0xf8, 0xa1, 0x83, 0x02,
0xd1, 0xa2, 0xa3, 0x02, 0xd1, 0x77, 0x01, 0x00, 0x94, 0x73, 0x06, 0x00, 0x11, 0xf7, 0xff, 0xff, 0x17, 0xa1, 0x83,
0x01, 0xd1, 0xe0, 0x03, 0x16, 0xaa, 0x02, 0x01, 0x80, 0x52, 0x60, 0x01, 0x00, 0x94, 0xc0, 0x1b, 0x00, 0x34, 0xa1,
0xd3, 0x02, 0xd1, 0xe0, 0x03, 0x16, 0xaa, 0x82, 0x00, 0x80, 0x52, 0x5b, 0x01, 0x00, 0x94, 0x20, 0x1b, 0x00, 0x34,
0xa1, 0x83, 0x02, 0xd1, 0xe0, 0x03, 0x16, 0xaa, 0x02, 0x01, 0x80, 0x52, 0x56, 0x01, 0x00, 0x94, 0x80, 0x1a, 0x00,
0x34, 0x13, 0x00, 0x80, 0x52, 0xb4, 0x03, 0x5a, 0xf8, 0xa8, 0xc3, 0x54, 0xb8, 0x7f, 0x02, 0x08, 0x6b, 0x80, 0xe1,
0xff, 0x54, 0xbf, 0x7f, 0x35, 0xa9, 0xa8, 0x03, 0x56, 0xf8, 0x89, 0x5a, 0x73, 0xb8, 0x08, 0x01, 0x09, 0x8b, 0xa1,
0xa3, 0x02, 0xd1, 0xa2, 0xc3, 0x02, 0xd1, 0x5a, 0x01, 0x00, 0x94, 0x73, 0x06, 0x00, 0x11, 0xf5, 0xff, 0xff, 0x17,
0x53, 0x01, 0x00, 0x94, 0x20, 0xe0, 0x07, 0x37, 0xc3, 0x00, 0x00, 0x14, 0x1a, 0x0f, 0x13, 0x8b, 0x88, 0xdf, 0x41,
0x29, 0x95, 0x03, 0x08, 0x8b, 0x88, 0x17, 0x40, 0xb9, 0x1f, 0x0d, 0x00, 0x71, 0xc0, 0x12, 0x00, 0x54, 0x1f, 0x09,
0x00, 0x71, 0xe0, 0x14, 0x00, 0x54, 0x1f, 0x05, 0x00, 0x71, 0x21, 0x02, 0x00, 0x54, 0x88, 0x0b, 0x40, 0xb9, 0x93,
0x03, 0x08, 0x8b, 0xf4, 0x03, 0x1a, 0xaa, 0xb7, 0x01, 0x00, 0xb4, 0x69, 0x02, 0x40, 0xb9, 0x28, 0x1d, 0x00, 0x72,
0xa0, 0x00, 0x00, 0x54, 0xa9, 0x26, 0x49, 0x8b, 0x34, 0x01, 0x00, 0x94, 0xe0, 0x43, 0xc1, 0xda, 0x02, 0x00, 0x00,
0x14, 0x00, 0x00, 0x80, 0xd2, 0x80, 0x86, 0x00, 0xf8, 0x73, 0x12, 0x00, 0x91, 0xf7, 0x06, 0x00, 0xd1, 0xb7, 0xfe,
0xff, 0xb5, 0x09, 0x00, 0x80, 0xd2, 0x88, 0x07, 0x40, 0xb9, 0x88, 0x03, 0x08, 0x8b, 0xa8, 0x03, 0x10, 0xf8, 0x0a,
0x45, 0x40, 0xb8, 0xaa, 0x03, 0x12, 0xf8, 0xa8, 0x03, 0x11, 0xf8, 0xa8, 0x03, 0x52, 0xf8, 0x3f, 0x01, 0x08, 0xeb,
0xc0, 0x0c, 0x00, 0x54, 0xa9, 0x83, 0x12, 0xf8, 0xa8, 0x03, 0x51, 0xf8, 0x08, 0x79, 0x69, 0xb8, 0xc8, 0x0b, 0x00,
0x34, 0x15, 0x00, 0x80, 0xd2, 0xa9, 0x03, 0x50, 0xf8, 0x3b, 0x01, 0x08, 0x8b, 0x68, 0x0f, 0x40, 0x79, 0x6a, 0x2b,
0x40, 0x79, 0x69, 0x5b, 0x00, 0x91, 0xa9, 0xab, 0x33, 0xa9, 0x09, 0x79, 0x1d, 0x12, 0xa9, 0x43, 0x13, 0xb8, 0x1f,
0x31, 0x00, 0x71, 0xe9, 0xff, 0x9f, 0x52, 0x0a, 0xe0, 0xbf, 0x12, 0x54, 0x01, 0x89, 0x9a, 0x1f, 0x05, 0x00, 0x71,
0xaa, 0x83, 0x50, 0xf8, 0x49, 0x01, 0x9f, 0x9a, 0x3c, 0x03, 0x09, 0xcb, 0x1f, 0x19, 0x00, 0x71, 0xe8, 0x03, 0x8a,
0x9a, 0x37, 0x03, 0x08, 0xcb, 0xa8, 0x03, 0x54, 0xf8, 0xbf, 0x02, 0x08, 0xeb, 0xe0, 0x08, 0x00, 0x54, 0xa8, 0x83,
0x53, 0xf8, 0x08, 0x79, 0x75, 0x78, 0xe9, 0xff, 0x9f, 0x52, 0x1f, 0x01, 0x09, 0xeb, 0x00, 0x08, 0x00, 0x54, 0x69,
0x07, 0x40, 0xf9, 0x29, 0x03, 0x09, 0x8b, 0x6a, 0x0b, 0x40, 0x79, 0xa9, 0x26, 0x0a, 0x9b, 0x38, 0x01, 0x08, 0x8b,
0xa8, 0x43, 0x53, 0xb8, 0x1f, 0x09, 0x00, 0x71, 0x41, 0x02, 0x00, 0x54, 0x08, 0x03, 0x40, 0xf9, 0xe8, 0x00, 0xf8,
0xb7, 0x09, 0xad, 0x6c, 0xd3, 0x29, 0x1d, 0x48, 0x92, 0x0a, 0x8d, 0x40, 0x92, 0xea, 0x02, 0x0a, 0x8b, 0x49, 0x01,
0x09, 0x8b, 0x05, 0x00, 0x00, 0x14, 0x09, 0x5d, 0x40, 0x92, 0x49, 0x7b, 0x69, 0xf8, 0x0a, 0xfd, 0x58, 0xd3, 0x29,
0x01, 0x2a, 0x8b, 0x09, 0x03, 0x00, 0xf9, 0x08, 0xf9, 0x73, 0xd3, 0x18, 0x0b, 0x08, 0x8b, 0x28, 0xfe, 0xff, 0xb5,
0x27, 0x00, 0x00, 0x14, 0x13, 0x03, 0x40, 0xf9, 0x70, 0xfe, 0x7e, 0xd3, 0x62, 0xbe, 0x60, 0xd3, 0x63, 0xc2, 0x70,
0xd3, 0x61, 0xca, 0x71, 0xd3, 0x1f, 0x0e, 0x00, 0xf1, 0x10, 0x92, 0x9f, 0x9a, 0x51, 0x0e, 0x00, 0x10, 0x1f, 0x20,
0x03, 0xd5, 0x30, 0x7a, 0xb0, 0xb8, 0x11, 0x00, 0x00, 0x10, 0x30, 0x02, 0x10, 0x8b, 0x00, 0x02, 0x1f, 0xd6, 0x68,
0xca, 0x73, 0xd3, 0x08, 0x1d, 0x48, 0x92, 0x69, 0xaa, 0x40, 0x92, 0x89, 0x03, 0x09, 0x8b, 0x20, 0x01, 0x08, 0x8b,
0x10, 0x00, 0x00, 0x14, 0x68, 0x02, 0x14, 0x8a, 0x48, 0x7b, 0x68, 0xf8, 0x69, 0xca, 0x60, 0xd3, 0x3f, 0x01, 0x41,
0xf1, 0xe9, 0xb3, 0x6d, 0xb2, 0xe9, 0x33, 0x89, 0x9a, 0x69, 0xca, 0x60, 0xb3, 0x00, 0x01, 0x09, 0x8b, 0x07, 0x00,
0x00, 0x14, 0x20, 0x43, 0x33, 0x8b, 0x03, 0x00, 0x00, 0x14, 0x68, 0x02, 0x14, 0x8a, 0x40, 0x7b, 0x68, 0xf8, 0xe4,
0x03, 0x18, 0xaa, 0xab, 0x00, 0x00, 0x94, 0x00, 0x03, 0x00, 0xf9, 0x68, 0xf6, 0x73, 0xd3, 0x18, 0x0f, 0x08, 0x8b,
0x68, 0xfb, 0xff, 0xb5, 0xb5, 0x06, 0x00, 0x91, 0xb8, 0xff, 0xff, 0x17, 0xa9, 0x83, 0x52, 0xf8, 0x29, 0x05, 0x00,
0x91, 0xbb, 0x83, 0x51, 0xf8, 0x99, 0xff, 0xff, 0x17, 0xa8, 0x23, 0x00, 0xd1, 0x1a, 0x01, 0x50, 0xf8, 0x48, 0x33,
0x40, 0xf9, 0xa1, 0x03, 0x5a, 0xf8, 0xa9, 0x43, 0x00, 0xd1, 0x20, 0x01, 0x50, 0xb8, 0x22, 0x00, 0xa0, 0x52, 0x00,
0x01, 0x3f, 0xd6, 0xa8, 0x33, 0x00, 0xd1, 0x19, 0x01, 0x50, 0xb8, 0x6c, 0xfe, 0xff, 0x17, 0xbf, 0x02, 0x00, 0x91,
0xa8, 0x23, 0x00, 0xd1, 0x1a, 0x01, 0x50, 0xf8, 0xa8, 0x33, 0x00, 0xd1, 0x19, 0x01, 0x50, 0xb8, 0xbb, 0x83, 0x51,
0xf8, 0x65, 0xfe, 0xff, 0x17, 0xe8, 0x03, 0x1c, 0xaa, 0x09, 0x8d, 0x40, 0xb8, 0x13, 0x01, 0x09, 0x8b, 0xf4, 0x03,
0x1a, 0xaa, 0x77, 0xef, 0xff, 0xb4, 0x69, 0x82, 0x5f, 0xf8, 0x28, 0x3d, 0x00, 0x72, 0xa0, 0x00, 0x00, 0x54, 0xa9,
0x82, 0x49, 0x8b, 0xa2, 0x00, 0x00, 0x94, 0xe0, 0x43, 0xc1, 0xda, 0x02, 0x00, 0x00, 0x14, 0x00, 0x00, 0x80, 0xd2,
0x68, 0x06, 0x41, 0xf8, 0x08, 0x00, 0x08, 0x8b, 0x88, 0x86, 0x00, 0xf8, 0xf7, 0x06, 0x00, 0xd1, 0x97, 0xfe, 0xff,
0xb5, 0x6d, 0xff, 0xff, 0x17, 0x88, 0x0b, 0x40, 0xb9, 0x88, 0x03, 0x08, 0x8b, 0x13, 0x11, 0x00, 0x91, 0xf4, 0x03,
0x1a, 0xaa, 0x17, 0xed, 0xff, 0xb4, 0x69, 0xc2, 0x5f, 0xb8, 0x28, 0x1d, 0x00, 0x72, 0xa0, 0x00, 0x00, 0x54, 0xa9,
0x26, 0x49, 0x8b, 0x8f, 0x00, 0x00, 0x94, 0xe0, 0x43, 0xc1, 0xda, 0x02, 0x00, 0x00, 0x14, 0x00, 0x00, 0x80, 0xd2,
0x68, 0x86, 0x80, 0xb8, 0x08, 0x00, 0x08, 0x8b, 0x88, 0x86, 0x00, 0xf8, 0xf7, 0x06, 0x00, 0xd1, 0x97, 0xfe, 0xff,
0xb5, 0x5a, 0xff, 0xff, 0x17, 0xbf, 0x02, 0x00, 0x91, 0x99, 0x00, 0x00, 0x94, 0x48, 0x43, 0x40, 0xf9, 0xe0, 0x03,
0x19, 0xaa, 0x00, 0x01, 0x3f, 0xd6, 0xa0, 0xc3, 0x99, 0xb8, 0xbf, 0x43, 0x01, 0xd1, 0xfd, 0x7b, 0x45, 0xa9, 0xf4,
0x4f, 0x44, 0xa9, 0xf6, 0x57, 0x43, 0xa9, 0xf8, 0x5f, 0x42, 0xa9, 0xfa, 0x67, 0x41, 0xa9, 0xfc, 0x6f, 0xc6, 0xa8,
0xc0, 0x03, 0x5f, 0xd6, 0x0c, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0xb4, 0x01, 0x00, 0x00, 0x9c, 0x02, 0x00,
0x00, 0xf4, 0x02, 0x00, 0x00, 0x4c, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x24, 0x00,
0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0xf8, 0x5f, 0xbc, 0xa9, 0xf6, 0x57, 0x01, 0xa9, 0xf4,
0x4f, 0x02, 0xa9, 0xfd, 0x7b, 0x03, 0xa9, 0xfd, 0xc3, 0x00, 0x91, 0xf3, 0x03, 0x04, 0xaa, 0xf4, 0x03, 0x03, 0xaa,
0xf5, 0x03, 0x02, 0xaa, 0xf6, 0x03, 0x01, 0xaa, 0xf7, 0x03, 0x00, 0xaa, 0x43, 0x00, 0x00, 0xb4, 0x9f, 0x02, 0x00,
0xf9, 0xbf, 0x02, 0x00, 0xf1, 0xf8, 0x17, 0x9f, 0x1a, 0xd5, 0x03, 0x00, 0xb4, 0x68, 0x1a, 0x40, 0xf9, 0xe0, 0x03,
0x17, 0xaa, 0xe1, 0x03, 0x16, 0xaa, 0xe2, 0x03, 0x15, 0xaa, 0x00, 0x01, 0x3f, 0xd6, 0x1f, 0x04, 0x00, 0xb1, 0xe1,
0x00, 0x00, 0x54, 0x68, 0x46, 0x40, 0xf9, 0x00, 0x01, 0x3f, 0xd6, 0x08, 0x00, 0x40, 0xb9, 0x1f, 0x11, 0x00, 0x71,
0xa0, 0xfe, 0xff, 0x54, 0x0a, 0x00, 0x00, 0x14, 0x1f, 0x04, 0x00, 0xf1, 0x2b, 0x01, 0x00, 0x54, 0x94, 0x00, 0x00,
0xb4, 0x88, 0x02, 0x40, 0xf9, 0x08, 0x01, 0x00, 0x8b, 0x88, 0x02, 0x00, 0xf9, 0xd6, 0x02, 0x00, 0x8b, 0xb5, 0x02,
0x00, 0xcb, 0xe8, 0xff, 0xff, 0x17, 0x18, 0x00, 0x80, 0x52, 0xe0, 0x03, 0x18, 0xaa, 0xfd, 0x7b, 0x43, 0xa9, 0xf4,
0x4f, 0x42, 0xa9, 0xf6, 0x57, 0x41, 0xa9, 0xf8, 0x5f, 0xc4, 0xa8, 0xc0, 0x03, 0x5f, 0xd6, 0x38, 0x00, 0x80, 0x52,
0xf9, 0xff, 0xff, 0x17, 0xf6, 0x57, 0xbd, 0xa9, 0xf4, 0x4f, 0x01, 0xa9, 0xfd, 0x7b, 0x02, 0xa9, 0xfd, 0x83, 0x00,
0x91, 0xf3, 0x03, 0x02, 0xaa, 0xf4, 0x03, 0x01, 0xaa, 0xf5, 0x03, 0x00, 0xaa, 0x88, 0x00, 0x80, 0x52, 0xf6, 0x03,
0x08, 0xaa, 0x48, 0x02, 0x00, 0xb4, 0x68, 0x1e, 0x40, 0xf9, 0xe0, 0x03, 0x15, 0xaa, 0xe1, 0x03, 0x14, 0xaa, 0xe2,
0x03, 0x16, 0xaa, 0x00, 0x01, 0x3f, 0xd6, 0x1f, 0x04, 0x00, 0xb1, 0xe1, 0x00, 0x00, 0x54, 0x68, 0x46, 0x40, 0xf9,
0x00, 0x01, 0x3f, 0xd6, 0x08, 0x00, 0x40, 0xb9, 0x1f, 0x11, 0x00, 0x71, 0xa0, 0xfe, 0xff, 0x54, 0x05, 0x00, 0x00,
0x14, 0x94, 0x02, 0x00, 0x8b, 0xc8, 0x02, 0x00, 0xcb, 0x1f, 0x00, 0x00, 0xf1, 0xcc, 0xfd, 0xff, 0x54, 0xdf, 0x02,
0x00, 0xf1, 0xe0, 0x17, 0x9f, 0x1a, 0xfd, 0x7b, 0x42, 0xa9, 0xf4, 0x4f, 0x41, 0xa9, 0xf6, 0x57, 0xc3, 0xa8, 0xc0,
0x03, 0x5f, 0xd6, 0x44, 0x3c, 0x50, 0xb3, 0x7f, 0x00, 0x00, 0x71, 0x48, 0x00, 0x84, 0x9a, 0x3f, 0x0c, 0x00, 0x71,
0x28, 0x02, 0x00, 0x54, 0xf0, 0x03, 0x01, 0x2a, 0x1f, 0x0e, 0x00, 0xf1, 0x10, 0x92, 0x9f, 0x9a, 0xd1, 0x01, 0x00,
0x10, 0x1f, 0x20, 0x03, 0xd5, 0x30, 0x7a, 0xb0, 0xb8, 0x11, 0x00, 0x00, 0x10, 0x30, 0x02, 0x10, 0x8b, 0x00, 0x02,
0x1f, 0xd6, 0x00, 0x01, 0xc1, 0xda, 0xc0, 0x03, 0x5f, 0xd6, 0x00, 0x05, 0xc1, 0xda, 0xc0, 0x03, 0x5f, 0xd6, 0x00,
0x09, 0xc1, 0xda, 0xc0, 0x03, 0x5f, 0xd6, 0x00, 0x0d, 0xc1, 0xda, 0xc0, 0x03, 0x5f, 0xd6, 0x0c, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x03, 0x00, 0x80, 0xd2, 0xe4, 0x03, 0x1a,
0xaa, 0x95, 0xff, 0xff, 0x17, 0xea, 0x03, 0x09, 0xaa, 0x4b, 0x15, 0x40, 0x38, 0x7f, 0x7d, 0x01, 0x71, 0x21, 0x11,
0x8a, 0x9a, 0xa9, 0x23, 0x00, 0xd1, 0x29, 0x01, 0x50, 0xf8, 0x29, 0x39, 0x40, 0xf9, 0x08, 0x05, 0x00, 0x51, 0x00,
0x5b, 0x68, 0xf8, 0x20, 0x01, 0x1f, 0xd6, 0xa1, 0x03, 0x02, 0xd1, 0xe0, 0x03, 0x16, 0xaa, 0xe2, 0x03, 0x1a, 0xaa,
0xb5, 0xff, 0xff, 0x17, 0xa4, 0x93, 0x01, 0xd1, 0x00, 0x00, 0x80, 0x52, 0xe3, 0x03, 0x1b, 0xaa, 0x00, 0x01, 0x1f,
0xd6, 0xa0, 0x03, 0x5a, 0xf8, 0xa1, 0x03, 0x56, 0xf8, 0x00, 0x01, 0x1f, 0xd6, 0x48, 0x43, 0x40, 0xf9, 0xe0, 0x03,
0x16, 0xaa, 0x00, 0x01, 0x1f, 0xd6
0xa9, 0xfd, 0x7b, 0x05, 0xa9, 0xfd, 0x43, 0x01, 0x91, 0xff, 0x43, 0x03, 0xd1, 0xfb, 0x03, 0x04, 0xaa, 0xf6, 0x03,
0x03, 0xaa, 0xf8, 0x03, 0x02, 0xaa, 0xf9, 0x03, 0x01, 0xaa, 0xf5, 0x03, 0x00, 0xaa, 0xbf, 0xc3, 0x19, 0xb8, 0x88,
0x95, 0x98, 0x52, 0x48, 0x89, 0xb5, 0x72, 0xa8, 0x43, 0x18, 0xb8, 0x88, 0x34, 0x40, 0xf9, 0x00, 0x01, 0x3f, 0xd6,
0xfa, 0x03, 0x00, 0xaa, 0x13, 0x02, 0x80, 0x52, 0xb3, 0x83, 0x18, 0xb8, 0x68, 0x17, 0x40, 0xf9, 0xa1, 0xd3, 0x01,
0xd1, 0xa2, 0xe3, 0x01, 0xd1, 0xe0, 0x03, 0x15, 0xaa, 0x00, 0x01, 0x3f, 0xd6, 0x1f, 0x04, 0x00, 0x31, 0xe1, 0x00,
0x00, 0x54, 0x68, 0x4f, 0x40, 0xf9, 0x00, 0x01, 0x3f, 0xd6, 0x08, 0x00, 0x40, 0xb9, 0x1f, 0x11, 0x00, 0x71, 0xa0,
0xfe, 0xff, 0x54, 0xf1, 0x01, 0x00, 0x14, 0xf7, 0x03, 0x00, 0xaa, 0xa1, 0x43, 0x02, 0xd1, 0x02, 0x02, 0x80, 0x52,
0x7f, 0x02, 0x00, 0x94, 0xa8, 0x27, 0x77, 0xa9, 0x1f, 0x00, 0x00, 0x71, 0x00, 0x11, 0x59, 0xfa, 0x20, 0x01, 0x58,
0xfa, 0x60, 0x00, 0x00, 0x54, 0x8a, 0x02, 0x00, 0x94, 0xe8, 0xff, 0xff, 0x17, 0x80, 0x02, 0x00, 0x94, 0x60, 0x3c,
0x00, 0x34, 0x38, 0x00, 0x80, 0x52, 0xbb, 0x83, 0x11, 0xf8, 0xa8, 0x13, 0x00, 0xd1, 0x15, 0x01, 0x10, 0xb8, 0xa8,
0x43, 0x00, 0xd1, 0x16, 0x01, 0x10, 0xf8, 0xa8, 0x53, 0x00, 0xd1, 0x1a, 0x01, 0x10, 0xb8, 0xa1, 0x47, 0x02, 0xd1,
0xe0, 0x03, 0x17, 0xaa, 0x22, 0x00, 0x80, 0x52, 0x6a, 0x02, 0x00, 0x94, 0xc0, 0x3a, 0x00, 0x34, 0xa8, 0xf3, 0x56,
0x38, 0x10, 0x05, 0x00, 0x51, 0x1f, 0x1a, 0x00, 0x71, 0x48, 0x3a, 0x00, 0x54, 0x1f, 0x1a, 0x00, 0xf1, 0x10, 0x92,
0x9f, 0x9a, 0x11, 0x00, 0x00, 0x90, 0x31, 0x52, 0x22, 0x91, 0x30, 0x7a, 0xb0, 0xb8, 0x11, 0x00, 0x00, 0x10, 0x30,
0x02, 0x10, 0x8b, 0x00, 0x02, 0x1f, 0xd6, 0xa1, 0x83, 0x01, 0xd1, 0x56, 0x02, 0x00, 0x94, 0xe0, 0x38, 0x00, 0x34,
0xa1, 0xe3, 0x02, 0xd1, 0xe0, 0x03, 0x17, 0xaa, 0x82, 0x00, 0x80, 0x52, 0x56, 0x02, 0x00, 0x94, 0x40, 0x38, 0x00,
0x34, 0xbf, 0x03, 0x16, 0xf8, 0x68, 0x43, 0x40, 0xf9, 0xa2, 0x83, 0x54, 0xb8, 0xa6, 0x03, 0x5a, 0xf8, 0xff, 0x83,
0x00, 0xd1, 0x49, 0x00, 0x80, 0x52, 0xe9, 0x13, 0x00, 0xb9, 0xa1, 0x83, 0x02, 0xd1, 0xa9, 0xa3, 0x02, 0xd1, 0xe9,
0x07, 0x00, 0xf9, 0xa9, 0x93, 0x02, 0xd1, 0xe9, 0x03, 0x00, 0xf9, 0xe0, 0x03, 0x1a, 0xaa, 0x03, 0x00, 0x80, 0xd2,
0x24, 0x00, 0x80, 0x52, 0xe5, 0x03, 0x1a, 0xaa, 0x07, 0x00, 0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0xff, 0x83, 0x00,
0x91, 0xc0, 0x35, 0x00, 0x35, 0x68, 0x2b, 0x40, 0xf9, 0xa0, 0x03, 0x56, 0xf8, 0xa1, 0x83, 0x54, 0xb8, 0x62, 0x00,
0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0x60, 0x2e, 0x00, 0x35, 0xa1, 0x03, 0x56, 0xf8, 0xa2, 0x83, 0x54, 0xb8, 0xa3,
0xc3, 0x02, 0xd1, 0xe0, 0x03, 0x17, 0xaa, 0xe4, 0x03, 0x1b, 0xaa, 0xc0, 0x01, 0x00, 0x94, 0x80, 0x2d, 0x00, 0x34,
0x68, 0x2f, 0x40, 0xf9, 0x46, 0x02, 0x00, 0x94, 0x68, 0x33, 0x40, 0xf9, 0x44, 0x02, 0x00, 0x94, 0x33, 0x00, 0x80,
0x52, 0x67, 0x01, 0x00, 0x14, 0xa1, 0x83, 0x01, 0xd1, 0x27, 0x02, 0x00, 0x94, 0x00, 0x33, 0x00, 0x34, 0xa1, 0xe3,
0x02, 0xd1, 0xe0, 0x03, 0x17, 0xaa, 0x82, 0x00, 0x80, 0x52, 0x27, 0x02, 0x00, 0x94, 0x60, 0x32, 0x00, 0x34, 0x13,
0x00, 0x80, 0x52, 0xb4, 0x03, 0x5a, 0xf8, 0xa8, 0x83, 0x54, 0xb8, 0x7f, 0x02, 0x08, 0x6b, 0x80, 0xf6, 0xff, 0x54,
0xbf, 0x03, 0x16, 0xf8, 0xbf, 0x03, 0x15, 0xf8, 0x88, 0x5a, 0x73, 0xf8, 0xa1, 0x83, 0x02, 0xd1, 0xa2, 0xc3, 0x02,
0xd1, 0x28, 0x02, 0x00, 0x94, 0x73, 0x06, 0x00, 0x11, 0xf6, 0xff, 0xff, 0x17, 0xa1, 0x83, 0x02, 0xd1, 0x12, 0x02,
0x00, 0x94, 0x60, 0x30, 0x00, 0x34, 0xa1, 0xc3, 0x02, 0xd1, 0x0f, 0x02, 0x00, 0x94, 0x00, 0x30, 0x00, 0x34, 0xa1,
0xe3, 0x02, 0xd1, 0x0c, 0x02, 0x00, 0x94, 0xa0, 0x2f, 0x00, 0x34, 0xbc, 0x03, 0x56, 0xf8, 0xa8, 0xeb, 0x74, 0xa9,
0xa8, 0x83, 0x10, 0xf8, 0x68, 0x37, 0x40, 0xf9, 0x00, 0x01, 0x3f, 0xd6, 0xbf, 0x03, 0x1a, 0xf8, 0x68, 0x3b, 0x40,
0xf9, 0xa1, 0x83, 0x01, 0xd1, 0xa9, 0x63, 0x00, 0xd1, 0x20, 0x01, 0x10, 0xb8, 0x22, 0x00, 0xa0, 0x52, 0x23, 0x00,
0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0x13, 0x00, 0x80, 0x52, 0x15, 0x00, 0x80, 0xd2, 0xb4, 0x03, 0x5a, 0xf8, 0x56,
0x83, 0x00, 0x91, 0x48, 0x13, 0x40, 0xb9, 0x7f, 0x02, 0x08, 0x6b, 0xe0, 0x12, 0x00, 0x54, 0xc8, 0x02, 0x40, 0xb9,
0x09, 0xfd, 0x9f, 0x52, 0xe9, 0xff, 0xaf, 0x72, 0x09, 0x01, 0x09, 0x0b, 0x3f, 0x2d, 0x00, 0x71, 0x09, 0x23, 0xc9,
0x1a, 0x2a, 0x10, 0x81, 0x52, 0x29, 0x01, 0x0a, 0x0a, 0x24, 0x99, 0x40, 0x7a, 0x04, 0x09, 0x4c, 0x7a, 0x01, 0x01,
0x00, 0x54, 0xc8, 0x0a, 0x40, 0xb9, 0x69, 0x47, 0x40, 0xf9, 0xc0, 0x02, 0x08, 0x8b, 0x21, 0x01, 0x80, 0x52, 0x20,
0x01, 0x3f, 0xd6, 0x80, 0x7a, 0x35, 0xf8, 0xb5, 0x06, 0x00, 0x91, 0xc8, 0x06, 0x40, 0xb9, 0xd6, 0x02, 0x08, 0x8b,
0x73, 0x06, 0x00, 0x11, 0xe8, 0xff, 0xff, 0x17, 0xa1, 0x83, 0x01, 0xd1, 0xdf, 0x01, 0x00, 0x94, 0x00, 0x2a, 0x00,
0x34, 0xa1, 0x83, 0x02, 0xd1, 0xe0, 0x03, 0x17, 0xaa, 0x82, 0x00, 0x80, 0x52, 0xdf, 0x01, 0x00, 0x94, 0x60, 0x29,
0x00, 0x34, 0xa1, 0xc3, 0x02, 0xd1, 0xe0, 0x03, 0x17, 0xaa, 0x82, 0x00, 0x80, 0x52, 0xda, 0x01, 0x00, 0x94, 0xc0,
0x28, 0x00, 0x36, 0x68, 0x2b, 0x40, 0xf9, 0xa0, 0x03, 0x5a, 0xf8, 0xa1, 0x03, 0x56, 0xb8, 0xa2, 0x03, 0x55, 0xb8,
0x00, 0x01, 0x3f, 0xd6, 0xc0, 0xec, 0xff, 0x34, 0x3f, 0x01, 0x00, 0x14, 0xa1, 0x83, 0x01, 0xd1, 0xcb, 0x01, 0x00,
0x94, 0x80, 0x27, 0x00, 0x34, 0xa1, 0x83, 0x02, 0xd1, 0xc8, 0x01, 0x00, 0x94, 0x20, 0x27, 0x00, 0x34, 0xa1, 0xc3,
0x02, 0xd1, 0xe0, 0x03, 0x17, 0xaa, 0x42, 0x00, 0x80, 0x52, 0xc8, 0x01, 0x00, 0x94, 0x80, 0x26, 0x00, 0x34, 0xf4,
0x03, 0x00, 0x91, 0xa8, 0x03, 0x55, 0x78, 0x08, 0x71, 0x1d, 0x53, 0x08, 0x3d, 0x00, 0x11, 0x08, 0x3d, 0x7c, 0x92,
0xe9, 0x03, 0x00, 0x91, 0x38, 0x01, 0x08, 0xcb, 0x1f, 0x03, 0x00, 0x91, 0xa8, 0x03, 0x55, 0x78, 0x02, 0xf1, 0x7d,
0xd3, 0xe0, 0x03, 0x17, 0xaa, 0xe1, 0x03, 0x18, 0xaa, 0xba, 0x01, 0x00, 0x94, 0xa0, 0x24, 0x00, 0x34, 0xa1, 0xe3,
0x02, 0xd1, 0xe0, 0x03, 0x17, 0xaa, 0x42, 0x00, 0x80, 0x52, 0xb5, 0x01, 0x00, 0x94, 0x00, 0x24, 0x00, 0x34, 0xa8,
0x83, 0x54, 0x78, 0x09, 0x71, 0x1d, 0x53, 0x29, 0x3d, 0x00, 0x11, 0x29, 0x3d, 0x7c, 0x92, 0xea, 0x03, 0x00, 0x91,
0x59, 0x01, 0x09, 0xcb, 0x3f, 0x03, 0x00, 0x91, 0x02, 0x7d, 0x7d, 0xd3, 0xe0, 0x03, 0x17, 0xaa, 0xe1, 0x03, 0x19,
0xaa, 0xa9, 0x01, 0x00, 0x94, 0x80, 0x22, 0x00, 0x34, 0x15, 0x00, 0x80, 0xd2, 0xb6, 0x03, 0x5a, 0xf8, 0xbb, 0x03,
0x56, 0xf8, 0xbc, 0x83, 0x54, 0x78, 0xbf, 0x02, 0x1c, 0xeb, 0x00, 0x1a, 0x00, 0x54, 0x3a, 0x7b, 0x75, 0xf8, 0x53,
0x03, 0x40, 0xf9, 0xf3, 0x01, 0xf0, 0xb7, 0x68, 0xfe, 0x6b, 0xd3, 0x69, 0xaa, 0x40, 0x92, 0x6a, 0xaa, 0x6a, 0x93,
0x4a, 0x31, 0x55, 0x92, 0x09, 0x1d, 0x48, 0xb3, 0x28, 0x01, 0x0a, 0xaa, 0xe9, 0x03, 0x13, 0x2a, 0x7f, 0x02, 0x41,
0xf2, 0xea, 0x03, 0x96, 0x9a, 0x08, 0x01, 0x89, 0x9a, 0x49, 0x01, 0x1b, 0x8b, 0x20, 0x01, 0x08, 0x8b, 0x53, 0x01,
0xf8, 0xb6, 0x04, 0x00, 0x00, 0x14, 0x68, 0x3e, 0x40, 0x92, 0x00, 0x7b, 0x68, 0xf8, 0xd3, 0x00, 0xf8, 0xb6, 0x61,
0xca, 0x71, 0xd3, 0x63, 0xc2, 0x70, 0xd3, 0x62, 0xbe, 0x60, 0xd3, 0xe4, 0x03, 0x1a, 0xaa, 0x63, 0x01, 0x00, 0x94,
0x40, 0x03, 0x00, 0xf9, 0x68, 0xf6, 0x73, 0xd3, 0x5a, 0x0f, 0x08, 0x8b, 0x7f, 0x2a, 0x4d, 0xf2, 0x81, 0xfc, 0xff,
0x54, 0xb5, 0x06, 0x00, 0x91, 0xdf, 0xff, 0xff, 0x17, 0xa1, 0x83, 0x01, 0xd1, 0x7b, 0x01, 0x00, 0x94, 0x80, 0x1d,
0x00, 0x34, 0xa1, 0x93, 0x02, 0xd1, 0xe0, 0x03, 0x17, 0xaa, 0x82, 0x00, 0x80, 0x52, 0x7b, 0x01, 0x00, 0x94, 0xe0,
0x1c, 0x00, 0x34, 0xa1, 0x83, 0x02, 0xd1, 0x73, 0x01, 0x00, 0x94, 0x80, 0x1c, 0x00, 0x34, 0x13, 0x00, 0x80, 0x52,
0xb4, 0x03, 0x5a, 0xf8, 0xa8, 0xc3, 0x55, 0xb8, 0x7f, 0x02, 0x08, 0x6b, 0xa0, 0xe0, 0xff, 0x54, 0xbf, 0xff, 0x34,
0xa9, 0xa8, 0x03, 0x56, 0xf8, 0x89, 0x5a, 0x73, 0xb8, 0x08, 0x01, 0x09, 0x8b, 0xa1, 0xc3, 0x02, 0xd1, 0xa2, 0xe3,
0x02, 0xd1, 0x78, 0x01, 0x00, 0x94, 0x73, 0x06, 0x00, 0x11, 0xf5, 0xff, 0xff, 0x17, 0x71, 0x01, 0x00, 0x94, 0x40,
0xdf, 0x07, 0x37, 0xd3, 0x00, 0x00, 0x14, 0x98, 0x0e, 0x15, 0x8b, 0x88, 0xe7, 0x41, 0x29, 0x96, 0x03, 0x08, 0x8b,
0x88, 0x17, 0x40, 0xb9, 0x1f, 0x0d, 0x00, 0x71, 0xc0, 0x16, 0x00, 0x54, 0x1f, 0x09, 0x00, 0x71, 0xc0, 0x13, 0x00,
0x54, 0x1f, 0x05, 0x00, 0x71, 0x81, 0x02, 0x00, 0x54, 0x88, 0x0b, 0x40, 0xb9, 0x93, 0x03, 0x08, 0x8b, 0x94, 0x22,
0x00, 0xd1, 0xf5, 0x03, 0x18, 0xaa, 0xf9, 0x01, 0x00, 0xb4, 0x69, 0x02, 0x40, 0xb9, 0x28, 0x1d, 0x40, 0x92, 0xe8,
0x00, 0x00, 0x34, 0xc9, 0x26, 0x49, 0x8b, 0x55, 0x01, 0x00, 0x94, 0x80, 0x7a, 0x68, 0xf8, 0x20, 0x01, 0x3f, 0xd6,
0xe0, 0x43, 0xc1, 0xda, 0x02, 0x00, 0x00, 0x14, 0x00, 0x00, 0x80, 0xd2, 0xa0, 0x86, 0x00, 0xf8, 0x73, 0x12, 0x00,
0x91, 0x39, 0x07, 0x00, 0xd1, 0x79, 0xfe, 0xff, 0xb5, 0x09, 0x00, 0x80, 0xd2, 0x88, 0x07, 0x40, 0xb9, 0x88, 0x03,
0x08, 0x8b, 0xa8, 0x03, 0x10, 0xf8, 0x0a, 0x45, 0x40, 0xb8, 0xaa, 0x03, 0x12, 0xf8, 0xa8, 0x03, 0x11, 0xf8, 0xa8,
0x03, 0x52, 0xf8, 0x3f, 0x01, 0x08, 0xeb, 0xc0, 0x0c, 0x00, 0x54, 0xa9, 0x83, 0x12, 0xf8, 0xa8, 0x03, 0x51, 0xf8,
0x08, 0x79, 0x69, 0xb8, 0xc8, 0x0b, 0x00, 0x34, 0x1c, 0x00, 0x80, 0xd2, 0xa9, 0x03, 0x50, 0xf8, 0x35, 0x01, 0x08,
0x8b, 0xa8, 0x0e, 0x40, 0x79, 0xa9, 0x2a, 0x40, 0x79, 0xa9, 0x03, 0x14, 0xf8, 0xa9, 0x5a, 0x00, 0x91, 0xa9, 0x83,
0x13, 0xf8, 0x09, 0x79, 0x1d, 0x12, 0xa9, 0x43, 0x13, 0xb8, 0x1f, 0x31, 0x00, 0x71, 0xe9, 0xff, 0x9f, 0x52, 0x0a,
0xe0, 0xbf, 0x12, 0x54, 0x01, 0x89, 0x9a, 0x1f, 0x05, 0x00, 0x71, 0xaa, 0x83, 0x50, 0xf8, 0x49, 0x01, 0x9f, 0x9a,
0x56, 0x03, 0x09, 0xcb, 0x1f, 0x19, 0x00, 0x71, 0xe8, 0x03, 0x8a, 0x9a, 0x5b, 0x03, 0x08, 0xcb, 0xa8, 0x03, 0x54,
0xf8, 0x9f, 0x03, 0x08, 0xeb, 0xc0, 0x08, 0x00, 0x54, 0xa8, 0x83, 0x53, 0xf8, 0x08, 0x79, 0x7c, 0x78, 0xe9, 0xff,
0x9f, 0x52, 0x1f, 0x01, 0x09, 0xeb, 0xe0, 0x07, 0x00, 0x54, 0xa9, 0x06, 0x40, 0xf9, 0x49, 0x03, 0x09, 0x8b, 0xaa,
0x0a, 0x40, 0x79, 0x89, 0x27, 0x0a, 0x9b, 0x39, 0x01, 0x08, 0x8b, 0xa8, 0x43, 0x53, 0xb8, 0x1f, 0x09, 0x00, 0x71,
0x41, 0x02, 0x00, 0x54, 0x29, 0x03, 0x40, 0xf9, 0xe9, 0x00, 0xf8, 0xb7, 0x28, 0xfd, 0x73, 0xd3, 0x2a, 0xfd, 0x64,
0xd3, 0x29, 0x8d, 0x40, 0x92, 0x69, 0x03, 0x09, 0x8b, 0x29, 0xe1, 0x0a, 0x8b, 0x06, 0x00, 0x00, 0x14, 0x28, 0xf9,
0x73, 0xd3, 0x2a, 0x5d, 0x40, 0x92, 0x0a, 0x7b, 0x6a, 0xf8, 0x29, 0xfd, 0x58, 0xd3, 0x49, 0x01, 0x29, 0x8b, 0x29,
0x03, 0x00, 0xf9, 0x39, 0x0b, 0x08, 0x8b, 0x28, 0xfe, 0xff, 0xb5, 0x26, 0x00, 0x00, 0x14, 0x33, 0x03, 0x40, 0xf9,
0x70, 0xfe, 0x7e, 0xd3, 0x62, 0xbe, 0x60, 0xd3, 0x63, 0xc2, 0x70, 0xd3, 0x61, 0xca, 0x71, 0xd3, 0x1f, 0x0e, 0x00,
0xf1, 0x10, 0x92, 0x9f, 0x9a, 0x11, 0x00, 0x00, 0x90, 0x31, 0xc2, 0x22, 0x91, 0x30, 0x7a, 0xb0, 0xb8, 0x11, 0x00,
0x00, 0x10, 0x30, 0x02, 0x10, 0x8b, 0x00, 0x02, 0x1f, 0xd6, 0x68, 0xfe, 0x6b, 0xd3, 0x69, 0xaa, 0x40, 0x92, 0xc9,
0x02, 0x09, 0x8b, 0x20, 0xe1, 0x08, 0x8b, 0x10, 0x00, 0x00, 0x14, 0x40, 0x43, 0x33, 0x8b, 0x03, 0x00, 0x00, 0x14,
0x68, 0x02, 0x14, 0x8a, 0x00, 0x7b, 0x68, 0xf8, 0xe4, 0x03, 0x19, 0xaa, 0xc7, 0x00, 0x00, 0x94, 0x09, 0x00, 0x00,
0x14, 0x68, 0x02, 0x14, 0x8a, 0x08, 0x7b, 0x68, 0xf8, 0x89, 0x00, 0xa0, 0x52, 0x3f, 0x81, 0x53, 0xea, 0xe9, 0xb3,
0x6d, 0xb2, 0xe9, 0x03, 0x89, 0x9a, 0x69, 0xca, 0x60, 0xb3, 0x00, 0x01, 0x09, 0x8b, 0x20, 0x03, 0x00, 0xf9, 0x68,
0xf6, 0x73, 0xd3, 0x39, 0x0f, 0x08, 0x8b, 0x88, 0xfb, 0xff, 0xb5, 0x9c, 0x07, 0x00, 0x91, 0xb9, 0xff, 0xff, 0x17,
0xa9, 0x83, 0x52, 0xf8, 0x29, 0x05, 0x00, 0x91, 0xbb, 0x83, 0x51, 0xf8, 0x99, 0xff, 0xff, 0x17, 0x68, 0x3f, 0x40,
0xf9, 0xa1, 0x03, 0x5a, 0xf8, 0xa9, 0x63, 0x00, 0xd1, 0x20, 0x01, 0x50, 0xb8, 0x22, 0x00, 0xa0, 0x52, 0x00, 0x01,
0x3f, 0xd6, 0x03, 0x00, 0x00, 0x14, 0x9f, 0x02, 0x00, 0x91, 0xbb, 0x83, 0x51, 0xf8, 0xa8, 0x13, 0x00, 0xd1, 0x15,
0x01, 0x50, 0xb8, 0xa8, 0x43, 0x00, 0xd1, 0x16, 0x01, 0x50, 0xf8, 0xa8, 0x53, 0x00, 0xd1, 0x1a, 0x01, 0x50, 0xb8,
0x38, 0x00, 0x80, 0x52, 0x5c, 0xfe, 0xff, 0x17, 0x13, 0x00, 0x80, 0x52, 0x68, 0x3f, 0x40, 0xf9, 0xa1, 0x03, 0x56,
0xf8, 0xa2, 0x83, 0x54, 0xb8, 0xe0, 0x03, 0x1a, 0xaa, 0x00, 0x01, 0x3f, 0xd6, 0xb3, 0xca, 0x07, 0x37, 0x2e, 0x00,
0x00, 0x14, 0x88, 0x0b, 0x40, 0xb9, 0x93, 0x22, 0x00, 0xd1, 0x88, 0x03, 0x08, 0x8b, 0x14, 0x11, 0x00, 0x91, 0xf5,
0x03, 0x18, 0xaa, 0x79, 0xee, 0xff, 0xb4, 0x89, 0xc2, 0x5f, 0xb8, 0x28, 0x1d, 0x40, 0x92, 0xe8, 0x00, 0x00, 0x34,
0xc9, 0x26, 0x49, 0x8b, 0xb9, 0x00, 0x00, 0x94, 0x60, 0x7a, 0x68, 0xf8, 0x20, 0x01, 0x3f, 0xd6, 0xe0, 0x43, 0xc1,
0xda, 0x02, 0x00, 0x00, 0x14, 0x00, 0x00, 0x80, 0xd2, 0x88, 0x86, 0x80, 0xb8, 0x08, 0x00, 0x08, 0x8b, 0xa8, 0x86,
0x00, 0xf8, 0x39, 0x07, 0x00, 0xd1, 0x59, 0xfe, 0xff, 0xb5, 0x63, 0xff, 0xff, 0x17, 0xe8, 0x03, 0x1c, 0xaa, 0x09,
0x8d, 0x40, 0xb8, 0x93, 0x22, 0x00, 0xd1, 0x14, 0x01, 0x09, 0x8b, 0xf5, 0x03, 0x18, 0xaa, 0xb9, 0xeb, 0xff, 0xb4,
0x89, 0x82, 0x5f, 0xf8, 0x28, 0x3d, 0x40, 0xf2, 0xe0, 0x00, 0x00, 0x54, 0xc9, 0x82, 0x49, 0x8b, 0xa3, 0x00, 0x00,
0x94, 0x60, 0x7a, 0x68, 0xf8, 0x20, 0x01, 0x3f, 0xd6, 0xe0, 0x43, 0xc1, 0xda, 0x02, 0x00, 0x00, 0x14, 0x00, 0x00,
0x80, 0xd2, 0x88, 0x06, 0x41, 0xf8, 0x08, 0x00, 0x08, 0x8b, 0xa8, 0x86, 0x00, 0xf8, 0x39, 0x07, 0x00, 0xd1, 0x59,
0xfe, 0xff, 0xb5, 0x4d, 0xff, 0xff, 0x17, 0x9f, 0x02, 0x00, 0x91, 0xa4, 0x00, 0x00, 0x94, 0x68, 0x1b, 0x40, 0xf9,
0xe0, 0x03, 0x15, 0xaa, 0x00, 0x01, 0x3f, 0xd6, 0xa8, 0xc3, 0x99, 0xb8, 0xe0, 0x03, 0x08, 0xaa, 0x21, 0xa7, 0x80,
0xd2, 0x22, 0xa7, 0x80, 0xd2, 0x03, 0x00, 0x80, 0xd2, 0x20, 0xa7, 0x20, 0xd4, 0xa0, 0xc3, 0x99, 0xb8, 0xbf, 0x43,
0x01, 0xd1, 0xfd, 0x7b, 0x45, 0xa9, 0xf4, 0x4f, 0x44, 0xa9, 0xf6, 0x57, 0x43, 0xa9, 0xf8, 0x5f, 0x42, 0xa9, 0xfa,
0x67, 0x41, 0xa9, 0xfc, 0x6f, 0xc6, 0xa8, 0xc0, 0x03, 0x5f, 0xd6, 0x0c, 0x00, 0x00, 0x00, 0x38, 0x02, 0x00, 0x00,
0x1c, 0x01, 0x00, 0x00, 0xe8, 0x01, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x78, 0x03, 0x00, 0x00, 0xdc, 0x03, 0x00,
0x00, 0x0c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xf8, 0x5f,
0xbc, 0xa9, 0xf6, 0x57, 0x01, 0xa9, 0xf4, 0x4f, 0x02, 0xa9, 0xfd, 0x7b, 0x03, 0xa9, 0xfd, 0xc3, 0x00, 0x91, 0xf3,
0x03, 0x04, 0xaa, 0xf4, 0x03, 0x03, 0xaa, 0xf5, 0x03, 0x02, 0xaa, 0xf6, 0x03, 0x01, 0xaa, 0xf7, 0x03, 0x00, 0xaa,
0x43, 0x00, 0x00, 0xb4, 0x9f, 0x02, 0x00, 0xf9, 0xbf, 0x02, 0x00, 0xf1, 0xf8, 0x17, 0x9f, 0x1a, 0xd5, 0x03, 0x00,
0xb4, 0x68, 0x1e, 0x40, 0xf9, 0xe0, 0x03, 0x17, 0xaa, 0xe1, 0x03, 0x16, 0xaa, 0xe2, 0x03, 0x15, 0xaa, 0x00, 0x01,
0x3f, 0xd6, 0x1f, 0x04, 0x00, 0xb1, 0xe1, 0x00, 0x00, 0x54, 0x68, 0x4e, 0x40, 0xf9, 0x00, 0x01, 0x3f, 0xd6, 0x08,
0x00, 0x40, 0xb9, 0x1f, 0x11, 0x00, 0x71, 0xa0, 0xfe, 0xff, 0x54, 0x0a, 0x00, 0x00, 0x14, 0x1f, 0x04, 0x00, 0xf1,
0x2b, 0x01, 0x00, 0x54, 0x94, 0x00, 0x00, 0xb4, 0x88, 0x02, 0x40, 0xf9, 0x08, 0x01, 0x00, 0x8b, 0x88, 0x02, 0x00,
0xf9, 0xd6, 0x02, 0x00, 0x8b, 0xb5, 0x02, 0x00, 0xcb, 0xe8, 0xff, 0xff, 0x17, 0x18, 0x00, 0x80, 0x52, 0xe0, 0x03,
0x18, 0xaa, 0xfd, 0x7b, 0x43, 0xa9, 0xf4, 0x4f, 0x42, 0xa9, 0xf6, 0x57, 0x41, 0xa9, 0xf8, 0x5f, 0xc4, 0xa8, 0xc0,
0x03, 0x5f, 0xd6, 0x38, 0x00, 0x80, 0x52, 0xf9, 0xff, 0xff, 0x17, 0xf6, 0x57, 0xbd, 0xa9, 0xf4, 0x4f, 0x01, 0xa9,
0xfd, 0x7b, 0x02, 0xa9, 0xfd, 0x83, 0x00, 0x91, 0xf3, 0x03, 0x02, 0xaa, 0xf4, 0x03, 0x01, 0xaa, 0xf5, 0x03, 0x00,
0xaa, 0x88, 0x00, 0x80, 0x52, 0xf6, 0x03, 0x08, 0xaa, 0x48, 0x02, 0x00, 0xb4, 0x68, 0x22, 0x40, 0xf9, 0xe0, 0x03,
0x15, 0xaa, 0xe1, 0x03, 0x14, 0xaa, 0xe2, 0x03, 0x16, 0xaa, 0x00, 0x01, 0x3f, 0xd6, 0x1f, 0x04, 0x00, 0xb1, 0xe1,
0x00, 0x00, 0x54, 0x68, 0x4e, 0x40, 0xf9, 0x00, 0x01, 0x3f, 0xd6, 0x08, 0x00, 0x40, 0xb9, 0x1f, 0x11, 0x00, 0x71,
0xa0, 0xfe, 0xff, 0x54, 0x05, 0x00, 0x00, 0x14, 0x94, 0x02, 0x00, 0x8b, 0xc8, 0x02, 0x00, 0xcb, 0x1f, 0x00, 0x00,
0xf1, 0xcc, 0xfd, 0xff, 0x54, 0xdf, 0x02, 0x00, 0xf1, 0xe0, 0x17, 0x9f, 0x1a, 0xfd, 0x7b, 0x42, 0xa9, 0xf4, 0x4f,
0x41, 0xa9, 0xf6, 0x57, 0xc3, 0xa8, 0xc0, 0x03, 0x5f, 0xd6, 0x44, 0x3c, 0x50, 0xb3, 0x7f, 0x00, 0x00, 0x71, 0x48,
0x00, 0x84, 0x9a, 0xf0, 0x03, 0x01, 0x2a, 0x1f, 0x0e, 0x00, 0xf1, 0x10, 0x92, 0x9f, 0x9a, 0x11, 0x00, 0x00, 0x90,
0x31, 0xc2, 0x29, 0x91, 0x30, 0x7a, 0xb0, 0xb8, 0x11, 0x00, 0x00, 0x10, 0x30, 0x02, 0x10, 0x8b, 0x00, 0x02, 0x1f,
0xd6, 0xf1, 0x03, 0x00, 0xaa, 0xf0, 0x03, 0x08, 0xaa, 0x1f, 0x21, 0x03, 0xd5, 0x0c, 0x00, 0x00, 0x14, 0xf1, 0x03,
0x00, 0xaa, 0xf0, 0x03, 0x08, 0xaa, 0x11, 0x0a, 0xc1, 0xda, 0x08, 0x00, 0x00, 0x14, 0xf1, 0x03, 0x00, 0xaa, 0xf0,
0x03, 0x08, 0xaa, 0x11, 0x0e, 0xc1, 0xda, 0x04, 0x00, 0x00, 0x14, 0xf1, 0x03, 0x00, 0xaa, 0xf0, 0x03, 0x08, 0xaa,
0x5f, 0x21, 0x03, 0xd5, 0xe0, 0x03, 0x11, 0xaa, 0xc0, 0x03, 0x5f, 0xd6, 0x0c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00,
0x00, 0x1c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x17, 0xaa, 0x02, 0x01, 0x80, 0x52, 0x03, 0x00,
0x80, 0xd2, 0xe4, 0x03, 0x1b, 0xaa, 0x8c, 0xff, 0xff, 0x17, 0x03, 0x00, 0x80, 0xd2, 0xe4, 0x03, 0x1b, 0xaa, 0x89,
0xff, 0xff, 0x17, 0xea, 0x03, 0x09, 0xaa, 0x4b, 0x15, 0x40, 0x38, 0x7f, 0x7d, 0x01, 0x71, 0x21, 0x11, 0x8a, 0x9a,
0x69, 0x4b, 0x40, 0xf9, 0xc0, 0x03, 0x5f, 0xd6, 0xa1, 0xf3, 0x01, 0xd1, 0xe0, 0x03, 0x17, 0xaa, 0xe2, 0x03, 0x1b,
0xaa, 0xad, 0xff, 0xff, 0x17, 0xa4, 0x93, 0x01, 0xd1, 0x00, 0x00, 0x80, 0x52, 0xe3, 0x03, 0x16, 0xaa, 0x00, 0x01,
0x1f, 0xd6, 0x68, 0x1b, 0x40, 0xf9, 0xe0, 0x03, 0x17, 0xaa, 0x00, 0x01, 0x1f, 0xd6, 0xa0, 0x03, 0x5a, 0xf8, 0xa1,
0x03, 0x55, 0xf8, 0x00, 0x01, 0x1f, 0xd6
};
private static bool is_dyld_stub_binder (string module_name, string symbol_name) {
@@ -813,7 +855,7 @@ namespace Frida.Fruity.Injector {
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);
throw new Error.NOT_SUPPORTED ("Unsupported iOS version (%s not found)", nick);
return val;
}
@@ -863,7 +905,7 @@ namespace Frida.Fruity.Injector {
GDB.Breakpoint? hit_breakpoint = exception.breakpoint;
if (hit_breakpoint == null)
throw new Error.UNSUPPORTED ("Unexpected exception");
throw new Error.NOT_SUPPORTED ("Unexpected exception");
if (restart_breakpoint != null)
yield restart_breakpoint.remove (cancellable);
@@ -871,7 +913,7 @@ namespace Frida.Fruity.Injector {
if (hit_breakpoint == restart_breakpoint) {
if (process_info_ptr == null)
throw new Error.UNSUPPORTED ("Missing gProcessInfo");
throw new Error.NOT_SUPPORTED ("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);
@@ -892,7 +934,7 @@ namespace Frida.Fruity.Injector {
hit_breakpoint = exception.breakpoint;
if (hit_breakpoint == null)
throw new Error.UNSUPPORTED ("Unexpected exception");
throw new Error.NOT_SUPPORTED ("Unexpected exception");
dyld_fields = yield lldb.get_apple_dyld_fields (BYPASS_CACHE, cancellable);
}
@@ -924,7 +966,7 @@ namespace Frida.Fruity.Injector {
hit_breakpoint = exception.breakpoint;
if (hit_breakpoint == null)
throw new Error.UNSUPPORTED ("Unexpected exception");
throw new Error.NOT_SUPPORTED ("Unexpected exception");
assert (hit_breakpoint == caller_breakpoint);
yield caller_breakpoint.remove (cancellable);
@@ -959,7 +1001,7 @@ namespace Frida.Fruity.Injector {
GDB.Breakpoint? hit_breakpoint = exception.breakpoint;
if (hit_breakpoint == null)
throw new Error.UNSUPPORTED ("Unexpected exception");
throw new Error.NOT_SUPPORTED ("Unexpected exception");
yield legacy_breakpoint.remove (cancellable);
@@ -1005,7 +1047,7 @@ namespace Frida.Fruity.Injector {
}
}
throw new Error.UNSUPPORTED ("Unable to probe dyld v3 internals; please file a bug");
throw new Error.NOT_SUPPORTED ("Unable to probe dyld v3 internals; please file a bug");
}
private async void initialize_libsystem_from_legacy_codepath (Gee.Map<string, uint64?> dyld_symbols,
@@ -1178,14 +1220,14 @@ namespace Frida.Fruity.Injector {
}, null, cancellable);
size_t size = length + 1;
if (size > page_size)
throw new Error.UNSUPPORTED ("Buffer too small; please file a bug");
throw new Error.NOT_SUPPORTED ("Buffer too small; please file a bug");
Bytes output_bytes = yield lldb.read_byte_array (output, size, cancellable);
unowned string output_str = (string) output_bytes.get_data ();
foreach (var line in output_str.split ("\n")) {
var tokens = line.split ("\t", 2);
if (tokens.length != 2)
throw new Error.UNSUPPORTED ("Unable to fetch dyld symbols; please file a bug");
throw new Error.NOT_SUPPORTED ("Unable to fetch dyld symbols; please file a bug");
unowned string raw_address = tokens[0];
unowned string name = tokens[1];
@@ -1202,73 +1244,72 @@ namespace Frida.Fruity.Injector {
/* Compiled from helpers/symbol-fetcher.c */
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, 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, 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, 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, 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
0xa9, 0xf4, 0x4f, 0x06, 0xa9, 0xfd, 0x7b, 0x07, 0xa9, 0xfd, 0xc3, 0x01, 0x91, 0xf4, 0x03, 0x01, 0xaa, 0xe0, 0x0b,
0x00, 0xf9, 0x13, 0x00, 0x80, 0xd2, 0x15, 0x00, 0x80, 0xd2, 0x38, 0x80, 0x00, 0x91, 0x39, 0x10, 0x40, 0xb9, 0x16,
0x00, 0x00, 0x90, 0xd6, 0x1e, 0x13, 0x91, 0x1a, 0x00, 0x00, 0x90, 0x5a, 0x3b, 0x13, 0x91, 0xd9, 0x03, 0x00, 0x34,
0x08, 0x03, 0x40, 0xb9, 0x1f, 0x09, 0x00, 0x71, 0xa0, 0x01, 0x00, 0x54, 0x1f, 0x2d, 0x00, 0x71, 0x20, 0x01, 0x00,
0x54, 0x1f, 0x65, 0x00, 0x71, 0x41, 0x01, 0x00, 0x54, 0x00, 0x23, 0x00, 0x91, 0xe1, 0x03, 0x16, 0xaa, 0xa4, 0x00,
0x00, 0x94, 0x60, 0x01, 0x00, 0x34, 0x13, 0xef, 0x41, 0xa9, 0x04, 0x00, 0x00, 0x14, 0xfc, 0x03, 0x18, 0xaa, 0x02,
0x00, 0x00, 0x14, 0xf7, 0x03, 0x18, 0xaa, 0x08, 0x07, 0x40, 0xb9, 0x18, 0x03, 0x08, 0x8b, 0x39, 0x07, 0x00, 0x51,
0xb9, 0xfd, 0xff, 0x35, 0x09, 0x00, 0x00, 0x14, 0x00, 0x23, 0x00, 0x91, 0xe1, 0x03, 0x1a, 0xaa, 0x96, 0x00, 0x00,
0x94, 0x00, 0xff, 0xff, 0x34, 0x08, 0x0f, 0x40, 0xf9, 0x09, 0x17, 0x40, 0xf9, 0x15, 0x01, 0x09, 0xcb, 0xf4, 0xff,
0xff, 0x17, 0xfb, 0x07, 0x00, 0xf9, 0x1b, 0x00, 0x80, 0x52, 0x88, 0x02, 0x13, 0xcb, 0xa8, 0x02, 0x08, 0x8b, 0xe9,
0x0a, 0x40, 0xb9, 0x1a, 0x01, 0x09, 0x8b, 0xe9, 0x12, 0x40, 0xb9, 0x13, 0x01, 0x09, 0x8b, 0xe8, 0x0b, 0x40, 0xf9,
0xe8, 0x0f, 0x00, 0xf9, 0x16, 0x00, 0x00, 0x90, 0xd6, 0x52, 0x0f, 0x91, 0x39, 0x01, 0x80, 0x52, 0x95, 0x0b, 0x40,
0xb9, 0x88, 0x0f, 0x40, 0xb9, 0xbf, 0x02, 0x08, 0x6b, 0x40, 0x0a, 0x00, 0x54, 0x58, 0x53, 0x35, 0x8b, 0x17, 0x03,
0x40, 0xb9, 0x60, 0x02, 0x17, 0x8b, 0xe1, 0x03, 0x16, 0xaa, 0x64, 0x00, 0x00, 0x94, 0xa0, 0x07, 0x00, 0x37, 0x60,
0x02, 0x17, 0x8b, 0x01, 0x00, 0x00, 0x90, 0x21, 0x9c, 0x0f, 0x91, 0x5f, 0x00, 0x00, 0x94, 0x00, 0x07, 0x00, 0x37,
0x60, 0x02, 0x17, 0x8b, 0x01, 0x00, 0x00, 0x90, 0x21, 0xd8, 0x0f, 0x91, 0x5a, 0x00, 0x00, 0x94, 0x60, 0x06, 0x00,
0x37, 0x60, 0x02, 0x17, 0x8b, 0x01, 0x00, 0x00, 0x90, 0x21, 0x34, 0x10, 0x91, 0x6c, 0x00, 0x00, 0x94, 0xc0, 0x05,
0x00, 0x37, 0x60, 0x02, 0x17, 0x8b, 0x01, 0x00, 0x00, 0x90, 0x21, 0x6c, 0x10, 0x91, 0x67, 0x00, 0x00, 0x94, 0x20,
0x05, 0x00, 0x37, 0x60, 0x02, 0x17, 0x8b, 0x01, 0x00, 0x00, 0x90, 0x21, 0xd4, 0x10, 0x91, 0x62, 0x00, 0x00, 0x94,
0x80, 0x04, 0x00, 0x37, 0x60, 0x02, 0x17, 0x8b, 0x01, 0x00, 0x00, 0x90, 0x21, 0x20, 0x11, 0x91, 0x46, 0x00, 0x00,
0x94, 0xe0, 0x03, 0x00, 0x37, 0x60, 0x02, 0x17, 0x8b, 0x01, 0x00, 0x00, 0x90, 0x21, 0x68, 0x11, 0x91, 0x41, 0x00,
0x00, 0x94, 0x40, 0x03, 0x00, 0x37, 0x60, 0x02, 0x17, 0x8b, 0x01, 0x00, 0x00, 0x90, 0x21, 0xcc, 0x11, 0x91, 0x3c,
0x00, 0x00, 0x94, 0xa0, 0x02, 0x00, 0x37, 0x60, 0x02, 0x17, 0x8b, 0x01, 0x00, 0x00, 0x90, 0x21, 0x24, 0x12, 0x91,
0x56, 0x00, 0x00, 0x94, 0x00, 0x02, 0x00, 0x37, 0x60, 0x02, 0x17, 0x8b, 0x01, 0x00, 0x00, 0x90, 0x21, 0x44, 0x12,
0x91, 0x51, 0x00, 0x00, 0x94, 0x60, 0x01, 0x00, 0x37, 0x60, 0x02, 0x17, 0x8b, 0x01, 0x00, 0x00, 0x90, 0x21, 0x64,
0x12, 0x91, 0x2d, 0x00, 0x00, 0x94, 0xc0, 0x00, 0x00, 0x37, 0x60, 0x02, 0x17, 0x8b, 0x01, 0x00, 0x00, 0x90, 0x21,
0xb0, 0x12, 0x91, 0x28, 0x00, 0x00, 0x94, 0xc0, 0x01, 0x00, 0x34, 0x5b, 0x00, 0x00, 0x34, 0x6c, 0x00, 0x00, 0x94,
0x08, 0x07, 0x40, 0xf9, 0xe0, 0x63, 0x00, 0x91, 0x81, 0x02, 0x08, 0x8b, 0x49, 0x00, 0x00, 0x94, 0xe8, 0x0f, 0x40,
0xf9, 0x19, 0x15, 0x00, 0x38, 0xe8, 0x0f, 0x00, 0xf9, 0xe0, 0x63, 0x00, 0x91, 0x61, 0x02, 0x17, 0x8b, 0x5a, 0x00,
0x00, 0x94, 0x7b, 0x07, 0x00, 0x11, 0xb5, 0x06, 0x00, 0x11, 0xad, 0xff, 0xff, 0x17, 0x5e, 0x00, 0x00, 0x94, 0xe0,
0x63, 0x00, 0x91, 0xe1, 0x07, 0x40, 0xf9, 0x3c, 0x00, 0x00, 0x94, 0xe8, 0x0f, 0x40, 0xf9, 0x29, 0x01, 0x80, 0x52,
0x09, 0x15, 0x00, 0x38, 0xe8, 0x0f, 0x00, 0xf9, 0x01, 0x00, 0x00, 0x90, 0x21, 0xf4, 0x12, 0x91, 0xe0, 0x63, 0x00,
0x91, 0x4b, 0x00, 0x00, 0x94, 0xe9, 0x23, 0x41, 0xa9, 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, 0x81, 0x13,
0x91, 0x5f, 0x11, 0x00, 0x31, 0x80, 0x01, 0x00, 0x54, 0x2c, 0x24, 0xca, 0x9a, 0x8c, 0x0d, 0x40, 0xf2, 0xed, 0x17,
0x9f, 0x1a, 0x2d, 0x01, 0x0d, 0x2a, 0xbf, 0x01, 0x00, 0x72, 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, 0xe8, 0x0f, 0x40, 0xf9, 0x49, 0x01, 0x80, 0x52, 0x09,
0x15, 0x00, 0x38, 0xe8, 0x0f, 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, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
};
private async SymbolSet resolve_symbols (SymbolQuery query, Cancellable? cancellable) throws GLib.Error {
@@ -1343,52 +1384,52 @@ namespace Frida.Fruity.Injector {
private const uint8[] SYMBOL_RESOLVER_CODE = {
0xff, 0xc3, 0x01, 0xd1, 0xfc, 0x6f, 0x01, 0xa9, 0xfa, 0x67, 0x02, 0xa9, 0xf8, 0x5f, 0x03, 0xa9, 0xf6, 0x57, 0x04,
0xa9, 0xf4, 0x4f, 0x05, 0xa9, 0xfd, 0x7b, 0x06, 0xa9, 0xfd, 0x83, 0x01, 0x91, 0xf5, 0x03, 0x02, 0xaa, 0xf3, 0x03,
0x01, 0xaa, 0xf4, 0x03, 0x00, 0xaa, 0x08, 0x00, 0x80, 0xd2, 0x49, 0x04, 0x40, 0xb9, 0x0a, 0x03, 0x80, 0x52, 0xeb,
0x07, 0x7d, 0xb2, 0x37, 0x2d, 0x0a, 0x9b, 0x76, 0x19, 0x00, 0x30, 0x1f, 0x20, 0x03, 0xd5, 0x18, 0x61, 0x00, 0x91,
0x01, 0xaa, 0xf4, 0x03, 0x00, 0xaa, 0x08, 0x00, 0x80, 0xd2, 0x49, 0x04, 0x40, 0xb9, 0x0a, 0x03, 0x80, 0x52, 0x29,
0x7d, 0xaa, 0x9b, 0x37, 0x61, 0x00, 0x91, 0x16, 0x00, 0x00, 0x90, 0xd6, 0xa6, 0x0d, 0x91, 0x18, 0x61, 0x00, 0x91,
0xff, 0x02, 0x18, 0xeb, 0x60, 0x01, 0x00, 0x54, 0xb9, 0x06, 0x40, 0xf9, 0x28, 0x03, 0x08, 0x8b, 0x00, 0x05, 0x40,
0xf9, 0xe1, 0x03, 0x16, 0xaa, 0xad, 0x00, 0x00, 0x94, 0xe8, 0x03, 0x18, 0xaa, 0xe0, 0xfe, 0xff, 0x34, 0x28, 0x03,
0x18, 0x8b, 0x08, 0x81, 0x5e, 0xf8, 0x02, 0x00, 0x00, 0x14, 0x08, 0x00, 0x80, 0xd2, 0x19, 0x00, 0x80, 0xd2, 0xe8,
0x7f, 0x00, 0xa9, 0x16, 0x00, 0x80, 0xd2, 0x1b, 0x00, 0x80, 0xd2, 0x1c, 0x81, 0x00, 0x91, 0x1a, 0x11, 0x40, 0xb9,
0x58, 0x04, 0x80, 0x52, 0x18, 0x00, 0xb0, 0x72, 0x75, 0x06, 0x80, 0x52, 0x15, 0x00, 0xb0, 0x72, 0x5a, 0x04, 0x00,
0x34, 0x88, 0x03, 0x40, 0xb9, 0x1f, 0x01, 0x18, 0x6b, 0xa0, 0x01, 0x00, 0x54, 0x1f, 0x01, 0x15, 0x6b, 0xa0, 0x01,
0x00, 0x54, 0x1f, 0x65, 0x00, 0x71, 0x81, 0x01, 0x00, 0x54, 0x97, 0x23, 0x00, 0x91, 0xe0, 0x03, 0x17, 0xaa, 0x41,
0x14, 0x00, 0x70, 0x1f, 0x20, 0x03, 0xd5, 0x90, 0x00, 0x00, 0x94, 0x60, 0x01, 0x00, 0x34, 0x99, 0x0f, 0x40, 0xf9,
0x04, 0x00, 0x00, 0x14, 0xf6, 0x03, 0x1c, 0xaa, 0x02, 0x00, 0x00, 0x14, 0xfb, 0x03, 0x1c, 0xaa, 0x88, 0x07, 0x40,
0xb9, 0x9c, 0x03, 0x08, 0x8b, 0x5a, 0x07, 0x00, 0x51, 0x7a, 0xfd, 0xff, 0x35, 0x0b, 0x00, 0x00, 0x14, 0xe0, 0x03,
0x17, 0xaa, 0xa1, 0x12, 0x00, 0x50, 0x1f, 0x20, 0x03, 0xd5, 0x81, 0x00, 0x00, 0x94, 0xe0, 0xfe, 0xff, 0x34, 0x88,
0xf9, 0xe1, 0x03, 0x16, 0xaa, 0xaf, 0x00, 0x00, 0x94, 0xe8, 0x03, 0x18, 0xaa, 0xe0, 0xfe, 0xff, 0x34, 0x28, 0x03,
0x18, 0x8b, 0x08, 0x81, 0x5e, 0xf8, 0x02, 0x00, 0x00, 0x14, 0x08, 0x00, 0x80, 0xd2, 0x18, 0x00, 0x80, 0xd2, 0xe8,
0x7f, 0x00, 0xa9, 0x1a, 0x00, 0x80, 0xd2, 0x1b, 0x00, 0x80, 0xd2, 0x1c, 0x81, 0x00, 0x91, 0x16, 0x11, 0x40, 0xb9,
0x59, 0x04, 0x80, 0x52, 0x19, 0x00, 0xb0, 0x72, 0x77, 0x06, 0x80, 0x52, 0x17, 0x00, 0xb0, 0x72, 0x15, 0x00, 0x00,
0x90, 0xb5, 0x5e, 0x0d, 0x91, 0x16, 0x04, 0x00, 0x34, 0x88, 0x03, 0x40, 0xb9, 0x1f, 0x01, 0x19, 0x6b, 0xa0, 0x01,
0x00, 0x54, 0x1f, 0x01, 0x17, 0x6b, 0x20, 0x01, 0x00, 0x54, 0x1f, 0x65, 0x00, 0x71, 0x41, 0x01, 0x00, 0x54, 0x80,
0x23, 0x00, 0x91, 0xe1, 0x03, 0x15, 0xaa, 0x92, 0x00, 0x00, 0x94, 0x60, 0x01, 0x00, 0x34, 0x98, 0x0f, 0x40, 0xf9,
0x04, 0x00, 0x00, 0x14, 0xfb, 0x03, 0x1c, 0xaa, 0x02, 0x00, 0x00, 0x14, 0xfa, 0x03, 0x1c, 0xaa, 0x88, 0x07, 0x40,
0xb9, 0x9c, 0x03, 0x08, 0x8b, 0xd6, 0x06, 0x00, 0x51, 0xb6, 0xfd, 0xff, 0x35, 0x0b, 0x00, 0x00, 0x14, 0x80, 0x23,
0x00, 0x91, 0x01, 0x00, 0x00, 0x90, 0x21, 0x78, 0x0d, 0x91, 0x83, 0x00, 0x00, 0x94, 0xe0, 0xfe, 0xff, 0x34, 0x88,
0x0f, 0x40, 0xf9, 0x89, 0x17, 0x40, 0xf9, 0x08, 0x01, 0x09, 0xcb, 0xe8, 0x07, 0x00, 0xf9, 0xf2, 0xff, 0xff, 0x17,
0x96, 0x00, 0x00, 0xb4, 0xc8, 0xa2, 0x00, 0x91, 0xf7, 0x03, 0x40, 0xf9, 0x04, 0x00, 0x00, 0x14, 0xf7, 0x03, 0x40,
0xf9, 0xbb, 0x05, 0x00, 0xb4, 0x68, 0x23, 0x00, 0x91, 0xe9, 0x02, 0x19, 0xcb, 0xea, 0x07, 0x40, 0xf9, 0x49, 0x01,
0x09, 0x8b, 0x08, 0x01, 0x40, 0xb9, 0x35, 0x01, 0x08, 0x8b, 0x61, 0x0f, 0x00, 0x10, 0x1f, 0x20, 0x03, 0xd5, 0xe0,
0x03, 0x15, 0xaa, 0x31, 0x00, 0x00, 0x94, 0xf6, 0x02, 0x00, 0x8b, 0x01, 0x0f, 0x00, 0x10, 0x1f, 0x20, 0x03, 0xd5,
0x9a, 0x00, 0x00, 0xb4, 0x48, 0xa3, 0x00, 0x91, 0xf7, 0x03, 0x40, 0xf9, 0x04, 0x00, 0x00, 0x14, 0xf7, 0x03, 0x40,
0xf9, 0xbb, 0x05, 0x00, 0xb4, 0x68, 0x23, 0x00, 0x91, 0xe9, 0x02, 0x18, 0xcb, 0xea, 0x07, 0x40, 0xf9, 0x49, 0x01,
0x09, 0x8b, 0x08, 0x01, 0x40, 0xb9, 0x35, 0x01, 0x08, 0x8b, 0x01, 0x00, 0x00, 0x90, 0x21, 0x20, 0x0d, 0x91, 0xe0,
0x03, 0x15, 0xaa, 0x31, 0x00, 0x00, 0x94, 0xf6, 0x02, 0x00, 0x8b, 0x01, 0x00, 0x00, 0x90, 0x21, 0x40, 0x0d, 0x91,
0xe0, 0x03, 0x15, 0xaa, 0x2c, 0x00, 0x00, 0x94, 0xf7, 0x02, 0x00, 0x8b, 0x80, 0x02, 0x40, 0xf9, 0x60, 0x02, 0x00,
0xb4, 0x21, 0x01, 0x80, 0x52, 0xc0, 0x02, 0x3f, 0xd6, 0x40, 0x01, 0x00, 0xb4, 0xf5, 0x03, 0x00, 0xaa, 0x94, 0x42,
0x00, 0x91, 0x81, 0x82, 0x5f, 0xf8, 0x01, 0xff, 0xff, 0xb4, 0xe0, 0x03, 0x15, 0xaa, 0xe0, 0x02, 0x3f, 0xd6, 0x60,
0x86, 0x00, 0xf8, 0x94, 0x22, 0x00, 0x91, 0xfa, 0xff, 0xff, 0x17, 0x94, 0x42, 0x00, 0x91, 0x88, 0x82, 0x5f, 0xf8,
0x08, 0xfe, 0xff, 0xb4, 0x7f, 0x86, 0x00, 0xf8, 0x94, 0x22, 0x00, 0x91, 0xfc, 0xff, 0xff, 0x17, 0xfd, 0x7b, 0x46,
0xa9, 0xf4, 0x4f, 0x45, 0xa9, 0xf6, 0x57, 0x44, 0xa9, 0xf8, 0x5f, 0x43, 0xa9, 0xfa, 0x67, 0x42, 0xa9, 0xfc, 0x6f,
0x41, 0xa9, 0xff, 0xc3, 0x01, 0x91, 0xc0, 0x03, 0x5f, 0xd6, 0x15, 0x00, 0x80, 0xd2, 0xd9, 0xff, 0xff, 0x17, 0xe8,
0x03, 0x00, 0xaa, 0x0a, 0x00, 0x80, 0xd2, 0x00, 0x00, 0x80, 0xd2, 0x09, 0x01, 0x40, 0xf9, 0x2b, 0x15, 0x40, 0x38,
0x6c, 0x19, 0x40, 0x92, 0x8c, 0x21, 0xca, 0x9a, 0x80, 0x01, 0x00, 0xaa, 0x4a, 0x1d, 0x00, 0x91, 0x6b, 0xff, 0x3f,
0x37, 0x09, 0x01, 0x00, 0xf9, 0xc0, 0x03, 0x5f, 0xd6, 0xff, 0x43, 0x01, 0xd1, 0xf8, 0x5f, 0x01, 0xa9, 0xf6, 0x57,
0x41, 0xa9, 0xff, 0xc3, 0x01, 0x91, 0xc0, 0x03, 0x5f, 0xd6, 0x15, 0x00, 0x80, 0xd2, 0xd9, 0xff, 0xff, 0x17, 0x09,
0x00, 0x80, 0xd2, 0x08, 0x00, 0x80, 0xd2, 0x0a, 0x00, 0x40, 0xf9, 0x4b, 0x15, 0x40, 0x38, 0x6c, 0x19, 0x40, 0x92,
0x8c, 0x21, 0xc9, 0x9a, 0x88, 0x01, 0x08, 0xaa, 0x29, 0x1d, 0x00, 0x91, 0x6b, 0xff, 0x3f, 0x37, 0x0a, 0x00, 0x00,
0xf9, 0xe0, 0x03, 0x08, 0xaa, 0xc0, 0x03, 0x5f, 0xd6, 0xff, 0x43, 0x01, 0xd1, 0xf8, 0x5f, 0x01, 0xa9, 0xf6, 0x57,
0x02, 0xa9, 0xf4, 0x4f, 0x03, 0xa9, 0xfd, 0x7b, 0x04, 0xa9, 0xfd, 0x03, 0x01, 0x91, 0xf4, 0x03, 0x01, 0xaa, 0xf3,
0x03, 0x00, 0xaa, 0xe8, 0x03, 0x00, 0xaa, 0xe8, 0x07, 0x00, 0xf9, 0xc8, 0x04, 0x00, 0xb4, 0x3a, 0x00, 0x00, 0x94,
0x60, 0x00, 0x00, 0xb4, 0x88, 0x02, 0x40, 0x39, 0x88, 0x04, 0x00, 0x34, 0x15, 0x00, 0x80, 0x52, 0xe8, 0x07, 0x40,
0xf9, 0x08, 0x01, 0x00, 0x8b, 0x16, 0x15, 0x40, 0x38, 0xe8, 0x07, 0x00, 0xf9, 0xdf, 0x02, 0x35, 0x6b, 0xc0, 0x02,
0x03, 0x00, 0xaa, 0xe8, 0x03, 0x00, 0xaa, 0xe8, 0x07, 0x00, 0xf9, 0x08, 0x05, 0x00, 0xb4, 0x39, 0x00, 0x00, 0x94,
0x88, 0x02, 0x40, 0x39, 0x48, 0x00, 0x00, 0x35, 0xc0, 0x04, 0x00, 0xb5, 0x15, 0x00, 0x80, 0x52, 0xe8, 0x07, 0x40,
0xf9, 0x08, 0x01, 0x00, 0x8b, 0x16, 0x15, 0x40, 0x38, 0xe8, 0x07, 0x00, 0xf9, 0xdf, 0x02, 0x35, 0x6b, 0xa0, 0x02,
0x00, 0x54, 0xe8, 0x07, 0x40, 0xf9, 0x08, 0x05, 0x00, 0x91, 0x38, 0x00, 0x80, 0x52, 0xf7, 0x03, 0x14, 0xaa, 0x09,
0xf1, 0x5f, 0x38, 0x49, 0x01, 0x00, 0x34, 0xb8, 0x00, 0x00, 0x36, 0xea, 0x16, 0xc0, 0x38, 0x3f, 0x01, 0x0a, 0x6b,
0xf8, 0x17, 0x9f, 0x1a, 0x02, 0x00, 0x00, 0x14, 0x18, 0x00, 0x80, 0x52, 0xe8, 0x07, 0x00, 0xf9, 0x08, 0x05, 0x00,
0x91, 0xf6, 0xff, 0xff, 0x17, 0xe8, 0x07, 0x00, 0xf9, 0x1f, 0x00, 0x00, 0x94, 0xb5, 0x06, 0x00, 0x11, 0x98, 0xfd,
0x07, 0x36, 0xf4, 0x03, 0x17, 0xaa, 0x02, 0x00, 0x00, 0x14, 0x00, 0x00, 0x80, 0xd2, 0x68, 0x02, 0x00, 0x8b, 0x1f,
0x00, 0x00, 0xf1, 0xe8, 0x03, 0x88, 0x9a, 0xda, 0xff, 0xff, 0x17, 0x00, 0x00, 0x80, 0xd2, 0x03, 0x00, 0x00, 0x14,
0x13, 0x00, 0x00, 0x94, 0x12, 0x00, 0x00, 0x94, 0xfd, 0x7b, 0x44, 0xa9, 0xf4, 0x4f, 0x43, 0xa9, 0xf6, 0x57, 0x42,
0xa9, 0xf8, 0x5f, 0x41, 0xa9, 0xff, 0x43, 0x01, 0x91, 0xc0, 0x03, 0x5f, 0xd6, 0x08, 0x00, 0x40, 0x39, 0x29, 0x00,
0x40, 0x39, 0x1f, 0x01, 0x09, 0x6b, 0xc1, 0x00, 0x00, 0x54, 0x00, 0x04, 0x00, 0x91, 0x21, 0x04, 0x00, 0x91, 0x48,
0xff, 0xff, 0x35, 0x20, 0x00, 0x80, 0x52, 0xc0, 0x03, 0x5f, 0xd6, 0x00, 0x00, 0x80, 0x52, 0xc0, 0x03, 0x5f, 0xd6,
0xe0, 0x23, 0x00, 0x91, 0xae, 0xff, 0xff, 0x17, 0x5f, 0x64, 0x6c, 0x6f, 0x70, 0x65, 0x6e, 0x00, 0x5f, 0x64, 0x6c,
0x73, 0x79, 0x6d, 0x00, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x5f, 0x5f, 0x4c, 0x49, 0x4e, 0x4b, 0x45, 0x44,
0x49, 0x54, 0x00, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2f,
0x6c, 0x69, 0x62, 0x64, 0x79, 0x6c, 0x64, 0x2e, 0x64, 0x79, 0x6c, 0x69, 0x62, 0x00
0x91, 0xf6, 0xff, 0xff, 0x17, 0xe8, 0x07, 0x00, 0xf9, 0x1e, 0x00, 0x00, 0x94, 0xb8, 0x00, 0x00, 0x37, 0xb5, 0x06,
0x00, 0x11, 0xeb, 0xff, 0xff, 0x17, 0xf7, 0x03, 0x14, 0xaa, 0x04, 0x00, 0x00, 0x14, 0x68, 0x02, 0x00, 0x8b, 0xf4,
0x03, 0x17, 0xaa, 0x60, 0xfb, 0xff, 0xb5, 0x08, 0x00, 0x80, 0xd2, 0xf4, 0x03, 0x17, 0xaa, 0xd8, 0xff, 0xff, 0x17,
0x00, 0x00, 0x80, 0xd2, 0x03, 0x00, 0x00, 0x14, 0x10, 0x00, 0x00, 0x94, 0x0f, 0x00, 0x00, 0x94, 0xfd, 0x7b, 0x44,
0xa9, 0xf4, 0x4f, 0x43, 0xa9, 0xf6, 0x57, 0x42, 0xa9, 0xf8, 0x5f, 0x41, 0xa9, 0xff, 0x43, 0x01, 0x91, 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, 0xe0, 0x23, 0x00, 0x91,
0xaf, 0xff, 0xff, 0x17, 0x5f, 0x64, 0x6c, 0x6f, 0x70, 0x65, 0x6e, 0x00, 0x5f, 0x64, 0x6c, 0x73, 0x79, 0x6d, 0x00,
0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x5f, 0x5f, 0x4c, 0x49, 0x4e, 0x4b, 0x45, 0x44, 0x49, 0x54, 0x00, 0x2f,
0x75, 0x73, 0x72, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2f, 0x6c, 0x69, 0x62, 0x64,
0x79, 0x6c, 0x64, 0x2e, 0x64, 0x79, 0x6c, 0x69, 0x62, 0x00
};
private string demangle (string symbol_name) {
@@ -1470,7 +1511,7 @@ namespace Frida.Fruity.Injector {
public uint64 get (string module_name, string symbol_name) throws Error {
uint64 address;
if (!lookup (module_name, symbol_name, out address))
throw new Error.UNSUPPORTED ("Symbol not found: %s", symbol_name);
throw new Error.NOT_SUPPORTED ("Symbol not found: %s", symbol_name);
return address;
}
@@ -1655,13 +1696,35 @@ namespace Frida.Fruity.Injector {
if (pc == 1337)
break;
if ((LLDB.Signal) exception.signum == SIGTRAP && exception.metype == EXC_BREAKPOINT) {
uint64 x1 = exception.context["x1"];
uint64 x2 = exception.context["x2"];
var action = (GadgetBreakpointAction) exception.context["x3"];
if (x1 == x2 == 1337 && action == INVOKE_RETURN)
break;
if (x1 == x2 == 1337 && action == PAGE_PLAN) {
var plan_size = (size_t) exception.context["x4"];
var plan_address = exception.context["x5"];
yield DebuggerMappings.handle_page_plan (lldb, plan_address, plan_size, page_size,
cancellable);
var thread = exception.thread;
yield thread.write_register ("x0", 0x1337, cancellable);
yield thread.write_register ("pc", pc + 4, cancellable);
continue;
}
}
if (exception_handler != null) {
bool handled = yield exception_handler.try_handle_exception (exception, cancellable);
if (handled)
continue;
}
throw new Error.UNSUPPORTED ("Invocation of 0x%" + uint64.FORMAT_MODIFIER + "x crashed at %s",
throw new Error.NOT_SUPPORTED ("Invocation of 0x%" + uint64.FORMAT_MODIFIER + "x crashed at %s",
impl, yield summarize_exception (exception, cancellable));
}
+10 -1
View File
@@ -729,6 +729,15 @@ namespace Frida.GDB {
check_execute_response (response);
}
public async void perform_execute (Bytes command, Cancellable? cancellable, Promise<bool> request) throws Error, IOError {
try {
yield execute (command, cancellable);
request.resolve (true);
} catch (GLib.Error e) {
request.reject (e);
}
}
private static void check_execute_response (Packet packet) throws Error {
unowned string response = packet.payload;
if (response[0] == 'E') {
@@ -1678,7 +1687,7 @@ namespace Frida.GDB {
var response = yield client.query (request, cancellable);
return Protocol.parse_pointer_value (response.payload, client.pointer_size, client.byte_order);
return Protocol.parse_integer_value (response.payload, client.byte_order);
}
public async void write_register (string name, uint64 val, Cancellable? cancellable = null) throws Error, IOError {
+4 -4
View File
@@ -9,7 +9,7 @@
"version": "1.0.0",
"dependencies": {
"@frida/buffer": "^7.0.4",
"frida-java-bridge": "^7.0.4"
"frida-java-bridge": "^7.0.8"
},
"devDependencies": {
"esbuild": "^0.25.5",
@@ -534,9 +534,9 @@
"license": "MIT"
},
"node_modules/frida-java-bridge": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/frida-java-bridge/-/frida-java-bridge-7.0.4.tgz",
"integrity": "sha512-dE5XCvasUwA/wiVb5gSwBPf6dortI8VtD0qLlw2T0ryqX/0lg4BEtEkg1oRr9IlHDVBTjPOqe9KRzdPar8U3EQ==",
"version": "7.0.8",
"resolved": "https://registry.npmjs.org/frida-java-bridge/-/frida-java-bridge-7.0.8.tgz",
"integrity": "sha512-EmqoTGzcDuCd+YFcjBJJPf7iVQCSbbj9fD0/TN8YYYwl5ZJtTqaCLTTsaC07o3bJaDVs/f3ks+Vu1bOw0S1PnQ==",
"license": "LGPL-2.0 WITH WxWindows-exception-3.1"
},
"node_modules/ieee754": {
+1 -1
View File
@@ -12,6 +12,6 @@
},
"dependencies": {
"@frida/buffer": "^7.0.4",
"frida-java-bridge": "^7.0.4"
"frida-java-bridge": "^7.0.8"
}
}
+3 -2
View File
@@ -167,7 +167,7 @@ if have_local_backend
'darwin' / 'policy-softener.vala',
'darwin' / 'policy-softener-glue.c',
]
if host_os in ['macos', 'ios', 'tvos']
if host_os in ['macos', 'ios', 'tvos', 'xros']
helper_backend_sources += [
'darwin' / 'frida-helper-backend.vala',
'darwin' / 'frida-helper-backend-glue.m',
@@ -179,7 +179,7 @@ if have_local_backend
'darwin' / 'frida-helper-null-backend.vala',
]
endif
if host_os in ['ios', 'tvos']
if host_os in ['ios', 'tvos', 'xros']
helper_backend_sources += [
'darwin' / 'springboard.m',
'darwin' / 'substituted-client.c',
@@ -511,6 +511,7 @@ if have_fruity_backend
'fruity' / 'springboard-services.vala',
'fruity' / 'lldb.vala',
'fruity' / 'injector.vala',
'fruity' / 'debugger-mappings.vala',
'fruity' / 'usbmux.vala',
'fruity' / 'dns.vala',
'fruity' / 'keyed-archive.vala',
+2015 -737
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -1,6 +1,6 @@
[wrap-git]
url = https://github.com/frida/frida-gum.git
revision = 17.2.2
revision = 17.2.16
depth = 1
[provide]
+1 -1
View File
@@ -1,6 +1,6 @@
[wrap-git]
url = https://github.com/frida/lwip.git
revision = 267d9f082e9e38083b643421a93c03d4a7046fd0
revision = c5e2835a213436eaf0c40d0a95a35e7cf0dad2d3
depth = 1
[provide]
+1 -1
View File
@@ -5,7 +5,7 @@
# include <psapi.h>
typedef HANDLE FridaProcessHandle;
#elif defined (HAVE_DARWIN)
# if defined (HAVE_IOS) || defined (HAVE_TVOS)
# if defined (HAVE_IOS) || defined (HAVE_TVOS) || defined (HAVE_XROS)
# define PROC_PIDLISTFDS 1
# define PROC_PIDLISTFD_SIZE (sizeof (struct proc_fdinfo))
struct proc_fdinfo
+5
View File
@@ -3762,6 +3762,11 @@ namespace Frida.HostSessionTest {
timer.reset ();
var script = yield session.create_script ("""
send(Module.getGlobalExportByName('open'));
try {
ptr(0x69).writeU32(1337);
} catch (e) {
send('I cannot believe Exceptor works!');
}
""");
printerr (" => took %u ms\n", (uint) (timer.elapsed () * 1000.0));
+3
View File
@@ -118,6 +118,9 @@ namespace QuickJS {
[CCode (cname = "JS_NewAtom")]
public Atom make_atom (string str);
[CCode (cname = "JS_NewBool")]
public Value make_bool (bool v);
[CCode (cname = "JS_NewInt32")]
public Value make_int32 (int32 v);