Compare commits

...
50 Commits
Author SHA1 Message Date
Ole André Vadla Ravnås 20d5d121b7 subprojects: Prepare for release 2025-06-20 01:13:54 +02:00
Ole André Vadla Ravnås dc71534220 subprojects: Bump outdated 2025-06-20 01:12:26 +02:00
Ole André Vadla Ravnås 35afee9b4a package-manager: Handle tarballs with root entries
Like if there's a directory entry for "package/", or somehow any files
at the root level.
2025-06-20 01:11:39 +02:00
Ole André Vadla Ravnås 7b130e6eba package-manager: Fix handling of scoped specs 2025-06-20 01:11:39 +02:00
Ole André Vadla Ravnås d28c46c332 package-manager: Fix a stylistic inconsistency 2025-06-20 01:11:39 +02:00
Ole André Vadla Ravnås ab103a73ca package-manager: Simplify substring logic 2025-06-20 01:11:39 +02:00
Ole André Vadla Ravnås 7b7d9acf8c subprojects: Prepare for release 2025-06-19 23:25:44 +02:00
Ole André Vadla Ravnås 215076a0fa subprojects: Bump outdated 2025-06-19 23:23:46 +02:00
Ole André Vadla Ravnås 3d47bf73b4 package-manager: Only report installed packages
The toplevel packages that were left untouched should not be included.

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

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

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

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

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

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

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

Kudos to @mrmacete for helping track this one down.
2025-06-10 20:41:36 +02:00
Ole André Vadla Ravnås ec3b864007 subprojects: Prepare for release 2025-06-07 13:32:23 +02:00
Ole André Vadla Ravnås 93fc48d20e subprojects: Bump outdated 2025-06-07 13:30:19 +02:00
Ole André Vadla Ravnås 4f120d9e46 meson: Simplify the Vala flags logic 2025-06-07 13:29:46 +02:00
Ole André Vadla Ravnås f9ee24038b gadget: Correct QuickJS big-endian bytecode check 2025-06-07 13:27:49 +02:00
Ole André Vadla Ravnås 5692298b03 subprojects: Bump outdated 2025-06-07 11:23:12 +02:00
Ole André Vadla Ravnås 375be6181a compiler: Rename conflictful Go symbols in backend
To avoid conflicts when we're linked into a Go binary.
2025-06-07 11:22:36 +02:00
Ole André Vadla Ravnås e5fa1b1fab api: Add version defines and macros 2025-06-07 11:20:23 +02:00
42 changed files with 2834 additions and 1769 deletions

No files matched your search

+11 -4
View File
@@ -206,10 +206,15 @@ jobs:
cat /etc/motd
export PS1='\u@frida:\w\$ '
/root/frida-tests
if [ $? -eq 0 ]; then
status=\$?
echo "exit status: \$status"
if [ \$status -eq 0 ]; then
echo EXIT_OK
elif [ \$status -gt 128 ]; then
signal=\$((\$status - 128))
echo "EXIT_FAIL (terminated by signal \$signal)"
else
echo EXIT_FAIL
echo "EXIT_FAIL (exit code \$status)"
fi
EOF
@@ -418,6 +423,7 @@ jobs:
strategy:
matrix:
arch: [x86, x86_64, arm, armbe8, arm64, arm64be, arm64beilp32, mips, mipsel, mips64, mips64el]
fail-fast: false
runs-on: ubuntu-latest
container: ghcr.io/frida/core-linux-helpers-${{ matrix.arch }}:latest
steps:
@@ -431,7 +437,7 @@ jobs:
- name: Check for unexpected changes
run: |
git config --global --add safe.directory "$(realpath .)"
status_output="$(git status --porcelain)"
status_output=$(git status --porcelain tests/labrats/{resident-agent,simple-agent}-linux-${{ matrix.arch }}.so tests/labrats/{forker,sleeper,spawner}-linux-${{ matrix.arch }})
if [ -n "$status_output" ]; then
echo "Unexpected changes detected:"
echo "$status_output"
@@ -450,6 +456,7 @@ jobs:
strategy:
matrix:
arch: [x86, x86_64, arm, armbe8, arm64, arm64be, arm64beilp32, mips, mipsel, mips64, mips64el]
fail-fast: false
runs-on: ubuntu-latest
container: ghcr.io/frida/core-linux-helpers-${{ matrix.arch }}:latest
steps:
@@ -463,7 +470,7 @@ jobs:
- name: Check for unexpected changes
run: |
git config --global --add safe.directory "$(realpath .)"
status_output="$(git status --porcelain)"
status_output=$(git status --porcelain src/linux/helpers/{bootstrapper,loader}-${{ matrix.arch }}.bin)
if [ -n "$status_output" ]; then
echo "Unexpected changes detected:"
echo "$status_output"
+14 -1
View File
@@ -446,7 +446,14 @@ namespace Frida {
public string read_fixed_string (size_t offset, size_t size) throws Error {
string * start = (string *) get_pointer (offset, size);
string val = start->substring (0, (long) size);
size_t max_length = size - offset;
string * end = memchr (start, 0, max_length);
size_t n;
if (end != null)
n = end - start;
else
n = size;
string val = start->substring (0, (long) n);
if (!val.validate ())
throw new Error.PROTOCOL ("Invalid UTF-8 string");
return val;
@@ -579,6 +586,12 @@ namespace Frida {
return val;
}
public unowned BufferReader skip (size_t n) throws Error {
check_available (n);
offset += n;
return this;
}
private void check_available (size_t n) throws Error {
if (available < n)
throw new Error.PROTOCOL ("Malformed buffer: truncated");
+114
View File
@@ -0,0 +1,114 @@
namespace Frida.FS {
public void mkdirp (File dir, Cancellable? cancellable = null) throws Error {
try {
dir.make_directory_with_parents (cancellable);
} catch (GLib.Error e) {
if (!(e is IOError.EXISTS))
throw new Error.PERMISSION_DENIED ("%s", e.message);
}
}
public void rmtree (File dir, Cancellable? cancellable = null) throws Error {
rmtree_worker (dir, 0, cancellable);
}
private void rmtree_worker (File dir, uint depth, Cancellable? cancellable = null) throws Error {
FileEnumerator enumerator;
try {
enumerator = dir.enumerate_children (FileAttribute.STANDARD_NAME, NOFOLLOW_SYMLINKS, cancellable);
} catch (GLib.Error e) {
if (depth == 0 && e is IOError.NOT_FOUND)
return;
throw new Error.PERMISSION_DENIED ("%s", e.message);
}
try {
FileInfo? info;
File? child;
while (enumerator.iterate (out info, out child, cancellable) && info != null) {
if (info == null)
continue;
if (info.get_file_type () == DIRECTORY)
rmtree (child, cancellable);
else
child.delete (cancellable);
}
dir.delete (cancellable);
} catch (GLib.Error e) {
if (!(e is IOError.EXISTS))
throw new Error.PERMISSION_DENIED ("%s", e.message);
}
}
public async void rmtree_async (File dir, Cancellable? cancellable = null) throws Error, IOError {
yield rmtree_async_worker (dir, 0, cancellable);
}
private async void rmtree_async_worker (File dir, uint depth, Cancellable? cancellable = null) throws Error, IOError {
int io_priority = Priority.DEFAULT;
FileEnumerator enumerator;
try {
enumerator = yield dir.enumerate_children_async (FileAttribute.STANDARD_NAME, NOFOLLOW_SYMLINKS, io_priority,
cancellable);
} catch (GLib.Error e) {
if (depth == 0 && e is IOError.NOT_FOUND)
return;
throw new Error.PERMISSION_DENIED ("%s", e.message);
}
try {
while (true) {
var batch = yield enumerator.next_files_async (1000, io_priority, cancellable);
if (batch.is_empty ())
break;
foreach (FileInfo info in batch) {
File child = dir.get_child (info.get_name ());
if (info.get_file_type () == DIRECTORY)
yield rmtree_async_worker (child, depth + 1, cancellable);
else
yield child.delete_async (io_priority, cancellable);
}
}
yield dir.delete_async (io_priority, cancellable);
} catch (GLib.Error e) {
throw new Error.PERMISSION_DENIED ("%s", e.message);
}
}
public async string read_all_text (File f, Cancellable? cancellable) throws Error, IOError {
Bytes b = yield read_all_bytes (f, cancellable);
string text = (string) b.get_data ();
if (!text.validate ())
throw new Error.PROTOCOL ("Unable to read '%s': invalid UTF-8", f.get_parse_name ());
return text;
}
public async void write_all_text (File f, string t, Cancellable? cancellable) throws Error, IOError {
yield write_all_bytes (f, new Bytes (t.data), cancellable);
}
public async Bytes read_all_bytes (File f, Cancellable? cancellable) throws Error, IOError {
try {
return yield f.load_bytes_async (cancellable, null);
} catch (GLib.Error e) {
if (e is IOError.CANCELLED)
throw (IOError) e;
if (e is IOError.NOT_FOUND)
throw new Error.INVALID_ARGUMENT ("%s", e.message);
throw new Error.PERMISSION_DENIED ("%s", e.message);
}
}
public async void write_all_bytes (File f, Bytes b, Cancellable? cancellable) throws Error, IOError {
try {
yield f.replace_contents_bytes_async (b, null, false, FileCreateFlags.NONE, cancellable, null);
} catch (GLib.Error e) {
if (e is IOError.CANCELLED)
throw (IOError) e;
throw new Error.PERMISSION_DENIED ("%s", e.message);
}
}
}
@@ -1,5 +1,5 @@
#ifndef __FRIDA_SYSCALL_H__
#define __FRIDA_SYSCALL_H__
#ifndef __FRIDA_LINUX_SYSCALL_H__
#define __FRIDA_LINUX_SYSCALL_H__
#include <linux/unistd.h>
#include <sys/syscall.h>
@@ -14,7 +14,7 @@ namespace Frida {
[CCode (cheader_filename = "sys/mman.h", cname = "MAP_ANONYMOUS")]
public const int MAP_ANONYMOUS;
[CCode (cheader_filename = "linux/frida-syscall.h", cprefix = "SYS_", has_type_id = false)]
[CCode (cheader_filename = "linux-syscall.h", cprefix = "SYS_", has_type_id = false)]
public enum SysCall {
memfd_create,
pidfd_getfd,
+107
View File
@@ -0,0 +1,107 @@
namespace Frida {
private uint linux_major = 0;
private uint linux_minor = 0;
public bool check_kernel_version (uint major, uint minor) {
if (linux_major == 0) {
var name = Posix.utsname ();
name.release.scanf ("%u.%u", out linux_major, out linux_minor);
}
return (linux_major == major && linux_minor >= minor) || linux_major > major;
}
public class FileDescriptor : Object, FileDescriptorBased {
public int handle;
public FileDescriptor (int handle) {
this.handle = handle;
}
~FileDescriptor () {
if (handle != -1)
Posix.close (handle);
}
public int steal () {
int result = handle;
handle = -1;
return result;
}
public int get_fd () {
return handle;
}
}
public sealed class PidFileDescriptor : FileDescriptor {
private uint pid;
private PidFileDescriptor (int fd, uint pid) {
base (fd);
this.pid = pid;
}
public static bool is_supported () {
return check_kernel_version (5, 3);
}
public static bool getfd_is_supported () {
return check_kernel_version (5, 6);
}
public static PidFileDescriptor from_pid (uint pid) throws Error {
int fd = pidfd_open (pid, 0);
if (fd == -1)
throw_pidfd_error (pid, errno);
return new PidFileDescriptor (fd, pid);
}
public FileDescriptor getfd (int targetfd) throws Error {
int fd = pidfd_getfd (handle, targetfd, 0);
if (fd == -1)
throw_pidfd_error (pid, errno);
return new FileDescriptor (fd);
}
private static int pidfd_open (uint pid, uint flags) {
return Linux.syscall (SysCall.pidfd_open, pid, flags);
}
private static int pidfd_getfd (int pidfd, int targetfd, uint flags) {
return Linux.syscall (SysCall.pidfd_getfd, pidfd, targetfd, flags);
}
[NoReturn]
private static void throw_pidfd_error (uint pid, int err) throws Error {
switch (err) {
case Posix.ESRCH:
throw new Error.PROCESS_NOT_FOUND ("Process not found");
case Posix.EPERM:
throw new Error.PERMISSION_DENIED ("Unable to use pidfd for pid %u: %s", pid, strerror (err));
default:
throw new Error.NOT_SUPPORTED ("Unable to use pidfd for pid %u: %s", pid, strerror (err));
}
}
}
namespace MemoryFileDescriptor {
public bool is_supported () {
return check_kernel_version (3, 17);
}
public static FileDescriptor from_bytes (string name, Bytes bytes) {
assert (is_supported ());
var fd = new FileDescriptor (memfd_create (name, 0));
unowned uint8[] data = bytes.get_data ();
ssize_t n = Posix.write (fd.handle, data, data.length);
assert (n == data.length);
return fd;
}
private int memfd_create (string name, uint flags) {
return Linux.syscall (SysCall.memfd_create, name, flags);
}
}
}
+17 -1
View File
@@ -9,6 +9,7 @@ base_sources = [
'p2p-glue.c',
'dbus.vala',
'promise.vala',
'fs.vala',
'socket.vala',
'socket-glue.c',
'buffer.vala',
@@ -28,6 +29,15 @@ if host_os_family == 'darwin'
base_sources += 'corefoundation.vala'
endif
if host_os_family == 'linux'
base_sources += 'linux.vala'
extra_vala_args += [
'--pkg=linux',
'--pkg=linux-system',
'--pkg=posix',
]
endif
extra_deps = []
if host_os_family != 'windows'
extra_vala_args += '--pkg=gio-unix-2.0'
@@ -45,6 +55,12 @@ if host_os_family == 'darwin'
'--pkg=darwin-xpc',
]
endif
if host_os_family == 'linux'
base_vala_args += [
'--vapidir=' + meson.current_source_dir(),
'--pkg=gio-unix-2.0',
]
endif
base_gir_name = f'FridaBase-@[email protected]'
@@ -62,7 +78,7 @@ base = static_library('frida-base-' + api_version, base_sources,
base_dep = declare_dependency(
include_directories: include_directories('.'),
link_with: base,
dependencies: [nice_dep, json_glib_dep, gum_dep],
dependencies: [nice_dep, json_glib_dep, gum_dep] + extra_deps,
)
base_build_dir = meson.current_build_dir()
+7 -1
View File
@@ -1242,7 +1242,13 @@ namespace Frida.Gadget {
}
private sealed class Script : Object, RpcPeer {
private const uint8 QUICKJS_BYTECODE_MAGIC = 0x02;
private const uint8 QUICKJS_BYTECODE_MAGIC =
#if BIG_ENDIAN
0x42
#else
0x02
#endif
;
public enum ChangeBehavior {
IGNORE,
+17 -5
View File
@@ -363,11 +363,13 @@ if host_toolchain == 'microsoft'
lib = find_program('lib')
ar = ''
nm = ''
ranlib = ''
strip = ''
else
lib = ''
ar = find_program('ar')
nm = find_program('nm')
ranlib = find_program('ranlib')
strip = find_program('strip')
endif
if host_os_family != 'windows'
@@ -421,9 +423,12 @@ if compiler_backend_opt.allowed()
go,
host_os,
host_abi,
shlib_suffix,
cc.get_id(),
'>>>', cc.cmd_array(), '<<<',
'>>>', ar, '<<<',
'>>>', nm, '<<<',
'>>>', ranlib, '<<<',
],
capture: true,
check: true
@@ -432,7 +437,13 @@ if compiler_backend_opt.allowed()
status = lines[0]
if status == 'ok'
have_compiler_backend = true
go_config = lines[1]
tokens = lines[1].split(' ')
go_mode = tokens[0]
go_config = tokens[1]
compiler_backend_static_compilation = go_mode == 'c-archive'
if compiler_backend_static_compilation
vala_flags += '--define=COMPILER_BACKEND_STATIC_COMPILATION'
endif
else
error_message = lines[1]
if compiler_backend_opt.enabled()
@@ -729,14 +740,15 @@ vala_flags += [
'--pkg', 'config',
]
vala_flags += ['--define=' + host_os_family.to_upper()]
vala_flags += '--define=' + host_os_family.to_upper()
if host_os != host_os_family
vala_flags += ['--define=' + host_os.to_upper()]
vala_flags += '--define=' + host_os.to_upper()
endif
vala_flags += ['--define=' + host_arch.to_upper()]
vala_flags += '--define=' + host_arch.to_upper()
if host_abi != host_arch
vala_flags += ['--define=' + host_abi.to_upper()]
vala_flags += '--define=' + host_abi.to_upper()
endif
vala_flags += '--define=' + host_machine.endian().to_upper() + '_ENDIAN'
add_project_arguments(vala_flags, language: 'vala')
add_project_arguments('-I' + vapidir, language: 'c')
+40 -5
View File
@@ -26,6 +26,11 @@ OBJECT_TYPE_PATTERN = re.compile(r"\bpublic\s+(sealed )?(class|interface)\s+(\w+
def main():
parser = argparse.ArgumentParser(description="Generate refined Frida API definitions")
parser.add_argument('--output', dest='output_type', choices=['bundle', 'header', 'gir', 'vapi', 'vapi-stamp'], default='bundle')
parser.add_argument('frida_version', metavar='frida-version', type=str)
parser.add_argument('frida_major_version', metavar='frida-major-version', type=str)
parser.add_argument('frida_minor_version', metavar='frida-minor-version', type=str)
parser.add_argument('frida_micro_version', metavar='frida-micro-version', type=str)
parser.add_argument('frida_nano_version', metavar='frida-nano-version', type=str)
parser.add_argument('api_version', metavar='api-version', type=str)
parser.add_argument('core_header', metavar='/path/to/frida-core.h', type=argparse.FileType('r', encoding='utf-8'))
parser.add_argument('core_gir', metavar='/path/to/Frida-x.y.gir', type=argparse.FileType('r', encoding='utf-8'))
@@ -38,6 +43,13 @@ def main():
args = parser.parse_args()
output_type = args.output_type
frida_version = args.frida_version
frida_version_components = (
args.frida_major_version,
args.frida_minor_version,
args.frida_micro_version,
args.frida_nano_version,
)
api_version = args.api_version
core_header = args.core_header.read()
core_gir = args.core_gir.read()
@@ -53,6 +65,7 @@ def main():
toplevel_names = [
"frida.vala",
"package-manager.vala",
"control-service.vala",
"portal-service.vala",
"file-monitor.vala",
@@ -78,7 +91,7 @@ def main():
elif output_type == 'vapi':
enable_vapi = True
api = parse_api(api_version, toplevel_code, core_header, core_vapi, base_header, base_vapi)
api = parse_api(frida_version, frida_version_components, api_version, toplevel_code, core_header, core_vapi, base_header, base_vapi)
if enable_header:
emit_header(api, output_dir)
@@ -93,7 +106,26 @@ def emit_header(api, output_dir):
with OutputFile(output_dir / 'frida-core.h') as output_header_file:
output_header_file.write("#ifndef __FRIDA_CORE_H__\n#define __FRIDA_CORE_H__\n\n")
output_header_file.write("#include <glib.h>\n#include <glib-object.h>\n#include <gio/gio.h>\n#include <json-glib/json-glib.h>\n")
output_header_file.write("#include <glib.h>\n#include <glib-object.h>\n#include <gio/gio.h>\n#include <json-glib/json-glib.h>\n\n")
output_header_file.write(f"#define FRIDA_VERSION \"{api.frida_version}\"\n\n")
for name, value in zip(['MAJOR', 'MINOR', 'MICRO', 'NANO'], api.frida_version_components):
output_header_file.write(f"#define FRIDA_{name}_VERSION {value}\n")
output_header_file.write("""
#define FRIDA_CHECK_VERSION(maj, min, mic) \\
(FRIDA_CURRENT_VERSION >= FRIDA_VERSION_ENCODE ((maj), (min), (mic)))
#define FRIDA_CURRENT_VERSION \\
FRIDA_VERSION_ENCODE ( \\
FRIDA_MAJOR_VERSION, \\
FRIDA_MINOR_VERSION, \\
FRIDA_MICRO_VERSION)
#define FRIDA_VERSION_ENCODE(maj, min, mic) \\
(((maj) * 1000000U) + ((min) * 1000U) + (mic))
""")
output_header_file.write("\nG_BEGIN_DECLS\n")
@@ -271,7 +303,7 @@ def emit_vapi(api, output_dir):
output_deps_file.write("gobject-2.0\n")
output_deps_file.write("gio-2.0\n")
def parse_api(api_version, toplevel_code, core_header, core_vapi, base_header, base_vapi):
def parse_api(frida_version, frida_version_components, api_version, toplevel_code, core_header, core_vapi, base_header, base_vapi):
all_headers = core_header + "\n" + base_header
all_enum_names = [m.group(1) for m in re.finditer(r"^\t+public\s+enum\s+(\w+)\s+", toplevel_code + "\n" + base_vapi, re.MULTILINE)]
@@ -464,7 +496,7 @@ def parse_api(api_version, toplevel_code, core_header, core_vapi, base_header, b
m = re.search(r"^[\w\*]+ frida_{}.+?;".format(f.name), all_headers, re.MULTILINE | re.DOTALL)
f.c_prototype = beautify_cprototype(m.group(0))
return ApiSpec(api_version, object_types, functions, enum_types, error_types)
return ApiSpec(frida_version, frida_version_components, api_version, object_types, functions, enum_types, error_types)
def function_is_public(name):
return not name.startswith("_") and \
@@ -478,7 +510,8 @@ def function_is_public(name):
"parse_control_address",
"parse_cluster_address",
"parse_socket_address",
"negotiate_connection"
"negotiate_connection",
"check_kernel_version",
]
def parse_vala_object_types(source) -> List[ApiObjectType]:
@@ -489,6 +522,8 @@ def parse_vapi_functions(vapi) -> List[ApiFunction]:
@dataclass
class ApiSpec:
frida_version: str
frida_version_components: List[int]
version: str
object_types: List[ApiObjectType]
functions: List[ApiFunction]
+5
View File
@@ -3,6 +3,11 @@ fs = import('fs')
generate_api = [python, files('generate.py')]
generate_api_args = [
frida_version,
frida_major_version.to_string(),
frida_minor_version.to_string(),
frida_micro_version.to_string(),
frida_nano_version.to_string(),
api_version,
core_build_dir / 'frida-core.h',
core_build_dir / core_gir_name,
+1 -1
View File
@@ -4,7 +4,7 @@
"description": "Script runtime used by Frida's Barebone backend",
"type": "module",
"scripts": {
"build": "esbuild script-runtime/entrypoint.ts --outfile=script-runtime.js --bundle --platform=neutral --target=es2022 --minify",
"build": "esbuild script-runtime/entrypoint.ts --outfile=script-runtime.js --bundle --platform=node --target=es2022 --minify",
"check": "tsc",
"watch": "tsc -w"
},
+4 -20
View File
@@ -208,7 +208,10 @@ namespace Frida.Barebone {
}
~CompilationAssets () {
rmtree (workdir);
try {
FS.rmtree (workdir);
} catch (Error e) {
}
}
private static string make_main_rs (string code, Machine machine) {
@@ -428,23 +431,4 @@ namespace Frida.Barebone {
yield file.replace_contents_async (content.data, null, false, FileCreateFlags.NONE, cancellable, null);
return file;
}
private void rmtree (File dir) {
try {
var enumerator = dir.enumerate_children (FileAttribute.STANDARD_NAME, NOFOLLOW_SYMLINKS);
FileInfo? info;
File? child;
while (enumerator.iterate (out info, out child) && info != null) {
if (info == null)
continue;
if (info.get_file_type () == DIRECTORY)
rmtree (child);
else
child.delete ();
}
dir.delete ();
} catch (GLib.Error e) {
}
}
}
+5 -5
View File
@@ -3,17 +3,17 @@
#include <glib.h>
#ifdef HAVE_ARM64
# define FRIDA_CGO_INIT_FUNC _rt0_arm64_windows_lib
# define FRIDA_CGO_INIT_FUNC _st0_arm64_windows_lib
#elif GLIB_SIZEOF_VOID_P == 8
# define FRIDA_CGO_INIT_FUNC _rt0_amd64_windows_lib
# define FRIDA_CGO_INIT_FUNC _st0_amd64_windows_lib
#else
# define FRIDA_CGO_INIT_FUNC rt0_386_windows_lib
# define FRIDA_CGO_INIT_FUNC st0_386_windows_lib
#endif
extern void FRIDA_CGO_INIT_FUNC ();
void
frida_compiler_backend_init (void)
_frida_compiler_backend_init_go_runtime (void)
{
FRIDA_CGO_INIT_FUNC ();
}
@@ -21,7 +21,7 @@ frida_compiler_backend_init (void)
#else
void
frida_compiler_backend_init (void)
_frida_compiler_backend_init_go_runtime (void)
{
}
+7 -7
View File
@@ -144,8 +144,8 @@ type BuildEndCallback func()
type BuildOutputCallback func(bundle string)
type BuildDiagnosticCallback func(d Diagnostic)
//export frida_compiler_backend_build
func frida_compiler_backend_build(cProjectRoot, cEntrypoint *C.char, outputFormat C.FridaOutputFormat, bundleFormat C.FridaBundleFormat,
//export _frida_compiler_backend_build
func _frida_compiler_backend_build(cProjectRoot, cEntrypoint *C.char, outputFormat C.FridaOutputFormat, bundleFormat C.FridaBundleFormat,
disableTypeCheck, sourceMap, compress uintptr,
onCompleteFn C.FridaBuildCompleteFunc, onCompleteData unsafe.Pointer, onCompleteDataDestroy C.FridaDestroyFunc,
onDiagnosticFn C.FridaDiagnosticFunc, onDiagnosticData unsafe.Pointer) {
@@ -179,8 +179,8 @@ func frida_compiler_backend_build(cProjectRoot, cEntrypoint *C.char, outputForma
}()
}
//export frida_compiler_backend_watch
func frida_compiler_backend_watch(cProjectRoot, cEntrypoint *C.char, outputFormat C.FridaOutputFormat, bundleFormat C.FridaBundleFormat,
//export _frida_compiler_backend_watch
func _frida_compiler_backend_watch(cProjectRoot, cEntrypoint *C.char, outputFormat C.FridaOutputFormat, bundleFormat C.FridaBundleFormat,
disableTypeCheck, sourceMap, compress uintptr,
onReadyFn C.FridaWatchReadyFunc, onReadyData unsafe.Pointer, onReadyDataDestroy C.FridaDestroyFunc,
onStartingFn C.FridaStartingFunc, onStartingData unsafe.Pointer,
@@ -238,8 +238,8 @@ func frida_compiler_backend_watch(cProjectRoot, cEntrypoint *C.char, outputForma
}()
}
//export frida_compiler_backend_watch_session_dispose
func frida_compiler_backend_watch_session_dispose(h uintptr) {
//export _frida_compiler_backend_watch_session_dispose
func _frida_compiler_backend_watch_session_dispose(h uintptr) {
handle := cgo.Handle(h)
session := handle.Value().(*WatchSession)
session.Dispose()
@@ -445,7 +445,7 @@ func makeContext(options BuildOptions, callbacks BuildEventCallbacks) (ctx esbui
Bundle: true,
Outdir: projectRoot,
AbsWorkingDir: projectRoot,
Platform: esbuild.PlatformNeutral,
Platform: esbuild.PlatformNode,
Format: format,
Inject: []string{"frida-builtins:///node-globals.js"},
EntryPoints: []string{entrypoint},
+7
View File
@@ -0,0 +1,7 @@
{
global:
_frida_compiler_backend_*;
local:
*;
};
+101 -38
View File
@@ -57,60 +57,123 @@ def build_backend(
run(npm, "install")
# run(npm, "link", "/home/oleavr/src/frida-fs")
backend_a = "frida-compiler-backend.a"
backend_h = "frida-compiler-backend.h"
mode = config["mode"]
backend_stem = "frida-compiler-backend"
if mode == "c-shared":
backend_stem += "-raw"
backend_a = priv_dir / f"{backend_stem}.a"
backend_shlib = priv_dir / (f"{backend_stem}" + config["shlib_suffix"])
backend_h = priv_dir / f"{backend_stem}.h"
extra_go_args = config["extra_go_args"].copy()
if mode == "c-shared":
version_script = priv_dir / "backend.version"
extra_go_args.append(f"-ldflags=-linkmode=external -extldflags=-Wl,--version-script={version_script}")
run(
go,
"build",
"-buildmode=c-archive",
f"-buildmode={mode}",
"-o",
backend_a,
backend_a.name if mode == "c-archive" else backend_shlib.name,
"-buildvcs=false",
*config["extra_go_args"],
*extra_go_args,
*go_sources,
)
if (mingw := config.get("mingw")) is not None and (abi := config["abi"]) in {
"x86",
"x86_64",
}:
prefix = Path(mingw["prefix"])
ar = Path(mingw["ar"])
if mode == "c-archive":
symbols_to_scramble = detect_conflictful_symbols_in_archive(backend_a, config["nm"])
scramble_symbols_in_archive(backend_a, symbols_to_scramble, config["ranlib"])
libmingwex_a = prefix / "lib" / "libmingwex.a"
if not libmingwex_a.exists():
libmingwex_a = prefix / mingw["triplet"] / "lib" / "libmingwex.a"
if (mingw := config.get("mingw")) is not None and (abi := config["abi"]) in {
"x86",
"x86_64",
}:
prefix = Path(mingw["prefix"])
ar = config["ar"]
libgcc_objects = [
"_chkstk_ms.o",
]
run(ar, "x", mingw["libcc"], *libgcc_objects)
libmingwex_a = prefix / "lib" / "libmingwex.a"
if not libmingwex_a.exists():
libmingwex_a = prefix / mingw["triplet"] / "lib" / "libmingwex.a"
gwex_objflavor = "64" if abi == "x86_64" else "32"
gwex_objects = [
f"lib{gwex_objflavor}_libmingwex_a-{name}.o"
for name in [
"dmisc",
"gdtoa",
"gmisc",
"mingw_fprintf",
"mingw_pformat",
"misc",
libgcc_objects = [
"_chkstk_ms.o",
]
]
run(ar, "x", libmingwex_a, *gwex_objects)
run(*ar, "x", mingw["libcc"], *libgcc_objects)
extra_objects = []
if abi == "x86_64":
run(ar, "x", backend_a, "go.o")
sort_pdata_in_object(Path(priv_dir) / "go.o")
extra_objects.append("go.o")
gwex_objflavor = "64" if abi == "x86_64" else "32"
gwex_objects = [
f"lib{gwex_objflavor}_libmingwex_a-{name}.o"
for name in [
"dmisc",
"gdtoa",
"gmisc",
"mingw_fprintf",
"mingw_pformat",
"misc",
]
]
run(*ar, "x", libmingwex_a, *gwex_objects)
run(ar, "rs", backend_a, *libgcc_objects, *gwex_objects, *extra_objects)
extra_objects = []
if abi == "x86_64":
run(*ar, "x", backend_a.name, "go.o")
sort_pdata_in_object(Path(priv_dir) / "go.o")
extra_objects.append("go.o")
shutil.copy(priv_dir / backend_a, output_dir / backend_a)
shutil.copy(priv_dir / backend_h, output_dir / backend_h)
run(*ar, "rs", backend_a.name, *libgcc_objects, *gwex_objects, *extra_objects)
shutil.copy(priv_dir / backend_a.name, output_dir / backend_a.name)
else:
shutil.copy(priv_dir / backend_shlib.name, output_dir / backend_shlib.name)
shutil.copy(priv_dir / backend_h.name, output_dir / backend_h.name)
def detect_conflictful_symbols_in_archive(
archive: Path, nm_cmd_array: List[str]
) -> List[str]:
result = []
for line in subprocess.run(
[*nm_cmd_array, str(archive)], capture_output=True, encoding="utf-8", check=True
).stdout.splitlines():
tokens = line.lstrip().split(" ")
if len(tokens) >= 3 and tokens[1] in {"S", "T"}:
symbol = tokens[2]
if all(sub not in symbol for sub in ("/", ".", ":", "frida")):
result.append(symbol)
return result
def scramble_symbols_in_archive(
archive: Path, symbols: List[str], ranlib_cmd_array: List[str]
):
data = archive.read_bytes()
for old_sym in symbols:
new_sym = roll_first_alpha(old_sym)
data = data.replace(old_sym.encode("ascii"), new_sym.encode("ascii"))
archive.write_bytes(data)
subprocess.run([*ranlib_cmd_array, str(archive)], check=True)
def roll_first_alpha(s: str) -> str:
chars = list(s)
for i, c in enumerate(chars):
if c.isalpha():
if c == "z":
chars[i] = "a"
elif c == "Z":
chars[i] = "A"
else:
chars[i] = chr(ord(c) + 1)
break
return "".join(chars)
# Work around the Go toolchain's almost-MSVC-compatible object files
+2
View File
@@ -0,0 +1,2 @@
[resource-compiler]
namespace = Frida.Data.Compiler
+81 -26
View File
@@ -29,6 +29,8 @@ namespace Frida {
public async string build (string entrypoint, BuildOptions? options = null, Cancellable? cancellable = null)
throws Error, IOError {
CompilerBackend.check_available ();
BuildOptions opts = (options != null) ? options : new BuildOptions ();
string project_root = compute_project_root (entrypoint, opts);
@@ -77,6 +79,8 @@ namespace Frida {
public async void watch (string entrypoint, WatchOptions? options = null, Cancellable? cancellable = null)
throws Error, IOError {
CompilerBackend.check_available ();
WatchOptions opts = (options != null) ? options : new WatchOptions ();
string project_root = compute_project_root (entrypoint, opts);
@@ -227,40 +231,82 @@ namespace Frida {
}
namespace CompilerBackend {
private extern void init ();
private void init () {
#if HAVE_COMPILER_BACKEND
private extern void build (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);
private extern void watch (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);
namespace WatchSession {
private extern void dispose (size_t handle);
}
#if COMPILER_BACKEND_STATIC_COMPILATION
_init_go_runtime ();
build = (BuildFunc) _build;
watch = (WatchFunc) _watch;
WatchSession.dispose = (WatchSession.DisposeFunc) WatchSession._dispose;
#else
private const string DISABLED_MESSAGE = "Compiler backend disabled at build-time";
unowned uint8[] backend_so = Frida.Data.Compiler.get_frida_compiler_backend_so_blob ().data;
private void build (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) {
on_complete (null, DISABLED_MESSAGE);
}
FileDescriptor fd;
if (MemoryFileDescriptor.is_supported ()) {
fd = MemoryFileDescriptor.from_bytes ("frida-compiler-backend.so", new Bytes.static (backend_so));
} else {
string name_used;
try {
fd = new FileDescriptor (FileUtils.open_tmp ("frida-compiler-backend-XXXXXX.so", out name_used));
FileUtils.unlink (name_used);
private void watch (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) {
on_ready (0, DISABLED_MESSAGE);
}
var output = new UnixOutputStream (fd.handle, false);
output.write_all (backend_so, null);
namespace WatchSession {
private void dispose (size_t handle) {
Posix.lseek (fd.handle, 0, Posix.SEEK_SET);
} catch (GLib.Error e) {
assert_not_reached ();
}
}
Module backend;
try {
backend = new Module ("/proc/self/fd/%d".printf (fd.handle), LOCAL);
} catch (ModuleError e) {
assert_not_reached ();
}
}
build = resolve_symbol (backend, "_frida_compiler_backend_build");
watch = resolve_symbol (backend, "_frida_compiler_backend_watch");
WatchSession.dispose = resolve_symbol (backend, "_frida_compiler_backend_watch_session_dispose");
#endif
#endif
}
private void check_available () throws Error {
if (build == null)
throw new Error.NOT_SUPPORTED ("Compiler backend disabled at build-time");
}
private BuildFunc? build;
private WatchFunc? watch;
[CCode (has_target = false)]
private delegate void BuildFunc (string project_root, string entrypoint, OutputFormat output_format,
BundleFormat bundle_format, size_t disable_type_check, size_t source_map, size_t compress,
owned BuildCompleteFunc on_complete, DiagnosticFunc on_diagnostic);
[CCode (has_target = false)]
private delegate void WatchFunc (string project_root, string entrypoint, OutputFormat output_format,
BundleFormat bundle_format, size_t disable_type_check, size_t source_map, size_t compress,
owned WatchReadyFunc on_ready, StartingFunc on_starting, FinishedFunc on_finished, OutputFunc on_output,
DiagnosticFunc on_diagnostic);
#if COMPILER_BACKEND_STATIC_COMPILATION
private extern void _init_go_runtime ();
private extern void _build ();
private extern void _watch ();
#endif
namespace WatchSession {
[CCode (has_target = false)]
private delegate void DisposeFunc (size_t handle);
private DisposeFunc? dispose;
#if COMPILER_BACKEND_STATIC_COMPILATION
private extern void _dispose ();
#endif
}
private delegate void BuildCompleteFunc (owned string? bundle, owned string? error_message);
private delegate void WatchReadyFunc (size_t session_handle, owned string? error_message);
@@ -269,6 +315,15 @@ namespace Frida {
private delegate void OutputFunc (owned string bundle);
private delegate void DiagnosticFunc (owned string category, int code, owned string? path, int line, int character,
owned string text);
#if HAVE_COMPILER_BACKEND && !COMPILER_BACKEND_STATIC_COMPILATION
private static T resolve_symbol<T> (Module m, string name) {
void * address;
if (!m.symbol (name, out address))
assert_not_reached ();
return (T) address;
}
#endif
}
private string compute_project_root (string entrypoint, CompilerOptions options) {
+33 -2
View File
@@ -9,6 +9,7 @@ if have_compiler_backend
'go.mod',
'go.sum',
'backend.go',
'backend.version',
'tscompiler.go',
'tsconfig.go',
'shims.go',
@@ -16,7 +17,7 @@ if have_compiler_backend
'package-lock.json',
],
output: [
'frida-compiler-backend.a',
'frida-compiler-backend' + (compiler_backend_static_compilation ? '.a' : ('-raw' + shlib_suffix)),
'frida-compiler-backend.h',
],
command: [
@@ -30,5 +31,35 @@ if have_compiler_backend
'@INPUT@',
],
)
backend_libs += compiler_backend[0]
if compiler_backend_static_compilation
backend_libs += compiler_backend[0]
else
filename = 'frida-compiler-backend' + shlib_suffix
identity = (host_os_family == 'darwin') ? 'FridaCompilerBackend' : filename
compiler_backend_shlib = custom_target('frida-compiler-backend-shlib',
input: compiler_backend[0],
output: filename,
command: post_process + ['shared-library', identity, 'elf-cleaner:off'],
)
compiler_data = custom_target('frida-data-compiler',
input: [
'compiler.resources',
compiler_backend_shlib,
],
output: [
'frida-data-compiler.vapi',
'frida-data-compiler.h',
'frida-data-compiler.c',
'frida-data-compiler-blob' + resource_blob_extension,
],
command: [
resource_compiler_cmd_array,
'-c', '@INPUT0@',
'-o', meson.current_build_dir() / 'frida-data-compiler',
'@INPUT1@',
],
)
backend_sources += compiler_data
endif
endif
+31 -1494
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -14,7 +14,7 @@
"@frida/http-parser-js": "^1.0.0",
"@frida/https": "^1.0.0",
"@frida/ieee754": "^2.0.2",
"@frida/net": "^4.0.2",
"@frida/net": "^5.0.0",
"@frida/os": "^1.0.2",
"@frida/path": "^2.0.3",
"@frida/process": "^1.2.1",
+1
View File
@@ -18,6 +18,7 @@ export { default as process } from 'node:process';
//go:embed node_modules/@frida/*/package.json
//go:embed node_modules/@frida/*/*.js
//go:embed node_modules/@frida/*/*/*.js
//go:embed node_modules/@frida/*/*/*/*.js
//go:embed node_modules/frida-fs/package.json
//go:embed node_modules/frida-fs/*/*.js
var embeddedShims embed.FS
+4 -4
View File
@@ -8,7 +8,7 @@
"name": "frida-osanalytics-agent",
"version": "1.0.0",
"dependencies": {
"frida-objc-bridge": "^8.0.4"
"frida-objc-bridge": "^8.0.5"
},
"devDependencies": {
"esbuild": "^0.25.5"
@@ -481,9 +481,9 @@
}
},
"node_modules/frida-objc-bridge": {
"version": "8.0.4",
"resolved": "https://registry.npmjs.org/frida-objc-bridge/-/frida-objc-bridge-8.0.4.tgz",
"integrity": "sha512-AUzwq/+TFtblQLTI97UPX22pBcvyG2oUde9380DXbcJ0zXts4n9JDVONHUr03aBowa0Le+bdBoVdCs7jyyjvlg==",
"version": "8.0.5",
"resolved": "https://registry.npmjs.org/frida-objc-bridge/-/frida-objc-bridge-8.0.5.tgz",
"integrity": "sha512-0xnL0VgxSQXgLj3S33S0kdAvLrCHSCIZb9HVraEgEyKnf9wOcu0KZ9fI5xzx0e0y+ry/g2Vl3yw9j3dsn92Ffg==",
"license": "LGPL-2.0 WITH WxWindows-exception-3.1"
}
}
+2 -2
View File
@@ -4,12 +4,12 @@
"description": "Agent used by Frida's Darwin backend on iOS/iPadOS/tvOS",
"type": "module",
"scripts": {
"build": "esbuild index.js --outfile=osanalytics.js --bundle --platform=neutral --target=es2022 --minify"
"build": "esbuild index.js --outfile=osanalytics.js --bundle --platform=node --target=es2022 --minify"
},
"devDependencies": {
"esbuild": "^0.25.5"
},
"dependencies": {
"frida-objc-bridge": "^8.0.4"
"frida-objc-bridge": "^8.0.5"
}
}
+4 -4
View File
@@ -8,7 +8,7 @@
"name": "frida-reportcrash-agent",
"version": "1.0.0",
"dependencies": {
"frida-objc-bridge": "^8.0.4"
"frida-objc-bridge": "^8.0.5"
},
"devDependencies": {
"esbuild": "^0.25.5"
@@ -481,9 +481,9 @@
}
},
"node_modules/frida-objc-bridge": {
"version": "8.0.4",
"resolved": "https://registry.npmjs.org/frida-objc-bridge/-/frida-objc-bridge-8.0.4.tgz",
"integrity": "sha512-AUzwq/+TFtblQLTI97UPX22pBcvyG2oUde9380DXbcJ0zXts4n9JDVONHUr03aBowa0Le+bdBoVdCs7jyyjvlg==",
"version": "8.0.5",
"resolved": "https://registry.npmjs.org/frida-objc-bridge/-/frida-objc-bridge-8.0.5.tgz",
"integrity": "sha512-0xnL0VgxSQXgLj3S33S0kdAvLrCHSCIZb9HVraEgEyKnf9wOcu0KZ9fI5xzx0e0y+ry/g2Vl3yw9j3dsn92Ffg==",
"license": "LGPL-2.0 WITH WxWindows-exception-3.1"
}
}
+2 -2
View File
@@ -4,12 +4,12 @@
"description": "Agent used by Frida's Darwin backend on iOS/iPadOS/tvOS",
"type": "module",
"scripts": {
"build": "esbuild index.js --outfile=reportcrash.js --bundle --platform=neutral --target=es2022 --minify"
"build": "esbuild index.js --outfile=reportcrash.js --bundle --platform=node --target=es2022 --minify"
},
"devDependencies": {
"esbuild": "^0.25.5"
},
"dependencies": {
"frida-objc-bridge": "^8.0.4"
"frida-objc-bridge": "^8.0.5"
}
}
+11 -1
View File
@@ -454,7 +454,7 @@ namespace Frida.Fruity {
write_entry (entry);
size_t offset_table_offset = (size_t) seekable.tell ();
offset_size = compute_offset_size (sorted_entries.last ().offset);
offset_size = compute_offset_size (offset_table_offset);
foreach (var entry in sorted_entries)
write_offset (entry.offset);
@@ -1088,6 +1088,11 @@ namespace Frida.Fruity {
}
public void write_dict (PlistDict dict) {
if (dict.is_empty) {
write_line ("<dict/>");
return;
}
write_line ("<dict>");
level++;
@@ -1114,6 +1119,11 @@ namespace Frida.Fruity {
}
public void write_array (PlistArray array) {
if (array.is_empty) {
write_line ("<array/>");
return;
}
write_line ("<array>");
level++;
+1 -1
View File
@@ -9,7 +9,7 @@ esbuild.build({
entryPoints: ['index.js'],
outfile: 'system-server.js',
bundle: true,
platform: 'neutral',
platform: 'node',
target: ['es2022'],
legalComments: 'none',
minify: true,
+4 -4
View File
@@ -9,7 +9,7 @@
"version": "1.0.0",
"dependencies": {
"@frida/buffer": "^7.0.4",
"frida-java-bridge": "^7.0.1"
"frida-java-bridge": "^7.0.4"
},
"devDependencies": {
"esbuild": "^0.25.5",
@@ -534,9 +534,9 @@
"license": "MIT"
},
"node_modules/frida-java-bridge": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/frida-java-bridge/-/frida-java-bridge-7.0.1.tgz",
"integrity": "sha512-pyNv12Y+erFgqdbFMsECh1OfqS77E62GeKHtxaBOZUPSpqcEkL0T2/6q/XD2161S4eGYBn6V7zumH2gbxtXK/Q==",
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/frida-java-bridge/-/frida-java-bridge-7.0.4.tgz",
"integrity": "sha512-dE5XCvasUwA/wiVb5gSwBPf6dortI8VtD0qLlw2T0ryqX/0lg4BEtEkg1oRr9IlHDVBTjPOqe9KRzdPar8U3EQ==",
"license": "LGPL-2.0 WITH WxWindows-exception-3.1"
},
"node_modules/ieee754": {
+1 -1
View File
@@ -12,6 +12,6 @@
},
"dependencies": {
"@frida/buffer": "^7.0.4",
"frida-java-bridge": "^7.0.1"
"frida-java-bridge": "^7.0.4"
}
}
-105
View File
@@ -3167,114 +3167,9 @@ namespace Frida {
return Linux.syscall (SysCall.tgkill, tgid, tid, sig);
}
private uint linux_major = 0;
private uint linux_minor = 0;
public bool check_kernel_version (uint major, uint minor) {
if (linux_major == 0) {
var name = Posix.utsname ();
name.release.scanf ("%u.%u", out linux_major, out linux_minor);
}
return (linux_major == major && linux_minor >= minor) || linux_major > major;
}
public extern bool _syscall_satisfies (int syscall_id, LinuxSyscall mask);
public class FileDescriptor : Object, FileDescriptorBased {
public int handle;
public FileDescriptor (int handle) {
this.handle = handle;
}
~FileDescriptor () {
if (handle != -1)
Posix.close (handle);
}
public int steal () {
int result = handle;
handle = -1;
return result;
}
public int get_fd () {
return handle;
}
}
public sealed class PidFileDescriptor : FileDescriptor {
private uint pid;
private PidFileDescriptor (int fd, uint pid) {
base (fd);
this.pid = pid;
}
public static bool is_supported () {
return check_kernel_version (5, 3);
}
public static bool getfd_is_supported () {
return check_kernel_version (5, 6);
}
public static PidFileDescriptor from_pid (uint pid) throws Error {
int fd = pidfd_open (pid, 0);
if (fd == -1)
throw_pidfd_error (pid, errno);
return new PidFileDescriptor (fd, pid);
}
public FileDescriptor getfd (int targetfd) throws Error {
int fd = pidfd_getfd (handle, targetfd, 0);
if (fd == -1)
throw_pidfd_error (pid, errno);
return new FileDescriptor (fd);
}
private static int pidfd_open (uint pid, uint flags) {
return Linux.syscall (SysCall.pidfd_open, pid, flags);
}
private static int pidfd_getfd (int pidfd, int targetfd, uint flags) {
return Linux.syscall (SysCall.pidfd_getfd, pidfd, targetfd, flags);
}
[NoReturn]
private static void throw_pidfd_error (uint pid, int err) throws Error {
switch (err) {
case Posix.ESRCH:
throw new Error.PROCESS_NOT_FOUND ("Process not found");
case Posix.EPERM:
throw new Error.PERMISSION_DENIED ("Unable to use pidfd for pid %u: %s", pid, strerror (err));
default:
throw new Error.NOT_SUPPORTED ("Unable to use pidfd for pid %u: %s", pid, strerror (err));
}
}
}
namespace MemoryFileDescriptor {
public bool is_supported () {
return check_kernel_version (3, 17);
}
public static FileDescriptor from_bytes (string name, Bytes bytes) {
assert (is_supported ());
var fd = new FileDescriptor (memfd_create (name, 0));
unowned uint8[] data = bytes.get_data ();
ssize_t n = Posix.write (fd.handle, data, data.length);
assert (n == data.length);
return fd;
}
private int memfd_create (string name, uint flags) {
return Linux.syscall (SysCall.memfd_create, name, flags);
}
}
private void make_pty (out FileDescriptor read, out FileDescriptor write) throws Error {
#if HAVE_OPENPTY
int rfd = -1, wfd = -1;
-6
View File
@@ -84,12 +84,6 @@ build_arch () {
export CC="gcc -m32" CXX="g++ -m32" STRIP="strip"
fi
case "$ARCH" in
armbe8 | arm64be | arm64beilp32)
EXTRA_FLAGS+=("--without-prebuilds=sdk:host")
;;
esac
cd "$FRIDA_CORE_DIR"
rm -rf "$BUILD_DIR"
+3 -3
View File
@@ -1,6 +1,7 @@
base_sources = [
'frida.vala',
'frida-glue.c',
'package-manager.vala',
'control-service.vala',
'portal-service.vala',
'host-session-service.vala',
@@ -364,16 +365,14 @@ if have_local_backend
helper_backend_vala_args = [
base_vala_args,
gum_vala_args,
'--pkg=gio-unix-2.0',
'--pkg=posix',
]
helper_backend = static_library('frida-helper-backend', helper_backend_sources,
c_args: frida_component_cflags,
vala_args: [
helper_backend_vala_args,
'--vapidir=' + meson.current_source_dir() / 'linux',
'--pkg=frida-sysapi',
'--pkg=linux',
'--pkg=linux-system',
'--pkg=frida-gum-linux-1.0',
],
dependencies: [gio_dep, gio_unix_dep, gee_dep, gum_dep, base_dep] + helper_backend_extra_deps,
@@ -634,6 +633,7 @@ core = library('frida-core', core_sources,
base_vala_args,
gumjs_inspector_vala_args,
'--pkg=gmodule-2.0',
'--pkg=libsoup-3.0',
],
vala_gir: core_gir_name,
link_args: backend_libs_private,
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -1,6 +1,6 @@
[wrap-git]
url = https://github.com/frida/frida-gum.git
revision = 17.1.2
revision = 17.2.3
depth = 1
[provide]
-6
View File
@@ -77,12 +77,6 @@ build_arch () {
export CC="gcc -m32" CXX="g++ -m32" STRIP="strip"
fi
case "$ARCH" in
armbe8 | arm64be | arm64beilp32)
EXTRA_FLAGS+=("--without-prebuilds=sdk:host")
;;
esac
cd "$FRIDA_CORE_DIR"
rm -rf "$BUILD_DIR"
+4
View File
@@ -9,6 +9,10 @@ test_sources = [
'process-resource-usage.c',
]
if host_os_family == 'darwin'
test_sources += 'test-host-session-darwin-glue.m'
endif
test_vala_args = []
test_depends = []
+83
View File
@@ -0,0 +1,83 @@
#import <Foundation/Foundation.h>
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
static id frida_parse_plist (const uint8_t * data, int length, char ** error_message);
uint8_t *
frida_host_session_test_fruity_plist_to_binary_using_apple_implementation (const uint8_t * data, int length, char ** error_message,
int * output_length)
{
@autoreleasepool
{
uint8_t * result;
id plist;
NSData * bplist;
size_t len;
*error_message = NULL;
*output_length = 0;
plist = frida_parse_plist (data, length, error_message);
if (plist == nil)
return NULL;
bplist = [NSPropertyListSerialization dataWithPropertyList:plist
format:NSPropertyListBinaryFormat_v1_0
options:0
error:nil];
len = [bplist length];
result = malloc (len);
memcpy (result, [bplist bytes], len);
*output_length = (int) len;
return result;
}
}
char *
frida_host_session_test_fruity_plist_to_xml_using_apple_implementation (const uint8_t * data, int length, char ** error_message)
{
@autoreleasepool
{
id plist;
NSData * xml;
*error_message = NULL;
plist = frida_parse_plist (data, length, error_message);
if (plist == nil)
return NULL;
xml = [NSPropertyListSerialization dataWithPropertyList:plist
format:NSPropertyListXMLFormat_v1_0
options:0
error:nil];
return strndup ([xml bytes], [xml length]);
}
}
static id
frida_parse_plist (const uint8_t * data, int length, char ** error_message)
{
id plist;
NSData * input;
NSPropertyListFormat format;
NSError * error = nil;
input = [NSData dataWithBytes:data length:(NSUInteger) length];
plist = [NSPropertyListSerialization propertyListWithData:input
options:NSPropertyListImmutable
format:&format
error:&error];
if (error != nil)
*error_message = strdup ([[error localizedDescription] UTF8String]);
return plist;
}
+67 -1
View File
@@ -46,6 +46,12 @@ namespace Frida.HostSessionTest {
Fruity.Plist.to_xml_yields_complete_document ();
});
#if DARWIN
GLib.Test.add_func ("/HostSession/Fruity/Plist/output-matches-apple-implementation", () => {
Fruity.Plist.output_matches_apple_implementation ();
});
#endif
GLib.Test.add_func ("/HostSession/Fruity/backend", () => {
var h = new Harness ((h) => Fruity.backend.begin (h as Harness));
h.run ();
@@ -1551,7 +1557,7 @@ namespace Frida.HostSessionTest {
private static async void spawn (Harness h) {
if (!GLib.Test.slow () && (
Frida.Test.os () == Frida.Test.OS.ANDROID ||
Frida.Test.os_arch_suffix () == "-linux-arm" ||
Frida.Test.os_arch_suffix () == "-linux-armbe8" ||
Frida.Test.os_arch_suffix () == "-linux-arm64be"
)) {
stdout.printf ("<skipping, run in slow mode> ");
@@ -4059,6 +4065,66 @@ namespace Frida.HostSessionTest {
assert_true (actual_xml == expected_xml);
}
#if DARWIN
private static void output_matches_apple_implementation () {
var request = new Frida.Fruity.Plist ();
request.set_string ("Command", "Lookup");
var options = new Frida.Fruity.PlistDict ();
request.set_dict ("ClientOptions", options);
var attributes = new Frida.Fruity.PlistArray ();
options.set_array ("ReturnAttributes", attributes);
attributes.add_string ("ApplicationType");
attributes.add_string ("IsAppClip");
attributes.add_string ("SBAppTags");
attributes.add_string ("CFBundleIdentifier");
attributes.add_string ("CFBundleDisplayName");
attributes.add_string ("CFBundleShortVersionString");
attributes.add_string ("CFBundleVersion");
attributes.add_string ("Path");
attributes.add_string ("Container");
attributes.add_string ("GroupContainers");
attributes.add_string ("Entitlements");
var ids = new Frida.Fruity.PlistArray ();
options.set_array ("BundleIDs", ids);
ids.add_string ("UUU");
string? error_message;
string our_xml = request.to_xml ();
uint8[] our_bplist = request.to_binary ();
uint8[]? apple_bplist = to_binary_using_apple_implementation (our_xml.data, out error_message);
if (error_message != null)
printerr ("Oops: %s\n", error_message);
assert_nonnull (apple_bplist);
assert_null (error_message);
/*
try {
var home_dir = Environment.get_home_dir ();
FileUtils.set_data (Path.build_filename (home_dir, "frida-test-apple.plist"), apple_bplist);
FileUtils.set_data (Path.build_filename (home_dir, "frida-test-our.plist"), our_bplist);
} catch (FileError e) {
assert_not_reached ();
}
*/
string? apple_xml = to_xml_using_apple_implementation (our_bplist, out error_message);
if (error_message != null)
printerr ("Oops: %s\n", error_message);
assert_nonnull (apple_xml);
assert_null (error_message);
assert_cmpstr (our_xml, EQ, apple_xml);
assert_cmpstr (Base64.encode (our_bplist), EQ, Base64.encode (apple_bplist));
}
private extern uint8[]? to_binary_using_apple_implementation (uint8[] data, out string? error_message);
private extern string? to_xml_using_apple_implementation (uint8[] data, out string? error_message);
#endif
}
}
+42 -13
View File
@@ -18,7 +18,6 @@ if platform.system() == "Windows":
FRIDA_OS_TO_GO_OS = {
"android": "linux", # XXX: Work around lack of support for -buildmode=c-archive
"macos": "darwin",
}
@@ -53,14 +52,27 @@ def main(argv: List[str]):
go = Path(args.pop(0))
host_os = args.pop(0)
host_abi = args.pop(0)
shlib_suffix = args.pop(0)
cc_id = args.pop(0)
cc_cmd_array = pop_cmd_array_arg(args)
ar_cmd_array = pop_cmd_array_arg(args)
nm_cmd_array = pop_cmd_array_arg(args)
ranlib_cmd_array = pop_cmd_array_arg(args)
try:
config = detect_config(go, host_os, host_abi, cc_id, cc_cmd_array, ar_cmd_array)
config = detect_config(
go,
host_os,
host_abi,
shlib_suffix,
cc_id,
cc_cmd_array,
ar_cmd_array,
nm_cmd_array,
ranlib_cmd_array,
)
print("ok")
print(base64.b64encode(json.dumps(config).encode("utf-8")).decode("ascii"))
print(config["mode"], base64.b64encode(json.dumps(config).encode("utf-8")).decode("ascii"))
except Exception as e:
print("error")
print(str(e).replace("\n", "\\n"))
@@ -84,9 +96,12 @@ def detect_config(
go: Path,
host_os: str,
host_abi: str,
shlib_suffix: str,
cc_id: str,
cc_cmd_array: List[str],
ar_cmd_array: Optional[List[str]],
nm_cmd_array: Optional[List[str]],
ranlib_cmd_array: Optional[List[str]],
) -> dict:
source_root = Path(os.environ["MESON_SOURCE_ROOT"])
build_root = Path(os.environ["MESON_BUILD_ROOT"])
@@ -111,27 +126,23 @@ def detect_config(
"prefix": str(toolchain.prefix),
"bindir": str(toolchain.bindir),
"cc": str(toolchain.cc),
"ar": str(toolchain.ar),
"libcc": str(toolchain.libcc),
}
env["CC"] = str(toolchain.cc)
env["PATH"] = str(toolchain.cc.parent) + ";" + env["PATH"]
ar = str(toolchain.ar)
ar_cmd_array = [str(toolchain.ar)]
nm_cmd_array = [str(toolchain.nm)]
ranlib_cmd_array = [str(toolchain.ranlib)]
else:
env["CC"] = shlex.join(
[arg for arg in cc_cmd_array if MACHINE_FLAG_PATTERN.fullmatch(arg) is None]
)
ar = ar_cmd_array[0]
extra_go_args.append(f"-ldflags=-extar={ar}")
extra_go_args.append(f"-ldflags=-extar={ar_cmd_array[0]}")
if host_os == "macos":
extra_go_args.append("-ldflags=-extldflags=-mmacosx-version-min=11.0")
env["MACOSX_DEPLOYMENT_TARGET"] = "11.0"
if host_os == "android":
# XXX: Avoid socklen_t compatibility issue caused by us using GOOS=linux for Android
extra_go_args += ["-tags", "netgo"]
def run(*args):
return subprocess.run(
args,
@@ -152,16 +163,23 @@ def detect_config(
env["GOOS"] = goos
env["GOARCH"] = goarch
mode = "c-shared" if host_os == "android" else "c-archive"
try:
run(go, "build", "-buildmode=c-archive", "-o", "cgotest.a", "-buildvcs=false")
run(go, "build", f"-buildmode={mode}", "-o", "cgotest.a", "-buildvcs=false")
except subprocess.CalledProcessError as e:
raise BuildError(e.output.strip())
config = {
"mode": mode,
"os": host_os,
"abi": host_abi,
"shlib_suffix": shlib_suffix,
"extra_go_args": extra_go_args,
"env": env,
"ar": ar_cmd_array,
"nm": nm_cmd_array,
"ranlib": ranlib_cmd_array,
}
if mingw is not None:
config["mingw"] = mingw
@@ -183,6 +201,8 @@ class MinGWToolchain:
bindir: Path
cc: Path
ar: Path
nm: Path
ranlib: Path
libcc: Path
@staticmethod
@@ -254,6 +274,8 @@ class MinGWToolchain:
)
ar_path = cc_path.parent / "ar.exe"
nm_path = cc_path.parent / "nm.exe"
ranlib_path = cc_path.parent / "ranlib.exe"
try:
libcc_name = query_cc("-print-libgcc-file-name")
@@ -264,7 +286,14 @@ class MinGWToolchain:
libcc_path = Path(libcc_name).resolve()
return MinGWToolchain(
triplet, mingw_prefix, mingw_bindir, cc_path, ar_path, libcc_path
triplet,
mingw_prefix,
mingw_bindir,
cc_path,
ar_path,
nm_path,
ranlib_path,
libcc_path,
)
+2 -1
View File
@@ -23,6 +23,7 @@ def main(argv):
input_entitlements_path = args.pop(0) if args else None
else:
input_entitlements_path = None
flags = set(args.pop(0).split("|") if args else [])
is_apple_os = host_os in {"macos", "ios", "watchos", "tvos"}
@@ -62,7 +63,7 @@ def main(argv):
codesign_args += ["--entitlements", input_entitlements_path]
subprocess.run(codesign + codesign_args + [intermediate_path], **run_kwargs)
if host_os == "android":
if host_os == "android" and "elf-cleaner:off" not in flags:
api_level = 19 if host_abi in {"x86", "arm"} else 21
subprocess.run(termux_elf_cleaner + ["--api-level", str(api_level), "--quiet", intermediate_path],
**run_kwargs)