Compare commits

...
36 Commits
Author SHA1 Message Date
Ole André Vadla Ravnås bcd4a3d586 subprojects: Prepare for release 2025-12-15 21:28:35 +01:00
Ole André Vadla Ravnås 9937b40032 subprojects: Bump outdated 2025-12-15 21:16:49 +01:00
Ole André Vadla Ravnås 81299af1ef darwin: Use DO_NOT_REAP_CHILD when spawning helper
When the system is booted without -arm64e_preview_abi, the helper
binary is killed very early during startup. Enabling
DO_NOT_REAP_CHILD allows GLib to use posix_spawn(), insulating the
host process from signal-related side effects during helper launch.

This means the child process is no longer reaped automatically.
Since this code may run inside a host process that installs its own
signal handlers, GLib's child-watch support cannot be used. Instead,
the helper is reaped explicitly using non-blocking polling.
2025-12-15 17:54:19 +01:00
Ole André Vadla Ravnås f76a3315e7 submodules: Bump releng 2025-12-15 15:06:33 +01:00
Ole André Vadla Ravnås f5c01842c9 meson: Avoid repeating the GLib requirement 2025-12-15 15:05:40 +01:00
Ole André Vadla Ravnås 40879413c0 meson: Remove the unused frida_profile variable 2025-12-15 12:43:25 +01:00
Ole André Vadla Ravnås ab4a7f43f6 meson: Update version logic to support snapshot tags 2025-12-15 12:31:16 +01:00
Ole André Vadla Ravnås 8ed4a69e03 meson: Restore support for GLib being a subproject
Which was broken when gio-unix-2.0 became part of the public API on
non-Windows systems.
2025-12-15 12:09:12 +01:00
Ole André Vadla Ravnås d93557625d ci: Move xcframework .modulemap inside a subdir
To avoid clashes when an app links with multiple static frameworks, each
with their own modulemap.
2025-12-11 15:12:50 +01:00
Ole André Vadla Ravnås 7ecebf23b1 ci: Remove snapshot-tag.yml
Actually triggering ci.yml seems like a rabbit-hole. Leaving for later.
2025-12-08 23:48:06 +01:00
Ole André Vadla Ravnås e2b4b120d7 ci: Add modulemap to xcframework for FridaCore
Add a Clang module.modulemap to each header slice in the generated
FridaCore.xcframework so SwiftPM can load the FridaCore C module.
2025-12-08 23:44:34 +01:00
Ole André Vadla Ravnås e1cb645805 ci: Fix some stylistic inconsistencies 2025-12-08 23:43:35 +01:00
Ole André Vadla Ravnås a0ea09d4d6 ci: Improve snapshot-tag.yml so it triggers ci.yml 2025-12-08 22:46:53 +01:00
Ole André Vadla Ravnås 0f32cc8f4e darwin: Emit 128px app icons on macOS
Instead of two small sizes, we'll emit just one larger one.
2025-12-08 22:29:15 +01:00
Ole André Vadla Ravnås 46a566655f submodules: Bump releng 2025-12-08 22:21:08 +01:00
Ole André Vadla Ravnås 690597f908 ci: Add workflow for automated snapshot tagging 2025-12-08 22:21:08 +01:00
Ole André Vadla Ravnås 0c49c7ee62 ci: Publish releases with .xcframework 2025-12-08 22:21:08 +01:00
Ole André Vadla Ravnås ce40c30a20 ci: Build and upload .xcframework artifact 2025-12-08 22:21:08 +01:00
Ole André Vadla Ravnås 3bb44c222a ci: Add ios-arm64-simulator to the mobile matrix 2025-12-08 22:21:07 +01:00
Ole André Vadla Ravnås 5ec73cab32 ci: Temporarily disable mobile tests
As the backend infrastructure needs some love.
2025-12-08 18:05:39 +01:00
Ole André Vadla Ravnås 257f198659 ci: Fix the emulator job 2025-12-08 18:05:39 +01:00
Ole André Vadla Ravnås 5fca68ebe0 ci: Fix the macOS/x86_64 job
As --host was omitted, we ended up building for macOS/arm64.
2025-12-08 18:05:39 +01:00
Ole André Vadla Ravnås 9eab4f8975 linux: Add missing Gum #include
Which only worked in the past due to luck, i.e. some unrelated code
including it.
2025-11-12 13:18:00 +00:00
Ole André Vadla Ravnås afd8c8789f subprojects: Prepare for release 2025-11-05 18:59:04 +01:00
Ole André Vadla Ravnås cfd5a730e4 subprojects: Bump outdated 2025-11-05 18:57:16 +01:00
Ole André Vadla Ravnås 3f411908e7 subprojects: Prepare for release 2025-11-04 10:30:52 +01:00
Ole André Vadla Ravnås 4e44f4d243 subprojects: Bump outdated 2025-11-04 10:29:26 +01:00
Leo Conforti 9573f1aa22 compiler: Add platform and externals options
Introduce a platform property and externals API to CompilerOptions, and
plumb them through to the Go backend. The backend maps the platform to an
esbuild platform and passes externals to esbuild for exclusion from the
bundle.
2025-11-04 09:52:09 +01:00
Ole André Vadla RavnåsandHåvard Sørbø 79a08e4767 simmy: Wire up spawn() argv and env options
Though `argv` was already wired up for the program case, we didn't wire
it up for the app case.

Co-authored-by: Håvard Sørbø <[email protected]>
2025-11-03 19:30:56 +01:00
Ole André Vadla Ravnås 57dfe9d5ad subprojects: Prepare for release 2025-11-01 00:38:11 +01:00
Ole André Vadla Ravnås 347662b45b subprojects: Bump outdated 2025-11-01 00:36:24 +01:00
Ole André Vadla Ravnås cc95375136 darwin: Revive app listing/launching on iOS >= 16
When running on rootful systems. This brings dccb612 back to life.
It was broken in 8108d4d, which fixed two Interceptor singleton leaks.
Turns out the one in springboard.m was intentional, as it was done as
part of init-once logic, with no teardown intended. And since nothing
else uses Interceptor in this case, the instrumentation we just
applied gets reverted right away.

Kudo to @alexhude for reporting.
2025-11-01 00:23:17 +01:00
Ole André Vadla Ravnås 329c4075d0 subprojects: Prepare for release 2025-10-31 20:24:06 +01:00
Ole André Vadla Ravnås c4198498d5 subprojects: Bump outdated 2025-10-31 20:21:36 +01:00
Ole André Vadla Ravnås 20ef7bb318 simmy: Degrade functionality when SIP is enabled
As get_frontmost_application() and icons rely on being able to inject
our internal agent into SpringBoard.

Down the road we might be able to reimplement this functionality as a
helper program that we spawn inside the Simulator runtime. The uncertain
part is whether we'll be able to give that program the appropriate
entitlements.
2025-10-31 20:09:20 +01:00
Ole André Vadla RavnåsandHåvard Sørbø 367f8cf22b simmy: Handle app enumeration with selected IDs
Co-authored-by: Håvard Sørbø <[email protected]>
2025-10-30 14:58:35 +01:00
13 changed files with 558 additions and 104 deletions

No files matched your search

+145 -6
View File
@@ -2,11 +2,15 @@ name: CI
on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch:
inputs:
tag:
description: "Tag to build/test"
required: false
type: string
env:
FRIDA_CORE_OPTIONS: '--with-devkits=core --enable-tests'
@@ -71,6 +75,7 @@ jobs:
if: ${{ !startsWith(matrix.id, 'windows-') && matrix.id != 'linux-x86' }}
run: |
./configure \
--host=${{ matrix.id }} \
--enable-compiler-backend \
${{ env.FRIDA_CORE_OPTIONS }}
make
@@ -205,7 +210,7 @@ jobs:
/sbin/entropy
cat /etc/motd
export PS1='\u@frida:\w\$ '
/root/frida-tests
/root/tests/frida-tests
status=\$?
echo "exit status: \$status"
if [ \$status -eq 0 ]; then
@@ -281,7 +286,8 @@ jobs:
COPY initscript /tmp/initramfs/init
RUN chmod +x /tmp/initramfs/init
COPY build/tests /tmp/initramfs/root/
COPY build/tests /tmp/initramfs/root/tests/
COPY build/lib/agent/frida-agent.so /tmp/initramfs/root/lib/agent/
RUN find . | cpio -o --format=newc -R root:root > /root/initramfs.img
COPY launch.sh /root/launch.sh
@@ -297,6 +303,7 @@ jobs:
matrix:
id:
- ios-arm64
- ios-arm64-simulator
- android-x86
- android-x86_64
- android-arm
@@ -341,6 +348,7 @@ jobs:
name: core-devkit-${{ matrix.id }}
path: build/src/devkit/
- name: Package tests
if: false
run: |
mkdir -p /tmp/pkg
cd build
@@ -360,7 +368,7 @@ jobs:
esac
tar -C /tmp/pkg -czf /tmp/runner.tar.gz .
- name: Test on Corellium iOS device
if: matrix.id == 'ios-arm64'
if: false
continue-on-error: true
uses: frida/corellium-action@v4
with:
@@ -376,7 +384,7 @@ jobs:
tar xf $ASSET_PATH
./frida-tests
- name: Test on Corellium Android device
if: matrix.id == 'android-arm64'
if: false
continue-on-error: true
uses: frida/corellium-action@v4
with:
@@ -480,3 +488,134 @@ jobs:
else
echo "No unexpected changes detected."
fi
xcframework:
name: Build FridaCore.xcframework
runs-on: macos-latest
needs:
- native
- mobile
steps:
- name: Check out repo
uses: actions/checkout@v4
- name: Download macOS/x86_64 devkit
uses: actions/download-artifact@v4
with:
name: core-devkit-macos-x86_64
path: devkits/macos-x86_64
- name: Download macOS/arm64 devkit
uses: actions/download-artifact@v4
with:
name: core-devkit-macos-arm64
path: devkits/macos-arm64
- name: Download iOS/arm64 devkit
uses: actions/download-artifact@v4
with:
name: core-devkit-ios-arm64
path: devkits/ios-arm64
- name: Download iOS/arm64-simulator devkit
uses: actions/download-artifact@v4
with:
name: core-devkit-ios-arm64-simulator
path: devkits/ios-arm64-simulator
- name: Create FridaCore.xcframework
shell: bash
run: |
set -euo pipefail
mkdir -p devkits/macos-universal
lipo -create \
devkits/macos-x86_64/libfrida-core.a \
devkits/macos-arm64/libfrida-core.a \
-output devkits/macos-universal/libfrida-core.a
platforms=(
"macos-universal"
"ios-arm64"
"ios-arm64-simulator"
)
for platform in "${platforms[@]}"; do
mkdir -p "xcframework_headers/${platform}/FridaCore"
done
cp devkits/macos-x86_64/frida-core.h \
xcframework_headers/macos-universal/frida-core-x86_64.h
cp devkits/macos-arm64/frida-core.h \
xcframework_headers/macos-universal/frida-core-arm64.h
cat > xcframework_headers/macos-universal/frida-core.h <<'EOF'
#if defined (__x86_64__)
# include "frida-core-x86_64.h"
#elif defined (__arm64__)
# include "frida-core-arm64.h"
#else
# error "Unsupported macOS architecture for FridaCore"
#endif
EOF
cp devkits/ios-arm64/frida-core.h \
xcframework_headers/ios-arm64/frida-core.h
cp devkits/ios-arm64-simulator/frida-core.h \
xcframework_headers/ios-arm64-simulator/frida-core.h
for platform in "${platforms[@]}"; do
cat > "xcframework_headers/${platform}/FridaCore/module.modulemap" <<'EOF'
module FridaCore [extern_c] {
header "../frida-core.h"
export *
}
EOF
done
xcodebuild -create-xcframework \
-library devkits/macos-universal/libfrida-core.a \
-headers xcframework_headers/macos-universal \
-library devkits/ios-arm64/libfrida-core.a \
-headers xcframework_headers/ios-arm64 \
-library devkits/ios-arm64-simulator/libfrida-core.a \
-headers xcframework_headers/ios-arm64-simulator \
-output FridaCore.xcframework
- name: Upload FridaCore.xcframework
uses: actions/upload-artifact@v4
with:
name: FridaCore.xcframework
path: FridaCore.xcframework
publish-xcframework:
if: github.ref_type == 'tag'
runs-on: macos-latest
needs:
- xcframework
steps:
- name: Download FridaCore.xcframework artifact
uses: actions/download-artifact@v4
with:
name: FridaCore.xcframework
path: dist
- name: Rewrap into FridaCore.xcframework directory
shell: bash
run: |
set -euo pipefail
cd dist
mkdir -p FridaCore.xcframework
shopt -s dotglob
for f in *; do
if [[ "$f" != "FridaCore.xcframework" ]]; then
mv "$f" FridaCore.xcframework/
fi
done
- name: Zip FridaCore.xcframework
run: |
cd dist
zip -r FridaCore.xcframework.zip FridaCore.xcframework
- name: Create GitHub release
uses: softprops/action-gh-release@v2
with:
files: |
dist/FridaCore.xcframework.zip
prerelease: ${{ contains(github.ref_name, 'snapshot') }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+5 -1
View File
@@ -52,7 +52,6 @@ endif
extra_deps = []
if host_os_family != 'windows'
extra_vala_args += '--pkg=gio-unix-2.0'
extra_deps += gio_unix_dep
endif
@@ -60,6 +59,11 @@ base_vala_args = [gum_vala_args, '--pkg=gio-2.0', '--pkg=json-glib-1.0']
if nice_dep.found()
base_vala_args += '--pkg=nice'
endif
if host_os_family != 'windows'
base_vala_args += [
'--pkg=gio-unix-2.0',
]
endif
if host_os_family == 'darwin'
base_vala_args += [
'--pkg=corefoundation',
+28 -11
View File
@@ -32,18 +32,34 @@ frida_version = get_option('frida_version')
if frida_version == ''
frida_version = run_command(releng / 'frida_version.py', meson.project_source_root(), check: true).stdout().strip()
endif
tokens = frida_version.split('.')
frida_major_version = tokens[0].to_int()
frida_minor_version = tokens[1].to_int()
if tokens.length() == 4
frida_micro_version = tokens[2].split('-')[0].to_int() - 1
frida_nano_version = tokens[3].to_int() + 1
is_dev = frida_version.contains('-dev.')
if is_dev
dev_parts = frida_version.split('-dev.')
assert(dev_parts.length() == 2)
prefix = dev_parts[0]
frida_nano_version = dev_parts[1].to_int() + 1
else
assert(tokens.length() == 3)
frida_micro_version = tokens[2].to_int()
prefix = frida_version
frida_nano_version = 0
endif
frida_profile = (frida_version != '0.0.0' and frida_nano_version == 0) ? 'prod' : 'dev'
parts = prefix.split('-')
core = parts[0]
has_suffix = parts.length() > 1
core_tokens = core.split('.')
assert(core_tokens.length() == 3)
frida_major_version = core_tokens[0].to_int()
frida_minor_version = core_tokens[1].to_int()
micro_encoded = core_tokens[2].to_int()
if is_dev and not has_suffix
frida_micro_version = micro_encoded - 1
else
frida_micro_version = micro_encoded
endif
api_version = '1.0'
@@ -292,6 +308,7 @@ gum_dep = dependency('frida-gum-1.0', default_options: [
gumjs_dep = dependency('frida-gumjs-1.0')
gumjs_inspector_dep = dependency('frida-gumjs-inspector-1.0')
glib_version_req = '>=2.74'
glib_options = [
'cocoa=disabled',
'selinux=disabled',
@@ -315,7 +332,7 @@ if optimize_for_prod
gee_options += 'disable-internal-asserts=true'
endif
glib_dep = dependency('glib-2.0', version: '>=2.72', default_options: glib_options)
glib_dep = dependency('glib-2.0', version: glib_version_req, default_options: glib_options)
gobject_dep = dependency('gobject-2.0')
gmodule_dep = dependency('gmodule-2.0')
gio_dep = dependency('gio-2.0')
@@ -346,7 +363,7 @@ quickjs_dep = dependency('quickjs', required: get_option('barebone_backend'), de
])
lzfse_dep = dependency('lzfse', required: get_option('barebone_backend'))
native_glib_dep = dependency('glib-2.0', version: '>=2.74', native: true, default_options: glib_options)
native_glib_dep = dependency('glib-2.0', version: glib_version_req, native: true, default_options: glib_options)
native_gio_dep = dependency('gio-2.0', native: true)
native_gee_dep = dependency('gee-0.8', native: true, default_options: gee_options)
native_brotlienc_dep = dependency('libbrotlienc', native: true)
+1 -1
Submodule releng updated: 800f2385c3...c144673b9d.
+39 -3
View File
@@ -106,6 +106,8 @@ type BuildOptions struct {
DisableTypeCheck bool
SourceMap bool
Compress bool
Platform esbuild.Platform
Externals []string
}
type OutputFormat C.FridaOutputFormat
@@ -146,7 +148,7 @@ type BuildDiagnosticCallback func(d Diagnostic)
//export _frida_compiler_backend_build
func _frida_compiler_backend_build(cProjectRoot, cEntrypoint *C.char, outputFormat C.FridaOutputFormat, bundleFormat C.FridaBundleFormat,
disableTypeCheck, sourceMap, compress uintptr,
disableTypeCheck, sourceMap, compress uintptr, cPlatform *C.char, cExternals **C.char, numExternals C.int,
onCompleteFn C.FridaBuildCompleteFunc, onCompleteData unsafe.Pointer, onCompleteDataDestroy C.FridaDestroyFunc,
onDiagnosticFn C.FridaDiagnosticFunc, onDiagnosticData unsafe.Pointer) {
options := BuildOptions{
@@ -157,6 +159,8 @@ func _frida_compiler_backend_build(cProjectRoot, cEntrypoint *C.char, outputForm
DisableTypeCheck: disableTypeCheck != 0,
SourceMap: sourceMap != 0,
Compress: compress != 0,
Platform: platformFromFrida(C.GoString(cPlatform)),
Externals: parseCExternals(cExternals, numExternals),
}
onComplete := NewCDelegate(onCompleteFn, onCompleteData, onCompleteDataDestroy)
onDiagnostic := NewCDelegate(onDiagnosticFn, onDiagnosticData, nil)
@@ -181,7 +185,7 @@ func _frida_compiler_backend_build(cProjectRoot, cEntrypoint *C.char, outputForm
//export _frida_compiler_backend_watch
func _frida_compiler_backend_watch(cProjectRoot, cEntrypoint *C.char, outputFormat C.FridaOutputFormat, bundleFormat C.FridaBundleFormat,
disableTypeCheck, sourceMap, compress uintptr,
disableTypeCheck, sourceMap, compress uintptr, cPlatform *C.char, cExternals **C.char, numExternals C.int,
onReadyFn C.FridaWatchReadyFunc, onReadyData unsafe.Pointer, onReadyDataDestroy C.FridaDestroyFunc,
onStartingFn C.FridaStartingFunc, onStartingData unsafe.Pointer,
onFinishedFn C.FridaFinishedFunc, onFinishedData unsafe.Pointer,
@@ -195,6 +199,8 @@ func _frida_compiler_backend_watch(cProjectRoot, cEntrypoint *C.char, outputForm
DisableTypeCheck: disableTypeCheck != 0,
SourceMap: sourceMap != 0,
Compress: compress != 0,
Platform: platformFromFrida(C.GoString(cPlatform)),
Externals: parseCExternals(cExternals, numExternals),
}
onReady := NewCDelegate(onReadyFn, onReadyData, onReadyDataDestroy)
onStarting := NewCDelegate(onStartingFn, onStartingData, nil)
@@ -246,6 +252,35 @@ func _frida_compiler_backend_watch_session_dispose(h uintptr) {
handle.Delete()
}
func platformFromFrida(s string) esbuild.Platform {
switch s {
case "gum":
return esbuild.PlatformNode
case "browser":
return esbuild.PlatformBrowser
case "neutral":
return esbuild.PlatformNeutral
default:
panic(fmt.Sprintf("Unknown platform: %q", s))
}
}
func parseCExternals(cExternals **C.char, numExternals C.int) []string {
if numExternals == 0 {
return nil
}
n := int(numExternals)
cArray := (*[1 << 20]*C.char)(unsafe.Pointer(cExternals))[:n:n]
externals := make([]string, n)
for i := 0; i < n; i++ {
externals[i] = C.GoString(cArray[i])
}
return externals
}
func makeCBuildDiagnosticCallback(onDiagnostic *CDelegate[C.FridaDiagnosticFunc]) BuildDiagnosticCallback {
return func(d Diagnostic) {
var cPath *C.char
@@ -445,9 +480,10 @@ func makeContext(options BuildOptions, callbacks BuildEventCallbacks) (ctx esbui
Bundle: true,
Outdir: projectRoot,
AbsWorkingDir: projectRoot,
Platform: esbuild.PlatformNode,
Platform: options.Platform,
Format: format,
Inject: []string{"frida-builtins:///node-globals.js"},
External: options.Externals,
EntryPoints: []string{entrypoint},
Write: false,
Plugins: plugins,
+43 -5
View File
@@ -46,7 +46,8 @@ namespace Frida {
CompilerBackend.build (project_root, entrypoint, opts.output_format, opts.bundle_format,
(size_t) (opts.type_check == NONE), (size_t) (opts.source_maps == INCLUDED),
(size_t) (opts.compression == TERSER), (owned) on_complete, on_diagnostic);
(size_t) (opts.compression == TERSER), opts.platform.to_nick (),
opts.externals.to_array (), (owned) on_complete, on_diagnostic);
yield;
if (error_message != null)
@@ -96,7 +97,8 @@ namespace Frida {
CompilerBackend.watch (project_root, entrypoint, opts.output_format, opts.bundle_format,
(size_t) (opts.type_check == NONE), (size_t) (opts.source_maps == INCLUDED),
(size_t) (opts.compression == TERSER), (owned) on_ready, on_starting, on_finished,
(size_t) (opts.compression == TERSER), opts.platform.to_nick (),
opts.externals.to_array (), (owned) on_ready, on_starting, on_finished,
on_output, on_diagnostic);
yield;
@@ -283,13 +285,14 @@ namespace Frida {
[CCode (has_target = false)]
private delegate void BuildFunc (string project_root, string entrypoint, OutputFormat output_format,
BundleFormat bundle_format, size_t disable_type_check, size_t source_map, size_t compress,
owned BuildCompleteFunc on_complete, DiagnosticFunc on_diagnostic);
string platform, string[] externals, owned BuildCompleteFunc on_complete,
DiagnosticFunc on_diagnostic);
[CCode (has_target = false)]
private delegate void WatchFunc (string project_root, string entrypoint, OutputFormat output_format,
BundleFormat bundle_format, size_t disable_type_check, size_t source_map, size_t compress,
owned WatchReadyFunc on_ready, StartingFunc on_starting, FinishedFunc on_finished, OutputFunc on_output,
DiagnosticFunc on_diagnostic);
string platform, string[] externals, owned WatchReadyFunc on_ready, StartingFunc on_starting,
FinishedFunc on_finished, OutputFunc on_output, DiagnosticFunc on_diagnostic);
#if COMPILER_BACKEND_STATIC_COMPILATION
private extern void _init_go_runtime ();
@@ -373,6 +376,27 @@ namespace Frida {
set;
default = NONE;
}
public JsPlatform platform {
get;
set;
default = GUM;
}
internal Gee.List<string> externals = new Gee.ArrayList<string> ();
public void clear_externals () {
externals.clear ();
}
public void add_external (string external) {
externals.add (external);
}
public void enumerate_externals (Func<string> func) {
foreach (var external in externals)
func (external);
}
}
public sealed class BuildOptions : CompilerOptions {
@@ -446,4 +470,18 @@ namespace Frida {
return Marshal.enum_to_nick<JsCompression> (this);
}
}
public enum JsPlatform {
GUM,
BROWSER,
NEUTRAL;
public static JsPlatform from_nick (string nick) throws Error {
return Marshal.enum_from_nick<JsPlatform> (nick);
}
public string to_nick () {
return Marshal.enum_to_nick<JsPlatform> (this);
}
}
}
+123 -21
View File
@@ -314,6 +314,9 @@ namespace Frida {
SocketService? service = null;
TimeoutSource? timeout_source = null;
bool timed_out = false;
bool child_exited = false;
int child_status = 0;
try {
string tempdir;
@@ -341,7 +344,6 @@ namespace Frida {
return false;
});
idle_source.attach (main_context);
yield;
var incoming_handler = service.incoming.connect ((c) => {
@@ -350,42 +352,63 @@ namespace Frida {
return true;
});
var timer = new Timer ();
timeout_source = new TimeoutSource (10);
timeout_source = new TimeoutSource.seconds (10);
timeout_source.set_callback (() => {
timed_out = true;
launch_helper.callback ();
return Source.CONTINUE;
return Source.REMOVE;
});
timeout_source.attach (main_context);
string[] argv = { helper_path, socket_address };
GLib.SpawnFlags flags = GLib.SpawnFlags.LEAVE_DESCRIPTORS_OPEN | /* GLib.SpawnFlags.CLOEXEC_PIPES */ 256;
GLib.SpawnFlags flags =
GLib.SpawnFlags.LEAVE_DESCRIPTORS_OPEN |
GLib.SpawnFlags.DO_NOT_REAP_CHILD |
/* GLib.SpawnFlags.CLOEXEC_PIPES */ 256;
GLib.Process.spawn_async (null, argv, null, flags, null, out pending_pid);
while (pending_stream == null && timer.elapsed () < 10.0 && !process_is_dead (pending_pid))
var exit_monitor = new ChildExitMonitor (pending_pid, main_context);
var exit_handler = exit_monitor.exited.connect ((status) => {
child_exited = true;
child_status = status;
launch_helper.callback ();
});
while (pending_stream == null && !timed_out && !child_exited)
yield;
exit_monitor.disconnect (exit_handler);
exit_monitor.stop ();
timeout_source.destroy ();
timeout_source = null;
service.disconnect (incoming_handler);
service.stop ();
service = null;
timeout_source.destroy ();
timeout_source = null;
if (pending_stream == null)
throw new Error.TIMED_OUT ("Unexpectedly timed out while spawning helper process");
if (pending_stream == null) {
if (child_exited)
throw new Error.PROCESS_NOT_FOUND ("Helper exited during launch (status=%d)", child_status);
if (timed_out)
throw new Error.TIMED_OUT ("Unexpectedly timed out while spawning helper");
}
pending_connection = yield new DBusConnection (pending_stream, ServerGuid.HOST_SESSION_SERVICE,
AUTHENTICATION_SERVER | AUTHENTICATION_ALLOW_ANONYMOUS, null, cancellable);
pending_proxy = yield pending_connection.get_proxy (null, ObjectPath.HELPER, DO_NOT_LOAD_PROPERTIES,
cancellable);
if (pending_connection.is_closed ())
throw new Error.NOT_SUPPORTED ("Helper terminated prematurely");
} catch (GLib.Error e) {
bool died_unexpectedly = pending_pid != 0 && process_is_dead (pending_pid);
if (pending_pid != 0 && !died_unexpectedly)
if (pending_pid != 0 && !child_exited) {
Posix.kill ((Posix.pid_t) pending_pid, Posix.Signal.KILL);
reap_later.begin (pending_pid);
}
if (timeout_source != null)
timeout_source.destroy ();
@@ -393,10 +416,6 @@ namespace Frida {
if (service != null)
service.stop ();
if (died_unexpectedly) {
throw new Error.PROCESS_NOT_FOUND ("Peer process (%d) died unexpectedly: %s",
pending_pid, e.message);
}
if (e is Error)
throw (Error) e;
throw new Error.PERMISSION_DENIED ("%s", e.message);
@@ -422,10 +441,6 @@ namespace Frida {
return proxy;
}
private static bool process_is_dead (uint pid) {
return Posix.kill ((Posix.pid_t) pid, 0) == -1 && Posix.errno == Posix.ESRCH;
}
private void on_connection_closed (bool remote_peer_vanished, GLib.Error? error) {
obtain_request = null;
@@ -441,7 +456,10 @@ namespace Frida {
connection.on_closed.disconnect (on_connection_closed);
connection = null;
Pid pid = process_pid;
process_pid = 0;
if (pid != 0)
reap_later.begin (pid);
}
private void on_output (uint pid, int fd, uint8[] data) {
@@ -559,4 +577,88 @@ namespace Frida {
return false;
}
}
private class ChildExitMonitor : Object {
public signal void exited (int status);
private Pid pid;
private MainContext? context;
private TimeoutSource? source;
private uint interval_ms = 10;
private const uint MAX_INTERVAL_MS = 1000;
public ChildExitMonitor (Pid pid, MainContext? ctx = null) {
this.pid = pid;
context = ctx ?? MainContext.get_thread_default ();
arm ();
}
public void stop () {
if (source != null) {
source.destroy ();
source = null;
}
}
private void arm () {
source = new TimeoutSource (interval_ms);
source.set_callback (() => {
int status;
if (try_reap (pid, out status)) {
stop ();
exited (status);
return Source.REMOVE;
}
if (interval_ms < MAX_INTERVAL_MS) {
interval_ms = uint.min (MAX_INTERVAL_MS, 2 * interval_ms);
stop ();
arm ();
return Source.REMOVE;
}
return Source.CONTINUE;
});
source.attach (context);
}
private static bool try_reap (Pid pid, out int status) {
status = 0;
var r = Posix.waitpid ((Posix.pid_t) pid, out status, Posix.WNOHANG);
if (r > 0)
return true;
if (r == 0)
return false;
if (Posix.errno == Posix.EINTR)
return false;
if (Posix.errno == Posix.ECHILD)
return true;
return true;
}
}
private async void reap_later (Pid pid) {
var monitor = new ChildExitMonitor (pid);
bool done = false;
ulong h = monitor.exited.connect ((status) => {
done = true;
reap_later.callback ();
});
try {
while (!done)
yield;
} finally {
monitor.disconnect (h);
monitor.stop ();
}
}
}
-2
View File
@@ -109,8 +109,6 @@ _frida_get_springboard_api (void)
gum_interceptor_replace (interceptor, frida_xpc_look_up_endpoint, frida_replacement_xpc_look_up_endpoint, NULL, NULL);
else
g_error ("Unable to locate _xpc_look_up_endpoint(); please file a bug");
g_object_unref (interceptor);
}
#endif
+1 -1
View File
@@ -489,7 +489,7 @@ static void
frida_add_app_icons (GHashTable * parameters, NSImage * image)
{
GVariantBuilder builder;
const guint sizes[] = { 16, 32 };
const guint sizes[] = { 128 };
guint i;
g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
+1
View File
@@ -4,6 +4,7 @@
#include <string.h>
#include <unistd.h>
#include <gio/gunixmounts.h>
#include <gum/gum.h>
typedef struct _FridaEnumerateProcessesOperation FridaEnumerateProcessesOperation;
+140 -43
View File
@@ -12,12 +12,15 @@ struct _FridaSimmyContext
void * core_simulator;
NSString * SimDeviceLaunchApplicationKeyArguments;
NSString * SimDeviceLaunchApplicationKeyEnvironment;
NSString * SimDeviceLaunchApplicationKeyStandardErrPath;
NSString * SimDeviceLaunchApplicationKeyStandardOutPath;
NSString * SimDeviceLaunchApplicationKeyTerminateRunningProcess;
NSString * SimDeviceLaunchApplicationKeyWaitForDebugger;
NSString * SimDeviceSpawnKeyArguments;
NSString * SimDeviceSpawnKeyEnvironment;
NSString * SimDeviceSpawnKeyStderr;
NSString * SimDeviceSpawnKeyStdin;
NSString * SimDeviceSpawnKeyStdout;
@@ -30,6 +33,9 @@ struct _FridaSimmyContext
static void frida_simmy_context_destroy (FridaSimmyContext * self);
static void frida_simmy_context_emit_devices (FridaSimmyContext * self);
static NSArray * frida_argv_to_arguments_array (gchar * const * argv, gint argv_length, gint start_index);
static NSDictionary * frida_envp_to_environment_dictionary (gchar * const * envp, gint envp_length);
@interface SimRuntime : NSObject
@property (nonatomic, readonly, strong) NSString * identifier;
@property (nonatomic, readonly, strong) NSString * shortName;
@@ -153,12 +159,15 @@ frida_simmy_context_emit_devices (FridaSimmyContext * self)
g_assert (str != NULL); \
self->N = *str
FRIDA_ASSIGN_CS_CONSTANT (SimDeviceLaunchApplicationKeyArguments);
FRIDA_ASSIGN_CS_CONSTANT (SimDeviceLaunchApplicationKeyEnvironment);
FRIDA_ASSIGN_CS_CONSTANT (SimDeviceLaunchApplicationKeyStandardErrPath);
FRIDA_ASSIGN_CS_CONSTANT (SimDeviceLaunchApplicationKeyStandardOutPath);
FRIDA_ASSIGN_CS_CONSTANT (SimDeviceLaunchApplicationKeyTerminateRunningProcess);
FRIDA_ASSIGN_CS_CONSTANT (SimDeviceLaunchApplicationKeyWaitForDebugger);
FRIDA_ASSIGN_CS_CONSTANT (SimDeviceSpawnKeyArguments);
FRIDA_ASSIGN_CS_CONSTANT (SimDeviceSpawnKeyEnvironment);
FRIDA_ASSIGN_CS_CONSTANT (SimDeviceSpawnKeyStderr);
FRIDA_ASSIGN_CS_CONSTANT (SimDeviceSpawnKeyStdin);
FRIDA_ASSIGN_CS_CONSTANT (SimDeviceSpawnKeyStdout);
@@ -234,7 +243,7 @@ _frida_simmy_device_list_applications (FridaSimmyDevice * self, FridaSimmyDevice
}
void
_frida_simmy_device_launch_application (FridaSimmyDevice * self, const gchar * identifier, FridaHostSpawnOptions * options,
_frida_simmy_device_launch_application (FridaSimmyDevice * self, const gchar * identifier, FridaHostSpawnOptions * opts,
FridaSimmyDeviceLaunchApplicationCompleteFunc on_complete, gpointer on_complete_target,
GDestroyNotify on_complete_target_destroy_notify)
{
@@ -249,20 +258,12 @@ _frida_simmy_device_launch_application (FridaSimmyDevice * self, const gchar * i
device = frida_simmy_device_get_handle (self);
ctx = frida_simmy_device_get_simmy_context (self);
pipes = frida_make_stdio_pipes (options->stdio, FALSE, NULL, NULL, &out_fd, &out_name, &err_fd, &err_name, &error);
if (opts->has_envp)
goto envp_not_supported;
pipes = frida_make_stdio_pipes (opts->stdio, FALSE, NULL, NULL, &out_fd, &out_name, &err_fd, &err_name, &error);
if (error != NULL)
{
dispatch_async (ctx->dispatch_queue, ^
{
on_complete (error->message, NULL, on_complete_target);
g_error_free (error);
if (on_complete_target_destroy_notify != NULL)
on_complete_target_destroy_notify (on_complete_target);
});
return;
}
goto propagate_error;
main_context = g_main_context_ref_thread_default ();
@@ -275,7 +276,13 @@ _frida_simmy_device_launch_application (FridaSimmyDevice * self, const gchar * i
ctx->SimDeviceLaunchApplicationKeyTerminateRunningProcess: @YES,
} mutableCopy];
if (options->stdio == FRIDA_STDIO_PIPE)
if (opts->has_argv)
launch_opts[ctx->SimDeviceLaunchApplicationKeyArguments] = frida_argv_to_arguments_array (opts->argv, opts->argv_length1, 1);
if (opts->has_env)
launch_opts[ctx->SimDeviceLaunchApplicationKeyEnvironment] = frida_envp_to_environment_dictionary (opts->env, opts->env_length1);
if (opts->stdio == FRIDA_STDIO_PIPE)
{
launch_opts[ctx->SimDeviceLaunchApplicationKeyStandardOutPath] = @(out_name);
launch_opts[ctx->SimDeviceLaunchApplicationKeyStandardErrPath] = @(err_name);
@@ -310,26 +317,18 @@ _frida_simmy_device_launch_application (FridaSimmyDevice * self, const gchar * i
g_free (out_name);
g_free (err_name);
}
void
_frida_simmy_device_spawn_program (FridaSimmyDevice * self, const gchar * program, FridaHostSpawnOptions * options,
FridaSimmyDeviceSpawnProgramCompleteFunc on_complete, gpointer on_complete_target,
GDestroyNotify on_complete_target_destroy_notify)
{
const FridaStdio stdio = options->stdio;
SimDevice * device;
FridaSimmyContext * ctx;
__block FridaStdioPipes * pipes;
__block FridaFileDescriptor * in_fd, * out_fd, * err_fd;
GError * error = NULL;
__block GMainContext * main_context;
return;
device = frida_simmy_device_get_handle (self);
ctx = frida_simmy_device_get_simmy_context (self);
pipes = frida_make_stdio_pipes (options->stdio, TRUE, &in_fd, NULL, &out_fd, NULL, &err_fd, NULL, &error);
if (error != NULL)
envp_not_supported:
{
error = g_error_new_literal (
FRIDA_ERROR,
FRIDA_ERROR_NOT_SUPPORTED,
"The 'envp' option is not supported when spawning Simmy apps, use the 'env' option instead");
goto propagate_error;
}
propagate_error:
{
dispatch_async (ctx->dispatch_queue, ^
{
@@ -340,8 +339,34 @@ _frida_simmy_device_spawn_program (FridaSimmyDevice * self, const gchar * progra
if (on_complete_target_destroy_notify != NULL)
on_complete_target_destroy_notify (on_complete_target);
});
return;
}
}
void
_frida_simmy_device_spawn_program (FridaSimmyDevice * self, const gchar * program, FridaHostSpawnOptions * opts,
FridaSimmyDeviceSpawnProgramCompleteFunc on_complete, gpointer on_complete_target,
GDestroyNotify on_complete_target_destroy_notify)
{
const FridaStdio stdio = opts->stdio;
SimDevice * device;
FridaSimmyContext * ctx;
__block FridaStdioPipes * pipes;
__block FridaFileDescriptor * in_fd, * out_fd, * err_fd;
GError * error = NULL;
__block GMainContext * main_context;
device = frida_simmy_device_get_handle (self);
ctx = frida_simmy_device_get_simmy_context (self);
if (opts->has_envp)
goto envp_not_supported;
pipes = frida_make_stdio_pipes (opts->stdio, TRUE, &in_fd, NULL, &out_fd, NULL, &err_fd, NULL, &error);
if (error != NULL)
goto propagate_error;
main_context = g_main_context_ref_thread_default ();
@autoreleasepool
@@ -353,17 +378,11 @@ _frida_simmy_device_spawn_program (FridaSimmyDevice * self, const gchar * progra
ctx->SimDeviceSpawnKeyWaitForDebugger: @YES,
} mutableCopy];
if (options->has_argv)
{
NSMutableArray<NSString *> * args;
int i;
if (opts->has_argv)
spawn_opts[ctx->SimDeviceSpawnKeyArguments] = frida_argv_to_arguments_array (opts->argv, opts->argv_length1, 0);
args = [NSMutableArray arrayWithCapacity:options->argv_length1];
for (i = 0; i != options->argv_length1; i++)
[args addObject:[NSString stringWithUTF8String:options->argv[i]]];
spawn_opts[ctx->SimDeviceSpawnKeyArguments] = args;
}
if (opts->has_env)
spawn_opts[ctx->SimDeviceSpawnKeyEnvironment] = frida_envp_to_environment_dictionary (opts->env, opts->env_length1);
if (stdio == FRIDA_STDIO_PIPE)
{
@@ -404,6 +423,30 @@ _frida_simmy_device_spawn_program (FridaSimmyDevice * self, const gchar * progra
on_complete_target_destroy_notify (on_complete_target);
}];
}
return;
envp_not_supported:
{
error = g_error_new_literal (
FRIDA_ERROR,
FRIDA_ERROR_NOT_SUPPORTED,
"The 'envp' option is not supported when spawning Simmy programs, use the 'env' option instead");
goto propagate_error;
}
propagate_error:
{
dispatch_async (ctx->dispatch_queue, ^
{
on_complete (error->message, NULL, on_complete_target);
g_error_free (error);
if (on_complete_target_destroy_notify != NULL)
on_complete_target_destroy_notify (on_complete_target);
});
return;
}
}
const gchar *
@@ -429,3 +472,57 @@ _frida_simmy_runtime_get_root (FridaSimmyRuntime * self)
{
return ((SimRuntime *) frida_simmy_runtime_get_handle (self)).root.UTF8String;
}
static NSArray *
frida_argv_to_arguments_array (gchar * const * argv, gint argv_length, gint start_index)
{
NSMutableArray * result;
gint i;
result = [NSMutableArray arrayWithCapacity:argv_length];
for (i = start_index; i < argv_length; i++)
[result addObject:[NSString stringWithUTF8String:argv[i]]];
return result;
}
static NSDictionary *
frida_envp_to_environment_dictionary (gchar * const * envp, gint envp_length)
{
NSMutableDictionary * result;
gint i;
result = [NSMutableDictionary dictionaryWithCapacity:envp_length];
for (i = 0; i != envp_length; i++)
{
const gchar * pair, * equals_sign, * name_start, * value_start;
NSUInteger name_size, value_size;
NSString * name, * value;
pair = envp[i];
equals_sign = strchr (pair, '=');
if (equals_sign == NULL)
continue;
name_start = pair;
name_size = equals_sign - name_start;
value_start = equals_sign + 1;
value_size = pair + strlen (pair) - value_start;
name = [[NSString alloc] initWithBytes:name_start
length:name_size
encoding:NSUTF8StringEncoding];
value = [[NSString alloc] initWithBytes:value_start
length:value_size
encoding:NSUTF8StringEncoding];
[result setObject:value forKey:name];
[value release];
[name release];
}
return result;
}
+31 -9
View File
@@ -235,7 +235,13 @@ namespace Frida {
Cancellable? cancellable) throws Error, IOError {
var opts = FrontmostQueryOptions._deserialize (options);
return yield springboard_agent.get_frontmost_application (opts, cancellable);
try {
return yield springboard_agent.get_frontmost_application (opts, cancellable);
} catch (Error e) {
if (e is Error.PERMISSION_DENIED)
throw new Error.NOT_SUPPORTED ("Frontmost query is only supported with SIP disabled (for now)");
throw e;
}
}
public async HostApplicationInfo[] enumerate_applications (HashTable<string, Variant> options,
@@ -246,12 +252,28 @@ namespace Frida {
Future<Gee.List<Simmy.Application>> list_apps_request = device.list_applications ();
Future<Gee.List<LaunchdJob>> list_jobs_request = list_launchd_jobs (cancellable);
var selected_ids = new Gee.HashSet<string> ();
opts.enumerate_selected_identifiers (identifier => {
selected_ids.add (identifier);
});
bool include_all_apps = selected_ids.is_empty;
var apps = new Gee.ArrayList<Simmy.Application> ();
foreach (Simmy.Application app in yield list_apps_request.wait_async (cancellable)) {
unowned string id = app.identifier;
if (include_all_apps || id in selected_ids)
apps.add (app);
}
Gee.Map<string, Bytes>? icons = null;
if (scope == FULL) {
var app_ids = new Gee.ArrayList<string> ();
foreach (Simmy.Application app in yield list_apps_request.wait_async (cancellable))
foreach (var app in apps)
app_ids.add (app.identifier);
icons = yield springboard_agent.fetch_application_icons (app_ids, cancellable);
try {
icons = yield springboard_agent.fetch_application_icons (app_ids, cancellable);
} catch (Error e) {
}
}
var pids = new Gee.HashMap<string, uint> ();
@@ -268,11 +290,11 @@ namespace Frida {
}
var result = new HostApplicationInfo[0];
foreach (Simmy.Application app in yield list_apps_request.wait_async (cancellable)) {
foreach (var app in apps) {
unowned string identifier = app.identifier;
var info = HostApplicationInfo (identifier, app.display_name, pids[identifier], make_parameters_dict ());
if (scope == FULL)
if (scope == FULL && icons != null)
add_app_icons (info.parameters, icons[identifier]);
result += info;
}
@@ -675,10 +697,10 @@ namespace Frida {
return promise.future;
}
public Future<SpawnedProcess> launch_application (string identifier, HostSpawnOptions options) {
public Future<SpawnedProcess> launch_application (string identifier, HostSpawnOptions opts) {
var promise = new Promise<SpawnedProcess> ();
_launch_application (identifier, options, (error_message, process) => {
_launch_application (identifier, opts, (error_message, process) => {
if (error_message != null)
promise.reject (new Error.NOT_SUPPORTED ("%s", error_message));
else
@@ -688,10 +710,10 @@ namespace Frida {
return promise.future;
}
public Future<SpawnedProcess> spawn_program (string program, HostSpawnOptions options) {
public Future<SpawnedProcess> spawn_program (string program, HostSpawnOptions opts) {
var promise = new Promise<SpawnedProcess> ();
_spawn_program (program, options, (error_message, process) => {
_spawn_program (program, opts, (error_message, process) => {
if (error_message != null)
promise.reject (new Error.NOT_SUPPORTED ("%s", error_message));
else
+1 -1
View File
@@ -1,6 +1,6 @@
[wrap-git]
url = https://github.com/frida/frida-gum.git
revision = 17.4.2
revision = 17.5.2
depth = 1
[provide]