Compare commits

...
191 Commits
Author SHA1 Message Date
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
Ole André Vadla Ravnås 7b7d9acf8c subprojects: Prepare for release 2025-06-19 23:25:44 +02:00
Ole André Vadla Ravnås 215076a0fa subprojects: Bump outdated 2025-06-19 23:23:46 +02:00
Ole André Vadla Ravnås 3d47bf73b4 package-manager: Only report installed packages
The toplevel packages that were left untouched should not be included.

Also simplify the install() logic while at it.
2025-06-19 23:22:22 +02:00
Ole André Vadla Ravnås 7d84a44c7f package-manager: Fix the lockfile up-to-date path 2025-06-19 22:55:19 +02:00
Ole André Vadla Ravnås ef7e0a88e0 package-manager: Fix two stylistic inconsistencies 2025-06-19 22:53:09 +02:00
Ole André Vadla Ravnås 1f95416a77 subprojects: Prepare for release 2025-06-19 21:03:42 +02:00
Ole André Vadla Ravnås 80c7ec2dce meson: Fix build when libsoup is a subproject 2025-06-19 20:23:30 +02:00
Ole André Vadla Ravnås 69c68fdf7f subprojects: Bump outdated 2025-06-19 20:18:51 +02:00
Ole André Vadla Ravnås 7070042128 compiler: Make backend a shared library on Android
To avoid dynamic linking issues due to thread-local storage. This was
caused by our previous hack where we pretended Android was GOOS=linux
to work around the Go toolchain refusing `-buildmode=c-archive` for
GOOS=android.
2025-06-19 20:17:06 +02:00
Ole André Vadla Ravnås 9a4ce30be5 post-process: Support skipping ELF-cleaner step
It seems to corrupt shared library ELFs generated by the Go toolchain.
2025-06-19 20:08:47 +02:00
Ole André Vadla Ravnås 7731aea6f7 linux: Split out useful primitives into base
- check_kernel_version()
- FileDescriptor
- PidFileDescriptor
- MemoryFileDescriptor
2025-06-19 20:08:47 +02:00
Ole André Vadla Ravnås 3f8ace5f7b subprojects: Prepare for release 2025-06-18 23:34:57 +02:00
Ole André Vadla Ravnås d1e8aaa8e6 subprojects: Bump outdated 2025-06-18 23:33:44 +02:00
Ole André Vadla Ravnås 28a1084e7d compiler: Bump @frida/net to 5.0.0 2025-06-18 23:16:34 +02:00
Ole André Vadla Ravnås ac62e5d96d package-manager: Fix manifest progress
It should not have details, so it ends up in the toplevel progress
group, as far as UIs are concerned.
2025-06-18 22:56:43 +02:00
Ole André Vadla Ravnås 05bdfde104 package-manager: Add url property to Package
Only present in search results.
2025-06-18 19:49:44 +02:00
Ole André Vadla Ravnås 938e724f2d package-manager: Fix a stylistic inconsistency 2025-06-18 19:48:05 +02:00
Ole André Vadla Ravnås bf1d417445 Add PackageManager
To aid in discovering and installing Frida-specific packages without the
need for Node.js + npm. Power users and package maintainers will still
typically be using npm though. The goal is to streamline the consumption
of bridges and other Frida-specific packages.
2025-06-17 12:40:37 +02:00
Ole André Vadla Ravnås d9317e6265 base: Add FS namespace with filesystem helpers 2025-06-17 10:28:26 +02:00
Ole André Vadla Ravnås 01fd21f004 buffer: Add BufferReader.skip() 2025-06-17 10:28:26 +02:00
Ole André Vadla Ravnås e576f36f05 buffer: Allow trailing NULs in read_fixed_string() 2025-06-17 10:28:26 +02:00
He Li 9a7623a448 compiler: Fix missing shim assets (#1176)
Previously, the embeddedShims glob only matched files up to two directory
levels deep. This caused imports like:

    open node_modules/@frida/assert/internal/util/comparisons.js:
    file does not exist

This change adds an extra glob pattern that matches one more directory
level, allowing shim assets located one level deeper to be found correctly.
2025-06-17 10:27:49 +02:00
Ole André Vadla Ravnås 7dc0b5e4ee subprojects: Prepare for release 2025-06-13 16:28:17 +02:00
Ole André Vadla Ravnås a18eab4afa subprojects: Bump outdated 2025-06-13 16:27:21 +02:00
WorksButNotTested 8a30f241d1 ci: Fix builds of helpers and labrats 2025-06-13 16:25:05 +02:00
WorksButNotTested 78fbe5a20b tests: Disable slow test on armbe8 2025-06-13 16:25:05 +02:00
Ole André Vadla Ravnås e667582d54 android: Bump frida-java-bridge in system-server 2025-06-13 16:22:25 +02:00
Ole André Vadla Ravnås f5dd273c8c subprojects: Prepare for release 2025-06-10 22:09:49 +02:00
Ole André Vadla Ravnås 5438597c19 subprojects: Bump outdated 2025-06-10 22:05:53 +02:00
WorksButNotTested bb1f944f43 ci: Fix emulator error propagation 2025-06-10 22:05:07 +02:00
Ole André Vadla Ravnås 294df78147 darwin: Bump frida-objc-bridge in internal agents 2025-06-10 22:04:16 +02:00
Ole André Vadla Ravnås 2f1d24f96f android: Bump frida-java-bridge in system-server 2025-06-10 22:02:29 +02:00
Ole André Vadla Ravnås 918c83d25c compiler: Update package-lock.json 2025-06-10 21:07:51 +02:00
Ole André Vadla Ravnås a580d22bb6 agents: Switch esbuild platform to node
Internal agent bundles were still built with `--platform=neutral`, so
esbuild ignored each package’s package.json metadata. Modules that
rely on Node-style resolution could therefore fail to bundle.
2025-06-10 21:04:44 +02:00
Ole André Vadla Ravnås 238b81c26d compiler: Switch esbuild platform to node
Neutral mode ignores package.json, so modules that rely on "main" or
"exports" fields were left unresolved. Setting PlatformNode lets esbuild
read package.json and resolve such modules correctly.

No functional change for code that was already valid under Neutral; it
just unbreaks packages that expect Node semantics.

Kudos to @hsorbo for helping track this one down.
2025-06-10 20:59:21 +02:00
Ole André Vadla Ravnås 413ba51568 plist: Fix XML output of empty dicts/arrays
Apple’s encoder emits <dict/> and <array/> for empty collections; we were
producing <dict></dict> and <array></array>. The stricter form makes it
harder to compare plists byte-for-byte.

Our to_xml() now emits the self-closing tags so its XML output matches
Apple’s encoder.
2025-06-10 20:48:55 +02:00
Ole André Vadla Ravnås 3767957065 plist: Fix offsetIntSize for binary output
When to_binary() builds a bplist, the trailer’s offset-size field must
encode the offset of the offset table itself. We were deriving
offsetIntSize from the last object’s offset, so a plist whose table began
at 0x100 or beyond could still advertise size = 1 and be rejected by
Core Foundation as corrupt.

Size is now chosen from offset_table_offset. The XML path (to_xml())
is unaffected.

Kudos to @mrmacete for helping track this one down.
2025-06-10 20:41:36 +02:00
Ole André Vadla Ravnås ec3b864007 subprojects: Prepare for release 2025-06-07 13:32:23 +02:00
Ole André Vadla Ravnås 93fc48d20e subprojects: Bump outdated 2025-06-07 13:30:19 +02:00
Ole André Vadla Ravnås 4f120d9e46 meson: Simplify the Vala flags logic 2025-06-07 13:29:46 +02:00
Ole André Vadla Ravnås f9ee24038b gadget: Correct QuickJS big-endian bytecode check 2025-06-07 13:27:49 +02:00
Ole André Vadla Ravnås 5692298b03 subprojects: Bump outdated 2025-06-07 11:23:12 +02:00
Ole André Vadla Ravnås 375be6181a compiler: Rename conflictful Go symbols in backend
To avoid conflicts when we're linked into a Go binary.
2025-06-07 11:22:36 +02:00
Ole André Vadla Ravnås e5fa1b1fab api: Add version defines and macros 2025-06-07 11:20:23 +02:00
Ole André Vadla Ravnås 8e76c7257b subprojects: Prepare for release 2025-06-06 22:11:36 +02:00
Ole André Vadla Ravnås 282927b5b6 subprojects: Bump outdated 2025-06-06 22:10:29 +02:00
Ole André Vadla Ravnås fe235491a5 compiler: Make the DeviceManager optional
It is no longer used, but we cannot drop the constructor argument
without breaking API.
2025-06-06 22:09:40 +02:00
Ole André Vadla Ravnås 46d4d1223a subprojects: Prepare for release 2025-06-06 14:11:13 +02:00
Ole André Vadla Ravnås 6f8d8cba28 linux: Fix the system-server.js build system logic 2025-06-06 13:26:51 +02:00
Ole André Vadla Ravnås 2ee3926912 subprojects: Bump outdated 2025-06-06 12:38:22 +02:00
Ole André Vadla Ravnås 11f93e20b8 compile-js-agent: Remove commented “npm link” example
As it is no longer relevant.
2025-06-06 12:37:32 +02:00
Ole André Vadla Ravnås ad15eb2b01 darwin: Switch reportcrash.js bundling to ESBuild 2025-06-06 12:36:27 +02:00
Ole André Vadla Ravnås 26c9cf3cc5 darwin: Switch osanalytics.js bundling to ESBuild 2025-06-06 12:34:21 +02:00
Ole André Vadla Ravnås 8176ea1361 linux: Switch system-server.js bundling to ESBuild 2025-06-06 12:29:35 +02:00
Ole André Vadla Ravnås ecc63e5591 barebone: Simplify the ESBuild invocation 2025-06-06 12:27:23 +02:00
Ole André Vadla Ravnås ac5898a547 barebone: Fix ESM-handling
Where we failed to await the returned Promise, so any errors would end
up being swallowed.
2025-06-06 11:38:16 +02:00
Ole André Vadla Ravnås 055360cbb6 barebone: Remove bridge globals 2025-06-06 11:37:07 +02:00
Ole André Vadla Ravnås c9b18a5f4b barebone: Switch runtime bundling to ESBuild 2025-06-06 11:36:28 +02:00
Ole André Vadla Ravnås eb55aef18e subprojects: Prepare for release 2025-06-05 22:05:20 +02:00
Ole André Vadla Ravnås 11ba9175d0 subprojects: Bump outdated 2025-06-05 21:11:15 +02:00
Ole André Vadla Ravnås 6dd7e203bf ci: Fix a stylistic inconsistency 2025-06-05 20:07:22 +02:00
Ole André Vadla Ravnås 3a312faa1e ci: Fix the Windows build step 2025-06-05 19:27:22 +02:00
Ole André Vadla Ravnås 6f97782eff meson: Warn when Compiler backend is auto-disabled 2025-06-05 19:21:48 +02:00
Ole André Vadla Ravnås 412e525210 cgo: Fix path logic when consumed as a subproject 2025-06-05 19:21:16 +02:00
Ole André Vadla Ravnås c6e8ef5a29 ci: Clean up and fix Compiler backend enable logic 2025-06-05 19:14:45 +02:00
Ole André Vadla Ravnås 0df0eefdc9 cgo: Treat arm64e as unsupported
As cgo does not yet support it.
2025-06-05 19:08:26 +02:00
Ole André Vadla Ravnås dc60f8bf10 ci: Simplify the Compiler backend enable logic 2025-06-05 19:01:31 +02:00
Ole André Vadla Ravnås 2b9f3764c5 ci: Disable Compiler backend for the emulator job 2025-06-05 18:55:35 +02:00
Ole André Vadla Ravnås 89e01be599 ci: Skip tests on macOS for now
So we can get back to a green baseline.
2025-06-05 18:49:26 +02:00
Ole André Vadla Ravnås 228a37fabf ci: Fix the compiler backend option passed in 2025-06-05 18:36:03 +02:00
Ole André Vadla Ravnås 40ec5e03cc subprojects: Bump outdated 2025-06-05 17:02:16 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 6acb6da386 ci: Explicitly enable compiler
So it's not silently disabled in cases where cgo should be available.

Co-authored-by: Håvard Sørbø <[email protected]>
2025-06-05 17:00:49 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 9b9c91c1f2 ci: Improve naming of the Go toolchain steps
Co-authored-by: Håvard Sørbø <[email protected]>
2025-06-05 17:00:49 +02:00
Ole André Vadla Ravnås c5809da386 ci: Temporarily remove the FreeBSD/arm64 job
Until we have a working runner for it.
2025-06-05 17:00:49 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 6b76a1b2d4 ci: Fix the native Windows/x86 job
Which was building for x86_64 instead of x86.

Co-authored-by: Håvard Sørbø <[email protected]>
2025-06-05 17:00:49 +02:00
Ole André Vadla Ravnås 3da7b8bbd0 submodules: Bump releng 2025-06-05 17:00:49 +02:00
Ole André Vadla Ravnås adc93c3bf8 ci: Add native job for Windows/arm64 2025-06-05 17:00:49 +02:00
Ole André Vadla Ravnås b85397b690 ci: Install MinGW in the Windows native jobs 2025-06-05 17:00:49 +02:00
Ole André Vadla Ravnås b22326f233 ci: Add Go to the build jobs 2025-06-05 17:00:49 +02:00
Ole André Vadla Ravnås 531cfb17c0 ci: Remove trailing whitespace 2025-06-05 17:00:49 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 0a4bb7aed5 compiler: Normalize paths passed to typescript-go
So it also works on Windows.

Co-authored-by: Håvard Sørbø <[email protected]>
2025-06-05 17:00:49 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 274898d39c compiler: Fix handling of TypeScript diagnostics
Where ESBuild Message entries without notes were incorrectly handled.

Co-authored-by: Håvard Sørbø <[email protected]>
2025-06-05 17:00:49 +02:00
Ole André Vadla RavnåsandHåvard Sørbø c6c30833c8 compiler: Avoid Go alignment bug on Windows/x86_64
Where C arguments passed on the stack that are smaller than 8 bytes are
incorrectly laid out when calling into the Go runtime.

Co-authored-by: Håvard Sørbø <[email protected]>
2025-06-05 17:00:49 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 7b30a9c516 compiler: Fix cross-platform build issues
Co-authored-by: Håvard Sørbø <[email protected]>
2025-06-05 17:00:49 +02:00
Ole André Vadla Ravnås 32220057a8 meson: Allow compiler backend w/o local backend
Now that it no longer needs it for script execution.
2025-06-02 09:39:34 +02:00
Ole André Vadla RavnåsandHåvard Sørbø b7284691ca compiler: Move to ESBuild and typescript-go
For massively improved performance, and to reduce our maintenance burden
by no longer having to maintain a bundler.

Also add options to configure the output and bundle format, and support
disabling type checks.

Co-authored-by: Håvard Sørbø <[email protected]>
2025-06-01 23:46:10 +02:00
Ole André Vadla Ravnås 71a1b0f800 subprojects: Bump outdated 2025-06-01 11:04:52 +02:00
Ole André Vadla Ravnås b8b42a904b submodules: Bump releng 2025-06-01 11:04:51 +02:00
WorksButNotTested fdb4c5107c ci: Add jobs that test on armbe8 and arm64be (#1162) 2025-05-29 21:30:35 +02:00
Francesco Tamagni 8108d4d954 Plug Interceptor singleton leaks (#1167) 2025-05-29 21:29:15 +02:00
Ole André Vadla Ravnås 44a9757589 subprojects: Prepare for release 2025-05-29 17:32:06 +02:00
Ole André Vadla Ravnås 8c939d4954 subprojects: Bump outdated 2025-05-29 17:30:09 +02:00
Francesco Tamagni 8bb0dd14a4 device: Allow agent sessions to detach before release (#1164)
To be robust against scenarios where an out-of-order detach could lead
to indefinite hang at release time.
2025-05-29 17:22:57 +02:00
Ole André Vadla Ravnås 59619f57ca subprojects: Prepare for release 2025-05-28 23:17:01 +02:00
Ole André Vadla Ravnås 5ed7378bb0 subprojects: Bump outdated 2025-05-28 23:16:07 +02:00
londek 4d2bba4b2a darwin: Fix the launchd agent (#1166)
Which was still using an old GumJS API that is now gone.
2025-05-28 23:11:27 +02:00
Ole André Vadla Ravnås e2e2eaab82 subprojects: Prepare for release 2025-05-24 21:03:20 +02:00
Ole André Vadla Ravnås d286cbb09c subprojects: Bump outdated 2025-05-24 21:01:59 +02:00
Ole André Vadla Ravnås c910622a6a compile-js-agent: Explicitly run the build script
To ensure incremental compilation works consistently, as `npm install`
will not always run the `prepare` script.
2025-05-24 21:00:59 +02:00
Ole André Vadla Ravnås 7599500a3b compile-js-agent: Add commented “npm link” example 2025-05-24 20:59:14 +02:00
Ole André Vadla Ravnås fe4db7e37f compile-js-agent: Improve error-reporting
By capturing both stdout and stderr.
2025-05-24 20:58:33 +02:00
Ole André Vadla Ravnås 6064d0c084 Fix agents generated by latest frida-compile
We need to explicitly declare internal agents as ESM now that the
TypeScript compiler is more conformant and ends up generating CommonJS
glue code.

This fixes our Darwin and Android agents, as well as the Barebone
backend's script runtime.
2025-05-24 20:50:43 +02:00
Ole André Vadla Ravnås f970529e08 subprojects: Prepare for release 2025-05-22 21:39:32 +02:00
Ole André Vadla Ravnås 031614ddc2 compiler: Fix asset bundling logic on Windows
Where virtual paths were stored with the wrong path separator.
2025-05-22 21:20:34 +02:00
Ole André Vadla Ravnås 71d82bcebc subprojects: Bump outdated 2025-05-22 18:22:36 +02:00
Ole André Vadla Ravnås 9c7759cb53 tests: Adjust profile-compiler.sh to new layout 2025-05-22 18:20:21 +02:00
Ole André Vadla Ravnås 11b3e1415f Upgrade to frida-compile 18
Now with TypeScript 5.8.3, latest frida-fs, etc.
2025-05-22 18:17:44 +02:00
98 changed files with 10709 additions and 6028 deletions

No files matched your search

+190 -15
View File
@@ -16,13 +16,13 @@ jobs:
strategy:
matrix:
include:
- { id: windows-x86_64, runner: '"windows-latest"' }
- { id: windows-x86, runner: '"windows-latest"' }
- { id: macos-x86_64, runner: '"macos-latest"' }
- { id: macos-arm64, runner: '"macos-latest"' }
- { id: linux-x86_64, runner: '"ubuntu-latest"' }
- { id: linux-x86, runner: '"ubuntu-latest"' }
- { id: freebsd-arm64, runner: '["self-hosted", "freebsd", "arm64"]' }
- { id: windows-arm64, runner: '"windows-11-arm"', sys: CLANGARM64, pkg: 'mingw-w64-clang-aarch64-clang' }
- { id: windows-x86_64, runner: '"windows-latest"', sys: MINGW64, pkg: 'mingw-w64-x86_64-gcc' }
- { id: windows-x86, runner: '"windows-latest"', sys: MINGW32, pkg: 'mingw-w64-i686-gcc' }
- { id: macos-x86_64, runner: '"macos-latest"' }
- { id: macos-arm64, runner: '"macos-latest"' }
- { id: linux-x86_64, runner: '"ubuntu-latest"' }
- { id: linux-x86, runner: '"ubuntu-latest"' }
fail-fast: false
runs-on: ${{ fromJSON(matrix.runner) }}
steps:
@@ -30,6 +30,18 @@ jobs:
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install MinGW toolchain for cgo support
if: ${{ startsWith(matrix.id, 'windows-') }}
id: msys2
uses: msys2/setup-msys2@v2
with:
msystem: ${{ matrix.sys }}
install: ${{ matrix.pkg }}
- name: Install Go toolchain
uses: actions/setup-go@v5
with:
go-version-file: 'src/compiler/go.mod'
cache-dependency-path: 'src/compiler/go.mod'
- name: Set up Apple certificates
if: ${{ startsWith(matrix.id, 'macos-') }}
uses: ./.github/actions/setup-apple-certificates
@@ -48,18 +60,29 @@ jobs:
- name: Build
if: ${{ startsWith(matrix.id, 'windows-') }}
run: |
.\configure ${{ env.FRIDA_CORE_OPTIONS }}
.\configure `
--host=${{ matrix.id }} `
--enable-compiler-backend `
${{ env.FRIDA_CORE_OPTIONS }}
.\make
env:
MSYS2_LOCATION: ${{ steps.msys2.outputs.msys2-location }}
- name: Build
if: ${{ !startsWith(matrix.id, 'windows-') && matrix.id != 'linux-x86' }}
run: |
./configure ${{ env.FRIDA_CORE_OPTIONS }}
./configure \
--enable-compiler-backend \
${{ env.FRIDA_CORE_OPTIONS }}
make
- name: Build
if: matrix.id == 'linux-x86'
run: |
CC="gcc -m32" CXX="g++ -m32" STRIP="strip" \
./configure --build=linux-x86 --host=linux-x86 ${{ env.FRIDA_CORE_OPTIONS }}
./configure \
--build=linux-x86 \
--host=linux-x86 \
--enable-compiler-backend \
${{ env.FRIDA_CORE_OPTIONS }}
make
- name: Upload devkit
if: ${{ !startsWith(matrix.id, 'linux-') }}
@@ -68,6 +91,7 @@ jobs:
name: core-devkit-${{ matrix.id }}
path: build/src/devkit/
- name: Test
if: ${{ matrix.id != 'windows-arm64' && !startsWith(matrix.id, 'macos-') }}
run: make test
cross:
@@ -91,9 +115,17 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install ${{ matrix.pkg }}
- name: Install Go toolchain
uses: actions/setup-go@v5
with:
go-version-file: 'src/compiler/go.mod'
cache-dependency-path: 'src/compiler/go.mod'
- name: Build
run: |
./configure ${{ matrix.opts }} ${{ env.FRIDA_CORE_OPTIONS }}
./configure \
${{ matrix.opts }} \
${{ !contains(matrix.id, 'mips') && '--enable-compiler-backend' || '' }} \
${{ env.FRIDA_CORE_OPTIONS }}
make
- name: Upload devkit
if: ${{ !startsWith(matrix.id, 'linux-') }}
@@ -114,9 +146,17 @@ jobs:
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Go toolchain
uses: actions/setup-go@v5
with:
go-version-file: 'src/compiler/go.mod'
cache-dependency-path: 'src/compiler/go.mod'
- name: Build
run: |
./configure --host=$XTOOLS_HOST ${{ env.FRIDA_CORE_OPTIONS }}
./configure \
--host=$XTOOLS_HOST \
${{ !startsWith(matrix.arch, 'mips') && '--enable-compiler-backend' || '' }} \
${{ env.FRIDA_CORE_OPTIONS }}
make
- name: Upload devkit
uses: actions/upload-artifact@v4
@@ -127,6 +167,131 @@ jobs:
if: matrix.arch == 'x86' || matrix.arch == 'x86_64'
run: make test
emulator:
strategy:
matrix:
arch: [armbe8, arm64be]
fail-fast: false
runs-on: ubuntu-latest
container: ghcr.io/frida/x-tools-linux-${{ matrix.arch }}:latest
steps:
- name: Check out repo
uses: actions/checkout@v4
with:
submodules: recursive
- name: Build
run: |
./configure --host=$XTOOLS_HOST --without-prebuilds=sdk:host --enable-tests
make
- name: Run custom container
uses: addnab/docker-run-action@v3
with:
image: docker:stable
options: -v ${{ github.workspace }}:/workspace:delegated
run: |
cat <<EOF > /workspace/initscript
#!/bin/sh
dmesg -n1
mount -t proc none /proc
mount -t sysfs none /sys
mount -t tmpfs none /tmp
mount -t devtmpfs none /dev
mount -t 9p -o rw,sync,dirsync,relatime,trans=virtio,msize=131072,version=9p2000.L host0 /workspace
ip link set lo up
ip addr add 192.168.76.20/24 dev eth0
ip link set eth0 up
ip route add default via 192.168.76.2 dev eth0
export LD_LIBRARY_PATH=/lib:/lib64:/libilp32
/sbin/entropy
cat /etc/motd
export PS1='\u@frida:\w\$ '
/root/frida-tests
status=\$?
echo "exit status: \$status"
if [ \$status -eq 0 ]; then
echo EXIT_OK
elif [ \$status -gt 128 ]; then
signal=\$((\$status - 128))
echo "EXIT_FAIL (terminated by signal \$signal)"
else
echo "EXIT_FAIL (exit code \$status)"
fi
EOF
cat <<EOF > /workspace/launch.sh
#!/bin/sh
LOGFILE=/workspace/qemu.log
: > "\$LOGFILE"
timeout 120 qemu-system-aarch64 \
-M virt \
-machine virtualization=true \
-machine type=virt \
-cpu cortex-a72 \
-smp 4 \
-kernel /root/Image.gz \
-initrd /root/initramfs.img \
-append 'earlyprintk=serial,ttyAMA0 console=ttyAMA0 coredump_filter=0x3f' \
-m 4096M \
-net nic,id=eth \
-net user,id=mynet,net=192.168.76.0/24 \
-virtfs local,path=/workspace/,mount_tag=host0,security_model=passthrough,id=host0 \
-nographic \
-no-reboot \
>> "\$LOGFILE" 2>&1 &
QEMU_PID=\$!
echo "QEMU started with PID \$QEMU_PID"
tail -n 0 -f "\$LOGFILE" | while read line; do
echo "\$line"
echo "\$line" | grep "EXIT_OK" >/dev/null 2>&1
if [ \$? -eq 0 ]; then
echo "Success signal received from guest. Killing QEMU..."
kill -9 "\$QEMU_PID"
cat -n "\$LOGFILE"
exit 0
fi
echo "\$line" | grep "EXIT_FAIL" >/dev/null 2>&1
if [ \$? -eq 0 ]; then
echo "Failure signal received from guest. Killing QEMU..."
kill -9 "\$QEMU_PID"
cat -n "\$LOGFILE"
exit 1
fi
if ! kill -0 "\$QEMU_PID" 2>/dev/null; then
echo "QEMU process has exited."
cat -n "\$LOGFILE"
exit 1
fi
done
EOF
cat <<EOF > /workspace/Dockerfile.ci
FROM ghcr.io/frida/x-tools-linux-be-target:latest
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
apt-get install -y \
cpio
RUN mkdir /tmp/initramfs
WORKDIR /tmp/initramfs
RUN cpio --extract < /root/initramfs.img
RUN mkdir /tmp/initramfs/workspace
COPY initscript /tmp/initramfs/init
RUN chmod +x /tmp/initramfs/init
COPY build/tests /tmp/initramfs/root/
RUN find . | cpio -o --format=newc -R root:root > /root/initramfs.img
COPY launch.sh /root/launch.sh
RUN chmod +x /root/launch.sh
ENTRYPOINT ["/root/launch.sh"]
EOF
docker build -t ci-image -f /workspace/Dockerfile.ci /workspace
docker run --rm -v /workspace:/workspace ci-image
mobile:
strategy:
matrix:
@@ -143,6 +308,11 @@ jobs:
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Go toolchain
uses: actions/setup-go@v5
with:
go-version-file: 'src/compiler/go.mod'
cache-dependency-path: 'src/compiler/go.mod'
- name: Set up Apple certificates
if: startsWith(matrix.id, 'ios-')
uses: ./.github/actions/setup-apple-certificates
@@ -160,7 +330,10 @@ jobs:
run: echo ANDROID_NDK_ROOT=${{ steps.setup-ndk.outputs.ndk-path }} >> $GITHUB_ENV
- name: Build
run: |
./configure --host=${{ matrix.id }} ${{ env.FRIDA_CORE_OPTIONS }}
./configure \
--host=${{ matrix.id }} \
--enable-compiler-backend \
${{ env.FRIDA_CORE_OPTIONS }}
make
- name: Upload devkit
uses: actions/upload-artifact@v4
@@ -250,6 +423,7 @@ jobs:
strategy:
matrix:
arch: [x86, x86_64, arm, armbe8, arm64, arm64be, arm64beilp32, mips, mipsel, mips64, mips64el]
fail-fast: false
runs-on: ubuntu-latest
container: ghcr.io/frida/core-linux-helpers-${{ matrix.arch }}:latest
steps:
@@ -263,7 +437,7 @@ jobs:
- name: Check for unexpected changes
run: |
git config --global --add safe.directory "$(realpath .)"
status_output="$(git status --porcelain)"
status_output=$(git status --porcelain tests/labrats/{resident-agent,simple-agent}-linux-${{ matrix.arch }}.so tests/labrats/{forker,sleeper,spawner}-linux-${{ matrix.arch }})
if [ -n "$status_output" ]; then
echo "Unexpected changes detected:"
echo "$status_output"
@@ -282,6 +456,7 @@ jobs:
strategy:
matrix:
arch: [x86, x86_64, arm, armbe8, arm64, arm64be, arm64beilp32, mips, mipsel, mips64, mips64el]
fail-fast: false
runs-on: ubuntu-latest
container: ghcr.io/frida/core-linux-helpers-${{ matrix.arch }}:latest
steps:
@@ -295,7 +470,7 @@ jobs:
- name: Check for unexpected changes
run: |
git config --global --add safe.directory "$(realpath .)"
status_output="$(git status --porcelain)"
status_output=$(git status --porcelain src/linux/helpers/{bootstrapper,loader}-${{ matrix.arch }}.bin)
if [ -n "$status_output" ]; then
echo "Unexpected changes detected:"
echo "$status_output"
+3
View File
@@ -435,6 +435,7 @@ def compile(privdir: Path, state: State):
environ={**build_env, **group.extra_environ},
allowed_prebuilds=state.allowed_prebuilds,
extra_meson_options=[
"-Dcompiler_backend=disabled",
"-Dhelper_modern=",
"-Dhelper_legacy=",
"-Dagent_modern=",
@@ -499,6 +500,8 @@ def option_should_be_forwarded(k: "OptionKey",
if k.is_project():
if is_for_us:
if k.name == "compiler_backend":
return False
tokens = k.name.split("_")
if tokens[0] in {"helper", "agent"} and tokens[-1] in {"modern", "legacy"}:
return False
+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);
}
+106 -31
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,14 @@ namespace Frida {
public string read_fixed_string (size_t offset, size_t size) throws Error {
string * start = (string *) get_pointer (offset, size);
string val = start->substring (0, (long) size);
size_t max_length = size_t.min (size, this.size - offset);
string * end = memchr (start, 0, max_length);
size_t n;
if (end != null)
n = end - start;
else
n = size;
string val = start->substring (0, (long) n);
if (!val.validate ())
throw new Error.PROTOCOL ("Invalid UTF-8 string");
return val;
@@ -458,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);
@@ -467,14 +528,20 @@ 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;
@@ -483,105 +550,113 @@ namespace Frida {
public uint64 read_pointer (size_t offset) throws Error {
var pointer_size = buffer.pointer_size;
check_available (pointer_size);
var ptr = buffer.read_pointer (offset);
offset += pointer_size;
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;
return this;
}
private void check_available (size_t n) throws Error {
if (available < n)
throw new Error.PROTOCOL ("Malformed buffer: truncated");
}
}
public extern Bytes make_bytes_with_owner<T> (void * data, size_t size, owned T? owner = null);
}
+114
View File
@@ -0,0 +1,114 @@
namespace Frida.FS {
public void mkdirp (File dir, Cancellable? cancellable = null) throws Error {
try {
dir.make_directory_with_parents (cancellable);
} catch (GLib.Error e) {
if (!(e is IOError.EXISTS))
throw new Error.PERMISSION_DENIED ("%s", e.message);
}
}
public void rmtree (File dir, Cancellable? cancellable = null) throws Error {
rmtree_worker (dir, 0, cancellable);
}
private void rmtree_worker (File dir, uint depth, Cancellable? cancellable = null) throws Error {
FileEnumerator enumerator;
try {
enumerator = dir.enumerate_children (FileAttribute.STANDARD_NAME, NOFOLLOW_SYMLINKS, cancellable);
} catch (GLib.Error e) {
if (depth == 0 && e is IOError.NOT_FOUND)
return;
throw new Error.PERMISSION_DENIED ("%s", e.message);
}
try {
FileInfo? info;
File? child;
while (enumerator.iterate (out info, out child, cancellable) && info != null) {
if (info == null)
continue;
if (info.get_file_type () == DIRECTORY)
rmtree (child, cancellable);
else
child.delete (cancellable);
}
dir.delete (cancellable);
} catch (GLib.Error e) {
if (!(e is IOError.EXISTS))
throw new Error.PERMISSION_DENIED ("%s", e.message);
}
}
public async void rmtree_async (File dir, Cancellable? cancellable = null) throws Error, IOError {
yield rmtree_async_worker (dir, 0, cancellable);
}
private async void rmtree_async_worker (File dir, uint depth, Cancellable? cancellable = null) throws Error, IOError {
int io_priority = Priority.DEFAULT;
FileEnumerator enumerator;
try {
enumerator = yield dir.enumerate_children_async (FileAttribute.STANDARD_NAME, NOFOLLOW_SYMLINKS, io_priority,
cancellable);
} catch (GLib.Error e) {
if (depth == 0 && e is IOError.NOT_FOUND)
return;
throw new Error.PERMISSION_DENIED ("%s", e.message);
}
try {
while (true) {
var batch = yield enumerator.next_files_async (1000, io_priority, cancellable);
if (batch.is_empty ())
break;
foreach (FileInfo info in batch) {
File child = dir.get_child (info.get_name ());
if (info.get_file_type () == DIRECTORY)
yield rmtree_async_worker (child, depth + 1, cancellable);
else
yield child.delete_async (io_priority, cancellable);
}
}
yield dir.delete_async (io_priority, cancellable);
} catch (GLib.Error e) {
throw new Error.PERMISSION_DENIED ("%s", e.message);
}
}
public async string read_all_text (File f, Cancellable? cancellable) throws Error, IOError {
Bytes b = yield read_all_bytes (f, cancellable);
string text = (string) b.get_data ();
if (!text.validate ())
throw new Error.PROTOCOL ("Unable to read '%s': invalid UTF-8", f.get_parse_name ());
return text;
}
public async void write_all_text (File f, string t, Cancellable? cancellable) throws Error, IOError {
yield write_all_bytes (f, new Bytes (t.data), cancellable);
}
public async Bytes read_all_bytes (File f, Cancellable? cancellable) throws Error, IOError {
try {
return yield f.load_bytes_async (cancellable, null);
} catch (GLib.Error e) {
if (e is IOError.CANCELLED)
throw (IOError) e;
if (e is IOError.NOT_FOUND)
throw new Error.INVALID_ARGUMENT ("%s", e.message);
throw new Error.PERMISSION_DENIED ("%s", e.message);
}
}
public async void write_all_bytes (File f, Bytes b, Cancellable? cancellable) throws Error, IOError {
try {
yield f.replace_contents_bytes_async (b, null, false, FileCreateFlags.NONE, cancellable, null);
} catch (GLib.Error e) {
if (e is IOError.CANCELLED)
throw (IOError) e;
throw new Error.PERMISSION_DENIED ("%s", e.message);
}
}
}
@@ -1,5 +1,5 @@
#ifndef __FRIDA_SYSCALL_H__
#define __FRIDA_SYSCALL_H__
#ifndef __FRIDA_LINUX_SYSCALL_H__
#define __FRIDA_LINUX_SYSCALL_H__
#include <linux/unistd.h>
#include <sys/syscall.h>
@@ -14,7 +14,7 @@ namespace Frida {
[CCode (cheader_filename = "sys/mman.h", cname = "MAP_ANONYMOUS")]
public const int MAP_ANONYMOUS;
[CCode (cheader_filename = "linux/frida-syscall.h", cprefix = "SYS_", has_type_id = false)]
[CCode (cheader_filename = "linux-syscall.h", cprefix = "SYS_", has_type_id = false)]
public enum SysCall {
memfd_create,
pidfd_getfd,
+107
View File
@@ -0,0 +1,107 @@
namespace Frida {
private uint linux_major = 0;
private uint linux_minor = 0;
public bool check_kernel_version (uint major, uint minor) {
if (linux_major == 0) {
var name = Posix.utsname ();
name.release.scanf ("%u.%u", out linux_major, out linux_minor);
}
return (linux_major == major && linux_minor >= minor) || linux_major > major;
}
public class FileDescriptor : Object, FileDescriptorBased {
public int handle;
public FileDescriptor (int handle) {
this.handle = handle;
}
~FileDescriptor () {
if (handle != -1)
Posix.close (handle);
}
public int steal () {
int result = handle;
handle = -1;
return result;
}
public int get_fd () {
return handle;
}
}
public sealed class PidFileDescriptor : FileDescriptor {
private uint pid;
private PidFileDescriptor (int fd, uint pid) {
base (fd);
this.pid = pid;
}
public static bool is_supported () {
return check_kernel_version (5, 3);
}
public static bool getfd_is_supported () {
return check_kernel_version (5, 6);
}
public static PidFileDescriptor from_pid (uint pid) throws Error {
int fd = pidfd_open (pid, 0);
if (fd == -1)
throw_pidfd_error (pid, errno);
return new PidFileDescriptor (fd, pid);
}
public FileDescriptor getfd (int targetfd) throws Error {
int fd = pidfd_getfd (handle, targetfd, 0);
if (fd == -1)
throw_pidfd_error (pid, errno);
return new FileDescriptor (fd);
}
private static int pidfd_open (uint pid, uint flags) {
return Linux.syscall (SysCall.pidfd_open, pid, flags);
}
private static int pidfd_getfd (int pidfd, int targetfd, uint flags) {
return Linux.syscall (SysCall.pidfd_getfd, pidfd, targetfd, flags);
}
[NoReturn]
private static void throw_pidfd_error (uint pid, int err) throws Error {
switch (err) {
case Posix.ESRCH:
throw new Error.PROCESS_NOT_FOUND ("Process not found");
case Posix.EPERM:
throw new Error.PERMISSION_DENIED ("Unable to use pidfd for pid %u: %s", pid, strerror (err));
default:
throw new Error.NOT_SUPPORTED ("Unable to use pidfd for pid %u: %s", pid, strerror (err));
}
}
}
namespace MemoryFileDescriptor {
public bool is_supported () {
return check_kernel_version (3, 17);
}
public static FileDescriptor from_bytes (string name, Bytes bytes) {
assert (is_supported ());
var fd = new FileDescriptor (memfd_create (name, 0));
unowned uint8[] data = bytes.get_data ();
ssize_t n = Posix.write (fd.handle, data, data.length);
assert (n == data.length);
return fd;
}
private int memfd_create (string name, uint flags) {
return Linux.syscall (SysCall.memfd_create, name, flags);
}
}
}
+18 -1
View File
@@ -9,9 +9,11 @@ base_sources = [
'p2p-glue.c',
'dbus.vala',
'promise.vala',
'fs.vala',
'socket.vala',
'socket-glue.c',
'buffer.vala',
'buffer-glue.c',
'value.vala',
]
@@ -28,6 +30,15 @@ if host_os_family == 'darwin'
base_sources += 'corefoundation.vala'
endif
if host_os_family == 'linux'
base_sources += 'linux.vala'
extra_vala_args += [
'--pkg=linux',
'--pkg=linux-system',
'--pkg=posix',
]
endif
extra_deps = []
if host_os_family != 'windows'
extra_vala_args += '--pkg=gio-unix-2.0'
@@ -45,6 +56,12 @@ if host_os_family == 'darwin'
'--pkg=darwin-xpc',
]
endif
if host_os_family == 'linux'
base_vala_args += [
'--vapidir=' + meson.current_source_dir(),
'--pkg=gio-unix-2.0',
]
endif
base_gir_name = f'FridaBase-@[email protected]'
@@ -62,7 +79,7 @@ base = static_library('frida-base-' + api_version, base_sources,
base_dep = declare_dependency(
include_directories: include_directories('.'),
link_with: base,
dependencies: [nice_dep, json_glib_dep, gum_dep],
dependencies: [nice_dep, json_glib_dep, gum_dep] + extra_deps,
)
base_build_dir = meson.current_build_dir()
+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);
}
+52
View File
@@ -1,6 +1,8 @@
#include "frida-gadget.h"
#import <Foundation/Foundation.h>
#include <gum/gumdarwin.h>
#include <mach-o/loader.h>
#include <objc/runtime.h>
#include <pthread.h>
@@ -51,3 +53,53 @@ 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);
}
+18 -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 {
@@ -759,7 +683,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 +691,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 +699,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 +728,7 @@ namespace Frida.Gadget {
return true;
});
#endif
assert (our_range != null);
@@ -1234,7 +1158,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);
}
@@ -1242,7 +1166,13 @@ namespace Frida.Gadget {
}
private sealed class Script : Object, RpcPeer {
private const uint8 QUICKJS_BYTECODE_MAGIC = 0x02;
private const uint8 QUICKJS_BYTECODE_MAGIC =
#if BIG_ENDIAN
0x42
#else
0x02
#endif
;
public enum ChangeBehavior {
IGNORE,
@@ -2170,6 +2100,10 @@ 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);
#endif
}
private extern void log_info (string message);
+7 -7
View File
@@ -55,6 +55,7 @@ struct _FridaUnwindHookState
gpointer set_info_original;
void (* set_info) (gpointer cursor, gint is_return_address);
gpointer (* get_reg) (gpointer cursor, gint reg);
GumInterceptor * interceptor;
};
#if __has_feature (ptrauth_calls)
@@ -97,7 +98,6 @@ _frida_unwind_sitter_hook_libunwind (void)
#if GLIB_SIZEOF_VOID_P == 8
gpointer * set_info_slot;
gpointer get_reg_impl;
GumInterceptor * interceptor;
if (state != NULL)
return;
@@ -121,8 +121,9 @@ _frida_unwind_sitter_hook_libunwind (void)
state->set_info = FRIDA_RESIGN_PTR (state->set_info_original);
state->get_reg = FRIDA_RESIGN_PTR (get_reg_impl);
interceptor = gum_interceptor_obtain ();
if (gum_interceptor_replace (interceptor, state->set_info_original, frida_unwind_cursor_set_info_replacement, NULL, NULL)
state->interceptor = gum_interceptor_obtain ();
if (gum_interceptor_replace (state->interceptor, state->set_info_original, frida_unwind_cursor_set_info_replacement, NULL, NULL)
!= GUM_REPLACE_OK)
goto unsupported_version;
@@ -137,13 +138,12 @@ unsupported_version:
void
_frida_unwind_sitter_unhook_libunwind (void)
{
GumInterceptor * interceptor;
if (state == NULL)
return;
interceptor = gum_interceptor_obtain ();
gum_interceptor_revert (interceptor, state->set_info_original);
gum_interceptor_revert (state->interceptor, state->set_info_original);
g_object_unref (state->interceptor);
g_slice_free (FridaUnwindHookState, state);
state = NULL;
+104 -67
View File
@@ -6,13 +6,17 @@ project('frida-core', 'vala', 'c', 'cpp',
default_options: ['c_std=gnu99,c99', 'cpp_std=c++17'],
)
fs = import('fs')
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']
@@ -20,7 +24,7 @@ cc = meson.get_compiler('c')
cpp = meson.get_compiler('cpp')
releng = meson.global_source_root() / 'releng'
if not import('fs').exists(releng)
if not fs.exists(releng)
releng = meson.project_source_root() / 'releng'
endif
@@ -98,11 +102,6 @@ else
host_cpu_mode = '32'
endif
host_docks_mobile_devices = host_os in ['windows', 'macos', 'linux'] and host_cpu_mode == '64'
gumjs_archs = {
'x86': 'ia32',
'x86_64': 'x64',
}
host_arch_gumjs = gumjs_archs.get(host_arch, host_arch)
if host_os_family == 'darwin'
c_languages += ['objc', 'objcpp']
@@ -272,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'
@@ -362,6 +363,44 @@ if host_os == 'android'
])
endif
if host_toolchain == 'microsoft'
lib = find_program('lib')
ar = ''
nm = ''
ranlib = ''
strip = ''
else
lib = ''
ar = find_program('ar')
nm = find_program('nm')
ranlib = find_program('ranlib')
strip = find_program('strip')
endif
if host_os_family != 'windows'
if host_os_family == 'darwin'
readelf = ''
otool = find_program('otool')
libtool = find_program('libtool')
else
readelf = find_program('readelf')
otool = ''
libtool = ''
endif
else
readelf = ''
otool = ''
libtool = ''
endif
if host_os_family == 'darwin'
install_name_tool = find_program('install_name_tool')
lipo = find_program('lipo')
codesign = find_program('codesign')
else
install_name_tool = ''
lipo = ''
codesign = ''
endif
have_local_backend = get_option('local_backend').allowed()
have_fruity_backend = get_option('fruity_backend') \
.disable_auto_if(not host_docks_mobile_devices) \
@@ -374,15 +413,54 @@ have_barebone_backend = get_option('barebone_backend') \
.disable_if(not quickjs_dep.found()) \
.disable_auto_if(not host_docks_mobile_devices) \
.allowed()
have_compiler_backend = get_option('compiler_backend') \
.disable_if(not have_local_backend, error_message: 'compiler backend requires the local backend for script execution') \
.disable_auto_if(host_os == 'watchos') \
.allowed()
if get_option('compiler_snapshot').auto()
# Generating our snapshot with V8's CPU simulator takes a very long time.
generate_compiler_snapshot = meson.can_run_host_binaries()
else
generate_compiler_snapshot = get_option('compiler_snapshot').enabled()
compiler_backend_opt = get_option('compiler_backend') \
.disable_auto_if(host_os == 'watchos')
have_compiler_backend = false
if compiler_backend_opt.allowed()
go = find_program('go', native: true, required: false)
if go.found()
message('Detecting cgo availability')
detect_output = run_command(
[
python,
files('tools' / 'cgo' / 'detect.py'),
go,
host_os,
host_abi,
shlib_suffix,
cc.get_id(),
'>>>', cc.cmd_array(), '<<<',
'>>>', ar, '<<<',
'>>>', nm, '<<<',
'>>>', ranlib, '<<<',
],
capture: true,
check: true
).stdout()
lines = detect_output.split('\n')
status = lines[0]
if status == 'ok'
have_compiler_backend = true
tokens = lines[1].split(' ')
go_mode = tokens[0]
go_config = tokens[1]
compiler_backend_static_compilation = go_mode == 'c-archive'
if compiler_backend_static_compilation
vala_flags += '--define=COMPILER_BACKEND_STATIC_COMPILATION'
endif
else
error_message = lines[1]
if compiler_backend_opt.enabled()
error(error_message)
else
warning(f'Building without Compiler backend: @error_message@')
endif
endif
elif compiler_backend_opt.enabled()
error('Need Go >= 1.24 to build the Compiler backend powered by ESBuild and typescript-go')
else
warning('Building without Compiler backend: Go >= 1.24 not found')
endif
endif
build_gadget = get_option('gadget') \
@@ -452,12 +530,6 @@ gumjs_inspector_vala_args = ['--pkg=frida-gumjs-inspector-1.0', gum_vala_args]
have_v8 = gumjs_dep.get_variable('gumjs_v8') == 'enabled'
if have_v8
vala_flags += ['--define=HAVE_V8']
v8_mksnapshot = find_program('v8-mksnapshot-@0@-@1@'.format(host_os, host_abi), required: false)
if not v8_mksnapshot.found()
v8_mksnapshot = ''
endif
else
v8_mksnapshot = ''
endif
backend_deps_private = []
@@ -579,42 +651,6 @@ if host_os in ['ios', 'tvos']
backend_libs_private += ['-Wl,-framework,CoreGraphics', '-Wl,-framework,UIKit']
endif
if host_toolchain == 'microsoft'
lib = find_program('lib')
ar = ''
nm = ''
strip = ''
else
lib = ''
ar = find_program('ar')
nm = find_program('nm')
strip = find_program('strip')
endif
if host_os_family != 'windows'
if host_os_family == 'darwin'
readelf = ''
otool = find_program('otool')
libtool = find_program('libtool')
else
readelf = find_program('readelf')
otool = ''
libtool = ''
endif
else
readelf = ''
otool = ''
libtool = ''
endif
if host_os_family == 'darwin'
install_name_tool = find_program('install_name_tool')
lipo = find_program('lipo')
codesign = find_program('codesign')
else
install_name_tool = ''
lipo = ''
codesign = ''
endif
if get_option('devkits').length() != 0
if get_option('default_library') != 'static'
error('Devkits can only be generated from static libraries')
@@ -622,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'), '<<<',
@@ -708,14 +745,15 @@ vala_flags += [
'--pkg', 'config',
]
vala_flags += ['--define=' + host_os_family.to_upper()]
vala_flags += '--define=' + host_os_family.to_upper()
if host_os != host_os_family
vala_flags += ['--define=' + host_os.to_upper()]
vala_flags += '--define=' + host_os.to_upper()
endif
vala_flags += ['--define=' + host_arch.to_upper()]
vala_flags += '--define=' + host_arch.to_upper()
if host_abi != host_arch
vala_flags += ['--define=' + host_abi.to_upper()]
vala_flags += '--define=' + host_abi.to_upper()
endif
vala_flags += '--define=' + host_machine.endian().to_upper() + '_ENDIAN'
add_project_arguments(vala_flags, language: 'vala')
add_project_arguments('-I' + vapidir, language: 'c')
@@ -760,7 +798,6 @@ summary(
'assets': get_option('assets'),
'mapper': have_mapper,
'connectivity': tls_provider_dep.found(),
'compiler_snapshot': generate_compiler_snapshot,
'gadget': build_gadget,
'server': build_server,
'portal': build_portal,
+10 -7
View File
@@ -37,13 +37,7 @@ option('barebone_backend',
option('compiler_backend',
type: 'feature',
value: 'auto',
description: 'Include frida-compile backend powered by GumJS',
)
option('compiler_snapshot',
type: 'feature',
value: 'auto',
description: 'Speed up compiler startup by using a snapshot'
description: 'Include frida-compile backend powered by ESBuild and typescript-go',
)
option('assets',
@@ -156,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: 5d9edf166c...38daa4fd6a.
+40 -5
View File
@@ -26,6 +26,11 @@ OBJECT_TYPE_PATTERN = re.compile(r"\bpublic\s+(sealed )?(class|interface)\s+(\w+
def main():
parser = argparse.ArgumentParser(description="Generate refined Frida API definitions")
parser.add_argument('--output', dest='output_type', choices=['bundle', 'header', 'gir', 'vapi', 'vapi-stamp'], default='bundle')
parser.add_argument('frida_version', metavar='frida-version', type=str)
parser.add_argument('frida_major_version', metavar='frida-major-version', type=str)
parser.add_argument('frida_minor_version', metavar='frida-minor-version', type=str)
parser.add_argument('frida_micro_version', metavar='frida-micro-version', type=str)
parser.add_argument('frida_nano_version', metavar='frida-nano-version', type=str)
parser.add_argument('api_version', metavar='api-version', type=str)
parser.add_argument('core_header', metavar='/path/to/frida-core.h', type=argparse.FileType('r', encoding='utf-8'))
parser.add_argument('core_gir', metavar='/path/to/Frida-x.y.gir', type=argparse.FileType('r', encoding='utf-8'))
@@ -38,6 +43,13 @@ def main():
args = parser.parse_args()
output_type = args.output_type
frida_version = args.frida_version
frida_version_components = (
args.frida_major_version,
args.frida_minor_version,
args.frida_micro_version,
args.frida_nano_version,
)
api_version = args.api_version
core_header = args.core_header.read()
core_gir = args.core_gir.read()
@@ -53,6 +65,7 @@ def main():
toplevel_names = [
"frida.vala",
"package-manager.vala",
"control-service.vala",
"portal-service.vala",
"file-monitor.vala",
@@ -78,7 +91,7 @@ def main():
elif output_type == 'vapi':
enable_vapi = True
api = parse_api(api_version, toplevel_code, core_header, core_vapi, base_header, base_vapi)
api = parse_api(frida_version, frida_version_components, api_version, toplevel_code, core_header, core_vapi, base_header, base_vapi)
if enable_header:
emit_header(api, output_dir)
@@ -93,7 +106,26 @@ def emit_header(api, output_dir):
with OutputFile(output_dir / 'frida-core.h') as output_header_file:
output_header_file.write("#ifndef __FRIDA_CORE_H__\n#define __FRIDA_CORE_H__\n\n")
output_header_file.write("#include <glib.h>\n#include <glib-object.h>\n#include <gio/gio.h>\n#include <json-glib/json-glib.h>\n")
output_header_file.write("#include <glib.h>\n#include <glib-object.h>\n#include <gio/gio.h>\n#include <json-glib/json-glib.h>\n\n")
output_header_file.write(f"#define FRIDA_VERSION \"{api.frida_version}\"\n\n")
for name, value in zip(['MAJOR', 'MINOR', 'MICRO', 'NANO'], api.frida_version_components):
output_header_file.write(f"#define FRIDA_{name}_VERSION {value}\n")
output_header_file.write("""
#define FRIDA_CHECK_VERSION(maj, min, mic) \\
(FRIDA_CURRENT_VERSION >= FRIDA_VERSION_ENCODE ((maj), (min), (mic)))
#define FRIDA_CURRENT_VERSION \\
FRIDA_VERSION_ENCODE ( \\
FRIDA_MAJOR_VERSION, \\
FRIDA_MINOR_VERSION, \\
FRIDA_MICRO_VERSION)
#define FRIDA_VERSION_ENCODE(maj, min, mic) \\
(((maj) * 1000000U) + ((min) * 1000U) + (mic))
""")
output_header_file.write("\nG_BEGIN_DECLS\n")
@@ -271,7 +303,7 @@ def emit_vapi(api, output_dir):
output_deps_file.write("gobject-2.0\n")
output_deps_file.write("gio-2.0\n")
def parse_api(api_version, toplevel_code, core_header, core_vapi, base_header, base_vapi):
def parse_api(frida_version, frida_version_components, api_version, toplevel_code, core_header, core_vapi, base_header, base_vapi):
all_headers = core_header + "\n" + base_header
all_enum_names = [m.group(1) for m in re.finditer(r"^\t+public\s+enum\s+(\w+)\s+", toplevel_code + "\n" + base_vapi, re.MULTILINE)]
@@ -464,7 +496,7 @@ def parse_api(api_version, toplevel_code, core_header, core_vapi, base_header, b
m = re.search(r"^[\w\*]+ frida_{}.+?;".format(f.name), all_headers, re.MULTILINE | re.DOTALL)
f.c_prototype = beautify_cprototype(m.group(0))
return ApiSpec(api_version, object_types, functions, enum_types, error_types)
return ApiSpec(frida_version, frida_version_components, api_version, object_types, functions, enum_types, error_types)
def function_is_public(name):
return not name.startswith("_") and \
@@ -478,7 +510,8 @@ def function_is_public(name):
"parse_control_address",
"parse_cluster_address",
"parse_socket_address",
"negotiate_connection"
"negotiate_connection",
"check_kernel_version",
]
def parse_vala_object_types(source) -> List[ApiObjectType]:
@@ -489,6 +522,8 @@ def parse_vapi_functions(vapi) -> List[ApiFunction]:
@dataclass
class ApiSpec:
frida_version: str
frida_version_components: List[int]
version: str
object_types: List[ApiObjectType]
functions: List[ApiFunction]
+5
View File
@@ -3,6 +3,11 @@ fs = import('fs')
generate_api = [python, files('generate.py')]
generate_api_args = [
frida_version,
frida_major_version.to_string(),
frida_minor_version.to_string(),
frida_micro_version.to_string(),
frida_nano_version.to_string(),
api_version,
core_build_dir / 'frida-core.h',
core_build_dir / core_gir_name,
+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 ();
}
+37 -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 ();
@@ -111,8 +100,19 @@ namespace Frida {
var page_size = yield machine.query_page_size (cancellable);
// 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);
@@ -465,7 +465,8 @@ namespace Frida {
public async void load_script (AgentScriptId script_id, Cancellable? cancellable) throws Error, IOError {
check_open ();
get_script (script_id).load ();
var script = get_script (script_id);
yield script.load (cancellable);
}
public async void eternalize_script (AgentScriptId script_id, Cancellable? cancellable) throws Error, IOError {
+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',
+443 -445
View File
@@ -9,318 +9,434 @@
"version": "1.0.0",
"devDependencies": {
"@types/frida-gum": "^19.0.0",
"frida-compile": "^17.0.0"
"esbuild": "^0.25.5",
"typescript": "^5.8.3"
}
},
"node_modules/@frida/assert": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@frida/assert/-/assert-3.0.2.tgz",
"integrity": "sha512-JXJq5SbXGrM5EkjrZKfRmB29zOoEOix02NC6A5TSJ+C1GE/X051EinJJsuOO2pEOx7KZwpvAHvS0WXW0+levKg==",
"dev": true
},
"node_modules/@frida/base64-js": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@frida/base64-js/-/base64-js-2.0.3.tgz",
"integrity": "sha512-2w0F+1TynOTCZ/v7du9LdHPWwq0lJhazjo2fF9upMyQmA1zHetT14fLuQ1v/6T0qPgyeEGkiSrybstU8EsgeUA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/@frida/buffer": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/@frida/buffer/-/buffer-7.0.4.tgz",
"integrity": "sha512-RxQ1lZRRiCJj7nhcCiD8xeJx0NsLpGGnjqsmTg7jShGmbnVFMN5W7+J+3gqdPSQhc/IxNBIWc6zRXVp4+qnYHg==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
"node_modules/@esbuild/aix-ppc64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz",
"integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==",
"cpu": [
"ppc64"
],
"dependencies": {
"base64-js": "^1.5.1",
"ieee754": "^1.2.1"
}
},
"node_modules/@frida/crosspath": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@frida/crosspath/-/crosspath-3.0.0.tgz",
"integrity": "sha512-bNdO1spIPD2P40XtK89N49oZpJhstdlnkJZcD4yJ17jrdkm9Ctu0sd9MIEX6Z8Tm8ydhVJBAOMEKl9/R27onAQ==",
"dev": true,
"dependencies": {
"@types/node": "^17.0.36"
},
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=14.9.0"
"node": ">=18"
}
},
"node_modules/@frida/crypto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@frida/crypto/-/crypto-1.0.1.tgz",
"integrity": "sha512-WXTkVjESvX8TIVXIynJJv9BKSIdQP0Iis04StIXknkDi1ULdMlrypA9p5C4KW1H6GCkNsVnKbybpzsulYCTvag==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/diagnostics_channel": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/diagnostics_channel/-/diagnostics_channel-1.0.0.tgz",
"integrity": "sha512-mYX1jp/5Bpk24tHArJNx65iCk7qSuV8YJkdU0gFNVtJUXxfV8BG5WuPa4mL+ynxsbWWpsg/cwKZbLAepYKTdQQ==",
"dev": true
},
"node_modules/@frida/events": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/@frida/events/-/events-4.0.4.tgz",
"integrity": "sha512-qJVQ6VWHf9sjUKuiJzoCAC00frbpcwxeYfvQ+PP9LU/d70j+QvjWgYe98Qa3ekLaBU6r/AvWm8ThKCDUCLWrQQ==",
"node_modules/@esbuild/android-arm": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz",
"integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=0.8.x"
"node": ">=18"
}
},
"node_modules/@frida/http": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@frida/http/-/http-4.0.2.tgz",
"integrity": "sha512-cvkc7ex7GmVXVOWqtjXKBWUUbYEBgpNRKZbEEoMeI8KiIs8zejKwg+N7rx7296Ao+EP3+xcUr4wBVr3xLaUVfQ==",
"node_modules/@esbuild/android-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz",
"integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==",
"cpu": [
"arm64"
],
"dev": true,
"dependencies": {
"http-parser-js": "^0.5.3"
}
},
"node_modules/@frida/http-parser-js": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/http-parser-js/-/http-parser-js-1.0.0.tgz",
"integrity": "sha512-2nMrNXt/OeTlWbqnE8AH4Sfz4I2+BGoN206dzKEyC/g2svtn83Xu+zuv/V3TkwrA27s26Mcy84ZwsXeNlqNxUQ==",
"dev": true
},
"node_modules/@frida/https": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/https/-/https-1.0.0.tgz",
"integrity": "sha512-OiqQ6qsALcWOktRLq07oJ0i6sH8eX6MXb/MdZS1qVKDRf6wchH4Pjn6fiLB+pt/OlYbggk+DOfpHwSdjTwuHMQ==",
"dev": true
},
"node_modules/@frida/ieee754": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@frida/ieee754/-/ieee754-2.0.2.tgz",
"integrity": "sha512-wlcUebnne4ENN7GDr5pTH598ZDLMVOsh0FjenxeVOe6u7ewZkz9gGRnLnZKJAm9kl5G6XhdxhI0cSXVQK/rQUw==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/@frida/net": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@frida/net/-/net-4.0.2.tgz",
"integrity": "sha512-qQRe7hQ+ZfCcG/SE3P1TRqQ9bmuK/T7wPCYaT4z56rBPWAxsaQbQHpX4fR6OrFaSDr7X0xJLsTbdIp9hGhhLZg==",
"dev": true
},
"node_modules/@frida/os": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@frida/os/-/os-1.0.2.tgz",
"integrity": "sha512-3ISAiGNiyIya3QN2EHBCz1wqP0enTdSxP99wUeroeh8+AQRmgoOr/5TRnrVry8pe378anay3fmV/tdUMMSkehQ==",
"dev": true
},
"node_modules/@frida/path": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@frida/path/-/path-2.0.3.tgz",
"integrity": "sha512-2RQy36QatoC846fzBhBhV8sXMsSOBGoYvwTHeaE1zUdz7F4RNScP4QEekTTooBYWYX/XjiF36KQpYAzc9OYFtg==",
"dev": true
},
"node_modules/@frida/process": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@frida/process/-/process-1.2.1.tgz",
"integrity": "sha512-nvCu22DstFW2ttGFtOKekHM7vnjbZm+XgtvavOt427GNT6uV7k0JYK9tnMbcLMRWv57DG6udAmuJlWs8Paq1ag==",
"dev": true
},
"node_modules/@frida/punycode": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@frida/punycode/-/punycode-3.0.0.tgz",
"integrity": "sha512-XVSDY2KamDs1D5/fTVgHcOSNxdU4kTboxzqJMBbTjcQC7XScIT9c0EfbwKCq7Kci6gWQdsHSCr7lU+9Oc4KAdg==",
"dev": true
},
"node_modules/@frida/querystring": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/querystring/-/querystring-1.0.0.tgz",
"integrity": "sha512-15m1fOZPmoO/vWlgPJrG/J9/BJDz6a2/JpVGpS8ynNzo+fBhTznaStX5nHxUs24mVTqh/OqLo0EiYJM5WWHXxg==",
"dev": true
},
"node_modules/@frida/readable-stream": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/@frida/readable-stream/-/readable-stream-4.1.3.tgz",
"integrity": "sha512-ntGUFmi+CryRGRJIK13a/VST2Ad19uivbln8Xd92vKPAARq+6vMIASDyZIqyl5BLRccfiyCHdYgrgQ6RI5rUig==",
"dev": true
},
"node_modules/@frida/reserved-words": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/reserved-words/-/reserved-words-1.0.0.tgz",
"integrity": "sha512-2yG/XxJlsGlk/mm6eZTb4OAaQEhkTI2qaFfZFtAsrA/XuCpuMWkS4y/guyBlsRu4hAuhK2HPmNM8+OLLK1zM9Q==",
"dev": true
},
"node_modules/@frida/stream": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@frida/stream/-/stream-1.0.2.tgz",
"integrity": "sha512-4OuaC1ztmEKgTq3WeBhsy8Oq+AwW9n9cYnvLklcC9jwD93AEwgbWpecLlxJCVuALvTMdhKPg0nQVfyGYP/i9Bw==",
"dev": true,
"dependencies": {
"@frida/readable-stream": "^4.1.3"
}
},
"node_modules/@frida/string_decoder": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@frida/string_decoder/-/string_decoder-2.0.0.tgz",
"integrity": "sha512-in371tYZMHQiW9HF5MS3JDw6Ao6tyBoq34UWy2rzOswYyMG1rpizh85ofi/yVkxDiaqybEZefxzkVittpPGT6g==",
"dev": true
},
"node_modules/@frida/terser": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/terser/-/terser-1.0.0.tgz",
"integrity": "sha512-59h9WuNzD1Rx/zwoWqQ/FW/4Y/Q3R91Eng2hEwdHapqiTDvtKbZ08F6CynCR7ZVinrh4tLYsF46AtVPTz1ys9g==",
"dev": true,
"dependencies": {
"@jridgewell/source-map": "^0.3.2",
"acorn": "^8.5.0",
"commander": "^2.20.0",
"source-map-support": "~0.5.20"
},
"bin": {
"terser": "bin/terser"
},
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=10"
"node": ">=18"
}
},
"node_modules/@frida/terser/node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true
},
"node_modules/@frida/timers": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@frida/timers/-/timers-3.0.0.tgz",
"integrity": "sha512-3b+0igv10aT8TMxefrTAd06rActqbxJLY2Xkkq9vYcPBffB/yHszl0NYIp/5ko8WC3ecDYPU6bQiY6fjs72zTA==",
"dev": true
},
"node_modules/@frida/tty": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/tty/-/tty-1.0.0.tgz",
"integrity": "sha512-p/kjLnKYxEAB1MdYP8+5rKv9CsHzyA+0jg9BcGETzjQVKHHcroHDULRxDYUh+DC7qs6cpX8QdDQh9E+a6ydgsQ==",
"dev": true
},
"node_modules/@frida/url": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@frida/url/-/url-1.0.2.tgz",
"integrity": "sha512-ZKunbKJHMr8w2Eb/5K1avy0MzK1B998S17wYXNv3RmzBGxMm8S5T0F3qEpRxkU7/72P8m4izyQU87fWl+FjQsQ==",
"node_modules/@esbuild/android-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz",
"integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==",
"cpu": [
"x64"
],
"dev": true,
"dependencies": {
"@frida/punycode": "^3.0.0",
"@frida/querystring": "^1.0.0"
}
},
"node_modules/@frida/util": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@frida/util/-/util-1.0.3.tgz",
"integrity": "sha512-htcG3uDiRXv89ERVNNYhfase39kJ2X75ZARfrYcYEtJLFEsSk0nemM1YnEIR4CjrHvdvkWHrwgKkS+acOyoNEg==",
"dev": true
},
"node_modules/@frida/vm": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@frida/vm/-/vm-2.0.0.tgz",
"integrity": "sha512-7fsjLWscZT5odNIBtg6qbLNI+vAk1xmii6H5W2kaYkMYt0vRohQEcDSUWacA+eaWlu5SvMjZI82Yibj/3G9pJw==",
"dev": true
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
"integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
"dev": true,
"dependencies": {
"@jridgewell/set-array": "^1.0.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/trace-mapping": "^0.3.9"
},
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=6.0.0"
"node": ">=18"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
"integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
"node_modules/@esbuild/darwin-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz",
"integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=6.0.0"
"node": ">=18"
}
},
"node_modules/@jridgewell/set-array": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
"node_modules/@esbuild/darwin-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz",
"integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=6.0.0"
"node": ">=18"
}
},
"node_modules/@jridgewell/source-map": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz",
"integrity": "sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==",
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz",
"integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==",
"cpu": [
"arm64"
],
"dev": true,
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.0",
"@jridgewell/trace-mapping": "^0.3.9"
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
"dev": true
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.18",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz",
"integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==",
"node_modules/@esbuild/freebsd-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz",
"integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==",
"cpu": [
"x64"
],
"dev": true,
"dependencies": {
"@jridgewell/resolve-uri": "3.1.0",
"@jridgewell/sourcemap-codec": "1.4.14"
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.14",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
"dev": true
"node_modules/@esbuild/linux-arm": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz",
"integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz",
"integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz",
"integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz",
"integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz",
"integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==",
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz",
"integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz",
"integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz",
"integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz",
"integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz",
"integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz",
"integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz",
"integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz",
"integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz",
"integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz",
"integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz",
"integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz",
"integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@types/frida-gum": {
"version": "19.0.0",
@@ -329,177 +445,59 @@
"dev": true,
"license": "MIT"
},
"node_modules/@types/node": {
"version": "17.0.45",
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz",
"integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==",
"dev": true
},
"node_modules/acorn": {
"version": "8.8.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
"integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
"dev": true,
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true
},
"node_modules/commander": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
"integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
"node_modules/esbuild": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz",
"integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"engines": {
"node": ">=16"
}
},
"node_modules/frida-compile": {
"version": "17.0.0",
"resolved": "https://registry.npmjs.org/frida-compile/-/frida-compile-17.0.0.tgz",
"integrity": "sha512-ixJRj14qLH/Z0ckFWd5fKeDMm0W2+2WDpSGnLRgpn0nuCQAbDHRCqVCWtPnV8uzPJmA6XOX0pujsMpYe9q9RRw==",
"dev": true,
"dependencies": {
"@frida/assert": "^3.0.1",
"@frida/base64-js": "^2.0.3",
"@frida/buffer": "^7.0.4",
"@frida/crosspath": "^3.0.0",
"@frida/crypto": "^1.0.1",
"@frida/diagnostics_channel": "^1.0.0",
"@frida/events": "^4.0.4",
"@frida/http": "^4.0.2",
"@frida/http-parser-js": "^1.0.0",
"@frida/https": "^1.0.0",
"@frida/ieee754": "^2.0.2",
"@frida/net": "^4.0.1",
"@frida/os": "^1.0.0",
"@frida/path": "^2.0.3",
"@frida/process": "^1.2.1",
"@frida/punycode": "^3.0.0",
"@frida/querystring": "^1.0.0",
"@frida/readable-stream": "^4.1.3",
"@frida/reserved-words": "^1.0.0",
"@frida/stream": "^1.0.2",
"@frida/string_decoder": "^2.0.0",
"@frida/terser": "^1.0.0",
"@frida/timers": "^3.0.0",
"@frida/tty": "^1.0.0",
"@frida/url": "^1.0.2",
"@frida/util": "^1.0.3",
"@frida/vm": "^2.0.0",
"commander": "^11.1.0",
"frida-fs": "^6.0.0",
"typed-emitter": "^2.1.0"
},
"bin": {
"frida-compile": "dist/cli.js"
}
},
"node_modules/frida-fs": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/frida-fs/-/frida-fs-6.0.0.tgz",
"integrity": "sha512-I0fnKupZh7fU2ixwCIjJnEqNdhfm/SC1ZYBMy58EmeqOWSbjw1Dpy99mJ7BJdbk2KNXJeaBZGxDYLtn0J9S+UA==",
"dev": true,
"license": "MIT"
},
"node_modules/http-parser-js": {
"version": "0.5.8",
"resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz",
"integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==",
"dev": true
},
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/rxjs": {
"version": "7.8.1",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz",
"integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==",
"dev": true,
"optional": true,
"dependencies": {
"tslib": "^2.1.0"
}
},
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dev": true,
"dependencies": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"node_modules/tslib": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz",
"integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==",
"dev": true,
"optional": true
},
"node_modules/typed-emitter": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-2.1.0.tgz",
"integrity": "sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==",
"dev": true,
"node": ">=18"
},
"optionalDependencies": {
"rxjs": "*"
"@esbuild/aix-ppc64": "0.25.5",
"@esbuild/android-arm": "0.25.5",
"@esbuild/android-arm64": "0.25.5",
"@esbuild/android-x64": "0.25.5",
"@esbuild/darwin-arm64": "0.25.5",
"@esbuild/darwin-x64": "0.25.5",
"@esbuild/freebsd-arm64": "0.25.5",
"@esbuild/freebsd-x64": "0.25.5",
"@esbuild/linux-arm": "0.25.5",
"@esbuild/linux-arm64": "0.25.5",
"@esbuild/linux-ia32": "0.25.5",
"@esbuild/linux-loong64": "0.25.5",
"@esbuild/linux-mips64el": "0.25.5",
"@esbuild/linux-ppc64": "0.25.5",
"@esbuild/linux-riscv64": "0.25.5",
"@esbuild/linux-s390x": "0.25.5",
"@esbuild/linux-x64": "0.25.5",
"@esbuild/netbsd-arm64": "0.25.5",
"@esbuild/netbsd-x64": "0.25.5",
"@esbuild/openbsd-arm64": "0.25.5",
"@esbuild/openbsd-x64": "0.25.5",
"@esbuild/sunos-x64": "0.25.5",
"@esbuild/win32-arm64": "0.25.5",
"@esbuild/win32-ia32": "0.25.5",
"@esbuild/win32-x64": "0.25.5"
}
},
"node_modules/typescript": {
"version": "5.8.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
}
}
+6 -3
View File
@@ -2,12 +2,15 @@
"name": "frida-barebone-script-runtime",
"version": "1.0.0",
"description": "Script runtime used by Frida's Barebone backend",
"type": "module",
"scripts": {
"prepare": "npm run build",
"build": "frida-compile script-runtime/entrypoint.ts -o script-runtime.js -c"
"build": "esbuild script-runtime/entrypoint.ts --outfile=script-runtime.js --bundle --platform=node --target=es2022 --minify",
"check": "tsc",
"watch": "tsc -w"
},
"devDependencies": {
"@types/frida-gum": "^19.0.0",
"frida-compile": "^17.0.0"
"esbuild": "^0.25.5",
"typescript": "^5.8.3"
}
}
+40 -73
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,14 +165,17 @@ 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);
}
}
~CompilationAssets () {
rmtree (workdir);
try {
FS.rmtree (workdir);
} catch (Error e) {
}
}
private static string make_main_rs (string code, Machine machine) {
@@ -267,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;
@@ -279,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;
}
@@ -304,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]
@@ -428,23 +414,4 @@ namespace Frida.Barebone {
yield file.replace_contents_async (content.data, null, false, FileCreateFlags.NONE, cancellable, null);
return file;
}
private void rmtree (File dir) {
try {
var enumerator = dir.enumerate_children (FileAttribute.STANDARD_NAME, NOFOLLOW_SYMLINKS);
FileInfo? info;
File? child;
while (enumerator.iterate (out info, out child) && info != null) {
if (info == null)
continue;
if (info.get_file_type () == DIRECTORY)
rmtree (child);
else
child.delete ();
}
dir.delete ();
} catch (GLib.Error e) {
}
}
}
+18 -18
View File
@@ -210,24 +210,6 @@ Object.defineProperties(globalThis, {
}
}
},
ObjC: {
enumerable: true,
value: {
available: false
}
},
Swift: {
enumerable: true,
value: {
available: false
}
},
Java: {
enumerable: true,
value: {
available: false
}
},
console: {
enumerable: true,
value: new Console()
@@ -322,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);
@@ -356,6 +345,17 @@ const marshalers: { [type: string]: Marshaler } = {
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 {
+276 -47
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> ();
@@ -72,7 +73,7 @@ namespace Frida {
private QuickJS.Value int64_func = QuickJS.Undefined;
private QuickJS.Value uint64_func = QuickJS.Undefined;
private Gee.ArrayList<QuickJS.Value?> entrypoints = new Gee.ArrayList<QuickJS.Value?> ();
private Gee.Queue<Entrypoint> entrypoints = new Gee.ArrayQueue<Entrypoint> ();
private Gee.Map<string, Asset> assets = new Gee.HashMap<string, Asset> ();
private Cancellable io_cancellable = new Cancellable ();
@@ -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;
@@ -328,6 +341,8 @@ namespace Frida {
foreach (var val in values)
ctx.free_value (val);
entrypoints.clear ();
QuickJS.Atom atoms[] = {
address_key,
base_key,
@@ -376,48 +391,65 @@ namespace Frida {
yield;
}
public void load () {
foreach (QuickJS.Value? entrypoint in entrypoints) {
var result = ctx.eval_function (entrypoint);
if (result.is_exception ())
public async void load (Cancellable? cancellable) throws IOError {
Entrypoint? entrypoint;
while ((entrypoint = entrypoints.poll ()) != null) {
var result = ctx.eval_function (ctx.dup_value (entrypoint.callable));
if (result.is_exception ()) {
catch_and_emit ();
ctx.free_value (result);
if (runtime_obj.is_undefined ()) {
runtime_obj = global.get_property_str (ctx, "$rt");
if (!runtime_obj.is_undefined ()) {
dispatch_exception_func = runtime_obj.get_property_str (ctx, "dispatchException");
assert (!dispatch_exception_func.is_undefined ());
dispatch_message_func = runtime_obj.get_property_str (ctx, "dispatchMessage");
assert (!dispatch_message_func.is_undefined ());
var native_pointer_instance = global.get_property_str (ctx, "NULL");
assert (!native_pointer_instance.is_undefined ());
var native_pointer_proto = native_pointer_instance.get_prototype (ctx);
var ir_proto = ctx.make_object_proto (native_pointer_proto);
add_cfunc (ir_proto, "replace", on_invocation_retval_replace, 1);
ctx.set_class_proto (invocation_retval_class, ir_proto);
ctx.free_value (native_pointer_proto);
ctx.free_value (native_pointer_instance);
ptr_func = global.get_property_str (ctx, "ptr");
assert (!ptr_func.is_undefined ());
int64_func = global.get_property_str (ctx, "int64");
assert (!int64_func.is_undefined ());
uint64_func = global.get_property_str (ctx, "uint64");
assert (!uint64_func.is_undefined ());
}
continue;
}
if (entrypoint.kind == ESM) {
var op = new PromiseWaitOperation (this, result);
var r = yield op.perform (cancellable);
if (!r.error.is_null ())
on_unhandled_exception (r.error);
} else {
ctx.free_value (result);
}
maybe_bind_runtime ();
}
perform_pending_io ();
}
private void maybe_bind_runtime () {
if (!runtime_obj.is_undefined ())
return;
runtime_obj = global.get_property_str (ctx, "$rt");
if (runtime_obj.is_undefined ())
return;
dispatch_exception_func = runtime_obj.get_property_str (ctx, "dispatchException");
assert (!dispatch_exception_func.is_undefined ());
dispatch_message_func = runtime_obj.get_property_str (ctx, "dispatchMessage");
assert (!dispatch_message_func.is_undefined ());
var native_pointer_instance = global.get_property_str (ctx, "NULL");
assert (!native_pointer_instance.is_undefined ());
var native_pointer_proto = native_pointer_instance.get_prototype (ctx);
var ir_proto = ctx.make_object_proto (native_pointer_proto);
add_cfunc (ir_proto, "replace", on_invocation_retval_replace, 1);
ctx.set_class_proto (invocation_retval_class, ir_proto);
ctx.free_value (native_pointer_proto);
ctx.free_value (native_pointer_instance);
ptr_func = global.get_property_str (ctx, "ptr");
assert (!ptr_func.is_undefined ());
int64_func = global.get_property_str (ctx, "int64");
assert (!int64_func.is_undefined ());
uint64_func = global.get_property_str (ctx, "uint64");
assert (!uint64_func.is_undefined ());
}
public void post (string json, Bytes? data) {
var json_val = ctx.make_string (json);
var data_val = (data != null) ? ctx.make_array_buffer (data.get_data ()) : QuickJS.Null;
@@ -495,7 +527,7 @@ namespace Frida {
throw_malformed_package ();
var val = compile_module (entrypoint);
entrypoints.add (val);
entrypoints.offer (new Entrypoint (this, val, ESM));
string rest = raw_assets[assets_offset:];
if (rest.has_prefix (delimiter_marker))
@@ -507,7 +539,7 @@ namespace Frida {
}
} else {
var val = compile_script (source, name);
entrypoints.add (val);
entrypoints.offer (new Entrypoint (this, val, PLAIN));
}
}
@@ -653,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) {
@@ -708,6 +736,111 @@ namespace Frida {
}
}
private class Entrypoint {
private weak BareboneScript script;
public QuickJS.Value callable;
public Kind kind;
public enum Kind {
PLAIN,
ESM
}
public Entrypoint (BareboneScript script, QuickJS.Value callable, Kind kind) {
this.script = script;
this.callable = callable;
this.kind = kind;
}
~Entrypoint () {
script.ctx.free_value (callable);
}
}
private class PromiseWaitOperation {
private BareboneScript script;
private QuickJS.Value promise;
private enum Magic {
ON_SUCCESS,
ON_FAILURE,
}
public PromiseWaitOperation (BareboneScript script, QuickJS.Value promise) {
this.script = script;
this.promise = promise;
}
~PromiseWaitOperation () {
script.ctx.free_value (promise);
}
public async Result perform (Cancellable? cancellable) throws IOError {
var res = new Result (script, perform.callback);
unowned QuickJS.Context ctx = script.ctx;
var data = ctx.make_object ();
data.set_opaque (res);
var on_success = ctx.make_cfunction_data (on_settled, 1, Magic.ON_SUCCESS, { data });
var on_failure = ctx.make_cfunction_data (on_settled, 1, Magic.ON_FAILURE, { data });
var then_func = promise.get_property_str (ctx, "then");
var catch_func = promise.get_property_str (ctx, "catch");
ctx.free_value (then_func.call (ctx, promise, { on_success }));
ctx.free_value (catch_func.call (ctx, promise, { on_failure }));
ctx.free_value (catch_func);
ctx.free_value (then_func);
ctx.free_value (on_failure);
ctx.free_value (on_success);
script.perform_pending_io ();
yield;
return res;
}
private static QuickJS.Value on_settled (QuickJS.Context ctx, QuickJS.Value this_val, QuickJS.Value[] argv, int magic,
QuickJS.Value[] data) {
QuickJS.ClassID cid;
unowned Result res = (Result) data[0].get_any_opaque (out cid);
if (magic == Magic.ON_SUCCESS)
res.val = ctx.dup_value (argv[0]);
else
res.error = ctx.dup_value (argv[0]);
var source = new IdleSource ();
source.set_callback ((owned) res.on_complete);
source.attach (MainContext.get_thread_default ());
return QuickJS.Undefined;
}
public class Result {
public BareboneScript script;
public SourceFunc on_complete;
public QuickJS.Value val = QuickJS.Null;
public QuickJS.Value error = QuickJS.Null;
public Result (BareboneScript script, owned SourceFunc on_complete) {
this.script = script;
this.on_complete = (owned) on_complete;
}
~Result () {
unowned QuickJS.Context ctx = script.ctx;
ctx.free_value (val);
ctx.free_value (error);
}
}
}
private class NativeCallbackHandler : Object, Barebone.CallbackHandler {
public uint arity {
get { return _arity; }
@@ -1000,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 ();
@@ -1667,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 ();
@@ -1736,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;
}
@@ -1774,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 ()
+10
View File
@@ -0,0 +1,10 @@
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022"],
"module": "Node16",
"strict": true,
"noEmit": true
},
"include": ["script-runtime/**/*.ts"]
}
-469
View File
@@ -1,469 +0,0 @@
import * as crosspath from "@frida/crosspath";
import type * as backend from "frida-compile";
import {
makeDefaultCompilerOptions,
build as _build,
watch as _watch,
queryDefaultAssets as _queryDefaultAssets,
} from "frida-compile";
import ts from "frida-compile/ext/typescript.js";
import fridaFs from "frida-fs";
import fs from "fs";
const { DiagnosticCategory, FileWatcherEventKind } = ts;
const { S_IFDIR } = fs.constants;
export const compilerRoot = "/frida-compile";
export const compilerNodeModules = compilerRoot + "/node_modules";
export const agentDirectories = new Set<string>(__agentDirectories__);
export const agentFiles = new Map<string, string>(__agentFiles__);
const cachedSourceFiles = new Map<string, ts.SourceFile>();
declare const __agentDirectories__: string[];
declare const __agentFiles__: [string, string][];
const pendingDiagnostics: ts.Diagnostic[] = [];
const fileWatchers = new Map<WatcherId, WatcherCallback>();
let nextWatcherId: WatcherId = 1;
populateSourceFileCache();
function populateSourceFileCache() {
const config = makeDefaultCompilerOptions();
for (const [name, contents] of agentFiles) {
if (name.endsWith(".d.ts")) {
const sf = ts.createSourceFile(name, contents, config.target!);
ts.prebindSourceFile(sf, config);
cachedSourceFiles.set(name, sf);
}
}
}
export function init(): void {
function onChange(message: WatchChangeMessage): void {
const callback = fileWatchers.get(message.id);
callback?.(fileWatcherEventKindFromFileState(message.state));
recv("watch:change", onChange);
}
recv("watch:change", onChange);
const origCreateCompilerHostFromProgramHost = (ts as any).createCompilerHostFromProgramHost;
(ts as any).createCompilerHostFromProgramHost = (...args: any[]): ts.CompilerHost => {
const host = origCreateCompilerHostFromProgramHost(...args);
patchCompilerHost(host);
return host;
};
}
export function build(projectRoot: string, entrypoint: string, sourceMaps: backend.SourceMaps, compression: backend.Compression): string {
const system = new FridaSystem(projectRoot);
const assets = _queryDefaultAssets(projectRoot, system);
try {
return _build({
projectRoot,
entrypoint,
assets,
system,
sourceMaps,
compression,
onDiagnostic,
onCompilerHostCreated: patchCompilerHost,
});
} finally {
flushDiagnostics();
}
}
export function watch(projectRoot: string, entrypoint: string, sourceMaps: backend.SourceMaps, compression: backend.Compression): void {
const system = new FridaSystem(projectRoot);
const assets = _queryDefaultAssets(projectRoot, system);
_watch({
projectRoot,
entrypoint,
assets,
system,
sourceMaps,
compression,
onDiagnostic,
})
.on("compilationStarting", () => {
send(["watch:compilation-starting"]);
})
.on("compilationFinished", () => {
send(["watch:compilation-finished"]);
})
.on("bundleUpdated", bundle => {
send(["watch:bundle-updated", bundle]);
});
}
function patchCompilerHost(host: ts.CompilerHost) {
const origGetSourceFile = host.getSourceFile;
host.getSourceFile = (fileName, ...args) => {
const compilerPath = nativePathToCompilerPath(fileName);
if (compilerPath !== null) {
const sf = cachedSourceFiles.get(compilerPath);
if (sf !== undefined) {
return sf;
}
} else {
const startPos = fileName.indexOf("/node_modules/@types/");
if (startPos !== -1) {
const builtinsPath = fileName.substring(startPos);
const sf = cachedSourceFiles.get(builtinsPath);
if (sf !== undefined) {
let allowCache = true;
if (builtinsPath.startsWith("/node_modules/@types/frida-gum/")) {
try {
const hashOnDisk = Checksum.compute("sha256", File.readAllText(fileName));
const hashInCache = Checksum.compute("sha256", agentFiles.get(sf.fileName)!);
allowCache = hashOnDisk === hashInCache;
} catch (e) {
}
}
if (allowCache) {
return sf;
}
}
}
}
return origGetSourceFile(fileName, ...args);
};
}
export { _build, _watch, _queryDefaultAssets };
type DiagnosticFile = [path: string, line: number, character: number];
function onDiagnostic(diagnostic: ts.Diagnostic): void {
pendingDiagnostics.push(diagnostic);
if (pendingDiagnostics.length === 1) {
Script.nextTick(flushDiagnostics);
}
}
function flushDiagnostics(): void {
const pending = pendingDiagnostics.splice(0, pendingDiagnostics.length);
if (pending.length === 0) {
return;
}
send([
"diagnostics",
pending.map(({
category,
code,
file: tsFile,
start,
messageText
}) => {
let file: DiagnosticFile | null = null;
if (tsFile !== undefined) {
const { line, character } = ts.getLineAndCharacterOfPosition(tsFile, start!);
file = [tsFile.fileName, line, character];
}
return [
diagnosticCategoryToString(category),
code,
file,
ts.flattenDiagnosticMessageText(messageText, "\n")
];
}),
]);
}
function diagnosticCategoryToString(category: ts.DiagnosticCategory): string {
switch (category) {
case DiagnosticCategory.Warning:
return "warning";
case DiagnosticCategory.Error:
return "error";
case DiagnosticCategory.Suggestion:
return "suggestion";
case DiagnosticCategory.Message:
return "message";
}
}
class FridaSystem implements ts.System {
args = [];
newLine = "\n";
useCaseSensitiveFileNames = true;
#projectRoot: string;
#projectNodeModules: string;
constructor(projectRoot: string) {
this.#projectRoot = crosspath.ensurePosix(projectRoot);
this.#projectNodeModules = crosspath.join(this.#projectRoot, "node_modules");
}
write(s: string): void {
}
writeOutputIsTTY(): boolean {
return true;
}
readFile(path: string, encoding?: string): string | undefined {
let result: string | undefined;
if (path.startsWith(this.#projectRoot)) {
try {
result = File.readAllText(path);
} catch (e) {
}
}
if (result === undefined) {
const agentZipPath = this.#nativePathToAgentZipPath(path);
if (agentZipPath !== null) {
result = agentFiles.get(agentZipPath);
}
}
return result;
}
getFileSize(path: string): number {
throw new Error("not implemented");
}
writeFile(path: string, data: string, writeByteOrderMark?: boolean): void {
File.writeAllText(path, data);
}
watchFile(path: string, callback: ts.FileWatcherCallback, pollingInterval?: number, options?: ts.WatchOptions): ts.FileWatcher {
if (path.startsWith(compilerRoot)) {
return makeDummyWatcher();
}
return makeFileWatcher(path, "file", pollingInterval ?? 0, kind => {
callback(path, kind);
});
}
watchDirectory(path: string, callback: ts.DirectoryWatcherCallback, recursive?: boolean, options?: ts.WatchOptions): ts.FileWatcher {
if (path.startsWith(compilerRoot)) {
return makeDummyWatcher();
}
return makeFileWatcher(path, "directory", 0, kind => {
callback(path);
});
}
resolvePath(path: string): string {
return path;
}
fileExists(path: string): boolean {
if (path.startsWith(this.#projectRoot)) {
try {
const st = fs.statSync(path);
return !st.isDirectory();
} catch (e) {
}
}
const agentZipPath = this.#nativePathToAgentZipPath(path);
if (agentZipPath === null) {
return false;
}
return agentFiles.has(agentZipPath);
}
directoryExists(path: string): boolean {
if (path === compilerNodeModules) {
return true;
}
if (path.startsWith(this.#projectRoot)) {
try {
const st = fs.statSync(path);
return st.isDirectory();
} catch (e) {
}
}
const agentZipPath = this.#nativePathToAgentZipPath(path);
if (agentZipPath === null) {
return false;
}
return agentDirectories.has(agentZipPath);
}
createDirectory(path: string): void {
throw new Error("not implemented");
}
getExecutingFilePath(): string {
return [compilerRoot, "ext", "typescript.js"].join("/");
}
getCurrentDirectory(): string {
return this.#projectRoot;
}
getDirectories(path: string): string[] {
const result = new Set<string>();
if (path.startsWith(this.#projectRoot)) {
try {
for (const entry of fridaFs.list(path).filter(entry => entry.type === S_IFDIR)) {
result.add(entry.name);
}
} catch (e) {
}
}
const agentZipPath = this.#nativePathToAgentZipPath(path);
if (agentZipPath !== null) {
for (const dir of agentDirectories) {
const slashIndex = dir.lastIndexOf("/");
const parent = dir.substring(0, slashIndex);
if (parent === agentZipPath) {
const basename = dir.substring(slashIndex + 1);
result.add(basename);
}
}
}
return Array.from(result);
}
readDirectory(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[] {
return [];
}
getModifiedTime(path: string): Date | undefined {
return undefined;
}
setModifiedTime(path: string, time: Date): void {
}
deleteFile(path: string): void {
}
createHash(data: string): string {
return this.createSHA256Hash(data);
}
createSHA256Hash(data: string): string {
return Checksum.compute("sha256", data);
}
getMemoryUsage(): number {
return Frida.heapSize;
}
exit(exitCode?: number): void {
}
realpath(path: string): string {
return path;
}
getEnvironmentVariable(name: string): string {
return "";
}
setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): any {
return setTimeout(callback);
}
clearTimeout(timeoutId: any): void {
return clearTimeout(timeoutId);
}
clearScreen(): void {
}
base64decode(input: string): string {
throw new Error("not implemented");
}
base64encode(input: string): string {
throw new Error("not implemented");
}
#nativePathToAgentZipPath(path: string): string | null {
const compilerPath = nativePathToCompilerPath(path);
if (compilerPath !== null) {
return compilerPath;
}
if (path.startsWith(this.#projectNodeModules)) {
return "/node_modules" + path.substring(this.#projectNodeModules.length);
}
return null;
}
}
function nativePathToCompilerPath(path: string): string | null {
if (!path.startsWith(compilerRoot)) {
return null;
}
const subPath = path.substring(compilerRoot.length);
if (subPath.startsWith("/node_modules")) {
return subPath;
}
return "/node_modules/frida-compile" + subPath;
}
type WatcherId = number;
type WatcherCallback = (eventKind: ts.FileWatcherEventKind) => void;
type FileState = "pristine" | "modified" | "deleted";
interface WatchChangeMessage {
id: WatcherId;
state: FileState;
}
function makeFileWatcher(path: string, type: "file" | "directory", pollingInterval: number, callback: WatcherCallback): ts.FileWatcher {
if (nextWatcherId === 0xffffffff) {
nextWatcherId = 1;
}
let id: WatcherId = nextWatcherId++;
while (fileWatchers.has(id)) {
id = nextWatcherId++;
}
fileWatchers.set(id, callback);
send(["watch:add", id, path, type, pollingInterval ?? 0]);
return {
close() {
send(["watch:remove", id]);
fileWatchers.delete(id);
}
};
}
function makeDummyWatcher(): ts.FileWatcher {
return {
close() {
}
};
}
function fileWatcherEventKindFromFileState(state: FileState): ts.FileWatcherEventKind {
switch (state) {
case "pristine": return FileWatcherEventKind.Created;
case "modified": return FileWatcherEventKind.Changed;
case "deleted": return FileWatcherEventKind.Deleted;
}
}
-5
View File
@@ -1,5 +0,0 @@
const { init, build, watch } = FridaCompilerAgentCore;
init();
rpc.exports = { build, watch };
-222
View File
@@ -1,222 +0,0 @@
const {
compilerRoot,
compilerNodeModules,
agentDirectories,
agentFiles,
_build,
_queryDefaultAssets,
} = FridaCompilerAgentCore;
const projectRoot = '/agent';
const projectNodeModules = '/agent/node_modules';
const entrypoint = 'index.ts';
const sourceMaps = 'included';
const compression = 'none';
const hashes = new Map();
let nextHashId = 1;
function main() {
const system = new StubSystem();
const assets = _queryDefaultAssets(projectRoot, system);
_build({
projectRoot,
entrypoint,
assets,
system,
sourceMaps,
compression,
onDiagnostic,
});
}
function onDiagnostic(diagnostic) {
throwNotImplemented('diagnostic', ts.flattenDiagnosticMessageText(diagnostic, '\n'));
}
class StubSystem {
args = [];
newLine = '\n';
useCaseSensitiveFileNames = true;
write(s) {
}
writeOutputIsTTY() {
return true;
}
readFile(path, encoding) {
if (path === '/agent/tsconfig.json')
return '{}';
if (path === '/agent/index.ts')
return 'Interceptor.attach(ptr(1234), { onEnter(args) {} });'
const agentZipPath = this.#nativePathToAgentZipPath(path);
if (agentZipPath !== null) {
return agentFiles.get(agentZipPath);
}
throwNotImplemented('readFile', path);
}
getFileSize(path) {
throwNotImplemented('getFileSize');
}
writeFile(path, data, writeByteOrderMark) {
throwNotImplemented('writeFile');
}
watchFile(path, callback, pollingInterval, options) {
throwNotImplemented('watchFile');
}
watchDirectory(path, callback, recursive, options) {
throwNotImplemented('watchDirectory');
}
resolvePath(path) {
throwNotImplemented('resolvePath');
}
fileExists(path) {
if (path === '/package.json' || path === '/agent/package.json')
return false;
const agentZipPath = this.#nativePathToAgentZipPath(path);
if (agentZipPath !== null)
return agentFiles.has(agentZipPath);
throwNotImplemented('fileExists', path);
}
directoryExists(path) {
if (path === '/' || path === projectRoot || path === compilerNodeModules)
return true;
const agentZipPath = this.#nativePathToAgentZipPath(path);
if (agentZipPath !== null)
return agentDirectories.has(agentZipPath);
if (path === '/node_modules/@types' || path === '/node_modules')
return false;
throwNotImplemented('directoryExists', path);
}
createDirectory(path) {
throwNotImplemented('createDirectory');
}
getExecutingFilePath() {
return [compilerRoot, 'ext', 'typescript.js'].join('/');
}
getCurrentDirectory() {
return '/';
}
getDirectories(path) {
const agentZipPath = this.#nativePathToAgentZipPath(path);
if (agentZipPath !== null) {
const result = [];
for (const dir of agentDirectories) {
const slashIndex = dir.lastIndexOf('/');
const parent = dir.substring(0, slashIndex);
if (parent === agentZipPath) {
const basename = dir.substring(slashIndex + 1);
result.push(basename);
}
}
return result;
}
throwNotImplemented('getDirectories', path);
}
readDirectory(path, extensions, exclude, include, depth) {
if (!extensions.includes('.ts'))
throwNotImplemented('readDirectory', path, extensions);
return ['index.ts'];
}
getModifiedTime(path) {
}
setModifiedTime(path, time) {
}
deleteFile(path) {
}
createHash(data) {
let hash = hashes.get(data);
if (hash === undefined) {
hash = 'hash' + nextHashId++;
hashes.set(data, hash);
}
return hash;
}
createSHA256Hash(data) {
throwNotImplemented('createSHA256Hash');
}
getMemoryUsage() {
throwNotImplemented('getMemoryUsage');
}
exit(exitCode) {
}
realpath(path) {
return path;
}
getEnvironmentVariable(name) {
return '';
}
setTimeout(callback, ms, ...args) {
throwNotImplemented('setTimeout');
}
clearTimeout(timeoutId) {
throwNotImplemented('clearTimeout');
}
clearScreen() {
}
base64decode(input) {
throwNotImplemented('base64decode');
}
base64encode(input) {
throwNotImplemented('base64encode');
}
#nativePathToAgentZipPath(path) {
if (path.startsWith(compilerRoot)) {
const subPath = path.substring(compilerRoot.length);
if (subPath.startsWith('/node_modules')) {
return subPath;
}
return '/node_modules/frida-compile' + subPath;
}
if (path.startsWith(projectNodeModules)) {
return '/node_modules' + path.substring(projectNodeModules.length);
}
return null;
}
}
function throwNotImplemented(operation, ...details) {
throw new Error('not implemented: ' + operation + ((details.length > 0) ? ` (${details.join(' ')})` : ''));
}
main();
+28
View File
@@ -0,0 +1,28 @@
#ifdef _MSC_VER
#include <glib.h>
#ifdef HAVE_ARM64
# define FRIDA_CGO_INIT_FUNC _st0_arm64_windows_lib
#elif GLIB_SIZEOF_VOID_P == 8
# define FRIDA_CGO_INIT_FUNC _st0_amd64_windows_lib
#else
# define FRIDA_CGO_INIT_FUNC st0_386_windows_lib
#endif
extern void FRIDA_CGO_INIT_FUNC ();
void
_frida_compiler_backend_init_go_runtime (void)
{
FRIDA_CGO_INIT_FUNC ();
}
#else
void
_frida_compiler_backend_init_go_runtime (void)
{
}
#endif
+816
View File
@@ -0,0 +1,816 @@
package main
/*
#include <stdint.h>
typedef enum {
FRIDA_OUTPUT_UNESCAPED,
FRIDA_OUTPUT_HEX_BYTES,
FRIDA_OUTPUT_C_STRING,
} FridaOutputFormat;
typedef enum {
FRIDA_BUNDLE_ESM,
FRIDA_BUNDLE_IIFE,
} FridaBundleFormat;
typedef void (* FridaBuildCompleteFunc) (char * bundle, char * error_message, void * user_data);
typedef void (* FridaWatchReadyFunc) (uintptr_t session_handle, char * error_message, void * user_data);
typedef void (* FridaStartingFunc) (void * user_data);
typedef void (* FridaFinishedFunc) (void * user_data);
typedef void (* FridaOutputFunc) (char * bundle, void * user_data);
typedef void (* FridaDiagnosticFunc) (char * category, int code, char * path, int line, int character, char * text,
void * user_data);
typedef void (* FridaDestroyFunc) (void * user_data);
static inline void
invoke_build_complete_func (FridaBuildCompleteFunc fn,
char * bundle,
char * error_message,
void * user_data)
{
fn (bundle, error_message, user_data);
}
static inline void
invoke_watch_ready_func (FridaWatchReadyFunc fn,
uintptr_t session_handle,
char * error_message,
void * user_data)
{
fn (session_handle, error_message, user_data);
}
static inline void
invoke_starting_func (FridaStartingFunc fn,
void * user_data)
{
fn (user_data);
}
static inline void
invoke_finished_func (FridaFinishedFunc fn,
void * user_data)
{
fn (user_data);
}
static inline void
invoke_output_func (FridaOutputFunc fn,
char * bundle,
void * user_data)
{
fn (bundle, user_data);
}
static inline void
invoke_diagnostic_func (FridaDiagnosticFunc fn,
char * category,
int code,
char * path,
int line,
int character,
char * text,
void * user_data)
{
fn (category, code, path, line, character, text, user_data);
}
static inline void
invoke_destroy_func (FridaDestroyFunc fn,
void * user_data)
{
fn (user_data);
}
*/
import "C"
import (
"fmt"
"path"
"path/filepath"
"runtime/cgo"
"strings"
"sync"
"unsafe"
esbuild "github.com/evanw/esbuild/pkg/api"
tsscanner "github.com/frida/typescript-go/pkg/scanner"
)
type BuildOptions struct {
ProjectRoot string
Entrypoint string
OutputFormat OutputFormat
BundleFormat BundleFormat
DisableTypeCheck bool
SourceMap bool
Compress bool
}
type OutputFormat C.FridaOutputFormat
const (
OutputFormatUnescaped OutputFormat = OutputFormat(C.FRIDA_OUTPUT_UNESCAPED)
OutputFormatHexBytes OutputFormat = OutputFormat(C.FRIDA_OUTPUT_HEX_BYTES)
OutputFormatCString OutputFormat = OutputFormat(C.FRIDA_OUTPUT_C_STRING)
)
type BundleFormat C.FridaBundleFormat
const (
BundleFormatESM BundleFormat = BundleFormat(C.FRIDA_BUNDLE_ESM)
BundleFormatIIFE BundleFormat = BundleFormat(C.FRIDA_BUNDLE_IIFE)
)
type Diagnostic struct {
category string
code int
path string
line, character int
text string
}
type BuildEventCallbacks struct {
OnStart BuildStartCallback
OnEnd BuildEndCallback
OnOutput BuildOutputCallback
OnDiagnostic BuildDiagnosticCallback
OnConfigChange ConfigChangeCallback
}
type BuildStartCallback func()
type BuildEndCallback func()
type BuildOutputCallback func(bundle string)
type BuildDiagnosticCallback func(d Diagnostic)
//export _frida_compiler_backend_build
func _frida_compiler_backend_build(cProjectRoot, cEntrypoint *C.char, outputFormat C.FridaOutputFormat, bundleFormat C.FridaBundleFormat,
disableTypeCheck, sourceMap, compress uintptr,
onCompleteFn C.FridaBuildCompleteFunc, onCompleteData unsafe.Pointer, onCompleteDataDestroy C.FridaDestroyFunc,
onDiagnosticFn C.FridaDiagnosticFunc, onDiagnosticData unsafe.Pointer) {
options := BuildOptions{
ProjectRoot: C.GoString(cProjectRoot),
Entrypoint: C.GoString(cEntrypoint),
OutputFormat: OutputFormat(outputFormat),
BundleFormat: BundleFormat(bundleFormat),
DisableTypeCheck: disableTypeCheck != 0,
SourceMap: sourceMap != 0,
Compress: compress != 0,
}
onComplete := NewCDelegate(onCompleteFn, onCompleteData, onCompleteDataDestroy)
onDiagnostic := NewCDelegate(onDiagnosticFn, onDiagnosticData, nil)
go func() {
defer onComplete.Dispose()
defer onDiagnostic.Dispose()
onDiagnostic := makeCBuildDiagnosticCallback(onDiagnostic)
bundle, err := build(options, onDiagnostic)
var cBundle, cErrorMessage *C.char
if err == nil {
cBundle = C.CString(bundle)
} else {
cErrorMessage = C.CString(err.Error())
}
C.invoke_build_complete_func(onComplete.Func, cBundle, cErrorMessage, onComplete.Data)
}()
}
//export _frida_compiler_backend_watch
func _frida_compiler_backend_watch(cProjectRoot, cEntrypoint *C.char, outputFormat C.FridaOutputFormat, bundleFormat C.FridaBundleFormat,
disableTypeCheck, sourceMap, compress uintptr,
onReadyFn C.FridaWatchReadyFunc, onReadyData unsafe.Pointer, onReadyDataDestroy C.FridaDestroyFunc,
onStartingFn C.FridaStartingFunc, onStartingData unsafe.Pointer,
onFinishedFn C.FridaFinishedFunc, onFinishedData unsafe.Pointer,
onOutputFn C.FridaOutputFunc, onOutputData unsafe.Pointer,
onDiagnosticFn C.FridaDiagnosticFunc, onDiagnosticData unsafe.Pointer) {
options := BuildOptions{
ProjectRoot: C.GoString(cProjectRoot),
Entrypoint: C.GoString(cEntrypoint),
OutputFormat: OutputFormat(outputFormat),
BundleFormat: BundleFormat(bundleFormat),
DisableTypeCheck: disableTypeCheck != 0,
SourceMap: sourceMap != 0,
Compress: compress != 0,
}
onReady := NewCDelegate(onReadyFn, onReadyData, onReadyDataDestroy)
onStarting := NewCDelegate(onStartingFn, onStartingData, nil)
onFinished := NewCDelegate(onFinishedFn, onFinishedData, nil)
onOutput := NewCDelegate(onOutputFn, onOutputData, nil)
onDiagnostic := NewCDelegate(onDiagnosticFn, onDiagnosticData, nil)
go func() {
defer onReady.Dispose()
onDispose := func() {
onStarting.Dispose()
onFinished.Dispose()
onOutput.Dispose()
onDiagnostic.Dispose()
}
callbacks := BuildEventCallbacks{
OnStart: func() {
C.invoke_starting_func(onStarting.Func, onStarting.Data)
},
OnEnd: func() {
C.invoke_starting_func(onFinished.Func, onFinished.Data)
},
OnOutput: func(bundle string) {
C.invoke_output_func(onOutput.Func, C.CString(bundle), onOutput.Data)
},
OnDiagnostic: makeCBuildDiagnosticCallback(onDiagnostic),
}
session, err := NewWatchSession(options, onDispose, callbacks)
var cSession C.uintptr_t
var cErrorMessage *C.char
if err == nil {
cSession = C.uintptr_t(cgo.NewHandle(session))
} else {
cErrorMessage = C.CString(err.Error())
}
C.invoke_watch_ready_func(onReady.Func, cSession, cErrorMessage, onReady.Data)
}()
}
//export _frida_compiler_backend_watch_session_dispose
func _frida_compiler_backend_watch_session_dispose(h uintptr) {
handle := cgo.Handle(h)
session := handle.Value().(*WatchSession)
session.Dispose()
handle.Delete()
}
func makeCBuildDiagnosticCallback(onDiagnostic *CDelegate[C.FridaDiagnosticFunc]) BuildDiagnosticCallback {
return func(d Diagnostic) {
var cPath *C.char
if d.path != "" {
cPath = C.CString(d.path)
}
C.invoke_diagnostic_func(onDiagnostic.Func, C.CString(d.category), C.int(d.code), cPath, C.int(d.line),
C.int(d.character), C.CString(d.text), onDiagnostic.Data)
}
}
func build(options BuildOptions, onDiagnostic BuildDiagnosticCallback) (bundle string, err error) {
callbacks := BuildEventCallbacks{
OnOutput: func(b string) {
bundle = b
},
OnDiagnostic: onDiagnostic,
}
ctx, err := makeContext(options, callbacks)
if err != nil {
return
}
defer ctx.Dispose()
result := ctx.Rebuild()
if len(result.Errors) != 0 {
err = fmt.Errorf("Compilation failed")
}
return
}
type WatchSession struct {
mu sync.Mutex
options BuildOptions
callbacks BuildEventCallbacks
ctx esbuild.BuildContext
onDispose SessionDisposeHandler
}
type SessionDisposeHandler func()
func NewWatchSession(opts BuildOptions, onDispose SessionDisposeHandler, callbacks BuildEventCallbacks) (session *WatchSession, err error) {
cbs := BuildEventCallbacks{
OnStart: callbacks.OnStart,
OnEnd: callbacks.OnEnd,
OnOutput: callbacks.OnOutput,
OnDiagnostic: callbacks.OnDiagnostic,
OnConfigChange: func() {
if callbacks.OnConfigChange != nil {
callbacks.OnConfigChange()
}
session.onConfigChange()
},
}
ctx, err := makeContext(opts, cbs)
if err != nil {
return
}
ctx.Watch(esbuild.WatchOptions{})
session = &WatchSession{
options: opts,
callbacks: cbs,
ctx: ctx,
onDispose: onDispose,
}
return
}
func (s *WatchSession) Dispose() {
s.mu.Lock()
defer s.mu.Unlock()
if s.ctx != nil {
s.ctx.Dispose()
s.ctx = nil
}
s.onDispose()
}
func (s *WatchSession) onConfigChange() {
go func() {
s.mu.Lock()
defer s.mu.Unlock()
if s.ctx != nil {
s.ctx.Dispose()
s.ctx = nil
}
ctx, err := makeContext(s.options, s.callbacks)
if err != nil {
return
}
s.ctx = ctx
ctx.Watch(esbuild.WatchOptions{})
}()
}
func makeContext(options BuildOptions, callbacks BuildEventCallbacks) (ctx esbuild.BuildContext, err error) {
var e error
var projectRoot string
if projectRoot, e = filepath.EvalSymlinks(options.ProjectRoot); e != nil {
err = fmt.Errorf("Failed to resolve project root: %w", e)
return
}
var entrypoint string
if filepath.IsAbs(options.Entrypoint) {
entrypoint = options.Entrypoint
} else {
entrypoint = filepath.Join(projectRoot, options.Entrypoint)
}
if entrypoint, e = filepath.EvalSymlinks(entrypoint); e != nil {
err = fmt.Errorf("Failed to resolve entrypoint: %w", e)
return
}
rel, e := filepath.Rel(projectRoot, entrypoint)
if e != nil {
err = fmt.Errorf("Could not compute entrypoint path relative to project root: %w", e)
return
}
if strings.HasPrefix(rel, "..") {
err = fmt.Errorf("Entrypoint must be inside the project root")
return
}
isTS := strings.HasSuffix(entrypoint, ".ts")
var tsconfigCache *TSConfigCache
var tsconfigText string
var tsCompiler *TSCompiler
if isTS {
tsconfigCache = NewTSConfigCache(projectRoot, options.SourceMap, callbacks.OnConfigChange)
tsCompiler = NewTSCompiler(projectRoot, entrypoint, tsconfigCache.GetCompilerOptions)
_, tsconfigText, err = tsconfigCache.GetCompilerOptions(tsCompiler)
if err != nil {
err = fmt.Errorf("Failed to load tsconfig options: %w", err)
return
}
}
sourcemapOption := esbuild.SourceMapNone
if options.SourceMap {
if options.BundleFormat == BundleFormatESM {
sourcemapOption = esbuild.SourceMapExternal
} else {
sourcemapOption = esbuild.SourceMapInline
}
}
minifyWhitespace := false
minifyIdentifiers := false
minifySyntax := false
if options.Compress {
minifyWhitespace = true
minifyIdentifiers = true
minifySyntax = true
}
var format esbuild.Format
if options.BundleFormat == BundleFormatESM {
format = esbuild.FormatESModule
} else {
format = esbuild.FormatIIFE
}
plugins := []esbuild.Plugin{
makeBuildObserverPlugin(projectRoot, entrypoint, options, callbacks),
}
if isTS && !options.DisableTypeCheck {
plugins = append(plugins, makeTypeScriptPlugin(tsCompiler))
}
plugins = append(plugins, makeFridaShimsPlugin())
buildOpts := esbuild.BuildOptions{
Sourcemap: sourcemapOption,
SourcesContent: esbuild.SourcesContentExclude,
Target: esbuild.ES2022,
MinifyWhitespace: minifyWhitespace,
MinifyIdentifiers: minifyIdentifiers,
MinifySyntax: minifySyntax,
LegalComments: esbuild.LegalCommentsNone,
Bundle: true,
Outdir: projectRoot,
AbsWorkingDir: projectRoot,
Platform: esbuild.PlatformNode,
Format: format,
Inject: []string{"frida-builtins:///node-globals.js"},
EntryPoints: []string{entrypoint},
Write: false,
Plugins: plugins,
}
if isTS {
buildOpts.TsconfigRaw = tsconfigText
}
if buildCtx, ctxErr := esbuild.Context(buildOpts); ctxErr == nil {
ctx = buildCtx
} else {
for _, e := range ctxErr.Errors {
emitDiagnostic("error", e, callbacks.OnDiagnostic)
}
err = fmt.Errorf("Failed to create ESBuild context")
}
return
}
func emitDiagnostic(category string, message esbuild.Message, onDiagnostic BuildDiagnosticCallback) {
d := Diagnostic{
category: category,
code: -1,
text: message.Text,
}
l := message.Location
if l != nil {
d.path = l.File
d.line = l.Line
d.character = l.Column
}
if message.PluginName == "frida-custom-ts" && len(message.Notes) == 2 {
d.category = message.Notes[0].Text
fmt.Sscan(message.Notes[1].Text, &d.code)
}
onDiagnostic(d)
}
func changeToJS(p string) string {
ext := path.Ext(p)
base := p[:len(p)-len(ext)]
return base + ".js"
}
func makeBuildObserverPlugin(projectRoot, entrypoint string, options BuildOptions, callbacks BuildEventCallbacks) esbuild.Plugin {
return esbuild.Plugin{
Name: "frida-build-observer",
Setup: func(build esbuild.PluginBuild) {
if callbacks.OnStart != nil {
build.OnStart(func() (esbuild.OnStartResult, error) {
callbacks.OnStart()
return esbuild.OnStartResult{}, nil
})
}
build.OnEnd(func(result *esbuild.BuildResult) (esbuild.OnEndResult, error) {
if len(result.Errors) == 0 {
var output string
if options.BundleFormat == BundleFormatESM {
output = makeESMBundle(result.OutputFiles, projectRoot, entrypoint)
} else {
output = string(result.OutputFiles[0].Contents)
}
switch options.OutputFormat {
case OutputFormatHexBytes:
output = encodeStringToHexBytes(output)
case OutputFormatCString:
output = encodeStringToCString(output)
}
callbacks.OnOutput(output)
} else {
for _, e := range result.Errors {
emitDiagnostic("error", e, callbacks.OnDiagnostic)
}
for _, e := range result.Warnings {
emitDiagnostic("warning", e, callbacks.OnDiagnostic)
}
}
if callbacks.OnEnd != nil {
callbacks.OnEnd()
}
return esbuild.OnEndResult{}, nil
})
},
}
}
func makeESMBundle(files []esbuild.OutputFile, projectRoot, entrypoint string) string {
entrypointJS, entrypointMap := outputForEntrypoint(projectRoot, entrypoint)
relEntryp, err := filepath.Rel(projectRoot, entrypoint)
if err != nil {
panic(fmt.Sprintf("Cannot compute entrypoint relative path: %v", err))
}
entrySubDir := filepath.Dir(relEntryp)
entryIndexJS := -1
entryIndexMap := -1
for i, of := range files {
if of.Path == entrypointJS {
entryIndexJS = i
}
if of.Path == entrypointMap {
entryIndexMap = i
}
}
if entryIndexJS < 0 {
panic(fmt.Sprintf("Entrypoint JS %q not found in files", entrypointJS))
}
orderedFiles := make([]esbuild.OutputFile, 0, len(files))
orderedFiles = append(orderedFiles, files[entryIndexJS])
if entryIndexMap >= 0 {
orderedFiles = append(orderedFiles, files[entryIndexMap])
}
for i, of := range files {
if i == entryIndexJS || i == entryIndexMap {
continue
}
orderedFiles = append(orderedFiles, of)
}
var sb strings.Builder
sb.WriteString("📦\n")
for _, of := range orderedFiles {
size := len(of.Contents)
relPath, _ := filepath.Rel(projectRoot, of.Path)
withSub := filepath.Join(entrySubDir, relPath)
sb.WriteString(fmt.Sprintf("%d /%s\n", size, filepath.ToSlash(withSub)))
}
sb.WriteString("✄\n")
for i, of := range orderedFiles {
sb.Write(of.Contents)
if i < len(orderedFiles)-1 {
sb.WriteString("\n✄\n")
}
}
return sb.String()
}
func outputForEntrypoint(projectRoot, entrypoint string) (jsOut, mapOut string) {
jsOut = filepath.Join(projectRoot, changeToJS(filepath.Base(entrypoint)))
mapOut = jsOut + ".map"
return
}
func encodeStringToHexBytes(s string) string {
n := len(s)
if n == 0 {
return ""
}
totalLen := n*4 + (n-1)*2 + 1
buf := make([]byte, 0, totalLen)
hexDigits := "0123456789abcdef"
for i := 0; i < n; i++ {
b := s[i]
buf = append(buf, '0', 'x')
buf = append(buf,
hexDigits[b>>4],
hexDigits[b&0xF],
)
if i < n-1 {
if (i+1)%12 == 0 {
buf = append(buf, ',', '\n')
} else {
buf = append(buf, ',', ' ')
}
}
}
buf = append(buf, '\n')
return string(buf)
}
func encodeStringToCString(s string) string {
n := len(s)
if n == 0 {
return `""`
}
hexDigits := "0123456789abcdef"
var bldr strings.Builder
openLiteral := func() {
bldr.WriteByte('"')
}
closeLiteral := func() {
bldr.WriteByte('"')
}
inLiteral := false
for i := 0; i < n; i++ {
c := s[i]
if !inLiteral {
openLiteral()
inLiteral = true
}
if c == '\n' {
bldr.WriteByte('\\')
bldr.WriteByte('n')
closeLiteral()
inLiteral = false
if i < n-1 {
bldr.WriteByte('\n')
openLiteral()
inLiteral = true
}
continue
}
switch c {
case '"':
bldr.WriteByte('\\')
bldr.WriteByte('"')
case '\\':
bldr.WriteByte('\\')
bldr.WriteByte('\\')
case '\a':
bldr.WriteByte('\\')
bldr.WriteByte('a')
case '\b':
bldr.WriteByte('\\')
bldr.WriteByte('b')
case '\t':
bldr.WriteByte('\\')
bldr.WriteByte('t')
case '\v':
bldr.WriteByte('\\')
bldr.WriteByte('v')
case '\f':
bldr.WriteByte('\\')
bldr.WriteByte('f')
case '\r':
bldr.WriteByte('\\')
bldr.WriteByte('r')
default:
isPrintableExceptQuoteAndBackslash := c >= 0x20 && c <= 0x7E
if isPrintableExceptQuoteAndBackslash {
bldr.WriteByte(c)
} else {
bldr.WriteByte('\\')
bldr.WriteByte('x')
bldr.WriteByte(hexDigits[c>>4])
bldr.WriteByte(hexDigits[c&0xF])
}
}
}
if inLiteral {
closeLiteral()
}
bldr.WriteByte('\n')
return bldr.String()
}
func makeTypeScriptPlugin(compiler *TSCompiler) esbuild.Plugin {
return esbuild.Plugin{
Name: "frida-custom-ts",
Setup: func(build esbuild.PluginBuild) {
build.OnStart(func() (esbuild.OnStartResult, error) {
compiler.EnsureProgramUpToDate()
return esbuild.OnStartResult{}, nil
})
build.OnEnd(func(result *esbuild.BuildResult) (esbuild.OnEndResult, error) {
if len(result.Errors) == 0 {
compiler.CommitPendingInputs()
} else {
compiler.DropPendingInputs()
}
return esbuild.OnEndResult{}, nil
})
build.OnLoad(esbuild.OnLoadOptions{Filter: "\\.ts$"}, func(args esbuild.OnLoadArgs) (esbuild.OnLoadResult, error) {
compiledJS, tsDiagnostics, err := compiler.Compile(args.Path)
result := esbuild.OnLoadResult{
WatchFiles: compiler.WatchFiles(),
WatchDirs: compiler.WatchDirs(),
}
var esbuildMessages []esbuild.Message
for _, d := range tsDiagnostics {
f := d.File()
pos := d.Pos()
line, column := tsscanner.GetLineAndCharacterOfPosition(f, pos)
esbuildMessages = append(esbuildMessages, esbuild.Message{
Text: d.Message(),
Location: &esbuild.Location{
File: f.FileName(),
Line: line,
Column: column,
Length: d.Len(),
LineText: f.Text()[pos:d.End()],
},
Notes: []esbuild.Note{
{Text: d.Category().Name()},
{Text: fmt.Sprintf("%d", d.Code())},
},
})
}
if err != nil {
mainErr := esbuild.Message{Text: err.Error()}
result.Errors = append([]esbuild.Message{mainErr}, esbuildMessages...)
return result, nil
}
if len(esbuildMessages) > 0 {
result.Errors = esbuildMessages
return result, nil
}
result.Contents = &compiledJS
result.Loader = esbuild.LoaderJS
return result, nil
})
},
}
}
type CDelegate[F any] struct {
Func F
null F
Data unsafe.Pointer
dataDestroy C.FridaDestroyFunc
}
func NewCDelegate[F any](function F, data unsafe.Pointer, dataDestroy C.FridaDestroyFunc) *CDelegate[F] {
return &CDelegate[F]{Func: function, Data: data, dataDestroy: dataDestroy}
}
func (d *CDelegate[F]) Dispose() {
if d.dataDestroy != nil {
C.invoke_destroy_func(d.dataDestroy, d.Data)
}
d.Func = d.null
d.Data = nil
d.dataDestroy = nil
}
func main() {}
+7
View File
@@ -0,0 +1,7 @@
{
global:
_frida_compiler_backend_*;
local:
*;
};
+375
View File
@@ -0,0 +1,375 @@
import base64
import json
import os
import shutil
import struct
import subprocess
import sys
from pathlib import Path
from typing import List
def main(argv):
go_config = json.loads(base64.b64decode(argv[1]).decode("utf-8"))
output_dir, priv_dir, go, npm, *inputs = [Path(d).resolve() for d in argv[2:]]
try:
build_backend(go_config, inputs, output_dir, priv_dir, go, npm)
except subprocess.CalledProcessError as e:
print(e, file=sys.stderr)
print(
"Output:\n\t| " + "\n\t| ".join(e.output.strip().split("\n")),
file=sys.stderr,
)
sys.exit(2)
except Exception as e:
print(e, file=sys.stderr)
sys.exit(1)
def build_backend(
config: dict,
inputs: List[Path],
output_dir: Path,
priv_dir: Path,
go: Path,
npm: Path,
):
base_dir = min(inputs, key=lambda p: len(p.parts)).parent
for f in inputs:
dest = priv_dir / f.relative_to(base_dir)
dest.parent.mkdir(exist_ok=True)
shutil.copy(f, dest)
go_sources = [str(f.relative_to(base_dir)) for f in inputs if f.suffix == ".go"]
def run(*args):
return subprocess.run(
args,
cwd=priv_dir,
env=config["env"],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
encoding="utf-8",
check=True,
)
run(npm, "install")
# run(npm, "link", "/home/oleavr/src/frida-fs")
mode = config["mode"]
backend_stem = "frida-compiler-backend"
if mode == "c-shared":
backend_stem += "-raw"
backend_a = priv_dir / f"{backend_stem}.a"
backend_shlib = priv_dir / (f"{backend_stem}" + config["shlib_suffix"])
backend_h = priv_dir / f"{backend_stem}.h"
extra_go_args = config["extra_go_args"].copy()
if mode == "c-shared":
version_script = priv_dir / "backend.version"
extra_go_args.append(f"-ldflags=-linkmode=external -extldflags=-Wl,--version-script={version_script}")
run(
go,
"build",
f"-buildmode={mode}",
"-o",
backend_a.name if mode == "c-archive" else backend_shlib.name,
"-buildvcs=false",
*extra_go_args,
*go_sources,
)
if mode == "c-archive":
symbols_to_scramble = detect_conflictful_symbols_in_archive(backend_a, config["nm"])
scramble_symbols_in_archive(backend_a, symbols_to_scramble, config["ranlib"])
if (mingw := config.get("mingw")) is not None and (abi := config["abi"]) in {
"x86",
"x86_64",
}:
prefix = Path(mingw["prefix"])
ar = config["ar"]
libmingwex_a = prefix / "lib" / "libmingwex.a"
if not libmingwex_a.exists():
libmingwex_a = prefix / mingw["triplet"] / "lib" / "libmingwex.a"
libgcc_objects = [
"_chkstk_ms.o",
]
run(*ar, "x", mingw["libcc"], *libgcc_objects)
gwex_objflavor = "64" if abi == "x86_64" else "32"
gwex_objects = [
f"lib{gwex_objflavor}_libmingwex_a-{name}.o"
for name in [
"dmisc",
"gdtoa",
"gmisc",
"mingw_fprintf",
"mingw_pformat",
"misc",
]
]
run(*ar, "x", libmingwex_a, *gwex_objects)
extra_objects = []
if abi == "x86_64":
run(*ar, "x", backend_a.name, "go.o")
sort_pdata_in_object(Path(priv_dir) / "go.o")
extra_objects.append("go.o")
run(*ar, "rs", backend_a.name, *libgcc_objects, *gwex_objects, *extra_objects)
shutil.copy(priv_dir / backend_a.name, output_dir / backend_a.name)
else:
shutil.copy(priv_dir / backend_shlib.name, output_dir / backend_shlib.name)
shutil.copy(priv_dir / backend_h.name, output_dir / backend_h.name)
def detect_conflictful_symbols_in_archive(
archive: Path, nm_cmd_array: List[str]
) -> List[str]:
result = []
for line in subprocess.run(
[*nm_cmd_array, str(archive)], capture_output=True, encoding="utf-8", check=True
).stdout.splitlines():
tokens = line.lstrip().split(" ")
if len(tokens) >= 3 and tokens[1] in {"S", "T"}:
symbol = tokens[2]
if all(sub not in symbol for sub in ("/", ".", ":", "frida")):
result.append(symbol)
return result
def scramble_symbols_in_archive(
archive: Path, symbols: List[str], ranlib_cmd_array: List[str]
):
data = archive.read_bytes()
for old_sym in symbols:
new_sym = roll_first_alpha(old_sym)
data = data.replace(old_sym.encode("ascii"), new_sym.encode("ascii"))
archive.write_bytes(data)
subprocess.run([*ranlib_cmd_array, str(archive)], check=True)
def roll_first_alpha(s: str) -> str:
chars = list(s)
for i, c in enumerate(chars):
if c.isalpha():
if c == "z":
chars[i] = "a"
elif c == "Z":
chars[i] = "A"
else:
chars[i] = chr(ord(c) + 1)
break
return "".join(chars)
# Work around the Go toolchain's almost-MSVC-compatible object files
# until our patch is merged upstream:
# https://go-review.googlesource.com/c/go/+/678795
def sort_pdata_in_object(object_file: Path):
data = bytearray(object_file.read_bytes())
# --- Parse COFF File Header (IMAGE_FILE_HEADER) ---
# Format: WORD Machine; WORD NumberOfSections;
# DWORD TimeDateStamp; DWORD PointerToSymbolTable;
# DWORD NumberOfSymbols; WORD SizeOfOptionalHeader;
# WORD Characteristics;
IMAGE_FILE_HEADER_FMT = "<HHLLLHH"
IMAGE_FILE_HEADER_SIZE = struct.calcsize(IMAGE_FILE_HEADER_FMT)
if len(data) < IMAGE_FILE_HEADER_SIZE:
print("Error: File too small to be a valid COFF object", file=sys.stderr)
return
(
machine,
number_of_sections,
time_date_stamp,
pointer_to_symbol_table,
number_of_symbols,
size_of_optional_header,
characteristics,
) = struct.unpack(IMAGE_FILE_HEADER_FMT, data[0:IMAGE_FILE_HEADER_SIZE])
# --- Parse Section Headers to find .pdata ---
# Each IMAGE_SECTION_HEADER is 40 bytes: Name[8], Misc(VirtualSize), VirtualAddress,
# SizeOfRawData, PointerToRawData, PointerToRelocations, PointerToLinenumbers,
# NumberOfRelocations, NumberOfLinenumbers, Characteristics
SECTION_HEADER_FMT = "<8sLLLLLLHHI"
SECTION_HEADER_SIZE = struct.calcsize(SECTION_HEADER_FMT)
section_table_offset = IMAGE_FILE_HEADER_SIZE + size_of_optional_header
pdata_section_index = None
pdata_pointer_to_raw = None
pdata_size_of_raw = None
pdata_pointer_to_relocs = None
pdata_number_of_relocs = None
# Keep all section headers for rewriting relocation entries later if needed
section_headers = []
for i in range(number_of_sections):
offset = section_table_offset + i * SECTION_HEADER_SIZE
section_data = data[offset : offset + SECTION_HEADER_SIZE]
(
name,
virtual_size,
virtual_address,
size_of_raw_data,
pointer_to_raw_data,
pointer_to_relocations,
pointer_to_linenumbers,
number_of_relocations,
number_of_linenumbers,
sec_characteristics,
) = struct.unpack(SECTION_HEADER_FMT, section_data)
section_name = name.rstrip(b"\x00").decode("utf-8")
section_headers.append(
{
"name": section_name,
"offset": offset,
"virtual_size": virtual_size,
"virtual_address": virtual_address,
"size_of_raw_data": size_of_raw_data,
"pointer_to_raw_data": pointer_to_raw_data,
"pointer_to_relocations": pointer_to_relocations,
"number_of_relocations": number_of_relocations,
}
)
if section_name == ".pdata":
pdata_section_index = i
pdata_pointer_to_raw = pointer_to_raw_data
pdata_size_of_raw = size_of_raw_data
pdata_pointer_to_relocs = pointer_to_relocations
pdata_number_of_relocs = number_of_relocations
if pdata_section_index is None:
print("Error: No .pdata section found in the object file", file=sys.stderr)
return
# --- Parse Symbol Table ---
# Each IMAGE_SYMBOL is 18 bytes: Name[8], Value (4 bytes), SectionNumber (2 bytes),
# Type (2 bytes), StorageClass (1 byte), NumberOfAuxSymbols (1 byte)
SYMBOL_TABLE_ENTRY_SIZE = 18
symbols = []
for sym_index in range(number_of_symbols):
sym_offset = pointer_to_symbol_table + sym_index * SYMBOL_TABLE_ENTRY_SIZE
entry = data[sym_offset : sym_offset + SYMBOL_TABLE_ENTRY_SIZE]
if len(entry) < SYMBOL_TABLE_ENTRY_SIZE:
print("Error: Truncated symbol table entry", file=sys.stderr)
return
# Unpack: Name (8s), Value (L), SectionNumber (h), Type (H), StorageClass (B), NumberOfAuxSymbols (B)
name_bytes, value, section_number, sym_type, storage_class, num_aux = (
struct.unpack("<8sLhHBB", entry)
)
# Decode name: if name_bytes[0:4] are zeros, use string from offset in string table
if name_bytes[:4] == b"\x00\x00\x00\x00":
str_table_offset = struct.unpack("<L", name_bytes[4:])[0]
# String table starts immediately after symbol table: size (4 bytes) + NUL-terminated strings
str_tab_start = (
pointer_to_symbol_table + number_of_symbols * SYMBOL_TABLE_ENTRY_SIZE
)
# Fetch the name from string table
str_offset = str_tab_start + str_table_offset
name_end = data.find(b"\x00", str_offset)
symbol_name = data[str_offset:name_end].decode("utf-8")
else:
symbol_name = name_bytes.partition(b"\x00")[0].decode("utf-8")
symbols.append(
{"name": symbol_name, "value": value, "section_number": section_number}
)
# --- Read original .pdata section raw data ---
pdata_data = data[pdata_pointer_to_raw : pdata_pointer_to_raw + pdata_size_of_raw]
if len(pdata_data) % 12 != 0:
print("Error: .pdata size is not a multiple of 12 bytes", file=sys.stderr)
return
num_entries = len(pdata_data) // 12
# --- Read relocation entries for .pdata ---
# Each IMAGE_RELOCATION is 10 bytes: VirtualAddress (4), SymbolTableIndex (4), Type (2)
RELOC_ENTRY_SIZE = 10
reloc_entries = []
reloc_table_start = pdata_pointer_to_relocs
for rindex in range(pdata_number_of_relocs):
reloff = reloc_table_start + rindex * RELOC_ENTRY_SIZE
entry = data[reloff : reloff + RELOC_ENTRY_SIZE]
if len(entry) < RELOC_ENTRY_SIZE:
print("Error: Truncated relocation entry", file=sys.stderr)
return
va, sym_index, rtype = struct.unpack("<LLH", entry)
reloc_entries.append(
{"virtual_address": va, "symbol_index": sym_index, "type": rtype}
)
# There should be 3 relocations per .pdata entry
if len(reloc_entries) != num_entries * 3:
print(
"Warning: Expected {} relocations but found {}".format(
num_entries * 3, len(reloc_entries)
),
file=sys.stderr,
)
# --- Associate each entry with its relocations and sorting key ---
entries = []
for i in range(num_entries):
entry_bytes = pdata_data[i * 12 : (i + 1) * 12]
entry_relocs = reloc_entries[i * 3 : i * 3 + 3]
# Sorting key: use symbol.Value of first relocation"s symbol index
sym_idx = entry_relocs[0]["symbol_index"]
if sym_idx < 0 or sym_idx >= number_of_symbols:
key = 0
else:
key = symbols[sym_idx]["value"]
entries.append({"entry_bytes": entry_bytes, "relocs": entry_relocs, "key": key})
# --- Sort entries by computed key ---
entries.sort(key=lambda x: x["key"])
# --- Build new .pdata data buffer ---
sorted_pdata = bytearray()
for e in entries:
sorted_pdata.extend(e["entry_bytes"])
# --- Build new relocation table buffer ---
new_reloc_buf = bytearray()
for new_i, e in enumerate(entries):
for reloc in e["relocs"]:
field_offset = reloc["virtual_address"] % 12
new_va = new_i * 12 + field_offset
packed = struct.pack("<LLH", new_va, reloc["symbol_index"], reloc["type"])
new_reloc_buf.extend(packed)
# --- Write back sorted .pdata and new relocations into data buffer ---
# Replace .pdata raw data
data[pdata_pointer_to_raw : pdata_pointer_to_raw + pdata_size_of_raw] = sorted_pdata
# Replace relocation entries
data[pdata_pointer_to_relocs : pdata_pointer_to_relocs + len(new_reloc_buf)] = (
new_reloc_buf
)
# --- Emit the fixed object file ---
object_file.write_bytes(data)
if __name__ == "__main__":
main(sys.argv)
@@ -1,3 +1,2 @@
[resource-compiler]
namespace = Frida.Data.Compiler
compress = *.js:text:7; *.bin:generic:7
-3
View File
@@ -1,3 +0,0 @@
[resource-compiler]
namespace = Frida.Data.Compiler
compress = *.js:text:11; *.bin:generic:11
+288 -338
View File
@@ -5,59 +5,52 @@ namespace Frida {
public signal void output (string bundle);
public signal void diagnostics (Variant diagnostics);
public DeviceManager manager {
get;
construct;
private size_t watch_session_handle = 0;
private Gee.Queue<Diagnostic> pending_diagnostics = new Gee.ArrayQueue<Diagnostic> ();
private MainContext main_context;
// TODO: Remove the DeviceManager parameter.
public Compiler (DeviceManager? manager = null) {
Object ();
}
#if HAVE_COMPILER_BACKEND
private Promise<Agent>? load_request;
private Gee.Map<uint, MonitorEntry> monitors = new Gee.HashMap<uint, MonitorEntry> ();
private Gee.Set<MonitorEntry> dirty_monitors = new Gee.HashSet<MonitorEntry> ();
private TimeoutSource? monitor_flush_timer;
private Cancellable io_cancellable = new Cancellable ();
#endif
public Compiler (DeviceManager manager) {
Object (manager: manager);
static construct {
CompilerBackend.init ();
}
#if HAVE_COMPILER_BACKEND
public override void dispose () {
if (load_request != null)
close.begin ();
base.dispose ();
construct {
main_context = Frida.get_main_context ();
}
private async void close () {
try {
var agent = yield get_agent (null);
yield agent.close (null);
} catch (GLib.Error e) {
}
load_request = null;
if (monitor_flush_timer != null) {
monitor_flush_timer.destroy ();
monitor_flush_timer = null;
}
foreach (var entry in monitors.values)
detach_monitor_entry (entry);
monitors.clear ();
~Compiler () {
cancel_watch ();
}
#endif
public async string build (string entrypoint, BuildOptions? options = null, Cancellable? cancellable = null)
throws Error, IOError {
#if HAVE_COMPILER_BACKEND
var agent = yield get_agent (cancellable);
CompilerBackend.check_available ();
BuildOptions opts = (options != null) ? options : new BuildOptions ();
string project_root = compute_project_root (entrypoint, opts);
starting ();
try {
string bundle = yield agent.build (entrypoint, options, cancellable);
string? bundle = null;
string? error_message = null;
CompilerBackend.BuildCompleteFunc on_complete = (b, e) => {
bundle = b;
error_message = e;
schedule_on_frida_thread (build.callback);
};
CompilerBackend.build (project_root, entrypoint, opts.output_format, opts.bundle_format,
(size_t) (opts.type_check == NONE), (size_t) (opts.source_maps == INCLUDED),
(size_t) (opts.compression == TERSER), (owned) on_complete, on_diagnostic);
yield;
if (error_message != null)
throw new Error.INVALID_ARGUMENT ("%s", error_message);
output (bundle);
@@ -65,9 +58,6 @@ namespace Frida {
} finally {
finished ();
}
#else
throw_not_supported ();
#endif
}
public string build_sync (string entrypoint, BuildOptions? options = null, Cancellable? cancellable = null)
@@ -89,13 +79,38 @@ namespace Frida {
public async void watch (string entrypoint, WatchOptions? options = null, Cancellable? cancellable = null)
throws Error, IOError {
#if HAVE_COMPILER_BACKEND
var agent = yield get_agent (cancellable);
CompilerBackend.check_available ();
yield agent.watch (entrypoint, options, cancellable);
#else
throw_not_supported ();
#endif
WatchOptions opts = (options != null) ? options : new WatchOptions ();
string project_root = compute_project_root (entrypoint, opts);
cancel_watch ();
size_t session_handle = 0;
string? error_message = null;
CompilerBackend.WatchReadyFunc on_ready = (h, e) => {
session_handle = h;
error_message = e;
schedule_on_frida_thread (watch.callback);
};
CompilerBackend.watch (project_root, entrypoint, opts.output_format, opts.bundle_format,
(size_t) (opts.type_check == NONE), (size_t) (opts.source_maps == INCLUDED),
(size_t) (opts.compression == TERSER), (owned) on_ready, on_starting, on_finished,
on_output, on_diagnostic);
yield;
if (error_message != null)
throw new Error.INVALID_ARGUMENT ("%s", error_message);
watch_session_handle = session_handle;
}
private void cancel_watch () {
if (watch_session_handle != 0) {
CompilerBackend.WatchSession.dispose (watch_session_handle);
watch_session_handle = 0;
}
}
public void watch_sync (string entrypoint, WatchOptions? options = null, Cancellable? cancellable = null)
@@ -115,343 +130,238 @@ namespace Frida {
}
}
#if HAVE_COMPILER_BACKEND
private void on_watch_add (uint id, string path, string type, int64 polling_interval) {
var file = File.parse_name (path);
private void on_starting () {
schedule_on_frida_thread (() => {
starting ();
return Source.REMOVE;
});
}
GLib.FileMonitor monitor;
try {
if (type == "file")
monitor = file.monitor_file (FileMonitorFlags.SEND_MOVED, io_cancellable);
else if (type == "directory")
monitor = file.monitor_directory (FileMonitorFlags.NONE, io_cancellable);
else
assert_not_reached ();
} catch (GLib.Error e) {
return;
private void on_finished () {
schedule_on_frida_thread (() => {
finished ();
return Source.REMOVE;
});
}
private void on_output (owned string bundle) {
schedule_on_frida_thread (() => {
output (bundle);
return Source.REMOVE;
});
}
private void on_diagnostic (owned string category, int code, owned string? path, int line, int character,
owned string text) {
var diag = new Diagnostic () {
category = category,
code = code,
path = path,
line = line,
character = character,
text = text,
};
bool schedule_emit = false;
lock (pending_diagnostics) {
schedule_emit = pending_diagnostics.is_empty;
pending_diagnostics.add (diag);
}
if (polling_interval != 0)
monitor.rate_limit = (int) polling_interval;
var entry = new MonitorEntry (id, monitor);
entry.file_changed.connect (on_file_changed);
monitors[id] = entry;
}
private void on_watch_remove (uint id) {
MonitorEntry? entry;
if (monitors.unset (id, out entry))
detach_monitor_entry (entry);
}
private void detach_monitor_entry (MonitorEntry entry) {
dirty_monitors.remove (entry);
entry.file_changed.disconnect (on_file_changed);
entry.destroy ();
}
private void on_file_changed (MonitorEntry entry) {
dirty_monitors.add (entry);
if (monitor_flush_timer == null) {
var source = new TimeoutSource (50);
source.set_callback (on_monitor_flush_tick);
source.attach (MainContext.get_thread_default ());
monitor_flush_timer = source;
if (schedule_emit) {
schedule_on_frida_thread (() => {
emit_pending_diagnostics ();
return Source.REMOVE;
});
}
}
private bool on_monitor_flush_tick () {
var settled = new Gee.ArrayList<MonitorEntry> ();
var now = get_monotonic_time ();
settled.add_all_iterator (dirty_monitors.filter (m => now - m.last_change >= 50000));
Agent agent = load_request.future.value;
foreach (var entry in settled) {
agent.notify_file_changed (entry.id, entry.state, io_cancellable);
dirty_monitors.remove (entry);
private void emit_pending_diagnostics () {
var batch = new Gee.ArrayList<Diagnostic> ();
lock (pending_diagnostics) {
batch.add_all (pending_diagnostics);
pending_diagnostics.clear ();
}
if (!dirty_monitors.is_empty)
return Source.CONTINUE;
var builder = new VariantBuilder (new VariantType.array (VariantType.VARDICT));
monitor_flush_timer = null;
return Source.REMOVE;
}
private async Agent get_agent (Cancellable? cancellable) throws Error, IOError {
Future<Agent> future;
if (load_request != null) {
future = load_request.future;
} else {
load_request = new Promise<Agent> ();
future = load_request.future;
load_agent.begin ();
foreach (var d in batch) {
builder.open (VariantType.VARDICT);
builder.add ("{sv}", "category", new Variant.string (d.category));
builder.add ("{sv}", "code", new Variant.int64 (d.code));
if (d.path != null) {
var b = new VariantBuilder (VariantType.VARDICT);
b.add ("{sv}", "path", new Variant.string (d.path));
b.add ("{sv}", "line", new Variant.int64 (d.line));
b.add ("{sv}", "character", new Variant.int64 (d.character));
builder.add ("{sv}", "file", b.end ());
}
builder.add ("{sv}", "text", new Variant.string (d.text));
builder.close ();
}
return yield future.wait_async (cancellable);
diagnostics (builder.end ());
}
private async void load_agent () {
try {
var device = yield manager.get_device_by_type (LOCAL, 0, io_cancellable);
var session = yield device.get_host_session (io_cancellable);
var agent = new Agent (this, (LocalHostSession) session);
load_request.resolve (agent);
} catch (GLib.Error e) {
if ((e is Error || e is IOError.CANCELLED))
e = new Error.NOT_SUPPORTED ("%s", e.message);
load_request.reject (e);
load_request = null;
}
}
#else
[NoReturn]
private void throw_not_supported () throws Error {
throw new Error.NOT_SUPPORTED ("Compiler backend disabled at build-time");
}
#endif
private T create<T> () {
return Object.new (typeof (T), parent: this);
}
protected void schedule_on_frida_thread (owned SourceFunc function) {
var source = new IdleSource ();
source.set_callback ((owned) function);
source.attach (main_context);
}
private class Diagnostic {
public string category;
public int code;
public string? path;
public int line;
public int character;
public string text;
}
private abstract class CompilerTask<T> : AsyncTask<T> {
public weak Compiler parent {
get;
construct;
}
}
}
namespace CompilerBackend {
private void init () {
#if HAVE_COMPILER_BACKEND
private class Agent : InternalAgent {
public weak Compiler parent {
get;
construct;
}
private Promise<string> source_request = new Promise<string> ();
private Promise<Bytes?> snapshot_request = new Promise<Bytes?> ();
public Agent (Compiler parent, LocalHostSession host_session) {
Object (
parent: parent,
host_session: host_session,
#if HAVE_V8
script_runtime: ScriptRuntime.V8
#if COMPILER_BACKEND_STATIC_COMPILATION
_init_go_runtime ();
build = (BuildFunc) _build;
watch = (WatchFunc) _watch;
WatchSession.dispose = (WatchSession.DisposeFunc) WatchSession._dispose;
#else
script_runtime: ScriptRuntime.DEFAULT
#endif
);
}
unowned uint8[] backend_so = Frida.Data.Compiler.get_frida_compiler_backend_so_blob ().data;
construct {
load_resources ();
}
FileDescriptor fd;
if (MemoryFileDescriptor.is_supported ()) {
fd = MemoryFileDescriptor.from_bytes ("frida-compiler-backend.so", new Bytes.static (backend_so));
} else {
string name_used;
try {
fd = new FileDescriptor (FileUtils.open_tmp ("frida-compiler-backend-XXXXXX.so", out name_used));
FileUtils.unlink (name_used);
private void load_resources () {
new Thread<void> ("compiler-agent-loader", () => {
var agent_js_blob = Data.Compiler.get_agent_js_blob ();
Bytes agent_js_bytes = decompress (agent_js_blob.data, agent_js_blob.uncompressed_size);
source_request.resolve ((string) agent_js_bytes.get_data ());
var output = new UnixOutputStream (fd.handle, false);
output.write_all (backend_so, null);
var snapshot_blob = Data.Compiler.get_snapshot_bin_blob ();
Bytes snapshot = decompress (snapshot_blob.data, snapshot_blob.uncompressed_size);
snapshot_request.resolve ((snapshot.get_size () != 0) ? snapshot : null);
});
}
public async string build (string entrypoint, BuildOptions? options, Cancellable? cancellable)
throws Error, IOError {
BuildOptions opts = (options != null) ? options : new BuildOptions ();
Json.Node bundle = yield call ("build", new Json.Node[] {
new Json.Node.alloc ().init_string (compute_project_root (entrypoint, opts)),
new Json.Node.alloc ().init_string (entrypoint),
new Json.Node.alloc ().init_string (opts.source_maps.to_nick ()),
new Json.Node.alloc ().init_string (opts.compression.to_nick ()),
}, null, cancellable);
return bundle.get_string ();
}
public async void watch (string entrypoint, WatchOptions? options, Cancellable? cancellable)
throws Error, IOError {
WatchOptions opts = (options != null) ? options : new WatchOptions ();
yield call ("watch", new Json.Node[] {
new Json.Node.alloc ().init_string (compute_project_root (entrypoint, opts)),
new Json.Node.alloc ().init_string (entrypoint),
new Json.Node.alloc ().init_string (opts.source_maps.to_nick ()),
new Json.Node.alloc ().init_string (opts.compression.to_nick ()),
}, null, cancellable);
}
private static string compute_project_root (string entrypoint, CompilerOptions options) {
string? project_root = options.project_root;
if (project_root != null)
return project_root;
if (Path.is_absolute (entrypoint))
return Path.get_dirname (entrypoint);
return Environment.get_current_dir ();
}
public void notify_file_changed (uint id, FileState state, Cancellable? cancellable) {
var notification = new Json.Builder ();
notification
.begin_object ()
.set_member_name ("type")
.add_string_value ("watch:change")
.set_member_name ("id")
.add_int_value (id)
.set_member_name ("state")
.add_string_value (Marshal.enum_to_nick<FileState> (state))
.end_object ();
post.begin (notification.get_root (), cancellable);
}
protected override async uint get_target_pid (Cancellable? cancellable) throws Error, IOError {
return 0;
}
protected override async string? load_source (Cancellable? cancellable) throws Error, IOError {
return yield source_request.future.wait_async (cancellable);
}
protected override async Bytes? load_snapshot (Cancellable? cancellable, out SnapshotTransport transport)
throws Error, IOError {
transport = SHARED_MEMORY;
return yield snapshot_request.future.wait_async (cancellable);
}
protected override void on_event (string type, Json.Array event) {
if (type == "diagnostics") {
on_build_diagnostics (event.get_array_element (1));
} else if (type == "watch:compilation-starting") {
parent.starting ();
} else if (type == "watch:compilation-finished") {
parent.finished ();
} else if (type == "watch:bundle-updated") {
on_watch_bundle_updated (event.get_string_element (1));
} else if (type == "watch:add") {
parent.on_watch_add ((uint) event.get_int_element (1), event.get_string_element (2),
event.get_string_element (3), event.get_int_element (4));
} else if (type == "watch:remove") {
parent.on_watch_remove ((uint) event.get_int_element (1));
} else {
Posix.lseek (fd.handle, 0, Posix.SEEK_SET);
} catch (GLib.Error e) {
assert_not_reached ();
}
}
private void on_build_diagnostics (Json.Array diagnostics) {
uint n = diagnostics.get_length ();
var builder = new VariantBuilder (new VariantType.array (VariantType.VARDICT));
for (uint i = 0; i != n; i++) {
var diag = diagnostics.get_array_element (i);
builder.open (VariantType.VARDICT);
builder.add ("{sv}", "category", new Variant.string (diag.get_string_element (0)));
builder.add ("{sv}", "code", new Variant.int64 (diag.get_int_element (1)));
if (!diag.get_null_element (2)) {
var file = diag.get_array_element (2);
var b = new VariantBuilder (VariantType.VARDICT);
b.add ("{sv}", "path", new Variant.string (file.get_string_element (0)));
b.add ("{sv}", "line", new Variant.int64 (file.get_int_element (1)));
b.add ("{sv}", "character", new Variant.int64 (file.get_int_element (2)));
builder.add ("{sv}", "file", b.end ());
}
builder.add ("{sv}", "text", new Variant.string (diag.get_string_element (3)));
builder.close ();
}
parent.diagnostics (builder.end ());
}
private void on_watch_bundle_updated (string bundle) {
parent.output (bundle);
}
private static Bytes decompress (uint8[] data, uint uncompressed_size) {
var decoder = new Brotli.Decoder ();
decoder.set_parameter (LARGE_WINDOW, 1);
uint8[] uncompressed_data = new uint8[uncompressed_size + 1];
size_t available_in = data.length;
size_t available_out = uncompressed_size;
uint8 * next_in = data;
uint8 * next_out = uncompressed_data;
decoder.decompress_stream (&available_in, &next_in, &available_out, &next_out);
uncompressed_data.length = (int) (next_out - (uint8 *) uncompressed_data);
return new Bytes.take ((owned) uncompressed_data);
Module backend;
try {
backend = new Module ("/proc/self/fd/%d".printf (fd.handle), LOCAL);
} catch (ModuleError e) {
assert_not_reached ();
}
build = resolve_symbol (backend, "_frida_compiler_backend_build");
watch = resolve_symbol (backend, "_frida_compiler_backend_watch");
WatchSession.dispose = resolve_symbol (backend, "_frida_compiler_backend_watch_session_dispose");
#endif
#endif
}
private class MonitorEntry : Object {
public signal void file_changed ();
public uint id;
public GLib.FileMonitor monitor;
public FileState state = PRISTINE;
public int64 last_change = -1;
public MonitorEntry (uint id, GLib.FileMonitor monitor) {
this.id = id;
this.monitor = monitor;
monitor.changed.connect (on_file_changed);
}
public void destroy () {
monitor.changed.disconnect (on_file_changed);
monitor.cancel ();
}
private void on_file_changed (File file, File? other_file, FileMonitorEvent event) {
switch (event) {
case CREATED:
state = PRISTINE;
break;
case CHANGED:
if (state != PRISTINE)
state = MODIFIED;
break;
case DELETED:
case MOVED:
state = DELETED;
break;
default:
return;
}
last_change = get_monotonic_time ();
file_changed ();
}
private void check_available () throws Error {
if (build == null)
throw new Error.NOT_SUPPORTED ("Compiler backend disabled at build-time");
}
private enum FileState {
PRISTINE,
MODIFIED,
DELETED,
private BuildFunc? build;
private WatchFunc? watch;
[CCode (has_target = false)]
private delegate void BuildFunc (string project_root, string entrypoint, OutputFormat output_format,
BundleFormat bundle_format, size_t disable_type_check, size_t source_map, size_t compress,
owned BuildCompleteFunc on_complete, DiagnosticFunc on_diagnostic);
[CCode (has_target = false)]
private delegate void WatchFunc (string project_root, string entrypoint, OutputFormat output_format,
BundleFormat bundle_format, size_t disable_type_check, size_t source_map, size_t compress,
owned WatchReadyFunc on_ready, StartingFunc on_starting, FinishedFunc on_finished, OutputFunc on_output,
DiagnosticFunc on_diagnostic);
#if COMPILER_BACKEND_STATIC_COMPILATION
private extern void _init_go_runtime ();
private extern void _build ();
private extern void _watch ();
#endif
namespace WatchSession {
[CCode (has_target = false)]
private delegate void DisposeFunc (size_t handle);
private DisposeFunc? dispose;
#if COMPILER_BACKEND_STATIC_COMPILATION
private extern void _dispose ();
#endif
}
private delegate void BuildCompleteFunc (owned string? bundle, owned string? error_message);
private delegate void WatchReadyFunc (size_t session_handle, owned string? error_message);
private delegate void StartingFunc ();
private delegate void FinishedFunc ();
private delegate void OutputFunc (owned string bundle);
private delegate void DiagnosticFunc (owned string category, int code, owned string? path, int line, int character,
owned string text);
#if HAVE_COMPILER_BACKEND && !COMPILER_BACKEND_STATIC_COMPILATION
private static T resolve_symbol<T> (Module m, string name) {
void * address;
if (!m.symbol (name, out address))
assert_not_reached ();
return (T) address;
}
#endif
}
private string compute_project_root (string entrypoint, CompilerOptions options) {
string? project_root = options.project_root;
if (project_root != null)
return project_root;
if (Path.is_absolute (entrypoint))
return Path.get_dirname (entrypoint);
return Environment.get_current_dir ();
}
public class CompilerOptions : Object {
public string? project_root {
get;
set;
}
public OutputFormat output_format {
get;
set;
default = UNESCAPED;
}
public BundleFormat bundle_format {
get;
set;
default = ESM;
}
public TypeCheckMode type_check {
get;
set;
default = FULL;
}
public SourceMaps source_maps {
get;
set;
@@ -471,6 +381,46 @@ namespace Frida {
public sealed class WatchOptions : CompilerOptions {
}
public enum OutputFormat {
UNESCAPED,
HEX_BYTES,
C_STRING;
public static OutputFormat from_nick (string nick) throws Error {
return Marshal.enum_from_nick<OutputFormat> (nick);
}
public string to_nick () {
return Marshal.enum_to_nick<OutputFormat> (this);
}
}
public enum BundleFormat {
ESM,
IIFE;
public static BundleFormat from_nick (string nick) throws Error {
return Marshal.enum_from_nick<BundleFormat> (nick);
}
public string to_nick () {
return Marshal.enum_to_nick<BundleFormat> (this);
}
}
public enum TypeCheckMode {
FULL,
NONE;
public static TypeCheckMode from_nick (string nick) throws Error {
return Marshal.enum_from_nick<TypeCheckMode> (nick);
}
public string to_nick () {
return Marshal.enum_to_nick<TypeCheckMode> (this);
}
}
public enum SourceMaps {
INCLUDED,
OMITTED;
-91
View File
@@ -1,91 +0,0 @@
from pathlib import Path
import shutil
import subprocess
import sys
INPUTS = [
"agent-entrypoint.js",
"agent-core.ts",
"agent-warmup.js",
"package.json",
"package-lock.json",
"tsconfig.json",
"rollup.config.agent-core.ts",
"rollup.config.typescript.ts",
]
def main(argv):
output_dir, priv_dir, input_dir, npm, v8_mksnapshot = [Path(d).resolve() if d else None for d in argv[1:6]]
host_os_family, host_arch, host_cpu_mode = argv[6:9]
try:
generate_agent(output_dir, priv_dir, input_dir, npm, v8_mksnapshot, host_os_family, host_arch, host_cpu_mode)
except subprocess.CalledProcessError as e:
print(e, file=sys.stderr)
print("Output:\n\t| " + "\n\t| ".join(e.output.strip().split("\n")), file=sys.stderr)
sys.exit(2)
except Exception as e:
print(e, file=sys.stderr)
sys.exit(1)
def generate_agent(output_dir, priv_dir, input_dir, npm, v8_mksnapshot, host_os_family, host_arch, host_cpu_mode):
entrypoint = input_dir / "agent-entrypoint.js"
priv_dir.mkdir(exist_ok=True)
for name in INPUTS:
if name == "agent-entrypoint.js":
continue
shutil.copy(input_dir / name, priv_dir / name)
run_kwargs = {
"cwd": priv_dir,
"stdout": subprocess.PIPE,
"stderr": subprocess.STDOUT,
"encoding": "utf-8",
"check": True,
}
subprocess.run([npm, "install"], **run_kwargs)
#subprocess.run([npm, "link", "/Users/oleavr/src/frida-compile"], **run_kwargs)
components = ["typescript", "agent-core"]
for component in components:
subprocess.run([
npm, "run", "build:" + component,
"--",
"--environment", f"FRIDA_HOST_OS_FAMILY:{host_os_family},FRIDA_HOST_ARCH:{host_arch},FRIDA_HOST_CPU_MODE:{host_cpu_mode}",
"--silent",
],
**run_kwargs)
chunks = []
for component in components:
script = (priv_dir / f"{component}.js").read_text(encoding="utf-8")
chunks.append(script)
components_source = "\n".join(chunks)
agent = output_dir / "agent.js"
snapshot = output_dir / "snapshot.bin"
if v8_mksnapshot is not None:
shutil.copy(entrypoint, agent)
(priv_dir / "embed.js").write_text(components_source, encoding="utf-8")
subprocess.run([
v8_mksnapshot,
"--turbo-instruction-scheduling",
f"--startup-blob={snapshot}",
"embed.js",
input_dir / "agent-warmup.js",
],
**run_kwargs)
else:
agent.write_text("\n".join([
components_source,
entrypoint.read_text(encoding="utf-8"),
]), encoding="utf-8")
snapshot.write_bytes(b"")
if __name__ == "__main__":
main(sys.argv)
+14
View File
@@ -0,0 +1,14 @@
module github.com/frida/frida-core-compiler
go 1.24.3
require (
github.com/evanw/esbuild v0.25.5
github.com/frida/typescript-go v0.0.0-20250601212135-a4721f45f19c
)
require (
github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/go-json-experiment/json v0.0.0-20250517221953-25912455fbc8 // indirect
golang.org/x/sys v0.33.0 // indirect
)
+17
View File
@@ -0,0 +1,17 @@
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/evanw/esbuild v0.25.5 h1:E+JpeY5S/1LFmnX1vtuZqUKT7qDVcfXdhzMhM3uIKFs=
github.com/evanw/esbuild v0.25.5/go.mod h1:D2vIQZqV/vIf/VRHtViaUtViZmG7o+kKmlBfVQuRi48=
github.com/frida/typescript-go v0.0.0-20250601212135-a4721f45f19c h1:IWBI9AwSFLWymI4enx1jrAw0E4H2E+qHwsihv+AxSoE=
github.com/frida/typescript-go v0.0.0-20250601212135-a4721f45f19c/go.mod h1:L4RMzD/pFBl7CqIf9XTrX41RO2xcok3OOVVcowv0H4k=
github.com/go-json-experiment/json v0.0.0-20250517221953-25912455fbc8 h1:o8UqXPI6SVwQt04RGsqKp3qqmbOfTNMqDrWsc4O47kk=
github.com/go-json-experiment/json v0.0.0-20250517221953-25912455fbc8/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/peter-evans/patience v0.3.0 h1:rX0JdJeepqdQl1Sk9c9uvorjYYzL2TfgLX1adqYm9cA=
github.com/peter-evans/patience v0.3.0/go.mod h1:Kmxu5sY1NmBLFSStvXjX1wS9mIv7wMcP/ubucyMOAu0=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
+45 -41
View File
@@ -1,61 +1,65 @@
compiler_sources = files(
'compiler.vala',
'backend-glue.c',
)
if have_compiler_backend
compiler_mksnapshot = generate_compiler_snapshot ? v8_mksnapshot : ''
compiler_agent = custom_target('frida-compiler-agent',
compiler_backend = custom_target('frida-compiler-backend',
input: [
'agent-entrypoint.js',
'agent-core.ts',
'agent-warmup.js',
'go.mod',
'go.sum',
'backend.go',
'backend.version',
'tscompiler.go',
'tsconfig.go',
'shims.go',
'package.json',
'package-lock.json',
'tsconfig.json',
'rollup.config.agent-core.ts',
'rollup.config.typescript.ts',
],
output: [
'agent.js',
'snapshot.bin',
'frida-compiler-backend' + (compiler_backend_static_compilation ? '.a' : ('-raw' + shlib_suffix)),
'frida-compiler-backend.h',
],
command: [
python,
files('generate-agent.py'),
files('build-backend.py'),
go_config,
meson.current_build_dir(),
'@PRIVATE_DIR@',
meson.current_source_dir(),
go,
npm,
compiler_mksnapshot,
host_os_family,
host_arch_gumjs,
host_cpu_mode,
'@INPUT@',
],
)
compiler_data = custom_target('frida-data-compiler',
input: [
'compiler.resources.' + frida_profile,
compiler_agent,
],
output: [
'frida-data-compiler.vapi',
'frida-data-compiler.h',
'frida-data-compiler.c',
'frida-data-compiler-blob' + resource_blob_extension,
'frida-data-compiler-agent.js.br',
'frida-data-compiler-snapshot.bin.br',
],
command: [
resource_compiler_cmd_array,
'-c', '@INPUT0@',
'-o', meson.current_build_dir() / 'frida-data-compiler',
'@INPUT1@',
'@INPUT2@',
],
)
compiler_sources += compiler_data
if compiler_backend_static_compilation
backend_libs += compiler_backend[0]
else
filename = 'frida-compiler-backend' + shlib_suffix
identity = (host_os_family == 'darwin') ? 'FridaCompilerBackend' : filename
compiler_backend_shlib = custom_target('frida-compiler-backend-shlib',
input: compiler_backend[0],
output: filename,
command: post_process + ['shared-library', identity, 'elf-cleaner:off'],
)
backend_vala_args_private += '--pkg=libbrotlidec'
backend_deps_private += brotlidec_dep
compiler_data = custom_target('frida-data-compiler',
input: [
'compiler.resources',
compiler_backend_shlib,
],
output: [
'frida-data-compiler.vapi',
'frida-data-compiler.h',
'frida-data-compiler.c',
'frida-data-compiler-blob' + resource_blob_extension,
],
command: [
resource_compiler_cmd_array,
'-c', '@INPUT0@',
'-o', meson.current_build_dir() / 'frida-data-compiler',
'@INPUT1@',
],
)
backend_sources += compiler_data
endif
endif
+96 -1840
View File
File diff suppressed because it is too large. Load diff
+30 -21
View File
@@ -1,27 +1,36 @@
{
"name": "frida-compiler-agent",
"name": "frida-compiler-shims",
"version": "1.0.0",
"description": "Agent used by Frida's compiler",
"main": "agent.ts",
"scripts": {
"build:typescript": "rollup --config rollup.config.typescript.ts --configPlugin typescript",
"build:agent-core": "rollup --config rollup.config.agent-core.ts --configPlugin typescript"
},
"description": "Shims used by Frida's compiler",
"private": true,
"dependencies": {
"@frida/crosspath": "3.0.0",
"frida-compile": "17.0.0",
"frida-fs": "6.0.0"
},
"devDependencies": {
"@frida/rollup-plugin-node-polyfills": "^3.0.1",
"@rollup/plugin-node-resolve": "^14.1.0",
"@rollup/plugin-replace": "^4.0.0",
"@rollup/plugin-typescript": "^8.3.4",
"@frida/assert": "^3.0.2",
"@frida/base64-js": "^2.0.3",
"@frida/buffer": "^7.0.4",
"@frida/crypto": "^1.0.1",
"@frida/diagnostics_channel": "^1.0.0",
"@frida/events": "^4.0.4",
"@frida/http": "^4.0.2",
"@frida/http-parser-js": "^1.0.0",
"@frida/https": "^1.0.0",
"@frida/ieee754": "^2.0.2",
"@frida/net": "^5.0.0",
"@frida/os": "^1.0.2",
"@frida/path": "^2.0.3",
"@frida/process": "^1.2.1",
"@frida/punycode": "^3.0.0",
"@frida/querystring": "^1.0.0",
"@frida/readable-stream": "^4.1.3",
"@frida/reserved-words": "^1.0.0",
"@frida/stream": "^1.0.2",
"@frida/string_decoder": "^2.0.0",
"@frida/timers": "^3.0.0",
"@frida/tty": "^1.0.0",
"@frida/url": "^1.0.2",
"@frida/util": "^1.0.3",
"@frida/vm": "^2.0.0",
"@types/frida-gum": "19.0.0",
"@types/glob": "^8.0.0",
"@types/node": "18.7.23",
"glob": "^8.0.3",
"rollup": "^2.79.1",
"rollup-plugin-terser": "^7.0.2"
"@types/node": "18.19.103",
"frida-fs": "7.0.0"
}
}
-184
View File
@@ -1,184 +0,0 @@
import crosspath from "@frida/crosspath";
import fs from "fs";
import { sync as glob } from "glob";
import replace from "@rollup/plugin-replace";
import resolve from "@rollup/plugin-node-resolve";
import typescript from "@rollup/plugin-typescript";
import polyfills from "@frida/rollup-plugin-node-polyfills";
import { terser } from "rollup-plugin-terser";
import { defineConfig } from "rollup";
import type rollup from "rollup";
export default defineConfig({
input: "agent-core.ts",
output: {
file: "agent-core.js",
format: "umd",
name: "FridaCompilerAgentCore",
generatedCode: {
preset: "es2015",
},
strict: false,
interop: "default",
globals: {
"typescript": "ts",
},
},
plugins: [
typescript(),
replace({
preventAssignment: true,
values: computeSubstitutionValues(),
}),
stubTsImportPlugin(),
polyfills(),
resolve(),
/*
terser({
ecma: 2020,
compress: {
module: true,
global_defs: {
"process.env.FRIDA_COMPILE": true
},
},
mangle: {
module: true,
},
}),
*/
],
});
function computeSubstitutionValues() {
const hostOsFamily = process.env.FRIDA_HOST_OS_FAMILY;
if (hostOsFamily === undefined) {
throw new Error("missing FRIDA_HOST_OS_FAMILY");
}
const hostArch = process.env.FRIDA_HOST_ARCH;
if (hostArch === undefined) {
throw new Error("missing FRIDA_HOST_ARCH");
}
const hostCpuMode = process.env.FRIDA_HOST_CPU_MODE;
if (hostCpuMode === undefined) {
throw new Error("missing FRIDA_HOST_CPU_MODE");
}
const outputDir = __dirname;
const compilerDir = crosspath.join(__dirname, "node_modules", "frida-compile");
let usingLinkedCompiler = false;
try {
usingLinkedCompiler = fs.statSync(crosspath.join(compilerDir, "node_modules")).isDirectory();
} catch (e) {
}
const assetParentDir = usingLinkedCompiler ? compilerDir : outputDir;
const assetModulesDir = crosspath.join(assetParentDir, "node_modules");
const shimDirs = [
["@frida", "assert"],
["@frida", "base64-js"],
["@frida", "buffer"],
["@frida", "crypto"],
["@frida", "diagnostics_channel"],
["@frida", "events"],
["@frida", "http"],
["@frida", "http-parser-js"],
["@frida", "https"],
["@frida", "ieee754"],
["@frida", "net"],
["@frida", "os"],
["@frida", "path"],
["@frida", "process"],
["@frida", "punycode"],
["@frida", "querystring"],
["@frida", "readable-stream"],
["@frida", "stream"],
["@frida", "string_decoder"],
["@frida", "timers"],
["@frida", "tty"],
["@frida", "url"],
["@frida", "util"],
["@frida", "vm"],
["frida-fs"],
];
const typeDirs = [
["@types", "node"],
["@types", "frida-gum"],
];
const assets: string[] = [];
for (const shimDir of shimDirs) {
assets.push(...glob(crosspath.join(assetModulesDir, ...shimDir, "package.json")));
assets.push(...glob(crosspath.join(assetModulesDir, ...shimDir, "**", "*.js")));
}
for (const typeDir of typeDirs) {
assets.push(...glob(crosspath.join(assetModulesDir, ...typeDir, "package.json")));
assets.push(...glob(crosspath.join(assetModulesDir, ...typeDir, "**", "*.d.ts")));
}
assets.push(...glob(crosspath.join(compilerDir, "ext", "lib.es*.d.ts")));
assets.push(...glob(crosspath.join(compilerDir, "ext", "lib.decorators*.d.ts")));
const ignoredAssetFiles = new Set([
"@frida/process/browser.js",
]);
const agentDirectories = new Set<string>();
const agentFiles = new Map<string, string>();
for (const assetPath of assets) {
let assetRelpath = assetPath.substring(assetParentDir.length);
if (usingLinkedCompiler && assetRelpath.startsWith("/ext/")) {
assetRelpath = crosspath.join("/", "node_modules", "frida-compile", assetRelpath.substring(1));
}
const identifier = assetRelpath.split("/").slice(2).join("/");
if (ignoredAssetFiles.has(identifier)) {
continue;
}
let currentDir = crosspath.dirname(assetRelpath);
do {
agentDirectories.add(currentDir);
currentDir = crosspath.dirname(currentDir);
} while (currentDir !== "/");
agentFiles.set(assetRelpath, fs.readFileSync(assetPath, "utf-8"));
}
const orderedAgentDirectories = Array.from(agentDirectories);
orderedAgentDirectories.sort();
const orderedAgentFiles = Array.from(agentFiles);
orderedAgentFiles.sort((a, b) => a[0].localeCompare(b[0]));
return {
"Frida.version": "'0.0.0'",
"Process.id": "1",
"Process.platform": `'${hostOsFamily}'`,
"Process.arch": `'${hostArch}'`,
"Process.pointerSize": (hostCpuMode === "64") ? "8" : "4",
"__agentDirectories__": JSON.stringify(orderedAgentDirectories, null, 4),
"__agentFiles__": JSON.stringify(orderedAgentFiles, null, 4),
};
}
function stubTsImportPlugin(): rollup.Plugin {
return {
name: "stub-ts-import",
async resolveId(source, importer, options) {
if (crosspath.basename(source) === "typescript.js") {
return {
id: "typescript",
external: true,
meta: {},
moduleSideEffects: false,
syntheticNamedExports: false
};
}
return this.resolve(source, importer, { skipSelf: true, ...options });
}
};
}
-15
View File
@@ -1,15 +0,0 @@
import path from "path";
import { defineConfig } from "rollup";
export default defineConfig({
input: path.join("node_modules", "frida-compile", "ext", "typescript.js"),
output: {
file: "typescript.js",
format: "umd",
name: "ts",
generatedCode: {
preset: "es2015",
},
strict: false,
},
});
+196
View File
@@ -0,0 +1,196 @@
package main
import (
"embed"
"encoding/json"
"fmt"
"path/filepath"
"strings"
esbuild "github.com/evanw/esbuild/pkg/api"
)
var nodeGlobals = `
export { Buffer } from 'node:buffer';
export { default as process } from 'node:process';
`
//go:embed node_modules/@frida/*/package.json
//go:embed node_modules/@frida/*/*.js
//go:embed node_modules/@frida/*/*/*.js
//go:embed node_modules/@frida/*/*/*/*.js
//go:embed node_modules/frida-fs/package.json
//go:embed node_modules/frida-fs/*/*.js
var embeddedShims embed.FS
func makeFridaShimsPlugin() esbuild.Plugin {
const (
nsBuiltins = "frida-builtins"
nsShim = "frida-shim"
)
const (
builtinFilter = `^frida-builtins://(.+)$`
shimFilter = `^(assert|base64-js|buffer|crypto|diagnostics_channel|events|fs|http|https|http-parser-js|ieee754|net|os|path|process|punycode|querystring|readable-stream|stream|string_decoder|timers|tty|url|util|vm)$`
shimNodePrefixFilter = `^node:(assert|buffer|crypto|diagnostics_channel|events|fs|http|https|net|os|path|process|punycode|querystring|stream|string_decoder|timers|tty|url|util|vm)$`
)
return esbuild.Plugin{
Name: "frida-custom-shims",
Setup: func(build esbuild.PluginBuild) {
build.OnResolve(esbuild.OnResolveOptions{Filter: builtinFilter},
func(args esbuild.OnResolveArgs) (esbuild.OnResolveResult, error) {
return esbuild.OnResolveResult{
Path: strings.TrimPrefix(args.Path, "frida-builtins://"),
Namespace: nsBuiltins,
SideEffects: esbuild.SideEffectsFalse,
}, nil
})
build.OnLoad(esbuild.OnLoadOptions{Filter: ".*", Namespace: nsBuiltins},
func(args esbuild.OnLoadArgs) (esbuild.OnLoadResult, error) {
if args.Path != "/node-globals.js" {
return esbuild.OnLoadResult{
Errors: []esbuild.Message{{Text: "Unexpected path: " + args.Path}},
}, nil
}
return esbuild.OnLoadResult{
Contents: &nodeGlobals,
Loader: esbuild.LoaderJS,
}, nil
})
registerShimResolve := func(pattern string) {
build.OnResolve(esbuild.OnResolveOptions{Filter: pattern},
func(args esbuild.OnResolveArgs) (esbuild.OnResolveResult, error) {
return makeResolveResult(nsShim, args.Path)
})
}
registerShimResolve(shimFilter)
registerShimResolve(shimNodePrefixFilter)
build.OnResolve(esbuild.OnResolveOptions{Filter: ".*", Namespace: nsShim},
func(args esbuild.OnResolveArgs) (esbuild.OnResolveResult, error) {
if strings.HasPrefix(args.Path, ".") {
abs := filepath.ToSlash(filepath.Join(filepath.Dir(args.Importer), args.Path))
return esbuild.OnResolveResult{
Path: abs,
Namespace: nsShim,
SideEffects: esbuild.SideEffectsFalse,
}, nil
}
return makeResolveResult(nsShim, args.Path)
})
build.OnLoad(esbuild.OnLoadOptions{Filter: ".*", Namespace: nsShim},
func(args esbuild.OnLoadArgs) (esbuild.OnLoadResult, error) {
data, err := embeddedShims.ReadFile(filepath.ToSlash(args.Path))
if err != nil {
return esbuild.OnLoadResult{
Errors: []esbuild.Message{{
Text: fmt.Sprintf("Error reading shim file %q: %v", args.Path, err),
}},
}, nil
}
content := string(data)
return esbuild.OnLoadResult{
Contents: &content,
Loader: loaderFor(args.Path),
}, nil
})
},
}
}
func makeResolveResult(ns string, module string) (esbuild.OnResolveResult, error) {
path, errs := resolveShim(module)
if len(errs) > 0 {
return esbuild.OnResolveResult{Errors: errs}, nil
}
return esbuild.OnResolveResult{
Path: path,
Namespace: ns,
SideEffects: esbuild.SideEffectsFalse,
}, nil
}
func loaderFor(path string) esbuild.Loader {
switch ext := filepath.Ext(path); ext {
case ".js", ".mjs", ".cjs":
return esbuild.LoaderJS
case ".json":
return esbuild.LoaderJSON
default:
panic(fmt.Sprintf("frida-shims: unsupported file type %q", ext))
}
}
var shimMap = map[string]string{
"assert": "@frida/assert",
"base64-js": "@frida/base64-js",
"buffer": "@frida/buffer",
"crypto": "@frida/crypto",
"diagnostics_channel": "@frida/diagnostics_channel",
"events": "@frida/events",
"fs": "frida-fs",
"http": "@frida/http",
"https": "@frida/https",
"http-parser-js": "@frida/http-parser-js",
"ieee754": "@frida/ieee754",
"net": "@frida/net",
"os": "@frida/os",
"path": "@frida/path",
"process": "@frida/process",
"punycode": "@frida/punycode",
"querystring": "@frida/querystring",
"readable-stream": "@frida/readable-stream",
"stream": "@frida/stream",
"string_decoder": "@frida/string_decoder",
"timers": "@frida/timers",
"tty": "@frida/tty",
"url": "@frida/url",
"util": "@frida/util",
"vm": "@frida/vm",
}
type PackageJSON struct {
Main string `json:"main"`
Module string `json:"module"`
}
func resolveShim(shimName string) (string, []esbuild.Message) {
var subDir string
if strings.HasPrefix(shimName, "@frida/") {
subDir = shimName
} else {
actualShimName := strings.TrimPrefix(shimName, "node:")
var ok bool
subDir, ok = shimMap[actualShimName]
if !ok {
return "", []esbuild.Message{{Text: "Unknown shim: " + actualShimName}}
}
}
shimPackageDir := filepath.Join("node_modules", subDir)
packageJSONPath := filepath.Join(shimPackageDir, "package.json")
pkgJSONBytes, _ := embeddedShims.ReadFile(filepath.ToSlash(packageJSONPath))
var pkg PackageJSON
json.Unmarshal(pkgJSONBytes, &pkg)
entryFile := ""
if pkg.Module != "" {
entryFile = pkg.Module
} else if pkg.Main != "" {
entryFile = pkg.Main
} else {
entryFile = "index.js"
}
resolvedEntryPath := filepath.Join(shimPackageDir, entryFile)
return filepath.ToSlash(resolvedEntryPath), nil
}
+448
View File
@@ -0,0 +1,448 @@
package main
import (
"context"
"embed"
"fmt"
"maps"
"os"
"path/filepath"
"slices"
"sort"
"strings"
"sync"
"time"
"github.com/frida/typescript-go/pkg/ast"
"github.com/frida/typescript-go/pkg/bundled"
"github.com/frida/typescript-go/pkg/compiler"
"github.com/frida/typescript-go/pkg/core"
"github.com/frida/typescript-go/pkg/tsoptions"
"github.com/frida/typescript-go/pkg/tspath"
"github.com/frida/typescript-go/pkg/vfs"
"github.com/frida/typescript-go/pkg/vfs/iovfs"
"github.com/frida/typescript-go/pkg/vfs/osvfs"
)
//go:embed node_modules/@types/*/package.json
//go:embed node_modules/@types/*/*.d.ts
//go:embed node_modules/@types/*/*/*.d.ts
var embeddedTypes embed.FS
type TSCompiler struct {
projectRoot string
entrypoint string
loadCompilerOptions LoadCompilerOptionsHandler
fs vfs.FS
captureFs *captureFS
mu sync.Mutex
options *core.CompilerOptions
program *compiler.Program
programErr error
forceFreshProgram bool
mtimes map[tspath.Path]time.Time
inputDirs, inputFiles []string
pendingDirs, pendingFiles []string
}
type LoadCompilerOptionsHandler func(host tsoptions.ParseConfigHost) (*core.CompilerOptions, string, error)
func NewTSCompiler(projectRoot, entrypoint string, loadCompilerOptions LoadCompilerOptionsHandler) *TSCompiler {
captureFs := newCaptureFS(osvfs.FS())
fs := newTypesFS(bundled.WrapFS(captureFs), projectRoot)
return &TSCompiler{
projectRoot: projectRoot,
entrypoint: tspath.NormalizePath(entrypoint),
loadCompilerOptions: loadCompilerOptions,
fs: fs,
captureFs: captureFs,
}
}
func (c *TSCompiler) resetProgramState() {
c.options = nil
c.program = nil
c.programErr = nil
c.forceFreshProgram = false
c.mtimes = nil
}
func (c *TSCompiler) EnsureProgramUpToDate() error {
opts, _, err := c.loadCompilerOptions(c)
if err != nil {
c.resetProgramState()
c.recomputeInputs()
return err
}
var prog *compiler.Program
var progErr error
if c.forceFreshProgram || c.program == nil || opts != c.options {
c.forceFreshProgram = false
prog, progErr = c.createProgram(opts)
} else {
prog, progErr = c.updateProgram(c.program, opts)
}
c.program = prog
c.programErr = progErr
c.options = opts
c.recomputeInputs()
return progErr
}
func (c *TSCompiler) createProgram(options *core.CompilerOptions) (*compiler.Program, error) {
host := compiler.NewCompilerHost(options, c.projectRoot, c.fs, bundled.LibPath())
program := compiler.NewProgram(compiler.ProgramOptions{
RootFiles: []string{c.entrypoint},
Host: host,
Options: options,
})
c.updateMtimes(program)
return program, nil
}
func (c *TSCompiler) updateProgram(old *compiler.Program, options *core.CompilerOptions) (*compiler.Program, error) {
newMtimes, err := c.collectMtimes(old)
if err != nil {
return c.createProgram(options)
}
updated := []tspath.Path{}
newProg := old
for path, mtime := range newMtimes {
if !mtime.Equal(c.mtimes[path]) {
var reused bool
newProg, reused = newProg.UpdateProgram(path)
updated = append(updated, path)
if !reused {
c.updateMtimes(newProg)
return newProg, nil
}
}
}
c.mtimes = newMtimes
return newProg, nil
}
func (c *TSCompiler) updateMtimes(p *compiler.Program) {
mt, _ := c.collectMtimes(p)
c.mtimes = mt
}
func (c *TSCompiler) collectMtimes(p *compiler.Program) (map[tspath.Path]time.Time, error) {
mt := make(map[tspath.Path]time.Time, len(p.SourceFiles()))
for _, sf := range p.SourceFiles() {
name := sf.FileName()
if isBundled(name) {
continue
}
info := c.fs.Stat(name)
if info == nil {
return nil, fmt.Errorf("File %q disappeared", name)
}
mt[sf.Path()] = info.ModTime()
}
return mt, nil
}
func isBundled(name string) bool {
return strings.HasPrefix(name, "bundled://")
}
func (c *TSCompiler) WatchDirs() []string {
if c.inputDirs != nil {
return c.inputDirs
}
return c.pendingDirs
}
func (c *TSCompiler) WatchFiles() []string {
if c.inputFiles != nil {
return c.inputFiles
}
return c.pendingFiles
}
func (c *TSCompiler) CommitPendingInputs() {
c.inputDirs, c.pendingDirs = c.pendingDirs, nil
c.inputFiles, c.pendingFiles = c.pendingFiles, nil
}
func (c *TSCompiler) DropPendingInputs() {
c.pendingDirs, c.pendingFiles = nil, nil
}
func (c *TSCompiler) recomputeInputs() {
var capHint int
if c.program != nil {
capHint = 1 + len(c.program.GetSourceFiles())
} else {
capHint = 1
}
files := make([]string, 0, capHint)
files = append(files, filepath.Join(c.projectRoot, "tsconfig.json"))
if c.program != nil {
for _, sf := range c.program.GetSourceFiles() {
name := sf.FileName()
if !isBundled(name) {
files = append(files, name)
}
}
}
sort.Strings(files)
c.pendingDirs = uniqueDirs(files)
c.pendingFiles = files
}
func (c *TSCompiler) Compile(filePathToCompile string) (string, []*ast.Diagnostic, error) {
c.mu.Lock()
defer c.mu.Unlock()
if c.programErr != nil {
return "", nil, c.programErr
}
program := c.program
var targetSourceFile *ast.SourceFile
normalizedFilePathToCompile := tspath.NormalizePath(filePathToCompile)
for _, sf := range program.GetSourceFiles() {
if sf.FileName() == normalizedFilePathToCompile {
targetSourceFile = sf
break
}
}
if targetSourceFile == nil {
return "", nil, fmt.Errorf("TypeScript source file not found in program: %s", filePathToCompile)
}
c.captureFs.ClearOutputs()
res := program.Emit(compiler.EmitOptions{
TargetSourceFile: targetSourceFile,
})
ctx := context.Background()
diagnostics := program.GetSyntacticDiagnostics(ctx, targetSourceFile)
if len(diagnostics) == 0 {
diagnostics = append(diagnostics, program.GetBindDiagnostics(ctx, targetSourceFile)...)
}
if len(diagnostics) == 0 {
diagnostics = append(diagnostics, program.GetOptionsDiagnostics(ctx)...)
}
if len(diagnostics) == 0 {
diagnostics = append(diagnostics, program.GetGlobalDiagnostics(ctx)...)
}
if len(diagnostics) == 0 {
semanticDiags := program.GetSemanticDiagnostics(ctx, targetSourceFile)
for _, d := range semanticDiags {
switch d.Code() {
case
2305, // Module '{0}' has no exported member '{1}'.
2306, // File '{0}' is not a module.
2307: // Cannot find module '{0}' or its corresponding type declarations.
c.forceFreshProgram = true
}
}
diagnostics = append(diagnostics, semanticDiags...)
}
if res.EmitSkipped {
errMsg := "TypeScript compilation failed and was skipped"
if len(diagnostics) == 0 {
errMsg = fmt.Sprintf("TypeScript compilation failed and was skipped for %s, but no diagnostics reported", filePathToCompile)
}
return "", diagnostics, fmt.Errorf(errMsg)
}
var compiledJS string
var foundJSOutput bool
for path, content := range c.captureFs.GetOutputs() {
ext := filepath.Ext(path)
if ext == ".js" {
compiledJS = content
foundJSOutput = true
break
}
}
if !foundJSOutput {
if len(diagnostics) == 0 {
return "", nil, fmt.Errorf("TypeScript compilation for %s seemed to succeed (emit not skipped, no diagnostics) but no .js output file was captured. Captured outputs: %v", filePathToCompile, c.captureFs.GetOutputs())
}
return "", diagnostics, fmt.Errorf("No .js output file was captured for %s. Captured outputs: %v", filePathToCompile, c.captureFs.GetOutputs())
}
return compiledJS, diagnostics, nil
}
func uniqueDirs(files []string) []string {
m := make(map[string]struct{}, len(files))
for _, f := range files {
m[filepath.Dir(f)] = struct{}{}
}
out := make([]string, 0, len(m))
for d := range m {
out = append(out, d)
}
sort.Strings(out)
return out
}
// FS implements ParseConfigHost.
func (c *TSCompiler) FS() vfs.FS {
return c.fs
}
// GetCurrentDirectory implements ParseConfigHost.
func (c *TSCompiler) GetCurrentDirectory() string {
return c.projectRoot
}
type captureFS struct {
vfs.FS
outputs map[string]string
mutex sync.Mutex
}
var _ vfs.FS = (*captureFS)(nil)
func newCaptureFS(inner vfs.FS) *captureFS {
return &captureFS{
FS: inner,
outputs: make(map[string]string),
}
}
func (c *captureFS) ClearOutputs() {
c.mutex.Lock()
defer c.mutex.Unlock()
c.outputs = make(map[string]string)
}
func (c *captureFS) GetOutputs() map[string]string {
c.mutex.Lock()
defer c.mutex.Unlock()
snap := make(map[string]string, len(c.outputs))
for k, v := range c.outputs {
snap[k] = v
}
return snap
}
func (c *captureFS) WriteFile(path string, data string, writeByteOrderMark bool) error {
c.mutex.Lock()
defer c.mutex.Unlock()
c.outputs[path] = data
return nil
}
func (c *captureFS) Remove(path string) error {
c.mutex.Lock()
defer c.mutex.Unlock()
delete(c.outputs, path)
return nil
}
type typesFS struct {
vfs.FS
projectRoot string
types vfs.FS
}
var _ vfs.FS = (*typesFS)(nil)
func newTypesFS(inner vfs.FS, projectRoot string) *typesFS {
return &typesFS{
FS: inner,
projectRoot: projectRoot,
types: iovfs.From(embeddedTypes, true),
}
}
func (t *typesFS) DirectoryExists(path string) bool {
embeddedPath := t.resolveEmbeddedPath(path)
if embeddedPath != "" {
if t.types.DirectoryExists(embeddedPath) {
return true
}
}
return t.FS.DirectoryExists(path)
}
func (t *typesFS) GetAccessibleEntries(path string) vfs.Entries {
embeddedPath := t.resolveEmbeddedPath(path)
var embeddedEntries vfs.Entries
if embeddedPath != "" {
embeddedEntries = t.types.GetAccessibleEntries(embeddedPath)
}
otherEntries := t.FS.GetAccessibleEntries(path)
return vfs.Entries{
Files: mergeAndSort(embeddedEntries.Files, otherEntries.Files),
Directories: mergeAndSort(embeddedEntries.Directories, otherEntries.Directories),
}
}
func (t *typesFS) FileExists(path string) bool {
embeddedPath := t.resolveEmbeddedPath(path)
if embeddedPath != "" {
if t.types.FileExists(embeddedPath) {
return true
}
}
return t.FS.FileExists(path)
}
func (t *typesFS) ReadFile(path string) (contents string, ok bool) {
contents, ok = t.FS.ReadFile(path)
if ok {
return contents, ok
}
embeddedPath := t.resolveEmbeddedPath(path)
if embeddedPath != "" {
contents, ok = t.types.ReadFile(embeddedPath)
}
return contents, ok
}
func (c *typesFS) resolveEmbeddedPath(path string) string {
rel, err := filepath.Rel(c.projectRoot, path)
if err != nil {
return ""
}
if rel == ".." || strings.HasPrefix(rel, ".."+string(os.PathSeparator)) {
return ""
}
return "/" + filepath.ToSlash(rel)
}
func mergeAndSort(a, b []string) []string {
m := make(map[string]struct{}, len(a)+len(b))
for _, v := range append(a, b...) {
m[v] = struct{}{}
}
return slices.Sorted(maps.Keys(m))
}
+158
View File
@@ -0,0 +1,158 @@
package main
import (
"encoding/json"
"fmt"
"path/filepath"
"reflect"
"strings"
"sync"
"time"
tscore "github.com/frida/typescript-go/pkg/core"
"github.com/frida/typescript-go/pkg/tsoptions"
"github.com/frida/typescript-go/pkg/tspath"
)
type TSConfigCache struct {
projectRoot string
sourceMap bool
tsconfigPath string
onChange ConfigChangeCallback
mu sync.Mutex
lastModTime time.Time
cachedOpts *tscore.CompilerOptions
lastText string
}
type ConfigChangeCallback func()
func NewTSConfigCache(
projectRoot string,
sourceMap bool,
callback ConfigChangeCallback,
) *TSConfigCache {
return &TSConfigCache{
projectRoot: projectRoot,
sourceMap: sourceMap,
tsconfigPath: filepath.Join(projectRoot, "tsconfig.json"),
lastModTime: time.Time{},
cachedOpts: nil,
lastText: "",
onChange: callback,
}
}
func (c *TSConfigCache) GetCompilerOptions(
host tsoptions.ParseConfigHost,
) (*tscore.CompilerOptions, string, error) {
c.mu.Lock()
defer c.mu.Unlock()
fs := host.FS()
info := fs.Stat(c.tsconfigPath)
var currentModTime time.Time
if info != nil {
currentModTime = info.ModTime()
} else {
currentModTime = time.Time{}
}
if c.cachedOpts != nil && currentModTime.Equal(c.lastModTime) {
return c.cachedOpts, c.lastText, nil
}
var tsconfigText string
if info != nil {
data, ok := fs.ReadFile(c.tsconfigPath)
if !ok {
return nil, "", fmt.Errorf("Unable to read %q", c.tsconfigPath)
}
tsconfigText = string(data)
} else {
tsconfigText = "{}"
}
parsedSource := tsoptions.NewTsconfigSourceFileFromFilePath(
tspath.NormalizePath(c.tsconfigPath),
tspath.ToPath(c.tsconfigPath, "", fs.UseCaseSensitiveFileNames()),
tsconfigText,
)
parsedCommandLine := tsoptions.ParseJsonSourceFileConfigFileContent(
parsedSource,
host,
c.projectRoot,
nil,
c.tsconfigPath,
nil, nil, nil,
)
if len(parsedCommandLine.Errors) > 0 {
var msgs []string
for _, diag := range parsedCommandLine.Errors {
msgs = append(msgs, diag.Message())
}
return nil, "", fmt.Errorf(
"Failed to parse %s: %s",
c.tsconfigPath,
strings.Join(msgs, "; "),
)
}
newOpts := parsedCommandLine.CompilerOptions()
newOpts.Module = tscore.ModuleKindNode16
newOpts.ModuleResolution = tscore.ModuleResolutionKindNode16
newOpts.NoEmit = tscore.TSFalse
sourceMapOptVal := boolToTristate(c.sourceMap)
newOpts.SourceMap = sourceMapOptVal
newOpts.InlineSourceMap = sourceMapOptVal
if newOpts.Target == tscore.ScriptTargetNone {
newOpts.Target = tscore.ScriptTargetES2022
}
if newOpts.Lib == nil {
newOpts.Lib = []string{"lib.es2022.d.ts"}
}
if newOpts.SkipLibCheck == tscore.TSUnknown {
newOpts.SkipLibCheck = tscore.TSTrue
}
if newOpts.Strict == tscore.TSUnknown {
newOpts.Strict = tscore.TSTrue
}
tsconfigData, _ := json.Marshal(parsedCommandLine.ParsedConfig)
tsconfigText = string(tsconfigData)
hadPreviousOpts := c.cachedOpts != nil
optsChanged := true
if c.cachedOpts != nil && reflect.DeepEqual(newOpts, c.cachedOpts) {
optsChanged = false
}
if optsChanged {
c.cachedOpts = newOpts
c.lastText = tsconfigText
}
c.lastModTime = currentModTime
c.mu.Unlock()
defer c.mu.Lock()
if hadPreviousOpts && optsChanged {
if c.onChange != nil {
c.onChange()
}
}
return newOpts, tsconfigText, nil
}
func boolToTristate(val bool) tscore.Tristate {
if val {
return tscore.TSTrue
}
return tscore.TSFalse
}
-11
View File
@@ -1,11 +0,0 @@
{
"compilerOptions": {
"target": "es2020",
"lib": ["es2020"],
"module": "ES2020",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"strict": true,
"noEmit": true
}
}
+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.
+1 -1
View File
@@ -257,7 +257,7 @@ function findSubstrateLauncher() {
if (Process.arch !== 'arm64')
return null;
const imp = Module.enumerateImports('/sbin/launchd').filter(imp => imp.name === 'posix_spawn')[0];
const imp = Process.mainModule.enumerateImports().find(imp => imp.name === 'posix_spawn');
if (imp === undefined)
return null;
const impl = imp.slot.readPointer().strip();
+424 -487
View File
@@ -8,546 +8,483 @@
"name": "frida-osanalytics-agent",
"version": "1.0.0",
"dependencies": {
"frida-objc-bridge": "^8.0.4"
"frida-objc-bridge": "^8.0.5"
},
"devDependencies": {
"@types/frida-gum": "^19.0.0",
"frida-compile": "^17.0.0"
"esbuild": "^0.25.5"
}
},
"node_modules/@frida/assert": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@frida/assert/-/assert-3.0.2.tgz",
"integrity": "sha512-JXJq5SbXGrM5EkjrZKfRmB29zOoEOix02NC6A5TSJ+C1GE/X051EinJJsuOO2pEOx7KZwpvAHvS0WXW0+levKg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/base64-js": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@frida/base64-js/-/base64-js-2.0.3.tgz",
"integrity": "sha512-2w0F+1TynOTCZ/v7du9LdHPWwq0lJhazjo2fF9upMyQmA1zHetT14fLuQ1v/6T0qPgyeEGkiSrybstU8EsgeUA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
"node_modules/@esbuild/aix-ppc64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz",
"integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==",
"cpu": [
"ppc64"
],
"license": "MIT"
},
"node_modules/@frida/buffer": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/@frida/buffer/-/buffer-7.0.4.tgz",
"integrity": "sha512-RxQ1lZRRiCJj7nhcCiD8xeJx0NsLpGGnjqsmTg7jShGmbnVFMN5W7+J+3gqdPSQhc/IxNBIWc6zRXVp4+qnYHg==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"license": "MIT",
"dependencies": {
"base64-js": "^1.5.1",
"ieee754": "^1.2.1"
}
},
"node_modules/@frida/crosspath": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@frida/crosspath/-/crosspath-3.0.0.tgz",
"integrity": "sha512-bNdO1spIPD2P40XtK89N49oZpJhstdlnkJZcD4yJ17jrdkm9Ctu0sd9MIEX6Z8Tm8ydhVJBAOMEKl9/R27onAQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "^17.0.36"
},
"engines": {
"node": ">=14.9.0"
"node": ">=18"
}
},
"node_modules/@frida/crypto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@frida/crypto/-/crypto-1.0.1.tgz",
"integrity": "sha512-WXTkVjESvX8TIVXIynJJv9BKSIdQP0Iis04StIXknkDi1ULdMlrypA9p5C4KW1H6GCkNsVnKbybpzsulYCTvag==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/diagnostics_channel": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/diagnostics_channel/-/diagnostics_channel-1.0.0.tgz",
"integrity": "sha512-mYX1jp/5Bpk24tHArJNx65iCk7qSuV8YJkdU0gFNVtJUXxfV8BG5WuPa4mL+ynxsbWWpsg/cwKZbLAepYKTdQQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/events": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/@frida/events/-/events-4.0.4.tgz",
"integrity": "sha512-qJVQ6VWHf9sjUKuiJzoCAC00frbpcwxeYfvQ+PP9LU/d70j+QvjWgYe98Qa3ekLaBU6r/AvWm8ThKCDUCLWrQQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.8.x"
}
},
"node_modules/@frida/http": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@frida/http/-/http-4.0.2.tgz",
"integrity": "sha512-cvkc7ex7GmVXVOWqtjXKBWUUbYEBgpNRKZbEEoMeI8KiIs8zejKwg+N7rx7296Ao+EP3+xcUr4wBVr3xLaUVfQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"http-parser-js": "^0.5.3"
}
},
"node_modules/@frida/http-parser-js": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/http-parser-js/-/http-parser-js-1.0.0.tgz",
"integrity": "sha512-2nMrNXt/OeTlWbqnE8AH4Sfz4I2+BGoN206dzKEyC/g2svtn83Xu+zuv/V3TkwrA27s26Mcy84ZwsXeNlqNxUQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/https": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/https/-/https-1.0.0.tgz",
"integrity": "sha512-OiqQ6qsALcWOktRLq07oJ0i6sH8eX6MXb/MdZS1qVKDRf6wchH4Pjn6fiLB+pt/OlYbggk+DOfpHwSdjTwuHMQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/ieee754": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@frida/ieee754/-/ieee754-2.0.2.tgz",
"integrity": "sha512-wlcUebnne4ENN7GDr5pTH598ZDLMVOsh0FjenxeVOe6u7ewZkz9gGRnLnZKJAm9kl5G6XhdxhI0cSXVQK/rQUw==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
"node_modules/@esbuild/android-arm": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz",
"integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==",
"cpu": [
"arm"
],
"license": "BSD-3-Clause"
},
"node_modules/@frida/net": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@frida/net/-/net-4.0.2.tgz",
"integrity": "sha512-qQRe7hQ+ZfCcG/SE3P1TRqQ9bmuK/T7wPCYaT4z56rBPWAxsaQbQHpX4fR6OrFaSDr7X0xJLsTbdIp9hGhhLZg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/os": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@frida/os/-/os-1.0.2.tgz",
"integrity": "sha512-3ISAiGNiyIya3QN2EHBCz1wqP0enTdSxP99wUeroeh8+AQRmgoOr/5TRnrVry8pe378anay3fmV/tdUMMSkehQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/path": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@frida/path/-/path-2.0.3.tgz",
"integrity": "sha512-2RQy36QatoC846fzBhBhV8sXMsSOBGoYvwTHeaE1zUdz7F4RNScP4QEekTTooBYWYX/XjiF36KQpYAzc9OYFtg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/process": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@frida/process/-/process-1.2.1.tgz",
"integrity": "sha512-nvCu22DstFW2ttGFtOKekHM7vnjbZm+XgtvavOt427GNT6uV7k0JYK9tnMbcLMRWv57DG6udAmuJlWs8Paq1ag==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/punycode": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@frida/punycode/-/punycode-3.0.0.tgz",
"integrity": "sha512-XVSDY2KamDs1D5/fTVgHcOSNxdU4kTboxzqJMBbTjcQC7XScIT9c0EfbwKCq7Kci6gWQdsHSCr7lU+9Oc4KAdg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/querystring": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/querystring/-/querystring-1.0.0.tgz",
"integrity": "sha512-15m1fOZPmoO/vWlgPJrG/J9/BJDz6a2/JpVGpS8ynNzo+fBhTznaStX5nHxUs24mVTqh/OqLo0EiYJM5WWHXxg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/readable-stream": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/@frida/readable-stream/-/readable-stream-4.1.3.tgz",
"integrity": "sha512-ntGUFmi+CryRGRJIK13a/VST2Ad19uivbln8Xd92vKPAARq+6vMIASDyZIqyl5BLRccfiyCHdYgrgQ6RI5rUig==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/reserved-words": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/reserved-words/-/reserved-words-1.0.0.tgz",
"integrity": "sha512-2yG/XxJlsGlk/mm6eZTb4OAaQEhkTI2qaFfZFtAsrA/XuCpuMWkS4y/guyBlsRu4hAuhK2HPmNM8+OLLK1zM9Q==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/stream": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@frida/stream/-/stream-1.0.2.tgz",
"integrity": "sha512-4OuaC1ztmEKgTq3WeBhsy8Oq+AwW9n9cYnvLklcC9jwD93AEwgbWpecLlxJCVuALvTMdhKPg0nQVfyGYP/i9Bw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@frida/readable-stream": "^4.1.3"
}
},
"node_modules/@frida/string_decoder": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@frida/string_decoder/-/string_decoder-2.0.0.tgz",
"integrity": "sha512-in371tYZMHQiW9HF5MS3JDw6Ao6tyBoq34UWy2rzOswYyMG1rpizh85ofi/yVkxDiaqybEZefxzkVittpPGT6g==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/terser": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/terser/-/terser-1.0.0.tgz",
"integrity": "sha512-59h9WuNzD1Rx/zwoWqQ/FW/4Y/Q3R91Eng2hEwdHapqiTDvtKbZ08F6CynCR7ZVinrh4tLYsF46AtVPTz1ys9g==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"@jridgewell/source-map": "^0.3.2",
"acorn": "^8.5.0",
"commander": "^2.20.0",
"source-map-support": "~0.5.20"
},
"bin": {
"terser": "bin/terser"
},
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=10"
"node": ">=18"
}
},
"node_modules/@frida/terser/node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/timers": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@frida/timers/-/timers-3.0.0.tgz",
"integrity": "sha512-3b+0igv10aT8TMxefrTAd06rActqbxJLY2Xkkq9vYcPBffB/yHszl0NYIp/5ko8WC3ecDYPU6bQiY6fjs72zTA==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/tty": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/tty/-/tty-1.0.0.tgz",
"integrity": "sha512-p/kjLnKYxEAB1MdYP8+5rKv9CsHzyA+0jg9BcGETzjQVKHHcroHDULRxDYUh+DC7qs6cpX8QdDQh9E+a6ydgsQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/url": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@frida/url/-/url-1.0.2.tgz",
"integrity": "sha512-ZKunbKJHMr8w2Eb/5K1avy0MzK1B998S17wYXNv3RmzBGxMm8S5T0F3qEpRxkU7/72P8m4izyQU87fWl+FjQsQ==",
"node_modules/@esbuild/android-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz",
"integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"dependencies": {
"@frida/punycode": "^3.0.0",
"@frida/querystring": "^1.0.0"
}
},
"node_modules/@frida/util": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@frida/util/-/util-1.0.3.tgz",
"integrity": "sha512-htcG3uDiRXv89ERVNNYhfase39kJ2X75ZARfrYcYEtJLFEsSk0nemM1YnEIR4CjrHvdvkWHrwgKkS+acOyoNEg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/vm": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@frida/vm/-/vm-2.0.0.tgz",
"integrity": "sha512-7fsjLWscZT5odNIBtg6qbLNI+vAk1xmii6H5W2kaYkMYt0vRohQEcDSUWacA+eaWlu5SvMjZI82Yibj/3G9pJw==",
"dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.8",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
"integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/set-array": "^1.2.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/trace-mapping": "^0.3.24"
},
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=6.0.0"
"node": ">=18"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"node_modules/@esbuild/android-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz",
"integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=6.0.0"
"node": ">=18"
}
},
"node_modules/@jridgewell/set-array": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
"node_modules/@esbuild/darwin-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz",
"integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=6.0.0"
"node": ">=18"
}
},
"node_modules/@jridgewell/source-map": {
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
"integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
"node_modules/@esbuild/darwin-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz",
"integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25"
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.25",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz",
"integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"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==",
"node_modules/@esbuild/freebsd-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz",
"integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT"
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@types/node": {
"version": "17.0.45",
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz",
"integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==",
"node_modules/@esbuild/linux-arm": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz",
"integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT"
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/acorn": {
"version": "8.14.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
"node_modules/@esbuild/linux-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz",
"integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz",
"integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz",
"integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz",
"integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==",
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz",
"integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz",
"integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz",
"integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz",
"integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz",
"integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz",
"integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz",
"integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz",
"integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz",
"integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz",
"integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz",
"integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz",
"integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/esbuild": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz",
"integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true,
"license": "MIT"
},
"node_modules/commander": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
"integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=16"
}
},
"node_modules/frida-compile": {
"version": "17.0.0",
"resolved": "https://registry.npmjs.org/frida-compile/-/frida-compile-17.0.0.tgz",
"integrity": "sha512-ixJRj14qLH/Z0ckFWd5fKeDMm0W2+2WDpSGnLRgpn0nuCQAbDHRCqVCWtPnV8uzPJmA6XOX0pujsMpYe9q9RRw==",
"dev": true,
"dependencies": {
"@frida/assert": "^3.0.1",
"@frida/base64-js": "^2.0.3",
"@frida/buffer": "^7.0.4",
"@frida/crosspath": "^3.0.0",
"@frida/crypto": "^1.0.1",
"@frida/diagnostics_channel": "^1.0.0",
"@frida/events": "^4.0.4",
"@frida/http": "^4.0.2",
"@frida/http-parser-js": "^1.0.0",
"@frida/https": "^1.0.0",
"@frida/ieee754": "^2.0.2",
"@frida/net": "^4.0.1",
"@frida/os": "^1.0.0",
"@frida/path": "^2.0.3",
"@frida/process": "^1.2.1",
"@frida/punycode": "^3.0.0",
"@frida/querystring": "^1.0.0",
"@frida/readable-stream": "^4.1.3",
"@frida/reserved-words": "^1.0.0",
"@frida/stream": "^1.0.2",
"@frida/string_decoder": "^2.0.0",
"@frida/terser": "^1.0.0",
"@frida/timers": "^3.0.0",
"@frida/tty": "^1.0.0",
"@frida/url": "^1.0.2",
"@frida/util": "^1.0.3",
"@frida/vm": "^2.0.0",
"commander": "^11.1.0",
"frida-fs": "^6.0.0",
"typed-emitter": "^2.1.0"
"node": ">=18"
},
"bin": {
"frida-compile": "dist/cli.js"
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.25.5",
"@esbuild/android-arm": "0.25.5",
"@esbuild/android-arm64": "0.25.5",
"@esbuild/android-x64": "0.25.5",
"@esbuild/darwin-arm64": "0.25.5",
"@esbuild/darwin-x64": "0.25.5",
"@esbuild/freebsd-arm64": "0.25.5",
"@esbuild/freebsd-x64": "0.25.5",
"@esbuild/linux-arm": "0.25.5",
"@esbuild/linux-arm64": "0.25.5",
"@esbuild/linux-ia32": "0.25.5",
"@esbuild/linux-loong64": "0.25.5",
"@esbuild/linux-mips64el": "0.25.5",
"@esbuild/linux-ppc64": "0.25.5",
"@esbuild/linux-riscv64": "0.25.5",
"@esbuild/linux-s390x": "0.25.5",
"@esbuild/linux-x64": "0.25.5",
"@esbuild/netbsd-arm64": "0.25.5",
"@esbuild/netbsd-x64": "0.25.5",
"@esbuild/openbsd-arm64": "0.25.5",
"@esbuild/openbsd-x64": "0.25.5",
"@esbuild/sunos-x64": "0.25.5",
"@esbuild/win32-arm64": "0.25.5",
"@esbuild/win32-ia32": "0.25.5",
"@esbuild/win32-x64": "0.25.5"
}
},
"node_modules/frida-fs": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/frida-fs/-/frida-fs-6.0.0.tgz",
"integrity": "sha512-I0fnKupZh7fU2ixwCIjJnEqNdhfm/SC1ZYBMy58EmeqOWSbjw1Dpy99mJ7BJdbk2KNXJeaBZGxDYLtn0J9S+UA==",
"dev": true,
"license": "MIT"
},
"node_modules/frida-objc-bridge": {
"version": "8.0.4",
"resolved": "https://registry.npmjs.org/frida-objc-bridge/-/frida-objc-bridge-8.0.4.tgz",
"integrity": "sha512-AUzwq/+TFtblQLTI97UPX22pBcvyG2oUde9380DXbcJ0zXts4n9JDVONHUr03aBowa0Le+bdBoVdCs7jyyjvlg==",
"version": "8.0.5",
"resolved": "https://registry.npmjs.org/frida-objc-bridge/-/frida-objc-bridge-8.0.5.tgz",
"integrity": "sha512-0xnL0VgxSQXgLj3S33S0kdAvLrCHSCIZb9HVraEgEyKnf9wOcu0KZ9fI5xzx0e0y+ry/g2Vl3yw9j3dsn92Ffg==",
"license": "LGPL-2.0 WITH WxWindows-exception-3.1"
},
"node_modules/http-parser-js": {
"version": "0.5.10",
"resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz",
"integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==",
"dev": true,
"license": "MIT"
},
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "BSD-3-Clause"
},
"node_modules/rxjs": {
"version": "7.8.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
"dev": true,
"license": "Apache-2.0",
"optional": true,
"dependencies": {
"tslib": "^2.1.0"
}
},
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dev": true,
"license": "MIT",
"dependencies": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"dev": true,
"license": "0BSD",
"optional": true
},
"node_modules/typed-emitter": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-2.1.0.tgz",
"integrity": "sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==",
"dev": true,
"license": "MIT",
"optionalDependencies": {
"rxjs": "*"
}
}
}
}
+4 -5
View File
@@ -2,15 +2,14 @@
"name": "frida-osanalytics-agent",
"version": "1.0.0",
"description": "Agent used by Frida's Darwin backend on iOS/iPadOS/tvOS",
"type": "module",
"scripts": {
"prepare": "npm run build",
"build": "frida-compile index.js -o osanalytics.js -S -c"
"build": "esbuild index.js --outfile=osanalytics.js --bundle --platform=node --target=es2022 --minify"
},
"devDependencies": {
"@types/frida-gum": "^19.0.0",
"frida-compile": "^17.0.0"
"esbuild": "^0.25.5"
},
"dependencies": {
"frida-objc-bridge": "^8.0.4"
"frida-objc-bridge": "^8.0.5"
}
}
+424 -487
View File
@@ -8,546 +8,483 @@
"name": "frida-reportcrash-agent",
"version": "1.0.0",
"dependencies": {
"frida-objc-bridge": "^8.0.4"
"frida-objc-bridge": "^8.0.5"
},
"devDependencies": {
"@types/frida-gum": "^19.0.0",
"frida-compile": "^17.0.0"
"esbuild": "^0.25.5"
}
},
"node_modules/@frida/assert": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@frida/assert/-/assert-3.0.2.tgz",
"integrity": "sha512-JXJq5SbXGrM5EkjrZKfRmB29zOoEOix02NC6A5TSJ+C1GE/X051EinJJsuOO2pEOx7KZwpvAHvS0WXW0+levKg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/base64-js": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@frida/base64-js/-/base64-js-2.0.3.tgz",
"integrity": "sha512-2w0F+1TynOTCZ/v7du9LdHPWwq0lJhazjo2fF9upMyQmA1zHetT14fLuQ1v/6T0qPgyeEGkiSrybstU8EsgeUA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
"node_modules/@esbuild/aix-ppc64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz",
"integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==",
"cpu": [
"ppc64"
],
"license": "MIT"
},
"node_modules/@frida/buffer": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/@frida/buffer/-/buffer-7.0.4.tgz",
"integrity": "sha512-RxQ1lZRRiCJj7nhcCiD8xeJx0NsLpGGnjqsmTg7jShGmbnVFMN5W7+J+3gqdPSQhc/IxNBIWc6zRXVp4+qnYHg==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"license": "MIT",
"dependencies": {
"base64-js": "^1.5.1",
"ieee754": "^1.2.1"
}
},
"node_modules/@frida/crosspath": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@frida/crosspath/-/crosspath-3.0.0.tgz",
"integrity": "sha512-bNdO1spIPD2P40XtK89N49oZpJhstdlnkJZcD4yJ17jrdkm9Ctu0sd9MIEX6Z8Tm8ydhVJBAOMEKl9/R27onAQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "^17.0.36"
},
"engines": {
"node": ">=14.9.0"
"node": ">=18"
}
},
"node_modules/@frida/crypto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@frida/crypto/-/crypto-1.0.1.tgz",
"integrity": "sha512-WXTkVjESvX8TIVXIynJJv9BKSIdQP0Iis04StIXknkDi1ULdMlrypA9p5C4KW1H6GCkNsVnKbybpzsulYCTvag==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/diagnostics_channel": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/diagnostics_channel/-/diagnostics_channel-1.0.0.tgz",
"integrity": "sha512-mYX1jp/5Bpk24tHArJNx65iCk7qSuV8YJkdU0gFNVtJUXxfV8BG5WuPa4mL+ynxsbWWpsg/cwKZbLAepYKTdQQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/events": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/@frida/events/-/events-4.0.4.tgz",
"integrity": "sha512-qJVQ6VWHf9sjUKuiJzoCAC00frbpcwxeYfvQ+PP9LU/d70j+QvjWgYe98Qa3ekLaBU6r/AvWm8ThKCDUCLWrQQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.8.x"
}
},
"node_modules/@frida/http": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@frida/http/-/http-4.0.2.tgz",
"integrity": "sha512-cvkc7ex7GmVXVOWqtjXKBWUUbYEBgpNRKZbEEoMeI8KiIs8zejKwg+N7rx7296Ao+EP3+xcUr4wBVr3xLaUVfQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"http-parser-js": "^0.5.3"
}
},
"node_modules/@frida/http-parser-js": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/http-parser-js/-/http-parser-js-1.0.0.tgz",
"integrity": "sha512-2nMrNXt/OeTlWbqnE8AH4Sfz4I2+BGoN206dzKEyC/g2svtn83Xu+zuv/V3TkwrA27s26Mcy84ZwsXeNlqNxUQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/https": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/https/-/https-1.0.0.tgz",
"integrity": "sha512-OiqQ6qsALcWOktRLq07oJ0i6sH8eX6MXb/MdZS1qVKDRf6wchH4Pjn6fiLB+pt/OlYbggk+DOfpHwSdjTwuHMQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/ieee754": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@frida/ieee754/-/ieee754-2.0.2.tgz",
"integrity": "sha512-wlcUebnne4ENN7GDr5pTH598ZDLMVOsh0FjenxeVOe6u7ewZkz9gGRnLnZKJAm9kl5G6XhdxhI0cSXVQK/rQUw==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
"node_modules/@esbuild/android-arm": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz",
"integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==",
"cpu": [
"arm"
],
"license": "BSD-3-Clause"
},
"node_modules/@frida/net": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@frida/net/-/net-4.0.2.tgz",
"integrity": "sha512-qQRe7hQ+ZfCcG/SE3P1TRqQ9bmuK/T7wPCYaT4z56rBPWAxsaQbQHpX4fR6OrFaSDr7X0xJLsTbdIp9hGhhLZg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/os": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@frida/os/-/os-1.0.2.tgz",
"integrity": "sha512-3ISAiGNiyIya3QN2EHBCz1wqP0enTdSxP99wUeroeh8+AQRmgoOr/5TRnrVry8pe378anay3fmV/tdUMMSkehQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/path": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@frida/path/-/path-2.0.3.tgz",
"integrity": "sha512-2RQy36QatoC846fzBhBhV8sXMsSOBGoYvwTHeaE1zUdz7F4RNScP4QEekTTooBYWYX/XjiF36KQpYAzc9OYFtg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/process": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@frida/process/-/process-1.2.1.tgz",
"integrity": "sha512-nvCu22DstFW2ttGFtOKekHM7vnjbZm+XgtvavOt427GNT6uV7k0JYK9tnMbcLMRWv57DG6udAmuJlWs8Paq1ag==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/punycode": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@frida/punycode/-/punycode-3.0.0.tgz",
"integrity": "sha512-XVSDY2KamDs1D5/fTVgHcOSNxdU4kTboxzqJMBbTjcQC7XScIT9c0EfbwKCq7Kci6gWQdsHSCr7lU+9Oc4KAdg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/querystring": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/querystring/-/querystring-1.0.0.tgz",
"integrity": "sha512-15m1fOZPmoO/vWlgPJrG/J9/BJDz6a2/JpVGpS8ynNzo+fBhTznaStX5nHxUs24mVTqh/OqLo0EiYJM5WWHXxg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/readable-stream": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/@frida/readable-stream/-/readable-stream-4.1.3.tgz",
"integrity": "sha512-ntGUFmi+CryRGRJIK13a/VST2Ad19uivbln8Xd92vKPAARq+6vMIASDyZIqyl5BLRccfiyCHdYgrgQ6RI5rUig==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/reserved-words": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/reserved-words/-/reserved-words-1.0.0.tgz",
"integrity": "sha512-2yG/XxJlsGlk/mm6eZTb4OAaQEhkTI2qaFfZFtAsrA/XuCpuMWkS4y/guyBlsRu4hAuhK2HPmNM8+OLLK1zM9Q==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/stream": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@frida/stream/-/stream-1.0.2.tgz",
"integrity": "sha512-4OuaC1ztmEKgTq3WeBhsy8Oq+AwW9n9cYnvLklcC9jwD93AEwgbWpecLlxJCVuALvTMdhKPg0nQVfyGYP/i9Bw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@frida/readable-stream": "^4.1.3"
}
},
"node_modules/@frida/string_decoder": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@frida/string_decoder/-/string_decoder-2.0.0.tgz",
"integrity": "sha512-in371tYZMHQiW9HF5MS3JDw6Ao6tyBoq34UWy2rzOswYyMG1rpizh85ofi/yVkxDiaqybEZefxzkVittpPGT6g==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/terser": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/terser/-/terser-1.0.0.tgz",
"integrity": "sha512-59h9WuNzD1Rx/zwoWqQ/FW/4Y/Q3R91Eng2hEwdHapqiTDvtKbZ08F6CynCR7ZVinrh4tLYsF46AtVPTz1ys9g==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"@jridgewell/source-map": "^0.3.2",
"acorn": "^8.5.0",
"commander": "^2.20.0",
"source-map-support": "~0.5.20"
},
"bin": {
"terser": "bin/terser"
},
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=10"
"node": ">=18"
}
},
"node_modules/@frida/terser/node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/timers": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@frida/timers/-/timers-3.0.0.tgz",
"integrity": "sha512-3b+0igv10aT8TMxefrTAd06rActqbxJLY2Xkkq9vYcPBffB/yHszl0NYIp/5ko8WC3ecDYPU6bQiY6fjs72zTA==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/tty": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/tty/-/tty-1.0.0.tgz",
"integrity": "sha512-p/kjLnKYxEAB1MdYP8+5rKv9CsHzyA+0jg9BcGETzjQVKHHcroHDULRxDYUh+DC7qs6cpX8QdDQh9E+a6ydgsQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/url": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@frida/url/-/url-1.0.2.tgz",
"integrity": "sha512-ZKunbKJHMr8w2Eb/5K1avy0MzK1B998S17wYXNv3RmzBGxMm8S5T0F3qEpRxkU7/72P8m4izyQU87fWl+FjQsQ==",
"node_modules/@esbuild/android-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz",
"integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"dependencies": {
"@frida/punycode": "^3.0.0",
"@frida/querystring": "^1.0.0"
}
},
"node_modules/@frida/util": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@frida/util/-/util-1.0.3.tgz",
"integrity": "sha512-htcG3uDiRXv89ERVNNYhfase39kJ2X75ZARfrYcYEtJLFEsSk0nemM1YnEIR4CjrHvdvkWHrwgKkS+acOyoNEg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/vm": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@frida/vm/-/vm-2.0.0.tgz",
"integrity": "sha512-7fsjLWscZT5odNIBtg6qbLNI+vAk1xmii6H5W2kaYkMYt0vRohQEcDSUWacA+eaWlu5SvMjZI82Yibj/3G9pJw==",
"dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.8",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
"integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/set-array": "^1.2.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/trace-mapping": "^0.3.24"
},
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=6.0.0"
"node": ">=18"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"node_modules/@esbuild/android-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz",
"integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=6.0.0"
"node": ">=18"
}
},
"node_modules/@jridgewell/set-array": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
"node_modules/@esbuild/darwin-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz",
"integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=6.0.0"
"node": ">=18"
}
},
"node_modules/@jridgewell/source-map": {
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
"integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
"node_modules/@esbuild/darwin-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz",
"integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25"
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.25",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz",
"integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"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==",
"node_modules/@esbuild/freebsd-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz",
"integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT"
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@types/node": {
"version": "17.0.45",
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz",
"integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==",
"node_modules/@esbuild/linux-arm": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz",
"integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT"
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/acorn": {
"version": "8.14.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
"node_modules/@esbuild/linux-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz",
"integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz",
"integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz",
"integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz",
"integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==",
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz",
"integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz",
"integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz",
"integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz",
"integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz",
"integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz",
"integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz",
"integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz",
"integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz",
"integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz",
"integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz",
"integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz",
"integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/esbuild": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz",
"integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true,
"license": "MIT"
},
"node_modules/commander": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
"integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=16"
}
},
"node_modules/frida-compile": {
"version": "17.0.0",
"resolved": "https://registry.npmjs.org/frida-compile/-/frida-compile-17.0.0.tgz",
"integrity": "sha512-ixJRj14qLH/Z0ckFWd5fKeDMm0W2+2WDpSGnLRgpn0nuCQAbDHRCqVCWtPnV8uzPJmA6XOX0pujsMpYe9q9RRw==",
"dev": true,
"dependencies": {
"@frida/assert": "^3.0.1",
"@frida/base64-js": "^2.0.3",
"@frida/buffer": "^7.0.4",
"@frida/crosspath": "^3.0.0",
"@frida/crypto": "^1.0.1",
"@frida/diagnostics_channel": "^1.0.0",
"@frida/events": "^4.0.4",
"@frida/http": "^4.0.2",
"@frida/http-parser-js": "^1.0.0",
"@frida/https": "^1.0.0",
"@frida/ieee754": "^2.0.2",
"@frida/net": "^4.0.1",
"@frida/os": "^1.0.0",
"@frida/path": "^2.0.3",
"@frida/process": "^1.2.1",
"@frida/punycode": "^3.0.0",
"@frida/querystring": "^1.0.0",
"@frida/readable-stream": "^4.1.3",
"@frida/reserved-words": "^1.0.0",
"@frida/stream": "^1.0.2",
"@frida/string_decoder": "^2.0.0",
"@frida/terser": "^1.0.0",
"@frida/timers": "^3.0.0",
"@frida/tty": "^1.0.0",
"@frida/url": "^1.0.2",
"@frida/util": "^1.0.3",
"@frida/vm": "^2.0.0",
"commander": "^11.1.0",
"frida-fs": "^6.0.0",
"typed-emitter": "^2.1.0"
"node": ">=18"
},
"bin": {
"frida-compile": "dist/cli.js"
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.25.5",
"@esbuild/android-arm": "0.25.5",
"@esbuild/android-arm64": "0.25.5",
"@esbuild/android-x64": "0.25.5",
"@esbuild/darwin-arm64": "0.25.5",
"@esbuild/darwin-x64": "0.25.5",
"@esbuild/freebsd-arm64": "0.25.5",
"@esbuild/freebsd-x64": "0.25.5",
"@esbuild/linux-arm": "0.25.5",
"@esbuild/linux-arm64": "0.25.5",
"@esbuild/linux-ia32": "0.25.5",
"@esbuild/linux-loong64": "0.25.5",
"@esbuild/linux-mips64el": "0.25.5",
"@esbuild/linux-ppc64": "0.25.5",
"@esbuild/linux-riscv64": "0.25.5",
"@esbuild/linux-s390x": "0.25.5",
"@esbuild/linux-x64": "0.25.5",
"@esbuild/netbsd-arm64": "0.25.5",
"@esbuild/netbsd-x64": "0.25.5",
"@esbuild/openbsd-arm64": "0.25.5",
"@esbuild/openbsd-x64": "0.25.5",
"@esbuild/sunos-x64": "0.25.5",
"@esbuild/win32-arm64": "0.25.5",
"@esbuild/win32-ia32": "0.25.5",
"@esbuild/win32-x64": "0.25.5"
}
},
"node_modules/frida-fs": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/frida-fs/-/frida-fs-6.0.0.tgz",
"integrity": "sha512-I0fnKupZh7fU2ixwCIjJnEqNdhfm/SC1ZYBMy58EmeqOWSbjw1Dpy99mJ7BJdbk2KNXJeaBZGxDYLtn0J9S+UA==",
"dev": true,
"license": "MIT"
},
"node_modules/frida-objc-bridge": {
"version": "8.0.4",
"resolved": "https://registry.npmjs.org/frida-objc-bridge/-/frida-objc-bridge-8.0.4.tgz",
"integrity": "sha512-AUzwq/+TFtblQLTI97UPX22pBcvyG2oUde9380DXbcJ0zXts4n9JDVONHUr03aBowa0Le+bdBoVdCs7jyyjvlg==",
"version": "8.0.5",
"resolved": "https://registry.npmjs.org/frida-objc-bridge/-/frida-objc-bridge-8.0.5.tgz",
"integrity": "sha512-0xnL0VgxSQXgLj3S33S0kdAvLrCHSCIZb9HVraEgEyKnf9wOcu0KZ9fI5xzx0e0y+ry/g2Vl3yw9j3dsn92Ffg==",
"license": "LGPL-2.0 WITH WxWindows-exception-3.1"
},
"node_modules/http-parser-js": {
"version": "0.5.10",
"resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz",
"integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==",
"dev": true,
"license": "MIT"
},
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "BSD-3-Clause"
},
"node_modules/rxjs": {
"version": "7.8.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
"dev": true,
"license": "Apache-2.0",
"optional": true,
"dependencies": {
"tslib": "^2.1.0"
}
},
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dev": true,
"license": "MIT",
"dependencies": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"dev": true,
"license": "0BSD",
"optional": true
},
"node_modules/typed-emitter": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-2.1.0.tgz",
"integrity": "sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==",
"dev": true,
"license": "MIT",
"optionalDependencies": {
"rxjs": "*"
}
}
}
}
+4 -5
View File
@@ -2,15 +2,14 @@
"name": "frida-reportcrash-agent",
"version": "1.0.0",
"description": "Agent used by Frida's Darwin backend on iOS/iPadOS/tvOS",
"type": "module",
"scripts": {
"prepare": "npm run build",
"build": "frida-compile index.js -o reportcrash.js -S -c"
"build": "esbuild index.js --outfile=reportcrash.js --bundle --platform=node --target=es2022 --minify"
},
"devDependencies": {
"@types/frida-gum": "^19.0.0",
"frida-compile": "^17.0.0"
"esbuild": "^0.25.5"
},
"dependencies": {
"frida-objc-bridge": "^8.0.4"
"frida-objc-bridge": "^8.0.5"
}
}
+2
View File
@@ -109,6 +109,8 @@ _frida_get_springboard_api (void)
gum_interceptor_replace (interceptor, frida_xpc_look_up_endpoint, frida_replacement_xpc_look_up_endpoint, NULL, NULL);
else
g_error ("Unable to locate _xpc_look_up_endpoint(); please file a bug");
g_object_unref (interceptor);
}
#endif
+5 -1
View File
@@ -1459,7 +1459,9 @@ namespace Frida {
break;
}
}
assert (session_id != null);
if (session_id == null)
return;
agent_sessions.unset (session_id);
if (may_block) {
@@ -1483,6 +1485,8 @@ namespace Frida {
Promise<bool> detach_request;
if (pending_detach_requests.unset (id, out detach_request))
detach_request.resolve (true);
else if (session != null)
agent_sessions.unset (id);
}
private void on_spawn_added (HostSpawnInfo info) {
+4 -1
View File
@@ -808,7 +808,10 @@ 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);
+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)
+32 -2
View File
@@ -1,5 +1,7 @@
#include "upload-api.h"
static uint64_t frida_query_debugger_mapping_enforced (const FridaUploadApi * api);
uint64_t
frida_listen (int rx_buffer_size, const FridaUploadApi * api)
{
@@ -35,7 +37,7 @@ frida_listen (int rx_buffer_size, const FridaUploadApi * api)
if (res == -1)
goto listen_failed;
return ((uint64_t) fd << 16) | ntohs (addr.sin6_port);
return (frida_query_debugger_mapping_enforced (api) << 56) | ((uint64_t) fd << 16) | ntohs (addr.sin6_port);
socket_failed:
{
@@ -67,10 +69,38 @@ failure:
if (fd != -1)
api->close (fd);
return ((uint64_t) error_code << 56);
return ((uint64_t) error_code << 57);
}
}
static uint64_t
frida_query_debugger_mapping_enforced (const FridaUploadApi * api)
{
uint64_t is_enforced;
mach_port_t task;
int page_size;
mach_vm_address_t start;
vm_address_t addr;
vm_prot_t cur_prot, max_prot;
task = api->_mach_task_self ();
page_size = api->getpagesize ();
api->mach_vm_allocate (task, &start, page_size, VM_FLAGS_ANYWHERE);
*(uint32_t *) start = 1337;
api->mprotect ((void *) start, page_size, PROT_READ | PROT_EXEC);
addr = 0;
api->vm_remap (task, &addr, page_size, 0, VM_FLAGS_ANYWHERE, task, start, FALSE, &cur_prot, &max_prot, VM_INHERIT_NONE);
is_enforced = (cur_prot & (VM_PROT_READ | VM_PROT_EXECUTE)) != (VM_PROT_READ | VM_PROT_EXECUTE);
api->mach_vm_deallocate (task, addr, page_size);
api->mach_vm_deallocate (task, start, page_size);
return is_enforced;
}
#ifdef BUILDING_TEST_PROGRAM
#include <assert.h>
+21 -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:
+308 -269
View File
@@ -185,7 +185,9 @@ 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 lldb.spray_pages (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];
@@ -355,6 +357,8 @@ namespace Frida.Fruity.Injector {
.end_object ()
.set_member_name ("teardown")
.add_string_value ("full")
.set_member_name ("code_signing")
.add_string_value ("optional")
.end_object ();
string raw_config = Json.to_string (config.get_root (), false);
string config_param = "frida_gadget_config=" + Base64.encode (raw_config.data);
@@ -362,7 +366,10 @@ namespace Frida.Fruity.Injector {
var apple_strv_builder = new StringVectorBuilder (args_builder);
apple_strv_builder
.append_string (range_param)
.append_string (range_param);
var config_offset = args_builder.offset;
apple_strv_builder
.append_string (config_param)
.append_terminator ();
var apple_strv_offset = apple_strv_builder.append_placeholder ();
@@ -375,17 +382,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,13 +409,19 @@ 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 >> 57) & 0x7f);
bool debugger_mapping_enforced = ((listen_result >> 56) & 0x1) != 0;
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);
if (debugger_mapping_enforced) {
string overwrite_config_param = "frida_gadget_config=" + Base64.encode (raw_config.replace ("optional", "required", 1).data);
yield lldb.write_byte_array (args + config_offset, new Bytes.static (overwrite_config_param.data), cancellable);
}
yield lldb.write_byte_array (code, new Bytes.static (UPLOAD_RECEIVER_CODE), cancellable);
// The generated session ID only acts as a sanitycheck for now
@@ -565,17 +580,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 +605,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,184 +629,205 @@ 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");
}
}
/* Compiled from helpers/upload-listener.c */
private const uint8[] UPLOAD_LISTENER_CODE = {
0xff, 0x83, 0x01, 0xd1, 0xf6, 0x57, 0x03, 0xa9, 0xf4, 0x4f, 0x04, 0xa9, 0xfd, 0x7b, 0x05, 0xa9, 0xfd, 0x43, 0x01,
0x91, 0xf3, 0x03, 0x01, 0xaa, 0x08, 0x00, 0x00, 0x90, 0x08, 0xb1, 0x04, 0x91, 0xa0, 0xc3, 0x1d, 0xb8, 0x00, 0x01,
0xc0, 0x3d, 0xe0, 0x07, 0x80, 0x3d, 0x00, 0xc1, 0xc0, 0x3c, 0xe0, 0xc3, 0x81, 0x3c, 0x28, 0x00, 0x40, 0xf9, 0xc0,
0x03, 0x80, 0x52, 0x21, 0x00, 0x80, 0x52, 0x02, 0x00, 0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0x1f, 0x04, 0x00, 0x31,
0xc0, 0x04, 0x00, 0x54, 0xf4, 0x03, 0x00, 0xaa, 0x68, 0x06, 0x40, 0xf9, 0xa3, 0x93, 0x00, 0xd1, 0xe1, 0xff, 0x9f,
0x52, 0x42, 0x00, 0x82, 0x52, 0x84, 0x00, 0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0x1f, 0x04, 0x00, 0x31, 0xe0, 0x03,
0x00, 0x54, 0x88, 0x03, 0x80, 0x52, 0xe8, 0x0f, 0x00, 0xb9, 0x68, 0x0a, 0x40, 0xf9, 0xe1, 0x43, 0x00, 0x91, 0xe0,
0x03, 0x14, 0xaa, 0x82, 0x03, 0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0x1f, 0x04, 0x00, 0x31, 0x00, 0x03, 0x00, 0x54,
0x68, 0x12, 0x40, 0xf9, 0xe1, 0x43, 0x00, 0x91, 0xe2, 0x33, 0x00, 0x91, 0xe0, 0x03, 0x14, 0xaa, 0x00, 0x01, 0x3f,
0xd6, 0x1f, 0x04, 0x00, 0x31, 0x60, 0x02, 0x00, 0x54, 0x68, 0x0e, 0x40, 0xf9, 0xe0, 0x03, 0x14, 0xaa, 0x21, 0x00,
0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0x1f, 0x04, 0x00, 0x31, 0xe0, 0x01, 0x00, 0x54, 0x88, 0x7e, 0x40, 0x93, 0xe9,
0x27, 0x40, 0x79, 0x29, 0x09, 0xc0, 0x5a, 0x35, 0x7d, 0x10, 0x53, 0x15, 0xbd, 0x70, 0xb3, 0x0d, 0x00, 0x00, 0x14,
0x15, 0x20, 0xe0, 0xd2, 0x0b, 0x00, 0x00, 0x14, 0x15, 0x40, 0xe0, 0xd2, 0x06, 0x00, 0x00, 0x14, 0x15, 0x60, 0xe0,
0xd2, 0x04, 0x00, 0x00, 0x14, 0x15, 0x80, 0xe0, 0xd2, 0x02, 0x00, 0x00, 0x14, 0x15, 0xa0, 0xe0, 0xd2, 0x68, 0x42,
0x40, 0xf9, 0xe0, 0x03, 0x14, 0xaa, 0x00, 0x01, 0x3f, 0xd6, 0xe0, 0x03, 0x15, 0xaa, 0xfd, 0x7b, 0x45, 0xa9, 0xf4,
0x4f, 0x44, 0xa9, 0xf6, 0x57, 0x43, 0xa9, 0xff, 0x83, 0x01, 0x91, 0xc0, 0x03, 0x5f, 0xd6, 0x00, 0x1e, 0x00, 0x00,
0xff, 0x83, 0x02, 0xd1, 0xf8, 0x5f, 0x06, 0xa9, 0xf6, 0x57, 0x07, 0xa9, 0xf4, 0x4f, 0x08, 0xa9, 0xfd, 0x7b, 0x09,
0xa9, 0xfd, 0x43, 0x02, 0x91, 0xf3, 0x03, 0x01, 0xaa, 0x08, 0x00, 0x00, 0x90, 0x08, 0xf1, 0x07, 0x91, 0xe0, 0x47,
0x00, 0xb9, 0x00, 0x01, 0xc0, 0x3d, 0xe0, 0x0b, 0x80, 0x3d, 0x00, 0xc1, 0xc0, 0x3c, 0xe0, 0xc3, 0x82, 0x3c, 0x28,
0x00, 0x40, 0xf9, 0xc0, 0x03, 0x80, 0x52, 0x21, 0x00, 0x80, 0x52, 0x02, 0x00, 0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6,
0x1f, 0x04, 0x00, 0x31, 0xa0, 0x0a, 0x00, 0x54, 0xf4, 0x03, 0x00, 0xaa, 0x68, 0x06, 0x40, 0xf9, 0xe3, 0x13, 0x01,
0x91, 0xe1, 0xff, 0x9f, 0x52, 0x42, 0x00, 0x82, 0x52, 0x84, 0x00, 0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0x1f, 0x04,
0x00, 0x31, 0xc0, 0x09, 0x00, 0x54, 0x88, 0x03, 0x80, 0x52, 0xe8, 0x1f, 0x00, 0xb9, 0x68, 0x0a, 0x40, 0xf9, 0xe1,
0x83, 0x00, 0x91, 0xe0, 0x03, 0x14, 0xaa, 0x82, 0x03, 0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0x1f, 0x04, 0x00, 0x31,
0xe0, 0x08, 0x00, 0x54, 0x68, 0x12, 0x40, 0xf9, 0xe1, 0x83, 0x00, 0x91, 0xe2, 0x73, 0x00, 0x91, 0xe0, 0x03, 0x14,
0xaa, 0x00, 0x01, 0x3f, 0xd6, 0x1f, 0x04, 0x00, 0x31, 0x40, 0x08, 0x00, 0x54, 0x68, 0x0e, 0x40, 0xf9, 0xe0, 0x03,
0x14, 0xaa, 0x21, 0x00, 0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0x1f, 0x04, 0x00, 0x31, 0xc0, 0x07, 0x00, 0x54, 0x68,
0x36, 0x40, 0xf9, 0x00, 0x01, 0x3f, 0xd6, 0xf5, 0x03, 0x00, 0xaa, 0x68, 0x26, 0x40, 0xf9, 0x00, 0x01, 0x3f, 0xd6,
0x68, 0x3a, 0x40, 0xf9, 0x16, 0x7c, 0x40, 0x93, 0xa1, 0xe3, 0x00, 0xd1, 0xe0, 0x03, 0x15, 0xaa, 0xe2, 0x03, 0x16,
0xaa, 0x23, 0x00, 0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0xa0, 0x83, 0x5c, 0xf8, 0x28, 0xa7, 0x80, 0x52, 0x08, 0x00,
0x00, 0xb9, 0x68, 0x2a, 0x40, 0xf9, 0xb7, 0x00, 0x80, 0x52, 0xe1, 0x03, 0x16, 0xaa, 0xa2, 0x00, 0x80, 0x52, 0x00,
0x01, 0x3f, 0xd6, 0xbf, 0x03, 0x1c, 0xf8, 0x68, 0x42, 0x40, 0xf9, 0xa6, 0x83, 0x5c, 0xf8, 0x49, 0x00, 0x80, 0x52,
0xe9, 0x13, 0x00, 0xb9, 0xe9, 0x23, 0x01, 0x91, 0xaa, 0x13, 0x01, 0xd1, 0xea, 0x27, 0x00, 0xa9, 0xa1, 0x03, 0x01,
0xd1, 0xe0, 0x03, 0x15, 0xaa, 0xe2, 0x03, 0x16, 0xaa, 0x03, 0x00, 0x80, 0xd2, 0x24, 0x00, 0x80, 0x52, 0xe5, 0x03,
0x15, 0xaa, 0x07, 0x00, 0x80, 0x52, 0x00, 0x01, 0x3f, 0xd6, 0xa8, 0xc3, 0x5b, 0xb8, 0xff, 0x02, 0x28, 0x6a, 0xf7,
0x07, 0x9f, 0x1a, 0x68, 0x3e, 0x40, 0xf9, 0xa1, 0x03, 0x5c, 0xf8, 0x1f, 0x00, 0x00, 0x94, 0x68, 0x3e, 0x40, 0xf9,
0xa1, 0x83, 0x5c, 0xf8, 0x1c, 0x00, 0x00, 0x94, 0xe8, 0x1e, 0x48, 0xd3, 0x89, 0x7e, 0x40, 0x93, 0x08, 0x41, 0x09,
0xaa, 0xe9, 0x47, 0x40, 0x79, 0x29, 0x09, 0xc0, 0x5a, 0x29, 0x7d, 0x10, 0x53, 0x15, 0x01, 0x09, 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, 0x49,
0xa9, 0xf4, 0x4f, 0x48, 0xa9, 0xf6, 0x57, 0x47, 0xa9, 0xf8, 0x5f, 0x46, 0xa9, 0xff, 0x83, 0x02, 0x91, 0xc0, 0x03,
0x5f, 0xd6, 0xe0, 0x03, 0x15, 0xaa, 0xe2, 0x03, 0x16, 0xaa, 0x00, 0x01, 0x1f, 0xd6, 0x00, 0x1e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00
0x00, 0x00, 0x00, 0x00
};
/* 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,
0x79, 0x02, 0x00, 0x94, 0xa8, 0x27, 0x77, 0xa9, 0x1f, 0x00, 0x00, 0x71, 0x00, 0x11, 0x59, 0xfa, 0x20, 0x01, 0x58,
0xfa, 0x60, 0x00, 0x00, 0x54, 0x84, 0x02, 0x00, 0x94, 0xe8, 0xff, 0xff, 0x17, 0x7a, 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, 0x64, 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, 0xf2, 0x21, 0x91, 0x30, 0x7a, 0xb0, 0xb8, 0x11, 0x00, 0x00, 0x10, 0x30,
0x02, 0x10, 0x8b, 0x00, 0x02, 0x1f, 0xd6, 0xa1, 0x83, 0x01, 0xd1, 0x50, 0x02, 0x00, 0x94, 0xe0, 0x38, 0x00, 0x34,
0xa1, 0xe3, 0x02, 0xd1, 0xe0, 0x03, 0x17, 0xaa, 0x82, 0x00, 0x80, 0x52, 0x50, 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, 0xba, 0x01, 0x00, 0x94, 0x80, 0x2d, 0x00, 0x34,
0x68, 0x2f, 0x40, 0xf9, 0x40, 0x02, 0x00, 0x94, 0x68, 0x33, 0x40, 0xf9, 0x3e, 0x02, 0x00, 0x94, 0x33, 0x00, 0x80,
0x52, 0x67, 0x01, 0x00, 0x14, 0xa1, 0x83, 0x01, 0xd1, 0x21, 0x02, 0x00, 0x94, 0x00, 0x33, 0x00, 0x34, 0xa1, 0xe3,
0x02, 0xd1, 0xe0, 0x03, 0x17, 0xaa, 0x82, 0x00, 0x80, 0x52, 0x21, 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, 0x22, 0x02, 0x00, 0x94, 0x73, 0x06, 0x00, 0x11, 0xf6, 0xff, 0xff, 0x17, 0xa1, 0x83, 0x02, 0xd1, 0x0c, 0x02,
0x00, 0x94, 0x60, 0x30, 0x00, 0x34, 0xa1, 0xc3, 0x02, 0xd1, 0x09, 0x02, 0x00, 0x94, 0x00, 0x30, 0x00, 0x34, 0xa1,
0xe3, 0x02, 0xd1, 0x06, 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, 0xd9, 0x01, 0x00, 0x94, 0x00, 0x2a, 0x00,
0x34, 0xa1, 0x83, 0x02, 0xd1, 0xe0, 0x03, 0x17, 0xaa, 0x82, 0x00, 0x80, 0x52, 0xd9, 0x01, 0x00, 0x94, 0x60, 0x29,
0x00, 0x34, 0xa1, 0xc3, 0x02, 0xd1, 0xe0, 0x03, 0x17, 0xaa, 0x82, 0x00, 0x80, 0x52, 0xd4, 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, 0xc5, 0x01, 0x00,
0x94, 0x80, 0x27, 0x00, 0x34, 0xa1, 0x83, 0x02, 0xd1, 0xc2, 0x01, 0x00, 0x94, 0x20, 0x27, 0x00, 0x34, 0xa1, 0xc3,
0x02, 0xd1, 0xe0, 0x03, 0x17, 0xaa, 0x42, 0x00, 0x80, 0x52, 0xc2, 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, 0xb4, 0x01, 0x00, 0x94, 0xa0, 0x24, 0x00, 0x34, 0xa1, 0xe3,
0x02, 0xd1, 0xe0, 0x03, 0x17, 0xaa, 0x42, 0x00, 0x80, 0x52, 0xaf, 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, 0xa3, 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, 0x5d, 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, 0x75, 0x01, 0x00, 0x94, 0x80, 0x1d,
0x00, 0x34, 0xa1, 0x93, 0x02, 0xd1, 0xe0, 0x03, 0x17, 0xaa, 0x82, 0x00, 0x80, 0x52, 0x75, 0x01, 0x00, 0x94, 0xe0,
0x1c, 0x00, 0x34, 0xa1, 0x83, 0x02, 0xd1, 0x6d, 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, 0x72, 0x01, 0x00, 0x94, 0x73, 0x06, 0x00, 0x11, 0xf5, 0xff, 0xff, 0x17, 0x6b, 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, 0x4f, 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, 0x62, 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, 0xc1, 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, 0xb3, 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, 0x9d, 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, 0x9e, 0x00, 0x00, 0x94, 0x68, 0x1b, 0x40, 0xf9,
0xe0, 0x03, 0x15, 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, 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, 0x62, 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) {
@@ -1202,73 +1242,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 +1382,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) {
+11 -1
View File
@@ -454,7 +454,7 @@ namespace Frida.Fruity {
write_entry (entry);
size_t offset_table_offset = (size_t) seekable.tell ();
offset_size = compute_offset_size (sorted_entries.last ().offset);
offset_size = compute_offset_size (offset_table_offset);
foreach (var entry in sorted_entries)
write_offset (entry.offset);
@@ -1088,6 +1088,11 @@ namespace Frida.Fruity {
}
public void write_dict (PlistDict dict) {
if (dict.is_empty) {
write_line ("<dict/>");
return;
}
write_line ("<dict>");
level++;
@@ -1114,6 +1119,11 @@ namespace Frida.Fruity {
}
public void write_array (PlistArray array) {
if (array.is_empty) {
write_line ("<array/>");
return;
}
write_line ("<array>");
level++;
+46 -1
View File
@@ -508,6 +508,41 @@ namespace Frida.GDB {
yield write_byte_array (address, new Bytes ({ val ? 1 : 0 }), cancellable);
}
public async void spray_pages (uint64 address, size_t size, size_t page_size, Cancellable? cancellable = null)
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 = 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> ();
perform_execute.begin (builder.build (), cancellable, request);
builder.reset ();
if (is_last)
last_write = request.future;
}
yield last_write.wait_async (cancellable);
}
public BufferBuilder make_buffer_builder () {
return new BufferBuilder (byte_order, pointer_size);
}
@@ -729,6 +764,16 @@ namespace Frida.GDB {
check_execute_response (response);
}
private 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 +1723,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 {
+22
View File
@@ -0,0 +1,22 @@
import esbuild from 'esbuild';
import alias from 'esbuild-plugin-alias';
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const BUFFER_SHIM = require.resolve('@frida/buffer');
esbuild.build({
entryPoints: ['index.js'],
outfile: 'system-server.js',
bundle: true,
platform: 'node',
target: ['es2022'],
legalComments: 'none',
minify: true,
plugins: [
alias({
'buffer': BUFFER_SHIM,
'node:buffer': BUFFER_SHIM,
}),
],
}).catch(() => process.exit(1));
@@ -2,6 +2,7 @@ system_server_js = custom_target('system-server.js',
input: [
'package.json',
'package-lock.json',
'build.js',
'index.js',
],
output: [
+470 -460
View File
@@ -8,46 +8,443 @@
"name": "frida-system-server-agent",
"version": "1.0.0",
"dependencies": {
"frida-java-bridge": "^7.0.1"
"@frida/buffer": "^7.0.4",
"frida-java-bridge": "^7.0.6"
},
"devDependencies": {
"@types/frida-gum": "^19.0.0",
"frida-compile": "^17.0.0"
"esbuild": "^0.25.5",
"esbuild-plugin-alias": "^0.2.1"
}
},
"node_modules/@frida/assert": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@frida/assert/-/assert-3.0.2.tgz",
"integrity": "sha512-JXJq5SbXGrM5EkjrZKfRmB29zOoEOix02NC6A5TSJ+C1GE/X051EinJJsuOO2pEOx7KZwpvAHvS0WXW0+levKg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/base64-js": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@frida/base64-js/-/base64-js-2.0.3.tgz",
"integrity": "sha512-2w0F+1TynOTCZ/v7du9LdHPWwq0lJhazjo2fF9upMyQmA1zHetT14fLuQ1v/6T0qPgyeEGkiSrybstU8EsgeUA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
"node_modules/@esbuild/aix-ppc64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz",
"integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==",
"cpu": [
"ppc64"
],
"license": "MIT"
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz",
"integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz",
"integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz",
"integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz",
"integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz",
"integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz",
"integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz",
"integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz",
"integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz",
"integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz",
"integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz",
"integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz",
"integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==",
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz",
"integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz",
"integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz",
"integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz",
"integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz",
"integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz",
"integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz",
"integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz",
"integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz",
"integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz",
"integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz",
"integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz",
"integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@frida/buffer": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/@frida/buffer/-/buffer-7.0.4.tgz",
"integrity": "sha512-RxQ1lZRRiCJj7nhcCiD8xeJx0NsLpGGnjqsmTg7jShGmbnVFMN5W7+J+3gqdPSQhc/IxNBIWc6zRXVp4+qnYHg==",
"dev": true,
"funding": [
{
"type": "github",
@@ -68,322 +465,10 @@
"ieee754": "^1.2.1"
}
},
"node_modules/@frida/crosspath": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@frida/crosspath/-/crosspath-3.0.0.tgz",
"integrity": "sha512-bNdO1spIPD2P40XtK89N49oZpJhstdlnkJZcD4yJ17jrdkm9Ctu0sd9MIEX6Z8Tm8ydhVJBAOMEKl9/R27onAQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "^17.0.36"
},
"engines": {
"node": ">=14.9.0"
}
},
"node_modules/@frida/crypto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@frida/crypto/-/crypto-1.0.1.tgz",
"integrity": "sha512-WXTkVjESvX8TIVXIynJJv9BKSIdQP0Iis04StIXknkDi1ULdMlrypA9p5C4KW1H6GCkNsVnKbybpzsulYCTvag==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/diagnostics_channel": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/diagnostics_channel/-/diagnostics_channel-1.0.0.tgz",
"integrity": "sha512-mYX1jp/5Bpk24tHArJNx65iCk7qSuV8YJkdU0gFNVtJUXxfV8BG5WuPa4mL+ynxsbWWpsg/cwKZbLAepYKTdQQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/events": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/@frida/events/-/events-4.0.4.tgz",
"integrity": "sha512-qJVQ6VWHf9sjUKuiJzoCAC00frbpcwxeYfvQ+PP9LU/d70j+QvjWgYe98Qa3ekLaBU6r/AvWm8ThKCDUCLWrQQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.8.x"
}
},
"node_modules/@frida/http": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@frida/http/-/http-4.0.2.tgz",
"integrity": "sha512-cvkc7ex7GmVXVOWqtjXKBWUUbYEBgpNRKZbEEoMeI8KiIs8zejKwg+N7rx7296Ao+EP3+xcUr4wBVr3xLaUVfQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"http-parser-js": "^0.5.3"
}
},
"node_modules/@frida/http-parser-js": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/http-parser-js/-/http-parser-js-1.0.0.tgz",
"integrity": "sha512-2nMrNXt/OeTlWbqnE8AH4Sfz4I2+BGoN206dzKEyC/g2svtn83Xu+zuv/V3TkwrA27s26Mcy84ZwsXeNlqNxUQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/https": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/https/-/https-1.0.0.tgz",
"integrity": "sha512-OiqQ6qsALcWOktRLq07oJ0i6sH8eX6MXb/MdZS1qVKDRf6wchH4Pjn6fiLB+pt/OlYbggk+DOfpHwSdjTwuHMQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/ieee754": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@frida/ieee754/-/ieee754-2.0.2.tgz",
"integrity": "sha512-wlcUebnne4ENN7GDr5pTH598ZDLMVOsh0FjenxeVOe6u7ewZkz9gGRnLnZKJAm9kl5G6XhdxhI0cSXVQK/rQUw==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "BSD-3-Clause"
},
"node_modules/@frida/net": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@frida/net/-/net-4.0.2.tgz",
"integrity": "sha512-qQRe7hQ+ZfCcG/SE3P1TRqQ9bmuK/T7wPCYaT4z56rBPWAxsaQbQHpX4fR6OrFaSDr7X0xJLsTbdIp9hGhhLZg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/os": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@frida/os/-/os-1.0.2.tgz",
"integrity": "sha512-3ISAiGNiyIya3QN2EHBCz1wqP0enTdSxP99wUeroeh8+AQRmgoOr/5TRnrVry8pe378anay3fmV/tdUMMSkehQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/path": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@frida/path/-/path-2.0.3.tgz",
"integrity": "sha512-2RQy36QatoC846fzBhBhV8sXMsSOBGoYvwTHeaE1zUdz7F4RNScP4QEekTTooBYWYX/XjiF36KQpYAzc9OYFtg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/process": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@frida/process/-/process-1.2.1.tgz",
"integrity": "sha512-nvCu22DstFW2ttGFtOKekHM7vnjbZm+XgtvavOt427GNT6uV7k0JYK9tnMbcLMRWv57DG6udAmuJlWs8Paq1ag==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/punycode": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@frida/punycode/-/punycode-3.0.0.tgz",
"integrity": "sha512-XVSDY2KamDs1D5/fTVgHcOSNxdU4kTboxzqJMBbTjcQC7XScIT9c0EfbwKCq7Kci6gWQdsHSCr7lU+9Oc4KAdg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/querystring": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/querystring/-/querystring-1.0.0.tgz",
"integrity": "sha512-15m1fOZPmoO/vWlgPJrG/J9/BJDz6a2/JpVGpS8ynNzo+fBhTznaStX5nHxUs24mVTqh/OqLo0EiYJM5WWHXxg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/readable-stream": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/@frida/readable-stream/-/readable-stream-4.1.3.tgz",
"integrity": "sha512-ntGUFmi+CryRGRJIK13a/VST2Ad19uivbln8Xd92vKPAARq+6vMIASDyZIqyl5BLRccfiyCHdYgrgQ6RI5rUig==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/reserved-words": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/reserved-words/-/reserved-words-1.0.0.tgz",
"integrity": "sha512-2yG/XxJlsGlk/mm6eZTb4OAaQEhkTI2qaFfZFtAsrA/XuCpuMWkS4y/guyBlsRu4hAuhK2HPmNM8+OLLK1zM9Q==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/stream": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@frida/stream/-/stream-1.0.2.tgz",
"integrity": "sha512-4OuaC1ztmEKgTq3WeBhsy8Oq+AwW9n9cYnvLklcC9jwD93AEwgbWpecLlxJCVuALvTMdhKPg0nQVfyGYP/i9Bw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@frida/readable-stream": "^4.1.3"
}
},
"node_modules/@frida/string_decoder": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@frida/string_decoder/-/string_decoder-2.0.0.tgz",
"integrity": "sha512-in371tYZMHQiW9HF5MS3JDw6Ao6tyBoq34UWy2rzOswYyMG1rpizh85ofi/yVkxDiaqybEZefxzkVittpPGT6g==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/terser": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/terser/-/terser-1.0.0.tgz",
"integrity": "sha512-59h9WuNzD1Rx/zwoWqQ/FW/4Y/Q3R91Eng2hEwdHapqiTDvtKbZ08F6CynCR7ZVinrh4tLYsF46AtVPTz1ys9g==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"@jridgewell/source-map": "^0.3.2",
"acorn": "^8.5.0",
"commander": "^2.20.0",
"source-map-support": "~0.5.20"
},
"bin": {
"terser": "bin/terser"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@frida/terser/node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/timers": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@frida/timers/-/timers-3.0.0.tgz",
"integrity": "sha512-3b+0igv10aT8TMxefrTAd06rActqbxJLY2Xkkq9vYcPBffB/yHszl0NYIp/5ko8WC3ecDYPU6bQiY6fjs72zTA==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/tty": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@frida/tty/-/tty-1.0.0.tgz",
"integrity": "sha512-p/kjLnKYxEAB1MdYP8+5rKv9CsHzyA+0jg9BcGETzjQVKHHcroHDULRxDYUh+DC7qs6cpX8QdDQh9E+a6ydgsQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/url": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@frida/url/-/url-1.0.2.tgz",
"integrity": "sha512-ZKunbKJHMr8w2Eb/5K1avy0MzK1B998S17wYXNv3RmzBGxMm8S5T0F3qEpRxkU7/72P8m4izyQU87fWl+FjQsQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@frida/punycode": "^3.0.0",
"@frida/querystring": "^1.0.0"
}
},
"node_modules/@frida/util": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@frida/util/-/util-1.0.3.tgz",
"integrity": "sha512-htcG3uDiRXv89ERVNNYhfase39kJ2X75ZARfrYcYEtJLFEsSk0nemM1YnEIR4CjrHvdvkWHrwgKkS+acOyoNEg==",
"dev": true,
"license": "MIT"
},
"node_modules/@frida/vm": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@frida/vm/-/vm-2.0.0.tgz",
"integrity": "sha512-7fsjLWscZT5odNIBtg6qbLNI+vAk1xmii6H5W2kaYkMYt0vRohQEcDSUWacA+eaWlu5SvMjZI82Yibj/3G9pJw==",
"dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.8",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
"integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/set-array": "^1.2.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/trace-mapping": "^0.3.24"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/set-array": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/source-map": {
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
"integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.25",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@types/frida-gum": {
"version": "19.0.0",
"resolved": "https://registry.npmjs.org/@types/frida-gum/-/frida-gum-19.0.0.tgz",
"integrity": "sha512-qViK1KwvPEAkajwSUv0wpZvZLiX8xO4JFFCh8dfYZfzSyOEfoE0KliCP/nJSKIKG6N3hXnPowrvPufjs5fLKAA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/node": {
"version": "17.0.45",
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz",
"integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==",
"dev": true,
"license": "MIT"
},
"node_modules/acorn": {
"version": "8.14.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
"dev": true,
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"dev": true,
"funding": [
{
"type": "github",
@@ -400,89 +485,64 @@
],
"license": "MIT"
},
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true,
"license": "MIT"
},
"node_modules/commander": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
"integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
"node_modules/esbuild": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz",
"integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"engines": {
"node": ">=16"
}
},
"node_modules/frida-compile": {
"version": "17.0.0",
"resolved": "https://registry.npmjs.org/frida-compile/-/frida-compile-17.0.0.tgz",
"integrity": "sha512-ixJRj14qLH/Z0ckFWd5fKeDMm0W2+2WDpSGnLRgpn0nuCQAbDHRCqVCWtPnV8uzPJmA6XOX0pujsMpYe9q9RRw==",
"dev": true,
"dependencies": {
"@frida/assert": "^3.0.1",
"@frida/base64-js": "^2.0.3",
"@frida/buffer": "^7.0.4",
"@frida/crosspath": "^3.0.0",
"@frida/crypto": "^1.0.1",
"@frida/diagnostics_channel": "^1.0.0",
"@frida/events": "^4.0.4",
"@frida/http": "^4.0.2",
"@frida/http-parser-js": "^1.0.0",
"@frida/https": "^1.0.0",
"@frida/ieee754": "^2.0.2",
"@frida/net": "^4.0.1",
"@frida/os": "^1.0.0",
"@frida/path": "^2.0.3",
"@frida/process": "^1.2.1",
"@frida/punycode": "^3.0.0",
"@frida/querystring": "^1.0.0",
"@frida/readable-stream": "^4.1.3",
"@frida/reserved-words": "^1.0.0",
"@frida/stream": "^1.0.2",
"@frida/string_decoder": "^2.0.0",
"@frida/terser": "^1.0.0",
"@frida/timers": "^3.0.0",
"@frida/tty": "^1.0.0",
"@frida/url": "^1.0.2",
"@frida/util": "^1.0.3",
"@frida/vm": "^2.0.0",
"commander": "^11.1.0",
"frida-fs": "^6.0.0",
"typed-emitter": "^2.1.0"
},
"bin": {
"frida-compile": "dist/cli.js"
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.25.5",
"@esbuild/android-arm": "0.25.5",
"@esbuild/android-arm64": "0.25.5",
"@esbuild/android-x64": "0.25.5",
"@esbuild/darwin-arm64": "0.25.5",
"@esbuild/darwin-x64": "0.25.5",
"@esbuild/freebsd-arm64": "0.25.5",
"@esbuild/freebsd-x64": "0.25.5",
"@esbuild/linux-arm": "0.25.5",
"@esbuild/linux-arm64": "0.25.5",
"@esbuild/linux-ia32": "0.25.5",
"@esbuild/linux-loong64": "0.25.5",
"@esbuild/linux-mips64el": "0.25.5",
"@esbuild/linux-ppc64": "0.25.5",
"@esbuild/linux-riscv64": "0.25.5",
"@esbuild/linux-s390x": "0.25.5",
"@esbuild/linux-x64": "0.25.5",
"@esbuild/netbsd-arm64": "0.25.5",
"@esbuild/netbsd-x64": "0.25.5",
"@esbuild/openbsd-arm64": "0.25.5",
"@esbuild/openbsd-x64": "0.25.5",
"@esbuild/sunos-x64": "0.25.5",
"@esbuild/win32-arm64": "0.25.5",
"@esbuild/win32-ia32": "0.25.5",
"@esbuild/win32-x64": "0.25.5"
}
},
"node_modules/frida-fs": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/frida-fs/-/frida-fs-6.0.0.tgz",
"integrity": "sha512-I0fnKupZh7fU2ixwCIjJnEqNdhfm/SC1ZYBMy58EmeqOWSbjw1Dpy99mJ7BJdbk2KNXJeaBZGxDYLtn0J9S+UA==",
"node_modules/esbuild-plugin-alias": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/esbuild-plugin-alias/-/esbuild-plugin-alias-0.2.1.tgz",
"integrity": "sha512-jyfL/pwPqaFXyKnj8lP8iLk6Z0m099uXR45aSN8Av1XD4vhvQutxxPzgA2bTcAwQpa1zCXDcWOlhFgyP3GKqhQ==",
"dev": true,
"license": "MIT"
},
"node_modules/frida-java-bridge": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/frida-java-bridge/-/frida-java-bridge-7.0.1.tgz",
"integrity": "sha512-pyNv12Y+erFgqdbFMsECh1OfqS77E62GeKHtxaBOZUPSpqcEkL0T2/6q/XD2161S4eGYBn6V7zumH2gbxtXK/Q==",
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/frida-java-bridge/-/frida-java-bridge-7.0.6.tgz",
"integrity": "sha512-vZEpGYhwh0vW4ksAMPWm5fAp2XcoXxY7Wn35nwkBV7F8tTqSuu/QkwUUYOESeWKH2CdZ0p1gWytCmyXkP4UPtA==",
"license": "LGPL-2.0 WITH WxWindows-exception-3.1"
},
"node_modules/http-parser-js": {
"version": "0.5.10",
"resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz",
"integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==",
"dev": true,
"license": "MIT"
},
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
"dev": true,
"funding": [
{
"type": "github",
@@ -498,56 +558,6 @@
}
],
"license": "BSD-3-Clause"
},
"node_modules/rxjs": {
"version": "7.8.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
"dev": true,
"license": "Apache-2.0",
"optional": true,
"dependencies": {
"tslib": "^2.1.0"
}
},
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dev": true,
"license": "MIT",
"dependencies": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"dev": true,
"license": "0BSD",
"optional": true
},
"node_modules/typed-emitter": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-2.1.0.tgz",
"integrity": "sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==",
"dev": true,
"license": "MIT",
"optionalDependencies": {
"rxjs": "*"
}
}
}
}
+6 -5
View File
@@ -2,15 +2,16 @@
"name": "frida-system-server-agent",
"version": "1.0.0",
"description": "Agent used by Frida's Linux backend on Android",
"type": "module",
"scripts": {
"prepare": "npm run build",
"build": "frida-compile index.js -o system-server.js -S -c"
"build": "node build.js"
},
"devDependencies": {
"@types/frida-gum": "^19.0.0",
"frida-compile": "^17.0.0"
"esbuild": "^0.25.5",
"esbuild-plugin-alias": "^0.2.1"
},
"dependencies": {
"frida-java-bridge": "^7.0.1"
"@frida/buffer": "^7.0.4",
"frida-java-bridge": "^7.0.6"
}
}
-105
View File
@@ -3167,114 +3167,9 @@ namespace Frida {
return Linux.syscall (SysCall.tgkill, tgid, tid, sig);
}
private uint linux_major = 0;
private uint linux_minor = 0;
public bool check_kernel_version (uint major, uint minor) {
if (linux_major == 0) {
var name = Posix.utsname ();
name.release.scanf ("%u.%u", out linux_major, out linux_minor);
}
return (linux_major == major && linux_minor >= minor) || linux_major > major;
}
public extern bool _syscall_satisfies (int syscall_id, LinuxSyscall mask);
public class FileDescriptor : Object, FileDescriptorBased {
public int handle;
public FileDescriptor (int handle) {
this.handle = handle;
}
~FileDescriptor () {
if (handle != -1)
Posix.close (handle);
}
public int steal () {
int result = handle;
handle = -1;
return result;
}
public int get_fd () {
return handle;
}
}
public sealed class PidFileDescriptor : FileDescriptor {
private uint pid;
private PidFileDescriptor (int fd, uint pid) {
base (fd);
this.pid = pid;
}
public static bool is_supported () {
return check_kernel_version (5, 3);
}
public static bool getfd_is_supported () {
return check_kernel_version (5, 6);
}
public static PidFileDescriptor from_pid (uint pid) throws Error {
int fd = pidfd_open (pid, 0);
if (fd == -1)
throw_pidfd_error (pid, errno);
return new PidFileDescriptor (fd, pid);
}
public FileDescriptor getfd (int targetfd) throws Error {
int fd = pidfd_getfd (handle, targetfd, 0);
if (fd == -1)
throw_pidfd_error (pid, errno);
return new FileDescriptor (fd);
}
private static int pidfd_open (uint pid, uint flags) {
return Linux.syscall (SysCall.pidfd_open, pid, flags);
}
private static int pidfd_getfd (int pidfd, int targetfd, uint flags) {
return Linux.syscall (SysCall.pidfd_getfd, pidfd, targetfd, flags);
}
[NoReturn]
private static void throw_pidfd_error (uint pid, int err) throws Error {
switch (err) {
case Posix.ESRCH:
throw new Error.PROCESS_NOT_FOUND ("Process not found");
case Posix.EPERM:
throw new Error.PERMISSION_DENIED ("Unable to use pidfd for pid %u: %s", pid, strerror (err));
default:
throw new Error.NOT_SUPPORTED ("Unable to use pidfd for pid %u: %s", pid, strerror (err));
}
}
}
namespace MemoryFileDescriptor {
public bool is_supported () {
return check_kernel_version (3, 17);
}
public static FileDescriptor from_bytes (string name, Bytes bytes) {
assert (is_supported ());
var fd = new FileDescriptor (memfd_create (name, 0));
unowned uint8[] data = bytes.get_data ();
ssize_t n = Posix.write (fd.handle, data, data.length);
assert (n == data.length);
return fd;
}
private int memfd_create (string name, uint flags) {
return Linux.syscall (SysCall.memfd_create, name, flags);
}
}
private void make_pty (out FileDescriptor read, out FileDescriptor write) throws Error {
#if HAVE_OPENPTY
int rfd = -1, wfd = -1;
-6
View File
@@ -84,12 +84,6 @@ build_arch () {
export CC="gcc -m32" CXX="g++ -m32" STRIP="strip"
fi
case "$ARCH" in
armbe8 | arm64be | arm64beilp32)
EXTRA_FLAGS+=("--without-prebuilds=sdk:host")
;;
esac
cd "$FRIDA_CORE_DIR"
rm -rf "$BUILD_DIR"
+3 -3
View File
@@ -1,6 +1,7 @@
base_sources = [
'frida.vala',
'frida-glue.c',
'package-manager.vala',
'control-service.vala',
'portal-service.vala',
'host-session-service.vala',
@@ -364,16 +365,14 @@ if have_local_backend
helper_backend_vala_args = [
base_vala_args,
gum_vala_args,
'--pkg=gio-unix-2.0',
'--pkg=posix',
]
helper_backend = static_library('frida-helper-backend', helper_backend_sources,
c_args: frida_component_cflags,
vala_args: [
helper_backend_vala_args,
'--vapidir=' + meson.current_source_dir() / 'linux',
'--pkg=frida-sysapi',
'--pkg=linux',
'--pkg=linux-system',
'--pkg=frida-gum-linux-1.0',
],
dependencies: [gio_dep, gio_unix_dep, gee_dep, gum_dep, base_dep] + helper_backend_extra_deps,
@@ -634,6 +633,7 @@ core = library('frida-core', core_sources,
base_vala_args,
gumjs_inspector_vala_args,
'--pkg=gmodule-2.0',
'--pkg=libsoup-3.0',
],
vala_gir: core_gir_name,
link_args: backend_libs_private,
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.0.3
revision = 17.2.13
depth = 1
[provide]
+1 -1
View File
@@ -1,6 +1,6 @@
[wrap-git]
url = https://github.com/frida/lwip.git
revision = 267d9f082e9e38083b643421a93c03d4a7046fd0
revision = 13fb5e0f519cc46dc4cd938808430f60a73f03d4
depth = 1
[provide]
+1 -1
View File
@@ -1,6 +1,6 @@
[wrap-git]
url = https://github.com/frida/ngtcp2.git
revision = cc5cf523615b7fa7a9340234c7eec3c3645ae969
revision = 828dcaed498b40954e1b496664a3309796968db6
depth = 1
[provide]
-6
View File
@@ -77,12 +77,6 @@ build_arch () {
export CC="gcc -m32" CXX="g++ -m32" STRIP="strip"
fi
case "$ARCH" in
armbe8 | arm64be | arm64beilp32)
EXTRA_FLAGS+=("--without-prebuilds=sdk:host")
;;
esac
cd "$FRIDA_CORE_DIR"
rm -rf "$BUILD_DIR"
+4
View File
@@ -9,6 +9,10 @@ test_sources = [
'process-resource-usage.c',
]
if host_os_family == 'darwin'
test_sources += 'test-host-session-darwin-glue.m'
endif
test_vala_args = []
test_depends = []
+1 -1
View File
@@ -2,7 +2,7 @@
tests=$(dirname "$0")
repo=$(dirname "$tests")
builddir=../build/tmp_thin-macos-arm64/frida-core
builddir=build
flamegraph=/Users/oleavr/src/FlameGraph
set -ex
+20 -3
View File
@@ -25,14 +25,31 @@ namespace Frida.CompilerTest {
string project_dir = DirUtils.make_tmp ("compiler-test.XXXXXX");
string agent_ts_path = Path.build_filename (project_dir, "agent.ts");
FileUtils.set_contents (agent_ts_path, "console.log(\"Hello World\");");
FileUtils.set_contents (agent_ts_path, """
import { log } from "./logger.js";
const woot = Buffer.from("w00t").toString("base64");
log("Hello World: " + woot);
log(hexdump(Process.mainModule.base, { ansi: true }));
""");
string logger_ts_path = Path.build_filename (project_dir, "logger.ts");
FileUtils.set_contents (logger_ts_path, """
export function log(...items: any[]) {
const message = items.join("\n");
console.log(`[LOG] ${message}`);
}
""");
var timer = new Timer ();
yield compiler.build (agent_ts_path);
var code = yield compiler.build (agent_ts_path);
uint elapsed_msec = (uint) (timer.elapsed () * 1000.0);
if (GLib.Test.verbose ())
if (GLib.Test.verbose ()) {
print ("Output:\nvvv\n%s^^^\n", code);
print ("Built in %u ms\n", elapsed_msec);
}
unowned string? test_log_path = Environment.get_variable ("FRIDA_TEST_LOG");
if (test_log_path != null) {
+83
View File
@@ -0,0 +1,83 @@
#import <Foundation/Foundation.h>
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
static id frida_parse_plist (const uint8_t * data, int length, char ** error_message);
uint8_t *
frida_host_session_test_fruity_plist_to_binary_using_apple_implementation (const uint8_t * data, int length, char ** error_message,
int * output_length)
{
@autoreleasepool
{
uint8_t * result;
id plist;
NSData * bplist;
size_t len;
*error_message = NULL;
*output_length = 0;
plist = frida_parse_plist (data, length, error_message);
if (plist == nil)
return NULL;
bplist = [NSPropertyListSerialization dataWithPropertyList:plist
format:NSPropertyListBinaryFormat_v1_0
options:0
error:nil];
len = [bplist length];
result = malloc (len);
memcpy (result, [bplist bytes], len);
*output_length = (int) len;
return result;
}
}
char *
frida_host_session_test_fruity_plist_to_xml_using_apple_implementation (const uint8_t * data, int length, char ** error_message)
{
@autoreleasepool
{
id plist;
NSData * xml;
*error_message = NULL;
plist = frida_parse_plist (data, length, error_message);
if (plist == nil)
return NULL;
xml = [NSPropertyListSerialization dataWithPropertyList:plist
format:NSPropertyListXMLFormat_v1_0
options:0
error:nil];
return strndup ([xml bytes], [xml length]);
}
}
static id
frida_parse_plist (const uint8_t * data, int length, char ** error_message)
{
id plist;
NSData * input;
NSPropertyListFormat format;
NSError * error = nil;
input = [NSData dataWithBytes:data length:(NSUInteger) length];
plist = [NSPropertyListSerialization propertyListWithData:input
options:NSPropertyListImmutable
format:&format
error:&error];
if (error != nil)
*error_message = strdup ([[error localizedDescription] UTF8String]);
return plist;
}
+67 -1
View File
@@ -46,6 +46,12 @@ namespace Frida.HostSessionTest {
Fruity.Plist.to_xml_yields_complete_document ();
});
#if DARWIN
GLib.Test.add_func ("/HostSession/Fruity/Plist/output-matches-apple-implementation", () => {
Fruity.Plist.output_matches_apple_implementation ();
});
#endif
GLib.Test.add_func ("/HostSession/Fruity/backend", () => {
var h = new Harness ((h) => Fruity.backend.begin (h as Harness));
h.run ();
@@ -1551,7 +1557,7 @@ namespace Frida.HostSessionTest {
private static async void spawn (Harness h) {
if (!GLib.Test.slow () && (
Frida.Test.os () == Frida.Test.OS.ANDROID ||
Frida.Test.os_arch_suffix () == "-linux-arm" ||
Frida.Test.os_arch_suffix () == "-linux-armbe8" ||
Frida.Test.os_arch_suffix () == "-linux-arm64be"
)) {
stdout.printf ("<skipping, run in slow mode> ");
@@ -4059,6 +4065,66 @@ namespace Frida.HostSessionTest {
assert_true (actual_xml == expected_xml);
}
#if DARWIN
private static void output_matches_apple_implementation () {
var request = new Frida.Fruity.Plist ();
request.set_string ("Command", "Lookup");
var options = new Frida.Fruity.PlistDict ();
request.set_dict ("ClientOptions", options);
var attributes = new Frida.Fruity.PlistArray ();
options.set_array ("ReturnAttributes", attributes);
attributes.add_string ("ApplicationType");
attributes.add_string ("IsAppClip");
attributes.add_string ("SBAppTags");
attributes.add_string ("CFBundleIdentifier");
attributes.add_string ("CFBundleDisplayName");
attributes.add_string ("CFBundleShortVersionString");
attributes.add_string ("CFBundleVersion");
attributes.add_string ("Path");
attributes.add_string ("Container");
attributes.add_string ("GroupContainers");
attributes.add_string ("Entitlements");
var ids = new Frida.Fruity.PlistArray ();
options.set_array ("BundleIDs", ids);
ids.add_string ("UUU");
string? error_message;
string our_xml = request.to_xml ();
uint8[] our_bplist = request.to_binary ();
uint8[]? apple_bplist = to_binary_using_apple_implementation (our_xml.data, out error_message);
if (error_message != null)
printerr ("Oops: %s\n", error_message);
assert_nonnull (apple_bplist);
assert_null (error_message);
/*
try {
var home_dir = Environment.get_home_dir ();
FileUtils.set_data (Path.build_filename (home_dir, "frida-test-apple.plist"), apple_bplist);
FileUtils.set_data (Path.build_filename (home_dir, "frida-test-our.plist"), our_bplist);
} catch (FileError e) {
assert_not_reached ();
}
*/
string? apple_xml = to_xml_using_apple_implementation (our_bplist, out error_message);
if (error_message != null)
printerr ("Oops: %s\n", error_message);
assert_nonnull (apple_xml);
assert_null (error_message);
assert_cmpstr (our_xml, EQ, apple_xml);
assert_cmpstr (Base64.encode (our_bplist), EQ, Base64.encode (apple_bplist));
}
private extern uint8[]? to_binary_using_apple_implementation (uint8[] data, out string? error_message);
private extern string? to_xml_using_apple_implementation (uint8[] data, out string? error_message);
#endif
}
}
+369
View File
@@ -0,0 +1,369 @@
from __future__ import annotations
import base64
import json
import os
import platform
import re
import shlex
import shutil
import subprocess
import sys
from dataclasses import dataclass
from pathlib import Path
from typing import List, Optional, Tuple
if platform.system() == "Windows":
import winreg
FRIDA_OS_TO_GO_OS = {
"macos": "darwin",
}
FRIDA_ABI_TO_GO_ARCH = {
"armbe8": "armbe",
"armhf": "arm",
"mips64el": "mips64le",
"mipsel": "mipsle",
"x86": "386",
"x86_64": "amd64",
}
FRIDA_ABI_TO_MINGW_FLAVOR = {
"arm64": "clangarm64",
"x86": "mingw32",
"x86_64": "mingw64",
}
FRIDA_ABI_TO_MINGW_ARCH = {
"arm64": "aarch64",
"x86": "i686",
"x86_64": "x86_64",
}
MACHINE_FLAG_PATTERN = re.compile(
r"^-m(?:arch|float-abi|fpu|thumb|fpmath|stackrealign|cpu|tune|fp32|abi)(?:=.*)?$"
)
def main(argv: List[str]):
args = argv[1:]
go = Path(args.pop(0))
host_os = args.pop(0)
host_abi = args.pop(0)
shlib_suffix = args.pop(0)
cc_id = args.pop(0)
cc_cmd_array = pop_cmd_array_arg(args)
ar_cmd_array = pop_cmd_array_arg(args)
nm_cmd_array = pop_cmd_array_arg(args)
ranlib_cmd_array = pop_cmd_array_arg(args)
try:
config = detect_config(
go,
host_os,
host_abi,
shlib_suffix,
cc_id,
cc_cmd_array,
ar_cmd_array,
nm_cmd_array,
ranlib_cmd_array,
)
print("ok")
print(config["mode"], base64.b64encode(json.dumps(config).encode("utf-8")).decode("ascii"))
except Exception as e:
print("error")
print(str(e).replace("\n", "\\n"))
def pop_cmd_array_arg(args: List[str]) -> List[str]:
result = []
first = args.pop(0)
assert first == ">>>"
while True:
cur = args.pop(0)
if cur == "<<<":
break
result.append(cur)
if len(result) == 1 and not result[0]:
return None
return result
def detect_config(
go: Path,
host_os: str,
host_abi: str,
shlib_suffix: str,
cc_id: str,
cc_cmd_array: List[str],
ar_cmd_array: Optional[List[str]],
nm_cmd_array: Optional[List[str]],
ranlib_cmd_array: Optional[List[str]],
) -> dict:
source_root = Path(os.environ["MESON_SOURCE_ROOT"])
build_root = Path(os.environ["MESON_BUILD_ROOT"])
subdir = Path(os.environ["MESON_SUBDIR"])
work_dir = build_root / subdir / "tools" / "cgo"
work_dir.mkdir(parents=True, exist_ok=True)
for f in ("go.mod", "main.go"):
shutil.copyfile(source_root / subdir / "tools" / "cgo" / f, work_dir / f)
extra_go_args = []
mingw = None
env = {
**os.environ,
"CGO_ENABLED": "1",
}
if cc_id == "msvc":
toolchain = MinGWToolchain.detect(host_abi)
mingw = {
"triplet": toolchain.triplet,
"prefix": str(toolchain.prefix),
"bindir": str(toolchain.bindir),
"cc": str(toolchain.cc),
"libcc": str(toolchain.libcc),
}
env["CC"] = str(toolchain.cc)
env["PATH"] = str(toolchain.cc.parent) + ";" + env["PATH"]
ar_cmd_array = [str(toolchain.ar)]
nm_cmd_array = [str(toolchain.nm)]
ranlib_cmd_array = [str(toolchain.ranlib)]
else:
env["CC"] = shlex.join(
[arg for arg in cc_cmd_array if MACHINE_FLAG_PATTERN.fullmatch(arg) is None]
)
extra_go_args.append(f"-ldflags=-extar={ar_cmd_array[0]}")
if host_os == "macos":
extra_go_args.append("-ldflags=-extldflags=-mmacosx-version-min=11.0")
env["MACOSX_DEPLOYMENT_TARGET"] = "11.0"
def run(*args):
return subprocess.run(
args,
cwd=work_dir,
env=env,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
encoding="utf-8",
check=True,
)
goos = FRIDA_OS_TO_GO_OS.get(host_os, host_os)
goarch = FRIDA_ABI_TO_GO_ARCH.get(host_abi, host_abi)
needed = f"{goos}/{goarch}"
supported = run("go", "tool", "dist", "list").stdout.splitlines()
if needed not in supported:
raise NotSupportedError(f"Go does not support {needed}")
env["GOOS"] = goos
env["GOARCH"] = goarch
mode = "c-shared" if host_os == "android" else "c-archive"
try:
run(go, "build", f"-buildmode={mode}", "-o", "cgotest.a", "-buildvcs=false")
except subprocess.CalledProcessError as e:
raise BuildError(e.output.strip())
config = {
"mode": mode,
"os": host_os,
"abi": host_abi,
"shlib_suffix": shlib_suffix,
"extra_go_args": extra_go_args,
"env": env,
"ar": ar_cmd_array,
"nm": nm_cmd_array,
"ranlib": ranlib_cmd_array,
}
if mingw is not None:
config["mingw"] = mingw
return config
class BuildError(Exception):
pass
class NotSupportedError(Exception):
pass
@dataclass
class MinGWToolchain:
triplet: str
prefix: Path
bindir: Path
cc: Path
ar: Path
nm: Path
ranlib: Path
libcc: Path
@staticmethod
def detect(host_abi: str) -> MinGWToolchain:
msys_prefix = find_msys2_prefix_from_environment()
if msys_prefix is None:
msys_prefix = find_msys2_prefix_from_registry()
if msys_prefix is None:
msys_prefix = Path(os.environ["SystemDrive"] + r"\msys64")
if not msys_prefix.exists():
msys_prefix = None
if msys_prefix is not None:
flavor = host_abi_to_mingw_flavor(host_abi)
mingw_prefix = msys_prefix / flavor
if not mingw_prefix.exists():
mingw_prefix = None
else:
mingw_prefix = None
mingw_cc = host_abi_to_mingw_cc(host_abi)
if mingw_prefix is not None:
mingw_bindir = mingw_prefix / "bin"
cc_path = mingw_bindir / f"{mingw_cc}.exe"
if not cc_path.exists():
cc_path = None
else:
raw_cc_path = shutil.which(mingw_cc)
cc_path = Path(raw_cc_path) if raw_cc_path is not None else None
if cc_path is not None:
mingw_bindir = cc_path.parent
mingw_prefix = mingw_bindir.parent
if cc_path is None:
raise MinGWNotFoundError(
"could not find an MSYS2/MinGW toolchain under msys64, "
"nor a MinGW-based GCC/Clang on PATH matching the requested host_abi"
)
def query_cc(*args):
return subprocess.run(
[cc_path, *args],
cwd=cc_path.parent,
capture_output=True,
encoding="utf-8",
check=True,
).stdout.rstrip()
try:
triplet = query_cc("-dumpmachine")
except subprocess.CalledProcessError:
raise MinGWNotFoundError(
f"unable to detect the machine triplet of {cc_path}"
)
actual_mingw_arch = triplet.split("-", 1)[0]
expected_mingw_arch = FRIDA_ABI_TO_MINGW_ARCH[host_abi]
if actual_mingw_arch != expected_mingw_arch:
raise MinGWNotFoundError(
f"compiler at {cc_path} is for {actual_mingw_arch}, expected {expected_mingw_arch}"
)
if host_abi != "arm64" and "mingw" not in triplet:
raise MinGWNotFoundError(
f"compiler at {cc_path} does not target MinGW, its triplet is {triplet}"
)
ar_path = cc_path.parent / "ar.exe"
nm_path = cc_path.parent / "nm.exe"
ranlib_path = cc_path.parent / "ranlib.exe"
try:
libcc_name = query_cc("-print-libgcc-file-name")
except subprocess.CalledProcessError:
raise MinGWNotFoundError(
f"unable to detect the libgcc file name of {cc_path}"
)
libcc_path = Path(libcc_name).resolve()
return MinGWToolchain(
triplet,
mingw_prefix,
mingw_bindir,
cc_path,
ar_path,
nm_path,
ranlib_path,
libcc_path,
)
class MinGWNotFoundError(Exception):
pass
def host_abi_to_mingw_flavor(abi: str) -> str:
try:
return FRIDA_ABI_TO_MINGW_FLAVOR[abi]
except KeyError:
raise MinGWNotFoundError(f"unsupported host_abi: {abi}")
def host_abi_to_mingw_cc(abi: str) -> str:
return "clang" if abi == "arm64" else "gcc"
def find_msys2_prefix_from_environment() -> Optional[Path]:
location = os.environ.get("MSYS2_LOCATION")
if location is None:
return None
return Path(location)
def find_msys2_prefix_from_registry() -> Optional[Path]:
UNINSTALL_PATHS = [
(
winreg.HKEY_CURRENT_USER,
r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
),
(
winreg.HKEY_CURRENT_USER,
r"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall",
),
(
winreg.HKEY_LOCAL_MACHINE,
r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
),
(
winreg.HKEY_LOCAL_MACHINE,
r"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall",
),
]
for hive, subkey_path in UNINSTALL_PATHS:
try:
with winreg.OpenKey(hive, subkey_path) as uninstall_root:
num_subkeys, _, _ = winreg.QueryInfoKey(uninstall_root)
for i in range(num_subkeys):
try:
subkey_name = winreg.EnumKey(uninstall_root, i)
with winreg.OpenKey(uninstall_root, subkey_name) as app_key:
disp_name, _ = winreg.QueryValueEx(app_key, "DisplayName")
if disp_name.startswith("MSYS2"):
install_loc, _ = winreg.QueryValueEx(
app_key, "InstallLocation"
)
return Path(install_loc)
except FileNotFoundError:
continue
except OSError:
continue
except FileNotFoundError:
continue
except OSError:
continue
return None
if __name__ == "__main__":
main(sys.argv)
+3
View File
@@ -0,0 +1,3 @@
module frida.re/cgotest
go 1.24.3
+13
View File
@@ -0,0 +1,13 @@
package main
/*
#include <stdlib.h>
*/
import "C"
//export frobnicate
func frobnicate() int {
return 42
}
func main() {}
+10 -7
View File
@@ -22,14 +22,17 @@ def compile_js_agent(output_js: Path, inputs: List[Path], priv_dir: Path, npm: P
dest.parent.mkdir(exist_ok=True)
shutil.copy(f, dest)
run_kwargs = {
"cwd": priv_dir,
"stdout": subprocess.PIPE,
"stderr": subprocess.STDOUT,
"encoding": "utf-8",
"check": True,
}
try:
subprocess.run(
[npm, "install"],
capture_output=True,
cwd=priv_dir,
encoding="utf-8",
check=True,
)
subprocess.run([npm, "install"], **run_kwargs)
subprocess.run([npm, "run", "build"], **run_kwargs)
except subprocess.CalledProcessError as e:
print(e, file=sys.stderr)
print(
+2 -1
View File
@@ -23,6 +23,7 @@ def main(argv):
input_entitlements_path = args.pop(0) if args else None
else:
input_entitlements_path = None
flags = set(args.pop(0).split("|") if args else [])
is_apple_os = host_os in {"macos", "ios", "watchos", "tvos"}
@@ -62,7 +63,7 @@ def main(argv):
codesign_args += ["--entitlements", input_entitlements_path]
subprocess.run(codesign + codesign_args + [intermediate_path], **run_kwargs)
if host_os == "android":
if host_os == "android" and "elf-cleaner:off" not in flags:
api_level = 19 if host_abi in {"x86", "arm"} else 21
subprocess.run(termux_elf_cleaner + ["--api-level", str(api_level), "--quiet", intermediate_path],
**run_kwargs)
+13
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);
@@ -163,6 +166,9 @@ namespace QuickJS {
[CCode (cname = "JS_NewCFunction2")]
public Value make_cfunction2 (CFunction func, string name, int length, CFunctionEnum cproto, int magic);
[CCode (cname = "JS_NewCFunctionData")]
public Value make_cfunction_data (CFunctionData func, int length, int magic, [CCode (array_length_pos = 3.1)] Value[] data);
[CCode (cname = "JS_NewPromiseCapability")]
public Value make_promise ([CCode (array_length = false, array_null_terminated = false)] Value[] resolving_funcs);
@@ -201,6 +207,10 @@ namespace QuickJS {
[CCode (has_target = false)]
public delegate Value CFunction (Context ctx, Value this_val, [CCode (array_length_pos = 2.1)] Value[] argv);
[CCode (has_target = false)]
public delegate Value CFunctionData (Context ctx, Value this_val, [CCode (array_length_pos = 2.1)] Value[] argv, int magic,
[CCode (array_length = false, array_null_terminated = false)] Value[] data);
[CCode (cprefix = "JS_CFUNC_", has_type_id = false)]
public enum CFunctionEnum {
generic,
@@ -314,6 +324,9 @@ namespace QuickJS {
[CCode (cname = "JS_GetOpaque")]
public void * get_opaque (ClassID class_id);
[CCode (cname = "JS_GetAnyOpaque")]
public void * get_any_opaque (out ClassID class_id);
[CCode (cname = "JS_SetOpaque")]
public void set_opaque (void * opaque);
}