Skip to content

Commit

Permalink
darwin: Improve tvOS support to also cover frida-server (#470)
Browse files Browse the repository at this point in the history
  • Loading branch information
tmm1 authored Jun 13, 2023
1 parent d4069c7 commit 065a390
Show file tree
Hide file tree
Showing 53 changed files with 368 additions and 109 deletions.
11 changes: 10 additions & 1 deletion inject/post-process.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ case $host_os in
exit 1
fi
;;
tvos)
if [ -z "$TVOS_CERTID" ]; then
echo "TVOS_CERTID not set, see https://github.com/frida/frida#apple-oses"
exit 1
fi
;;
esac

intermediate_path=$output_inject_path.tmp
Expand All @@ -46,14 +52,17 @@ if [ "$strip_enabled" = "true" ]; then
fi

case $host_os in
macos|ios)
macos|ios|tvos)
case $host_os in
macos)
"$codesign" -f -s "$MACOS_CERTID" -i "re.frida.Inject" "$intermediate_path" || exit 1
;;
ios)
"$codesign" -f -s "$IOS_CERTID" --entitlements "$input_entitlements_path" "$intermediate_path" || exit 1
;;
tvos)
"$codesign" -f -s "$TVOS_CERTID" --entitlements "$input_entitlements_path" "$intermediate_path" || exit 1
;;
esac
;;
esac
Expand Down
17 changes: 17 additions & 0 deletions lib/base/frida-tvos.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#ifndef __FRIDA_TVOS_H__
#define __FRIDA_TVOS_H__

#ifdef HAVE_TVOS
# include <Availability.h>
# undef __TVOS_PROHIBITED
# define __TVOS_PROHIBITED
# undef __API_UNAVAILABLE
# define __API_UNAVAILABLE(...)
# include <spawn.h>
# include <mach/mach.h>
# include <mach/task.h>
# undef __TVOS_PROHIBITED
# define __TVOS_PROHIBITED __OS_AVAILABILITY(tvos,unavailable)
#endif

#endif
2 changes: 1 addition & 1 deletion lib/base/session-glue.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ _frida_query_windows_computer_name (void)
return g_utf16_to_utf8 (buffer, -1, NULL, NULL, NULL);
}

#elif defined (HAVE_IOS)
#elif defined (HAVE_IOS) || defined (HAVE_TVOS)

#include <CoreFoundation/CoreFoundation.h>
#include <dlfcn.h>
Expand Down
2 changes: 1 addition & 1 deletion lib/gadget/gadget-darwin.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
gchar *
frida_gadget_environment_detect_documents_dir (void)
{
#ifdef HAVE_IOS
#if defined (HAVE_IOS) || defined (HAVE_TVOS)
@autoreleasepool
{
NSArray<NSString *> * paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
Expand Down
2 changes: 1 addition & 1 deletion lib/gadget/gadget.vala
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,7 @@ namespace Frida.Gadget {
if (config_path == null)
config_path = derive_config_path_from_file_path (gadget_path);

#if IOS
#if IOS || TVOS
if (resource_dir == null && !FileUtils.test (config_path, FileTest.EXISTS)) {
var config_dir = Path.get_dirname (config_path);
if (Path.get_basename (config_dir) == "Frameworks") {
Expand Down
2 changes: 1 addition & 1 deletion lib/gadget/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ modulated_gadget = custom_target('frida-gadget-modulated',

if host_os == 'macos'
identity = '@executable_path/../Frameworks/FridaGadget.dylib'
elif host_os == 'ios'
elif host_os in ['ios', 'tvos']
identity = '@executable_path/Frameworks/FridaGadget.dylib'
else
identity = gadget_name
Expand Down
2 changes: 1 addition & 1 deletion lib/pipe/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ if host_os_family == 'windows'
'pipe-windows.c',
'pipe-sddl.c',
]
elif host_os in ['macos', 'ios']
elif host_os in ['macos', 'ios', 'tvos']
pipe_sources += ['pipe-darwin.c']

system_deps += [gio_unix_dep]
Expand Down
2 changes: 2 additions & 0 deletions lib/pipe/pipe-darwin.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "pipe-glue.h"

#include "frida-tvos.h"

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
Expand Down
4 changes: 2 additions & 2 deletions lib/pipe/pipe.vala
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ namespace Frida {
public Future<IOStream> open (string address, Cancellable? cancellable) {
#if WINDOWS
return WindowsPipe.open (address, cancellable);
#elif MACOS || IOS
#elif MACOS || IOS || TVOS
return DarwinPipe.open (address, cancellable);
#else
return UnixPipe.open (address, cancellable);
Expand Down Expand Up @@ -116,7 +116,7 @@ namespace Frida {
protected extern static InputStream _make_input_stream (void * backend);
protected extern static OutputStream _make_output_stream (void * backend);
}
#elif MACOS || IOS
#elif MACOS || IOS || TVOS
namespace DarwinPipe {
public static Future<IOStream> open (string address, Cancellable? cancellable) {
var promise = new Promise<IOStream> ();
Expand Down
4 changes: 2 additions & 2 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ endif
if host_os == 'macos'
backend_libs_private += ['-Wl,-framework,AppKit']
endif
if host_os == 'ios'
if host_os in ['ios', 'tvos']
backend_libs_private += ['-Wl,-framework,CoreGraphics', '-Wl,-framework,UIKit']
endif

Expand Down Expand Up @@ -409,7 +409,7 @@ add_project_arguments(native_vala_flags, language: ['vala'], native: true)
subdir('tools')
subdir('lib')
subdir('src')
if host_os not in ['watchos', 'tvos']
if host_os != 'watchos'
subdir('server')
subdir('portal')
subdir('inject')
Expand Down
6 changes: 3 additions & 3 deletions portal/portal.vala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Frida.Portal {
private static string? control_origin = null;
private static string? control_token = null;
private static string? control_asset_root = null;
#if !WINDOWS
#if !WINDOWS && !TVOS
private static bool daemonize = false;
#endif

Expand All @@ -32,7 +32,7 @@ namespace Frida.Portal {
"TOKEN" },
{ "control-asset-root", 0, 0, OptionArg.FILENAME, ref control_asset_root, "Serve static files inside ROOT on control " +
"endpoint (by default no files are served)", "ROOT" },
#if !WINDOWS
#if !WINDOWS && !TVOS
{ "daemonize", 'D', 0, OptionArg.NONE, ref daemonize, "Detach and become a daemon", null },
#endif
{ null }
Expand Down Expand Up @@ -72,7 +72,7 @@ namespace Frida.Portal {
}

ReadyHandler? on_ready = null;
#if !WINDOWS
#if !WINDOWS && !TVOS
if (daemonize) {
var sync_fds = new int[2];

Expand Down
11 changes: 10 additions & 1 deletion portal/post-process.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ case $host_os in
exit 1
fi
;;
tvos)
if [ -z "$TVOS_CERTID" ]; then
echo "TVOS_CERTID not set, see https://github.com/frida/frida#apple-oses"
exit 1
fi
;;
esac

intermediate_path=$output_portal_path.tmp
Expand All @@ -46,14 +52,17 @@ if [ "$strip_enabled" = "true" ]; then
fi

case $host_os in
macos|ios)
macos|ios|tvos)
case $host_os in
macos)
"$codesign" -f -s "$MACOS_CERTID" -i "re.frida.Portal" "$intermediate_path" || exit 1
;;
ios)
"$codesign" -f -s "$IOS_CERTID" --entitlements "$input_entitlements_path" "$intermediate_path" || exit 1
;;
tvos)
"$codesign" -f -s "$TVOS_CERTID" --entitlements "$input_entitlements_path" "$intermediate_path" || exit 1
;;
esac
;;
esac
Expand Down
4 changes: 2 additions & 2 deletions server/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ server_sources = [
if host_os_family == 'darwin'
server_sources += ['server-darwin.m']
endif
if host_os == 'ios'
if host_os in ['ios', 'tvos']
server_sources += [
'server-ios.c',
'server-ios-tvos.c',
]
endif

Expand Down
11 changes: 10 additions & 1 deletion server/post-process.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ case $host_os in
exit 1
fi
;;
tvos)
if [ -z "$TVOS_CERTID" ]; then
echo "TVOS_CERTID not set, see https://github.com/frida/frida#apple-oses"
exit 1
fi
;;
esac

intermediate_path=$output_server_path.tmp
Expand All @@ -46,14 +52,17 @@ if [ "$strip_enabled" = "true" ]; then
fi

case $host_os in
macos|ios)
macos|ios|tvos)
case $host_os in
macos)
"$codesign" -f -s "$MACOS_CERTID" -i "re.frida.Server" "$intermediate_path" || exit 1
;;
ios)
"$codesign" -f -s "$IOS_CERTID" --entitlements "$input_entitlements_path" "$intermediate_path" || exit 1
;;
tvos)
"$codesign" -f -s "$TVOS_CERTID" --entitlements "$input_entitlements_path" "$intermediate_path" || exit 1
;;
esac
;;
esac
Expand Down
8 changes: 4 additions & 4 deletions server/server-glue.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#include "server-glue.h"

#include "frida-core.h"
#ifdef HAVE_IOS
# include "server-ios.h"
#if defined (HAVE_IOS) || defined (HAVE_TVOS)
# include "server-ios-tvos.h"
#endif
#ifdef HAVE_ANDROID
# include "frida-selinux.h"
Expand Down Expand Up @@ -54,8 +54,8 @@ frida_server_environment_set_verbose_logging_enabled (gboolean enabled)
void
frida_server_environment_configure (void)
{
#ifdef HAVE_IOS
_frida_server_ios_configure ();
#if defined (HAVE_IOS) || defined (HAVE_TVOS)
_frida_server_ios_tvos_configure ();
#endif

#ifdef HAVE_ANDROID
Expand Down
4 changes: 2 additions & 2 deletions server/server-ios.c → server/server-ios-tvos.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "server-ios.h"
#include "server-ios-tvos.h"

#include <dlfcn.h>
#include <gio/gio.h>
Expand Down Expand Up @@ -26,7 +26,7 @@ static gboolean frida_refresh_inode (const gchar * path);
static gboolean frida_add_to_trust_cache (const gchar * path);

void
_frida_server_ios_configure (void)
_frida_server_ios_tvos_configure (void)
{
memorystatus_control (MEMORYSTATUS_CMD_SET_JETSAM_TASK_LIMIT, getpid (), 256, NULL, 0);

Expand Down
2 changes: 1 addition & 1 deletion server/server-ios.h → server/server-ios-tvos.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

G_BEGIN_DECLS

G_GNUC_INTERNAL void _frida_server_ios_configure (void);
G_GNUC_INTERNAL void _frida_server_ios_tvos_configure (void);

G_END_DECLS

Expand Down
10 changes: 5 additions & 5 deletions server/server.vala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Frida.Server {
private static string? token = null;
private static string? asset_root = null;
private static string? directory = null;
#if !WINDOWS
#if !WINDOWS && !TVOS
private static bool daemonize = false;
#endif
private static string? softener_flavor_str = null;
Expand Down Expand Up @@ -38,7 +38,7 @@ namespace Frida.Server {
{ "asset-root", 0, 0, OptionArg.FILENAME, ref asset_root, "Serve static files inside ROOT (by default no files are served)",
"ROOT" },
{ "directory", 'd', 0, OptionArg.STRING, ref directory, "Store binaries in DIRECTORY", "DIRECTORY" },
#if !WINDOWS
#if !WINDOWS && !TVOS
{ "daemonize", 'D', 0, OptionArg.NONE, ref daemonize, "Detach and become a daemon", null },
#endif
{ "policy-softener", 0, 0, OptionArg.STRING, ref softener_flavor_str, "Select policy softener", "system|internal" },
Expand Down Expand Up @@ -100,13 +100,13 @@ namespace Frida.Server {
}
}

#if IOS
#if IOS || TVOS
if (softener_flavor == INTERNAL)
InternalIOSPolicySoftener.enable ();
InternalIOSTVOSPolicySoftener.enable ();
#endif

ReadyHandler? on_ready = null;
#if !WINDOWS
#if !WINDOWS && !TVOS
if (daemonize) {
var sync_fds = new int[2];

Expand Down
2 changes: 1 addition & 1 deletion src/control-service.vala
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ namespace Frida {
}

private void on_server_connection (IOStream connection, SocketAddress remote_address) {
#if IOS
#if IOS || TVOS
/*
* We defer the launchd injection until the first connection is established in order
* to avoid bootloops on unsupported jailbreaks.
Expand Down
23 changes: 18 additions & 5 deletions src/darwin/agent/launchd.js
Original file line number Diff line number Diff line change
Expand Up @@ -263,25 +263,38 @@ function findSubstrateLauncher() {
const impl = imp.slot.readPointer().strip();
const header = findClosestMachHeader(impl);

const launcherDylibName = '4c 61 75 6e 63 68 65 72 2e 74 2e 64 79 6c 69 62';
const launcherDylibName = stringToHexPattern('Launcher.t.dylib');
const isSubstrate = Memory.scanSync(header, 2048, launcherDylibName).length > 0;
if (!isSubstrate)
return null;

const atvLauncherDylibName = stringToHexPattern('build.atv/Launcher.t.dylib');
const isATVSubstrate = Memory.scanSync(header, 2048, atvLauncherDylibName).length > 0;

return {
handlePosixSpawn: resolveFunction('fd 7b bf a9 fd 03 00 91 f4 4f bf a9 f6 57 bf a9 f8 5f bf a9 fa 67 bf a9 fc 6f bf a9 ff 43 04 d1'),
workerCont: resolveFunction('fd 7b bf a9 fd 03 00 91 f4 4f bf a9 f6 57 bf a9 f8 5f bf a9 fa 67 bf a9 fc 6f bf a9 ff 43 01 d1'),
handlePosixSpawn: resolveFunction('handlePosixSpawn',
isATVSubstrate
? 'fc 6f ba a9 fa 67 01 a9 f8 5f 02 a9 f6 57 03 a9 f4 4f 04 a9 fd 7b 05 a9 fd 43 01 91 ff 83 02 d1 e6 1f 00 f9'
: 'fd 7b bf a9 fd 03 00 91 f4 4f bf a9 f6 57 bf a9 f8 5f bf a9 fa 67 bf a9 fc 6f bf a9 ff 43 04 d1'),
workerCont: resolveFunction('workerCont',
isATVSubstrate
? 'f8 5f bc a9 f6 57 01 a9 f4 4f 02 a9 fd 7b 03 a9 fd c3 00 91 ff 83 00 d1 f3 03 00 aa c3 fc ff 97 f4 03 00 aa'
: 'fd 7b bf a9 fd 03 00 91 f4 4f bf a9 f6 57 bf a9 f8 5f bf a9 fa 67 bf a9 fc 6f bf a9 ff 43 01 d1'),
};

function resolveFunction(signature) {
function resolveFunction(name, signature) {
const matches = Memory.scanSync(header, 37056, signature);
if (matches.length !== 1) {
throw new Error('Unsupported version of Substrate; please file a bug');
throw new Error(`Unsupported version of Substrate; please file a bug: ${name} matched ${matches.length} times`);
}
return matches[0].address;
}
}

function stringToHexPattern(str) {
return str.split('').map(o => o.charCodeAt(0).toString(16)).join(' ');
}

function findClosestMachHeader(address) {
let cur = address.and(ptr(4095).not());
while (true) {
Expand Down
Loading

0 comments on commit 065a390

Please sign in to comment.