Compare commits

...
66 Commits
Author SHA1 Message Date
Ole André Vadla Ravnås 416d2ea388 subprojects: Prepare for release 2024-09-19 00:00:49 +02:00
Ole André Vadla Ravnås 02e83a6d4a subprojects: Bump outdated 2024-09-18 23:57:30 +02:00
Ole André Vadla Ravnås 539f359a1f fruity: Handle USB TunnelConnection dropping
Which happens on e.g. an iOS userspace reboot.
2024-09-18 23:49:56 +02:00
Ole André Vadla Ravnås 24dc7f4a3d fruity: Fix unreliable modeswitch activation
Where its Promise could be resolved more than once.
2024-09-18 23:14:35 +02:00
Ole André Vadla Ravnås f48ced3a4a subprojects: Prepare for release 2024-09-18 14:33:15 +02:00
Ole André Vadla Ravnås 54829052bd subprojects: Bump outdated 2024-09-18 14:31:38 +02:00
Ole André Vadla Ravnås 73abf705b1 submodules: Bump releng 2024-09-18 14:31:37 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 7e21f5cb1d fruity: Advertise our RemoteXPC protocol support
Like macOS does, but with most of the properties omitted.

We do this to more closely mimic macOS' behavior, and to avoid an error
ending up in the syslog:

    Invalid or missing remote device connection version flags

Co-authored-by: Håvard Sørbø <[email protected]>
2024-09-18 14:30:21 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 24a1f79b02 fruity: Handle iDevice not paired with anyone
Where the pairVerify step fails early.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-09-18 14:25:55 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 2d990888d9 fruity: Fix teardown when using our NCM driver
Co-authored-by: Håvard Sørbø <[email protected]>
2024-09-17 18:34:21 +02:00
Ole André Vadla Ravnås 0fd255d3a4 fruity: Fix error marshaling in find_tunnel() for non-macOS 2024-09-17 17:15:35 +02:00
Ole André Vadla Ravnås fc500a19d9 fruity: Fix a stylistic inconsistency 2024-09-17 17:12:12 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 7280bbdbf7 fruity: Reuse NCM peer when tunnel setup fails
Co-authored-by: Håvard Sørbø <[email protected]>
2024-09-17 13:25:25 +02:00
Ole André Vadla Ravnås 9539981511 subprojects: Prepare for release 2024-09-06 22:59:50 +02:00
Ole André Vadla Ravnås 3005ab2aa5 subprojects: Bump outdated 2024-09-06 22:58:46 +02:00
Ole André Vadla Ravnås 140c5cf2cd subprojects: Prepare for release 2024-09-06 21:57:05 +02:00
Ole André Vadla Ravnås 6bb27c17e9 subprojects: Bump outdated 2024-09-06 21:54:47 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 0f2d9c8b40 network-stack: Fix deadlock in perform_on_lwip_thread()
Where in the case of already being on the lwIP thread, we would enqueue
the request and then perform whichever is the oldest pending request. So
when there was already one or more requests pending, we would perform
that request instead. Then next we would join() our request, assuming it
had completed, and end up deadlocking the lwIP thread.

Kudos to @mrmacete for reporting and helping track this one down.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-09-06 15:16:48 +02:00
Ole André Vadla Ravnås 5606120f6a subprojects: Bump outdated 2024-08-30 23:00:20 +02:00
ajwerner 2376f425a3 linux: Handle process gone when detaching (#543)
This is an attempt to handle the situation where the process has gone
away and we're shutting down. I've observed the system looping
attempting to move the state out of ATTACHED. It's possible that the
state machine here needs to be made more complex (ALREADY_ATTACHED is
misleading).

Informs #478.
2024-08-30 22:37:41 +02:00
Ole André Vadla Ravnås 1f9e24e1ea windows: Revive the system session 2024-08-26 12:26:25 +02:00
Ole André Vadla Ravnås 694118cccc subprojects: Bump outdated 2024-08-26 01:51:50 +02:00
Ole André Vadla Ravnås 9d51496124 submodules: Bump releng 2024-08-26 01:51:49 +02:00
Ole André Vadla Ravnås 27849af528 subprojects: Bump outdated 2024-08-25 23:54:37 +02:00
Ole André Vadla Ravnås 9df97f9e6b windows: Add support for arm64 2024-08-25 23:52:42 +02:00
Ole André Vadla Ravnås 79126f0065 subprojects: Bump outdated 2024-08-25 13:41:41 +02:00
Ole André Vadla Ravnås 4b0d1eab04 meson: Add frida-netif to the public frida-core
It's needed by ControlService.
2024-08-25 13:40:51 +02:00
Ole André Vadla Ravnås 31188db39a subprojects: Prepare for release 2024-08-22 15:40:45 +02:00
Ole André Vadla Ravnås de09ec42d5 subprojects: Bump outdated 2024-08-22 15:39:00 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 34c1548ced tunnel-connection: Ensure JSON request ends up in its own UDP packet
When opening the tunnel, it seems problematic if a datagram and stream
data end up in the same UDP packet. We make our dummy-datagram larger to
avoid this.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-08-22 15:35:07 +02:00
Ole André Vadla RavnåsandHåvard Sørbø b753294acb tunnel-connection: Wire up missing stream close logic
Co-authored-by: Håvard Sørbø <[email protected]>
2024-08-22 15:35:00 +02:00
Ole André Vadla RavnåsandHåvard Sørbø 498c9be83e tunnel-connection: Consistently avoid writes after connection is gone
Which would result in a crash.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-08-22 15:32:30 +02:00
Ole André Vadla RavnåsandHåvard Sørbø bbcbe91b3e network-stack: Handle perform_on_lwip_thread() from the lwIP thread
Instead of deadlocking.

Co-authored-by: Håvard Sørbø <[email protected]>
2024-08-22 15:29:11 +02:00
Ole André Vadla Ravnås ce80773d21 subprojects: Prepare for release 2024-08-20 21:50:41 +02:00
Ole André Vadla Ravnås e06da4d410 subprojects: Bump outdated 2024-08-20 21:48:20 +02:00
Francesco Tamagni 120dc491c4 tunnel-interface-observer: Fix start() crash on i/tvOS
When SCDynamicStoreCopyKeyList() fails.
2024-08-20 21:12:49 +02:00
Ole André Vadla Ravnås 2ebec1addf subprojects: Prepare for release 2024-08-02 14:05:13 +02:00
Håvard Sørbø 6a1e373ba2 fruity: Make find_usbmux_device() non-throwing 2024-08-02 14:03:03 +02:00
Ole André Vadla Ravnås 100b7a63d7 fruity: Guard against lockdown open<->close loop 2024-08-02 14:03:03 +02:00
Håvard Sørbø b3f2d1e7cc fruity: Fix invalidation of closed lockdown client 2024-08-02 14:03:03 +02:00
Håvard Sørbø 313cdc89f8 lockdown-client: Bubble up CONNECTION_CLOSED error 2024-08-02 14:03:03 +02:00
Ole André Vadla Ravnås 3c8221dd55 subprojects: Bump outdated 2024-07-29 11:00:36 +02:00
Ole André Vadla Ravnås dca8509960 submodules: Bump releng 2024-07-29 11:00:36 +02:00
Ole André Vadla Ravnås 78ff6e5b08 subprojects: Prepare for release 2024-07-23 10:14:56 +02:00
Ole André Vadla Ravnås 6537809897 subprojects: Bump outdated 2024-07-23 10:11:56 +02:00
Ole André Vadla Ravnås ead2ff6701 submodules: Bump releng 2024-07-23 10:11:56 +02:00
xiofee d55232fe52 fruity: Fix crash when enumerating network interfaces on Windows (#538)
Some don't have a unicast address, and need to be ignored.
2024-07-23 10:11:26 +02:00
Ole André Vadla Ravnås dab3b91f9e subprojects: Prepare for release 2024-07-22 11:49:03 +02:00
Ole André Vadla Ravnås 71f7b2f16a subprojects: Bump outdated 2024-07-22 11:37:45 +02:00
Ole André Vadla Ravnås 4cf806641f submodules: Bump releng 2024-07-22 11:37:44 +02:00
Ole André Vadla Ravnås e34a533a35 fruity: Handle devices without tunnel support on non-macOS
In the portable CoreDevice backend.
2024-07-22 11:28:23 +02:00
Ole André Vadla Ravnås 6b56c88295 fruity: Use UsbmuxDevice from USB transport if present
So we can reach the loopback interface, and for better performance.
2024-07-19 23:10:15 +02:00
Ole André Vadla Ravnås d810111f1e fruity: Expose name from USB transport if present
It has a more descriptive name in case of UsbmuxTransport.
2024-07-19 23:09:42 +02:00
Ole André Vadla Ravnås 3d17ad39da subprojects: Prepare for release 2024-07-17 22:43:10 +02:00
Ole André Vadla Ravnås 429607e7e3 xpc-client: Wire up cancellable in request()
As we can't cancel the request itself, we have to cancel the connection.
2024-07-17 22:34:24 +02:00
Ole André Vadla Ravnås 6ef660718a subprojects: Bump outdated 2024-07-17 22:10:01 +02:00
Ole André Vadla Ravnås cf61fda141 subprojects: Prepare for release 2024-07-16 15:24:54 +02:00
Ole André Vadla Ravnås b272dda27d subprojects: Bump outdated 2024-07-16 15:20:35 +02:00
Ole André Vadla Ravnås 300d176e85 ci: Re-enable tests on macOS 2024-07-16 15:14:43 +02:00
Ole André Vadla Ravnås e7f045bbe9 darwin: Await ObjC init on macOS Sequoia and iOS 18
By making use of notifyObjCInit() if available.
2024-07-16 11:45:16 +02:00
Ole André Vadla Ravnås 0b6abfeb7c darwin: Handle dyld restart on macOS Sequoia and iOS 18 2024-07-16 11:12:02 +02:00
Ole André Vadla Ravnås c17c6e31bc tests: Avoid relying on executable name on Darwin 2024-07-16 11:06:55 +02:00
Ole André Vadla Ravnås 0825aab1d0 fruity: Improve CoreDevice pairing support
- Fix support for multiple pairing relationships.
- Keep the in-memory peer store up-to-date, so new pairing relationships
  don't require a process restart to be able to match them up with
  pairing services on the network.
2024-07-15 14:41:03 +02:00
Ole André Vadla Ravnås be65296610 ncm: Fix a stylistic inconsistency 2024-07-15 13:24:16 +02:00
Ole André Vadla Ravnås 0a6002a3ce ncm: Avoid using a broken kernel NCM driver
Where only one of the two network interfaces exist, i.e. the tethering
interface.
2024-07-15 13:03:49 +02:00
Ole André Vadla Ravnås a3deb22999 ncm: Detach all drivers before changing configuration
We would previously only try to detach for the data interface, which
makes no sense if that interface is on a different configuration.
2024-07-15 12:54:14 +02:00
31 changed files with 1229 additions and 688 deletions

No files matched your search

-1
View File
@@ -68,7 +68,6 @@ jobs:
name: core-devkit-${{ matrix.id }}
path: build/src/devkit/
- name: Test
if: ${{ !startsWith(matrix.id, 'macos-') }}
run: make test
cross:
+48 -4
View File
@@ -14,7 +14,7 @@ import subprocess
import sys
import tempfile
import traceback
from typing import Any, Literal, Mapping, Optional, Sequence
from typing import Any, Literal, Mapping, Optional, Sequence, Tuple
REPO_ROOT = Path(__file__).resolve().parent.parent
@@ -140,16 +140,19 @@ def setup(role: Role,
compat = set()
else:
summary = "enabled by user"
missing: list[MissingFeature] = []
if "native" in compat:
have_toolchain = True
other_label: Optional[str] = None
other_triplet: Optional[str] = None
extra_environ: dict[str, str] = {}
if host_os == "windows" and host_arch == "x86_64" and host_config == "mingw":
other_triplet = "i686-w64-mingw32"
have_toolchain = shutil.which(other_triplet + "-gcc") is not None
other_label = "x86"
have_toolchain, other_triplet = detect_mingw_toolchain_for("x86")
elif host_os == "linux" and host_arch == "x86_64" and host_config is None:
other_label = "x86"
other_triplet = "i686-linux-gnu"
have_toolchain = shutil.which(other_triplet + "-gcc") is not None
if not have_toolchain:
@@ -173,7 +176,7 @@ def setup(role: Role,
if not have_toolchain:
if not auto_detect:
raise ToolchainNotFoundError(f"unable to locate toolchain for {other_triplet}")
summary = "disabled due to missing toolchain for {other_triplet}"
missing.append(MissingFeature(other_label, other_triplet))
if host_os == "windows" and host_arch == "x86_64" and have_toolchain:
group = OutputGroup("x86", other_triplet, extra_environ)
@@ -269,6 +272,28 @@ def setup(role: Role,
]
if "emulated" in compat:
if host_os == "windows" and host_arch == "arm64":
for kind, emulated_arch in [("modern", "x86_64"), ("legacy", "x86")]:
if host_config == "mingw":
found, emulated_triplet = detect_mingw_toolchain_for(emulated_arch)
if not found:
if not auto_detect:
raise ToolchainNotFoundError(f"unable to locate toolchain for {emulated_triplet}")
missing.append(MissingFeature(emulated_arch, emulated_triplet))
continue
else:
emulated_triplet = None
outputs[OutputGroup(emulated_arch, emulated_triplet, extra_environ)] = [
Output(identifier=f"helper_emulated_{kind}",
name=HELPER_FILE_WINDOWS.name.replace(".exe", f"-{emulated_arch}.exe"),
file=HELPER_FILE_WINDOWS,
target=HELPER_TARGET),
Output(identifier=f"agent_emulated_{kind}",
name=AGENT_FILE_WINDOWS.name.replace(".dll", f"-{emulated_arch}.dll"),
file=AGENT_FILE_WINDOWS,
target=AGENT_TARGET),
]
if host_os == "android" and host_arch in {"x86_64", "x86"}:
outputs[OutputGroup("arm")] = [
Output(identifier="agent_emulated_legacy",
@@ -290,6 +315,8 @@ def setup(role: Role,
state = State(role, builddir, top_builddir, frida_version, host_os, host_config, allowed_prebuilds, outputs)
serialized_state = base64.b64encode(pickle.dumps(state)).decode('ascii')
if missing:
summary = ", ".join([f"{m.label} disabled due to missing toolchain for {m.triplet}" for m in missing])
variable_names, output_names = zip(*[(output.identifier, output.name) \
for output in itertools.chain.from_iterable(outputs.values())])
print("ok")
@@ -349,6 +376,12 @@ class Output:
target: str
@dataclass
class MissingFeature:
label: str
triplet: str
def compile(privdir: Path, state: State):
releng_location = query_releng_location(state.role)
subprojects = detect_relevant_subprojects(releng_location)
@@ -589,6 +622,12 @@ def configure_import_path(releng_location: Path):
sys.path.insert(0, str(releng_location.parent))
def detect_mingw_toolchain_for(arch: str) -> Tuple[bool, Optional[str]]:
triplet = MINGW_ARCHS.get(arch, arch) + "-w64-mingw32"
found = shutil.which(triplet + "-gcc") is not None
return (found, triplet)
STATE_FILENAME = "state.dat"
DEPFILE_FILENAME = "compat.deps"
@@ -616,6 +655,11 @@ MSVS_ENVVARS = {
"LIB",
}
MINGW_ARCHS = {
"x86": "i686",
"arm64": "aarch64",
}
if __name__ == "__main__":
main(sys.argv)
+3
View File
@@ -1,6 +1,8 @@
helper_modern = get_option('helper_modern')
helper_legacy = get_option('helper_legacy')
helper_compat = ''
helper_emulated_modern = get_option('helper_emulated_modern')
helper_emulated_legacy = get_option('helper_emulated_legacy')
helper_depends = []
agent_modern = get_option('agent_modern')
@@ -18,6 +20,7 @@ server_depends = []
no_overridden_compat_bits = \
helper_modern == 'auto' and helper_legacy == 'auto' \
and helper_emulated_modern == 'auto' and helper_emulated_legacy == 'auto' \
and agent_modern == 'auto' and agent_legacy == 'auto' \
and agent_emulated_modern == 'auto' and agent_emulated_legacy == 'auto'
+5
View File
@@ -13,6 +13,7 @@ namespace Frida {
public abstract unowned ObjectBuilder add_uint64_value (uint64 val);
public abstract unowned ObjectBuilder add_data_value (Bytes val);
public abstract unowned ObjectBuilder add_string_value (string val);
public abstract unowned ObjectBuilder add_uuid_value (uint8[] val);
public abstract unowned ObjectBuilder add_raw_value (Bytes val);
public abstract Bytes build ();
@@ -238,6 +239,10 @@ namespace Frida {
return this;
}
public unowned ObjectBuilder add_uuid_value (uint8[] val) {
assert_not_reached ();
}
public unowned ObjectBuilder add_raw_value (Bytes val) {
string uuid = Uuid.string_random ();
builder.add_string_value (uuid);
+9
View File
@@ -65,8 +65,17 @@ namespace Frida {
});
});
var cancel_source = new CancellableSource (cancellable);
cancel_source.set_callback (() => {
connection.cancel ();
return Source.REMOVE;
});
cancel_source.attach (main_context);
yield;
cancel_source.destroy ();
if (reply.type == Darwin.Xpc.Error.TYPE) {
var e = (Darwin.Xpc.Error) reply;
throw new Error.NOT_SUPPORTED ("%s", e.get_string (Darwin.Xpc.Error.KEY_DESCRIPTION));
+6 -1
View File
@@ -30,11 +30,16 @@ public class Frida.TunnelInterfaceObserver : Object, DynamicInterfaceObserver {
context.info = this;
store = new Darwin.SystemConfiguration.DynamicStore (null, CoreFoundation.String.make ("Frida"),
on_interfaces_changed_wrapper, context);
var pattern = CoreFoundation.String.make ("State:/Network/Interface/utun.*/IPv6");
var patterns = new CoreFoundation.Array (null, ((CoreFoundation.Type[]) &pattern)[:1]);
store.set_notification_keys (null, patterns);
store.set_dispatch_queue (event_queue);
handle_interface_changes (store.copy_key_list (pattern));
var initial_keys = store.copy_key_list (pattern);
if (initial_keys != null)
handle_interface_changes (initial_keys);
}
private static void on_interfaces_changed_wrapper (Darwin.SystemConfiguration.DynamicStore store,
+14 -2
View File
@@ -68,13 +68,25 @@ option('compat',
option('helper_modern',
type: 'string',
value: 'auto',
description: 'Prebuilt frida-helper to embed for use on modern systems'
description: 'Prebuilt frida-helper to embed for supporting modern targets'
)
option('helper_legacy',
type: 'string',
value: 'auto',
description: 'Prebuilt frida-helper to embed for use on legacy systems'
description: 'Prebuilt frida-helper to embed for supporting legacy targets'
)
option('helper_emulated_modern',
type: 'string',
value: 'auto',
description: 'Prebuilt frida-helper to embed for supporting modern emulated targets'
)
option('helper_emulated_legacy',
type: 'string',
value: 'auto',
description: 'Prebuilt frida-helper to embed for supporting legacy emulated targets'
)
option('agent_modern',
+1 -1
Submodule releng updated: 54cc29651c...f1f6586b6a.
+23 -2
View File
@@ -183,6 +183,7 @@ struct _FridaSpawnInstance
GumAddress modern_entry_address;
/* V4+ */
GumAddress notify_objc_init;
GumAddress info_ptr_address;
/* V3- */
@@ -2030,6 +2031,10 @@ _frida_darwin_helper_backend_prepare_spawn_instance_for_injection (FridaDarwinHe
instance->dyld_flavor = (modern_entry_address != 0) ? FRIDA_DYLD_V4_PLUS : FRIDA_DYLD_V3_MINUS;
if (instance->dyld_flavor == FRIDA_DYLD_V4_PLUS)
{
instance->notify_objc_init = gum_darwin_module_resolve_symbol_address (dyld, "__ZN5dyld412RuntimeState14notifyObjCInitEPKNS_6LoaderE");
if (instance->notify_objc_init != 0)
modern_entry_address = instance->notify_objc_init;
instance->modern_entry_address = modern_entry_address;
legacy_entry_address = 0;
@@ -2108,7 +2113,12 @@ _frida_darwin_helper_backend_prepare_spawn_instance_for_injection (FridaDarwinHe
if (instance->dyld_flavor == FRIDA_DYLD_V4_PLUS)
{
GumAddress restart_with_dyld_in_cache = gum_darwin_module_resolve_symbol_address (dyld,
"__ZN5dyld422restartWithDyldInCacheEPKNS_10KernelArgsEPKN5dyld39MachOFileEPK15DyldSharedCachePv");
if (restart_with_dyld_in_cache == 0)
{
restart_with_dyld_in_cache = gum_darwin_module_resolve_symbol_address (dyld,
"__ZN5dyld422restartWithDyldInCacheEPKNS_10KernelArgsEPKN5dyld39MachOFileEPv");
}
if (restart_with_dyld_in_cache != 0)
frida_spawn_instance_set_nth_breakpoint (instance, i++, restart_with_dyld_in_cache, FRIDA_BREAKPOINT_REPEAT_NEVER);
}
@@ -3085,9 +3095,15 @@ frida_spawn_instance_handle_breakpoint (FridaSpawnInstance * self, FridaBreakpoi
if (self->dyld_flavor == FRIDA_DYLD_V4_PLUS)
{
if (pc == self->modern_entry_address)
self->breakpoint_phase = FRIDA_BREAKPOINT_SET_LIBDYLD_INITIALIZE_CALLER_BREAKPOINT;
{
self->breakpoint_phase = (pc == self->notify_objc_init)
? FRIDA_BREAKPOINT_LIBSYSTEM_INITIALIZED
: FRIDA_BREAKPOINT_SET_LIBDYLD_INITIALIZE_CALLER_BREAKPOINT;
}
else
{
return frida_spawn_instance_handle_dyld_restart (self);
}
}
else
{
@@ -3353,6 +3369,7 @@ frida_spawn_instance_handle_dyld_restart (FridaSpawnInstance * self)
GumAddress * info_ptr;
struct dyld_all_image_infos * info = NULL;
GumDarwinModule * dyld = NULL;
gssize delta;
info_ptr = (GumAddress *) gum_darwin_read (self->task, self->info_ptr_address, sizeof (GumAddress), NULL);
if (info_ptr == NULL)
@@ -3367,7 +3384,11 @@ frida_spawn_instance_handle_dyld_restart (FridaSpawnInstance * self)
if (dyld == NULL)
goto beach;
self->modern_entry_address = GUM_ADDRESS (info->dyldImageLoadAddress) + (self->modern_entry_address - self->dyld->base_address);
delta = (gssize) info->dyldImageLoadAddress - (gssize) self->dyld->base_address;
self->modern_entry_address += delta;
if (self->notify_objc_init != 0)
self->notify_objc_init += delta;
g_object_unref (self->dyld);
self->dyld = g_steal_pointer (&dyld);
+42 -18
View File
@@ -2,6 +2,7 @@ from pathlib import Path
import shutil
import subprocess
import sys
import struct
def main(argv):
@@ -27,29 +28,36 @@ def main(argv):
embedded_assets = []
if host_os == "windows":
for agent, flavor in [(agent_modern, "64"),
(agent_legacy, "32")]:
embedded_agent = priv_dir / f"frida-agent-{flavor}.dll"
embedded_dbghelp = priv_dir / f"dbghelp-{flavor}.dll"
embedded_symsrv = priv_dir / f"symsrv-{flavor}.dll"
pending_archs = {"arm64", "x86_64", "x86"}
for agent in {agent_modern, agent_legacy, agent_emulated_modern, agent_emulated_legacy}:
if agent is None:
continue
arch = detect_pefile_arch(agent)
embedded_agent = priv_dir / f"frida-agent-{arch}.dll"
embedded_dbghelp = priv_dir / f"dbghelp-{arch}.dll"
embedded_symsrv = priv_dir / f"symsrv-{arch}.dll"
if agent is not None:
shutil.copy(agent, embedded_agent)
shutil.copy(agent, embedded_agent)
if agent_dbghelp_prefix is not None:
shutil.copy(agent_dbghelp_prefix / flavor / "dbghelp.dll", embedded_dbghelp)
else:
embedded_dbghelp.write_bytes(b"")
if agent_symsrv_prefix is not None:
shutil.copy(agent_symsrv_prefix / flavor / "symsrv.dll", embedded_symsrv)
else:
embedded_symsrv.write_bytes(b"")
if agent_dbghelp_prefix is not None:
shutil.copy(agent_dbghelp_prefix / arch / "dbghelp.dll", embedded_dbghelp)
else:
for f in [embedded_agent, embedded_dbghelp, embedded_symsrv]:
f.write_bytes(b"")
embedded_dbghelp.write_bytes(b"")
if agent_symsrv_prefix is not None:
shutil.copy(agent_symsrv_prefix / arch / "symsrv.dll", embedded_symsrv)
else:
embedded_symsrv.write_bytes(b"")
embedded_assets += [embedded_agent, embedded_dbghelp, embedded_symsrv]
pending_archs.remove(arch)
for missing_arch in pending_archs:
embedded_agent = priv_dir / f"frida-agent-{missing_arch}.dll"
embedded_dbghelp = priv_dir / f"dbghelp-{missing_arch}.dll"
embedded_symsrv = priv_dir / f"symsrv-{missing_arch}.dll"
for asset in {embedded_agent, embedded_dbghelp, embedded_symsrv}:
asset.write_bytes(b"")
embedded_assets += [asset]
elif host_os in {"macos", "ios", "watchos", "tvos"}:
embedded_agent = priv_dir / "frida-agent.dylib"
if agent_modern is not None and agent_legacy is not None:
@@ -103,5 +111,21 @@ def pop_cmd_array_arg(args):
return result
def detect_pefile_arch(location):
with location.open(mode="rb") as pe:
pe.seek(0x3c)
e_lfanew, = struct.unpack("<I", pe.read(4))
pe.seek(e_lfanew + 4)
machine, = struct.unpack("<H", pe.read(2))
return PE_MACHINES[machine]
PE_MACHINES = {
0x014c: "x86",
0x8664: "x86_64",
0xaa64: "arm64",
}
if __name__ == "__main__":
main(sys.argv)
+37 -6
View File
@@ -2,6 +2,7 @@ from pathlib import Path
import shutil
import subprocess
import sys
import struct
def main(argv):
@@ -14,12 +15,28 @@ def main(argv):
output_dir = Path(args.pop(0))
priv_dir = Path(args.pop(0))
resource_config = args.pop(0)
helper_modern, helper_legacy = [Path(p) if p else None for p in args[:2]]
helper_modern, helper_legacy, \
helper_emulated_modern, helper_emulated_legacy \
= [Path(p) if p else None for p in args[:4]]
priv_dir.mkdir(exist_ok=True)
embedded_assets = []
if host_os in {"macos", "ios", "watchos", "tvos"}:
if host_os == "windows":
pending_archs = {"arm64", "x86_64", "x86"}
for helper in {helper_modern, helper_legacy, helper_emulated_modern, helper_emulated_legacy}:
if helper is None:
continue
arch = detect_pefile_arch(helper)
embedded_helper = priv_dir / f"frida-helper-{arch}.exe"
shutil.copy(helper, embedded_helper)
embedded_assets += [embedded_helper]
pending_archs.remove(arch)
for missing_arch in pending_archs:
embedded_helper = priv_dir / f"frida-helper-{missing_arch}.exe"
embedded_helper.write_bytes(b"")
embedded_assets += [embedded_helper]
elif host_os in {"macos", "ios", "watchos", "tvos"}:
embedded_helper = priv_dir / "frida-helper"
if helper_modern is not None and helper_legacy is not None:
@@ -34,10 +51,8 @@ def main(argv):
embedded_assets += [embedded_helper]
else:
exe_suffix = ".exe" if host_os == "windows" else ""
embedded_helper_modern = priv_dir / f"frida-helper-64{exe_suffix}"
embedded_helper_legacy = priv_dir / f"frida-helper-32{exe_suffix}"
embedded_helper_modern = priv_dir / f"frida-helper-64"
embedded_helper_legacy = priv_dir / f"frida-helper-32"
if helper_modern is not None:
shutil.copy(helper_modern, embedded_helper_modern)
@@ -74,5 +89,21 @@ def pop_cmd_array_arg(args):
return result
def detect_pefile_arch(location):
with location.open(mode="rb") as pe:
pe.seek(0x3c)
e_lfanew, = struct.unpack("<I", pe.read(4))
pe.seek(e_lfanew + 4)
machine, = struct.unpack("<H", pe.read(2))
return PE_MACHINES[machine]
PE_MACHINES = {
0x014c: "x86",
0x8664: "x86_64",
0xaa64: "arm64",
}
if __name__ == "__main__":
main(sys.argv)
+1 -1
View File
@@ -211,7 +211,7 @@ namespace Frida.Fruity {
}
}
public async Tunnel? find_tunnel (Cancellable? cancellable) throws Error, IOError {
public async Tunnel? find_tunnel (UsbmuxDevice? device, Cancellable? cancellable) throws Error, IOError {
while (tunnel_request != null) {
try {
return yield tunnel_request.future.wait_async (cancellable);
+5 -1
View File
@@ -121,12 +121,16 @@ _frida_fruity_windows_pairing_browser_enumerate_network_interfaces (FridaFruityW
for (adapter = adapters; adapter != NULL; adapter = adapter->Next)
{
SOCKET_ADDRESS * raw_addr = &adapter->FirstUnicastAddress->Address;
SOCKET_ADDRESS * raw_addr;
GInetSocketAddress * addr;
if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK)
continue;
if (adapter->FirstUnicastAddress == NULL)
continue;
raw_addr = &adapter->FirstUnicastAddress->Address;
addr = G_INET_SOCKET_ADDRESS (g_socket_address_new_from_native (raw_addr->lpSockaddr, raw_addr->iSockaddrLength));
func (adapter->IfIndex, adapter->AdapterName, addr, func_target);
+295 -161
View File
@@ -163,7 +163,9 @@ namespace Frida.Fruity {
public string name {
get {
var transport = transports.first_match (t => t.name != null);
var transport = transports.first_match (t => t.name != null && t.connection_type == USB);
if (transport == null)
transport = transports.first_match (t => t.name != null);
if (transport == null)
return "iOS Device";
return transport.name;
@@ -192,8 +194,10 @@ namespace Frida.Fruity {
transports.clear ();
}
public UsbmuxDevice? find_usbmux_device () throws Error {
var transport = transports.first_match (t => t.usbmux_device != null);
public UsbmuxDevice? find_usbmux_device () {
var transport = transports.first_match (t => t.usbmux_device != null && t.connection_type == USB);
if (transport == null)
transport = transports.first_match (t => t.usbmux_device != null);
return (transport != null) ? transport.usbmux_device : null;
}
@@ -205,8 +209,9 @@ namespace Frida.Fruity {
}
public async Tunnel? find_tunnel (Cancellable? cancellable) throws Error, IOError {
var usbmux_device = find_usbmux_device ();
foreach (var transport in transports) {
Tunnel? tunnel = yield transport.find_tunnel (cancellable);
Tunnel? tunnel = yield transport.find_tunnel (usbmux_device, cancellable);
if (tunnel != null)
return tunnel;
}
@@ -282,6 +287,7 @@ namespace Frida.Fruity {
private async void process_usbmux_lockdown_service_requests () {
UsbmuxLockdownServiceRequest? req;
bool already_invalidated = false;
while ((req = usbmux_lockdown_service_requests.peek ()) != null) {
try {
if (cached_usbmux_lockdown_client == null)
@@ -289,8 +295,10 @@ namespace Frida.Fruity {
var stream = yield cached_usbmux_lockdown_client.start_service (req.service_name, req.cancellable);
req.promise.resolve (stream);
} catch (GLib.Error e) {
if (e is Error.TRANSPORT && cached_usbmux_lockdown_client != null) {
if (e is LockdownError.CONNECTION_CLOSED && cached_usbmux_lockdown_client != null &&
!already_invalidated) {
cached_usbmux_lockdown_client = null;
already_invalidated = true;
continue;
}
req.promise.reject ((e is LockdownError.INVALID_SERVICE)
@@ -434,7 +442,7 @@ namespace Frida.Fruity {
get;
}
public abstract async Tunnel? find_tunnel (Cancellable? cancellable) throws Error, IOError;
public abstract async Tunnel? find_tunnel (UsbmuxDevice? device, Cancellable? cancellable) throws Error, IOError;
}
public enum ConnectionType {
@@ -695,12 +703,12 @@ namespace Frida.Fruity {
Object (device: device);
}
public async Tunnel? find_tunnel (Cancellable? cancellable) throws Error, IOError {
public async Tunnel? find_tunnel (UsbmuxDevice? device, Cancellable? cancellable) throws Error, IOError {
return null;
}
}
private sealed class PortableCoreDeviceBackend : Object, Backend {
private sealed class PortableCoreDeviceBackend : Object, Backend, UsbDeviceBackend {
public bool supports_modeswitch {
get {
return LibUSB.has_capability (HAS_HOTPLUG) != 0;
@@ -711,6 +719,7 @@ namespace Frida.Fruity {
private Gee.Set<PortableCoreDeviceUsbTransport> usb_transports = new Gee.HashSet<PortableCoreDeviceUsbTransport> ();
private Promise<bool> usb_started = new Promise<bool> ();
private Promise<bool> usb_stopped = new Promise<bool> ();
private bool modeswitch_allowed = false;
private Promise<bool>? modeswitch_activated;
private Gee.Set<string>? modeswitch_udids_pending;
@@ -723,12 +732,13 @@ namespace Frida.Fruity {
private Gee.Map<uint32, LibUSB.Device> polled_usb_devices = new Gee.HashMap<uint32, LibUSB.Device> ();
private Source? polled_usb_timer;
private uint polled_usb_outdated = 0;
private Gee.Set<unowned PendingUsbOperation> pending_usb_ops = new Gee.HashSet<unowned PendingUsbOperation> ();
private PairingBrowser network_browser = PairingBrowser.make_default ();
private Gee.Map<string, PortableCoreDeviceNetworkTransport> network_transports =
new Gee.HashMap<string, PortableCoreDeviceNetworkTransport> ();
private Gee.List<PairingIdentity.Peer> peers = PairingIdentity.load_peers ();
private PairingStore pairing_store = new PairingStore ();
private MainContext main_context;
@@ -738,6 +748,7 @@ namespace Frida.Fruity {
CREATED,
STARTING,
STARTED,
FLUSHING,
STOPPING,
STOPPED,
}
@@ -769,7 +780,7 @@ namespace Frida.Fruity {
}
public async void stop (Cancellable? cancellable) throws IOError {
state = STOPPING;
state = FLUSHING;
io_cancellable.cancel ();
@@ -782,18 +793,19 @@ namespace Frida.Fruity {
yield transport.close (cancellable);
network_transports.clear ();
usb_worker.join ();
usb_worker = null;
if (polled_usb_timer != null) {
polled_usb_timer.destroy ();
polled_usb_timer = null;
}
foreach (var transport in usb_transports.to_array ())
yield transport.close (cancellable);
usb_transports.clear ();
try {
yield usb_stopped.future.wait_async (cancellable);
} catch (Error e) {
assert_not_reached ();
}
usb_worker.join ();
usb_worker = null;
usb_context = null;
state = STOPPED;
@@ -802,7 +814,6 @@ namespace Frida.Fruity {
public async void activate_modeswitch_support (Cancellable? cancellable) throws IOError {
modeswitch_allowed = true;
modeswitch_activated = new Promise<bool> ();
modeswitch_udids_pending = new Gee.HashSet<string> ();
foreach (var transport in usb_transports.to_array ()) {
var usb_device = transport.usb_device;
@@ -813,18 +824,22 @@ namespace Frida.Fruity {
}
}
if (!modeswitch_udids_pending.is_empty) {
modeswitch_activated = new Promise<bool> ();
try {
yield modeswitch_activated.future.wait_async (cancellable);
} catch (Error e) {
assert_not_reached ();
}
modeswitch_activated = null;
}
modeswitch_udids_pending = null;
}
private void perform_usb_work () {
if (LibUSB.Context.init (out usb_context) != SUCCESS) {
schedule_on_frida_thread (() => {
usb_started.resolve (true);
usb_stopped.resolve (true);
return Source.REMOVE;
});
return;
@@ -832,6 +847,7 @@ namespace Frida.Fruity {
AtomicUint.inc (ref pending_usb_device_arrivals);
bool callbacks_registered = true;
if (LibUSB.has_capability (HAS_HOTPLUG) != 0) {
usb_context.hotplug_register_callback (DEVICE_ARRIVED | DEVICE_LEFT, ENUMERATE, VENDOR_ID_APPLE,
PRODUCT_ID_IPHONE, LibUSB.HotPlugEvent.MATCH_ANY, on_usb_hotplug_event, out iphone_callback);
@@ -863,7 +879,30 @@ namespace Frida.Fruity {
if (AtomicUint.compare_and_exchange (ref polled_usb_outdated, 1, 0))
refresh_polled_usb_devices ();
if (state == FLUSHING) {
if (callbacks_registered) {
usb_context.hotplug_deregister_callback (iphone_callback);
usb_context.hotplug_deregister_callback (ipad_callback);
callbacks_registered = false;
}
if (polled_usb_timer != null) {
polled_usb_timer.destroy ();
polled_usb_timer = null;
}
lock (pending_usb_ops) {
if (pending_usb_ops.is_empty)
state = STOPPING;
}
}
}
schedule_on_frida_thread (() => {
usb_stopped.resolve (true);
return Source.REMOVE;
});
}
private int on_usb_hotplug_event (LibUSB.Context ctx, LibUSB.Device device, LibUSB.HotPlugEvent event) {
@@ -914,12 +953,12 @@ namespace Frida.Fruity {
}
try {
device = yield UsbDevice.open (raw_device, io_cancellable);
device = yield UsbDevice.open (raw_device, this, io_cancellable);
if (modeswitch_allowed && yield device.maybe_modeswitch (io_cancellable))
break;
var transport = new PortableCoreDeviceUsbTransport (device);
var transport = new PortableCoreDeviceUsbTransport (device, pairing_store);
usb_transports.add (transport);
transport_attached (transport);
@@ -934,9 +973,8 @@ namespace Frida.Fruity {
if (AtomicUint.dec_and_test (ref pending_usb_device_arrivals) && state == STARTING)
usb_started.resolve (true);
if (device != null && modeswitch_udids_pending != null) {
modeswitch_udids_pending.remove (device.udid);
if (modeswitch_udids_pending.is_empty)
if (device != null && modeswitch_udids_pending != null && modeswitch_udids_pending.remove (device.udid)) {
if (modeswitch_udids_pending.is_empty && modeswitch_activated != null)
modeswitch_activated.resolve (true);
}
}
@@ -981,6 +1019,19 @@ namespace Frida.Fruity {
polled_usb_devices = current_devices;
}
private UsbOperation allocate_usb_operation () {
var op = new PendingUsbOperation (this);
lock (pending_usb_ops)
pending_usb_ops.add (op);
return op;
}
private void on_usb_operation_complete (PendingUsbOperation op) {
lock (pending_usb_ops)
pending_usb_ops.remove (op);
usb_context.interrupt_event_handler ();
}
private static uint32 make_usb_device_id (LibUSB.Device device, LibUSB.DeviceDescriptor desc) {
return ((uint32) device.get_port_number () << 24) |
((uint32) device.get_device_address () << 16) |
@@ -988,13 +1039,14 @@ namespace Frida.Fruity {
}
private void on_network_pairing_service_discovered (PairingServiceDetails service) {
var peer = find_peer (service);
var peer = pairing_store.find_peer_matching_service (service);
if (peer == null)
return;
var transport = network_transports[peer.udid];
if (transport == null) {
transport = new PortableCoreDeviceNetworkTransport (peer, service.endpoint, service.interface_address);
transport = new PortableCoreDeviceNetworkTransport (peer, pairing_store, service.endpoint,
service.interface_address);
network_transports[peer.udid] = transport;
transport_attached (transport);
} else {
@@ -1003,41 +1055,39 @@ namespace Frida.Fruity {
}
}
private PairingIdentity.Peer? find_peer (PairingServiceDetails service) {
var mac = OpenSSL.Envelope.MessageAuthCode.fetch (null, OpenSSL.ShortName.siphash);
size_t hash_size = 8;
size_t return_size = OpenSSL.ParamReturnSize.UNMODIFIED;
OpenSSL.Param mac_params[] = {
{ OpenSSL.Envelope.MessageAuthParameter.SIZE, UNSIGNED_INTEGER,
(uint8[]) &hash_size, return_size },
{ null, INTEGER, null, return_size },
};
foreach (var peer in peers) {
var ctx = new OpenSSL.Envelope.MessageAuthCodeContext (mac);
ctx.init (peer.irk.get_data (), mac_params);
ctx.update (service.identifier.data);
uint8 output[8];
size_t outlen = 0;
ctx.final (output, out outlen);
uint8 tag[6];
for (uint i = 0; i != 6; i++)
tag[i] = output[5 - i];
if (Memory.cmp (tag, service.auth_tag.get_data (), service.auth_tag.get_size ()) == 0)
return peer;
}
return null;
}
private void schedule_on_frida_thread (owned SourceFunc function) {
var source = new IdleSource ();
source.set_callback ((owned) function);
source.attach (main_context);
}
private class PendingUsbOperation : Object, UsbOperation {
public LibUSB.Transfer transfer {
get {
return _transfer;
}
}
private weak PortableCoreDeviceBackend backend;
private LibUSB.Transfer _transfer;
public PendingUsbOperation (PortableCoreDeviceBackend backend) {
this.backend = backend;
}
construct {
_transfer = new LibUSB.Transfer ();
}
public override void dispose () {
if (_transfer != null) {
_transfer = null;
backend.on_usb_operation_complete (this);
}
base.dispose ();
}
}
}
private sealed class PortableCoreDeviceUsbTransport : Object, Transport {
@@ -1046,6 +1096,11 @@ namespace Frida.Fruity {
construct;
}
public PairingStore pairing_store {
get;
construct;
}
public ConnectionType connection_type {
get {
return USB;
@@ -1077,26 +1132,30 @@ namespace Frida.Fruity {
}
private Promise<Tunnel>? tunnel_request;
private NcmPeer? ncm_peer;
public PortableCoreDeviceUsbTransport (UsbDevice usb_device) {
Object (usb_device: usb_device);
public PortableCoreDeviceUsbTransport (UsbDevice device, PairingStore store) {
Object (usb_device: device, pairing_store: store);
}
public async void close (Cancellable? cancellable) throws IOError {
if (tunnel_request != null) {
try {
var tunnel = yield tunnel_request.future.wait_async (cancellable);
yield tunnel.close (cancellable);
if (tunnel != null)
yield tunnel.close (cancellable);
} catch (Error e) {
} finally {
tunnel_request = null;
}
}
usb_device.close ();
ncm_peer = null;
yield usb_device.close (cancellable);
}
public async Tunnel? find_tunnel (Cancellable? cancellable) throws Error, IOError {
public async Tunnel? find_tunnel (UsbmuxDevice? device, Cancellable? cancellable) throws Error, IOError {
while (tunnel_request != null) {
try {
return yield tunnel_request.future.wait_async (cancellable);
@@ -1109,8 +1168,36 @@ namespace Frida.Fruity {
tunnel_request = new Promise<Tunnel> ();
try {
var tunnel = new PortableUsbTunnel (usb_device);
yield tunnel.open (cancellable);
bool supported_by_os = true;
if (device != null) {
try {
var lockdown = yield LockdownClient.open (device, cancellable);
yield lockdown.start_session (cancellable);
var response = yield lockdown.get_value (null, null, cancellable);
Fruity.PlistDict properties = response.get_dict ("Value");
if (properties.get_string ("ProductName") == "iPhone OS") {
uint ios_major_version = uint.parse (properties.get_string ("ProductVersion").split (".")[0]);
supported_by_os = ios_major_version >= 17;
}
} catch (LockdownError e) {
throw new Error.PERMISSION_DENIED ("%s", e.message);
}
}
PortableUsbTunnel? tunnel = null;
if (supported_by_os) {
if (ncm_peer == null)
ncm_peer = yield NcmPeer.locate (usb_device, cancellable);
tunnel = new PortableUsbTunnel (usb_device, ncm_peer, pairing_store);
tunnel.lost.connect (on_tunnel_lost);
try {
yield tunnel.open (cancellable);
} catch (Error e) {
if (!(e is Error.NOT_SUPPORTED))
throw e;
}
}
tunnel_request.resolve (tunnel);
@@ -1122,96 +1209,30 @@ namespace Frida.Fruity {
throw_api_error (e);
}
}
private void on_tunnel_lost () {
tunnel_request = null;
}
}
private sealed class PortableUsbTunnel : Object, Tunnel {
public UsbDevice usb_device {
get;
construct;
}
public DiscoveryService discovery {
get {
return _discovery_service;
}
}
private UsbNcmDriver? ncm;
private TunnelConnection? tunnel_connection;
private DiscoveryService? _discovery_service;
public PortableUsbTunnel (UsbDevice usb_device) {
Object (usb_device: usb_device);
}
public async void open (Cancellable? cancellable) throws Error, IOError {
var peer = yield locate_ncm_peer (cancellable);
var netstack = peer.netstack;
var bootstrap_rsd_endpoint = (InetSocketAddress) Object.new (typeof (InetSocketAddress),
address: peer.ip,
port: 58783,
scope_id: netstack.scope_id
);
var bootstrap_stream = yield netstack.open_tcp_connection (bootstrap_rsd_endpoint, cancellable);
var bootstrap_disco = yield DiscoveryService.open (bootstrap_stream, cancellable);
var tunnel_service = bootstrap_disco.get_service ("com.apple.internal.dt.coredevice.untrusted.tunnelservice");
var tunnel_endpoint = (InetSocketAddress) Object.new (typeof (InetSocketAddress),
address: peer.ip,
port: tunnel_service.port,
scope_id: netstack.scope_id
);
var pairing_transport = new XpcPairingTransport (yield netstack.open_tcp_connection (tunnel_endpoint, cancellable));
var pairing_service = yield PairingService.open (pairing_transport, cancellable);
TunnelConnection tc = yield pairing_service.open_tunnel (peer.ip, netstack, cancellable);
var rsd_endpoint = (InetSocketAddress) Object.new (typeof (InetSocketAddress),
address: tc.remote_address,
port: tc.remote_rsd_port,
scope_id: tc.tunnel_netstack.scope_id
);
var rsd_connection = yield tc.tunnel_netstack.open_tcp_connection (rsd_endpoint, cancellable);
var disco = yield DiscoveryService.open (rsd_connection, cancellable);
tunnel_connection = tc;
_discovery_service = disco;
}
public async void close (Cancellable? cancellable) throws IOError {
_discovery_service.close ();
tunnel_connection.cancel ();
private class NcmPeer {
public NetworkStack netstack;
public InetAddress ip;
public UsbNcmDriver? ncm;
~NcmPeer () {
if (ncm != null)
ncm.close ();
}
public async IOStream open_tcp_connection (uint16 port, Cancellable? cancellable) throws Error, IOError {
var netstack = tunnel_connection.tunnel_netstack;
var endpoint = (InetSocketAddress) Object.new (typeof (InetSocketAddress),
address: tunnel_connection.remote_address,
port: port,
scope_id: netstack.scope_id
);
return yield netstack.open_tcp_connection (endpoint, cancellable);
public static async NcmPeer locate (UsbDevice usb_device, Cancellable? cancellable) throws Error, IOError {
var device_ifaddrs = detect_ncm_ifaddrs_on_system (usb_device);
if (device_ifaddrs.size == 2)
return yield locate_on_system_netifs (device_ifaddrs, cancellable);
return yield establish_using_our_driver (usb_device, cancellable);
}
private async NcmPeer locate_ncm_peer (Cancellable? cancellable) throws Error, IOError {
var device_ifaddrs = detect_ncm_ifaddrs_on_system ();
if (!device_ifaddrs.is_empty)
return yield locate_ncm_peer_on_system_netifs (device_ifaddrs, cancellable);
return yield establish_ncm_peer_using_our_driver (cancellable);
}
private class NcmPeer {
public NetworkStack netstack;
public InetAddress ip;
}
private Gee.List<InetSocketAddress> detect_ncm_ifaddrs_on_system () throws Error {
private static Gee.List<InetSocketAddress> detect_ncm_ifaddrs_on_system (UsbDevice usb_device) throws Error {
var device_ifaddrs = new Gee.ArrayList<InetSocketAddress> ();
#if LINUX
@@ -1235,7 +1256,7 @@ namespace Frida.Fruity {
return device_ifaddrs;
}
private async NcmPeer locate_ncm_peer_on_system_netifs (Gee.List<InetSocketAddress> ifaddrs, Cancellable? cancellable)
private static async NcmPeer locate_on_system_netifs (Gee.List<InetSocketAddress> ifaddrs, Cancellable? cancellable)
throws Error, IOError {
var main_context = MainContext.ref_thread_default ();
@@ -1248,18 +1269,18 @@ namespace Frida.Fruity {
var handler = probe.response_received.connect ((probe, response, sender) => {
successful_probe = probe;
observed_sender = sender;
locate_ncm_peer_on_system_netifs.callback ();
locate_on_system_netifs.callback ();
});
probes.add (probe);
handlers[probe] = handler;
}
var timeout_source = new TimeoutSource.seconds (2);
timeout_source.set_callback (locate_ncm_peer_on_system_netifs.callback);
timeout_source.set_callback (locate_on_system_netifs.callback);
timeout_source.attach (main_context);
var cancel_source = new CancellableSource (cancellable);
cancel_source.set_callback (locate_ncm_peer_on_system_netifs.callback);
cancel_source.set_callback (locate_on_system_netifs.callback);
cancel_source.attach (main_context);
yield;
@@ -1279,6 +1300,7 @@ namespace Frida.Fruity {
return new NcmPeer () {
netstack = successful_probe.netstack,
ip = observed_sender.get_address (),
ncm = null,
};
}
@@ -1335,22 +1357,23 @@ namespace Frida.Fruity {
}
}
private async NcmPeer establish_ncm_peer_using_our_driver (Cancellable? cancellable) throws Error, IOError {
ncm = yield UsbNcmDriver.open (usb_device, cancellable);
private static async NcmPeer establish_using_our_driver (UsbDevice usb_device, Cancellable? cancellable)
throws Error, IOError {
var ncm = yield UsbNcmDriver.open (usb_device, cancellable);
if (ncm.remote_ipv6_address == null) {
ulong change_handler = ncm.notify["remote-ipv6-address"].connect ((obj, pspec) => {
establish_ncm_peer_using_our_driver.callback ();
establish_using_our_driver.callback ();
});
var main_context = MainContext.get_thread_default ();
var timeout_source = new TimeoutSource.seconds (2);
timeout_source.set_callback (establish_ncm_peer_using_our_driver.callback);
timeout_source.set_callback (establish_using_our_driver.callback);
timeout_source.attach (main_context);
var cancel_source = new CancellableSource (cancellable);
cancel_source.set_callback (establish_ncm_peer_using_our_driver.callback);
cancel_source.set_callback (establish_using_our_driver.callback);
cancel_source.attach (main_context);
yield;
@@ -1367,7 +1390,8 @@ namespace Frida.Fruity {
return new NcmPeer () {
netstack = ncm.netstack,
ip = ncm.remote_ipv6_address
ip = ncm.remote_ipv6_address,
ncm = ncm,
};
}
@@ -1400,8 +1424,108 @@ namespace Frida.Fruity {
}
}
private sealed class PortableUsbTunnel : Object, Tunnel {
public signal void lost ();
public UsbDevice usb_device {
get;
construct;
}
public NcmPeer ncm_peer {
get;
construct;
}
public PairingStore pairing_store {
get;
construct;
}
public DiscoveryService discovery {
get {
return _discovery_service;
}
}
private UsbNcmDriver? ncm;
private TunnelConnection? tunnel_connection;
private DiscoveryService? _discovery_service;
public PortableUsbTunnel (UsbDevice device, NcmPeer peer, PairingStore store) {
Object (
usb_device: device,
ncm_peer: peer,
pairing_store: store
);
}
public async void open (Cancellable? cancellable) throws Error, IOError {
var netstack = ncm_peer.netstack;
var bootstrap_rsd_endpoint = (InetSocketAddress) Object.new (typeof (InetSocketAddress),
address: ncm_peer.ip,
port: 58783,
scope_id: netstack.scope_id
);
var bootstrap_stream = yield netstack.open_tcp_connection (bootstrap_rsd_endpoint, cancellable);
var bootstrap_disco = yield DiscoveryService.open (bootstrap_stream, cancellable);
var tunnel_service = bootstrap_disco.get_service ("com.apple.internal.dt.coredevice.untrusted.tunnelservice");
var tunnel_endpoint = (InetSocketAddress) Object.new (typeof (InetSocketAddress),
address: ncm_peer.ip,
port: tunnel_service.port,
scope_id: netstack.scope_id
);
var pairing_transport = new XpcPairingTransport (yield netstack.open_tcp_connection (tunnel_endpoint, cancellable));
var pairing_service = yield PairingService.open (pairing_transport, pairing_store, cancellable);
TunnelConnection tc = yield pairing_service.open_tunnel (ncm_peer.ip, netstack, cancellable);
tc.close.connect (on_tunnel_connection_close);
var rsd_endpoint = (InetSocketAddress) Object.new (typeof (InetSocketAddress),
address: tc.remote_address,
port: tc.remote_rsd_port,
scope_id: tc.tunnel_netstack.scope_id
);
var rsd_connection = yield tc.tunnel_netstack.open_tcp_connection (rsd_endpoint, cancellable);
var disco = yield DiscoveryService.open (rsd_connection, cancellable);
tunnel_connection = tc;
_discovery_service = disco;
}
public async void close (Cancellable? cancellable) throws IOError {
_discovery_service.close ();
tunnel_connection.cancel ();
if (ncm != null)
ncm.close ();
}
public async IOStream open_tcp_connection (uint16 port, Cancellable? cancellable) throws Error, IOError {
var netstack = tunnel_connection.tunnel_netstack;
var endpoint = (InetSocketAddress) Object.new (typeof (InetSocketAddress),
address: tunnel_connection.remote_address,
port: port,
scope_id: netstack.scope_id
);
return yield netstack.open_tcp_connection (endpoint, cancellable);
}
private void on_tunnel_connection_close () {
lost ();
}
}
private sealed class PortableCoreDeviceNetworkTransport : Object, Transport {
public PairingIdentity.Peer peer {
public PairingPeer peer {
get;
construct;
}
public PairingStore pairing_store {
get;
construct;
}
@@ -1448,10 +1572,11 @@ namespace Frida.Fruity {
private Promise<Tunnel>? tunnel_request;
public PortableCoreDeviceNetworkTransport (PairingIdentity.Peer peer, InetSocketAddress endpoint,
public PortableCoreDeviceNetworkTransport (PairingPeer peer, PairingStore store, InetSocketAddress endpoint,
InetSocketAddress interface_address) {
Object (
peer: peer,
pairing_store: store,
endpoint: endpoint,
interface_address: interface_address
);
@@ -1469,7 +1594,7 @@ namespace Frida.Fruity {
}
}
public async Tunnel? find_tunnel (Cancellable? cancellable) throws Error, IOError {
public async Tunnel? find_tunnel (UsbmuxDevice? device, Cancellable? cancellable) throws Error, IOError {
while (tunnel_request != null) {
try {
return yield tunnel_request.future.wait_async (cancellable);
@@ -1482,7 +1607,7 @@ namespace Frida.Fruity {
tunnel_request = new Promise<Tunnel> ();
try {
var tunnel = new PortableNetworkTunnel (endpoint, interface_address);
var tunnel = new PortableNetworkTunnel (endpoint, interface_address, pairing_store);
yield tunnel.open (cancellable);
tunnel_request.resolve (tunnel);
@@ -1508,6 +1633,11 @@ namespace Frida.Fruity {
construct;
}
public PairingStore pairing_store {
get;
construct;
}
public DiscoveryService discovery {
get {
return _discovery_service;
@@ -1517,8 +1647,12 @@ namespace Frida.Fruity {
private TunnelConnection? tunnel_connection;
private DiscoveryService? _discovery_service;
public PortableNetworkTunnel (InetSocketAddress endpoint, InetSocketAddress interface_address) {
Object (endpoint: endpoint, interface_address: interface_address);
public PortableNetworkTunnel (InetSocketAddress endpoint, InetSocketAddress interface_address, PairingStore store) {
Object (
endpoint: endpoint,
interface_address: interface_address,
pairing_store: store
);
}
public async void open (Cancellable? cancellable) throws Error, IOError {
@@ -1526,7 +1660,7 @@ namespace Frida.Fruity {
var pairing_connection = yield netstack.open_tcp_connection (endpoint, cancellable);
var pairing_transport = new PlainPairingTransport (pairing_connection);
var pairing_service = yield PairingService.open (pairing_transport, cancellable);
var pairing_service = yield PairingService.open (pairing_transport, pairing_store, cancellable);
TunnelConnection tc = yield pairing_service.open_tunnel (endpoint.get_address (), netstack, cancellable);
+3
View File
@@ -265,6 +265,8 @@ namespace Frida.Fruity {
}
private static LockdownError error_from_service (PlistServiceError e) {
if (e is PlistServiceError.CONNECTION_CLOSED)
return new LockdownError.CONNECTION_CLOSED ("%s", e.message);
return new LockdownError.PROTOCOL ("%s", e.message);
}
@@ -274,6 +276,7 @@ namespace Frida.Fruity {
}
public errordomain LockdownError {
CONNECTION_CLOSED,
INVALID_SERVICE,
NOT_PAIRED,
UNSUPPORTED,
+24 -16
View File
@@ -76,10 +76,10 @@ namespace Frida.Fruity {
var dev_desc = LibUSB.DeviceDescriptor (raw_device);
int current_config;
Usb.check (handle.get_configuration (out current_config), "Failed to get current configuration");
LibUSB.ConfigDescriptor current_config;
Usb.check (raw_device.get_active_config_descriptor (out current_config), "Failed to get active config descriptor");
int desired_config = -1;
int desired_config_value = -1;
bool found_cdc_header = false;
bool found_data_interface = false;
uint8 mac_address_index = 0;
@@ -107,22 +107,24 @@ namespace Frida.Fruity {
data_altsetting = setting.bAlternateSetting;
foreach (var ep in setting.endpoint) {
if ((ep.bEndpointAddress & LibUSB.EndpointDirection.MASK) == LibUSB.EndpointDirection.IN)
if ((ep.bEndpointAddress & LibUSB.EndpointDirection.MASK) ==
LibUSB.EndpointDirection.IN) {
rx_address = ep.bEndpointAddress;
else
} else {
tx_address = ep.bEndpointAddress;
}
}
}
}
}
if (found_cdc_header || found_data_interface) {
desired_config = config_value;
desired_config_value = config_value;
break;
}
}
if (!found_cdc_header || !found_data_interface)
throw_user_error ("No USB CDC-NCM interface found");
throw new Error.NOT_SUPPORTED ("%s", make_user_error_message ("No USB CDC-NCM interface found"));
uint8 mac_address[6];
string mac_address_str = yield device.read_string_descriptor (mac_address_index, device.default_language_id,
@@ -135,13 +137,20 @@ namespace Frida.Fruity {
mac_address[i] = (uint8) v;
}
handle.detach_kernel_driver (data_iface);
if (current_config != desired_config)
Usb.check (handle.set_configuration (desired_config), "Failed to set configuration");
if (current_config.bConfigurationValue != desired_config_value) {
foreach (var iface in current_config.@interface) {
unowned LibUSB.InterfaceDescriptor setting = iface.altsetting[0];
var res = handle.kernel_driver_active (setting.bInterfaceNumber);
if (res == 1)
handle.detach_kernel_driver (setting.bInterfaceNumber);
}
Usb.check (handle.set_configuration (desired_config_value), "Failed to set configuration");
}
try {
Usb.check (handle.claim_interface (data_iface), "Failed to claim USB interface");
} catch (Error e) {
throw_user_error (@"Unable to claim USB CDC-NCM interface ($(e.message))");
throw new Error.PERMISSION_DENIED ("%s",
make_user_error_message (@"Unable to claim USB CDC-NCM interface ($(e.message))"));
}
Usb.check (handle.set_interface_alt_setting (data_iface, data_altsetting),
"Failed to set USB interface alt setting");
@@ -154,13 +163,12 @@ namespace Frida.Fruity {
return true;
}
[NoReturn]
private void throw_user_error (string message) throws Error {
private string make_user_error_message (string message) {
#if WINDOWS
throw new Error.NOT_SUPPORTED ("%s; use https://zadig.akeo.ie to switch from Apple's official driver onto " +
"Microsoft's WinUSB driver, so libusb can access it", message);
return message + "; use https://zadig.akeo.ie to switch from Apple's official driver onto Microsoft's WinUSB " +
"driver, so libusb can access it";
#else
throw new Error.NOT_SUPPORTED ("%s", message);
return message;
#endif
}
+16 -5
View File
@@ -147,6 +147,7 @@ namespace Frida.Fruity {
private State state = STARTED;
private Gee.Queue<Request> requests = new Gee.ArrayQueue<Request> ();
private unowned Thread<bool>? lwip_thread;
private LWIP.NetworkInterface handle;
private LWIP.IP6Address raw_ipv6_address;
@@ -287,18 +288,29 @@ namespace Frida.Fruity {
internal LWIP.ErrorCode perform_on_lwip_thread (owned WorkFunc work) {
var req = new Request ((owned) work);
lock (requests)
requests.offer (req);
LWIP.Runtime.schedule (perform_next_request);
if (Thread.self<bool> () == lwip_thread) {
perform_request (req);
} else {
lock (requests)
requests.offer (req);
LWIP.Runtime.schedule (perform_next_request);
}
return req.join ();
}
private void perform_next_request () {
if (lwip_thread == null)
lwip_thread = Thread.self ();
Request req;
lock (requests)
req = requests.poll ();
perform_request (req);
}
private static void perform_request (Request req) {
LWIP.ErrorCode err = req.work ();
req.complete (err);
}
@@ -549,9 +561,8 @@ namespace Frida.Fruity {
_state = CLOSED;
update_events ();
if (!established.future.ready) {
if (!established.future.ready)
established.reject (parse_error (err));
}
return Source.REMOVE;
});
+51 -7
View File
@@ -7,6 +7,11 @@ namespace Frida.Fruity {
}
}
public UsbDeviceBackend backend {
get;
construct;
}
public LibUSB.DeviceHandle? handle {
get {
return _handle;
@@ -29,6 +34,8 @@ namespace Frida.Fruity {
private LibUSB.DeviceHandle? _handle;
private string _udid;
private uint16 _default_language_id;
private uint num_pending_operations;
private Promise<bool>? pending_operations_completed;
private enum AppleSpecificRequest {
GET_MODE = 0x45,
@@ -38,8 +45,9 @@ namespace Frida.Fruity {
private const string MODE_INITIAL_UNTETHERED = "3:3:3:0"; // => 5:3:3:0
private const string MODE_INITIAL_TETHERED = "4:4:3:4"; // => 5:4:3:4
public static async UsbDevice open (LibUSB.Device raw_device, Cancellable? cancellable = null) throws Error, IOError {
var device = new UsbDevice (raw_device);
public static async UsbDevice open (LibUSB.Device raw_device, UsbDeviceBackend backend, Cancellable? cancellable = null)
throws Error, IOError {
var device = new UsbDevice (raw_device, backend);
try {
yield device.init_async (Priority.DEFAULT, cancellable);
@@ -50,8 +58,8 @@ namespace Frida.Fruity {
return device;
}
private UsbDevice (LibUSB.Device raw_device) {
Object ();
private UsbDevice (LibUSB.Device raw_device, UsbDeviceBackend backend) {
Object (backend: backend);
_raw_device = raw_device;
}
@@ -71,7 +79,17 @@ namespace Frida.Fruity {
return true;
}
public void close () {
public async void close (Cancellable? cancellable) throws IOError {
if (num_pending_operations != 0) {
pending_operations_completed = new Promise<bool> ();
try {
yield pending_operations_completed.future.wait_async (cancellable);
} catch (Error e) {
assert_not_reached ();
}
pending_operations_completed = null;
}
_handle = null;
_raw_device = null;
}
@@ -174,7 +192,8 @@ namespace Frida.Fruity {
public async Bytes control_transfer (uint8 request_type, uint8 request, uint16 val, uint16 index, uint16 length,
uint timeout, Cancellable? cancellable) throws Error, IOError {
var transfer = new LibUSB.Transfer ();
var op = backend.allocate_usb_operation ();
unowned LibUSB.Transfer transfer = op.transfer;
var ready_closure = new TransferReadyClosure (control_transfer.callback);
var buffer = new uint8[sizeof (LibUSB.ControlSetup) + length];
@@ -190,7 +209,9 @@ namespace Frida.Fruity {
try {
Usb.check (transfer.submit (), "Failed to submit control transfer");
on_operation_started ();
yield;
on_operation_ended ();
} finally {
cancel_source.destroy ();
}
@@ -202,7 +223,8 @@ namespace Frida.Fruity {
public async size_t bulk_transfer (uint8 endpoint, uint8[] buffer, uint timeout, Cancellable? cancellable)
throws Error, IOError {
var transfer = new LibUSB.Transfer ();
var op = backend.allocate_usb_operation ();
unowned LibUSB.Transfer transfer = op.transfer;
var ready_closure = new TransferReadyClosure (bulk_transfer.callback);
transfer.fill_bulk_transfer (_handle, endpoint, buffer, on_transfer_ready, ready_closure, timeout);
@@ -216,7 +238,9 @@ namespace Frida.Fruity {
try {
Usb.check (transfer.submit (), "Failed to submit bulk transfer");
on_operation_started ();
yield;
on_operation_ended ();
} finally {
cancel_source.destroy ();
}
@@ -226,6 +250,16 @@ namespace Frida.Fruity {
return transfer.actual_length;
}
private void on_operation_started () {
num_pending_operations++;
}
private void on_operation_ended () {
num_pending_operations--;
if (num_pending_operations == 0 && pending_operations_completed != null)
pending_operations_completed.resolve (true);
}
private static void on_transfer_ready (LibUSB.Transfer transfer) {
TransferReadyClosure * closure = transfer.user_data;
closure->schedule ();
@@ -252,6 +286,16 @@ namespace Frida.Fruity {
}
}
internal interface UsbDeviceBackend : Object {
public abstract UsbOperation allocate_usb_operation ();
}
internal interface UsbOperation : Object {
public abstract LibUSB.Transfer transfer {
get;
}
}
namespace Usb {
internal static void check (LibUSB.Error error, string prefix) throws Error {
if (error >= LibUSB.Error.SUCCESS)
+261 -138
View File
@@ -14,6 +14,8 @@ namespace Frida.Fruity {
private Promise<Variant> handshake_promise = new Promise<Variant> ();
private Variant handshake_body;
private Cancellable io_cancellable = new Cancellable ();
public static async DiscoveryService open (IOStream stream, Cancellable? cancellable = null) throws Error, IOError {
var service = new DiscoveryService (stream);
@@ -42,6 +44,7 @@ namespace Frida.Fruity {
}
public void close () {
io_cancellable.cancel ();
connection.cancel ();
}
@@ -87,8 +90,30 @@ namespace Frida.Fruity {
reader.read_member ("MessageType");
unowned string message_type = reader.get_string_value ();
if (message_type == "Handshake")
if (message_type == "Handshake") {
handshake_promise.resolve (msg.body);
connection.post.begin (
new XpcBodyBuilder ()
.begin_dictionary ()
.set_member_name ("MessageType")
.add_string_value ("Handshake")
.set_member_name ("MessagingProtocolVersion")
.add_uint64_value (5)
.set_member_name ("Services")
.begin_dictionary ()
.end_dictionary ()
.set_member_name ("Properties")
.begin_dictionary ()
.set_member_name ("RemoteXPCVersionFlags")
.add_uint64_value (0x100000000000006)
.end_dictionary ()
.set_member_name ("UUID")
.add_uuid_value (make_random_v4_uuid ())
.end_dictionary ()
.build (),
io_cancellable);
}
} catch (Error e) {
}
}
@@ -106,6 +131,11 @@ namespace Frida.Fruity {
construct;
}
public PairingStore store {
get;
construct;
}
public DeviceOptions device_options {
get;
private set;
@@ -121,14 +151,12 @@ namespace Frida.Fruity {
private uint64 next_control_sequence_number = 0;
private uint64 next_encrypted_sequence_number = 0;
private string host_identifier;
private Key pair_record_key;
private ChaCha20Poly1305? client_cipher;
private ChaCha20Poly1305? server_cipher;
public static async PairingService open (PairingTransport transport, Cancellable? cancellable = null)
public static async PairingService open (PairingTransport transport, PairingStore store, Cancellable? cancellable = null)
throws Error, IOError {
var service = new PairingService (transport);
var service = new PairingService (transport, store);
try {
yield service.init_async (Priority.DEFAULT, cancellable);
@@ -139,26 +167,13 @@ namespace Frida.Fruity {
return service;
}
private PairingService (PairingTransport transport) {
Object (transport: transport);
private PairingService (PairingTransport transport, PairingStore store) {
Object (transport: transport, store: store);
}
construct {
transport.close.connect (on_close);
transport.message.connect (on_message);
Bytes? key;
var identity = PairingIdentity.try_load ();
if (identity != null) {
key = identity.private_key;
host_identifier = identity.identifier;
} else {
uint8 dummy_key[32] = { 0, };
key = new Bytes (dummy_key);
host_identifier = make_host_identifier ();
}
pair_record_key = new Key.from_raw_private_key (ED25519, null, key.get_data ());
}
private async bool init_async (int io_priority, Cancellable? cancellable) throws Error, IOError {
@@ -361,6 +376,10 @@ namespace Frida.Fruity {
.build ();
var start_response = yield request_pairing_data (start_payload, cancellable);
if (start_response.has_member ("error")) {
yield notify_pair_verify_failed (cancellable);
return null;
}
uint8[] raw_device_pubkey = start_response.read_member ("public-key").get_data_value ().get_data ();
start_response.end_member ();
var device_pubkey = new Key.from_raw_public_key (X25519, null, raw_device_pubkey);
@@ -378,11 +397,13 @@ namespace Frida.Fruity {
new Bytes.static ("\x00\x00\x00\x00PV-Msg02".data[:12]),
start_response.read_member ("encrypted-data").get_data_value ())));
unowned string host_identifier = store.self_identity.identifier;
var message = new ByteArray.sized (100);
message.append (raw_host_pubkey);
message.append (host_identifier.data);
message.append (raw_device_pubkey);
Bytes signature = compute_message_signature (ByteArray.free_to_bytes ((owned) message), pair_record_key);
Bytes signature = compute_message_signature (ByteArray.free_to_bytes ((owned) message), store.self_identity.key);
Bytes inner_params = new PairingParamsBuilder ()
.add_identifier (host_identifier)
@@ -410,25 +431,29 @@ namespace Frida.Fruity {
ObjectReader finish_response = yield request_pairing_data (finish_payload, cancellable);
if (finish_response.has_member ("error")) {
yield post_plain (transport.make_object_builder ()
.begin_dictionary ()
.set_member_name ("event")
.begin_dictionary ()
.set_member_name ("_0")
.begin_dictionary ()
.set_member_name ("pairVerifyFailed")
.begin_dictionary ()
.end_dictionary ()
.end_dictionary ()
.end_dictionary ()
.end_dictionary ()
.build (), cancellable);
yield notify_pair_verify_failed (cancellable);
return null;
}
return shared_key;
}
private async void notify_pair_verify_failed (Cancellable? cancellable) throws Error, IOError {
yield post_plain (transport.make_object_builder ()
.begin_dictionary ()
.set_member_name ("event")
.begin_dictionary ()
.set_member_name ("_0")
.begin_dictionary ()
.set_member_name ("pairVerifyFailed")
.begin_dictionary ()
.end_dictionary ()
.end_dictionary ()
.end_dictionary ()
.end_dictionary ()
.build (), cancellable);
}
private async Bytes setup_manual_pairing (Cancellable? cancellable) throws Error, IOError {
Bytes start_params = new PairingParamsBuilder ()
.add_method (0)
@@ -494,33 +519,29 @@ namespace Frida.Fruity {
var cipher = new ChaCha20Poly1305 (operation_key);
Key new_pair_record_key = make_keypair (ED25519);
Bytes new_pair_record_pubkey = get_raw_public_key (new_pair_record_key);
uint8 raw_irk[16];
Rng.generate (raw_irk);
Bytes irk = new Bytes (raw_irk);
Bytes signing_key = derive_chacha_key (shared_key,
"Pair-Setup-Controller-Sign-Info",
"Pair-Setup-Controller-Sign-Salt");
unowned PairingIdentity self_identity = store.self_identity;
Bytes self_identity_pubkey = get_raw_public_key (self_identity.key);
var message = new ByteArray.sized (100);
message.append (signing_key.get_data ());
message.append (host_identifier.data);
message.append (new_pair_record_pubkey.get_data ());
Bytes signature = compute_message_signature (ByteArray.free_to_bytes ((owned) message), new_pair_record_key);
message.append (self_identity.identifier.data);
message.append (self_identity_pubkey.get_data ());
Bytes signature = compute_message_signature (ByteArray.free_to_bytes ((owned) message), self_identity.key);
Bytes self_info = new OpackBuilder ()
.begin_dictionary ()
.set_member_name ("name")
.add_string_value (Environment.get_host_name ())
.set_member_name ("accountID")
.add_string_value (host_identifier)
.add_string_value (self_identity.identifier)
.set_member_name ("remotepairing_serial_number")
.add_string_value ("AAAAAAAAAAAA")
.set_member_name ("altIRK")
.add_data_value (irk)
.add_data_value (self_identity.irk)
.set_member_name ("model")
.add_string_value ("computer-model")
.set_member_name ("mac")
@@ -531,8 +552,8 @@ namespace Frida.Fruity {
.build ();
Bytes inner_params = new PairingParamsBuilder ()
.add_identifier (host_identifier)
.add_raw_public_key (new_pair_record_pubkey)
.add_identifier (self_identity.identifier)
.add_raw_public_key (self_identity_pubkey)
.add_signature (signature)
.add_info (self_info)
.build ();
@@ -569,17 +590,7 @@ namespace Frida.Fruity {
inner_finish_response.end_member ();
Bytes peer_info = inner_finish_response.read_member ("info").get_data_value ();
inner_finish_response.end_member ();
PairingIdentity.save_peer (peer_identifier, peer_pubkey, peer_info);
var identity = new PairingIdentity () {
identifier = host_identifier,
public_key = new_pair_record_pubkey,
private_key = get_raw_private_key (new_pair_record_key),
irk = irk
};
identity.save ();
pair_record_key = (owned) new_pair_record_key;
store.add_peer (peer_identifier, peer_pubkey, peer_info);
return shared_key;
}
@@ -745,16 +756,6 @@ namespace Frida.Fruity {
}
}
private static Key make_keypair (KeyType type) {
var ctx = new KeyContext.for_key_type (type);
ctx.keygen_init ();
Key? keypair = null;
ctx.keygen (ref keypair);
return keypair;
}
private static uint8[] key_to_der (Key key) {
var sink = new BasicIO (BasicIOMethod.memory ());
key.to_der (sink);
@@ -1331,64 +1332,36 @@ namespace Frida.Fruity {
}
}
public class PairingIdentity {
public string identifier;
public Bytes public_key;
public Bytes private_key;
public Bytes irk;
public static PairingIdentity? try_load () {
try {
Bytes raw_identity = query_self_identity_location ().load_bytes ();
Plist identity = new Plist.from_data (raw_identity.get_data ());
return new PairingIdentity () {
identifier = identity.get_string ("identifier"),
public_key = identity.get_bytes ("publicKey"),
private_key = identity.get_bytes ("privateKey"),
irk = identity.get_bytes ("irk")
};
} catch (GLib.Error e) {
return null;
public class PairingStore {
public PairingIdentity self_identity {
get {
return _self_identity;
}
}
public void save () throws Error {
var plist = new Plist ();
plist.set_string ("identifier", identifier);
plist.set_bytes ("publicKey", public_key);
plist.set_bytes ("privateKey", private_key);
plist.set_bytes ("irk", irk);
save_plist (plist, query_self_identity_location ());
public Gee.Iterable<PairingPeer> peers {
get {
return _peers;
}
}
public static Gee.List<Peer> load_peers () {
var peers = new Gee.ArrayList<Peer> ();
private PairingIdentity _self_identity;
private Gee.List<PairingPeer> _peers;
try {
var enumerator = query_peers_location ().enumerate_children (FileAttribute.STANDARD_NAME, FileQueryInfoFlags.NONE);
File? child;
while (enumerator.iterate (null, out child) && child != null) {
Plist plist = new Plist.from_data (child.load_bytes ().get_data ());
var reader = new VariantReader (OpackParser.parse (plist.get_bytes ("info")));
unowned string udid = reader.read_member ("remotepairing_udid").get_string_value ();
peers.add (new Peer () {
identifier = plist.get_string ("identifier"),
public_key = plist.get_bytes ("publicKey"),
irk = plist.get_bytes ("irk"),
name = plist.get_string ("name"),
model = plist.get_string ("model"),
udid = udid,
});
public PairingStore () {
_self_identity = try_load_identity ();
if (_self_identity == null) {
_self_identity = PairingIdentity.make ();
try {
save_identity (_self_identity);
} catch (GLib.Error e) {
}
} catch (GLib.Error e) {
}
return peers;
_peers = load_peers ();
}
public static void save_peer (string identifier, Bytes public_key, Bytes info) throws Error {
public void add_peer (string identifier, Bytes public_key, Bytes info) throws Error {
var r = new VariantReader (OpackParser.parse (info));
Bytes irk = r.read_member ("altIRK").get_data_value ();
@@ -1400,21 +1373,123 @@ namespace Frida.Fruity {
unowned string model = r.read_member ("model").get_string_value ();
r.end_member ();
var plist = new Plist ();
plist.set_string ("identifier", identifier);
plist.set_bytes ("publicKey", public_key);
plist.set_bytes ("irk", irk);
plist.set_string ("name", name);
plist.set_string ("model", model);
plist.set_bytes ("info", info);
save_plist (plist, query_peers_location ().get_child (identifier + ".plist"));
unowned string udid = r.read_member ("remotepairing_udid").get_string_value ();
r.end_member ();
var peer = new PairingPeer () {
identifier = identifier,
public_key = public_key,
irk = irk,
name = name,
model = model,
udid = udid,
info = info,
};
_peers.add (peer);
try {
save_peer (peer);
} catch (Error e) {
}
}
public static File query_self_identity_location () {
public PairingPeer? find_peer_matching_service (PairingServiceDetails service) {
var mac = OpenSSL.Envelope.MessageAuthCode.fetch (null, OpenSSL.ShortName.siphash);
size_t hash_size = 8;
size_t return_size = OpenSSL.ParamReturnSize.UNMODIFIED;
OpenSSL.Param mac_params[] = {
{ OpenSSL.Envelope.MessageAuthParameter.SIZE, UNSIGNED_INTEGER,
(uint8[]) &hash_size, return_size },
{ null, INTEGER, null, return_size },
};
foreach (var peer in _peers) {
var ctx = new OpenSSL.Envelope.MessageAuthCodeContext (mac);
ctx.init (peer.irk.get_data (), mac_params);
ctx.update (service.identifier.data);
uint8 output[8];
size_t outlen = 0;
ctx.final (output, out outlen);
uint8 tag[6];
for (uint i = 0; i != 6; i++)
tag[i] = output[5 - i];
if (Memory.cmp (tag, service.auth_tag.get_data (), service.auth_tag.get_size ()) == 0)
return peer;
}
return null;
}
private static PairingIdentity? try_load_identity () {
try {
var plist = new Plist.from_data (query_self_identity_location ().load_bytes ().get_data ());
return new PairingIdentity () {
identifier = plist.get_string ("identifier"),
key = new Key.from_raw_private_key (ED25519, null, plist.get_bytes ("privateKey").get_data ()),
irk = plist.get_bytes ("irk"),
};
} catch (GLib.Error e) {
return null;
}
}
private static void save_identity (PairingIdentity identity) throws Error {
var plist = new Plist ();
plist.set_string ("identifier", identity.identifier);
plist.set_bytes ("publicKey", get_raw_public_key (identity.key));
plist.set_bytes ("privateKey", get_raw_private_key (identity.key));
plist.set_bytes ("irk", identity.irk);
save_plist (plist, query_self_identity_location ());
}
private static Gee.List<PairingPeer> load_peers () {
var peers = new Gee.ArrayList<PairingPeer> ();
try {
var enumerator = query_peers_location ().enumerate_children (FileAttribute.STANDARD_NAME, FileQueryInfoFlags.NONE);
File? child;
while (enumerator.iterate (null, out child) && child != null) {
var plist = new Plist.from_data (child.load_bytes ().get_data ());
var info = plist.get_bytes ("info");
var r = new VariantReader (OpackParser.parse (info));
unowned string udid = r.read_member ("remotepairing_udid").get_string_value ();
peers.add (new PairingPeer () {
identifier = plist.get_string ("identifier"),
public_key = plist.get_bytes ("publicKey"),
irk = plist.get_bytes ("irk"),
name = plist.get_string ("name"),
model = plist.get_string ("model"),
udid = udid,
info = info,
});
}
} catch (GLib.Error e) {
}
return peers;
}
private static void save_peer (PairingPeer peer) throws Error {
var plist = new Plist ();
plist.set_string ("identifier", peer.identifier);
plist.set_bytes ("publicKey", peer.public_key);
plist.set_bytes ("irk", peer.irk);
plist.set_string ("name", peer.name);
plist.set_string ("model", peer.model);
plist.set_bytes ("info", peer.info);
save_plist (plist, query_peers_location ().get_child (peer.identifier + ".plist"));
}
private static File query_self_identity_location () {
return query_base_location ().get_child ("self-identity.plist");
}
public static File query_peers_location () {
private static File query_peers_location () {
return query_base_location ().get_child ("peers");
}
@@ -1428,22 +1503,40 @@ namespace Frida.Fruity {
} catch (GLib.Error e) {
}
try {
location.replace_contents (plist.to_xml ().data, null, false, PRIVATE | REPLACE_DESTINATION, null);
location.replace_contents (plist.to_binary (), null, false, PRIVATE | REPLACE_DESTINATION, null);
} catch (GLib.Error e) {
throw new Error.NOT_SUPPORTED ("%s", e.message);
}
}
}
public class Peer {
public string identifier;
public Bytes public_key;
public Bytes irk;
public string name;
public string model;
public string udid;
public class PairingIdentity {
public string identifier;
public Key key;
public Bytes irk;
public static PairingIdentity make () {
uint8 raw_irk[16];
Rng.generate (raw_irk);
return new PairingIdentity () {
identifier = make_host_identifier (),
key = make_keypair (ED25519),
irk = new Bytes (raw_irk),
};
}
}
public class PairingPeer {
public string identifier;
public Bytes public_key;
public Bytes irk;
public string name;
public string model;
public string udid;
public Bytes info;
}
public class PairingServiceMetadata {
public string identifier;
public Bytes auth_tag;
@@ -1660,6 +1753,8 @@ namespace Frida.Fruity {
}
public sealed class TunnelConnection : Object, AsyncInitable {
public signal void close ();
public InetSocketAddress address {
get;
construct;
@@ -1870,7 +1965,7 @@ namespace Frida.Fruity {
}
private void on_control_stream_opened () {
var zeroed_padding_packet = new uint8[1024];
var zeroed_padding_packet = new uint8[PREFERRED_MTU];
send_datagram (new Bytes.take ((owned) zeroed_padding_packet));
send_request (Json.to_string (
@@ -1928,6 +2023,8 @@ namespace Frida.Fruity {
}
public void cancel () {
if (connection != null)
close ();
connection = null;
socket = null;
@@ -2002,8 +2099,6 @@ namespace Frida.Fruity {
}
private void send_datagram (Bytes datagram) {
if (connection == null)
return;
tx_datagrams.offer (datagram);
process_pending_writes ();
}
@@ -2033,7 +2128,7 @@ namespace Frida.Fruity {
}
private void process_pending_writes () {
if (write_idle != null)
if (connection == null || write_idle != null)
return;
var source = new IdleSource ();
@@ -2159,6 +2254,13 @@ namespace Frida.Fruity {
}
private int on_stream_close (uint32 flags, int64 stream_id, uint64 app_error_code) {
if (!established.future.ready) {
established.reject (new Error.TRANSPORT ("Connection closed early with QUIC app error code %" +
uint64.FORMAT_MODIFIER + "u", app_error_code));
}
cancel ();
return 0;
}
@@ -3643,6 +3745,16 @@ namespace Frida.Fruity {
public const uint32 VERSION = 5;
}
private Key make_keypair (KeyType type) {
var ctx = new KeyContext.for_key_type (type);
ctx.keygen_init ();
Key? keypair = null;
ctx.keygen (ref keypair);
return keypair;
}
private Bytes get_raw_public_key (Key key) {
size_t size = 0;
key.get_raw_public_key (null, ref size);
@@ -3695,4 +3807,15 @@ namespace Frida.Fruity {
return result.str;
}
private uint8[] make_random_v4_uuid () {
uint8 uuid[16];
OpenSSL.Rng.generate (uuid);
const uint8 uuid_version = 4;
uuid[6] = (uuid_version << 4) | (uuid[6] & 0xf);
uuid[8] = 0x80 | (uuid[8] & 0x3f);
return uuid;
}
}
+4
View File
@@ -1931,6 +1931,10 @@ namespace Frida {
try {
yield suspend (null);
close ();
} catch (Error e) {
// If the process is gone, then there's no point in retrying.
if (e is Error.PROCESS_NOT_FOUND)
attach_state = ALREADY_ATTACHED;
} catch (GLib.Error e) {
}
}
+17 -5
View File
@@ -44,6 +44,14 @@ if have_local_backend
'@INPUT0@',
]
if helper_emulated_modern == 'auto'
helper_emulated_modern = ''
endif
if helper_emulated_legacy == 'auto'
helper_emulated_legacy = ''
endif
if host_os_family == 'windows'
backend_sources += [
'windows' / 'windows-host-session.vala',
@@ -54,6 +62,7 @@ if have_local_backend
'windows' / 'frida-helper-process-glue.c',
'windows' / 'access-helpers.c',
]
backend_vala_args += '--pkg=frida-gum-windows-1.0'
helper_backend_sources = [
'windows' / 'frida-helper-backend.vala',
@@ -61,7 +70,10 @@ if have_local_backend
'windows' / 'frida-helper-types.vala',
'windows' / 'wait-handle-source.c',
]
helper_backend_vala_args = base_vala_args
helper_backend_vala_args = [
base_vala_args,
'--pkg=frida-gum-windows-1.0',
]
helper_backend = static_library('frida-helper-backend', helper_backend_sources,
vala_args: helper_backend_vala_args,
c_args: frida_component_cflags,
@@ -105,7 +117,7 @@ if have_local_backend
'frida-data-helper-process.c',
'frida-data-helper-process-blob' + resource_blob_extension,
],
command: embed_helper + [helper_modern, helper_legacy],
command: embed_helper + [helper_modern, helper_legacy, helper_emulated_modern, helper_emulated_legacy],
depends: helper_depends,
)
backend_sources += [helper_process_data]
@@ -253,7 +265,7 @@ if have_local_backend
'frida-data-helper-process.c',
'frida-data-helper-process-blob' + resource_blob_extension,
],
command: embed_helper + [helper_modern, helper_legacy],
command: embed_helper + [helper_modern, helper_legacy, helper_emulated_modern, helper_emulated_legacy],
depends: helper_depends,
)
backend_sources += [helper_process_data]
@@ -406,7 +418,7 @@ if have_local_backend
'frida-data-helper-process.c',
'frida-data-helper-process-blob' + resource_blob_extension,
],
command: embed_helper + [helper_modern, helper_legacy],
command: embed_helper + [helper_modern, helper_legacy, helper_emulated_modern, helper_emulated_legacy],
depends: helper_depends,
)
backend_sources += [helper_process_data]
@@ -568,7 +580,7 @@ subdir('compiler')
core_sources = base_sources + backend_sources + compiler_sources
internal_libs = [base, pipe] + backend_libs
internal_libs = [base, netif, pipe] + backend_libs
internal_deps = [base_dep, netif_dep, pipe_dep]
if host_os_family == 'windows'
+161 -131
View File
@@ -2,6 +2,7 @@
#include <gio/gio.h>
#include <gum/gum.h>
#include <gum/arch-arm64/gumarm64writer.h>
#include <gum/arch-x86/gumx86writer.h>
#include <windows.h>
@@ -75,6 +76,7 @@ static void frida_propagate_open_process_error (guint32 pid, DWORD os_error, GEr
static gboolean frida_enable_debug_privilege (void);
static gboolean frida_remote_worker_context_init (FridaRemoteWorkerContext * rwc, FridaInjectionDetails * details, GError ** error);
static gsize frida_remote_worker_context_emit_payload (FridaRemoteWorkerContext * rwc, gpointer code);
static void frida_remote_worker_context_destroy (FridaRemoteWorkerContext * rwc, FridaInjectionDetails * details);
static gboolean frida_remote_worker_context_has_resolved_all_kernel32_functions (const FridaRemoteWorkerContext * rwc);
@@ -304,16 +306,169 @@ frida_remote_worker_context_init (FridaRemoteWorkerContext * rwc, FridaInjection
{
gpointer code;
guint code_size;
GumX86Writer cw;
const gchar * loadlibrary_failed = "loadlibrary_failed";
const gchar * skip_unload = "skip_unload";
const gchar * return_result = "return_result";
SIZE_T page_size, alloc_size;
DWORD old_protect;
gum_init ();
code = gum_alloc_n_pages (1, GUM_PAGE_RWX); /* Executable so debugger can be used to inspect code */
code_size = frida_remote_worker_context_emit_payload (rwc, code);
memset (rwc, 0, sizeof (FridaRemoteWorkerContext));
gum_module_enumerate_exports ("kernel32.dll", frida_remote_worker_context_collect_kernel32_export, rwc);
if (!frida_remote_worker_context_has_resolved_all_kernel32_functions (rwc))
goto failed_to_resolve_kernel32_functions;
StringCbCopyW (rwc->dll_path, sizeof (rwc->dll_path), details->dll_path);
StringCbCopyA (rwc->entrypoint_name, sizeof (rwc->entrypoint_name), details->entrypoint_name);
StringCbCopyA (rwc->entrypoint_data, sizeof (rwc->entrypoint_data), details->entrypoint_data);
page_size = gum_query_page_size ();
g_assert (code_size <= page_size);
alloc_size = page_size + sizeof (FridaRemoteWorkerContext);
rwc->entrypoint = VirtualAllocEx (details->process_handle, NULL, alloc_size, MEM_COMMIT, PAGE_READWRITE);
if (rwc->entrypoint == NULL)
goto virtual_alloc_ex_failed;
if (!WriteProcessMemory (details->process_handle, rwc->entrypoint, code, code_size, NULL))
goto write_process_memory_failed;
rwc->argument = GSIZE_TO_POINTER (GPOINTER_TO_SIZE (rwc->entrypoint) + page_size);
if (!WriteProcessMemory (details->process_handle, rwc->argument, rwc, sizeof (FridaRemoteWorkerContext), NULL))
goto write_process_memory_failed;
if (!VirtualProtectEx (details->process_handle, rwc->entrypoint, page_size, PAGE_EXECUTE_READ, &old_protect))
goto virtual_protect_ex_failed;
gum_free_pages (code);
return TRUE;
/* ERRORS */
failed_to_resolve_kernel32_functions:
{
g_set_error (error,
FRIDA_ERROR,
FRIDA_ERROR_NOT_SUPPORTED,
"Unexpected error while resolving kernel32 functions");
goto error_common;
}
virtual_alloc_ex_failed:
{
g_set_error (error,
FRIDA_ERROR,
FRIDA_ERROR_NOT_SUPPORTED,
"Unexpected error allocating memory in target process (VirtualAllocEx returned 0x%08lx)",
GetLastError ());
goto error_common;
}
write_process_memory_failed:
{
g_set_error (error,
FRIDA_ERROR,
FRIDA_ERROR_NOT_SUPPORTED,
"Unexpected error writing to memory in target process (WriteProcessMemory returned 0x%08lx)",
GetLastError ());
goto error_common;
}
virtual_protect_ex_failed:
{
g_set_error (error,
FRIDA_ERROR,
FRIDA_ERROR_NOT_SUPPORTED,
"Unexpected error changing memory permission in target process (VirtualProtectEx returned 0x%08lx)",
GetLastError ());
goto error_common;
}
error_common:
{
frida_remote_worker_context_destroy (rwc, details);
gum_free_pages (code);
return FALSE;
}
}
#define EMIT_ARM64_LOAD(reg, field) \
gum_arm64_writer_put_ldr_reg_reg_offset (&cw, ARM64_REG_##reg, ARM64_REG_X20, G_STRUCT_OFFSET (FridaRemoteWorkerContext, field))
#define EMIT_ARM64_LOAD_ADDRESS_OF(reg, field) \
gum_arm64_writer_put_add_reg_reg_imm (&cw, ARM64_REG_##reg, ARM64_REG_X20, G_STRUCT_OFFSET (FridaRemoteWorkerContext, field))
#define EMIT_ARM64_MOVE(dstreg, srcreg) \
gum_arm64_writer_put_mov_reg_reg (&cw, ARM64_REG_##dstreg, ARM64_REG_##srcreg)
#define EMIT_ARM64_CALL(reg) \
gum_arm64_writer_put_blr_reg_no_auth (&cw, ARM64_REG_##reg)
static gsize
frida_remote_worker_context_emit_payload (FridaRemoteWorkerContext * rwc, gpointer code)
{
gsize code_size;
const gchar * loadlibrary_failed = "loadlibrary_failed";
const gchar * skip_unload = "skip_unload";
const gchar * return_result = "return_result";
#ifdef HAVE_ARM64
GumArm64Writer cw;
gum_arm64_writer_init (&cw, code);
gum_arm64_writer_put_push_reg_reg (&cw, ARM64_REG_FP, ARM64_REG_LR);
gum_arm64_writer_put_mov_reg_reg (&cw, ARM64_REG_FP, ARM64_REG_SP);
gum_arm64_writer_put_push_reg_reg (&cw, ARM64_REG_X19, ARM64_REG_X20);
/* x20 = (FridaRemoteWorkerContext *) lpParameter */
EMIT_ARM64_MOVE (X20, X0);
/* x19 = LoadLibrary (x20->dll_path) */
EMIT_ARM64_LOAD_ADDRESS_OF (X0, dll_path);
EMIT_ARM64_LOAD (X8, load_library_impl);
EMIT_ARM64_CALL (X8);
gum_arm64_writer_put_cbz_reg_label (&cw, ARM64_REG_X0, loadlibrary_failed);
EMIT_ARM64_MOVE (X19, X0);
/* x8 = GetProcAddress (x19, x20->entrypoint_name) */
EMIT_ARM64_MOVE (X0, X19);
EMIT_ARM64_LOAD_ADDRESS_OF (X1, entrypoint_name);
EMIT_ARM64_LOAD (X8, get_proc_address_impl);
EMIT_ARM64_CALL (X8);
EMIT_ARM64_MOVE (X8, X0);
/* x8 (x20->entrypoint_data, &x20->stay_resident, NULL) */
EMIT_ARM64_LOAD_ADDRESS_OF (X0, entrypoint_data);
EMIT_ARM64_LOAD_ADDRESS_OF (X1, stay_resident);
EMIT_ARM64_MOVE (X2, XZR);
EMIT_ARM64_CALL (X8);
/* if (!x20->stay_resident) { */
EMIT_ARM64_LOAD (X0, stay_resident);
gum_arm64_writer_put_cbnz_reg_label (&cw, ARM64_REG_X0, skip_unload);
/* FreeLibrary (xsi) */
EMIT_ARM64_MOVE (X0, X19);
EMIT_ARM64_LOAD (X8, free_library_impl);
EMIT_ARM64_CALL (X8);
/* } */
gum_arm64_writer_put_label (&cw, skip_unload);
/* result = ERROR_SUCCESS */
EMIT_ARM64_MOVE (X0, XZR);
gum_arm64_writer_put_b_label (&cw, return_result);
gum_arm64_writer_put_label (&cw, loadlibrary_failed);
/* result = GetLastError() */
EMIT_ARM64_LOAD (X8, get_last_error_impl);
EMIT_ARM64_CALL (X8);
gum_arm64_writer_put_label (&cw, return_result);
gum_arm64_writer_put_pop_reg_reg (&cw, ARM64_REG_X19, ARM64_REG_X20);
gum_arm64_writer_put_pop_reg_reg (&cw, ARM64_REG_FP, ARM64_REG_LR);
gum_arm64_writer_put_ret (&cw);
gum_arm64_writer_flush (&cw);
code_size = gum_arm64_writer_offset (&cw);
gum_arm64_writer_clear (&cw);
#else
GumX86Writer cw;
gum_x86_writer_init (&cw, code);
/* Will clobber these */
@@ -393,80 +548,9 @@ frida_remote_worker_context_init (FridaRemoteWorkerContext * rwc, FridaInjection
gum_x86_writer_flush (&cw);
code_size = gum_x86_writer_offset (&cw);
gum_x86_writer_clear (&cw);
#endif
memset (rwc, 0, sizeof (FridaRemoteWorkerContext));
gum_module_enumerate_exports ("kernel32.dll", frida_remote_worker_context_collect_kernel32_export, rwc);
if (!frida_remote_worker_context_has_resolved_all_kernel32_functions (rwc))
goto failed_to_resolve_kernel32_functions;
StringCbCopyW (rwc->dll_path, sizeof (rwc->dll_path), details->dll_path);
StringCbCopyA (rwc->entrypoint_name, sizeof (rwc->entrypoint_name), details->entrypoint_name);
StringCbCopyA (rwc->entrypoint_data, sizeof (rwc->entrypoint_data), details->entrypoint_data);
page_size = gum_query_page_size ();
g_assert (code_size <= page_size);
alloc_size = page_size + sizeof (FridaRemoteWorkerContext);
rwc->entrypoint = VirtualAllocEx (details->process_handle, NULL, alloc_size, MEM_COMMIT, PAGE_READWRITE);
if (rwc->entrypoint == NULL)
goto virtual_alloc_ex_failed;
if (!WriteProcessMemory (details->process_handle, rwc->entrypoint, code, code_size, NULL))
goto write_process_memory_failed;
rwc->argument = GSIZE_TO_POINTER (GPOINTER_TO_SIZE (rwc->entrypoint) + page_size);
if (!WriteProcessMemory (details->process_handle, rwc->argument, rwc, sizeof (FridaRemoteWorkerContext), NULL))
goto write_process_memory_failed;
if (!VirtualProtectEx (details->process_handle, rwc->entrypoint, page_size, PAGE_EXECUTE_READ, &old_protect))
goto virtual_protect_ex_failed;
gum_free_pages (code);
return TRUE;
/* ERRORS */
failed_to_resolve_kernel32_functions:
{
g_set_error (error,
FRIDA_ERROR,
FRIDA_ERROR_NOT_SUPPORTED,
"Unexpected error while resolving kernel32 functions");
goto error_common;
}
virtual_alloc_ex_failed:
{
g_set_error (error,
FRIDA_ERROR,
FRIDA_ERROR_NOT_SUPPORTED,
"Unexpected error allocating memory in target process (VirtualAllocEx returned 0x%08lx)",
GetLastError ());
goto error_common;
}
write_process_memory_failed:
{
g_set_error (error,
FRIDA_ERROR,
FRIDA_ERROR_NOT_SUPPORTED,
"Unexpected error writing to memory in target process (WriteProcessMemory returned 0x%08lx)",
GetLastError ());
goto error_common;
}
virtual_protect_ex_failed:
{
g_set_error (error,
FRIDA_ERROR,
FRIDA_ERROR_NOT_SUPPORTED,
"Unexpected error changing memory permission in target process (VirtualProtectEx returned 0x%08lx)",
GetLastError ());
goto error_common;
}
error_common:
{
frida_remote_worker_context_destroy (rwc, details);
gum_free_pages (code);
return FALSE;
}
return code_size;
}
static void
@@ -508,60 +592,6 @@ frida_remote_worker_context_collect_kernel32_export (const GumExportDetails * de
return TRUE;
}
gboolean
frida_windows_system_is_x64 (void)
{
static gboolean initialized = FALSE;
static gboolean system_is_x64;
if (!initialized)
{
SYSTEM_INFO si;
GetNativeSystemInfo (&si);
system_is_x64 = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64;
initialized = TRUE;
}
return system_is_x64;
}
gboolean
frida_windows_process_is_x64 (guint32 pid, GError ** error)
{
HANDLE process_handle;
BOOL is_wow64, success;
if (!frida_windows_system_is_x64 ())
return FALSE;
process_handle = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, pid);
if (process_handle == NULL)
goto open_failed;
success = IsWow64Process (process_handle, &is_wow64);
CloseHandle (process_handle);
if (!success)
goto query_failed;
return !is_wow64;
open_failed:
{
frida_propagate_open_process_error (pid, GetLastError (), error);
return FALSE;
}
query_failed:
{
g_set_error (error,
FRIDA_ERROR,
FRIDA_ERROR_NOT_SUPPORTED,
"Unexpected error while interrogating process with pid %u (IsWow64Process failed)",
pid);
return FALSE;
}
}
static gboolean
frida_file_exists_and_is_readable (const WCHAR * filename)
{
+27 -9
View File
@@ -49,7 +49,7 @@ namespace Frida {
public async void inject_library_file (uint pid, PathTemplate path_template, string entrypoint, string data,
string[] dependencies, uint id, Cancellable? cancellable) throws Error {
string path = path_template.expand (WindowsProcess.is_x64 (pid) ? "64" : "32");
string path = path_template.expand (arch_name_from_pid (pid));
string target_dependent_path;
if (level == ELEVATED) {
@@ -101,6 +101,32 @@ namespace Frida {
protected extern static void _free_inject_instance (void * inject_instance, out bool is_resident);
}
public unowned string arch_name_from_pid (uint pid) throws Error {
switch (cpu_type_from_pid (pid)) {
case Gum.CpuType.IA32:
return "x86";
case Gum.CpuType.AMD64:
return "x86_64";
case Gum.CpuType.ARM64:
return "arm64";
default:
assert_not_reached ();
}
}
public Gum.CpuType cpu_type_from_pid (uint pid) throws Error {
try {
return Gum.Windows.cpu_type_from_pid (pid);
} catch (Gum.Error e) {
if (e is Gum.Error.NOT_FOUND)
throw new Error.PROCESS_NOT_FOUND ("Unable to find process with pid %u", pid);
else if (e is Gum.Error.PERMISSION_DENIED)
throw new Error.PERMISSION_DENIED ("Unable to access process with pid %u", pid);
else
throw new Error.NOT_SUPPORTED ("%s", e.message);
}
}
private class AssetDirectory {
public File file {
get;
@@ -206,14 +232,6 @@ namespace Frida {
}
}
namespace WindowsSystem {
public extern static bool is_x64 ();
}
namespace WindowsProcess {
public extern static bool is_x64 (uint32 pid) throws Error;
}
namespace WaitHandleSource {
public extern Source create (void * handle, bool owns_handle);
}
+33 -24
View File
@@ -57,9 +57,7 @@ namespace Frida {
string[] dependencies, uint id, Cancellable? cancellable) throws Error, IOError {
bool permission_denied = false;
try {
unowned string local_arch = sizeof (void *) == 8 ? "64" : "32";
unowned string remote_arch = WindowsProcess.is_x64 (pid) ? "64" : "32";
if (remote_arch == local_arch) {
if (cpu_type_from_pid (pid) == Gum.NATIVE_CPU) {
yield inprocess_backend.inject_library_file (pid, path_template, entrypoint, data, dependencies,
id, cancellable);
return;
@@ -172,15 +170,11 @@ namespace Frida {
Error? error = null;
try {
string native_helper_path = WindowsSystem.is_x64 ()
? resource_store.helper64.path
: resource_store.helper32.path;
string level_str = (level == PrivilegeLevel.ELEVATED) ? "ELEVATED" : "NORMAL";
void * process = spawn (native_helper_path,
void * process = spawn (resource_store.native_helper.path,
"MANAGER %s %s".printf (level_str, transport.remote_address),
level);
instance = new HelperInstance (resource_store.helper32, resource_store.helper64, transport,
stream_request, process);
instance = new HelperInstance (resource_store.helpers, transport, stream_request, process);
} catch (Error e) {
error = e;
}
@@ -247,8 +241,7 @@ namespace Frida {
}
}
private TemporaryFile helper32;
private TemporaryFile helper64;
private Gee.Collection<TemporaryFile> helpers;
private PipeTransport transport;
private Future<IOStream> stream_request;
private DBusConnection connection;
@@ -257,10 +250,9 @@ namespace Frida {
private Gee.Set<uint> injectee_ids = new Gee.HashSet<uint> ();
public HelperInstance (TemporaryFile helper32, TemporaryFile helper64, PipeTransport transport,
Future<IOStream> stream_request, void * process) {
this.helper32 = helper32;
this.helper64 = helper64;
public HelperInstance (Gee.Collection<TemporaryFile> helpers, PipeTransport transport, Future<IOStream> stream_request,
void * process) {
this.helpers = helpers;
this.transport = transport;
this.stream_request = stream_request;
this.process = process;
@@ -375,26 +367,43 @@ namespace Frida {
}
private class ResourceStore {
public TemporaryFile helper32 {
public TemporaryFile native_helper {
get;
private set;
}
public TemporaryFile helper64 {
public Gee.Collection<TemporaryFile> helpers {
get;
private set;
default = new Gee.ArrayList<TemporaryFile> ();
}
public ResourceStore (TemporaryDirectory tempdir) throws Error {
var blob32 = Frida.Data.Helper.get_frida_helper_32_exe_blob ();
helper32 = new TemporaryFile.from_stream ("frida-helper-32.exe",
new MemoryInputStream.from_data (blob32.data, null),
tempdir);
var helper_arm64 = add_helper ("arm64", Frida.Data.Helper.get_frida_helper_arm64_exe_blob (), tempdir);
var helper_x86_64 = add_helper ("x86_64", Frida.Data.Helper.get_frida_helper_x86_64_exe_blob (), tempdir);
var helper_x86 = add_helper ("x86", Frida.Data.Helper.get_frida_helper_x86_exe_blob (), tempdir);
var blob64 = Frida.Data.Helper.get_frida_helper_64_exe_blob ();
helper64 = new TemporaryFile.from_stream ("frida-helper-64.exe",
new MemoryInputStream.from_data (blob64.data, null),
switch (Gum.Windows.query_native_cpu_type ()) {
case ARM64:
native_helper = helper_arm64;
break;
case AMD64:
native_helper = helper_x86_64;
break;
case IA32:
native_helper = helper_x86;
break;
default:
assert_not_reached ();
}
}
private TemporaryFile add_helper (string name, Frida.Data.Helper.Blob blob, TemporaryDirectory tempdir) throws Error {
var file = new TemporaryFile.from_stream (@"frida-helper-$name.exe",
new MemoryInputStream.from_data (blob.data, null),
tempdir);
helpers.add (file);
return file;
}
}
}
+75 -102
View File
@@ -2,10 +2,12 @@
#include <windows.h>
#if GLIB_SIZEOF_VOID_P == 8
# define FRIDA_HELPER_SERVICE_ARCH "64"
#if defined (HAVE_ARM64)
# define FRIDA_HELPER_SERVICE_ARCH "arm64"
#elif GLIB_SIZEOF_VOID_P == 8
# define FRIDA_HELPER_SERVICE_ARCH "x86_64"
#else
# define FRIDA_HELPER_SERVICE_ARCH "32"
# define FRIDA_HELPER_SERVICE_ARCH "x86"
#endif
#define STANDALONE_JOIN_TIMEOUT_MSEC (5 * 1000)
@@ -17,25 +19,23 @@ struct _FridaServiceContext
gchar * service_basename;
SC_HANDLE scm;
SC_HANDLE service32;
SC_HANDLE service64;
HANDLE standalone32;
HANDLE standalone64;
GQueue system_services;
GQueue standalone_services;
};
static void WINAPI frida_managed_helper_service_main (DWORD argc, WCHAR ** argv);
static DWORD WINAPI frida_managed_helper_service_handle_control_code (DWORD control, DWORD event_type, void * event_data, void * context);
static void frida_managed_helper_service_report_status (DWORD current_state, DWORD exit_code, DWORD wait_hint);
static gboolean frida_register_and_start_services (FridaServiceContext * self);
static gboolean frida_register_and_start_services (FridaServiceContext * self, gchar ** archs, gint archs_length);
static void frida_stop_and_unregister_services (FridaServiceContext * self);
static gboolean frida_spawn_standalone_services (FridaServiceContext * self);
static gboolean frida_spawn_standalone_services (FridaServiceContext * self, gchar ** archs, gint archs_length);
static gboolean frida_join_standalone_services (FridaServiceContext * self);
static void frida_kill_standalone_services (FridaServiceContext * self);
static void frida_release_standalone_services (FridaServiceContext * self);
static gboolean frida_register_services (FridaServiceContext * self);
static gboolean frida_register_services (FridaServiceContext * self, gchar ** archs, gint archs_length);
static gboolean frida_unregister_services (FridaServiceContext * self);
static gboolean frida_start_services (FridaServiceContext * self);
static gboolean frida_stop_services (FridaServiceContext * self);
@@ -59,7 +59,7 @@ static WCHAR * frida_managed_helper_service_name = NULL;
static SERVICE_STATUS_HANDLE frida_managed_helper_service_status_handle = NULL;
void *
frida_helper_manager_start_services (const char * service_basename, FridaPrivilegeLevel level)
frida_helper_manager_start_services (const char * service_basename, gchar ** archs, gint archs_length, FridaPrivilegeLevel level)
{
FridaServiceContext * self;
@@ -72,7 +72,7 @@ frida_helper_manager_start_services (const char * service_basename, FridaPrivile
{
frida_unregister_stale_services (self);
if (!frida_register_and_start_services (self))
if (!frida_register_and_start_services (self, archs, archs_length))
{
CloseServiceHandle (self->scm);
self->scm = NULL;
@@ -81,7 +81,7 @@ frida_helper_manager_start_services (const char * service_basename, FridaPrivile
if (self->scm == NULL)
{
if (!frida_spawn_standalone_services (self))
if (!frida_spawn_standalone_services (self, archs, archs_length))
{
frida_service_context_free (self);
self = NULL;
@@ -138,15 +138,16 @@ char *
frida_helper_service_derive_filename_for_suffix (const char * suffix)
{
WCHAR filename_utf16[MAX_PATH + 1] = { 0, };
gchar * name, * tmp;
gchar * name, * tail, * tmp;
glong len;
GetModuleFileNameW (NULL, filename_utf16, MAX_PATH);
name = g_utf16_to_utf8 (filename_utf16, -1, NULL, &len, NULL);
if (g_str_has_suffix (name, "-32.exe") || g_str_has_suffix (name, "-64.exe"))
tail = strrchr (name, '-');
if (tail != NULL)
{
name[len - 6] = '\0';
tail[1] = '\0';
tmp = g_strconcat (name, suffix, ".exe", NULL);
g_free (name);
name = tmp;
@@ -293,9 +294,9 @@ frida_managed_helper_service_report_status (DWORD current_state, DWORD exit_code
}
static gboolean
frida_register_and_start_services (FridaServiceContext * self)
frida_register_and_start_services (FridaServiceContext * self, gchar ** archs, gint archs_length)
{
if (!frida_register_services (self))
if (!frida_register_services (self, archs, archs_length))
return FALSE;
if (!frida_start_services (self))
@@ -315,44 +316,35 @@ frida_stop_and_unregister_services (FridaServiceContext * self)
}
static gboolean
frida_spawn_standalone_services (FridaServiceContext * self)
frida_spawn_standalone_services (FridaServiceContext * self, gchar ** archs, gint archs_length)
{
HANDLE standalone32, standalone64;
gint i;
standalone32 = frida_spawn_standalone_service (self, "32");
if (standalone32 == NULL)
return FALSE;
if (frida_windows_system_is_x64 ())
for (i = 0; i != archs_length; i++)
{
standalone64 = frida_spawn_standalone_service (self, "64");
if (standalone64 == NULL)
{
frida_kill_standalone_service (self, standalone32);
CloseHandle (standalone32);
return FALSE;
}
HANDLE service = frida_spawn_standalone_service (self, archs[i]);
if (service == NULL)
goto unable_to_spawn;
g_queue_push_tail (&self->standalone_services, service);
}
else
{
standalone64 = NULL;
}
self->standalone32 = standalone32;
self->standalone64 = standalone64;
return TRUE;
unable_to_spawn:
{
frida_kill_standalone_services (self);
return FALSE;
}
}
static gboolean
frida_join_standalone_services (FridaServiceContext * self)
{
gboolean success = TRUE;
GList * cur;
if (frida_windows_system_is_x64 ())
success &= frida_join_standalone_service (self, self->standalone64);
success &= frida_join_standalone_service (self, self->standalone32);
for (cur = self->standalone_services.head; cur != NULL; cur = cur->next)
success &= frida_join_standalone_service (self, cur->data);
if (success)
frida_release_standalone_services (self);
@@ -363,10 +355,10 @@ frida_join_standalone_services (FridaServiceContext * self)
static void
frida_kill_standalone_services (FridaServiceContext * self)
{
if (frida_windows_system_is_x64 ())
frida_kill_standalone_service (self, self->standalone64);
GList * cur;
frida_kill_standalone_service (self, self->standalone32);
for (cur = self->standalone_services.head; cur != NULL; cur = cur->next)
frida_kill_standalone_service (self, cur->data);
frida_release_standalone_services (self);
}
@@ -374,94 +366,77 @@ frida_kill_standalone_services (FridaServiceContext * self)
static void
frida_release_standalone_services (FridaServiceContext * self)
{
if (frida_windows_system_is_x64 ())
{
g_assert (self->standalone64 != NULL);
CloseHandle (self->standalone64);
self->standalone64 = NULL;
}
HANDLE service;
g_assert (self->standalone32 != NULL);
CloseHandle (self->standalone32);
self->standalone32 = NULL;
while ((service = g_queue_pop_tail (&self->standalone_services)) != NULL)
CloseHandle (service);
}
static gboolean
frida_register_services (FridaServiceContext * self)
frida_register_services (FridaServiceContext * self, gchar ** archs, gint archs_length)
{
SC_HANDLE service32, service64;
gint i;
service32 = frida_register_service (self, "32");
if (service32 == NULL)
return FALSE;
if (frida_windows_system_is_x64 ())
for (i = 0; i != archs_length; i++)
{
service64 = frida_register_service (self, "64");
if (service64 == NULL)
{
frida_unregister_service (self, service32);
CloseServiceHandle (service32);
return FALSE;
}
SC_HANDLE service = frida_register_service (self, archs[i]);
if (service == NULL)
goto unable_to_register;
g_queue_push_tail (&self->system_services, service);
}
else
{
service64 = NULL;
}
self->service32 = service32;
self->service64 = service64;
return TRUE;
unable_to_register:
{
frida_unregister_services (self);
return FALSE;
}
}
static gboolean
frida_unregister_services (FridaServiceContext * self)
{
gboolean success = TRUE;
SC_HANDLE service;
if (frida_windows_system_is_x64 ())
while ((service = g_queue_pop_tail (&self->system_services)) != NULL)
{
success &= frida_unregister_service (self, self->service64);
CloseServiceHandle (self->service64);
self->service64 = NULL;
success &= frida_unregister_service (self, service);
CloseServiceHandle (service);
}
success &= frida_unregister_service (self, self->service32);
CloseServiceHandle (self->service32);
self->service32 = NULL;
return success;
}
static gboolean
frida_start_services (FridaServiceContext * self)
{
if (!frida_start_service (self, self->service32))
return FALSE;
GList * cur;
if (frida_windows_system_is_x64 ())
for (cur = self->system_services.head; cur != NULL; cur = cur->next)
{
if (!frida_start_service (self, self->service64))
{
frida_stop_service (self, self->service32);
return FALSE;
}
if (!frida_start_service (self, cur->data))
goto unable_to_start;
}
return TRUE;
unable_to_start:
{
frida_stop_services (self);
return FALSE;
}
}
static gboolean
frida_stop_services (FridaServiceContext * self)
{
gboolean success = TRUE;
GList * cur;
if (frida_windows_system_is_x64 ())
success &= frida_stop_service (self, self->service64);
success &= frida_stop_service (self, self->service32);
for (cur = self->system_services.head; cur != NULL; cur = cur->next)
success &= frida_stop_service (self, cur->data);
return success;
}
@@ -480,7 +455,7 @@ frida_register_service (FridaServiceContext * self, const gchar * suffix)
servicename_utf8 = g_strconcat (self->service_basename, suffix, NULL);
servicename = g_utf8_to_utf16 (servicename_utf8, -1, NULL, NULL, NULL);
displayname_utf8 = g_strdup_printf ("Frida %s-bit helper (%s)", suffix, servicename_utf8);
displayname_utf8 = g_strdup_printf ("Frida %s helper (%s)", suffix, servicename_utf8);
displayname = g_utf8_to_utf16 (displayname_utf8, -1, NULL, NULL, NULL);
filename_utf8 = frida_helper_service_derive_filename_for_suffix (suffix);
@@ -714,6 +689,7 @@ frida_service_context_new (const gchar * service_basename)
self = g_slice_new0 (FridaServiceContext);
self->service_basename = g_strdup (service_basename);
g_queue_init (&self->standalone_services);
return self;
}
@@ -721,11 +697,8 @@ frida_service_context_new (const gchar * service_basename)
static void
frida_service_context_free (FridaServiceContext * self)
{
g_assert (self->standalone64 == NULL);
g_assert (self->standalone32 == NULL);
g_assert (self->service64 == NULL);
g_assert (self->service32 == NULL);
g_assert (g_queue_is_empty (&self->system_services));
g_assert (g_queue_is_empty (&self->standalone_services));
if (self->scm != NULL)
CloseServiceHandle (self->scm);
+2 -1
View File
@@ -5,7 +5,8 @@
G_BEGIN_DECLS
G_GNUC_INTERNAL void * frida_helper_manager_start_services (const char * service_basename, FridaPrivilegeLevel level);
G_GNUC_INTERNAL void * frida_helper_manager_start_services (const char * service_basename, gchar ** archs, gint archs_length,
FridaPrivilegeLevel level);
G_GNUC_INTERNAL void frida_helper_manager_stop_services (void * context);
G_GNUC_INTERNAL char * frida_helper_service_derive_basename (void);
+26 -29
View File
@@ -60,8 +60,7 @@ namespace Frida {
private DBusConnection connection;
private uint registration_id;
private ServiceConnection helper32;
private ServiceConnection? helper64;
private Gee.Collection<ServiceConnection> helpers = new Gee.ArrayList<ServiceConnection> ();
private void * context;
public HelperManager (string parent_address, PrivilegeLevel level) {
@@ -98,18 +97,23 @@ namespace Frida {
private async void start () {
try {
helper32 = new ServiceConnection (HelperService.derive_svcname_for_suffix ("32"));
if (WindowsSystem.is_x64 ())
helper64 = new ServiceConnection (HelperService.derive_svcname_for_suffix ("64"));
var archs = new Gee.ArrayList<string> ();
if (Gum.Windows.query_native_cpu_type () == ARM64)
archs.add ("arm64");
if (Gum.Windows.query_native_cpu_type () != IA32)
archs.add ("x86_64");
archs.add ("x86");
context = start_services (HelperService.derive_basename (), level);
foreach (string arch in archs) {
var helper = new ServiceConnection (HelperService.derive_svcname_for_suffix (arch));
helpers.add (helper);
}
yield helper32.open ();
helper32.proxy.uninjected.connect (on_uninjected);
context = start_services (HelperService.derive_basename (), archs.to_array (), level);
if (helper64 != null) {
yield helper64.open ();
helper64.proxy.uninjected.connect (on_uninjected);
foreach (var helper in helpers) {
yield helper.open ();
helper.proxy.uninjected.connect (on_uninjected);
}
var stream_request = Pipe.open (parent_address, null);
@@ -130,20 +134,14 @@ namespace Frida {
}
public async void stop (Cancellable? cancellable) throws Error, IOError {
if (helper64 != null) {
foreach (var helper in helpers) {
try {
yield helper64.proxy.stop (cancellable);
yield helper.proxy.stop (cancellable);
} catch (GLib.Error e) {
if (e is IOError.CANCELLED)
throw (IOError) e;
}
}
try {
yield helper32.proxy.stop (cancellable);
} catch (GLib.Error e) {
if (e is IOError.CANCELLED)
throw (IOError) e;
}
Timeout.add (20, () => {
shutdown.begin ();
@@ -158,13 +156,14 @@ namespace Frida {
public async void inject_library_file (uint pid, PathTemplate path_template, string entrypoint, string data,
string[] dependencies, uint id, Cancellable? cancellable) throws Error, IOError {
try {
if (helper64 != null && yield helper64.proxy.can_handle_target (pid, cancellable)) {
yield helper64.proxy.inject_library_file (pid, path_template, entrypoint, data, dependencies, id,
cancellable);
} else {
yield helper32.proxy.inject_library_file (pid, path_template, entrypoint, data, dependencies, id,
cancellable);
foreach (var helper in helpers) {
if (yield helper.proxy.can_handle_target (pid, cancellable)) {
yield helper.proxy.inject_library_file (pid, path_template, entrypoint, data, dependencies,
id, cancellable);
return;
}
}
throw new Error.NOT_SUPPORTED ("Missing helper able to handle the given target");
} catch (GLib.Error e) {
throw_dbus_error (e);
}
@@ -210,7 +209,7 @@ namespace Frida {
}
}
private extern static void * start_services (string service_basename, PrivilegeLevel level);
private extern static void * start_services (string service_basename, string[] archs, PrivilegeLevel level);
private extern static void stop_services (void * context);
}
@@ -286,9 +285,7 @@ namespace Frida {
}
public async bool can_handle_target (uint pid, Cancellable? cancellable) throws Error, IOError {
uint local_arch = sizeof (void *) == 8 ? 64 : 32;
uint remote_arch = WindowsProcess.is_x64 (pid) ? 64 : 32;
return local_arch == remote_arch;
return cpu_type_from_pid (pid) == Gum.NATIVE_CPU;
}
public async void inject_library_file (uint pid, PathTemplate path_template, string entrypoint, string data,
+32 -14
View File
@@ -113,21 +113,23 @@ namespace Frida {
injector = new Winjector (helper, false, tempdir);
injector.uninjected.connect (on_uninjected);
var blob32 = Frida.Data.Agent.get_frida_agent_32_dll_blob ();
var blob64 = Frida.Data.Agent.get_frida_agent_64_dll_blob ();
var dbghelp32 = Frida.Data.Agent.get_dbghelp_32_dll_blob ();
var dbghelp64 = Frida.Data.Agent.get_dbghelp_64_dll_blob ();
var symsrv32 = Frida.Data.Agent.get_symsrv_32_dll_blob ();
var symsrv64 = Frida.Data.Agent.get_symsrv_64_dll_blob ();
agent = new AgentDescriptor (PathTemplate ("<arch>\\frida-agent.dll"),
new Bytes.static (blob32.data),
new Bytes.static (blob64.data),
new Bytes.static (Frida.Data.Agent.get_frida_agent_arm64_dll_blob ().data),
new Bytes.static (Frida.Data.Agent.get_frida_agent_x86_64_dll_blob ().data),
new Bytes.static (Frida.Data.Agent.get_frida_agent_x86_dll_blob ().data),
new AgentResource[] {
new AgentResource ("32\\dbghelp.dll", new Bytes.static (dbghelp32.data), tempdir),
new AgentResource ("32\\symsrv.dll", new Bytes.static (symsrv32.data), tempdir),
new AgentResource ("64\\dbghelp.dll", new Bytes.static (dbghelp64.data), tempdir),
new AgentResource ("64\\symsrv.dll", new Bytes.static (symsrv64.data), tempdir)
new AgentResource ("arm64\\dbghelp.dll",
new Bytes.static (Frida.Data.Agent.get_dbghelp_arm64_dll_blob ().data), tempdir),
new AgentResource ("arm64\\symsrv.dll",
new Bytes.static (Frida.Data.Agent.get_symsrv_arm64_dll_blob ().data), tempdir),
new AgentResource ("x86_64\\dbghelp.dll",
new Bytes.static (Frida.Data.Agent.get_dbghelp_x86_64_dll_blob ().data), tempdir),
new AgentResource ("x86_64\\symsrv.dll",
new Bytes.static (Frida.Data.Agent.get_symsrv_x86_64_dll_blob ().data), tempdir),
new AgentResource ("x86\\dbghelp.dll",
new Bytes.static (Frida.Data.Agent.get_dbghelp_x86_dll_blob ().data), tempdir),
new AgentResource ("x86\\symsrv.dll",
new Bytes.static (Frida.Data.Agent.get_symsrv_x86_dll_blob ().data), tempdir),
},
tempdir
);
@@ -164,7 +166,23 @@ namespace Frida {
protected override async AgentSessionProvider create_system_session_provider (Cancellable? cancellable,
out DBusConnection connection) throws Error, IOError {
var path_template = agent.get_path_template ();
var agent_path = path_template.expand (sizeof (void *) == 8 ? "64" : "32");
unowned string arch;
switch (Gum.NATIVE_CPU) {
case ARM64:
arch = "arm64";
break;
case AMD64:
arch = "x86_64";
break;
case IA32:
arch = "x86";
break;
default:
assert_not_reached ();
}
var agent_path = path_template.expand (arch);
system_session_container = yield AgentContainer.create (agent_path, cancellable);
+5 -4
View File
@@ -142,11 +142,12 @@ namespace Frida {
private PathTemplate? cached_path_template;
public AgentDescriptor (PathTemplate name_template, Bytes dll32, Bytes dll64, AgentResource[] dependencies,
TemporaryDirectory? tempdir = null) {
public AgentDescriptor (PathTemplate name_template, Bytes dll_arm64, Bytes dll_x86_64, Bytes dll_x86,
AgentResource[] dependencies, TemporaryDirectory? tempdir = null) {
var agents = new Gee.ArrayList<AgentResource> ();
agents.add (new AgentResource (name_template.expand ("32"), dll32, tempdir));
agents.add (new AgentResource (name_template.expand ("64"), dll64, tempdir));
agents.add (new AgentResource (name_template.expand ("arm64"), dll_arm64, tempdir));
agents.add (new AgentResource (name_template.expand ("x86_64"), dll_x86_64, tempdir));
agents.add (new AgentResource (name_template.expand ("x86"), dll_x86, tempdir));
Object (
name_template: name_template,
+1 -1
View File
@@ -1,6 +1,6 @@
[wrap-git]
url = https://github.com/frida/frida-gum.git
revision = 16.4.3
revision = 16.5.2
depth = 1
[provide]
+2 -4
View File
@@ -72,10 +72,8 @@ frida_test_process_backend_filename_of (void * handle)
image_count = _dyld_image_count ();
for (image_idx = 0; image_idx != image_count; image_idx++)
{
const gchar * image_path = _dyld_get_image_name (image_idx);
if (g_str_has_suffix (image_path, "/frida-tests"))
return g_strdup (image_path);
if (_dyld_get_image_header (image_idx)->filetype == MH_EXECUTE)
return g_strdup (_dyld_get_image_name (image_idx));
}
g_assert_not_reached ();