Compare commits

...
33 Commits
Author SHA1 Message Date
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
33 changed files with 2521 additions and 1583 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
View File
@@ -9,6 +9,7 @@ base_sources = [
'p2p-glue.c',
'dbus.vala',
'promise.vala',
'fs.vala',
'socket.vala',
'socket-glue.c',
'buffer.vala',
+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,
+9 -4
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'
@@ -424,6 +426,8 @@ if compiler_backend_opt.allowed()
cc.get_id(),
'>>>', cc.cmd_array(), '<<<',
'>>>', ar, '<<<',
'>>>', nm, '<<<',
'>>>', ranlib, '<<<',
],
capture: true,
check: true
@@ -729,14 +733,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')
+38 -4
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 \
@@ -489,6 +521,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) {
}
}
}
+3 -3
View File
@@ -3,11 +3,11 @@
#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 ();
+1 -1
View File
@@ -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},
+56 -10
View File
@@ -57,26 +57,29 @@ 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"
backend_a = priv_dir / "frida-compiler-backend.a"
backend_h = priv_dir / "frida-compiler-backend.h"
run(
go,
"build",
"-buildmode=c-archive",
"-o",
backend_a,
backend_a.name,
"-buildvcs=false",
*config["extra_go_args"],
*go_sources,
)
symbols_to_scramble = detect_conflictful_symbols_in_archive(backend_a, config["nm"])
scramble_symbols_in_archive(backend_a, symbols_to_scramble, config["ranlib"])
if (mingw := config.get("mingw")) is not None and (abi := config["abi"]) in {
"x86",
"x86_64",
}:
prefix = Path(mingw["prefix"])
ar = Path(mingw["ar"])
ar = config["ar"]
libmingwex_a = prefix / "lib" / "libmingwex.a"
if not libmingwex_a.exists():
@@ -85,7 +88,7 @@ def build_backend(
libgcc_objects = [
"_chkstk_ms.o",
]
run(ar, "x", mingw["libcc"], *libgcc_objects)
run(*ar, "x", mingw["libcc"], *libgcc_objects)
gwex_objflavor = "64" if abi == "x86_64" else "32"
gwex_objects = [
@@ -99,18 +102,61 @@ def build_backend(
"misc",
]
]
run(ar, "x", libmingwex_a, *gwex_objects)
run(*ar, "x", libmingwex_a, *gwex_objects)
extra_objects = []
if abi == "x86_64":
run(ar, "x", backend_a, "go.o")
run(*ar, "x", backend_a.name, "go.o")
sort_pdata_in_object(Path(priv_dir) / "go.o")
extra_objects.append("go.o")
run(ar, "rs", backend_a, *libgcc_objects, *gwex_objects, *extra_objects)
run(*ar, "rs", backend_a.name, *libgcc_objects, *gwex_objects, *extra_objects)
shutil.copy(priv_dir / backend_a, output_dir / backend_a)
shutil.copy(priv_dir / backend_h, output_dir / backend_h)
shutil.copy(priv_dir / backend_a.name, output_dir / backend_a.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
+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"
}
}
-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"
+1
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',
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.0
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
}
}
+33 -6
View File
@@ -56,9 +56,20 @@ def main(argv: List[str]):
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,
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"))
except Exception as e:
@@ -87,6 +98,8 @@ def detect_config(
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,18 +124,18 @@ 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")
@@ -162,6 +175,9 @@ def detect_config(
"abi": host_abi,
"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 +199,8 @@ class MinGWToolchain:
bindir: Path
cc: Path
ar: Path
nm: Path
ranlib: Path
libcc: Path
@staticmethod
@@ -254,6 +272,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 +284,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,
)