Compare commits

...
77 Commits
Author SHA1 Message Date
Ole André Vadla Ravnås 1bdf9a2fd3 android: Implement sigchain logic when needed 2026-03-09 11:41:15 +01:00
Ole André Vadla Ravnås d5d500be3a subprojects: Prepare for release 2026-03-08 20:35:38 +01:00
Ole André Vadla Ravnås 6a1aa42685 subprojects: Bump outdated 2026-03-08 19:44:01 +01:00
Ole André Vadla Ravnås 2f75c98c0c syscall-tracer: Make eBPF more verifier-friendly 2026-03-08 18:50:15 +01:00
Ole André Vadla Ravnås c50c6cc6dc linux: Bump BpfObject log buffer size to 128 KiB 2026-03-08 18:49:33 +01:00
Ole André Vadla Ravnås 34742d09c3 android: Use in-process helper everywhere
Even as far back as API level 19.
2026-03-08 17:24:05 +01:00
Ole André Vadla Ravnås b08453341d atomics: Fix -Watomic-alignment warnings
Clang may warn that 64-bit atomic operations are misaligned when guint64
only has 4-byte alignment on the target ABI.

Use an explicitly 8-byte aligned typedef for the atomic helpers and
update the Vala bindings to use typed pointers instead of void *.
2026-03-08 17:05:51 +01:00
Ole André Vadla Ravnås cd9c2183ce android: Support in-process helper on Nougat
And potentially even older OSes.

This brings us another step closer to using in-process everywhere.
2026-03-08 12:27:48 +01:00
Ole André Vadla Ravnås 35bb528992 android: Fix in-process helper on older ARTs
Where ART expects the main executable to export certain symbols. We work
around this by replacing the crashing stubs with a function that does
nothing.
2026-03-08 11:21:16 +01:00
Ole André Vadla Ravnås e3a4a031f8 tests: Fix the icon width/height checks 2026-03-08 00:13:06 +01:00
Ole André Vadla Ravnås e9083013a8 subprojects: Bump outdated 2026-03-07 23:51:36 +01:00
Ole André Vadla Ravnås 1105d0d45d droidy: Port to the new AndroidHelperClient API 2026-03-07 23:45:37 +01:00
Ole André Vadla Ravnås 0f5153a5d0 compiler: Bump @types/frida-gum to 19.0.2 2026-03-07 23:37:23 +01:00
Ole André Vadla Ravnås 23f288c5e5 android: Run android-helper in-process if possible
We only try to do this on modern systems, as older versions of ART
require the main executable to export certain symbols. That precludes
usage in scenarios where frida-core is embedded, e.g. like in r2frida.
2026-03-07 22:36:48 +01:00
Ole André Vadla Ravnås e25b4debac base: Add missing G_{BEGIN,END}_DECLS to headers 2026-03-07 21:54:55 +01:00
Ole André Vadla Ravnås e5e3033415 libc-shim: Omit fseeko64 and ftello64 on QNX
They're implicitly defined.
2026-03-03 21:50:37 +01:00
Ole André Vadla Ravnås 719c0c1161 meson: Ensure libc is defined for non-Linux too 2026-03-03 21:36:48 +01:00
Dep c899e04a9c android-helper: Fix crash on Transsion ROMs
Fix a NullPointerException when the android-helper initializes on
Infinix and other Transsion OS devices.

Their modified ActivityThread expects a fully initialized main
looper. Using Looper.prepare() causes a crash in android.os.Handler
before initialization completes.

Use Looper.prepareMainLooper() instead so the expected main looper
is available.

Verified on a rooted Infinix device by compiling the .dex and
running it via app_process.
2026-03-03 21:33:33 +01:00
Alexander Hude 575161cad7 darwin: Fix early instrumentation on iOS 26.4
In iOS 26.4, Apple changed the signature of restartWithDyldInCache,
which broke the existing detection logic.

Generalize the logic instead of relying on another specific symbol.
2026-03-03 21:26:43 +01:00
Ole André Vadla Ravnås a05633f683 linux: Fix the helpers host_machine auto-detection 2026-03-03 21:23:07 +01:00
Ole André Vadla Ravnås 6053f4eb84 linux: Update helpers/rebuild.sh to match Makefile 2026-03-03 21:22:28 +01:00
Ole André Vadla Ravnås 0753bcf4b8 gadget: Only use versioned stdio symbols on glibc 2026-03-03 21:14:18 +01:00
Ole André Vadla Ravnås a66dff2d71 agent: Only use versioned stdio symbols on glibc 2026-03-03 21:13:43 +01:00
Ole André Vadla Ravnås f0fd7aef7b libc-shim: Plug some more holes in the stdio API
- fseeko, fseeko64
- ftello, ftello64
2026-03-03 19:36:42 +01:00
Ole André Vadla Ravnås 41e02684f3 libc-shim: Version fopen/fopen64 for libstdc++
Static libstdc++ introduces references to fopen@GLIBC_2.2.5 and
fopen64@GLIBC_2.2.5.

Provide matching versioned symbols from the libc shim and define a
GLIBC_2.2.5 node in the embedding version scripts so these bind to the
shim instead of glibc in both agent and gadget.
2026-03-03 19:11:27 +01:00
Ole André Vadla Ravnås 3f251baaa2 libc-shim: Plug some more holes in the stdio API
- getwc, fgetwc, ungetwc
- putc, putwc, fputwc
2026-03-03 15:39:26 +01:00
Ole André Vadla Ravnås 066f2dd718 libc-shim: Skip deinit unless explicitly requested
When the process exits and runs destructor functions, there is no
need to clean up these resources.

Previously this could cause undefined behavior because higher-level
subsystems had not been torn down first, e.g. threads still running
when GThread was torn down. Skipping deinit in this case avoids
teardown-time undefined behavior.
2026-03-03 14:48:40 +01:00
Ole André Vadla Ravnås 1fa296e285 linux: Move to latest syscall-trace protocol
- Use a uint64 for the thread ID. Move it before PID for better packing.
- Support including a module UUID and version string. Not yet wired up
  in the Linux backend.
- Support excluding specific syscalls.

This is to align with the tweaks made for the Fruity implementation.
2026-03-02 15:12:32 +01:00
Ole André Vadla Ravnås 9a4b6ac14d linux: Add uint64 key helpers to BpfMap 2026-03-02 15:12:31 +01:00
Ole André Vadla RavnåsandHåvard Sørbø c23ab3e2c9 fruity: Implement syscall-trace service
Wire up a syscall tracing service on top of CoreProfile ktrace/kdebug.

Configure the ktrace tap to emit syscall entry and exit events and
decode them using the XNU syscall signatures.

Detect syscalls with filesystem path arguments and correlate them with
VFS activity to reconstruct the contents of userspace string pointers
passed to the kernel.

Stitch in callstack events and provide symbolication by leveraging
query_symbolicator_signature().

Stream decoded events to consumer and manage lifecycle, including start,
stop, and cleanup on termination.

Co-authored-by: Håvard Sørbø <[email protected]>
2026-03-02 15:12:30 +01:00
Ole André Vadla Ravnås a6701b2fc9 base: Add XNU syscall enums and signatures
Introduce enums and signature metadata for XNU syscalls.

Define syscall numbers, names, and argument layouts to enable decoding
of ktrace/kdebug events.

Provide a foundation for higher-level tracing and analysis.
2026-03-02 15:02:57 +01:00
Ole André Vadla RavnåsandHåvard Sørbø f810946569 dtx: Introduce CoreProfileService
Provide access to CoreProfile via DTX with initial support for
ktrace/kdebug collection through a TapConfig abstraction.

Add KtraceConfig as the first tap type, modelling a subset of available
flags and filters.

Allow additional tap types and broader configuration to be introduced
later.

Co-authored-by: Håvard Sørbø <[email protected]>
2026-03-02 15:02:57 +01:00
Ole André Vadla Ravnås 5cac7c0c6e dtx: Add per-PID symbolicator signature query
Extend DeviceInfoService with support for retrieving the symbolicator
signature for a specific process.

The returned data describes the process' loaded images, including UUIDs,
segment layouts, load addresses, and versions from each image's
Info.plist. Symbols themselves are not included.

Parse the response into structured types to simplify matching against
crash logs and trace data.
2026-03-02 15:02:57 +01:00
Ole André Vadla RavnåsandHåvard Sørbø 65c694a66d fruity: Support spawning non-debuggable apps
As these cannot be launched suspended through LLDB, fall back to
ProcessControlService and send SIGSTOP immediately after launch.

Ensure the app is not already running before spawning, as relying on
ExistingInstancePolicy.KILL may leave it in an inconsistent state.

Track launched PIDs and resume them by sending SIGCONT when requested.
Clean up tracking when the process terminates.

Co-authored-by: Håvard Sørbø <[email protected]>
2026-03-02 15:02:57 +01:00
Ole André Vadla RavnåsandHåvard Sørbø 13bfcaf1a4 dtx: Extend ProcessControlService process control
Extend ProcessControlService with additional capabilities exposed by
Instruments' processcontrol endpoint.

This adds support for:

- Resolving PID from bundle identifier
- Checking whether a PID is debuggable
- Launching apps with arguments and environment
- Sending signals to a process
- Observing process termination events

Introduce LaunchOptions to control launch behavior such as suspended
start and handling of existing instances.

Expose termination notifications via a new process_terminated signal.

Co-authored-by: Håvard Sørbø <[email protected]>
2026-03-02 15:02:57 +01:00
Ole André Vadla RavnåsandHåvard Sørbø 8f83d5c269 dtx: Lift buffering restrictions
Turned out to be too conservative. And it's hard to decide on
appropriate limits when dealing with bulk data use-cases.

Co-authored-by: Håvard Sørbø <[email protected]>
2026-03-02 15:02:57 +01:00
Ole André Vadla Ravnås b12c30078a dtx: Handle incoming nil arguments 2026-03-02 14:14:22 +01:00
Ole André Vadla Ravnås c7669b9701 numeric: Add bytes_hash() and bytes_equal() 2026-02-24 10:43:40 +01:00
Ole André Vadla Ravnås 5096dbfac4 linux: Fix a stylistic inconsistency 2026-02-23 20:24:45 +01:00
Ole André Vadla Ravnås 9c16fa16fb marshal: Avoid null dereference in enum_to_nick()
Return a formatted fallback string when the enum value is unknown.
2026-02-22 20:20:58 +01:00
Ole André Vadla Ravnås 966f609906 buffer: Make recyclable; add peek + align
Allow Buffer to be reset from either Bytes or an unowned uint8[] without
allocating intermediate Bytes objects.

Extend BufferReader with peeking and alignment helpers and make both
classes reusable through reset() semantics.

This enables zero-allocation parsing in hot paths such as kcdata
stackshot processing.
2026-02-22 15:30:25 +01:00
Ole André Vadla Ravnås 889576e1d5 linux: Simplify build_signatures_variant()
The null-check was a leftover from the older API.
2026-02-21 15:29:38 +01:00
Ole André Vadla Ravnås bb9d9bc6a8 linux: Use int32 for syscall numbers
For consistency with Darwin.
2026-02-21 15:29:34 +01:00
Ole André Vadla Ravnås fc2e14a7cf linux: Simplify the syscall event variant logic 2026-02-21 11:31:00 +01:00
Ole André Vadla Ravnås 868166c23a buffer: Add BufferReader.seek() 2026-02-20 22:19:09 +01:00
Ole André Vadla Ravnås 4d7a0464fb dns: Avoid allocating Bytes object needlessly 2026-02-20 12:42:43 +01:00
Ole André Vadla Ravnås 150e4425ed buffer: Add read_data() to Buffer and BufferReader
To access the raw data without having to allocate a new Bytes object.
2026-02-20 12:39:45 +01:00
Ole André Vadla Ravnås 6bbef7880f buffer: Make read_bytes() zero-copy 2026-02-20 12:39:45 +01:00
Ole André Vadla Ravnås 963a8de514 buffer: Optimize read_fixed_string()
We can't avoid copying, but at least don't waste time on UTF-8
validation. This should be done at the higher level.
2026-02-20 12:39:45 +01:00
Ole André Vadla Ravnås fdb0eebb5e buffer: Optimize read_string()
- Do not copy. The caller should make a copy if the string needs to
  outlive the Buffer/BufferReader.
- Do not validate. This should be done at the higher level.
2026-02-20 12:39:44 +01:00
Ole André Vadla Ravnås ea26ae84b7 subprojects: Bump outdated 2026-02-18 22:53:56 +01:00
Ole André Vadla Ravnås 69016b9d5b submodules: Bump releng 2026-02-18 22:53:55 +01:00
03afdb072a websocket: Pause libsoup input to avoid starvation
Co-authored-by: Håvard Sørbø <[email protected]>
Co-authored-by: Ole André Vadla Ravnås <[email protected]>
2026-02-18 22:52:39 +01:00
bf0830c1a2 network-stack: Handle incoming datagrams async
Incoming datagram delivery previously blocked while waiting for lwIP
thread work to complete.

Switch handle_incoming_datagrams() to an async API and schedule the
processing on the lwIP thread without joining immediately.

Use this to pace callers so they don't monopolize the GLib.MainContext
when floods of datagrams are coming in.

Co-authored-by: Håvard Sørbø <[email protected]>
Co-authored-by: Ole André Vadla Ravnås <[email protected]>
2026-02-18 22:52:39 +01:00
Kerbiter 4aac1ae324 compat: Include x86_64 in Windows x86 builds 2026-02-18 22:28:31 +01:00
Ole André Vadla Ravnås e74d51dd13 keyed-archive: Make to_string() prettier 2026-02-18 01:07:43 +01:00
Ole André Vadla RavnåsandHåvard Sørbø 984413c057 keyed-archive: Improve to_string() support
Intended for debugging during development.

Co-authored-by: Håvard Sørbø <[email protected]>
2026-02-17 23:55:02 +01:00
Ole André Vadla RavnåsandHåvard Sørbø ed78ab19d7 keyed-archive: Support NSSet
Only encoding for now.

Co-authored-by: Håvard Sørbø <[email protected]>
2026-02-17 23:54:57 +01:00
Ole André Vadla RavnåsandHåvard Sørbø 5b877cbbff dtx: Upgrade protocol handling
- Rename DTXMessageType.INVOKE to DISPATCH.
- Rename DTXMessageType.RESULT to OBJECT.
- Fix channel code and is_notification logic.
- Add missing message types.
- Support data messages.
- Do not advertise compression support. We don't support it yet.

Co-authored-by: Håvard Sørbø <[email protected]>
2026-02-17 23:54:54 +01:00
Ole André Vadla Ravnås 3f3457b249 subprojects: Prepare for release 2026-02-16 22:45:39 +01:00
Ole André Vadla Ravnås f1c0e87871 subprojects: Bump outdated 2026-02-16 22:08:06 +01:00
Ole André Vadla Ravnås 6096046b05 syscall-tracer: Decode timespec values
Recognize timespec pointer arguments and decode them into structured
values rather than emitting opaque byte arrays.

Supports both __kernel_timespec and old_timespec32 layouts.
2026-02-16 21:27:26 +01:00
Ole André Vadla Ravnås c0815c4d1a syscall-tracer: Fix a stylistic inconsistency 2026-02-16 21:24:05 +01:00
Ole André Vadla Ravnås ab42fcb1ed syscall-tracer: Remove a redundant check 2026-02-16 21:23:52 +01:00
Ole André Vadla Ravnås cd0a327a3c syscall-tracer: Fix raw attachment lifetime
The GVariant was previously created from data freed before return,
leaving it with a dangling pointer.
2026-02-16 21:01:17 +01:00
Ole André Vadla Ravnås 51ff27a08b syscall-tracer: Fix multi-attachment parsing
Fix parsing of multiple attachments by encoding how much space is
reserved for each attachment.
2026-02-16 20:56:54 +01:00
Ole André Vadla Ravnås 6b54eeb7d8 subprojects: Prepare for release 2026-02-14 10:52:09 +01:00
Ole André Vadla Ravnås 08de3d3d07 subprojects: Bump outdated 2026-02-14 10:50:25 +01:00
Ole André Vadla Ravnås 174b93cbd4 xpc-service: Drop support for redundant casts 2026-02-14 10:44:29 +01:00
Ole André Vadla Ravnås d0f8162a65 android: Fix a stylistic inconsistency 2026-02-13 22:53:59 +01:00
Ole André Vadla Ravnås a3427baeb3 subprojects: Prepare for release 2026-02-13 22:48:30 +01:00
Ole André Vadla Ravnås c792a09002 subprojects: Bump outdated 2026-02-13 22:47:31 +01:00
Ole André Vadla Ravnås 27605f7fde android: Defer spawn completion until setArgV0()
Only record the package name in selinux_android_setcontext(), and delay
contacting RoboLauncher until setArgV0(). This ensures ART is ready so
frida-java-bridge can attach to the VM.

Also refactor Zymbiote code and improve naming.
2026-02-13 22:46:03 +01:00
Ole André Vadla Ravnås ba8784fe8c subprojects: Prepare for release 2026-02-13 15:12:30 +01:00
Ole André Vadla Ravnås 0a6c2103fa subprojects: Bump outdated 2026-02-13 15:09:43 +01:00
Ole André Vadla Ravnås 14de0ef567 android: Fix spawn package name logic on new OSes
Where we should be hooking selinux_android_setcontext() to infer it,
like we used to.
2026-02-13 14:39:22 +01:00
Ole André Vadla Ravnås 4165572919 linux: Avoid repeated /proc/pid/maps parsing
By folding the ProcMapsSoEntry functionality into ProcMapsSnapshot.
2026-02-13 14:39:17 +01:00
78 changed files with 9397 additions and 2206 deletions

No files matched your search

+19 -8
View File
@@ -149,9 +149,20 @@ def setup(role: Role,
other_triplet: Optional[str] = None
extra_environ: dict[str, str] = {}
if host_os == "windows" and host_arch == "x86_64" and host_config == "mingw":
other_label = "x86"
have_toolchain, other_triplet = detect_mingw_toolchain_for("x86")
if host_os == "windows" and host_arch in {"x86_64", "x86"}:
if host_arch == "x86_64":
other_label = "x86"
other_kind = "legacy"
else:
other_label = "x86_64"
other_kind = "modern"
if host_config == "mingw":
have_toolchain, other_triplet = detect_mingw_toolchain_for(other_label)
else:
have_toolchain = True
other_triplet = None
elif host_os == "linux" and host_arch == "x86_64" and host_config is None:
other_label = "x86"
other_triplet = "i686-linux-gnu"
@@ -179,21 +190,21 @@ def setup(role: Role,
raise ToolchainNotFoundError(f"unable to locate toolchain for {other_triplet}")
missing.append(MissingFeature(other_label, other_triplet))
if host_os == "windows" and host_arch == "x86_64" and have_toolchain:
group = OutputGroup("x86", other_triplet, extra_environ)
if host_os == "windows" and host_arch in {"x86_64", "x86"} and have_toolchain:
group = OutputGroup(other_label, other_triplet, extra_environ)
outputs[group] = [
Output(identifier="helper_legacy",
Output(identifier=f"helper_{other_kind}",
name=HELPER_FILE_WINDOWS.name,
file=HELPER_FILE_WINDOWS,
target=HELPER_TARGET),
Output(identifier="agent_legacy",
Output(identifier=f"agent_{other_kind}",
name=AGENT_FILE_WINDOWS.name,
file=AGENT_FILE_WINDOWS,
target=AGENT_TARGET),
]
if "gadget" in components:
outputs[group] += [
Output(identifier="gadget_legacy",
Output(identifier=f"gadget_{other_kind}",
name=GADGET_FILE_WINDOWS.name,
file=GADGET_FILE_WINDOWS,
target=GADGET_TARGET),
+2
View File
@@ -51,6 +51,8 @@ void
_frida_agent_environment_deinit (void)
{
#ifndef HAVE_MUSL
frida_libc_shim_prepare_to_deinit ();
gum_shutdown ();
gio_shutdown ();
glib_shutdown ();
+14
View File
@@ -0,0 +1,14 @@
FRIDA_1.0 {
global:
frida_agent_main;
local:
*;
};
GLIBC_2.2.5 {
local:
fopen*;
fseeko*;
ftello*;
} FRIDA_1.0;
+7 -1
View File
@@ -28,7 +28,13 @@ if host_os_family == 'windows'
elif host_os_family == 'darwin'
extra_link_args += '-Wl,-exported_symbol,_frida_agent_main'
else
symscript = (host_os == 'android') ? 'frida-agent-android.version' : 'frida-agent.version'
if libc == 'glibc'
symscript = 'frida-agent-glibc.version'
elif host_os == 'android'
symscript = 'frida-agent-android.version'
else
symscript = 'frida-agent.version'
endif
extra_link_args += '-Wl,--version-script,' + meson.current_source_dir() / symscript
extra_link_depends += symscript
endif
+262 -127
View File
@@ -309,8 +309,17 @@ namespace Frida {
public sealed class Buffer : Object {
public Bytes bytes {
get;
construct;
get {
if (_bytes == null)
_bytes = new Bytes.static (_data);
return _bytes;
}
}
public size_t size {
get {
return _data.length;
}
}
public ByteOrder byte_order {
@@ -323,20 +332,39 @@ namespace Frida {
construct;
}
private unowned uint8 * data;
private size_t size;
private Bytes? _bytes;
private unowned uint8[] _data;
public Buffer (Bytes bytes, ByteOrder byte_order = HOST, uint pointer_size = (uint) sizeof (size_t)) {
Object (
bytes: bytes,
byte_order: byte_order,
pointer_size: pointer_size
);
reset_bytes (bytes);
}
construct {
data = bytes.get_data ();
size = bytes.get_size ();
public Buffer.from_data (uint8[] data, ByteOrder byte_order = HOST, uint pointer_size = (uint) sizeof (size_t)) {
Object (
byte_order: byte_order,
pointer_size: pointer_size
);
reset_data (data);
}
public void reset_bytes (Bytes bytes) {
_bytes = bytes;
_data = bytes.get_data ();
}
public void reset_data (uint8[] data) {
_bytes = null;
_data = data;
}
public unowned uint8[] peek_data () {
return _data;
}
public uint64 read_pointer (size_t offset) {
@@ -470,17 +498,13 @@ namespace Frida {
return *((double *) &bits);
}
public string read_string (size_t offset) throws Error {
public unowned string read_string (size_t offset) throws Error {
string * start = (string *) get_pointer (offset, sizeof (char));
size_t max_length = size - offset;
size_t max_length = _data.length - offset;
string * end = memchr (start, 0, max_length);
if (end == null)
throw new Error.PROTOCOL ("Missing null character");
size_t size = end - start;
string val = start->substring (0, (long) size);
if (!val.validate ())
throw new Error.PROTOCOL ("Invalid UTF-8 string");
return val;
return start;
}
[CCode (cname = "memchr", cheader_filename = "string.h")]
@@ -488,17 +512,14 @@ namespace Frida {
public string read_fixed_string (size_t offset, size_t size) throws Error {
string * start = (string *) get_pointer (offset, size);
size_t max_length = size_t.min (size, this.size - offset);
size_t max_length = size_t.min (size, _data.length - 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;
return start->substring (0, (long) n);
}
public unowned Buffer write_string (size_t offset, string val) {
@@ -508,9 +529,14 @@ namespace Frida {
}
public Bytes read_bytes (size_t offset, size_t size) {
var data = new uint8[size + 1];
Memory.copy (data, get_pointer (offset, size), size);
return new Bytes.take ((owned) data);
if (_bytes == null)
return make_bytes_with_owner ((uint8 *) _data + offset, _data.length - size, this);
return _bytes[offset:offset + size];
}
public unowned uint8[] read_data (size_t offset, size_t size) {
unowned uint8 * ptr = get_pointer (offset, size);
return ((uint8[]) ptr)[:size];
}
public unowned Buffer write_bytes (size_t offset, Bytes bytes) {
@@ -521,129 +547,49 @@ namespace Frida {
private uint8 * get_pointer (size_t offset, size_t n) {
size_t minimum_size = offset + n;
assert (size >= minimum_size);
return data + offset;
assert (_data.length >= minimum_size);
return (uint8 *) _data + offset;
}
}
public sealed class BufferReader {
public Buffer buffer {
get;
}
public size_t offset {
get {
return _offset;
}
get;
}
public size_t available {
get {
return buffer.bytes.get_size () - _offset;
return _size - _offset;
}
}
private Buffer buffer;
private size_t _offset = 0;
private size_t _size;
public BufferReader (Buffer buf) {
buffer = buf;
public BufferReader (Buffer buffer) {
reset (buffer);
}
public uint64 read_pointer () throws Error {
var pointer_size = buffer.pointer_size;
check_available (pointer_size);
var ptr = buffer.read_pointer (_offset);
_offset += pointer_size;
return ptr;
public void reset (Buffer buffer) {
_buffer = buffer;
_size = buffer.size;
_offset = 0;
}
public int8 read_int8 () throws Error {
check_available (sizeof (int8));
var val = buffer.read_int8 (_offset);
_offset += sizeof (int8);
return val;
public void reset_at (Buffer buffer, size_t offset) throws Error {
_buffer = buffer;
_size = buffer.size;
seek (offset);
}
public uint8 read_uint8 () throws Error {
check_available (sizeof (uint8));
var val = buffer.read_uint8 (_offset);
_offset += sizeof (uint8);
return val;
}
public int16 read_int16 () throws Error {
check_available (sizeof (int16));
var val = buffer.read_int16 (_offset);
_offset += sizeof (int16);
return val;
}
public uint16 read_uint16 () throws Error {
check_available (sizeof (uint16));
var val = buffer.read_uint16 (_offset);
_offset += sizeof (uint16);
return val;
}
public int32 read_int32 () throws Error {
check_available (sizeof (int32));
var val = buffer.read_int32 (_offset);
_offset += sizeof (int32);
return val;
}
public uint32 read_uint32 () throws Error {
check_available (sizeof (uint32));
var val = buffer.read_uint32 (_offset);
_offset += sizeof (uint32);
return val;
}
public int64 read_int64 () throws Error {
check_available (sizeof (int64));
var val = buffer.read_int64 (_offset);
_offset += sizeof (int64);
return val;
}
public uint64 read_uint64 () throws Error {
check_available (sizeof (uint64));
var val = buffer.read_uint64 (_offset);
_offset += sizeof (uint64);
return val;
}
public float read_float () throws Error {
check_available (sizeof (float));
var val = buffer.read_float (_offset);
_offset += sizeof (float);
return val;
}
public double read_double () throws Error {
check_available (sizeof (double));
var val = buffer.read_double (_offset);
_offset += sizeof (double);
return val;
}
public string read_string () throws Error {
check_available (1);
var val = buffer.read_string (_offset);
_offset += val.length + 1;
return val;
}
public string read_fixed_string (size_t size) throws Error {
check_available (size);
var val = buffer.read_fixed_string (_offset, size);
_offset += size;
return val;
}
public Bytes read_bytes (size_t size) throws Error {
check_available (size);
var val = buffer.bytes[_offset:_offset + size];
_offset += size;
return val;
public unowned BufferReader seek (size_t offset) throws Error {
if (offset > _size)
throw new Error.PROTOCOL ("Malformed buffer: truncated");
_offset = offset;
return this;
}
public unowned BufferReader skip (size_t n) throws Error {
@@ -652,6 +598,195 @@ namespace Frida {
return this;
}
public unowned BufferReader align (size_t alignment) throws Error {
size_t mask = alignment - 1;
size_t rem = _offset & mask;
if (rem != 0)
skip (alignment - rem);
return this;
}
public uint64 peek_pointer () throws Error {
var pointer_size = _buffer.pointer_size;
check_available (pointer_size);
return _buffer.read_pointer (_offset);
}
public uint64 read_pointer () throws Error {
var pointer_size = _buffer.pointer_size;
check_available (pointer_size);
var ptr = _buffer.read_pointer (_offset);
_offset += pointer_size;
return ptr;
}
public int8 peek_int8 () throws Error {
check_available (sizeof (int8));
return _buffer.read_int8 (_offset);
}
public int8 read_int8 () throws Error {
check_available (sizeof (int8));
var val = _buffer.read_int8 (_offset);
_offset += sizeof (int8);
return val;
}
public uint8 peek_uint8 () throws Error {
check_available (sizeof (uint8));
return _buffer.read_uint8 (_offset);
}
public uint8 read_uint8 () throws Error {
check_available (sizeof (uint8));
var val = _buffer.read_uint8 (_offset);
_offset += sizeof (uint8);
return val;
}
public int16 peek_int16 () throws Error {
check_available (sizeof (int16));
return _buffer.read_int16 (_offset);
}
public int16 read_int16 () throws Error {
check_available (sizeof (int16));
var val = _buffer.read_int16 (_offset);
_offset += sizeof (int16);
return val;
}
public uint16 peek_uint16 () throws Error {
check_available (sizeof (uint16));
return _buffer.read_uint16 (_offset);
}
public uint16 read_uint16 () throws Error {
check_available (sizeof (uint16));
var val = _buffer.read_uint16 (_offset);
_offset += sizeof (uint16);
return val;
}
public int32 peek_int32 () throws Error {
check_available (sizeof (int32));
return _buffer.read_int32 (_offset);
}
public int32 read_int32 () throws Error {
check_available (sizeof (int32));
var val = _buffer.read_int32 (_offset);
_offset += sizeof (int32);
return val;
}
public uint32 peek_uint32 () throws Error {
check_available (sizeof (uint32));
return _buffer.read_uint32 (_offset);
}
public uint32 read_uint32 () throws Error {
check_available (sizeof (uint32));
var val = _buffer.read_uint32 (_offset);
_offset += sizeof (uint32);
return val;
}
public int64 peek_int64 () throws Error {
check_available (sizeof (int64));
return _buffer.read_int64 (_offset);
}
public int64 read_int64 () throws Error {
check_available (sizeof (int64));
var val = _buffer.read_int64 (_offset);
_offset += sizeof (int64);
return val;
}
public uint64 peek_uint64 () throws Error {
check_available (sizeof (uint64));
return _buffer.read_uint64 (_offset);
}
public uint64 read_uint64 () throws Error {
check_available (sizeof (uint64));
var val = _buffer.read_uint64 (_offset);
_offset += sizeof (uint64);
return val;
}
public float peek_float () throws Error {
check_available (sizeof (float));
return _buffer.read_float (_offset);
}
public float read_float () throws Error {
check_available (sizeof (float));
var val = _buffer.read_float (_offset);
_offset += sizeof (float);
return val;
}
public double peek_double () throws Error {
check_available (sizeof (double));
return _buffer.read_double (_offset);
}
public double read_double () throws Error {
check_available (sizeof (double));
var val = _buffer.read_double (_offset);
_offset += sizeof (double);
return val;
}
public unowned string peek_string () throws Error {
check_available (1);
return _buffer.read_string (_offset);
}
public unowned string read_string () throws Error {
check_available (1);
unowned string val = _buffer.read_string (_offset);
_offset += val.length + 1;
return val;
}
public string peek_fixed_string (size_t size) throws Error {
check_available (size);
return _buffer.read_fixed_string (_offset, size);
}
public string read_fixed_string (size_t size) throws Error {
check_available (size);
var val = _buffer.read_fixed_string (_offset, size);
_offset += size;
return val;
}
public unowned uint8[] peek_data (size_t size) throws Error {
check_available (size);
return _buffer.read_data (_offset, size);
}
public unowned uint8[] read_data (size_t size) throws Error {
check_available (size);
unowned uint8[] slice = _buffer.read_data (_offset, size);
_offset += size;
return slice;
}
public Bytes read_bytes (size_t size) throws Error {
check_available (size);
var val = _buffer.read_bytes (_offset, size);
_offset += size;
return val;
}
public unowned uint8[] read_remaining_data () throws Error {
return read_data (available);
}
private void check_available (size_t n) throws Error {
if (available < n)
throw new Error.PROTOCOL ("Malformed buffer: truncated");
+12 -2
View File
@@ -1,18 +1,26 @@
#ifndef __FRIDA_ATOMICS_H__
#define __FRIDA_ATOMICS_H__
#include <glib.h>
G_BEGIN_DECLS
#ifdef _MSC_VER
/* TODO: Add once needed. */
#else
static inline guint64 frida_atomics_load_u64_acquire (volatile guint64 * p)
typedef guint64 FridaAtomicU64 __attribute__ ((aligned (8)));
static inline guint64
frida_atomics_load_u64_acquire (volatile FridaAtomicU64 * p)
{
return __atomic_load_n (p, __ATOMIC_ACQUIRE);
}
static inline void frida_atomics_store_u64_release (volatile guint64 * p, guint64 v)
static inline void
frida_atomics_store_u64_release (volatile FridaAtomicU64 * p, guint64 v)
{
__atomic_store_n (p, v, __ATOMIC_RELEASE);
}
@@ -24,4 +32,6 @@ static inline guint32 frida_atomics_load_u32_acquire (volatile guint32 * p)
#endif
G_END_DECLS
#endif
+3 -3
View File
@@ -1,6 +1,6 @@
[CCode (cheader_filename = "frida-atomics.h")]
namespace Frida.Atomics {
public static uint64 load_u64_acquire (void * p);
public static void store_u64_release (void * p, uint64 v);
public static uint32 load_u32_acquire (void * p);
public static uint64 load_u64_acquire (uint64 * p);
public static void store_u64_release (uint64 * p, uint64 v);
public static uint32 load_u32_acquire (uint32 * p);
}
+4
View File
@@ -6,6 +6,8 @@
#include <glib.h>
#include <xpc/xpc.h>
G_BEGIN_DECLS
typedef void (* FridaXpcHandler) (xpc_object_t object, gpointer user_data);
typedef gboolean (* FridaXpcDictionaryApplier) (const gchar * key, xpc_object_t val, gpointer user_data);
@@ -17,6 +19,8 @@ void _frida_xpc_connection_send_message_with_reply (xpc_connection_t connection,
gchar * _frida_xpc_object_to_string (xpc_object_t object);
gboolean _frida_xpc_dictionary_apply (xpc_object_t dict, FridaXpcDictionaryApplier applier, gpointer user_data);
G_END_DECLS
#endif
#endif
+41
View File
@@ -0,0 +1,41 @@
#ifndef __FRIDA_JNI_H__
#define __FRIDA_JNI_H__
#include <jni.h>
G_BEGIN_DECLS
typedef jint (* JNIDestroyJavaVMFunc) (JavaVM *);
typedef jint (* JNIAttachCurrentThreadFunc) (JavaVM *, JNIEnv **, void *);
typedef jint (* JNIDetachCurrentThreadFunc) (JavaVM *);
typedef jint (* JNIGetEnvFunc) (JavaVM *, JNIEnv **, jint);
typedef jclass (* JNIFindClassFunc) (JNIEnv *, const char *);
typedef jthrowable (* JNIExceptionOccurredFunc) (JNIEnv *);
typedef void (* JNIExceptionDescribeFunc) (JNIEnv *);
typedef void (* JNIExceptionClearFunc) (JNIEnv *);
typedef jint (* JNIPushLocalFrameFunc) (JNIEnv *, jint);
typedef jobject (* JNIPopLocalFrameFunc) (JNIEnv *, jobject);
typedef jobject (* JNINewGlobalRefFunc) (JNIEnv *, jobject);
typedef void (* JNIDeleteGlobalRefFunc) (JNIEnv *, jobject);
typedef void (* JNIDeleteLocalRefFunc) (JNIEnv *, jobject);
typedef jobject (* JNINewObjectFunc) (JNIEnv *, jclass, jmethodID, ...);
typedef jclass (* JNIGetObjectClassFunc) (JNIEnv *, jobject);
typedef jmethodID (* JNIGetMethodIDFunc) (JNIEnv *, jclass, const char *, const char *);
typedef jobject (* JNICallObjectMethodFunc) (JNIEnv *, jobject, jmethodID, ...);
typedef jstring (* JNINewStringUTFFunc) (JNIEnv *, const char *);
typedef const char * (* JNIGetStringUTFCharsFunc) (JNIEnv *, jstring, jboolean *);
typedef void (* JNIReleaseStringUTFCharsFunc) (JNIEnv *, jstring, const char *);
typedef jboolean (* JNIExceptionCheckFunc) (JNIEnv *);
G_END_DECLS
#endif
+14 -2
View File
@@ -46,7 +46,7 @@ namespace Frida {
public extern unowned LinuxSyscallSignature[]? get_compat32_syscall_signatures ();
public struct LinuxSyscallSignature {
public uint nr;
public int nr;
public string name;
public uint8 nargs;
public LinuxSyscallArg args[6];
@@ -141,7 +141,7 @@ namespace Frida {
private char[] kernel_log_buf;
public static BpfObject open (string name, uint8[] blob) throws Error {
var log_buf = new char[64 * 1024];
var log_buf = new char[128 * 1024];
var opts = Libbpf.Object.OpenOpts ();
opts.sz = sizeof (Libbpf.Object.OpenOpts);
@@ -348,6 +348,18 @@ namespace Frida {
remove_raw ((uint8[]) &key);
}
public void update_u64_u8 (uint64 key, uint8 val) throws Error {
update_raw ((uint8[]) &key, (uint8[]) &val);
}
public void update_u64_u32 (uint64 key, uint32 val) throws Error {
update_raw ((uint8[]) &key, (uint8[]) &val);
}
public void remove_u64 (uint64 key) throws Error {
remove_raw ((uint8[]) &key);
}
public void foreach_percpu_value<T> (uint8[] key, PercpuValueFunc<T> func) throws Error {
var ncpus = check_libbpf_result (Libbpf.num_possible_cpus ());
var percpu_stride = round_up_8 (value_size);
+2
View File
@@ -15,6 +15,8 @@ base_sources = [
'buffer.vala',
'buffer-glue.c',
'value.vala',
'xnu-syscalls' / 'xnu-syscalls.vala',
'xnu-syscalls' / 'xnu-syscalls-glue.c',
]
extra_vala_args = []
+12 -1
View File
@@ -2170,7 +2170,10 @@ namespace Frida {
public static string enum_to_nick<T> (int val) {
var klass = (EnumClass) typeof (T).class_ref ();
return klass.get_value (val).value_nick;
unowned EnumValue? v = klass.get_value (val);
if (v == null)
return "unknown-0x%x".printf (val);
return v.value_nick;
}
}
@@ -2196,5 +2199,13 @@ namespace Frida {
uint64 b = val_b;
return a == b;
}
public uint bytes_hash (Bytes b) {
return b.hash ();
}
public static bool bytes_equal (Bytes a, Bytes b) {
return a.compare (b) == 0;
}
}
}
+4
View File
@@ -940,6 +940,9 @@ namespace Frida {
Memory.copy (buffer, recv_queue.data, n);
recv_queue.remove_range (0, (uint) n);
if (recv_queue.len == 0)
websocket.resume_input ();
update_pending_io ();
} else {
if (state == OPEN)
@@ -1006,6 +1009,7 @@ namespace Frida {
private void on_message (int type, Bytes message) {
with_state_lock (() => {
recv_queue.append (message.get_data ());
websocket.pause_input ();
update_pending_io ();
});
}
+860
View File
@@ -0,0 +1,860 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from __future__ import annotations
import argparse
import re
from dataclasses import dataclass
from pathlib import Path
from typing import Dict, List, Optional, Tuple
MAX_ARGS = 9
@dataclass(frozen=True)
class SyscallArg:
type: str
name: str
@dataclass(frozen=True)
class SyscallSignature:
name: str
args: Tuple[SyscallArg, ...]
MACH_TRAP_INDEXED_CALL_RE = re.compile(r"/\*\s*(?P<idx>\d+)\s*\*/\s*MACH_TRAP\s*\(")
MACH_TRAPS_IFNDEF_KERNEL_RE = re.compile(r"^\s*#ifndef\s+KERNEL\b", re.MULTILINE)
MACH_TRAPS_ELSE_KERNEL_RE = re.compile(r"^\s*#else\b.*\bKERNEL\b", re.MULTILINE)
USER_EXTERN_PROTO_RE = re.compile(
r"^\s*extern\s+(?P<ret>.+?)\s+(?P<fn>[A-Za-z_]\w*)\s*\((?P<args>.*?)\)\s*;",
re.MULTILINE | re.DOTALL,
)
KERNEL_STRUCT_RE = re.compile(
r"\bstruct\s+(?P<name>[A-Za-z_]\w*)\s*\{\s*(?P<body>.*?)\s*\}\s*;",
re.DOTALL,
)
KERNEL_TRAP_EXTERN_RE = re.compile(
r"^\s*(?:extern\s+)?(?P<ret>.+?)\s+(?P<fn>[A-Za-z_]\w*)\s*\(\s*struct\s+(?P<args_struct>[A-Za-z_]\w*)\s*\*\s*args\s*\)\s*;",
re.MULTILINE | re.DOTALL,
)
PAD_ARG_RE = re.compile(
r"\bPAD_ARG_\s*\(\s*(?P<ty>[^,]+?)\s*,\s*(?P<name>[^)]+?)\s*\)\s*;",
)
PLAIN_FIELD_RE = re.compile(r"^\s*(?P<ty>.+?)\s+(?P<name>[A-Za-z_]\w*)\s*;\s*$")
BSD_MASTER_ENTRY_RE = re.compile(
r"^\s*(?P<nr>\d+)\s+(?P<audit>\S+)\s+(?P<files>\S+)\s+\{\s*(?P<proto>[^}]+?)\s*\}\s*(?:\{.*\})?\s*$"
)
BSD_MASTER_PROTO_RE = re.compile(
r"^\s*(?P<ret>.+?)\s+(?P<fn>[A-Za-z_]\w*)\s*\((?P<args>.*)\)\s*(?P<attrs>.*)$",
re.DOTALL,
)
LINE_COMMENT_RE = re.compile(r"//.*$")
BLOCK_COMMENT_RE = re.compile(r"/\*[^*]*\*+(?:[^/*][^*]*\*+)*/")
TRAILING_ARRAY_SUFFIX_RE = re.compile(r"\[[^\]]*\]\s*$")
POINTER_SPACING_RE = re.compile(r"\s*\*\s*")
PARAM_NAME_RE = re.compile(r"[A-Za-z_]\w*$")
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("--kernel-tree", required=True)
ap.add_argument("--out-vala", required=True)
ap.add_argument("--out-c", required=True)
args = ap.parse_args()
kernel_tree = Path(args.kernel_tree).resolve()
if not kernel_tree.exists():
raise SystemExit(f"--kernel-tree does not exist: {kernel_tree}")
mach_numbers, mach_sigs = load_mach_traps(kernel_tree)
bsd_numbers, bsd_sigs = load_bsd_syscalls_master(kernel_tree)
vala = render_vala(
mach_numbers=mach_numbers,
bsd_numbers=bsd_numbers,
)
c_src = render_c_source(
mach_numbers=mach_numbers,
bsd_numbers=bsd_numbers,
mach_sigs=mach_sigs,
bsd_sigs=bsd_sigs,
)
out_vala = Path(args.out_vala)
out_c = Path(args.out_c)
out_vala.parent.mkdir(parents=True, exist_ok=True)
out_c.parent.mkdir(parents=True, exist_ok=True)
out_vala.write_text(vala, encoding="utf-8")
out_c.write_text(c_src, encoding="utf-8")
return 0
def load_mach_traps(
kernel_tree: Path,
) -> Tuple[Dict[int, str], Dict[str, SyscallSignature]]:
table_path = kernel_tree / "osfmk" / "kern" / "syscall_sw.c"
if not table_path.exists():
raise RuntimeError(f"Missing Mach trap table source: {table_path}")
header_path = kernel_tree / "osfmk" / "mach" / "mach_traps.h"
if not header_path.exists():
raise RuntimeError(f"Missing Mach traps header: {header_path}")
table_text = table_path.read_text(encoding="utf-8", errors="ignore")
trap_routines = parse_mach_trap_table(table_text, table_path)
header_text = header_path.read_text(encoding="utf-8", errors="ignore")
userspace_text, kernel_text = split_mach_traps_header(header_text, header_path)
userspace_protos = parse_userspace_mach_traps_prototypes(
userspace_text, header_path
)
kernel_argmap = parse_kernel_mach_traps_args(kernel_text, header_path)
numbers: Dict[int, str] = {}
sigs: Dict[str, SyscallSignature] = {}
for index, routine in trap_routines:
if routine == "kern_invalid":
continue
nr = -index
public_name = normalize_mach_name(routine)
if public_name == "":
raise RuntimeError(f"{table_path}: empty normalized name from {routine!r}")
if nr in numbers:
raise RuntimeError(f"{table_path}: duplicate mach trap number {nr}")
if public_name in sigs:
raise RuntimeError(
f"{table_path}: normalized Mach name collision for {public_name!r}"
)
args = resolve_mach_trap_signature(
routine=routine,
userspace_protos=userspace_protos,
kernel_argmap=kernel_argmap,
table_path=table_path,
)
if len(args) > MAX_ARGS:
raise RuntimeError(
f"{table_path}: trap {routine!r} has {len(args)} args; max supported is {MAX_ARGS}"
)
numbers[nr] = public_name
sigs[public_name] = SyscallSignature(name=public_name, args=tuple(args))
return numbers, sigs
def parse_mach_trap_table(text: str, path: Path) -> List[Tuple[int, str]]:
anchor = text.find("mach_trap_table")
if anchor == -1:
raise RuntimeError(f"{path}: mach_trap_table not found")
brace = text.find("{", anchor)
if brace == -1:
raise RuntimeError(f"{path}: mach_trap_table '{{' not found")
payload, _ = extract_brace_payload(text, brace, path)
by_index: Dict[int, str] = {}
off = 0
while True:
m = MACH_TRAP_INDEXED_CALL_RE.search(payload, off)
if m is None:
break
idx = int(m.group("idx"), 10)
open_paren = m.end(0) - 1
args_blob, end_off = extract_parentheses_payload(payload, open_paren, path)
parts = [
a.strip() for a in split_top_level_commas(args_blob) if a.strip() != ""
]
if len(parts) < 1:
raise RuntimeError(f"{path}: bad MACH_TRAP() entry: {args_blob!r}")
routine = parts[0]
prev = by_index.get(idx)
if prev is None:
by_index[idx] = routine
else:
if prev == routine:
pass
elif prev == "kern_invalid" and routine != "kern_invalid":
by_index[idx] = routine
elif routine == "kern_invalid" and prev != "kern_invalid":
pass
else:
raise RuntimeError(
f"{path}: conflicting MACH_TRAP entries for index {idx}: {prev!r} vs {routine!r}"
)
off = end_off
return sorted(by_index.items(), key=lambda kv: kv[0])
def split_mach_traps_header(text: str, path: Path) -> Tuple[str, str]:
m_start = MACH_TRAPS_IFNDEF_KERNEL_RE.search(text)
if m_start is None:
raise RuntimeError(f"{path}: missing '#ifndef KERNEL'")
m_else = MACH_TRAPS_ELSE_KERNEL_RE.search(text, m_start.end())
if m_else is None:
raise RuntimeError(f"{path}: missing '#else ... KERNEL ...'")
userspace = text[m_start.end():m_else.start()]
kernel = text[m_else.end():]
return userspace, kernel
def parse_userspace_mach_traps_prototypes(
userspace_text: str, path: Path
) -> Dict[str, Tuple[SyscallArg, ...]]:
protos: Dict[str, Tuple[SyscallArg, ...]] = {}
for m in USER_EXTERN_PROTO_RE.finditer(userspace_text):
fn = m.group("fn").strip()
args_blob = m.group("args").strip()
ret_blob = strip_c_comments(m.group("ret")).strip()
if ret_blob == "":
raise RuntimeError(f"{path}: empty return type for {fn!r}")
line_no = line_number_at_offset(userspace_text, m.start())
args = parse_c_param_list(args_blob, path, line_no)
cur = tuple(args)
prev = protos.get(fn)
if prev is not None and prev != cur:
raise RuntimeError(f"{path}:{line_no}: conflicting prototype for {fn!r}")
protos[fn] = cur
return protos
def parse_kernel_mach_traps_args(
kernel_text: str, path: Path
) -> Dict[str, Tuple[SyscallArg, ...]]:
text = strip_c_comments(kernel_text)
structs: Dict[str, str] = {}
for m in KERNEL_STRUCT_RE.finditer(text):
name = m.group("name").strip()
body = m.group("body")
structs[name] = body
fn_to_struct: Dict[str, str] = {}
for m in KERNEL_TRAP_EXTERN_RE.finditer(text):
fn = m.group("fn").strip()
args_struct = m.group("args_struct").strip()
fn_to_struct[fn] = args_struct
out: Dict[str, Tuple[SyscallArg, ...]] = {}
for fn, args_struct in fn_to_struct.items():
body = structs.get(args_struct)
if body is None:
continue
args = parse_mach_args_struct_body(body, path)
out[fn] = tuple(args)
return out
def parse_mach_args_struct_body(body: str, path: Path) -> List[SyscallArg]:
args: List[SyscallArg] = []
body = strip_c_comments(body)
for raw_ln in body.splitlines():
ln = raw_ln.strip()
if ln == "" or ln.startswith("#"):
continue
if "PAD_ARG_8" in ln:
continue
m = PAD_ARG_RE.search(ln)
if m is not None:
ty = normalize_whitespace(m.group("ty").strip())
name = normalize_whitespace(m.group("name").strip())
if ty == "" or name == "":
raise RuntimeError(f"{path}: bad PAD_ARG_ in args struct: {raw_ln!r}")
args.append(SyscallArg(type=ty, name=name))
continue
m = PLAIN_FIELD_RE.match(ln)
if m is not None:
ty = normalize_whitespace(m.group("ty").strip())
name = m.group("name").strip()
if ty == "" or name == "":
raise RuntimeError(f"{path}: bad field in args struct: {raw_ln!r}")
args.append(SyscallArg(type=ty, name=name))
continue
if len(args) == 1 and args[0].name == "dummy":
return []
return args
def resolve_mach_trap_signature(
*,
routine: str,
userspace_protos: Dict[str, Tuple[SyscallArg, ...]],
kernel_argmap: Dict[str, Tuple[SyscallArg, ...]],
table_path: Path,
) -> List[SyscallArg]:
def get_userspace(name: str) -> Optional[Tuple[SyscallArg, ...]]:
return userspace_protos.get(name)
def get_kernel(name: str) -> Optional[Tuple[SyscallArg, ...]]:
return kernel_argmap.get(name)
proto_args = get_userspace(routine)
if proto_args is None and routine.endswith("_trap"):
proto_args = get_userspace(routine[: -len("_trap")])
if proto_args is not None:
return list(proto_args)
proto_args = get_kernel(routine)
if proto_args is None and routine.endswith("_trap"):
proto_args = get_kernel(routine[: -len("_trap")])
if proto_args is None:
raise RuntimeError(
f"{table_path}: missing userspace prototype for {routine!r}, and no kernel extern(struct *_args *args) mapping found"
)
return list(proto_args)
def normalize_mach_name(routine: str) -> str:
if routine.startswith("_"):
routine = routine[1:]
if routine.startswith("kernelrpc_"):
routine = routine[len("kernelrpc_"):]
if routine.endswith("_trap"):
routine = routine[: -len("_trap")]
return routine
def load_bsd_syscalls_master(
kernel_tree: Path,
) -> Tuple[Dict[int, str], Dict[str, SyscallSignature]]:
path = kernel_tree / "bsd" / "kern" / "syscalls.master"
if not path.exists():
raise RuntimeError(f"Missing BSD master file: {path}")
numbers: Dict[int, str] = {}
sigs: Dict[str, SyscallSignature] = {}
lines = path.read_text(encoding="utf-8", errors="ignore").splitlines()
stack: List[bool] = []
active = True
for line_no, raw in enumerate(lines, start=1):
line = raw.rstrip("\n")
stripped = line.lstrip()
if (
stripped.startswith("#if ")
or stripped.startswith("#ifdef ")
or stripped.startswith("#ifndef ")
):
stack.append(active)
continue
if stripped.startswith("#else"):
if not stack:
raise RuntimeError(f"{path}:{line_no}: #else without #if")
active = False
continue
if stripped.startswith("#endif"):
if not stack:
raise RuntimeError(f"{path}:{line_no}: #endif without #if")
active = stack.pop()
continue
if not active:
continue
m = BSD_MASTER_ENTRY_RE.match(line)
if m is None:
continue
nr = int(m.group("nr"), 10)
proto_blob = strip_c_comments(m.group("proto")).strip()
mp = BSD_MASTER_PROTO_RE.match(proto_blob)
if mp is None:
raise RuntimeError(
f"{path}:{line_no}: cannot parse prototype: {proto_blob!r}"
)
fn = mp.group("fn").strip()
args_blob = mp.group("args").strip()
if fn in {"nosys", "enosys"}:
continue
public_name = normalize_bsd_name(fn)
if public_name == "":
raise RuntimeError(f"{path}:{line_no}: empty normalized name from {fn!r}")
if nr in numbers:
raise RuntimeError(f"{path}:{line_no}: duplicate syscall number {nr}")
if public_name in sigs:
raise RuntimeError(
f"{path}:{line_no}: duplicate syscall name {public_name!r}"
)
args = parse_c_param_list(args_blob, path, line_no)
if len(args) > MAX_ARGS:
raise RuntimeError(
f"{path}:{line_no}: syscall {public_name!r} has {len(args)} args; max supported is {MAX_ARGS}"
)
numbers[nr] = public_name
sigs[public_name] = SyscallSignature(name=public_name, args=tuple(args))
return numbers, sigs
def normalize_bsd_name(fn: str) -> str:
if fn.startswith("sys_"):
return fn[len("sys_"):]
if fn.startswith("__"):
return fn[2:]
return fn
def strip_c_comments(s: str) -> str:
s = LINE_COMMENT_RE.sub("", s)
while True:
new_s = BLOCK_COMMENT_RE.sub("", s)
if new_s == s:
break
s = new_s
return s
def split_top_level_commas(text: str) -> List[str]:
parts: List[str] = []
buf: List[str] = []
depth = 0
in_string = False
string_quote = ""
cursor = 0
while cursor < len(text):
ch = text[cursor]
if in_string:
buf.append(ch)
if ch == "\\" and cursor + 1 < len(text):
buf.append(text[cursor + 1])
cursor += 2
continue
if ch == string_quote:
in_string = False
cursor += 1
continue
if ch in ("'", '"'):
in_string = True
string_quote = ch
buf.append(ch)
cursor += 1
continue
if ch == "(":
depth += 1
elif ch == ")":
depth = max(0, depth - 1)
if ch == "," and depth == 0:
parts.append("".join(buf).strip())
buf = []
cursor += 1
continue
buf.append(ch)
cursor += 1
parts.append("".join(buf).strip())
return parts
def parse_c_param_list(args_blob: str, path: Path, line_no: int) -> List[SyscallArg]:
raw = strip_c_comments(args_blob).strip()
if raw == "" or raw == "void":
return []
raw_params = [p.strip() for p in split_top_level_commas(raw) if p.strip() != ""]
if len(raw_params) == 1 and raw_params[0] == "void":
return []
args: List[SyscallArg] = []
for idx, p in enumerate(raw_params):
ty, name = split_param_decl(p, path, line_no)
if name is None:
name = f"arg{idx}"
if ty == "user_addr_t" and name in {"attrname", "link", "path"}:
ty = "char *"
args.append(SyscallArg(type=ty, name=name))
return args
def split_param_decl(decl: str, path: Path, line_no: int) -> Tuple[str, Optional[str]]:
d = strip_c_comments(decl).strip()
if d == "" or d == "void":
raise RuntimeError(f"{path}:{line_no}: bad parameter decl: {decl!r}")
tokens = _tokenize_decl(d)
ty_tokens, name = _split_type_and_name(tokens)
ty = _format_type(ty_tokens)
if not ty:
raise RuntimeError(
f"{path}:{line_no}: cannot parse parameter type from {decl!r}"
)
return ty, _camel_to_snake(name) if name else None
def _tokenize_decl(s: str) -> list[str]:
out = []
for c in s:
out.append(" * " if c == "*" else c)
return "".join(out).split()
def _split_type_and_name(tokens: list[str]) -> Tuple[list[str], Optional[str]]:
if not tokens:
return [], None
last = tokens[-1]
if last == "*":
return tokens, None
stars, remainder = _split_leading_stars(last)
if stars:
if _is_identifier(remainder):
return tokens[:-1] + ["*"] * stars, remainder
return tokens, None
if _is_identifier(last):
return tokens[:-1], last
return tokens, None
def _format_type(tokens: list[str]) -> str:
formatted: list[str] = []
i = 0
while i < len(tokens):
if tokens[i] != "*":
formatted.append(tokens[i])
i += 1
continue
j = i
while j < len(tokens) and tokens[j] == "*":
j += 1
formatted.append("*" * (j - i))
i = j
return " ".join(formatted).strip()
def _split_leading_stars(token: str) -> Tuple[int, str]:
i = 0
while i < len(token) and token[i] == "*":
i += 1
return i, token[i:]
def _is_identifier(s: str) -> bool:
if not s:
return False
if not (s[0].isalpha() or s[0] == "_"):
return False
return all(c.isalnum() or c == "_" for c in s)
def _camel_to_snake(name: str) -> str:
out = []
for i, c in enumerate(name):
if (
c.isupper()
and i > 0
and (name[i - 1].islower() or (i + 1 < len(name) and name[i + 1].islower()))
):
out.append("_")
out.append(c.lower())
return "".join(out)
def normalize_whitespace(s: str) -> str:
return " ".join(s.split())
def line_number_at_offset(text: str, offset: int) -> int:
return text.count("\n", 0, offset) + 1
def extract_parentheses_payload(
text: str, open_paren_offset: int, path: Path
) -> Tuple[str, int]:
if (
open_paren_offset < 0
or open_paren_offset >= len(text)
or text[open_paren_offset] != "("
):
raise RuntimeError(f"{path}: expected '(' at offset {open_paren_offset}")
depth = 0
cursor = open_paren_offset
start = open_paren_offset + 1
in_string = False
string_quote = ""
while cursor < len(text):
ch = text[cursor]
if in_string:
if ch == "\\":
cursor += 2
continue
if ch == string_quote:
in_string = False
cursor += 1
continue
if ch in ("'", '"'):
in_string = True
string_quote = ch
cursor += 1
continue
if ch == "(":
depth += 1
elif ch == ")":
depth -= 1
if depth == 0:
return text[start:cursor], cursor + 1
cursor += 1
raise RuntimeError(f"{path}: unterminated parentheses payload")
def extract_brace_payload(
text: str, open_brace_offset: int, path: Path
) -> Tuple[str, int]:
if (
open_brace_offset < 0
or open_brace_offset >= len(text)
or text[open_brace_offset] != "{"
):
raise RuntimeError(f"{path}: expected '{{' at offset {open_brace_offset}")
depth = 0
cursor = open_brace_offset
start = open_brace_offset + 1
in_string = False
string_quote = ""
while cursor < len(text):
ch = text[cursor]
if in_string:
if ch == "\\":
cursor += 2
continue
if ch == string_quote:
in_string = False
cursor += 1
continue
if ch in ("'", '"'):
in_string = True
string_quote = ch
cursor += 1
continue
if ch == "{":
depth += 1
elif ch == "}":
depth -= 1
if depth == 0:
return text[start:cursor], cursor + 1
cursor += 1
raise RuntimeError(f"{path}: unterminated brace payload")
def render_vala(*, mach_numbers: Dict[int, str], bsd_numbers: Dict[int, str]) -> str:
out: List[str] = []
out += [
"// AUTO-GENERATED FILE. DO NOT EDIT.\n",
"\n",
"namespace Frida {\n",
"\tpublic extern unowned XnuSyscallSignature[] get_xnu_mach_traps ();\n",
"\tpublic extern unowned XnuSyscallSignature[] get_xnu_bsd_syscalls ();\n",
"\n",
"\tpublic struct XnuSyscallSignature {\n",
"\t\tpublic int nr;\n",
"\t\tpublic string name;\n",
"\t\tpublic uint8 nargs;\n",
f"\t\tpublic XnuSyscallArg args[{MAX_ARGS}];\n",
"\t}\n",
"\n",
"\tpublic struct XnuSyscallArg {\n",
"\t\tpublic string? type;\n",
"\t\tpublic string? name;\n",
"\t}\n",
"\n",
"\tpublic enum XnuMachTrap {\n",
]
for nr, name in sorted(mach_numbers.items(), key=lambda kv: kv[0], reverse=True):
out += [f"\t\t{name.upper()} = {nr},\n"]
out += [
"\t}\n",
"\n",
"\tpublic enum XnuBsdSyscall {\n",
]
for nr, name in sorted(bsd_numbers.items(), key=lambda kv: kv[0]):
out += [f"\t\t{name.upper()} = {nr},\n"]
out += [
"\t}\n",
"}\n",
]
return "".join(out)
def render_c_source(
*,
mach_numbers: Dict[int, str],
bsd_numbers: Dict[int, str],
mach_sigs: Dict[str, SyscallSignature],
bsd_sigs: Dict[str, SyscallSignature],
) -> str:
out: List[str] = []
out += [
"/* AUTO-GENERATED FILE. DO NOT EDIT. */\n",
"\n",
'#include "frida-base.h"\n',
"\n",
]
emit_c_signature_table(
out,
c_var="frida_xnu_mach_traps",
numbers=mach_numbers,
sigs=mach_sigs,
reverse=True,
)
emit_c_signature_table(
out,
c_var="frida_xnu_bsd_syscalls",
numbers=bsd_numbers,
sigs=bsd_sigs,
)
emit_c_table_getter(
out, c_func="frida_get_xnu_mach_traps", c_var="frida_xnu_mach_traps"
)
out += ["\n"]
emit_c_table_getter(
out, c_func="frida_get_xnu_bsd_syscalls", c_var="frida_xnu_bsd_syscalls"
)
return "".join(out)
def emit_c_signature_table(
out: List[str],
*,
c_var: str,
numbers: Dict[int, str],
sigs: Dict[str, SyscallSignature],
reverse: bool = False,
) -> None:
out += [
f"static const FridaXnuSyscallSignature {c_var}[] =\n",
"{\n",
]
for nr, name in sorted(numbers.items(), key=lambda kv: kv[0], reverse=reverse):
sig = sigs[name]
args_parts: List[str] = []
for a in sig.args:
args_parts += [f"{{ {c_escape(a.type)}, {c_escape(a.name)} }}"]
args_blob = ", ".join(args_parts)
if args_blob != "":
out += [
f" {{ {nr}, {c_escape(name)}, {len(sig.args)}, {{ {args_blob} }} }},\n"
]
else:
out += [f" {{ {nr}, {c_escape(name)}, 0, {{}} }},\n"]
out += [
"};\n",
"\n",
]
def emit_c_table_getter(out: List[str], *, c_func: str, c_var: str) -> None:
out += [
"FridaXnuSyscallSignature *\n",
f"{c_func} (int * len)\n",
"{\n",
" if (len != NULL)\n",
f" *len = G_N_ELEMENTS ({c_var});\n",
f" return (FridaXnuSyscallSignature *) {c_var};\n",
"}\n",
]
def c_escape(s: str) -> str:
return '"' + s.replace("\\", "\\\\").replace('"', '\\"') + '"'
if __name__ == "__main__":
raise SystemExit(main())
+542
View File
@@ -0,0 +1,542 @@
/* AUTO-GENERATED FILE. DO NOT EDIT. */
#include "frida-base.h"
static const FridaXnuSyscallSignature frida_xnu_mach_traps[] =
{
{ -10, "mach_vm_allocate", 4, { { "mach_port_name_t", "target" }, { "mach_vm_offset_t *", "addr" }, { "mach_vm_size_t", "size" }, { "int", "flags" } } },
{ -11, "mach_vm_purgable_control", 4, { { "mach_port_name_t", "target" }, { "mach_vm_offset_t", "address" }, { "vm_purgable_t", "control" }, { "int *", "state" } } },
{ -12, "mach_vm_deallocate", 3, { { "mach_port_name_t", "target" }, { "mach_vm_address_t", "address" }, { "mach_vm_size_t", "size" } } },
{ -13, "task_dyld_process_info_notify_get", 2, { { "mach_port_name_array_t", "names_addr" }, { "natural_t *", "names_count_addr" } } },
{ -14, "mach_vm_protect", 5, { { "mach_port_name_t", "target" }, { "mach_vm_address_t", "address" }, { "mach_vm_size_t", "size" }, { "boolean_t", "set_maximum" }, { "vm_prot_t", "new_protection" } } },
{ -15, "mach_vm_map", 6, { { "mach_port_name_t", "target" }, { "mach_vm_offset_t *", "address" }, { "mach_vm_size_t", "size" }, { "mach_vm_offset_t", "mask" }, { "int", "flags" }, { "vm_prot_t", "cur_protection" } } },
{ -16, "mach_port_allocate", 3, { { "mach_port_name_t", "target" }, { "mach_port_right_t", "right" }, { "mach_port_name_t *", "name" } } },
{ -18, "mach_port_deallocate", 2, { { "mach_port_name_t", "target" }, { "mach_port_name_t", "name" } } },
{ -19, "mach_port_mod_refs", 4, { { "mach_port_name_t", "target" }, { "mach_port_name_t", "name" }, { "mach_port_right_t", "right" }, { "mach_port_delta_t", "delta" } } },
{ -20, "mach_port_move_member", 3, { { "mach_port_name_t", "target" }, { "mach_port_name_t", "member" }, { "mach_port_name_t", "after" } } },
{ -21, "mach_port_insert_right", 4, { { "mach_port_name_t", "target" }, { "mach_port_name_t", "name" }, { "mach_port_name_t", "poly" }, { "mach_msg_type_name_t", "poly_poly" } } },
{ -22, "mach_port_insert_member", 3, { { "mach_port_name_t", "target" }, { "mach_port_name_t", "name" }, { "mach_port_name_t", "pset" } } },
{ -23, "mach_port_extract_member", 3, { { "mach_port_name_t", "target" }, { "mach_port_name_t", "name" }, { "mach_port_name_t", "pset" } } },
{ -24, "mach_port_construct", 4, { { "mach_port_name_t", "target" }, { "mach_port_options_t *", "options" }, { "uint64_t", "context" }, { "mach_port_name_t *", "name" } } },
{ -25, "mach_port_destruct", 4, { { "mach_port_name_t", "target" }, { "mach_port_name_t", "name" }, { "mach_port_delta_t", "srdelta" }, { "uint64_t", "guard" } } },
{ -26, "mach_reply_port", 0, {} },
{ -27, "thread_self", 0, {} },
{ -28, "task_self", 0, {} },
{ -29, "host_self", 0, {} },
{ -31, "mach_msg", 7, { { "mach_msg_header_t *", "msg" }, { "mach_msg_option_t", "option" }, { "mach_msg_size_t", "send_size" }, { "mach_msg_size_t", "rcv_size" }, { "mach_port_name_t", "rcv_name" }, { "mach_msg_timeout_t", "timeout" }, { "mach_port_name_t", "notify" } } },
{ -32, "mach_msg_overwrite", 9, { { "mach_msg_header_t *", "msg" }, { "mach_msg_option_t", "option" }, { "mach_msg_size_t", "send_size" }, { "mach_msg_size_t", "rcv_size" }, { "mach_port_name_t", "rcv_name" }, { "mach_msg_timeout_t", "timeout" }, { "mach_msg_priority_t", "priority" }, { "mach_msg_header_t *", "rcv_msg" }, { "mach_msg_size_t", "rcv_limit" } } },
{ -33, "semaphore_signal", 1, { { "mach_port_name_t", "signal_name" } } },
{ -34, "semaphore_signal_all", 1, { { "mach_port_name_t", "signal_name" } } },
{ -35, "semaphore_signal_thread", 2, { { "mach_port_name_t", "signal_name" }, { "mach_port_name_t", "thread_name" } } },
{ -36, "semaphore_wait", 1, { { "mach_port_name_t", "wait_name" } } },
{ -37, "semaphore_wait_signal", 2, { { "mach_port_name_t", "wait_name" }, { "mach_port_name_t", "signal_name" } } },
{ -38, "semaphore_timedwait", 3, { { "mach_port_name_t", "wait_name" }, { "unsigned int", "sec" }, { "clock_res_t", "nsec" } } },
{ -39, "semaphore_timedwait_signal", 4, { { "mach_port_name_t", "wait_name" }, { "mach_port_name_t", "signal_name" }, { "unsigned int", "sec" }, { "clock_res_t", "nsec" } } },
{ -40, "mach_port_get_attributes", 5, { { "mach_port_name_t", "target" }, { "mach_port_name_t", "name" }, { "mach_port_flavor_t", "flavor" }, { "mach_port_info_t", "port_info_out" }, { "mach_msg_type_number_t *", "port_info_out_cnt" } } },
{ -41, "mach_port_guard", 4, { { "mach_port_name_t", "target" }, { "mach_port_name_t", "name" }, { "uint64_t", "guard" }, { "boolean_t", "strict" } } },
{ -42, "mach_port_unguard", 3, { { "mach_port_name_t", "target" }, { "mach_port_name_t", "name" }, { "uint64_t", "guard" } } },
{ -43, "mach_generate_activity_id", 3, { { "mach_port_name_t", "target" }, { "int", "count" }, { "uint64_t *", "activity_id" } } },
{ -44, "task_name_for_pid", 3, { { "mach_port_name_t", "target_tport" }, { "int", "pid" }, { "mach_port_name_t *", "tn" } } },
{ -45, "task_for_pid", 3, { { "mach_port_name_t", "target_tport" }, { "int", "pid" }, { "mach_port_name_t *", "t" } } },
{ -46, "pid_for_task", 2, { { "mach_port_name_t", "t" }, { "int *", "x" } } },
{ -47, "mach_msg2", 8, { { "void *", "data" }, { "mach_msg_option64_t", "options" }, { "uint64_t", "msgh_bits_and_send_size" }, { "uint64_t", "msgh_remote_and_local_port" }, { "uint64_t", "msgh_voucher_and_id" }, { "uint64_t", "desc_count_and_rcv_name" }, { "uint64_t", "rcv_size_and_priority" }, { "uint64_t", "timeout" } } },
{ -48, "macx_swapon", 4, { { "uint64_t", "filename" }, { "int", "flags" }, { "int", "size" }, { "int", "priority" } } },
{ -49, "macx_swapoff", 2, { { "uint64_t", "filename" }, { "int", "flags" } } },
{ -50, "thread_get_special_reply_port", 0, {} },
{ -51, "macx_triggers", 4, { { "int", "hi_water" }, { "int", "low_water" }, { "int", "flags" }, { "mach_port_t", "alert_port" } } },
{ -52, "macx_backing_store_suspend", 1, { { "boolean_t", "suspend" } } },
{ -53, "macx_backing_store_recovery", 1, { { "int", "pid" } } },
{ -58, "pfz_exit", 0, {} },
{ -59, "swtch_pri", 1, { { "int", "pri" } } },
{ -60, "swtch", 0, {} },
{ -61, "thread_switch", 3, { { "mach_port_name_t", "thread_name" }, { "int", "option" }, { "mach_msg_timeout_t", "option_time" } } },
{ -62, "clock_sleep", 5, { { "mach_port_name_t", "clock_name" }, { "sleep_type_t", "sleep_type" }, { "int", "sleep_sec" }, { "int", "sleep_nsec" }, { "mach_timespec_t *", "wakeup_time" } } },
{ -63, "mach_vm_reclaim_update_kernel_accounting", 2, { { "mach_port_name_t", "target_tport" }, { "uint64_t *", "bytes_reclaimed" } } },
{ -70, "host_create_mach_voucher", 4, { { "mach_port_name_t", "host" }, { "mach_voucher_attr_raw_recipe_array_t", "recipes" }, { "int", "recipes_size" }, { "mach_port_name_t *", "voucher" } } },
{ -72, "mach_voucher_extract_attr_recipe", 4, { { "mach_port_name_t", "voucher_name" }, { "mach_voucher_attr_key_t", "key" }, { "mach_voucher_attr_raw_recipe_t", "recipe" }, { "mach_msg_type_number_t *", "recipe_size" } } },
{ -76, "mach_port_type", 3, { { "ipc_space_t", "task" }, { "mach_port_name_t", "name" }, { "mach_port_type_t *", "ptype" } } },
{ -77, "mach_port_request_notification", 7, { { "ipc_space_t", "task" }, { "mach_port_name_t", "name" }, { "mach_msg_id_t", "msgid" }, { "mach_port_mscount_t", "sync" }, { "mach_port_name_t", "notify" }, { "mach_msg_type_name_t", "notify_poly" }, { "mach_port_name_t *", "previous" } } },
{ -88, "exclaves_ctl", 8, { { "mach_port_name_t", "name" }, { "uint32_t", "operation_and_flags" }, { "uint64_t", "identifier" }, { "mach_vm_address_t", "buffer" }, { "mach_vm_size_t", "size" }, { "mach_vm_size_t", "size2" }, { "mach_vm_size_t", "offset" }, { "mach_vm_address_t", "status" } } },
{ -89, "mach_timebase_info", 1, { { "user_addr_t", "info" } } },
{ -90, "mach_wait_until", 1, { { "uint64_t", "deadline" } } },
{ -91, "mk_timer_create", 0, {} },
{ -92, "mk_timer_destroy", 1, { { "mach_port_name_t", "name" } } },
{ -93, "mk_timer_arm", 2, { { "mach_port_name_t", "name" }, { "uint64_t", "expire_time" } } },
{ -94, "mk_timer_cancel", 2, { { "mach_port_name_t", "name" }, { "user_addr_t", "result_time" } } },
{ -95, "mk_timer_arm_leeway", 4, { { "mach_port_name_t", "name" }, { "uint64_t", "mk_timer_flags" }, { "uint64_t", "expire_time" }, { "uint64_t", "mk_leeway" } } },
{ -96, "debug_control_port_for_pid", 3, { { "mach_port_name_t", "target_tport" }, { "int", "pid" }, { "mach_port_name_t *", "t" } } },
{ -100, "iokit_user_client", 8, { { "void *", "userClientRef" }, { "uint32_t", "index" }, { "void *", "p1" }, { "void *", "p2" }, { "void *", "p3" }, { "void *", "p4" }, { "void *", "p5" }, { "void *", "p6" } } },
};
static const FridaXnuSyscallSignature frida_xnu_bsd_syscalls[] =
{
{ 1, "exit", 1, { { "int", "rval" } } },
{ 2, "fork", 0, {} },
{ 3, "read", 3, { { "int", "fd" }, { "user_addr_t", "cbuf" }, { "user_size_t", "nbyte" } } },
{ 4, "write", 3, { { "int", "fd" }, { "user_addr_t", "cbuf" }, { "user_size_t", "nbyte" } } },
{ 5, "open", 3, { { "char *", "path" }, { "int", "flags" }, { "int", "mode" } } },
{ 6, "close", 1, { { "int", "fd" } } },
{ 7, "wait4", 4, { { "int", "pid" }, { "user_addr_t", "status" }, { "int", "options" }, { "user_addr_t", "rusage" } } },
{ 9, "link", 2, { { "char *", "path" }, { "char *", "link" } } },
{ 10, "unlink", 1, { { "char *", "path" } } },
{ 12, "chdir", 1, { { "char *", "path" } } },
{ 13, "fchdir", 1, { { "int", "fd" } } },
{ 14, "mknod", 3, { { "char *", "path" }, { "int", "mode" }, { "int", "dev" } } },
{ 15, "chmod", 2, { { "char *", "path" }, { "int", "mode" } } },
{ 16, "chown", 3, { { "char *", "path" }, { "int", "uid" }, { "int", "gid" } } },
{ 18, "getfsstat", 3, { { "user_addr_t", "buf" }, { "int", "bufsize" }, { "int", "flags" } } },
{ 20, "getpid", 0, {} },
{ 23, "setuid", 1, { { "uid_t", "uid" } } },
{ 24, "getuid", 0, {} },
{ 25, "geteuid", 0, {} },
{ 26, "ptrace", 4, { { "int", "req" }, { "pid_t", "pid" }, { "caddr_t", "addr" }, { "int", "data" } } },
{ 27, "recvmsg", 3, { { "int", "s" }, { "struct msghdr *", "msg" }, { "int", "flags" } } },
{ 28, "sendmsg", 3, { { "int", "s" }, { "caddr_t", "msg" }, { "int", "flags" } } },
{ 29, "recvfrom", 6, { { "int", "s" }, { "void *", "buf" }, { "size_t", "len" }, { "int", "flags" }, { "struct sockaddr *", "from" }, { "int *", "fromlenaddr" } } },
{ 30, "accept", 3, { { "int", "s" }, { "caddr_t", "name" }, { "socklen_t *", "anamelen" } } },
{ 31, "getpeername", 3, { { "int", "fdes" }, { "caddr_t", "asa" }, { "socklen_t *", "alen" } } },
{ 32, "getsockname", 3, { { "int", "fdes" }, { "caddr_t", "asa" }, { "socklen_t *", "alen" } } },
{ 33, "access", 2, { { "char *", "path" }, { "int", "flags" } } },
{ 34, "chflags", 2, { { "char *", "path" }, { "int", "flags" } } },
{ 35, "fchflags", 2, { { "int", "fd" }, { "int", "flags" } } },
{ 36, "sync", 0, {} },
{ 37, "kill", 3, { { "int", "pid" }, { "int", "signum" }, { "int", "posix" } } },
{ 38, "crossarch_trap", 1, { { "uint32_t", "name" } } },
{ 39, "getppid", 0, {} },
{ 41, "dup", 1, { { "u_int", "fd" } } },
{ 42, "pipe", 0, {} },
{ 43, "getegid", 0, {} },
{ 46, "sigaction", 3, { { "int", "signum" }, { "struct __sigaction *", "nsa" }, { "struct sigaction *", "osa" } } },
{ 47, "getgid", 0, {} },
{ 48, "sigprocmask", 3, { { "int", "how" }, { "user_addr_t", "mask" }, { "user_addr_t", "omask" } } },
{ 49, "getlogin", 2, { { "char *", "namebuf" }, { "u_int", "namelen" } } },
{ 50, "setlogin", 1, { { "char *", "namebuf" } } },
{ 51, "acct", 1, { { "char *", "path" } } },
{ 52, "sigpending", 1, { { "struct sigvec *", "osv" } } },
{ 53, "sigaltstack", 2, { { "struct sigaltstack *", "nss" }, { "struct sigaltstack *", "oss" } } },
{ 54, "ioctl", 3, { { "int", "fd" }, { "u_long", "com" }, { "caddr_t", "data" } } },
{ 55, "reboot", 2, { { "int", "opt" }, { "char *", "msg" } } },
{ 56, "revoke", 1, { { "char *", "path" } } },
{ 57, "symlink", 2, { { "char *", "path" }, { "char *", "link" } } },
{ 58, "readlink", 3, { { "char *", "path" }, { "char *", "buf" }, { "int", "count" } } },
{ 59, "execve", 3, { { "char *", "fname" }, { "char **", "argp" }, { "char **", "envp" } } },
{ 60, "umask", 1, { { "int", "newmask" } } },
{ 61, "chroot", 1, { { "char *", "path" } } },
{ 65, "msync", 3, { { "caddr_ut", "addr" }, { "size_ut", "len" }, { "int", "flags" } } },
{ 66, "vfork", 0, {} },
{ 67, "oslog_coproc_reg", 3, { { "const char *", "uuid" }, { "const char *", "file_path" }, { "size_t", "file_path_len" } } },
{ 68, "oslog_coproc", 7, { { "void *", "buff" }, { "uint64_t", "buff_len" }, { "uint32_t", "type" }, { "const char *", "uuid" }, { "uint64_t", "timestamp" }, { "uint32_t", "offset" }, { "uint32_t", "stream_log" } } },
{ 73, "munmap", 2, { { "caddr_ut", "addr" }, { "size_ut", "len" } } },
{ 74, "mprotect", 3, { { "caddr_ut", "addr" }, { "size_ut", "len" }, { "int", "prot" } } },
{ 75, "madvise", 3, { { "caddr_ut", "addr" }, { "size_ut", "len" }, { "int", "behav" } } },
{ 78, "mincore", 3, { { "caddr_ut", "addr" }, { "size_ut", "len" }, { "user_addr_t", "vec" } } },
{ 79, "getgroups", 2, { { "u_int", "gidsetsize" }, { "gid_t *", "gidset" } } },
{ 80, "setgroups", 2, { { "u_int", "gidsetsize" }, { "gid_t *", "gidset" } } },
{ 81, "getpgrp", 0, {} },
{ 82, "setpgid", 2, { { "int", "pid" }, { "int", "pgid" } } },
{ 83, "setitimer", 3, { { "u_int", "which" }, { "struct itimerval *", "itv" }, { "struct itimerval *", "oitv" } } },
{ 85, "swapon", 0, {} },
{ 86, "getitimer", 2, { { "u_int", "which" }, { "struct itimerval *", "itv" } } },
{ 89, "getdtablesize", 0, {} },
{ 90, "dup2", 2, { { "u_int", "from" }, { "u_int", "to" } } },
{ 92, "fcntl", 3, { { "int", "fd" }, { "int", "cmd" }, { "long", "arg" } } },
{ 93, "select", 5, { { "int", "nd" }, { "u_int32_t *", "in" }, { "u_int32_t *", "ou" }, { "u_int32_t *", "ex" }, { "struct timeval *", "tv" } } },
{ 95, "fsync", 1, { { "int", "fd" } } },
{ 96, "setpriority", 3, { { "int", "which" }, { "id_t", "who" }, { "int", "prio" } } },
{ 97, "socket", 3, { { "int", "domain" }, { "int", "type" }, { "int", "protocol" } } },
{ 98, "connect", 3, { { "int", "s" }, { "caddr_t", "name" }, { "socklen_t", "namelen" } } },
{ 100, "getpriority", 2, { { "int", "which" }, { "id_t", "who" } } },
{ 104, "bind", 3, { { "int", "s" }, { "caddr_t", "name" }, { "socklen_t", "namelen" } } },
{ 105, "setsockopt", 5, { { "int", "s" }, { "int", "level" }, { "int", "name" }, { "caddr_t", "val" }, { "socklen_t", "valsize" } } },
{ 106, "listen", 2, { { "int", "s" }, { "int", "backlog" } } },
{ 111, "sigsuspend", 1, { { "sigset_t", "mask" } } },
{ 116, "gettimeofday", 3, { { "struct timeval *", "tp" }, { "struct timezone *", "tzp" }, { "uint64_t *", "mach_absolute_time" } } },
{ 117, "getrusage", 2, { { "int", "who" }, { "struct rusage *", "rusage" } } },
{ 118, "getsockopt", 5, { { "int", "s" }, { "int", "level" }, { "int", "name" }, { "caddr_t", "val" }, { "socklen_t *", "avalsize" } } },
{ 120, "readv", 3, { { "int", "fd" }, { "struct iovec *", "iovp" }, { "u_int", "iovcnt" } } },
{ 121, "writev", 3, { { "int", "fd" }, { "struct iovec *", "iovp" }, { "u_int", "iovcnt" } } },
{ 122, "settimeofday", 2, { { "struct timeval *", "tv" }, { "struct timezone *", "tzp" } } },
{ 123, "fchown", 3, { { "int", "fd" }, { "int", "uid" }, { "int", "gid" } } },
{ 124, "fchmod", 2, { { "int", "fd" }, { "int", "mode" } } },
{ 126, "setreuid", 2, { { "uid_t", "ruid" }, { "uid_t", "euid" } } },
{ 127, "setregid", 2, { { "gid_t", "rgid" }, { "gid_t", "egid" } } },
{ 128, "rename", 2, { { "char *", "from" }, { "char *", "to" } } },
{ 131, "flock", 2, { { "int", "fd" }, { "int", "how" } } },
{ 132, "mkfifo", 2, { { "char *", "path" }, { "int", "mode" } } },
{ 133, "sendto", 6, { { "int", "s" }, { "caddr_t", "buf" }, { "size_t", "len" }, { "int", "flags" }, { "caddr_t", "to" }, { "socklen_t", "tolen" } } },
{ 134, "shutdown", 2, { { "int", "s" }, { "int", "how" } } },
{ 135, "socketpair", 4, { { "int", "domain" }, { "int", "type" }, { "int", "protocol" }, { "int *", "rsv" } } },
{ 136, "mkdir", 2, { { "char *", "path" }, { "int", "mode" } } },
{ 137, "rmdir", 1, { { "char *", "path" } } },
{ 138, "utimes", 2, { { "char *", "path" }, { "struct timeval *", "tptr" } } },
{ 139, "futimes", 2, { { "int", "fd" }, { "struct timeval *", "tptr" } } },
{ 140, "adjtime", 2, { { "struct timeval *", "delta" }, { "struct timeval *", "olddelta" } } },
{ 142, "gethostuuid", 2, { { "unsigned char *", "uuid_buf" }, { "const struct timespec *", "timeoutp" } } },
{ 147, "setsid", 0, {} },
{ 151, "getpgid", 1, { { "pid_t", "pid" } } },
{ 152, "setprivexec", 1, { { "int", "flag" } } },
{ 153, "pread", 4, { { "int", "fd" }, { "user_addr_t", "buf" }, { "user_size_t", "nbyte" }, { "off_t", "offset" } } },
{ 154, "pwrite", 4, { { "int", "fd" }, { "user_addr_t", "buf" }, { "user_size_t", "nbyte" }, { "off_t", "offset" } } },
{ 155, "nfssvc", 2, { { "int", "flag" }, { "caddr_t", "argp" } } },
{ 157, "statfs", 2, { { "char *", "path" }, { "struct statfs *", "buf" } } },
{ 158, "fstatfs", 2, { { "int", "fd" }, { "struct statfs *", "buf" } } },
{ 159, "unmount", 2, { { "char *", "path" }, { "int", "flags" } } },
{ 161, "getfh", 2, { { "char *", "fname" }, { "fhandle_t *", "fhp" } } },
{ 164, "funmount", 2, { { "int", "fd" }, { "int", "flags" } } },
{ 165, "quotactl", 4, { { "const char *", "path" }, { "int", "cmd" }, { "int", "uid" }, { "caddr_t", "arg" } } },
{ 167, "mount", 4, { { "char *", "type" }, { "char *", "path" }, { "int", "flags" }, { "caddr_t", "data" } } },
{ 169, "csops", 4, { { "pid_t", "pid" }, { "uint32_t", "ops" }, { "user_addr_t", "useraddr" }, { "user_size_t", "usersize" } } },
{ 170, "csops_audittoken", 5, { { "pid_t", "pid" }, { "uint32_t", "ops" }, { "user_addr_t", "useraddr" }, { "user_size_t", "usersize" }, { "user_addr_t", "uaudittoken" } } },
{ 173, "waitid", 4, { { "idtype_t", "idtype" }, { "id_t", "id" }, { "siginfo_t *", "infop" }, { "int", "options" } } },
{ 177, "kdebug_typefilter", 2, { { "void **", "addr" }, { "size_t *", "size" } } },
{ 178, "kdebug_trace_string", 3, { { "uint32_t", "debugid" }, { "uint64_t", "str_id" }, { "const char *", "str" } } },
{ 179, "kdebug_trace64", 5, { { "uint32_t", "code" }, { "uint64_t", "arg1" }, { "uint64_t", "arg2" }, { "uint64_t", "arg3" }, { "uint64_t", "arg4" } } },
{ 180, "kdebug_trace", 5, { { "uint32_t", "code" }, { "u_long", "arg1" }, { "u_long", "arg2" }, { "u_long", "arg3" }, { "u_long", "arg4" } } },
{ 181, "setgid", 1, { { "gid_t", "gid" } } },
{ 182, "setegid", 1, { { "gid_t", "egid" } } },
{ 183, "seteuid", 1, { { "uid_t", "euid" } } },
{ 184, "sigreturn", 3, { { "struct ucontext *", "uctx" }, { "int", "infostyle" }, { "user_addr_t", "token" } } },
{ 185, "panic_with_data", 5, { { "uuid_t", "uuid" }, { "void *", "addr" }, { "uint32_t", "len" }, { "uint32_t", "flags" }, { "const char *", "msg" } } },
{ 186, "thread_selfcounts", 3, { { "uint32_t", "kind" }, { "user_addr_t", "buf" }, { "user_size_t", "size" } } },
{ 187, "fdatasync", 1, { { "int", "fd" } } },
{ 188, "stat", 2, { { "char *", "path" }, { "user_addr_t", "ub" } } },
{ 189, "fstat", 2, { { "int", "fd" }, { "user_addr_t", "ub" } } },
{ 190, "lstat", 2, { { "char *", "path" }, { "user_addr_t", "ub" } } },
{ 191, "pathconf", 2, { { "char *", "path" }, { "int", "name" } } },
{ 192, "fpathconf", 2, { { "int", "fd" }, { "int", "name" } } },
{ 194, "getrlimit", 2, { { "u_int", "which" }, { "struct rlimit *", "rlp" } } },
{ 195, "setrlimit", 2, { { "u_int", "which" }, { "struct rlimit *", "rlp" } } },
{ 196, "getdirentries", 4, { { "int", "fd" }, { "char *", "buf" }, { "u_int", "count" }, { "long *", "basep" } } },
{ 197, "mmap", 6, { { "caddr_ut", "addr" }, { "size_ut", "len" }, { "int", "prot" }, { "int", "flags" }, { "int", "fd" }, { "off_t", "pos" } } },
{ 199, "lseek", 3, { { "int", "fd" }, { "off_t", "offset" }, { "int", "whence" } } },
{ 200, "truncate", 2, { { "char *", "path" }, { "off_t", "length" } } },
{ 201, "ftruncate", 2, { { "int", "fd" }, { "off_t", "length" } } },
{ 202, "sysctl", 6, { { "int *", "name" }, { "u_int", "namelen" }, { "void *", "old" }, { "size_t *", "oldlenp" }, { "void *", "new" }, { "size_t", "newlen" } } },
{ 203, "mlock", 2, { { "caddr_ut", "addr" }, { "size_ut", "len" } } },
{ 204, "munlock", 2, { { "caddr_ut", "addr" }, { "size_ut", "len" } } },
{ 205, "undelete", 1, { { "char *", "path" } } },
{ 216, "open_dprotected_np", 5, { { "char *", "path" }, { "int", "flags" }, { "int", "class" }, { "int", "dpflags" }, { "int", "mode" } } },
{ 217, "fsgetpath_ext", 5, { { "user_addr_t", "buf" }, { "size_t", "bufsize" }, { "user_addr_t", "fsid" }, { "uint64_t", "objid" }, { "uint32_t", "options" } } },
{ 218, "openat_dprotected_np", 7, { { "int", "fd" }, { "char *", "path" }, { "int", "flags" }, { "int", "class" }, { "int", "dpflags" }, { "int", "mode" }, { "int", "authfd" } } },
{ 220, "getattrlist", 5, { { "const char *", "path" }, { "struct attrlist *", "alist" }, { "void *", "attribute_buffer" }, { "size_t", "buffer_size" }, { "u_long", "options" } } },
{ 221, "setattrlist", 5, { { "const char *", "path" }, { "struct attrlist *", "alist" }, { "void *", "attribute_buffer" }, { "size_t", "buffer_size" }, { "u_long", "options" } } },
{ 222, "getdirentriesattr", 8, { { "int", "fd" }, { "struct attrlist *", "alist" }, { "void *", "buffer" }, { "size_t", "buffersize" }, { "u_long *", "count" }, { "u_long *", "basep" }, { "u_long *", "newstate" }, { "u_long", "options" } } },
{ 223, "exchangedata", 3, { { "const char *", "path1" }, { "const char *", "path2" }, { "u_long", "options" } } },
{ 225, "searchfs", 6, { { "const char *", "path" }, { "struct fssearchblock *", "searchblock" }, { "uint32_t *", "nummatches" }, { "uint32_t", "scriptcode" }, { "uint32_t", "options" }, { "struct searchstate *", "state" } } },
{ 226, "delete", 1, { { "char *", "path" } } },
{ 227, "copyfile", 4, { { "char *", "from" }, { "char *", "to" }, { "int", "mode" }, { "int", "flags" } } },
{ 228, "fgetattrlist", 5, { { "int", "fd" }, { "struct attrlist *", "alist" }, { "void *", "attribute_buffer" }, { "size_t", "buffer_size" }, { "u_long", "options" } } },
{ 229, "fsetattrlist", 5, { { "int", "fd" }, { "struct attrlist *", "alist" }, { "void *", "attribute_buffer" }, { "size_t", "buffer_size" }, { "u_long", "options" } } },
{ 230, "poll", 3, { { "struct pollfd *", "fds" }, { "u_int", "nfds" }, { "int", "timeout" } } },
{ 234, "getxattr", 6, { { "char *", "path" }, { "char *", "attrname" }, { "user_addr_t", "value" }, { "size_t", "size" }, { "uint32_t", "position" }, { "int", "options" } } },
{ 235, "fgetxattr", 6, { { "int", "fd" }, { "char *", "attrname" }, { "user_addr_t", "value" }, { "size_t", "size" }, { "uint32_t", "position" }, { "int", "options" } } },
{ 236, "setxattr", 6, { { "char *", "path" }, { "char *", "attrname" }, { "user_addr_t", "value" }, { "size_t", "size" }, { "uint32_t", "position" }, { "int", "options" } } },
{ 237, "fsetxattr", 6, { { "int", "fd" }, { "char *", "attrname" }, { "user_addr_t", "value" }, { "size_t", "size" }, { "uint32_t", "position" }, { "int", "options" } } },
{ 238, "removexattr", 3, { { "char *", "path" }, { "char *", "attrname" }, { "int", "options" } } },
{ 239, "fremovexattr", 3, { { "int", "fd" }, { "char *", "attrname" }, { "int", "options" } } },
{ 240, "listxattr", 4, { { "char *", "path" }, { "user_addr_t", "namebuf" }, { "size_t", "bufsize" }, { "int", "options" } } },
{ 241, "flistxattr", 4, { { "int", "fd" }, { "user_addr_t", "namebuf" }, { "size_t", "bufsize" }, { "int", "options" } } },
{ 242, "fsctl", 4, { { "const char *", "path" }, { "u_long", "cmd" }, { "caddr_t", "data" }, { "u_int", "options" } } },
{ 243, "initgroups", 3, { { "u_int", "gidsetsize" }, { "gid_t *", "gidset" }, { "int", "gmuid" } } },
{ 244, "posix_spawn", 5, { { "pid_t *", "pid" }, { "const char *", "path" }, { "const struct _posix_spawn_args_desc *", "adesc" }, { "char **", "argv" }, { "char **", "envp" } } },
{ 245, "ffsctl", 4, { { "int", "fd" }, { "u_long", "cmd" }, { "caddr_t", "data" }, { "u_int", "options" } } },
{ 248, "fhopen", 2, { { "const struct fhandle *", "u_fhp" }, { "int", "flags" } } },
{ 250, "minherit", 3, { { "caddr_ut", "addr" }, { "size_ut", "len" }, { "int", "inherit" } } },
{ 251, "semsys", 5, { { "u_int", "which" }, { "int", "a2" }, { "int", "a3" }, { "int", "a4" }, { "int", "a5" } } },
{ 252, "msgsys", 5, { { "u_int", "which" }, { "int", "a2" }, { "int", "a3" }, { "int", "a4" }, { "int", "a5" } } },
{ 253, "shmsys", 4, { { "u_int", "which" }, { "int", "a2" }, { "int", "a3" }, { "int", "a4" } } },
{ 254, "semctl", 4, { { "int", "semid" }, { "int", "semnum" }, { "int", "cmd" }, { "semun_t", "arg" } } },
{ 255, "semget", 3, { { "key_t", "key" }, { "int", "nsems" }, { "int", "semflg" } } },
{ 256, "semop", 3, { { "int", "semid" }, { "struct sembuf *", "sops" }, { "int", "nsops" } } },
{ 258, "msgctl", 3, { { "int", "msqid" }, { "int", "cmd" }, { "struct msqid_ds *", "buf" } } },
{ 259, "msgget", 2, { { "key_t", "key" }, { "int", "msgflg" } } },
{ 260, "msgsnd", 4, { { "int", "msqid" }, { "void *", "msgp" }, { "size_t", "msgsz" }, { "int", "msgflg" } } },
{ 261, "msgrcv", 5, { { "int", "msqid" }, { "void *", "msgp" }, { "size_t", "msgsz" }, { "long", "msgtyp" }, { "int", "msgflg" } } },
{ 262, "shmat", 3, { { "int", "shmid" }, { "void *", "shmaddr" }, { "int", "shmflg" } } },
{ 263, "shmctl", 3, { { "int", "shmid" }, { "int", "cmd" }, { "struct shmid_ds *", "buf" } } },
{ 264, "shmdt", 1, { { "void *", "shmaddr" } } },
{ 265, "shmget", 3, { { "key_t", "key" }, { "size_t", "size" }, { "int", "shmflg" } } },
{ 266, "shm_open", 3, { { "const char *", "name" }, { "int", "oflag" }, { "int", "mode" } } },
{ 267, "shm_unlink", 1, { { "const char *", "name" } } },
{ 268, "sem_open", 4, { { "const char *", "name" }, { "int", "oflag" }, { "int", "mode" }, { "int", "value" } } },
{ 269, "sem_close", 1, { { "sem_t *", "sem" } } },
{ 270, "sem_unlink", 1, { { "const char *", "name" } } },
{ 271, "sem_wait", 1, { { "sem_t *", "sem" } } },
{ 272, "sem_trywait", 1, { { "sem_t *", "sem" } } },
{ 273, "sem_post", 1, { { "sem_t *", "sem" } } },
{ 274, "sysctlbyname", 6, { { "const char *", "name" }, { "size_t", "namelen" }, { "void *", "old" }, { "size_t *", "oldlenp" }, { "void *", "new" }, { "size_t", "newlen" } } },
{ 277, "open_extended", 6, { { "char *", "path" }, { "int", "flags" }, { "uid_t", "uid" }, { "gid_t", "gid" }, { "int", "mode" }, { "user_addr_t", "xsecurity" } } },
{ 278, "umask_extended", 2, { { "int", "newmask" }, { "user_addr_t", "xsecurity" } } },
{ 279, "stat_extended", 4, { { "char *", "path" }, { "user_addr_t", "ub" }, { "user_addr_t", "xsecurity" }, { "user_addr_t", "xsecurity_size" } } },
{ 280, "lstat_extended", 4, { { "char *", "path" }, { "user_addr_t", "ub" }, { "user_addr_t", "xsecurity" }, { "user_addr_t", "xsecurity_size" } } },
{ 281, "fstat_extended", 4, { { "int", "fd" }, { "user_addr_t", "ub" }, { "user_addr_t", "xsecurity" }, { "user_addr_t", "xsecurity_size" } } },
{ 282, "chmod_extended", 5, { { "char *", "path" }, { "uid_t", "uid" }, { "gid_t", "gid" }, { "int", "mode" }, { "user_addr_t", "xsecurity" } } },
{ 283, "fchmod_extended", 5, { { "int", "fd" }, { "uid_t", "uid" }, { "gid_t", "gid" }, { "int", "mode" }, { "user_addr_t", "xsecurity" } } },
{ 284, "access_extended", 4, { { "user_addr_t", "entries" }, { "size_t", "size" }, { "user_addr_t", "results" }, { "uid_t", "uid" } } },
{ 285, "settid", 2, { { "uid_t", "uid" }, { "gid_t", "gid" } } },
{ 286, "gettid", 2, { { "uid_t *", "uidp" }, { "gid_t *", "gidp" } } },
{ 287, "setsgroups", 2, { { "int", "setlen" }, { "user_addr_t", "guidset" } } },
{ 288, "getsgroups", 2, { { "user_addr_t", "setlen" }, { "user_addr_t", "guidset" } } },
{ 289, "setwgroups", 2, { { "int", "setlen" }, { "user_addr_t", "guidset" } } },
{ 290, "getwgroups", 2, { { "user_addr_t", "setlen" }, { "user_addr_t", "guidset" } } },
{ 291, "mkfifo_extended", 5, { { "char *", "path" }, { "uid_t", "uid" }, { "gid_t", "gid" }, { "int", "mode" }, { "user_addr_t", "xsecurity" } } },
{ 292, "mkdir_extended", 5, { { "char *", "path" }, { "uid_t", "uid" }, { "gid_t", "gid" }, { "int", "mode" }, { "user_addr_t", "xsecurity" } } },
{ 293, "identitysvc", 2, { { "int", "opcode" }, { "user_addr_t", "message" } } },
{ 294, "shared_region_check_np", 1, { { "uint64_t *", "start_address" } } },
{ 296, "vm_pressure_monitor", 3, { { "int", "wait_for_pressure" }, { "int", "nsecs_monitored" }, { "uint32_t *", "pages_reclaimed" } } },
{ 297, "psynch_rw_longrdlock", 5, { { "user_addr_t", "rwlock" }, { "uint32_t", "lgenval" }, { "uint32_t", "ugenval" }, { "uint32_t", "rw_wc" }, { "int", "flags" } } },
{ 298, "psynch_rw_yieldwrlock", 5, { { "user_addr_t", "rwlock" }, { "uint32_t", "lgenval" }, { "uint32_t", "ugenval" }, { "uint32_t", "rw_wc" }, { "int", "flags" } } },
{ 299, "psynch_rw_downgrade", 5, { { "user_addr_t", "rwlock" }, { "uint32_t", "lgenval" }, { "uint32_t", "ugenval" }, { "uint32_t", "rw_wc" }, { "int", "flags" } } },
{ 300, "psynch_rw_upgrade", 5, { { "user_addr_t", "rwlock" }, { "uint32_t", "lgenval" }, { "uint32_t", "ugenval" }, { "uint32_t", "rw_wc" }, { "int", "flags" } } },
{ 301, "psynch_mutexwait", 5, { { "user_addr_t", "mutex" }, { "uint32_t", "mgen" }, { "uint32_t", "ugen" }, { "uint64_t", "tid" }, { "uint32_t", "flags" } } },
{ 302, "psynch_mutexdrop", 5, { { "user_addr_t", "mutex" }, { "uint32_t", "mgen" }, { "uint32_t", "ugen" }, { "uint64_t", "tid" }, { "uint32_t", "flags" } } },
{ 303, "psynch_cvbroad", 7, { { "user_addr_t", "cv" }, { "uint64_t", "cvlsgen" }, { "uint64_t", "cvudgen" }, { "uint32_t", "flags" }, { "user_addr_t", "mutex" }, { "uint64_t", "mugen" }, { "uint64_t", "tid" } } },
{ 304, "psynch_cvsignal", 8, { { "user_addr_t", "cv" }, { "uint64_t", "cvlsgen" }, { "uint32_t", "cvugen" }, { "int", "thread_port" }, { "user_addr_t", "mutex" }, { "uint64_t", "mugen" }, { "uint64_t", "tid" }, { "uint32_t", "flags" } } },
{ 305, "psynch_cvwait", 8, { { "user_addr_t", "cv" }, { "uint64_t", "cvlsgen" }, { "uint32_t", "cvugen" }, { "user_addr_t", "mutex" }, { "uint64_t", "mugen" }, { "uint32_t", "flags" }, { "int64_t", "sec" }, { "uint32_t", "nsec" } } },
{ 306, "psynch_rw_rdlock", 5, { { "user_addr_t", "rwlock" }, { "uint32_t", "lgenval" }, { "uint32_t", "ugenval" }, { "uint32_t", "rw_wc" }, { "int", "flags" } } },
{ 307, "psynch_rw_wrlock", 5, { { "user_addr_t", "rwlock" }, { "uint32_t", "lgenval" }, { "uint32_t", "ugenval" }, { "uint32_t", "rw_wc" }, { "int", "flags" } } },
{ 308, "psynch_rw_unlock", 5, { { "user_addr_t", "rwlock" }, { "uint32_t", "lgenval" }, { "uint32_t", "ugenval" }, { "uint32_t", "rw_wc" }, { "int", "flags" } } },
{ 309, "psynch_rw_unlock2", 5, { { "user_addr_t", "rwlock" }, { "uint32_t", "lgenval" }, { "uint32_t", "ugenval" }, { "uint32_t", "rw_wc" }, { "int", "flags" } } },
{ 310, "getsid", 1, { { "pid_t", "pid" } } },
{ 311, "settid_with_pid", 2, { { "pid_t", "pid" }, { "int", "assume" } } },
{ 312, "psynch_cvclrprepost", 7, { { "user_addr_t", "cv" }, { "uint32_t", "cvgen" }, { "uint32_t", "cvugen" }, { "uint32_t", "cvsgen" }, { "uint32_t", "prepocnt" }, { "uint32_t", "preposeq" }, { "uint32_t", "flags" } } },
{ 313, "aio_fsync", 2, { { "int", "op" }, { "user_addr_t", "aiocbp" } } },
{ 314, "aio_return", 1, { { "user_addr_t", "aiocbp" } } },
{ 315, "aio_suspend", 3, { { "user_addr_t", "aiocblist" }, { "int", "nent" }, { "user_addr_t", "timeoutp" } } },
{ 316, "aio_cancel", 2, { { "int", "fd" }, { "user_addr_t", "aiocbp" } } },
{ 317, "aio_error", 1, { { "user_addr_t", "aiocbp" } } },
{ 318, "aio_read", 1, { { "user_addr_t", "aiocbp" } } },
{ 319, "aio_write", 1, { { "user_addr_t", "aiocbp" } } },
{ 320, "lio_listio", 4, { { "int", "mode" }, { "user_addr_t", "aiocblist" }, { "int", "nent" }, { "user_addr_t", "sigp" } } },
{ 322, "iopolicysys", 2, { { "int", "cmd" }, { "void *", "arg" } } },
{ 323, "process_policy", 7, { { "int", "scope" }, { "int", "action" }, { "int", "policy" }, { "int", "policy_subtype" }, { "user_addr_t", "attrp" }, { "pid_t", "target_pid" }, { "uint64_t", "target_threadid" } } },
{ 324, "mlockall", 1, { { "int", "how" } } },
{ 325, "munlockall", 1, { { "int", "how" } } },
{ 327, "issetugid", 0, {} },
{ 328, "pthread_kill", 2, { { "int", "thread_port" }, { "int", "sig" } } },
{ 329, "pthread_sigmask", 3, { { "int", "how" }, { "user_addr_t", "set" }, { "user_addr_t", "oset" } } },
{ 330, "sigwait", 2, { { "user_addr_t", "set" }, { "user_addr_t", "sig" } } },
{ 331, "disable_threadsignal", 1, { { "int", "value" } } },
{ 332, "pthread_markcancel", 1, { { "int", "thread_port" } } },
{ 333, "pthread_canceled", 1, { { "int", "action" } } },
{ 334, "semwait_signal", 6, { { "int", "cond_sem" }, { "int", "mutex_sem" }, { "int", "timeout" }, { "int", "relative" }, { "int64_t", "tv_sec" }, { "int32_t", "tv_nsec" } } },
{ 336, "proc_info", 6, { { "int32_t", "callnum" }, { "int32_t", "pid" }, { "uint32_t", "flavor" }, { "uint64_t", "arg" }, { "user_addr_t", "buffer" }, { "int32_t", "buffersize" } } },
{ 337, "sendfile", 6, { { "int", "fd" }, { "int", "s" }, { "off_t", "offset" }, { "off_t *", "nbytes" }, { "struct sf_hdtr *", "hdtr" }, { "int", "flags" } } },
{ 338, "stat64", 2, { { "char *", "path" }, { "user_addr_t", "ub" } } },
{ 339, "fstat64", 2, { { "int", "fd" }, { "user_addr_t", "ub" } } },
{ 340, "lstat64", 2, { { "char *", "path" }, { "user_addr_t", "ub" } } },
{ 341, "stat64_extended", 4, { { "char *", "path" }, { "user_addr_t", "ub" }, { "user_addr_t", "xsecurity" }, { "user_addr_t", "xsecurity_size" } } },
{ 342, "lstat64_extended", 4, { { "char *", "path" }, { "user_addr_t", "ub" }, { "user_addr_t", "xsecurity" }, { "user_addr_t", "xsecurity_size" } } },
{ 343, "fstat64_extended", 4, { { "int", "fd" }, { "user_addr_t", "ub" }, { "user_addr_t", "xsecurity" }, { "user_addr_t", "xsecurity_size" } } },
{ 344, "getdirentries64", 4, { { "int", "fd" }, { "void *", "buf" }, { "user_size_t", "bufsize" }, { "off_t *", "position" } } },
{ 345, "statfs64", 2, { { "char *", "path" }, { "struct statfs64 *", "buf" } } },
{ 346, "fstatfs64", 2, { { "int", "fd" }, { "struct statfs64 *", "buf" } } },
{ 347, "getfsstat64", 3, { { "user_addr_t", "buf" }, { "int", "bufsize" }, { "int", "flags" } } },
{ 348, "pthread_chdir", 1, { { "char *", "path" } } },
{ 349, "pthread_fchdir", 1, { { "int", "fd" } } },
{ 350, "audit", 2, { { "void *", "record" }, { "int", "length" } } },
{ 351, "auditon", 3, { { "int", "cmd" }, { "void *", "data" }, { "int", "length" } } },
{ 353, "getauid", 1, { { "au_id_t *", "auid" } } },
{ 354, "setauid", 1, { { "au_id_t *", "auid" } } },
{ 357, "getaudit_addr", 2, { { "struct auditinfo_addr *", "auditinfo_addr" }, { "int", "length" } } },
{ 358, "setaudit_addr", 2, { { "struct auditinfo_addr *", "auditinfo_addr" }, { "int", "length" } } },
{ 359, "auditctl", 1, { { "char *", "path" } } },
{ 360, "bsdthread_create", 5, { { "user_addr_t", "func" }, { "user_addr_t", "func_arg" }, { "user_addr_t", "stack" }, { "user_addr_t", "pthread" }, { "uint32_t", "flags" } } },
{ 361, "bsdthread_terminate", 4, { { "user_addr_t", "stackaddr" }, { "size_t", "freesize" }, { "uint32_t", "port" }, { "user_addr_t", "sema_or_ulock" } } },
{ 362, "kqueue", 0, {} },
{ 363, "kevent", 6, { { "int", "fd" }, { "const struct kevent *", "changelist" }, { "int", "nchanges" }, { "struct kevent *", "eventlist" }, { "int", "nevents" }, { "const struct timespec *", "timeout" } } },
{ 364, "lchown", 3, { { "char *", "path" }, { "uid_t", "owner" }, { "gid_t", "group" } } },
{ 366, "bsdthread_register", 7, { { "user_addr_t", "threadstart" }, { "user_addr_t", "wqthread" }, { "uint32_t", "flags" }, { "user_addr_t", "stack_addr_hint" }, { "user_addr_t", "targetconc_ptr" }, { "uint32_t", "dispatchqueue_offset" }, { "uint32_t", "tsd_offset" } } },
{ 367, "workq_open", 0, {} },
{ 368, "workq_kernreturn", 4, { { "int", "options" }, { "user_addr_t", "item" }, { "int", "affinity" }, { "int", "prio" } } },
{ 369, "kevent64", 7, { { "int", "fd" }, { "const struct kevent64_s *", "changelist" }, { "int", "nchanges" }, { "struct kevent64_s *", "eventlist" }, { "int", "nevents" }, { "unsigned int", "flags" }, { "const struct timespec *", "timeout" } } },
{ 372, "thread_selfid", 0, {} },
{ 373, "ledger", 4, { { "int", "cmd" }, { "caddr_t", "arg1" }, { "caddr_t", "arg2" }, { "caddr_t", "arg3" } } },
{ 374, "kevent_qos", 8, { { "int", "fd" }, { "const struct kevent_qos_s *", "changelist" }, { "int", "nchanges" }, { "struct kevent_qos_s *", "eventlist" }, { "int", "nevents" }, { "void *", "data_out" }, { "size_t *", "data_available" }, { "unsigned int", "flags" } } },
{ 375, "kevent_id", 8, { { "uint64_t", "id" }, { "const struct kevent_qos_s *", "changelist" }, { "int", "nchanges" }, { "struct kevent_qos_s *", "eventlist" }, { "int", "nevents" }, { "void *", "data_out" }, { "size_t *", "data_available" }, { "unsigned int", "flags" } } },
{ 380, "mac_execve", 4, { { "char *", "fname" }, { "char **", "argp" }, { "char **", "envp" }, { "struct mac *", "mac_p" } } },
{ 381, "mac_syscall", 3, { { "char *", "policy" }, { "int", "call" }, { "user_addr_t", "arg" } } },
{ 382, "mac_get_file", 2, { { "char *", "path_p" }, { "struct mac *", "mac_p" } } },
{ 383, "mac_set_file", 2, { { "char *", "path_p" }, { "struct mac *", "mac_p" } } },
{ 384, "mac_get_link", 2, { { "char *", "path_p" }, { "struct mac *", "mac_p" } } },
{ 385, "mac_set_link", 2, { { "char *", "path_p" }, { "struct mac *", "mac_p" } } },
{ 386, "mac_get_proc", 1, { { "struct mac *", "mac_p" } } },
{ 387, "mac_set_proc", 1, { { "struct mac *", "mac_p" } } },
{ 388, "mac_get_fd", 2, { { "int", "fd" }, { "struct mac *", "mac_p" } } },
{ 389, "mac_set_fd", 2, { { "int", "fd" }, { "struct mac *", "mac_p" } } },
{ 390, "mac_get_pid", 2, { { "pid_t", "pid" }, { "struct mac *", "mac_p" } } },
{ 394, "pselect", 6, { { "int", "nd" }, { "u_int32_t *", "in" }, { "u_int32_t *", "ou" }, { "u_int32_t *", "ex" }, { "const struct timespec *", "ts" }, { "const struct sigset_t *", "mask" } } },
{ 395, "pselect_nocancel", 6, { { "int", "nd" }, { "u_int32_t *", "in" }, { "u_int32_t *", "ou" }, { "u_int32_t *", "ex" }, { "const struct timespec *", "ts" }, { "const struct sigset_t *", "mask" } } },
{ 396, "read_nocancel", 3, { { "int", "fd" }, { "user_addr_t", "cbuf" }, { "user_size_t", "nbyte" } } },
{ 397, "write_nocancel", 3, { { "int", "fd" }, { "user_addr_t", "cbuf" }, { "user_size_t", "nbyte" } } },
{ 398, "open_nocancel", 3, { { "char *", "path" }, { "int", "flags" }, { "int", "mode" } } },
{ 399, "close_nocancel", 1, { { "int", "fd" } } },
{ 400, "wait4_nocancel", 4, { { "int", "pid" }, { "user_addr_t", "status" }, { "int", "options" }, { "user_addr_t", "rusage" } } },
{ 401, "recvmsg_nocancel", 3, { { "int", "s" }, { "struct msghdr *", "msg" }, { "int", "flags" } } },
{ 402, "sendmsg_nocancel", 3, { { "int", "s" }, { "caddr_t", "msg" }, { "int", "flags" } } },
{ 403, "recvfrom_nocancel", 6, { { "int", "s" }, { "void *", "buf" }, { "size_t", "len" }, { "int", "flags" }, { "struct sockaddr *", "from" }, { "int *", "fromlenaddr" } } },
{ 404, "accept_nocancel", 3, { { "int", "s" }, { "caddr_t", "name" }, { "socklen_t *", "anamelen" } } },
{ 405, "msync_nocancel", 3, { { "caddr_ut", "addr" }, { "size_ut", "len" }, { "int", "flags" } } },
{ 406, "fcntl_nocancel", 3, { { "int", "fd" }, { "int", "cmd" }, { "long", "arg" } } },
{ 407, "select_nocancel", 5, { { "int", "nd" }, { "u_int32_t *", "in" }, { "u_int32_t *", "ou" }, { "u_int32_t *", "ex" }, { "struct timeval *", "tv" } } },
{ 408, "fsync_nocancel", 1, { { "int", "fd" } } },
{ 409, "connect_nocancel", 3, { { "int", "s" }, { "caddr_t", "name" }, { "socklen_t", "namelen" } } },
{ 410, "sigsuspend_nocancel", 1, { { "sigset_t", "mask" } } },
{ 411, "readv_nocancel", 3, { { "int", "fd" }, { "struct iovec *", "iovp" }, { "u_int", "iovcnt" } } },
{ 412, "writev_nocancel", 3, { { "int", "fd" }, { "struct iovec *", "iovp" }, { "u_int", "iovcnt" } } },
{ 413, "sendto_nocancel", 6, { { "int", "s" }, { "caddr_t", "buf" }, { "size_t", "len" }, { "int", "flags" }, { "caddr_t", "to" }, { "socklen_t", "tolen" } } },
{ 414, "pread_nocancel", 4, { { "int", "fd" }, { "user_addr_t", "buf" }, { "user_size_t", "nbyte" }, { "off_t", "offset" } } },
{ 415, "pwrite_nocancel", 4, { { "int", "fd" }, { "user_addr_t", "buf" }, { "user_size_t", "nbyte" }, { "off_t", "offset" } } },
{ 416, "waitid_nocancel", 4, { { "idtype_t", "idtype" }, { "id_t", "id" }, { "siginfo_t *", "infop" }, { "int", "options" } } },
{ 417, "poll_nocancel", 3, { { "struct pollfd *", "fds" }, { "u_int", "nfds" }, { "int", "timeout" } } },
{ 418, "msgsnd_nocancel", 4, { { "int", "msqid" }, { "void *", "msgp" }, { "size_t", "msgsz" }, { "int", "msgflg" } } },
{ 419, "msgrcv_nocancel", 5, { { "int", "msqid" }, { "void *", "msgp" }, { "size_t", "msgsz" }, { "long", "msgtyp" }, { "int", "msgflg" } } },
{ 420, "sem_wait_nocancel", 1, { { "sem_t *", "sem" } } },
{ 421, "aio_suspend_nocancel", 3, { { "user_addr_t", "aiocblist" }, { "int", "nent" }, { "user_addr_t", "timeoutp" } } },
{ 422, "sigwait_nocancel", 2, { { "user_addr_t", "set" }, { "user_addr_t", "sig" } } },
{ 423, "semwait_signal_nocancel", 6, { { "int", "cond_sem" }, { "int", "mutex_sem" }, { "int", "timeout" }, { "int", "relative" }, { "int64_t", "tv_sec" }, { "int32_t", "tv_nsec" } } },
{ 424, "mac_mount", 5, { { "char *", "type" }, { "char *", "path" }, { "int", "flags" }, { "caddr_t", "data" }, { "struct mac *", "mac_p" } } },
{ 425, "mac_get_mount", 2, { { "char *", "path" }, { "struct mac *", "mac_p" } } },
{ 426, "mac_getfsstat", 5, { { "user_addr_t", "buf" }, { "int", "bufsize" }, { "user_addr_t", "mac" }, { "int", "macsize" }, { "int", "flags" } } },
{ 427, "fsgetpath", 4, { { "user_addr_t", "buf" }, { "size_t", "bufsize" }, { "user_addr_t", "fsid" }, { "uint64_t", "objid" } } },
{ 428, "audit_session_self", 0, {} },
{ 429, "audit_session_join", 1, { { "mach_port_name_t", "port" } } },
{ 430, "fileport_makeport", 2, { { "int", "fd" }, { "user_addr_t", "portnamep" } } },
{ 431, "fileport_makefd", 1, { { "mach_port_name_t", "port" } } },
{ 432, "audit_session_port", 2, { { "au_asid_t", "asid" }, { "user_addr_t", "portnamep" } } },
{ 433, "pid_suspend", 1, { { "int", "pid" } } },
{ 434, "pid_resume", 1, { { "int", "pid" } } },
{ 435, "pid_hibernate", 1, { { "int", "pid" } } },
{ 436, "pid_shutdown_sockets", 2, { { "int", "pid" }, { "int", "level" } } },
{ 439, "kas_info", 3, { { "int", "selector" }, { "void *", "value" }, { "size_t *", "size" } } },
{ 440, "memorystatus_control", 5, { { "uint32_t", "command" }, { "int32_t", "pid" }, { "uint32_t", "flags" }, { "user_addr_t", "buffer" }, { "size_t", "buffersize" } } },
{ 441, "guarded_open_np", 5, { { "char *", "path" }, { "const guardid_t *", "guard" }, { "u_int", "guardflags" }, { "int", "flags" }, { "int", "mode" } } },
{ 442, "guarded_close_np", 2, { { "int", "fd" }, { "const guardid_t *", "guard" } } },
{ 443, "guarded_kqueue_np", 2, { { "const guardid_t *", "guard" }, { "u_int", "guardflags" } } },
{ 444, "change_fdguard_np", 6, { { "int", "fd" }, { "const guardid_t *", "guard" }, { "u_int", "guardflags" }, { "const guardid_t *", "nguard" }, { "u_int", "nguardflags" }, { "int *", "fdflagsp" } } },
{ 445, "usrctl", 1, { { "uint32_t", "flags" } } },
{ 446, "proc_rlimit_control", 3, { { "pid_t", "pid" }, { "int", "flavor" }, { "void *", "arg" } } },
{ 447, "connectx", 8, { { "int", "socket" }, { "const sa_endpoints_t *", "endpoints" }, { "sae_associd_t", "associd" }, { "unsigned int", "flags" }, { "const struct iovec *", "iov" }, { "unsigned int", "iovcnt" }, { "size_t *", "len" }, { "sae_connid_t *", "connid" } } },
{ 448, "disconnectx", 3, { { "int", "s" }, { "sae_associd_t", "aid" }, { "sae_connid_t", "cid" } } },
{ 449, "peeloff", 2, { { "int", "s" }, { "sae_associd_t", "aid" } } },
{ 450, "socket_delegate", 4, { { "int", "domain" }, { "int", "type" }, { "int", "protocol" }, { "pid_t", "epid" } } },
{ 451, "telemetry", 6, { { "uint64_t", "cmd" }, { "uint64_t", "deadline" }, { "uint64_t", "interval" }, { "uint64_t", "leeway" }, { "uint64_t", "arg4" }, { "uint64_t", "arg5" } } },
{ 452, "proc_uuid_policy", 4, { { "uint32_t", "operation" }, { "uuid_t", "uuid" }, { "size_t", "uuidlen" }, { "uint32_t", "flags" } } },
{ 453, "memorystatus_get_level", 1, { { "user_addr_t", "level" } } },
{ 454, "system_override", 2, { { "uint64_t", "timeout" }, { "uint64_t", "flags" } } },
{ 455, "vfs_purge", 0, {} },
{ 456, "sfi_ctl", 4, { { "uint32_t", "operation" }, { "uint32_t", "sfi_class" }, { "uint64_t", "time" }, { "uint64_t *", "out_time" } } },
{ 457, "sfi_pidctl", 4, { { "uint32_t", "operation" }, { "pid_t", "pid" }, { "uint32_t", "sfi_flags" }, { "uint32_t *", "out_sfi_flags" } } },
{ 458, "coalition", 3, { { "uint32_t", "operation" }, { "uint64_t *", "cid" }, { "uint32_t", "flags" } } },
{ 459, "coalition_info", 4, { { "uint32_t", "flavor" }, { "uint64_t *", "cid" }, { "void *", "buffer" }, { "size_t *", "bufsize" } } },
{ 460, "necp_match_policy", 3, { { "uint8_t *", "parameters" }, { "size_t", "parameters_size" }, { "struct necp_aggregate_result *", "returned_result" } } },
{ 461, "getattrlistbulk", 5, { { "int", "dirfd" }, { "struct attrlist *", "alist" }, { "void *", "attribute_buffer" }, { "size_t", "buffer_size" }, { "uint64_t", "options" } } },
{ 462, "clonefileat", 5, { { "int", "src_dirfd" }, { "user_addr_t", "src" }, { "int", "dst_dirfd" }, { "user_addr_t", "dst" }, { "uint32_t", "flags" } } },
{ 463, "openat", 4, { { "int", "fd" }, { "char *", "path" }, { "int", "flags" }, { "int", "mode" } } },
{ 464, "openat_nocancel", 4, { { "int", "fd" }, { "char *", "path" }, { "int", "flags" }, { "int", "mode" } } },
{ 465, "renameat", 4, { { "int", "fromfd" }, { "char *", "from" }, { "int", "tofd" }, { "char *", "to" } } },
{ 466, "faccessat", 4, { { "int", "fd" }, { "char *", "path" }, { "int", "amode" }, { "int", "flag" } } },
{ 467, "fchmodat", 4, { { "int", "fd" }, { "char *", "path" }, { "int", "mode" }, { "int", "flag" } } },
{ 468, "fchownat", 5, { { "int", "fd" }, { "char *", "path" }, { "uid_t", "uid" }, { "gid_t", "gid" }, { "int", "flag" } } },
{ 469, "fstatat", 4, { { "int", "fd" }, { "char *", "path" }, { "user_addr_t", "ub" }, { "int", "flag" } } },
{ 470, "fstatat64", 4, { { "int", "fd" }, { "char *", "path" }, { "user_addr_t", "ub" }, { "int", "flag" } } },
{ 471, "linkat", 5, { { "int", "fd1" }, { "char *", "path" }, { "int", "fd2" }, { "char *", "link" }, { "int", "flag" } } },
{ 472, "unlinkat", 3, { { "int", "fd" }, { "char *", "path" }, { "int", "flag" } } },
{ 473, "readlinkat", 4, { { "int", "fd" }, { "char *", "path" }, { "user_addr_t", "buf" }, { "size_t", "bufsize" } } },
{ 474, "symlinkat", 3, { { "user_addr_t *", "path1" }, { "int", "fd" }, { "user_addr_t", "path2" } } },
{ 475, "mkdirat", 3, { { "int", "fd" }, { "char *", "path" }, { "int", "mode" } } },
{ 476, "getattrlistat", 6, { { "int", "fd" }, { "const char *", "path" }, { "struct attrlist *", "alist" }, { "void *", "attribute_buffer" }, { "size_t", "buffer_size" }, { "u_long", "options" } } },
{ 477, "proc_trace_log", 2, { { "pid_t", "pid" }, { "uint64_t", "uniqueid" } } },
{ 478, "bsdthread_ctl", 4, { { "user_addr_t", "cmd" }, { "user_addr_t", "arg1" }, { "user_addr_t", "arg2" }, { "user_addr_t", "arg3" } } },
{ 479, "openbyid_np", 3, { { "user_addr_t", "fsid" }, { "user_addr_t", "objid" }, { "int", "oflags" } } },
{ 480, "recvmsg_x", 4, { { "int", "s" }, { "struct msghdr_x *", "msgp" }, { "u_int", "cnt" }, { "int", "flags" } } },
{ 481, "sendmsg_x", 4, { { "int", "s" }, { "struct msghdr_x *", "msgp" }, { "u_int", "cnt" }, { "int", "flags" } } },
{ 482, "thread_selfusage", 0, {} },
{ 483, "csrctl", 3, { { "uint32_t", "op" }, { "user_addr_t", "useraddr" }, { "user_addr_t", "usersize" } } },
{ 484, "guarded_open_dprotected_np", 7, { { "char *", "path" }, { "const guardid_t *", "guard" }, { "u_int", "guardflags" }, { "int", "flags" }, { "int", "dpclass" }, { "int", "dpflags" }, { "int", "mode" } } },
{ 485, "guarded_write_np", 4, { { "int", "fd" }, { "const guardid_t *", "guard" }, { "user_addr_t", "cbuf" }, { "user_size_t", "nbyte" } } },
{ 486, "guarded_pwrite_np", 5, { { "int", "fd" }, { "const guardid_t *", "guard" }, { "user_addr_t", "buf" }, { "user_size_t", "nbyte" }, { "off_t", "offset" } } },
{ 487, "guarded_writev_np", 4, { { "int", "fd" }, { "const guardid_t *", "guard" }, { "struct iovec *", "iovp" }, { "int", "iovcnt" } } },
{ 488, "renameatx_np", 5, { { "int", "fromfd" }, { "char *", "from" }, { "int", "tofd" }, { "char *", "to" }, { "u_int", "flags" } } },
{ 489, "mremap_encrypted", 5, { { "caddr_ut", "addr" }, { "size_ut", "len" }, { "uint32_t", "cryptid" }, { "uint32_t", "cputype" }, { "uint32_t", "cpusubtype" } } },
{ 490, "netagent_trigger", 2, { { "uuid_t", "agent_uuid" }, { "size_t", "agent_uuidlen" } } },
{ 491, "stack_snapshot_with_config", 3, { { "int", "stackshot_config_version" }, { "user_addr_t", "stackshot_config" }, { "size_t", "stackshot_config_size" } } },
{ 492, "microstackshot", 3, { { "user_addr_t", "tracebuf" }, { "uint32_t", "tracebuf_size" }, { "uint32_t", "flags" } } },
{ 493, "grab_pgo_data", 4, { { "user_addr_t", "uuid" }, { "int", "flags" }, { "user_addr_t", "buffer" }, { "user_ssize_t", "size" } } },
{ 494, "persona", 6, { { "uint32_t", "operation" }, { "uint32_t", "flags" }, { "struct kpersona_info *", "info" }, { "uid_t *", "id" }, { "size_t *", "idlen" }, { "char *", "path" } } },
{ 496, "mach_eventlink_signal", 2, { { "mach_port_name_t", "eventlink_port" }, { "uint64_t", "signal_count" } } },
{ 497, "mach_eventlink_wait_until", 5, { { "mach_port_name_t", "eventlink_port" }, { "uint64_t", "wait_count" }, { "uint64_t", "deadline" }, { "uint32_t", "clock_id" }, { "uint32_t", "option" } } },
{ 498, "mach_eventlink_signal_wait_until", 6, { { "mach_port_name_t", "eventlink_port" }, { "uint64_t", "wait_count" }, { "uint64_t", "signal_count" }, { "uint64_t", "deadline" }, { "uint32_t", "clock_id" }, { "uint32_t", "option" } } },
{ 499, "work_interval_ctl", 4, { { "uint32_t", "operation" }, { "uint64_t", "work_interval_id" }, { "void *", "arg" }, { "size_t", "len" } } },
{ 500, "getentropy", 2, { { "void *", "buffer" }, { "size_t", "size" } } },
{ 502, "necp_client_action", 6, { { "int", "necp_fd" }, { "uint32_t", "action" }, { "uuid_t", "client_id" }, { "size_t", "client_id_len" }, { "uint8_t *", "buffer" }, { "size_t", "buffer_size" } } },
{ 503, "nexus_open", 2, { { "struct nxctl_init *", "init" }, { "uint32_t", "init_len" } } },
{ 504, "nexus_register", 5, { { "int", "ctl" }, { "struct nxprov_reg *", "reg" }, { "uint32_t", "reg_len" }, { "uuid_t *", "prov_uuid" }, { "uint32_t", "prov_uuid_len" } } },
{ 505, "nexus_deregister", 3, { { "int", "ctl" }, { "uuid_t", "prov_uuid" }, { "uint32_t", "prov_uuid_len" } } },
{ 506, "nexus_create", 5, { { "int", "ctl" }, { "uuid_t", "prov_uuid" }, { "uint32_t", "prov_uuid_len" }, { "uuid_t *", "nx_uuid" }, { "uint32_t", "nx_uuid_len" } } },
{ 507, "nexus_destroy", 3, { { "int", "ctl" }, { "uuid_t", "nx_uuid" }, { "uint32_t", "nx_uuid_len" } } },
{ 508, "nexus_get_opt", 4, { { "int", "ctl" }, { "uint32_t", "opt" }, { "void *", "aoptval" }, { "uint32_t *", "aoptlen" } } },
{ 509, "nexus_set_opt", 4, { { "int", "ctl" }, { "uint32_t", "opt" }, { "const void *", "aoptval" }, { "uint32_t", "optlen" } } },
{ 510, "channel_open", 2, { { "struct ch_init *", "init" }, { "uint32_t", "init_len" } } },
{ 511, "channel_get_info", 3, { { "int", "c" }, { "struct ch_info *", "cinfo" }, { "uint32_t", "cinfolen" } } },
{ 512, "channel_sync", 3, { { "int", "c" }, { "int", "mode" }, { "int", "flags" } } },
{ 513, "channel_get_opt", 4, { { "int", "c" }, { "uint32_t", "opt" }, { "void *", "aoptval" }, { "uint32_t *", "aoptlen" } } },
{ 514, "channel_set_opt", 4, { { "int", "c" }, { "uint32_t", "opt" }, { "const void *", "aoptval" }, { "uint32_t", "optlen" } } },
{ 515, "ulock_wait", 4, { { "uint32_t", "operation" }, { "void *", "addr" }, { "uint64_t", "value" }, { "uint32_t", "timeout" } } },
{ 516, "ulock_wake", 3, { { "uint32_t", "operation" }, { "void *", "addr" }, { "uint64_t", "wake_value" } } },
{ 517, "fclonefileat", 4, { { "int", "src_fd" }, { "int", "dst_dirfd" }, { "user_addr_t", "dst" }, { "uint32_t", "flags" } } },
{ 518, "fs_snapshot", 6, { { "uint32_t", "op" }, { "int", "dirfd" }, { "user_addr_t", "name1" }, { "user_addr_t", "name2" }, { "user_addr_t", "data" }, { "uint32_t", "flags" } } },
{ 520, "terminate_with_payload", 7, { { "int", "pid" }, { "uint32_t", "reason_namespace" }, { "uint64_t", "reason_code" }, { "void *", "payload" }, { "uint32_t", "payload_size" }, { "const char *", "reason_string" }, { "uint64_t", "reason_flags" } } },
{ 521, "abort_with_payload", 6, { { "uint32_t", "reason_namespace" }, { "uint64_t", "reason_code" }, { "void *", "payload" }, { "uint32_t", "payload_size" }, { "const char *", "reason_string" }, { "uint64_t", "reason_flags" } } },
{ 523, "necp_session_action", 6, { { "int", "necp_fd" }, { "uint32_t", "action" }, { "uint8_t *", "in_buffer" }, { "size_t", "in_buffer_length" }, { "uint8_t *", "out_buffer" }, { "size_t", "out_buffer_length" } } },
{ 524, "setattrlistat", 6, { { "int", "fd" }, { "const char *", "path" }, { "struct attrlist *", "alist" }, { "void *", "attribute_buffer" }, { "size_t", "buffer_size" }, { "uint32_t", "options" } } },
{ 525, "net_qos_guideline", 2, { { "struct net_qos_param *", "param" }, { "uint32_t", "param_len" } } },
{ 526, "fmount", 4, { { "const char *", "type" }, { "int", "fd" }, { "int", "flags" }, { "void *", "data" } } },
{ 527, "ntp_adjtime", 1, { { "struct timex *", "tp" } } },
{ 528, "ntp_gettime", 1, { { "struct ntptimeval *", "ntvp" } } },
{ 529, "os_fault_with_payload", 6, { { "uint32_t", "reason_namespace" }, { "uint64_t", "reason_code" }, { "void *", "payload" }, { "uint32_t", "payload_size" }, { "const char *", "reason_string" }, { "uint64_t", "reason_flags" } } },
{ 530, "kqueue_workloop_ctl", 4, { { "user_addr_t", "cmd" }, { "uint64_t", "options" }, { "user_addr_t", "addr" }, { "size_t", "sz" } } },
{ 531, "mach_bridge_remote_time", 1, { { "uint64_t", "local_timestamp" } } },
{ 532, "coalition_ledger", 4, { { "uint32_t", "operation" }, { "uint64_t *", "cid" }, { "void *", "buffer" }, { "size_t *", "bufsize" } } },
{ 533, "log_data", 4, { { "unsigned int", "tag" }, { "unsigned int", "flags" }, { "void *", "buffer" }, { "unsigned int", "size" } } },
{ 534, "memorystatus_available_memory", 0, {} },
{ 535, "objc_bp_assist_cfg_np", 2, { { "uint64_t", "adr" }, { "uint64_t", "ctl" } } },
{ 536, "shared_region_map_and_slide_2_np", 4, { { "uint32_t", "files_count" }, { "const struct shared_file_np *", "files" }, { "uint32_t", "mappings_count" }, { "const shared_file_mapping_slide_np_ut *", "mappings_u" } } },
{ 537, "pivot_root", 2, { { "const char *", "new_rootfs_path_before" }, { "const char *", "old_rootfs_path_after" } } },
{ 538, "task_inspect_for_pid", 3, { { "mach_port_name_t", "target_tport" }, { "int", "pid" }, { "mach_port_name_t *", "t" } } },
{ 539, "task_read_for_pid", 3, { { "mach_port_name_t", "target_tport" }, { "int", "pid" }, { "mach_port_name_t *", "t" } } },
{ 540, "preadv", 4, { { "int", "fd" }, { "struct iovec *", "iovp" }, { "int", "iovcnt" }, { "off_t", "offset" } } },
{ 541, "pwritev", 4, { { "int", "fd" }, { "struct iovec *", "iovp" }, { "int", "iovcnt" }, { "off_t", "offset" } } },
{ 542, "preadv_nocancel", 4, { { "int", "fd" }, { "struct iovec *", "iovp" }, { "int", "iovcnt" }, { "off_t", "offset" } } },
{ 543, "pwritev_nocancel", 4, { { "int", "fd" }, { "struct iovec *", "iovp" }, { "int", "iovcnt" }, { "off_t", "offset" } } },
{ 544, "ulock_wait2", 5, { { "uint32_t", "operation" }, { "void *", "addr" }, { "uint64_t", "value" }, { "uint64_t", "timeout" }, { "uint64_t", "value2" } } },
{ 545, "proc_info_extended_id", 8, { { "int32_t", "callnum" }, { "int32_t", "pid" }, { "uint32_t", "flavor" }, { "uint32_t", "flags" }, { "uint64_t", "ext_id" }, { "uint64_t", "arg" }, { "user_addr_t", "buffer" }, { "int32_t", "buffersize" } } },
{ 546, "tracker_action", 3, { { "int", "action" }, { "char *", "buffer" }, { "size_t", "buffer_size" } } },
{ 547, "debug_syscall_reject", 1, { { "uint64_t", "packed_selectors" } } },
{ 548, "debug_syscall_reject_config", 3, { { "uint64_t", "packed_selectors1" }, { "uint64_t", "packed_selectors2" }, { "uint64_t", "flags" } } },
{ 549, "graftdmg", 4, { { "int", "dmg_fd" }, { "const char *", "mountdir" }, { "uint32_t", "graft_type" }, { "graftdmg_args_un *", "gda" } } },
{ 550, "map_with_linking_np", 4, { { "void *", "regions" }, { "uint32_t", "region_count" }, { "void *", "link_info" }, { "uint32_t", "link_info_size" } } },
{ 551, "freadlink", 3, { { "int", "fd" }, { "user_addr_t", "buf" }, { "user_size_t", "bufsize" } } },
{ 552, "record_system_event", 4, { { "uint32_t", "type" }, { "uint32_t", "subsystem" }, { "const char *", "event" }, { "const char *", "payload" } } },
{ 553, "mkfifoat", 3, { { "int", "fd" }, { "char *", "path" }, { "int", "mode" } } },
{ 554, "mknodat", 4, { { "int", "fd" }, { "char *", "path" }, { "int", "mode" }, { "int", "dev" } } },
{ 555, "ungraftdmg", 2, { { "const char *", "mountdir" }, { "uint64_t", "flags" } } },
{ 556, "coalition_policy_set", 3, { { "uint64_t", "cid" }, { "uint32_t", "flavor" }, { "uint32_t", "value" } } },
{ 557, "coalition_policy_get", 2, { { "uint64_t", "cid" }, { "uint32_t", "flavor" } } },
};
FridaXnuSyscallSignature *
frida_get_xnu_mach_traps (int * len)
{
if (len != NULL)
*len = G_N_ELEMENTS (frida_xnu_mach_traps);
return (FridaXnuSyscallSignature *) frida_xnu_mach_traps;
}
FridaXnuSyscallSignature *
frida_get_xnu_bsd_syscalls (int * len)
{
if (len != NULL)
*len = G_N_ELEMENTS (frida_xnu_bsd_syscalls);
return (FridaXnuSyscallSignature *) frida_xnu_bsd_syscalls;
}
+539
View File
@@ -0,0 +1,539 @@
// AUTO-GENERATED FILE. DO NOT EDIT.
namespace Frida {
public extern unowned XnuSyscallSignature[] get_xnu_mach_traps ();
public extern unowned XnuSyscallSignature[] get_xnu_bsd_syscalls ();
public struct XnuSyscallSignature {
public int nr;
public string name;
public uint8 nargs;
public XnuSyscallArg args[9];
}
public struct XnuSyscallArg {
public string? type;
public string? name;
}
public enum XnuMachTrap {
MACH_VM_ALLOCATE = -10,
MACH_VM_PURGABLE_CONTROL = -11,
MACH_VM_DEALLOCATE = -12,
TASK_DYLD_PROCESS_INFO_NOTIFY_GET = -13,
MACH_VM_PROTECT = -14,
MACH_VM_MAP = -15,
MACH_PORT_ALLOCATE = -16,
MACH_PORT_DEALLOCATE = -18,
MACH_PORT_MOD_REFS = -19,
MACH_PORT_MOVE_MEMBER = -20,
MACH_PORT_INSERT_RIGHT = -21,
MACH_PORT_INSERT_MEMBER = -22,
MACH_PORT_EXTRACT_MEMBER = -23,
MACH_PORT_CONSTRUCT = -24,
MACH_PORT_DESTRUCT = -25,
MACH_REPLY_PORT = -26,
THREAD_SELF = -27,
TASK_SELF = -28,
HOST_SELF = -29,
MACH_MSG = -31,
MACH_MSG_OVERWRITE = -32,
SEMAPHORE_SIGNAL = -33,
SEMAPHORE_SIGNAL_ALL = -34,
SEMAPHORE_SIGNAL_THREAD = -35,
SEMAPHORE_WAIT = -36,
SEMAPHORE_WAIT_SIGNAL = -37,
SEMAPHORE_TIMEDWAIT = -38,
SEMAPHORE_TIMEDWAIT_SIGNAL = -39,
MACH_PORT_GET_ATTRIBUTES = -40,
MACH_PORT_GUARD = -41,
MACH_PORT_UNGUARD = -42,
MACH_GENERATE_ACTIVITY_ID = -43,
TASK_NAME_FOR_PID = -44,
TASK_FOR_PID = -45,
PID_FOR_TASK = -46,
MACH_MSG2 = -47,
MACX_SWAPON = -48,
MACX_SWAPOFF = -49,
THREAD_GET_SPECIAL_REPLY_PORT = -50,
MACX_TRIGGERS = -51,
MACX_BACKING_STORE_SUSPEND = -52,
MACX_BACKING_STORE_RECOVERY = -53,
PFZ_EXIT = -58,
SWTCH_PRI = -59,
SWTCH = -60,
THREAD_SWITCH = -61,
CLOCK_SLEEP = -62,
MACH_VM_RECLAIM_UPDATE_KERNEL_ACCOUNTING = -63,
HOST_CREATE_MACH_VOUCHER = -70,
MACH_VOUCHER_EXTRACT_ATTR_RECIPE = -72,
MACH_PORT_TYPE = -76,
MACH_PORT_REQUEST_NOTIFICATION = -77,
EXCLAVES_CTL = -88,
MACH_TIMEBASE_INFO = -89,
MACH_WAIT_UNTIL = -90,
MK_TIMER_CREATE = -91,
MK_TIMER_DESTROY = -92,
MK_TIMER_ARM = -93,
MK_TIMER_CANCEL = -94,
MK_TIMER_ARM_LEEWAY = -95,
DEBUG_CONTROL_PORT_FOR_PID = -96,
IOKIT_USER_CLIENT = -100,
}
public enum XnuBsdSyscall {
EXIT = 1,
FORK = 2,
READ = 3,
WRITE = 4,
OPEN = 5,
CLOSE = 6,
WAIT4 = 7,
LINK = 9,
UNLINK = 10,
CHDIR = 12,
FCHDIR = 13,
MKNOD = 14,
CHMOD = 15,
CHOWN = 16,
GETFSSTAT = 18,
GETPID = 20,
SETUID = 23,
GETUID = 24,
GETEUID = 25,
PTRACE = 26,
RECVMSG = 27,
SENDMSG = 28,
RECVFROM = 29,
ACCEPT = 30,
GETPEERNAME = 31,
GETSOCKNAME = 32,
ACCESS = 33,
CHFLAGS = 34,
FCHFLAGS = 35,
SYNC = 36,
KILL = 37,
CROSSARCH_TRAP = 38,
GETPPID = 39,
DUP = 41,
PIPE = 42,
GETEGID = 43,
SIGACTION = 46,
GETGID = 47,
SIGPROCMASK = 48,
GETLOGIN = 49,
SETLOGIN = 50,
ACCT = 51,
SIGPENDING = 52,
SIGALTSTACK = 53,
IOCTL = 54,
REBOOT = 55,
REVOKE = 56,
SYMLINK = 57,
READLINK = 58,
EXECVE = 59,
UMASK = 60,
CHROOT = 61,
MSYNC = 65,
VFORK = 66,
OSLOG_COPROC_REG = 67,
OSLOG_COPROC = 68,
MUNMAP = 73,
MPROTECT = 74,
MADVISE = 75,
MINCORE = 78,
GETGROUPS = 79,
SETGROUPS = 80,
GETPGRP = 81,
SETPGID = 82,
SETITIMER = 83,
SWAPON = 85,
GETITIMER = 86,
GETDTABLESIZE = 89,
DUP2 = 90,
FCNTL = 92,
SELECT = 93,
FSYNC = 95,
SETPRIORITY = 96,
SOCKET = 97,
CONNECT = 98,
GETPRIORITY = 100,
BIND = 104,
SETSOCKOPT = 105,
LISTEN = 106,
SIGSUSPEND = 111,
GETTIMEOFDAY = 116,
GETRUSAGE = 117,
GETSOCKOPT = 118,
READV = 120,
WRITEV = 121,
SETTIMEOFDAY = 122,
FCHOWN = 123,
FCHMOD = 124,
SETREUID = 126,
SETREGID = 127,
RENAME = 128,
FLOCK = 131,
MKFIFO = 132,
SENDTO = 133,
SHUTDOWN = 134,
SOCKETPAIR = 135,
MKDIR = 136,
RMDIR = 137,
UTIMES = 138,
FUTIMES = 139,
ADJTIME = 140,
GETHOSTUUID = 142,
SETSID = 147,
GETPGID = 151,
SETPRIVEXEC = 152,
PREAD = 153,
PWRITE = 154,
NFSSVC = 155,
STATFS = 157,
FSTATFS = 158,
UNMOUNT = 159,
GETFH = 161,
FUNMOUNT = 164,
QUOTACTL = 165,
MOUNT = 167,
CSOPS = 169,
CSOPS_AUDITTOKEN = 170,
WAITID = 173,
KDEBUG_TYPEFILTER = 177,
KDEBUG_TRACE_STRING = 178,
KDEBUG_TRACE64 = 179,
KDEBUG_TRACE = 180,
SETGID = 181,
SETEGID = 182,
SETEUID = 183,
SIGRETURN = 184,
PANIC_WITH_DATA = 185,
THREAD_SELFCOUNTS = 186,
FDATASYNC = 187,
STAT = 188,
FSTAT = 189,
LSTAT = 190,
PATHCONF = 191,
FPATHCONF = 192,
GETRLIMIT = 194,
SETRLIMIT = 195,
GETDIRENTRIES = 196,
MMAP = 197,
LSEEK = 199,
TRUNCATE = 200,
FTRUNCATE = 201,
SYSCTL = 202,
MLOCK = 203,
MUNLOCK = 204,
UNDELETE = 205,
OPEN_DPROTECTED_NP = 216,
FSGETPATH_EXT = 217,
OPENAT_DPROTECTED_NP = 218,
GETATTRLIST = 220,
SETATTRLIST = 221,
GETDIRENTRIESATTR = 222,
EXCHANGEDATA = 223,
SEARCHFS = 225,
DELETE = 226,
COPYFILE = 227,
FGETATTRLIST = 228,
FSETATTRLIST = 229,
POLL = 230,
GETXATTR = 234,
FGETXATTR = 235,
SETXATTR = 236,
FSETXATTR = 237,
REMOVEXATTR = 238,
FREMOVEXATTR = 239,
LISTXATTR = 240,
FLISTXATTR = 241,
FSCTL = 242,
INITGROUPS = 243,
POSIX_SPAWN = 244,
FFSCTL = 245,
FHOPEN = 248,
MINHERIT = 250,
SEMSYS = 251,
MSGSYS = 252,
SHMSYS = 253,
SEMCTL = 254,
SEMGET = 255,
SEMOP = 256,
MSGCTL = 258,
MSGGET = 259,
MSGSND = 260,
MSGRCV = 261,
SHMAT = 262,
SHMCTL = 263,
SHMDT = 264,
SHMGET = 265,
SHM_OPEN = 266,
SHM_UNLINK = 267,
SEM_OPEN = 268,
SEM_CLOSE = 269,
SEM_UNLINK = 270,
SEM_WAIT = 271,
SEM_TRYWAIT = 272,
SEM_POST = 273,
SYSCTLBYNAME = 274,
OPEN_EXTENDED = 277,
UMASK_EXTENDED = 278,
STAT_EXTENDED = 279,
LSTAT_EXTENDED = 280,
FSTAT_EXTENDED = 281,
CHMOD_EXTENDED = 282,
FCHMOD_EXTENDED = 283,
ACCESS_EXTENDED = 284,
SETTID = 285,
GETTID = 286,
SETSGROUPS = 287,
GETSGROUPS = 288,
SETWGROUPS = 289,
GETWGROUPS = 290,
MKFIFO_EXTENDED = 291,
MKDIR_EXTENDED = 292,
IDENTITYSVC = 293,
SHARED_REGION_CHECK_NP = 294,
VM_PRESSURE_MONITOR = 296,
PSYNCH_RW_LONGRDLOCK = 297,
PSYNCH_RW_YIELDWRLOCK = 298,
PSYNCH_RW_DOWNGRADE = 299,
PSYNCH_RW_UPGRADE = 300,
PSYNCH_MUTEXWAIT = 301,
PSYNCH_MUTEXDROP = 302,
PSYNCH_CVBROAD = 303,
PSYNCH_CVSIGNAL = 304,
PSYNCH_CVWAIT = 305,
PSYNCH_RW_RDLOCK = 306,
PSYNCH_RW_WRLOCK = 307,
PSYNCH_RW_UNLOCK = 308,
PSYNCH_RW_UNLOCK2 = 309,
GETSID = 310,
SETTID_WITH_PID = 311,
PSYNCH_CVCLRPREPOST = 312,
AIO_FSYNC = 313,
AIO_RETURN = 314,
AIO_SUSPEND = 315,
AIO_CANCEL = 316,
AIO_ERROR = 317,
AIO_READ = 318,
AIO_WRITE = 319,
LIO_LISTIO = 320,
IOPOLICYSYS = 322,
PROCESS_POLICY = 323,
MLOCKALL = 324,
MUNLOCKALL = 325,
ISSETUGID = 327,
PTHREAD_KILL = 328,
PTHREAD_SIGMASK = 329,
SIGWAIT = 330,
DISABLE_THREADSIGNAL = 331,
PTHREAD_MARKCANCEL = 332,
PTHREAD_CANCELED = 333,
SEMWAIT_SIGNAL = 334,
PROC_INFO = 336,
SENDFILE = 337,
STAT64 = 338,
FSTAT64 = 339,
LSTAT64 = 340,
STAT64_EXTENDED = 341,
LSTAT64_EXTENDED = 342,
FSTAT64_EXTENDED = 343,
GETDIRENTRIES64 = 344,
STATFS64 = 345,
FSTATFS64 = 346,
GETFSSTAT64 = 347,
PTHREAD_CHDIR = 348,
PTHREAD_FCHDIR = 349,
AUDIT = 350,
AUDITON = 351,
GETAUID = 353,
SETAUID = 354,
GETAUDIT_ADDR = 357,
SETAUDIT_ADDR = 358,
AUDITCTL = 359,
BSDTHREAD_CREATE = 360,
BSDTHREAD_TERMINATE = 361,
KQUEUE = 362,
KEVENT = 363,
LCHOWN = 364,
BSDTHREAD_REGISTER = 366,
WORKQ_OPEN = 367,
WORKQ_KERNRETURN = 368,
KEVENT64 = 369,
THREAD_SELFID = 372,
LEDGER = 373,
KEVENT_QOS = 374,
KEVENT_ID = 375,
MAC_EXECVE = 380,
MAC_SYSCALL = 381,
MAC_GET_FILE = 382,
MAC_SET_FILE = 383,
MAC_GET_LINK = 384,
MAC_SET_LINK = 385,
MAC_GET_PROC = 386,
MAC_SET_PROC = 387,
MAC_GET_FD = 388,
MAC_SET_FD = 389,
MAC_GET_PID = 390,
PSELECT = 394,
PSELECT_NOCANCEL = 395,
READ_NOCANCEL = 396,
WRITE_NOCANCEL = 397,
OPEN_NOCANCEL = 398,
CLOSE_NOCANCEL = 399,
WAIT4_NOCANCEL = 400,
RECVMSG_NOCANCEL = 401,
SENDMSG_NOCANCEL = 402,
RECVFROM_NOCANCEL = 403,
ACCEPT_NOCANCEL = 404,
MSYNC_NOCANCEL = 405,
FCNTL_NOCANCEL = 406,
SELECT_NOCANCEL = 407,
FSYNC_NOCANCEL = 408,
CONNECT_NOCANCEL = 409,
SIGSUSPEND_NOCANCEL = 410,
READV_NOCANCEL = 411,
WRITEV_NOCANCEL = 412,
SENDTO_NOCANCEL = 413,
PREAD_NOCANCEL = 414,
PWRITE_NOCANCEL = 415,
WAITID_NOCANCEL = 416,
POLL_NOCANCEL = 417,
MSGSND_NOCANCEL = 418,
MSGRCV_NOCANCEL = 419,
SEM_WAIT_NOCANCEL = 420,
AIO_SUSPEND_NOCANCEL = 421,
SIGWAIT_NOCANCEL = 422,
SEMWAIT_SIGNAL_NOCANCEL = 423,
MAC_MOUNT = 424,
MAC_GET_MOUNT = 425,
MAC_GETFSSTAT = 426,
FSGETPATH = 427,
AUDIT_SESSION_SELF = 428,
AUDIT_SESSION_JOIN = 429,
FILEPORT_MAKEPORT = 430,
FILEPORT_MAKEFD = 431,
AUDIT_SESSION_PORT = 432,
PID_SUSPEND = 433,
PID_RESUME = 434,
PID_HIBERNATE = 435,
PID_SHUTDOWN_SOCKETS = 436,
KAS_INFO = 439,
MEMORYSTATUS_CONTROL = 440,
GUARDED_OPEN_NP = 441,
GUARDED_CLOSE_NP = 442,
GUARDED_KQUEUE_NP = 443,
CHANGE_FDGUARD_NP = 444,
USRCTL = 445,
PROC_RLIMIT_CONTROL = 446,
CONNECTX = 447,
DISCONNECTX = 448,
PEELOFF = 449,
SOCKET_DELEGATE = 450,
TELEMETRY = 451,
PROC_UUID_POLICY = 452,
MEMORYSTATUS_GET_LEVEL = 453,
SYSTEM_OVERRIDE = 454,
VFS_PURGE = 455,
SFI_CTL = 456,
SFI_PIDCTL = 457,
COALITION = 458,
COALITION_INFO = 459,
NECP_MATCH_POLICY = 460,
GETATTRLISTBULK = 461,
CLONEFILEAT = 462,
OPENAT = 463,
OPENAT_NOCANCEL = 464,
RENAMEAT = 465,
FACCESSAT = 466,
FCHMODAT = 467,
FCHOWNAT = 468,
FSTATAT = 469,
FSTATAT64 = 470,
LINKAT = 471,
UNLINKAT = 472,
READLINKAT = 473,
SYMLINKAT = 474,
MKDIRAT = 475,
GETATTRLISTAT = 476,
PROC_TRACE_LOG = 477,
BSDTHREAD_CTL = 478,
OPENBYID_NP = 479,
RECVMSG_X = 480,
SENDMSG_X = 481,
THREAD_SELFUSAGE = 482,
CSRCTL = 483,
GUARDED_OPEN_DPROTECTED_NP = 484,
GUARDED_WRITE_NP = 485,
GUARDED_PWRITE_NP = 486,
GUARDED_WRITEV_NP = 487,
RENAMEATX_NP = 488,
MREMAP_ENCRYPTED = 489,
NETAGENT_TRIGGER = 490,
STACK_SNAPSHOT_WITH_CONFIG = 491,
MICROSTACKSHOT = 492,
GRAB_PGO_DATA = 493,
PERSONA = 494,
MACH_EVENTLINK_SIGNAL = 496,
MACH_EVENTLINK_WAIT_UNTIL = 497,
MACH_EVENTLINK_SIGNAL_WAIT_UNTIL = 498,
WORK_INTERVAL_CTL = 499,
GETENTROPY = 500,
NECP_CLIENT_ACTION = 502,
NEXUS_OPEN = 503,
NEXUS_REGISTER = 504,
NEXUS_DEREGISTER = 505,
NEXUS_CREATE = 506,
NEXUS_DESTROY = 507,
NEXUS_GET_OPT = 508,
NEXUS_SET_OPT = 509,
CHANNEL_OPEN = 510,
CHANNEL_GET_INFO = 511,
CHANNEL_SYNC = 512,
CHANNEL_GET_OPT = 513,
CHANNEL_SET_OPT = 514,
ULOCK_WAIT = 515,
ULOCK_WAKE = 516,
FCLONEFILEAT = 517,
FS_SNAPSHOT = 518,
TERMINATE_WITH_PAYLOAD = 520,
ABORT_WITH_PAYLOAD = 521,
NECP_SESSION_ACTION = 523,
SETATTRLISTAT = 524,
NET_QOS_GUIDELINE = 525,
FMOUNT = 526,
NTP_ADJTIME = 527,
NTP_GETTIME = 528,
OS_FAULT_WITH_PAYLOAD = 529,
KQUEUE_WORKLOOP_CTL = 530,
MACH_BRIDGE_REMOTE_TIME = 531,
COALITION_LEDGER = 532,
LOG_DATA = 533,
MEMORYSTATUS_AVAILABLE_MEMORY = 534,
OBJC_BP_ASSIST_CFG_NP = 535,
SHARED_REGION_MAP_AND_SLIDE_2_NP = 536,
PIVOT_ROOT = 537,
TASK_INSPECT_FOR_PID = 538,
TASK_READ_FOR_PID = 539,
PREADV = 540,
PWRITEV = 541,
PREADV_NOCANCEL = 542,
PWRITEV_NOCANCEL = 543,
ULOCK_WAIT2 = 544,
PROC_INFO_EXTENDED_ID = 545,
TRACKER_ACTION = 546,
DEBUG_SYSCALL_REJECT = 547,
DEBUG_SYSCALL_REJECT_CONFIG = 548,
GRAFTDMG = 549,
MAP_WITH_LINKING_NP = 550,
FREADLINK = 551,
RECORD_SYSTEM_EVENT = 552,
MKFIFOAT = 553,
MKNODAT = 554,
UNGRAFTDMG = 555,
COALITION_POLICY_SET = 556,
COALITION_POLICY_GET = 557,
}
}
+11
View File
@@ -0,0 +1,11 @@
FRIDA_1.0 {
local:
*;
};
GLIBC_2.2.5 {
local:
fopen*;
fseeko*;
ftello*;
} FRIDA_1.0;
+2
View File
@@ -118,6 +118,8 @@ frida_gadget_environment_deinit (void)
g_assert (worker_loop != NULL);
frida_libc_shim_prepare_to_deinit ();
source = g_idle_source_new ();
g_source_set_priority (source, G_PRIORITY_LOW);
g_source_set_callback (source, stop_worker_loop, NULL, NULL);
+1 -1
View File
@@ -45,7 +45,7 @@ elif host_os_family == 'darwin'
extra_link_args += '-Wl,-exported_symbols_list,' + meson.current_source_dir() / symlist
extra_link_depends += symlist
else
symscript = 'frida-gadget.version'
symscript = (libc == 'glibc') ? 'frida-gadget-glibc.version' : 'frida-gadget.version'
extra_link_args += '-Wl,--version-script,' + meson.current_source_dir() / symscript
extra_link_depends += symscript
endif
+304 -20
View File
@@ -10,6 +10,7 @@
# include <assert.h>
# include <fcntl.h>
# include <unistd.h>
# include <wchar.h>
#endif
#if defined (HAVE_DARWIN)
# include <sys/attr.h>
@@ -25,21 +26,44 @@
#undef feof
#undef ferror
#undef fgetwc
#undef fopen
#undef fopen64
#undef fputwc
#undef fseek
#undef fseeko
#undef fseeko64
#undef ftell
#undef ftello
#undef ftello64
#undef getc
#undef getc_unlocked
#undef getwc
#undef memcpy
#undef putc
#undef putchar
#undef putwc
#undef snprintf
#undef sprintf
#undef stderr
#undef stdin
#undef stdout
#undef ungetc
#undef ungetwc
#undef vsnprintf
#ifdef HAVE_MUSL
# define FRIDA_STDIO_OPAQUE_FILE 1
#endif
static gboolean frida_deinit_expected = FALSE;
void
frida_libc_shim_prepare_to_deinit (void)
{
frida_deinit_expected = TRUE;
}
#if defined (HAVE_WINDOWS) || defined (HAVE_ASAN)
void
@@ -70,6 +94,9 @@ __attribute__ ((destructor)) static
void
frida_libc_shim_deinit (void)
{
if (!frida_deinit_expected)
return;
# ifdef HAVE_ASAN
gum_deinit ();
# else
@@ -142,8 +169,8 @@ struct _FridaFile
size_t wcap;
size_t wlen;
int ungot;
gboolean has_ungot;
guint8 ungot_buf[8];
guint ungot_len;
};
struct _FridaFileHandle
@@ -171,6 +198,10 @@ struct _FridaDir
#endif
static FILE * frida_fopen_impl (const char * pathname, const char * mode);
static int frida_fseek_impl (FILE * stream, off_t offset, int whence);
static off_t frida_ftell_impl (FILE * stream);
static void frida_stdio_register_stream (FILE * stream);
static void frida_stdio_unregister_stream (FILE * stream);
#ifdef HAVE_FRIDA_DIR
@@ -193,6 +224,8 @@ static void frida_parse_fopen_mode (const char * mode, int * oflags);
static int frida_write_formatted_to_fd (int fd, const char * format, va_list args);
static gboolean frida_utf8_expected_len (guint8 first, guint * out_len);
#ifdef HAVE_FRIDA_DIR
static FridaDir * frida_dir_get_impl (DIR * dirp);
static DIR * frida_dir_wrap (FridaDir * impl);
@@ -317,6 +350,9 @@ frida_libc_shim_deinit (void)
fflush (NULL);
if (!frida_deinit_expected)
return;
G_LOCK (frida_stdio);
g_hash_table_iter_init (&iter, frida_streams);
@@ -639,8 +675,34 @@ asprintf_l (char ** ret, locale_t loc, const char * format, ...)
#endif
#ifdef HAVE_GLIBC
G_GNUC_INTERNAL FILE *
frida_fopen_glibc_225 (const char * pathname, const char * mode)
{
return frida_fopen_impl (pathname, mode);
}
__asm__ (".symver frida_fopen_glibc_225,fopen@@GLIBC_2.2.5");
G_GNUC_INTERNAL FILE *
frida_fopen64_glibc_225 (const char * pathname, const char * mode)
{
return frida_fopen_impl (pathname, mode);
}
__asm__ (".symver frida_fopen64_glibc_225,fopen64@@GLIBC_2.2.5");
#else
G_GNUC_INTERNAL FILE *
fopen (const char * pathname, const char * mode)
{
return frida_fopen_impl (pathname, mode);
}
#endif
static FILE *
frida_fopen_impl (const char * pathname, const char * mode)
{
FILE * result;
int oflags, fd;
@@ -801,11 +863,8 @@ getc_unlocked (FILE * stream)
f = frida_file_get_impl (stream);
if (f->has_ungot)
{
f->has_ungot = FALSE;
return f->ungot;
}
if (f->ungot_len != 0)
return f->ungot_buf[--f->ungot_len];
if (f->buf_mode == _IONBF)
{
@@ -846,6 +905,58 @@ getc (FILE * stream)
return getc_unlocked (stream);
}
G_GNUC_INTERNAL wint_t
getwc (FILE * stream)
{
return fgetwc (stream);
}
G_GNUC_INTERNAL wint_t
fgetwc (FILE * stream)
{
char bytes[4];
guint need, have;
int c;
gunichar ch;
c = getc_unlocked (stream);
if (c == EOF)
return WEOF;
bytes[0] = c;
if (!frida_utf8_expected_len (bytes[0], &need))
{
errno = EILSEQ;
frida_file_get_impl (stream)->err = errno;
return WEOF;
}
have = 1;
while (have != need)
{
c = getc_unlocked (stream);
if (c == EOF)
{
errno = EILSEQ;
frida_file_get_impl (stream)->err = errno;
return WEOF;
}
bytes[have++] = c;
}
ch = g_utf8_get_char_validated (bytes, (gssize) need);
if (ch == (gunichar) -1 || ch == (gunichar) -2)
{
errno = EILSEQ;
frida_file_get_impl (stream)->err = errno;
return WEOF;
}
return (wint_t) ch;
}
G_GNUC_INTERNAL int
ungetc (int c, FILE * stream)
{
@@ -856,16 +967,46 @@ ungetc (int c, FILE * stream)
if (c == EOF)
return EOF;
if (f->has_ungot)
if (f->ungot_len == G_N_ELEMENTS (f->ungot_buf))
return EOF;
f->ungot = c;
f->has_ungot = TRUE;
f->ungot_buf[f->ungot_len++] = c;
f->eof = FALSE;
return c;
}
G_GNUC_INTERNAL wint_t
ungetwc (wint_t wc, FILE * stream)
{
FridaFile * f;
char tmp[4];
int len;
int i;
if (wc == WEOF)
return WEOF;
f = frida_file_get_impl (stream);
len = g_unichar_to_utf8 ((gunichar) wc, tmp);
if (len <= 0 || len > 4)
{
errno = EILSEQ;
f->err = errno;
return WEOF;
}
if (f->ungot_len + len > G_N_ELEMENTS (f->ungot_buf))
return WEOF;
for (i = 0; i != len; i++)
f->ungot_buf[f->ungot_len++] = tmp[i];
f->eof = FALSE;
return wc;
}
G_GNUC_INTERNAL size_t
fread (void * ptr, size_t size, size_t nmemb, FILE * stream)
{
@@ -884,10 +1025,9 @@ fread (void * ptr, size_t size, size_t nmemb, FILE * stream)
while (got != want)
{
if (f->has_ungot)
if (f->ungot_len != 0)
{
out[got++] = (guint8) f->ungot;
f->has_ungot = FALSE;
out[got++] = f->ungot_buf[--f->ungot_len];
continue;
}
@@ -1006,6 +1146,12 @@ fwrite (const void * ptr, size_t size, size_t nmemb, FILE * stream)
return off / size;
}
G_GNUC_INTERNAL int
putc (int c, FILE * stream)
{
return fputc (c, stream);
}
G_GNUC_INTERNAL int
fputc (int c, FILE * stream)
{
@@ -1019,6 +1165,37 @@ fputc (int c, FILE * stream)
return ch;
}
G_GNUC_INTERNAL wint_t
putwc (wchar_t wc, FILE * stream)
{
return fputwc (wc, stream);
}
G_GNUC_INTERNAL wint_t
fputwc (wchar_t wc, FILE * stream)
{
char tmp[4];
int len;
size_t n;
if (wc == WEOF)
return WEOF;
len = g_unichar_to_utf8 ((gunichar) wc, tmp);
if (len <= 0 || len > 4)
{
errno = EILSEQ;
frida_file_get_impl (stream)->err = errno;
return WEOF;
}
n = fwrite (tmp, 1, len, stream);
if (n != len)
return WEOF;
return (wint_t) wc;
}
G_GNUC_INTERNAL int
fputs (const char * s, FILE * stream)
{
@@ -1062,6 +1239,84 @@ fgets (char * s, int size, FILE * stream)
G_GNUC_INTERNAL int
fseek (FILE * stream, long offset, int whence)
{
return frida_fseek_impl (stream, (off_t) offset, whence);
}
G_GNUC_INTERNAL long
ftell (FILE * stream)
{
off_t pos = frida_ftell_impl (stream);
if (pos == (off_t) -1)
return -1;
return (long) pos;
}
#ifdef HAVE_GLIBC
G_GNUC_INTERNAL int
frida_fseeko_glibc_225 (FILE * stream, off_t offset, int whence)
{
return frida_fseek_impl (stream, offset, whence);
}
__asm__ (".symver frida_fseeko_glibc_225,fseeko@@GLIBC_2.2.5");
G_GNUC_INTERNAL int
frida_fseeko64_glibc_225 (FILE * stream, off_t offset, int whence)
{
return frida_fseek_impl (stream, offset, whence);
}
__asm__ (".symver frida_fseeko64_glibc_225,fseeko64@@GLIBC_2.2.5");
G_GNUC_INTERNAL off_t
frida_ftello_glibc_225 (FILE * stream)
{
return frida_ftell_impl (stream);
}
__asm__ (".symver frida_ftello_glibc_225,ftello@@GLIBC_2.2.5");
G_GNUC_INTERNAL off_t
frida_ftello64_glibc_225 (FILE * stream)
{
return frida_ftell_impl (stream);
}
__asm__ (".symver frida_ftello64_glibc_225,ftello64@@GLIBC_2.2.5");
#else
G_GNUC_INTERNAL int
fseeko (FILE * stream, off_t offset, int whence)
{
return frida_fseek_impl (stream, offset, whence);
}
G_GNUC_INTERNAL off_t
ftello (FILE * stream)
{
return frida_ftell_impl (stream);
}
# ifndef HAVE_QNX
G_GNUC_INTERNAL int
fseeko64 (FILE * stream, off_t offset, int whence)
{
return frida_fseek_impl (stream, offset, whence);
}
G_GNUC_INTERNAL off_t
ftello64 (FILE * stream)
{
return frida_ftell_impl (stream);
}
# endif
#endif
static int
frida_fseek_impl (FILE * stream, off_t offset, int whence)
{
FridaFile * f;
off_t r;
@@ -1073,10 +1328,10 @@ fseek (FILE * stream, long offset, int whence)
f->rpos = 0;
f->rlen = 0;
f->has_ungot = FALSE;
f->ungot_len = 0;
f->eof = FALSE;
r = frida_lseek_nointr (f->fd, (off_t) offset, whence);
r = frida_lseek_nointr (f->fd, offset, whence);
if (r == (off_t) -1)
{
f->err = errno;
@@ -1086,8 +1341,8 @@ fseek (FILE * stream, long offset, int whence)
return 0;
}
G_GNUC_INTERNAL long
ftell (FILE * stream)
static off_t
frida_ftell_impl (FILE * stream)
{
FridaFile * f;
off_t pos;
@@ -1104,10 +1359,9 @@ ftell (FILE * stream)
if (f->buf_mode != _IONBF)
pos -= (off_t) (f->rlen - f->rpos);
if (f->has_ungot)
pos -= 1;
pos -= f->ungot_len;
return (long) pos;
return pos;
}
G_GNUC_INTERNAL void
@@ -1866,6 +2120,36 @@ beach:
}
}
static gboolean
frida_utf8_expected_len (guint8 first, guint * out_len)
{
if (first < 0x80)
{
*out_len = 1;
return TRUE;
}
if ((first & 0xe0) == 0xc0)
{
*out_len = 2;
return TRUE;
}
if ((first & 0xf0) == 0xe0)
{
*out_len = 3;
return TRUE;
}
if ((first & 0xf8) == 0xf0)
{
*out_len = 4;
return TRUE;
}
return FALSE;
}
#ifdef HAVE_FRIDA_DIR
static FridaDir *
+1
View File
@@ -1,4 +1,5 @@
namespace Frida {
public extern void libc_shim_prepare_to_deinit ();
#if DARWIN
public extern void libc_shim_deinit ();
#endif
+4
View File
@@ -302,6 +302,10 @@ if host_os == 'linux'
endif
cdata.set('HAVE_' + libc.to_upper(), 1)
vala_flags += '--define=' + libc.to_upper()
elif host_os == 'android'
libc = 'bionic'
else
libc = 'other'
endif
if get_option('b_sanitize') == 'address'
+1 -1
Submodule releng updated: 7ed66fe687...852c527081.
+1 -1
View File
@@ -11,7 +11,7 @@ helper.dex: build/frida-helper.jar
$<
mv build/classes.dex $@
build/frida-helper.jar: re/frida/Helper.java
build/frida-helper.jar: re/frida/Helper.java re/frida/HelperBackend.java
javac \
-cp .:$(android_jar) \
-bootclasspath $(android_jar) \
+87 -71
View File
@@ -1,66 +1,12 @@
namespace Frida {
public sealed class AndroidHelperClient : Object, AsyncInitable {
public signal void closed ();
public IOStream stream {
public sealed class AndroidHelperClient : Object {
public AndroidHelperTransport transport {
get;
construct;
}
private BufferedInputStream input;
private OutputStream output;
private Cancellable io_cancellable = new Cancellable ();
private State state = CLOSED;
private Gee.Queue<Request> pending_requests = new Gee.ArrayQueue<Request> ();
private ByteArray pending_output = new ByteArray ();
private bool writing = false;
private enum State {
CLOSED,
OPEN
}
private const uint32 MAX_RESPONSE_SIZE = 100 * 1024 * 1024;
public AndroidHelperClient (IOStream stream) {
Object (stream: stream);
}
construct {
input = (BufferedInputStream) Object.new (typeof (BufferedInputStream),
"base-stream", stream.get_input_stream (),
"close-base-stream", false,
"buffer-size", 128 * 1024);
output = stream.get_output_stream ();
state = OPEN;
process_incoming_responses.begin ();
}
public async void close (Cancellable? cancellable) throws IOError {
io_cancellable.cancel ();
var source = new IdleSource ();
source.set_callback (close.callback);
source.attach (MainContext.get_thread_default ());
yield;
try {
yield stream.close_async (Priority.DEFAULT, cancellable);
} catch (IOError e) {
}
ensure_closed ();
}
private void ensure_closed () {
if (state == CLOSED)
return;
state = CLOSED;
closed ();
public AndroidHelperClient (AndroidHelperTransport transport) {
Object (transport: transport);
}
public async HostApplicationInfo get_frontmost_application (FrontmostQueryOptions options,
@@ -72,7 +18,7 @@ namespace Frida {
.add_string_value (options.scope.to_nick ())
.end_array ();
Json.Node response = yield request (stanza.get_root (), cancellable);
Json.Node response = yield transport.request (stanza.get_root (), cancellable);
if (response.is_null ())
return HostApplicationInfo.empty ();
@@ -127,7 +73,7 @@ namespace Frida {
.add_string_value (options.scope.to_nick ())
.end_array ();
Json.Node response = yield request (stanza.get_root (), cancellable);
Json.Node response = yield transport.request (stanza.get_root (), cancellable);
Json.Reader reader = new Json.Reader (response);
@@ -193,7 +139,7 @@ namespace Frida {
.add_string_value (options.scope.to_nick ())
.end_array ();
Json.Node response = yield request (stanza.get_root (), cancellable);
Json.Node response = yield transport.request (stanza.get_root (), cancellable);
Json.Reader reader = new Json.Reader (response);
@@ -247,7 +193,7 @@ namespace Frida {
.add_int_value (uid)
.end_array ();
Json.Node response = yield request (stanza.get_root (), cancellable);
Json.Node response = yield transport.request (stanza.get_root (), cancellable);
var r = new Json.Reader (response);
parse_envelope_or_throw (r);
@@ -317,7 +263,7 @@ namespace Frida {
.add_int_value (uid)
.end_array ();
Json.Node response = yield request (stanza.get_root (), cancellable);
Json.Node response = yield transport.request (stanza.get_root (), cancellable);
var r = new Json.Reader (response);
parse_envelope_or_throw (r);
@@ -331,7 +277,7 @@ namespace Frida {
.add_int_value ((int) pid)
.end_array ();
Json.Node response = yield request (stanza.get_root (), cancellable);
Json.Node response = yield transport.request (stanza.get_root (), cancellable);
var r = new Json.Reader (response);
parse_envelope_or_throw (r);
@@ -343,6 +289,13 @@ namespace Frida {
return r.get_boolean_value ();
}
private async void request_ok (Json.Builder stanza, Cancellable? cancellable) throws Error, IOError {
Json.Node response = yield transport.request (stanza.get_root (), cancellable);
var r = new Json.Reader (response);
parse_envelope_or_throw (r);
}
private void parse_envelope_or_throw (Json.Reader r) throws Error {
r.read_element (0);
string? kind = r.get_string_value ();
@@ -452,6 +405,76 @@ namespace Frida {
throw new Error.PROTOCOL ("Unexpected JSON type: %s", type.name ());
}
}
public interface AndroidHelperTransport : Object {
public abstract async void close (Cancellable? cancellable) throws IOError;
public abstract async Json.Node request (Json.Node stanza, Cancellable? cancellable) throws Error, IOError;
}
public sealed class AndroidHelperStreamTransport : Object, AndroidHelperTransport {
public signal void closed ();
public IOStream stream {
get;
construct;
}
private BufferedInputStream input;
private OutputStream output;
private Cancellable io_cancellable = new Cancellable ();
private State state = CLOSED;
private Gee.Queue<Request> pending_requests = new Gee.ArrayQueue<Request> ();
private ByteArray pending_output = new ByteArray ();
private bool writing = false;
private enum State {
CLOSED,
OPEN
}
private const uint32 MAX_RESPONSE_SIZE = 100 * 1024 * 1024;
public AndroidHelperStreamTransport (IOStream stream) {
Object (stream: stream);
}
construct {
input = (BufferedInputStream) Object.new (typeof (BufferedInputStream),
"base-stream", stream.get_input_stream (),
"close-base-stream", false,
"buffer-size", 128 * 1024);
output = stream.get_output_stream ();
state = OPEN;
process_incoming_responses.begin ();
}
public async void close (Cancellable? cancellable) throws IOError {
io_cancellable.cancel ();
var source = new IdleSource ();
source.set_callback (close.callback);
source.attach (MainContext.get_thread_default ());
yield;
try {
yield stream.close_async (Priority.DEFAULT, cancellable);
} catch (IOError e) {
}
ensure_closed ();
}
private void ensure_closed () {
if (state == CLOSED)
return;
state = CLOSED;
closed ();
}
public async Json.Node request (Json.Node stanza, Cancellable? cancellable) throws Error, IOError {
if (state == CLOSED)
@@ -487,13 +510,6 @@ namespace Frida {
return r.response;
}
private async void request_ok (Json.Builder stanza, Cancellable? cancellable) throws Error, IOError {
Json.Node response = yield request (stanza.get_root (), cancellable);
var r = new Json.Reader (response);
parse_envelope_or_throw (r);
}
private void write_request (Json.Node request) {
string request_str = Json.to_string (request, false);
uint8[] request_data = request_str.data;
Binary file not shown.
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+2
View File
@@ -519,6 +519,8 @@ def function_is_public(name):
"check_kernel_version",
"get_syscall_signatures",
"get_compat32_syscall_signatures",
"get_xnu_mach_traps",
"get_xnu_bsd_syscalls",
"make_stdio_pipes",
"make_stdio_pipe",
}
+4 -4
View File
@@ -33,7 +33,7 @@
"@frida/url": "^1.0.2",
"@frida/util": "^1.0.3",
"@frida/vm": "^2.0.0",
"@types/frida-gum": "19.0.1",
"@types/frida-gum": "19.0.2",
"@types/node": "18.19.103",
"frida-fs": "7.0.0"
}
@@ -248,9 +248,9 @@
"license": "MIT"
},
"node_modules/@types/frida-gum": {
"version": "19.0.1",
"resolved": "https://registry.npmjs.org/@types/frida-gum/-/frida-gum-19.0.1.tgz",
"integrity": "sha512-mp8BpWWkQFJH86ZN5uXZuDiA7KY/+jDknrw0a06x0/+F5ucPwctHrCuV6iT+LLCp/GyICc36ssedF33B1WoLsw==",
"version": "19.0.2",
"resolved": "https://registry.npmjs.org/@types/frida-gum/-/frida-gum-19.0.2.tgz",
"integrity": "sha512-oh/f1r8dIMDWBoziXP3geIJ8ga/siU32MuifBztGsDglOKbHrhS0E3z0Dab0MIe3UFzC4Bvz/GRHfin2LDE8BQ==",
"license": "MIT"
},
"node_modules/@types/node": {
+1 -1
View File
@@ -29,7 +29,7 @@
"@frida/url": "^1.0.2",
"@frida/util": "^1.0.3",
"@frida/vm": "^2.0.0",
"@types/frida-gum": "19.0.1",
"@types/frida-gum": "19.0.2",
"@types/node": "18.19.103",
"frida-fs": "7.0.0"
}
+16 -12
View File
@@ -444,6 +444,7 @@ static void frida_set_nth_hardware_breakpoint (gpointer state, guint n, GumAddre
static void frida_set_hardware_single_step (gpointer debug_state, GumDarwinUnifiedThreadState * thread_state, gboolean enabled, GumCpuType cpu_type);
static gboolean frida_is_hardware_breakpoint_support_working (void);
static gboolean frida_find_restart_with_dyld_in_cache (const GumDarwinSymbolDetails * details, gpointer user_data);
static GumAddress frida_find_run_initializers_call (mach_port_t task, GumCpuType cpu_type, GumAddress start);
static GHashTable * frida_find_modinit_strcmp_checks (mach_port_t task, GumDarwinModule * dyld);
static GumAddress frida_find_function_end (mach_port_t task, GumCpuType cpu_type, GumAddress start, gsize max_size);
@@ -2107,18 +2108,8 @@ _frida_darwin_helper_backend_prepare_spawn_instance_for_injection (FridaDarwinHe
frida_spawn_instance_set_nth_breakpoint (instance, i++, sim_notify_address, FRIDA_BREAKPOINT_REPEAT_ALWAYS);
if (instance->dyld_flavor == FRIDA_DYLD_V4_PLUS)
{
GumAddress restart_with_dyld_in_cache = gum_darwin_module_resolve_symbol_address (dyld,
"__ZN5dyld422restartWithDyldInCacheEPKNS_10KernelArgsEPKN6mach_o6HeaderEPK15DyldSharedCachePv");
if (restart_with_dyld_in_cache == 0)
{
restart_with_dyld_in_cache = gum_darwin_module_resolve_symbol_address (dyld,
"__ZN5dyld422restartWithDyldInCacheEPKNS_10KernelArgsEPKN5dyld39MachOFileEPK15DyldSharedCachePv");
}
if (restart_with_dyld_in_cache == 0)
{
restart_with_dyld_in_cache = gum_darwin_module_resolve_symbol_address (dyld,
"__ZN5dyld422restartWithDyldInCacheEPKNS_10KernelArgsEPKN5dyld39MachOFileEPv");
}
GumAddress restart_with_dyld_in_cache = 0;
gum_darwin_module_enumerate_symbols (dyld, frida_find_restart_with_dyld_in_cache, &restart_with_dyld_in_cache);
if (restart_with_dyld_in_cache != 0)
frida_spawn_instance_set_nth_breakpoint (instance, i++, restart_with_dyld_in_cache, FRIDA_BREAKPOINT_REPEAT_NEVER);
}
@@ -5442,6 +5433,19 @@ frida_is_hardware_breakpoint_support_working (void)
#endif
}
static gboolean
frida_find_restart_with_dyld_in_cache (const GumDarwinSymbolDetails * details, gpointer user_data)
{
if (strstr (details->name, "restartWithDyldInCache") != NULL)
{
GumAddress * restart_with_dyld_in_cache = user_data;
*restart_with_dyld_in_cache = details->address;
return FALSE;
}
return TRUE;
}
static GumAddress
frida_find_run_initializers_call (mach_port_t task, GumCpuType cpu_type, GumAddress start)
{
+9 -6
View File
@@ -290,8 +290,9 @@ namespace Frida {
if (helper_client_request != null) {
AndroidHelperClient? helper = yield try_get_helper_client (cancellable);
if (helper != null) {
on_helper_client_closed (helper);
yield helper.close (cancellable);
var transport = (AndroidHelperStreamTransport) helper.transport;
on_helper_stream_transport_closed (transport);
yield transport.close (cancellable);
}
}
@@ -1060,8 +1061,10 @@ namespace Frida {
throw e;
}
var helper = new AndroidHelperClient (client.stream);
helper.closed.connect (on_helper_client_closed);
var transport = new AndroidHelperStreamTransport (client.stream);
transport.closed.connect (on_helper_stream_transport_closed);
var helper = new AndroidHelperClient (transport);
helper_shell = shell;
@@ -1080,8 +1083,8 @@ namespace Frida {
}
}
private void on_helper_client_closed (AndroidHelperClient helper) {
helper.closed.disconnect (on_helper_client_closed);
private void on_helper_stream_transport_closed (AndroidHelperStreamTransport transport) {
transport.closed.disconnect (on_helper_stream_transport_closed);
helper_client_request = null;
if (helper_shell != null) {
+401
View File
@@ -0,0 +1,401 @@
[CCode (gir_namespace = "FridaFruity", gir_version = "1.0")]
namespace Frida.Fruity {
public class CsSignature : Object {
public uint32 version;
public uint32 pid;
public uint32 stuff;
public uint32 flags;
public Gee.List<CsSigOwner> owners = new Gee.ArrayList<CsSigOwner> ();
private CsSegIndexEntry[]? seg_index = null;
private uint32 seg_index_gen = 0;
private struct CsSegIndexEntry {
public uint64 start;
public uint64 end;
public unowned CsSigOwner owner;
}
public void apply_refresh (CsSignature fresh, uint32 gen) {
foreach (var cur in owners) {
if (cur.mapped_gen_end != 0)
continue;
bool still_present = false;
foreach (var f in fresh.owners) {
if (cur.uuid.compare (f.uuid) == 0) {
still_present = true;
break;
}
}
if (!still_present)
cur.mapped_gen_end = gen;
}
foreach (var f in fresh.owners) {
CsSigOwner? cur = null;
foreach (var existing in owners) {
if (existing.uuid.compare (f.uuid) == 0) {
cur = existing;
break;
}
}
if (cur == null) {
f.mapped_gen_start = gen;
f.mapped_gen_end = 0;
owners.add (f);
} else {
uint32 start = cur.mapped_gen_start;
uint32 end = cur.mapped_gen_end;
cur.path = f.path;
cur.image_base = f.image_base;
cur.image_end = f.image_end;
cur.segments = f.segments;
cur.version = f.version;
cur.mapped_gen_start = start;
cur.mapped_gen_end = end;
}
}
invalidate_index ();
}
public void note_unmapped_uuid (Bytes uuid, uint32 gen) {
foreach (var o in owners) {
if (o.mapped_gen_end != 0)
continue;
if (o.uuid.compare (uuid) == 0) {
o.mapped_gen_end = gen;
invalidate_index ();
return;
}
}
}
public void resolve_addresses (uint32 gen, uint64[] addrs, AddressResolved on_symbol, ModulesReady on_modules) {
ensure_index (gen);
var used_owner_to_mod = new Gee.HashMap<CsSigOwner, uint32> ();
var module_list = new Gee.ArrayList<CsSigOwner> ();
foreach (var addr in addrs) {
CsSigOwner? owner;
uint32 rel;
if (!try_resolve (addr, out owner, out rel)) {
on_symbol (addr, uint32.MAX, 0);
continue;
}
uint32 mod_idx;
if (!used_owner_to_mod.has_key (owner)) {
mod_idx = (uint32) module_list.size;
used_owner_to_mod[owner] = mod_idx;
module_list.add (owner);
} else {
mod_idx = used_owner_to_mod[owner];
}
on_symbol (addr, mod_idx, rel);
}
on_modules (module_list);
}
public delegate void AddressResolved (uint64 addr, uint32 module_index, uint32 rel);
public delegate void ModulesReady (Gee.List<CsSigOwner> modules);
private void ensure_index (uint32 gen) {
if (seg_index != null && seg_index_gen == gen)
return;
var tmp = new Array<CsSegIndexEntry> (false, false);
foreach (var owner in owners) {
if (!owner_is_mapped_at (owner, gen))
continue;
foreach (var seg in owner.segments) {
if (seg.name == "__PAGEZERO")
continue;
tmp.append_val (CsSegIndexEntry () {
start = seg.vmaddr,
end = seg.vmaddr + seg.vmsize,
owner = owner,
});
}
}
tmp.sort ((a, b) => {
if (a.start < b.start)
return -1;
if (a.start > b.start)
return 1;
return 0;
});
seg_index = tmp.steal ();
seg_index_gen = gen;
}
private void invalidate_index () {
seg_index = null;
seg_index_gen = 0;
}
private bool try_resolve (uint64 addr, out CsSigOwner? owner, out uint32 rel) {
owner = null;
rel = 0;
int n = seg_index.length;
if (n == 0)
return false;
int lo = 0;
int hi = n - 1;
int best = -1;
while (lo <= hi) {
int mid = lo + ((hi - lo) / 2);
if (seg_index[mid].start <= addr) {
best = mid;
lo = mid + 1;
} else {
hi = mid - 1;
}
}
if (best == -1)
return false;
for (int i = best; i >= 0; i--) {
var e = seg_index[i];
if (e.start > addr)
continue;
if (addr < e.end) {
owner = e.owner;
rel = (uint32) (addr - owner.image_base);
return true;
}
}
return false;
}
private static bool owner_is_mapped_at (CsSigOwner owner, uint32 gen) {
if (gen < owner.mapped_gen_start)
return false;
uint32 end = owner.mapped_gen_end;
if (end == 0)
return true;
return gen < end;
}
}
public class CsSigOwner : Object {
public Bytes uuid;
public uint32 a;
public uint32 flags;
public uint64 load_timestamp;
public uint64 unload_timestamp;
public uint32 cpu_type;
public uint32 cpu_subtype;
public string path;
public uint64 image_base;
public uint64 image_end;
public Gee.List<CsSigSegment> segments = new Gee.ArrayList<CsSigSegment> ();
public string? version;
public uint32 mapped_gen_start = 1;
public uint32 mapped_gen_end = 0;
}
public class CsSigSegment {
public string name;
public uint64 vmaddr;
public uint64 vmsize;
}
public sealed class CsSignatureParser : Object {
private Buffer buf;
private BufferReader r;
public CsSignatureParser (Bytes blob) {
buf = new Buffer (blob, LITTLE_ENDIAN, 8);
r = new BufferReader (buf);
}
public CsSignature parse () throws Error {
uint32 magic = r.read_uint32 ();
uint32 version = r.read_uint32 ();
uint32 pid = r.read_uint32 ();
uint32 stuff = r.read_uint32 ();
uint32 flags = r.read_uint32 ();
uint32 owner_count = r.read_uint32 ();
if (magic != 0xff01ff02u)
throw new Error.PROTOCOL ("Bad signature magic 0x%08x", magic);
var sig = new CsSignature ();
sig.version = version;
sig.pid = pid;
sig.stuff = stuff;
sig.flags = flags;
for (uint32 i = 0; i != owner_count; i++)
sig.owners.add (parse_owner ());
decode_optional_data (sig);
return sig;
}
private CsSigOwner parse_owner () throws Error {
var o = new CsSigOwner ();
o.uuid = r.read_bytes (16);
o.a = r.read_uint32 ();
o.flags = r.read_uint32 () & 0x7fffffff;
o.load_timestamp = r.read_uint64 ();
o.unload_timestamp = r.read_uint64 ();
o.cpu_type = r.read_uint32 ();
o.cpu_subtype = r.read_uint32 ();
uint32 nsegs = r.read_uint32 ();
uint32 str_len = r.read_uint32 ();
o.path = r.read_fixed_string (str_len);
for (uint32 i = 0; i != nsegs; i++) {
var s = new CsSigSegment ();
s.name = r.read_fixed_string (16);
s.vmaddr = r.read_uint64 ();
s.vmsize = r.read_uint64 ();
o.segments.add (s);
}
o.segments.sort ((a, b) => {
if (a.vmaddr < b.vmaddr)
return -1;
if (a.vmaddr > b.vmaddr)
return 1;
return 0;
});
uint64 image_base = uint64.MAX;
uint64 image_end = 0;
foreach (var seg in o.segments) {
if (seg.name != "__PAGEZERO" && seg.vmaddr < image_base)
image_base = seg.vmaddr;
uint64 seg_end = seg.vmaddr + seg.vmsize;
if (seg_end > image_end)
image_end = seg_end;
}
o.image_base = image_base;
o.image_end = image_end;
return o;
}
private void decode_optional_data (CsSignature sig) throws Error {
if (r.available < 8)
return;
size_t start = r.offset;
uint64 hdr = r.read_uint64 ();
uint32 magic = (uint32) (hdr & 0xffffffffu);
uint32 sel = (uint32) (hdr >> 32);
if (magic != 0x00c0ffeeu) {
r.seek (start);
return;
}
if (sel == 2) {
if (r.available < 0x18)
throw new Error.PROTOCOL ("Optional v2 truncated");
r.skip (0x18);
return;
}
if (sel == 3) {
skip_optional_v3 ();
return;
}
if (sel != 4)
return;
size_t v3_start = r.offset;
uint32 count = skip_optional_v3 ();
size_t table_end = v3_start + 0x38 + (size_t) count * 0x60;
if (table_end + 4 > buf.size)
throw new Error.PROTOCOL ("Optional v4 truncated");
r.seek (table_end);
uint32 strings_size = r.read_uint32 ();
size_t strings_start = r.offset;
size_t strings_end = strings_start + (size_t) strings_size;
if (strings_end > buf.size)
throw new Error.PROTOCOL ("Optional v4 strings overrun");
r.seek (strings_start);
for (int i = 0; i < sig.owners.size; i++) {
if (r.offset >= strings_end)
throw new Error.PROTOCOL ("Optional v4 strings truncated");
sig.owners[i].version = r.read_string ();
}
r.seek (v3_start + 0x3c + (size_t) count * 0x60 + (size_t) strings_size);
}
private uint32 skip_optional_v3 () throws Error {
if (r.available < 0x38)
throw new Error.PROTOCOL ("Optional v3 truncated");
size_t base_offset = r.offset;
r.skip (0x30);
r.read_uint8 ();
r.skip (3);
uint32 count = r.read_uint32 ();
size_t total = 0x38 + (size_t) count * 0x60;
if (base_offset + total > buf.size)
throw new Error.PROTOCOL ("Optional v3 overrun");
r.seek (base_offset + total);
return count;
}
}
}
+2 -2
View File
@@ -50,8 +50,8 @@ namespace Frida.Fruity {
if (rr.key.klass != IN)
throw new Error.PROTOCOL ("Expected an AAAA record of class IN");
var subreader = new DnsPacketReader (rr.data);
var raw_address = subreader.reader.read_bytes (16);
var address = new InetAddress.from_bytes (raw_address.get_data (), IPV6);
unowned uint8[] raw_address = subreader.reader.read_data (16);
var address = new InetAddress.from_bytes (raw_address, IPV6);
return new DnsAaaaRecord () {
key = rr.key,
ttl = rr.ttl,
+787 -30
View File
@@ -69,6 +69,20 @@ namespace Frida.Fruity {
return result;
}
public async CsSignature query_symbolicator_signature (uint pid, Cancellable? cancellable = null) throws Error, IOError {
var args = new DTXArgumentListBuilder ()
.append_object (new NSNumber.from_integer (pid))
.append_object (new NSString (""));
var response = yield channel.invoke ("symbolicatorSignatureForPid:trackingSelector:", args, cancellable);
NSData? data = response as NSData;
if (data == null)
throw new Error.PROTOCOL ("Malformed response");
var parser = new CsSignatureParser (data.bytes);
return parser.parse ();
}
private static string resolve_real_app_name (string name) {
if (name.has_prefix ("/var/"))
return "/private" + name;
@@ -307,6 +321,8 @@ namespace Frida.Fruity {
}
public sealed class ProcessControlService : Object, AsyncInitable {
public signal void process_terminated (uint pid, int exit_code, int crashing_signal);
public HostChannelProvider channel_provider {
get;
construct;
@@ -335,15 +351,746 @@ namespace Frida.Fruity {
var connection = yield DTXConnection.obtain (channel_provider, cancellable);
channel = connection.make_channel ("com.apple.instruments.server.services.processcontrol");
channel.invocation.connect (on_invocation);
return true;
}
public async uint process_identifier_for_bundle_identifier (string bundle_id, Cancellable? cancellable = null)
throws Error, IOError {
var args = new DTXArgumentListBuilder ()
.append_object (new NSString (bundle_id));
var response = yield channel.invoke ("processIdentifierForBundleIdentifier:", args, cancellable);
NSNumber? pid = response as NSNumber;
if (pid == null)
throw new Error.PROTOCOL ("Malformed response");
return (uint) pid.integer;
}
public async bool is_pid_debuggable (uint pid, Cancellable? cancellable = null) throws Error, IOError {
var args = new DTXArgumentListBuilder ()
.append_object (new NSNumber.from_integer (pid));
var response = yield channel.invoke ("isPidDebuggable:", args, cancellable);
NSNumber? is_debuggable = response as NSNumber;
if (is_debuggable == null)
throw new Error.PROTOCOL ("Malformed response");
return is_debuggable.boolean;
}
public async void start_observing_pid (uint pid, Cancellable? cancellable = null) throws Error, IOError {
var args = new DTXArgumentListBuilder ()
.append_object (new NSNumber.from_integer (pid));
yield channel.invoke ("startObservingPid:", args, cancellable);
}
public async void stop_observing_pid (uint pid, Cancellable? cancellable = null) throws Error, IOError {
var args = new DTXArgumentListBuilder ()
.append_object (new NSNumber.from_integer (pid));
yield channel.invoke ("stopObservingPid:", args, cancellable);
}
public async uint launch (string bundle_id, LaunchOptions? options = null, Cancellable? cancellable = null)
throws Error, IOError {
var opts = options;
if (opts == null)
opts = new LaunchOptions ();
var args_val = new NSArray ();
foreach (unowned string arg in opts.arguments)
args_val.add_object (new NSString (arg));
var env_val = new NSDictionary ();
foreach (unowned string entry in opts.environment) {
string[] tokens = entry.split ("=", 2);
if (tokens.length != 2)
throw new Error.INVALID_ARGUMENT ("Invalid environment variable entry: %s", entry);
env_val.set_value (tokens[0], new NSString (tokens[1]));
}
var opts_val = new NSDictionary ();
opts_val.set_value ("StartSuspendedKey", new NSNumber.from_boolean (opts.launch_mode == SUSPENDED));
opts_val.set_value ("KillExisting", new NSNumber.from_boolean (opts.existing_instance_policy == KILL));
// TODO: Support CaptureOutput + iODestinationKey
var dtx_args = new DTXArgumentListBuilder ()
.append_object (new NSString (""))
.append_object (new NSString (bundle_id))
.append_object (env_val)
.append_object (args_val)
.append_object (opts_val);
var response = yield channel.invoke (
"launchSuspendedProcessWithDevicePath:bundleIdentifier:environment:arguments:options:",
dtx_args, cancellable);
NSNumber? pid = response as NSNumber;
if (pid == null)
throw new Error.PROTOCOL ("Malformed response");
return (uint) pid.integer;
}
public async void kill (uint pid, Cancellable? cancellable = null) throws Error, IOError {
var args = new DTXArgumentListBuilder ()
.append_object (new NSNumber.from_integer (pid));
yield channel.invoke ("killPid:", args, cancellable);
}
public async void send_signal (uint pid, uint sig, Cancellable? cancellable = null) throws Error, IOError {
var args = new DTXArgumentListBuilder ()
.append_object (new NSNumber.from_integer (sig))
.append_object (new NSNumber.from_integer (pid));
yield channel.invoke ("sendSignal:toPid:", args, cancellable);
}
private void on_invocation (string method_name, DTXArgumentList args, DTXMessageTransportFlags transport_flags) {
if (method_name == "processWithPID:terminatedWithExitCode:orCrashingSignal:") {
if (args.elements.length != 3)
return;
uint pid;
if (!try_parse_int (args.elements[0], out pid))
return;
int exit_code = -1;
int crashing_signal = -1;
if (!try_parse_int (args.elements[1], out exit_code)) {
if (!try_parse_int (args.elements[2], out crashing_signal))
return;
}
process_terminated (pid, exit_code, crashing_signal);
}
}
private bool try_parse_int (Value v, out int i) {
i = -1;
if (!v.holds (typeof (NSNumber)))
return false;
i = (int) ((NSNumber) v.get_object ()).integer;
return true;
}
}
public sealed class LaunchOptions : Object {
public string[] arguments {
get;
set;
default = {};
}
public string[] environment {
get;
set;
default = {};
}
public LaunchMode launch_mode {
get;
set;
default = LaunchMode.NORMAL;
}
public ExistingInstancePolicy existing_instance_policy {
get;
set;
default = ExistingInstancePolicy.KEEP;
}
}
public enum LaunchMode {
NORMAL,
SUSPENDED
}
public enum ExistingInstancePolicy {
KEEP,
KILL
}
public sealed class CoreProfileService : Object, AsyncInitable {
public signal void stackshot (Bytes blob);
public signal void kperfdata (Bytes blob);
public HostChannelProvider channel_provider {
get;
construct;
}
private DTXChannel channel;
private CoreProfileService (HostChannelProvider channel_provider) {
Object (channel_provider: channel_provider);
}
public static async CoreProfileService open (HostChannelProvider channel_provider, Cancellable? cancellable = null)
throws Error, IOError {
var service = new CoreProfileService (channel_provider);
try {
yield service.init_async (Priority.DEFAULT, cancellable);
} catch (GLib.Error e) {
throw_api_error (e);
}
return service;
}
private async bool init_async (int io_priority, Cancellable? cancellable) throws Error, IOError {
var connection = yield DTXConnection.obtain (channel_provider, cancellable);
channel = connection.make_channel ("com.apple.instruments.server.services.coreprofilesessiontap");
channel.notification.connect (on_notification);
channel.data.connect (on_data);
return true;
}
public async void set_config (KtraceConfig config, Cancellable? cancellable = null) throws Error, IOError {
var args = new DTXArgumentListBuilder ()
.append_object (config.encode ());
yield channel.invoke ("setConfig:", args, cancellable);
}
public async void start (Cancellable? cancellable = null) throws Error, IOError {
yield channel.invoke ("start", null, cancellable);
}
public async void stop (Cancellable? cancellable = null) throws Error, IOError {
yield channel.invoke ("stop", null, cancellable);
}
private void on_notification (NSObject obj) {
// printerr ("on_notification(): %s\n", obj.to_string ());
}
private void on_data (Bytes blob) {
if (Kcdata.is_stackshot (blob))
stackshot (blob);
else
kperfdata (blob);
}
}
public abstract class TapConfig : Object {
public TapRecordingMode buffer_mode {
get {
return _buffer_mode;
}
set {
_buffer_mode = value;
if (value != POLLED)
_polling_interval = 0;
}
}
public uint64 polling_interval {
get;
set;
default = 500;
}
public uint64 window_size {
get;
set;
default = 0;
}
public bool spool_to_disk_when_possible {
get;
set;
default = false;
}
public bool discard_heartbeats_when_possible {
get;
set;
default = false;
}
private TapRecordingMode _buffer_mode = POLLED;
internal virtual NSDictionary encode () {
var dict = new NSDictionary ();
dict.set_value ("bm", new NSNumber.from_integer (_buffer_mode));
if (_polling_interval != 0)
dict.set_value ("ur", new NSNumber.from_integer ((int64) _polling_interval));
if (_window_size != 0)
dict.set_value ("ws", new NSNumber.from_integer ((int64) _window_size));
if (_spool_to_disk_when_possible)
dict.set_value ("s2d", new NSNumber.from_boolean (true));
if (_discard_heartbeats_when_possible)
dict.set_value ("nohb", new NSNumber.from_boolean (true));
return dict;
}
}
public enum TapRecordingMode {
POLLED,
IMMEDIATE,
WINDOWED,
}
public sealed class KtraceConfig : TapConfig {
public bool can_use_raw_ktrace_file {
get;
set;
default = false;
}
public KtraceRecordingPriority recording_priority {
get;
set;
default = FOREGROUND;
}
public uint collection_interval {
get;
set;
default = 0;
}
public uint64 buffer_size_override {
get;
set;
default = 0;
}
public uint64 buffer_size_override_clamping {
get;
set;
default = 0;
}
public NSDictionary? provider_options {
get;
set;
default = null;
}
private Gee.List<KtraceTapTriggerConfig> trigger_configs = new Gee.ArrayList<KtraceTapTriggerConfig> ();
public void add_trigger_config (KtraceTapTriggerConfig tc) {
trigger_configs.add (tc);
}
internal override NSDictionary encode () {
var dict = base.encode ();
if (can_use_raw_ktrace_file)
dict.set_value ("curkt", new NSNumber.from_boolean (true));
dict.set_value ("rp", new NSNumber.from_integer (_recording_priority));
if (_collection_interval != 0)
dict.set_value ("kco", new NSNumber.from_integer (_collection_interval));
if (_buffer_size_override != 0)
dict.set_value ("bso", new NSNumber.from_integer ((int64) _buffer_size_override));
if (_buffer_size_override_clamping != 0)
dict.set_value ("bsoc", new NSNumber.from_integer ((int64) _buffer_size_override_clamping));
if (_provider_options != null)
dict.set_value ("po", _provider_options);
var tc = new NSArray ();
foreach (var cfg in trigger_configs)
tc.add_object (cfg.encode ());
dict.set_value ("tc", tc);
return dict;
}
}
public enum KtraceRecordingPriority {
BACKGROUND = 10,
FOREGROUND = 100,
}
public sealed class KtraceTapTriggerConfig : Object {
public KtraceTapTriggerKind kind {
get;
construct;
}
public KdebugCodeSet? filter {
get;
set;
}
public bool is_all_processes {
get {
return included_pids == null;
}
set {
if (value)
included_pids = null;
else
ensure_included_pids ();
}
}
public uint callstack_frame_depth {
get;
set;
default = 0;
}
public KtraceTapActions actions {
get;
default = new KtraceTapActions ();
}
private Gee.Set<uint>? included_pids = null;
public KtraceTapTriggerConfig (KtraceTapTriggerKind kind) {
Object (kind: kind);
}
public void include_pid (uint pid) {
ensure_included_pids ().add (pid);
}
private unowned Gee.Set<uint> ensure_included_pids () {
if (included_pids == null)
included_pids = new Gee.HashSet<uint> ();
return included_pids;
}
internal NSDictionary encode () {
var dict = new NSDictionary ();
dict.set_value ("uuid", new NSString (Uuid.string_random ().up ()));
dict.set_value ("tk", new NSNumber.from_integer (_kind));
if (_filter != null) {
dict.set_value ("kdf", new NSString (_filter.legacy_xml));
dict.set_value ("kdf2", _filter.kdebug_codes);
}
if (included_pids != null) {
var pf = new NSArray ();
foreach (var pid in included_pids)
pf.add_object (new NSNumber.from_integer (pid));
dict.set_value ("pf", pf);
}
if (_callstack_frame_depth != 0)
dict.set_value ("csd", new NSNumber.from_integer (_callstack_frame_depth));
var actions = _actions.items;
if (!actions.is_empty) {
var arr = new NSArray ();
foreach (var action in actions)
arr.add_object (action.encode ());
dict.set_value ("ta", arr);
}
return dict;
}
}
public enum KtraceTapTriggerKind {
TIME = 1,
PMI,
KDEBUG,
}
public sealed class KtraceTapActions : Object {
internal Gee.List<KtraceTapAction> items = new Gee.ArrayList<KtraceTapAction> ();
public unowned KtraceTapActions add (KtraceTapAction action) {
items.add (action);
return this;
}
public unowned KtraceTapActions add_stack_collection (KtraceTapStackCollectionMode mode) {
items.add (new KtraceTapStackCollectionAction (mode));
return this;
}
public unowned KtraceTapActions add_baseline () {
items.add (new KtraceTapAction0 ());
items.add (new KtraceTapAction2 ());
return this;
}
public unowned KtraceTapActions add_pmc_event (string event_name, string counter_name, uint32 extra = 0) {
items.add (new KtraceTapAddPmcEventAction (event_name, counter_name, extra));
return this;
}
public unowned KtraceTapActions add_kdebug_codeset (KdebugCodeSet codeset) {
items.add (new KtraceTapAddKdebugCodeSetAction (codeset.kdebug_codes));
return this;
}
public unowned KtraceTapActions add_kdebug_legacy_backtrace_filter () {
items.add (new KtraceTapKdebugBacktraceFilterAction ());
return this;
}
}
public enum KtraceTapActionKind {
ACTION0,
STACK_COLLECTION,
ACTION2,
KDEBUG_BACKTRACE_FILTER,
ADD_PMC_EVENT,
ADD_KDEBUG_CODESET,
}
public abstract class KtraceTapAction : Object {
public abstract KtraceTapActionKind kind {
get;
}
internal abstract NSArray encode ();
}
public sealed class KtraceTapAction0 : KtraceTapAction {
public override KtraceTapActionKind kind {
get {
return ACTION0;
}
}
internal override NSArray encode () {
var a = new NSArray ();
a.add_object (new NSNumber.from_integer (kind));
return a;
}
}
public sealed class KtraceTapAction2 : KtraceTapAction {
public override KtraceTapActionKind kind {
get {
return ACTION2;
}
}
internal override NSArray encode () {
var a = new NSArray ();
a.add_object (new NSNumber.from_integer (kind));
return a;
}
}
public sealed class KtraceTapStackCollectionAction : KtraceTapAction {
public KtraceTapStackCollectionMode mode {
get {
return _mode;
}
set {
_mode = value;
}
}
private KtraceTapStackCollectionMode _mode;
public KtraceTapStackCollectionAction (KtraceTapStackCollectionMode mode) {
_mode = mode;
}
public override KtraceTapActionKind kind {
get {
return STACK_COLLECTION;
}
}
internal override NSArray encode () {
var a = new NSArray ();
a.add_object (new NSNumber.from_integer (kind));
a.add_object (new NSNumber.from_boolean ((_mode & KtraceTapStackCollectionMode.USER) != 0));
a.add_object (new NSNumber.from_boolean ((_mode & KtraceTapStackCollectionMode.KERNEL) != 0));
return a;
}
}
[Flags]
public enum KtraceTapStackCollectionMode {
NONE = 0,
USER = (1 << 0),
KERNEL = (1 << 1),
}
public sealed class KtraceTapKdebugBacktraceFilterAction : KtraceTapAction {
public override KtraceTapActionKind kind {
get {
return KDEBUG_BACKTRACE_FILTER;
}
}
internal override NSArray encode () {
var a = new NSArray ();
a.add_object (new NSNumber.from_integer (kind));
return a;
}
}
public sealed class KtraceTapAddPmcEventAction : KtraceTapAction {
public string event_name {
get {
return _event_name;
}
set {
_event_name = value;
}
}
public string counter_name {
get {
return _counter_name;
}
set {
_counter_name = value;
}
}
public uint32 extra {
get {
return _extra;
}
set {
_extra = value;
}
}
private string _event_name;
private string _counter_name;
private uint32 _extra;
public KtraceTapAddPmcEventAction (string event_name, string counter_name, uint32 extra = 0) {
_event_name = event_name;
_counter_name = counter_name;
_extra = extra;
}
public override KtraceTapActionKind kind {
get {
return ADD_PMC_EVENT;
}
}
internal override NSArray encode () {
var a = new NSArray ();
a.add_object (new NSNumber.from_integer (kind));
a.add_object (new NSString (_event_name));
a.add_object (new NSString (_counter_name));
a.add_object (new NSNumber.from_integer (_extra));
return a;
}
}
public sealed class KtraceTapAddKdebugCodeSetAction : KtraceTapAction {
public NSSet codes {
get {
return _codes;
}
set {
_codes = value;
}
}
private NSSet _codes;
public KtraceTapAddKdebugCodeSetAction (NSSet codes) {
_codes = codes;
}
public override KtraceTapActionKind kind {
get {
return ADD_KDEBUG_CODESET;
}
}
internal override NSArray encode () {
var a = new NSArray ();
a.add_object (new NSNumber.from_integer (kind));
a.add_object (_codes);
return a;
}
}
public sealed class KdebugCodeSet : Object {
public string legacy_xml {
owned get {
var xml = new StringBuilder.sized (256);
xml.append ("<events>");
foreach (var c in codes) {
var kc = KdebugCode (c);
xml.append ("<event type=\"KDebug\" class=\"");
var klass = kc.klass;
if (klass == ANY)
xml.append_c ('*');
else
xml.append_printf ("%u", klass);
xml.append ("\" subclass=\"");
var subclass = kc.subclass;
if (subclass == KDEBUG_SUBCLASS_ANY)
xml.append_c ('*');
else
xml.append_printf ("%u", subclass);
xml.append ("\" code=\"");
uint code = kc.code;
if (code == KDEBUG_CODE_ANY)
xml.append_c ('*');
else
xml.append_printf ("%u", code);
xml.append ("\"/>");
}
xml.append ("</events>");
return xml.str;
}
}
public NSSet kdebug_codes {
get {
if (_kdebug_codes == null) {
_kdebug_codes = new NSSet ();
foreach (var c in codes)
_kdebug_codes.add_object (new NSNumber.from_integer (c));
}
return _kdebug_codes;
}
}
private Gee.Set<uint> codes = new Gee.HashSet<uint> ();
private NSSet _kdebug_codes = null;
public KdebugCodeSet copy () {
var s = new KdebugCodeSet ();
s.codes.add_all (codes);
s._kdebug_codes = _kdebug_codes;
return s;
}
public unowned KdebugCodeSet add (KdebugCode code) {
codes.add (code.raw);
_kdebug_codes = null;
return this;
}
}
public sealed class DTXConnection : Object, DTXTransport {
@@ -373,7 +1120,6 @@ namespace Frida.Fruity {
private Gee.HashMap<uint32, Gee.ArrayList<Fragment>> fragments = new Gee.HashMap<uint32, Gee.ArrayList<Fragment>> ();
private uint32 next_fragment_identifier = 1;
private size_t total_buffered = 0;
private Gee.ArrayQueue<Bytes> pending_writes = new Gee.ArrayQueue<Bytes> ();
private DTXControlChannel control_channel;
@@ -381,8 +1127,6 @@ namespace Frida.Fruity {
private int32 next_channel_code = 1;
private const uint32 DTX_FRAGMENT_MAGIC = 0x1f3d5b79U;
private const uint MAX_BUFFERED_COUNT = 100;
private const size_t MAX_BUFFERED_SIZE = 30 * 1024 * 1024;
private const size_t MAX_MESSAGE_SIZE = 128 * 1024 * 1024;
private const size_t MAX_FRAGMENT_SIZE = 128 * 1024;
private const string REMOTESERVER_ENDPOINT_17PLUS = "lockdown:com.apple.instruments.dtservicehub";
@@ -566,8 +1310,6 @@ namespace Frida.Fruity {
Gee.ArrayList<Fragment> entries = fragments[fragment.identifier];
if (entries == null) {
if (fragments.size == MAX_BUFFERED_COUNT)
throw new Error.PROTOCOL ("Total buffered count exceeds maximum");
if (fragment.index != 0)
throw new Error.PROTOCOL ("Expected first fragment to have index of zero");
fragment.data_size = 0;
@@ -585,10 +1327,6 @@ namespace Frida.Fruity {
first_fragment.data_size += (uint32) size;
if (first_fragment.data_size > MAX_MESSAGE_SIZE)
throw new Error.PROTOCOL ("Message size exceeds maximum");
total_buffered += size;
if (total_buffered > MAX_BUFFERED_SIZE)
throw new Error.PROTOCOL ("Total buffered size exceeds maximum");
}
if (entries.size == fragment.count) {
@@ -614,7 +1352,6 @@ namespace Frida.Fruity {
}
fragments.unset (fragment.identifier);
total_buffered -= message.length;
process_message (message, first_fragment);
}
@@ -714,33 +1451,37 @@ namespace Frida.Fruity {
message.payload_data = raw_message[payload_start_offset:payload_end_offset];
int32 channel_code = message.channel_code;
bool is_notification = false;
if (message.type == INVOKE) {
if ((message.conversation_index % 2) == 0)
channel_code = -channel_code;
} else if (message.type == RESULT && channel_code < 0) {
channel_code = -channel_code;
is_notification = true;
}
bool is_notification = message.conversation_index == 0;
var channel = channels[channel_code];
if (channel == null)
return;
switch (message.type) {
case INVOKE:
channel.handle_invoke (message);
case DISPATCH:
channel.handle_dispatch (message);
break;
case OK:
case RESULT:
case OBJECT:
case ERROR:
if (is_notification)
channel.handle_notification (message);
else
channel.handle_response (message);
break;
case DATA:
channel.handle_data (message);
break;
case BARRIER:
channel.handle_barrier (message);
break;
case PRIMITIVE:
case COMPRESSED:
case PROXIED_MESSAGE:
throw new Error.PROTOCOL ("Unsupported message type: %s", message.type.to_string ());
}
}
@@ -855,7 +1596,8 @@ namespace Frida.Fruity {
public void notify_of_published_capabilities () throws Error {
var capabilities = new NSDictionary ();
capabilities.set_value ("com.apple.private.DTXConnection", new NSNumber.from_integer (1));
capabilities.set_value ("com.apple.private.DTXBlockCompression", new NSNumber.from_integer (2));
capabilities.set_value ("com.apple.instruments.client.processcontrol.capability.terminationCallback",
new NSNumber.from_integer (1));
var args = new DTXArgumentListBuilder ()
.append_object (capabilities);
@@ -879,6 +1621,7 @@ namespace Frida.Fruity {
public class DTXChannel : Object {
public signal void invocation (string method_name, DTXArgumentList args, DTXMessageTransportFlags transport_flags);
public signal void notification (NSObject obj);
public signal void data (Bytes blob);
public signal void barrier ();
public int32 code {
@@ -935,7 +1678,7 @@ namespace Frida.Fruity {
check_open ();
var message = DTXMessage ();
message.type = INVOKE;
message.type = DISPATCH;
message.channel_code = code;
message.transport_flags = EXPECTS_REPLY;
@@ -965,7 +1708,7 @@ namespace Frida.Fruity {
check_open ();
var message = DTXMessage ();
message.type = INVOKE;
message.type = DISPATCH;
message.channel_code = code;
message.transport_flags = NONE;
@@ -982,10 +1725,10 @@ namespace Frida.Fruity {
transport.send_message (message, out identifier);
}
internal void handle_invoke (DTXMessage message) throws Error {
internal void handle_dispatch (DTXMessage message) throws Error {
NSString? method_name = NSKeyedArchive.decode (message.payload_data) as NSString;
if (method_name == null)
throw new Error.PROTOCOL ("Malformed invocation payload");
throw new Error.PROTOCOL ("Malformed dispatch payload");
var args = DTXArgumentList.parse (message.aux_data);
@@ -999,7 +1742,7 @@ namespace Frida.Fruity {
case OK:
request.resolve (null);
break;
case RESULT:
case OBJECT:
request.resolve (NSKeyedArchive.decode (message.payload_data));
break;
case ERROR: {
@@ -1037,6 +1780,10 @@ namespace Frida.Fruity {
notification (payload);
}
internal void handle_data (DTXMessage message) throws Error {
data (new Bytes (message.payload_data));
}
internal void handle_barrier (DTXMessage message) throws Error {
barrier ();
}
@@ -1053,11 +1800,15 @@ namespace Frida.Fruity {
}
public enum DTXMessageType {
OK = 0,
INVOKE = 2,
RESULT = 3,
ERROR = 4,
BARRIER = 5
OK,
DATA,
DISPATCH,
OBJECT,
ERROR,
BARRIER,
PRIMITIVE,
COMPRESSED,
PROXIED_MESSAGE,
}
public struct DTXMessage {
@@ -1111,6 +1862,12 @@ namespace Frida.Fruity {
}
case BUFFER: {
size_t size = reader.read_uint32 ();
if (size == 0) {
var gval = Value (typeof (NSObject));
elements += (owned) gval;
break;
}
unowned uint8[] buf = reader.read_byte_array (size);
NSObject? obj = NSKeyedArchive.decode (buf);
File diff suppressed because it is too large. Load diff
+558
View File
@@ -0,0 +1,558 @@
[CCode (gir_namespace = "FridaFruity", gir_version = "1.0")]
namespace Frida.Fruity.Kcdata {
public struct ItemHeader {
public ItemType type;
public uint32 size;
public uint64 flags;
}
public enum ItemType {
INVALID = 0x000u,
STRING_DESC = 0x001u,
UINT32_DESC = 0x002u,
UINT64_DESC = 0x003u,
INT32_DESC = 0x004u,
INT64_DESC = 0x005u,
BINDATA_DESC = 0x006u,
ARRAY = 0x011u,
TYPEDEFINTION = 0x012u,
CONTAINER_BEGIN = 0x013u,
CONTAINER_END = 0x014u,
ARRAY_PAD0 = 0x020u,
ARRAY_PAD1 = 0x021u,
ARRAY_PAD2 = 0x022u,
ARRAY_PAD3 = 0x023u,
ARRAY_PAD4 = 0x024u,
ARRAY_PAD5 = 0x025u,
ARRAY_PAD6 = 0x026u,
ARRAY_PAD7 = 0x027u,
ARRAY_PAD8 = 0x028u,
ARRAY_PAD9 = 0x029u,
ARRAY_PADa = 0x02au,
ARRAY_PADb = 0x02bu,
ARRAY_PADc = 0x02cu,
ARRAY_PADd = 0x02du,
ARRAY_PADe = 0x02eu,
ARRAY_PADf = 0x02fu,
LIBRARY_LOADINFO = 0x030u,
LIBRARY_LOADINFO64 = 0x031u,
TIMEBASE = 0x032u,
MACH_ABSOLUTE_TIME = 0x033u,
TIMEVAL = 0x034u,
USECS_SINCE_EPOCH = 0x035u,
PID = 0x036u,
PROCNAME = 0x037u,
NESTED_KCDATA = 0x038u,
LIBRARY_AOTINFO = 0x039u,
TASK_CRASHINFO_EXTMODINFO = 0x801u,
TASK_CRASHINFO_BSDINFOWITHUNIQID = 0x802u,
TASK_CRASHINFO_TASKDYLD_INFO = 0x803u,
TASK_CRASHINFO_UUID = 0x804u,
TASK_CRASHINFO_PID = 0x805u,
TASK_CRASHINFO_PPID = 0x806u,
TASK_CRASHINFO_RUSAGE = 0x807u,
TASK_CRASHINFO_RUSAGE_INFO = 0x808u,
TASK_CRASHINFO_PROC_NAME = 0x809u,
TASK_CRASHINFO_PROC_STARTTIME = 0x80Bu,
TASK_CRASHINFO_USERSTACK = 0x80Cu,
TASK_CRASHINFO_ARGSLEN = 0x80Du,
TASK_CRASHINFO_EXCEPTION_CODES = 0x80Eu,
TASK_CRASHINFO_PROC_PATH = 0x80Fu,
TASK_CRASHINFO_PROC_CSFLAGS = 0x810u,
TASK_CRASHINFO_PROC_STATUS = 0x811u,
TASK_CRASHINFO_UID = 0x812u,
TASK_CRASHINFO_GID = 0x813u,
TASK_CRASHINFO_PROC_ARGC = 0x814u,
TASK_CRASHINFO_PROC_FLAGS = 0x815u,
TASK_CRASHINFO_CPUTYPE = 0x816u,
TASK_CRASHINFO_WORKQUEUEINFO = 0x817u,
TASK_CRASHINFO_RESPONSIBLE_PID = 0x818u,
TASK_CRASHINFO_DIRTY_FLAGS = 0x819u,
TASK_CRASHINFO_CRASHED_THREADID = 0x81Au,
TASK_CRASHINFO_COALITION_ID = 0x81Bu,
TASK_CRASHINFO_UDATA_PTRS = 0x81Cu,
TASK_CRASHINFO_MEMORY_LIMIT = 0x81Du,
TASK_CRASHINFO_LEDGER_INTERNAL = 0x81Eu,
TASK_CRASHINFO_LEDGER_INTERNAL_COMPRESSED = 0x81Fu,
TASK_CRASHINFO_LEDGER_IOKIT_MAPPED = 0x820u,
TASK_CRASHINFO_LEDGER_ALTERNATE_ACCOUNTING = 0x821u,
TASK_CRASHINFO_LEDGER_ALTERNATE_ACCOUNTING_COMPRESSED = 0x822u,
TASK_CRASHINFO_LEDGER_PURGEABLE_NONVOLATILE = 0x823u,
TASK_CRASHINFO_LEDGER_PURGEABLE_NONVOLATILE_COMPRESSED = 0x824u,
TASK_CRASHINFO_LEDGER_PAGE_TABLE = 0x825u,
TASK_CRASHINFO_LEDGER_PHYS_FOOTPRINT = 0x826u,
TASK_CRASHINFO_LEDGER_PHYS_FOOTPRINT_LIFETIME_MAX = 0x827u,
TASK_CRASHINFO_LEDGER_NETWORK_NONVOLATILE = 0x828u,
TASK_CRASHINFO_LEDGER_NETWORK_NONVOLATILE_COMPRESSED = 0x829u,
TASK_CRASHINFO_LEDGER_WIRED_MEM = 0x82Au,
TASK_CRASHINFO_PROC_PERSONA_ID = 0x82Bu,
TASK_CRASHINFO_MEMORY_LIMIT_INCREASE = 0x82Cu,
TASK_CRASHINFO_LEDGER_TAGGED_FOOTPRINT = 0x82Du,
TASK_CRASHINFO_LEDGER_TAGGED_FOOTPRINT_COMPRESSED = 0x82Eu,
TASK_CRASHINFO_LEDGER_MEDIA_FOOTPRINT = 0x82Fu,
TASK_CRASHINFO_LEDGER_MEDIA_FOOTPRINT_COMPRESSED = 0x830u,
TASK_CRASHINFO_LEDGER_GRAPHICS_FOOTPRINT = 0x831u,
TASK_CRASHINFO_LEDGER_GRAPHICS_FOOTPRINT_COMPRESSED = 0x832u,
TASK_CRASHINFO_LEDGER_NEURAL_FOOTPRINT = 0x833u,
TASK_CRASHINFO_LEDGER_NEURAL_FOOTPRINT_COMPRESSED = 0x834u,
TASK_CRASHINFO_MEMORYSTATUS_EFFECTIVE_PRIORITY = 0x835u,
TASK_CRASHINFO_KERNEL_TRIAGE_INFO_V1 = 0x836u,
TASK_CRASHINFO_TASK_IS_CORPSE_FORK = 0x837u,
TASK_CRASHINFO_EXCEPTION_TYPE = 0x838u,
TASK_CRASHINFO_CRASH_COUNT = 0x839u,
TASK_CRASHINFO_THROTTLE_TIMEOUT = 0x83Au,
TASK_CRASHINFO_CS_SIGNING_ID = 0x83Bu,
TASK_CRASHINFO_CS_TEAM_ID = 0x83Cu,
TASK_CRASHINFO_CS_VALIDATION_CATEGORY = 0x83Du,
TASK_CRASHINFO_CS_TRUST_LEVEL = 0x83Eu,
TASK_CRASHINFO_PROC_CPUTYPE = 0x83Fu,
TASK_CRASHINFO_JIT_ADDRESS_RANGE = 0x840u,
TASK_CRASHINFO_MB = 0x841u,
TASK_CRASHINFO_CS_AUXILIARY_INFO = 0x842u,
TASK_CRASHINFO_RLIM_CORE = 0x843u,
TASK_CRASHINFO_CORE_ALLOWED = 0x844u,
TASK_CRASHINFO_TASK_SECURITY_CONFIG = 0x845u,
STACKSHOT_IOSTATS = 0x901u,
STACKSHOT_GLOBAL_MEM_STATS = 0x902u,
STACKSHOT_CONTAINER_TASK = 0x903u,
STACKSHOT_CONTAINER_THREAD = 0x904u,
STACKSHOT_TASK_SNAPSHOT = 0x905u,
STACKSHOT_THREAD_SNAPSHOT = 0x906u,
STACKSHOT_DONATING_PIDS = 0x907u,
STACKSHOT_SHAREDCACHE_LOADINFO = 0x908u,
STACKSHOT_THREAD_NAME = 0x909u,
STACKSHOT_KERN_STACKFRAME = 0x90Au,
STACKSHOT_KERN_STACKFRAME64 = 0x90Bu,
STACKSHOT_USER_STACKFRAME = 0x90Cu,
STACKSHOT_USER_STACKFRAME64 = 0x90Du,
STACKSHOT_BOOTARGS = 0x90Eu,
STACKSHOT_OSVERSION = 0x90Fu,
STACKSHOT_KERN_PAGE_SIZE = 0x910u,
STACKSHOT_JETSAM_LEVEL = 0x911u,
STACKSHOT_DELTA_SINCE_TIMESTAMP = 0x912u,
STACKSHOT_KERN_STACKLR = 0x913u,
STACKSHOT_KERN_STACKLR64 = 0x914u,
STACKSHOT_USER_STACKLR = 0x915u,
STACKSHOT_USER_STACKLR64 = 0x916u,
STACKSHOT_NONRUNNABLE_TIDS = 0x917u,
STACKSHOT_NONRUNNABLE_TASKS = 0x918u,
STACKSHOT_CPU_TIMES = 0x919u,
STACKSHOT_STACKSHOT_DURATION = 0x91au,
STACKSHOT_STACKSHOT_FAULT_STATS = 0x91bu,
STACKSHOT_KERNELCACHE_LOADINFO = 0x91cu,
STACKSHOT_THREAD_WAITINFO = 0x91du,
STACKSHOT_THREAD_GROUP_SNAPSHOT = 0x91eu,
STACKSHOT_THREAD_GROUP = 0x91fu,
STACKSHOT_JETSAM_COALITION_SNAPSHOT = 0x920u,
STACKSHOT_JETSAM_COALITION = 0x921u,
STACKSHOT_THREAD_POLICY_VERSION = 0x922u,
STACKSHOT_INSTRS_CYCLES = 0x923u,
STACKSHOT_USER_STACKTOP = 0x924u,
STACKSHOT_ASID = 0x925u,
STACKSHOT_PAGE_TABLES = 0x926u,
STACKSHOT_SYS_SHAREDCACHE_LAYOUT = 0x927u,
STACKSHOT_THREAD_DISPATCH_QUEUE_LABEL = 0x928u,
STACKSHOT_THREAD_TURNSTILEINFO = 0x929u,
STACKSHOT_TASK_CPU_ARCHITECTURE = 0x92au,
STACKSHOT_LATENCY_INFO = 0x92bu,
STACKSHOT_LATENCY_INFO_TASK = 0x92cu,
STACKSHOT_LATENCY_INFO_THREAD = 0x92du,
STACKSHOT_LOADINFO64_TEXT_EXEC = 0x92eu,
STACKSHOT_AOTCACHE_LOADINFO = 0x92fu,
STACKSHOT_TRANSITIONING_TASK_SNAPSHOT = 0x930u,
STACKSHOT_CONTAINER_TRANSITIONING_TASK = 0x931u,
STACKSHOT_USER_ASYNC_START_INDEX = 0x932u,
STACKSHOT_USER_ASYNC_STACKLR64 = 0x933u,
STACKSHOT_CONTAINER_PORTLABEL = 0x934u,
STACKSHOT_PORTLABEL = 0x935u,
STACKSHOT_PORTLABEL_NAME = 0x936u,
STACKSHOT_DYLD_COMPACTINFO = 0x937u,
STACKSHOT_SUSPENSION_INFO = 0x938u,
STACKSHOT_SUSPENSION_SOURCE = 0x939u,
STACKSHOT_TASK_DELTA_SNAPSHOT = 0x940u,
STACKSHOT_THREAD_DELTA_SNAPSHOT = 0x941u,
STACKSHOT_CONTAINER_SHAREDCACHE = 0x942u,
STACKSHOT_SHAREDCACHE_INFO = 0x943u,
STACKSHOT_SHAREDCACHE_AOTINFO = 0x944u,
STACKSHOT_SHAREDCACHE_ID = 0x945u,
STACKSHOT_CODESIGNING_INFO = 0x946u,
STACKSHOT_OS_BUILD_VERSION = 0x947u,
STACKSHOT_KERN_EXCLAVES_THREADINFO = 0x948u,
STACKSHOT_CONTAINER_EXCLAVES = 0x949u,
STACKSHOT_CONTAINER_EXCLAVE_SCRESULT = 0x94au,
STACKSHOT_EXCLAVE_SCRESULT_INFO = 0x94bu,
STACKSHOT_CONTAINER_EXCLAVE_IPCSTACKENTRY = 0x94cu,
STACKSHOT_EXCLAVE_IPCSTACKENTRY_INFO = 0x94du,
STACKSHOT_EXCLAVE_IPCSTACKENTRY_ECSTACK = 0x94eu,
STACKSHOT_CONTAINER_EXCLAVE_ADDRESSSPACE = 0x94fu,
STACKSHOT_EXCLAVE_ADDRESSSPACE_INFO = 0x950u,
STACKSHOT_EXCLAVE_ADDRESSSPACE_NAME = 0x951u,
STACKSHOT_CONTAINER_EXCLAVE_TEXTLAYOUT = 0x952u,
STACKSHOT_EXCLAVE_TEXTLAYOUT_INFO = 0x953u,
STACKSHOT_EXCLAVE_TEXTLAYOUT_SEGMENTS = 0x954u,
STACKSHOT_KERN_EXCLAVES_CRASH_THREADINFO = 0x955u,
STACKSHOT_LATENCY_INFO_CPU = 0x956u,
STACKSHOT_TASK_EXEC_META = 0x957u,
STACKSHOT_TASK_MEMORYSTATUS = 0x958u,
STACKSHOT_LATENCY_INFO_BUFFER = 0x95au,
TASK_BTINFO_PID = 0xA01u,
TASK_BTINFO_PPID = 0xA02u,
TASK_BTINFO_PROC_NAME = 0xA03u,
TASK_BTINFO_PROC_PATH = 0xA04u,
TASK_BTINFO_UID = 0xA05u,
TASK_BTINFO_GID = 0xA06u,
TASK_BTINFO_PROC_FLAGS = 0xA07u,
TASK_BTINFO_CPUTYPE = 0xA08u,
TASK_BTINFO_EXCEPTION_CODES = 0xA09u,
TASK_BTINFO_EXCEPTION_TYPE = 0xA0Au,
TASK_BTINFO_RUSAGE_INFO = 0xA0Bu,
TASK_BTINFO_COALITION_ID = 0xA0Cu,
TASK_BTINFO_CRASH_COUNT = 0xA0Du,
TASK_BTINFO_THROTTLE_TIMEOUT = 0xA0Eu,
TASK_BTINFO_THREAD_ID = 0xA20u,
TASK_BTINFO_THREAD_NAME = 0xA21u,
TASK_BTINFO_THREAD_STATE = 0xA22u,
TASK_BTINFO_THREAD_EXCEPTION_STATE = 0xA23u,
TASK_BTINFO_BACKTRACE = 0xA24u,
TASK_BTINFO_BACKTRACE64 = 0xA25u,
TASK_BTINFO_ASYNC_BACKTRACE64 = 0xA26u,
TASK_BTINFO_ASYNC_START_INDEX = 0xA27u,
TASK_BTINFO_PLATFORM = 0xA28u,
TASK_BTINFO_SC_LOADINFO = 0xA29u,
TASK_BTINFO_SC_LOADINFO64 = 0xA2Au,
TASK_BTINFO_FLAGS = 0xAFFu,
BUFFER_BEGIN_XNUPOST_CONFIG = 0x1e21c09fu,
BUFFER_BEGIN_COMPRESSED = 0x434f4d50u,
BUFFER_BEGIN_BTINFO = 0x46414E47u,
BUFFER_BEGIN_STACKSHOT = 0x59a25807u,
BUFFER_BEGIN_OS_REASON = 0x53A20900u,
BUFFER_BEGIN_DELTA_STACKSHOT = 0xDE17A59Au,
BUFFER_BEGIN_CRASHINFO = 0xDEADF157u,
BUFFER_END = 0xF19158EDu;
public string to_nick () {
return Marshal.enum_to_nick<ItemType> (this);
}
}
[Flags]
public enum StackshotFlagsLow {
GET_DQ = (1U << 0),
SAVE_LOADINFO = (1U << 1),
GET_GLOBAL_MEM_STATS = (1U << 2),
SAVE_KEXT_LOADINFO = (1U << 3),
ACTIVE_KERNEL_THREADS_ONLY = (1U << 8),
GET_BOOT_PROFILE = (1U << 9),
DO_COMPRESS = (1U << 10),
SAVE_IMP_DONATION_PIDS = (1U << 13),
SAVE_IN_KERNEL_BUFFER = (1U << 14),
RETRIEVE_EXISTING_BUFFER = (1U << 15),
KCDATA_FORMAT = (1U << 16),
ENABLE_BT_FAULTING = (1U << 17),
COLLECT_DELTA_SNAPSHOT = (1U << 18),
COLLECT_SHAREDCACHE_LAYOUT = (1U << 19),
TRYLOCK = (1U << 20),
ENABLE_UUID_FAULTING = (1U << 21),
FROM_PANIC = (1U << 22),
NO_IO_STATS = (1U << 23),
THREAD_WAITINFO = (1U << 24),
THREAD_GROUP = (1U << 25),
SAVE_JETSAM_COALITIONS = (1U << 26),
INSTRS_CYCLES = (1U << 27),
ASID = (1U << 28),
PAGE_TABLES = (1U << 29),
DISABLE_LATENCY_INFO = (1U << 30),
SAVE_DYLD_COMPACTINFO = (1U << 31)
}
[Flags]
public enum StackshotFlagsHigh {
INCLUDE_DRIVER_THREADS_IN_KERNEL = (1U << 0),
EXCLAVES = (1U << 1),
SKIP_EXCLAVES = (1U << 2),
}
public const size_t TASK_SNAPSHOT_PID_OFFSET = 84;
public static bool is_stackshot (Bytes bytes) {
if (bytes.get_size () < 16)
return false;
var type = (ItemType) uint32.from_little_endian (*((uint32 *) bytes.get_data ()));
switch (type) {
case ItemType.BUFFER_BEGIN_STACKSHOT:
case ItemType.BUFFER_BEGIN_DELTA_STACKSHOT:
case ItemType.BUFFER_BEGIN_COMPRESSED:
return true;
default:
return false;
}
}
public sealed class Reader : Object {
private Buffer buf;
private BufferReader r;
private Buffer payload_buf;
private BufferReader payload_r;
private BufferReader scan_r;
private Array<uint64> scan_container_ids = new Array<uint64> ();
[Compact]
private struct Scope {
public size_t end_item_offset;
public uint64 end_id;
}
private Array<Scope> scopes = new Array<Scope> ();
private size_t current_end_item_offset;
private const size_t HEADER_SIZE = 16;
private const size_t ALIGNMENT_SIZE = 16;
public Reader (Bytes bytes) {
buf = new Buffer (bytes, LITTLE_ENDIAN);
r = new BufferReader (buf);
payload_buf = new Buffer.from_data ((uint8[]) null, buf.byte_order, buf.pointer_size);
payload_r = new BufferReader (payload_buf);
scan_r = new BufferReader (buf);
current_end_item_offset = buf.bytes.get_size ();
}
public enum VisitResult {
CONTINUE,
STOP
}
public VisitResult for_each (ItemVisitor visitor) throws Error {
ItemHeader h;
unowned BufferReader p;
while (read_item (out h, out p)) {
if (visitor (h, p) == VisitResult.STOP)
return VisitResult.STOP;
}
return VisitResult.CONTINUE;
}
public delegate VisitResult ItemVisitor (ItemHeader h, BufferReader payload) throws Error;
public VisitResult for_each_container (ItemType want_container_type, ScopeVisitor visitor) throws Error {
ItemHeader h;
unowned BufferReader p;
while (read_item (out h, out p)) {
if (h.type != ItemType.CONTAINER_BEGIN)
continue;
var ctype = (ItemType) p.read_uint32 ();
var id = h.flags;
if (ctype != want_container_type) {
skip_container_body (id);
continue;
}
enter_container_body (id);
var result = visitor (this);
leave_container ();
if (result == VisitResult.STOP)
return VisitResult.STOP;
}
return VisitResult.CONTINUE;
}
public delegate VisitResult ScopeVisitor (Reader r) throws Error;
public unowned BufferReader get_first (ItemType type) throws Error {
unowned BufferReader result = null;
for_each ((h, p) => {
if (h.type != type)
return VisitResult.CONTINUE;
result = p;
return VisitResult.STOP;
});
if (result == null)
throw new Error.PROTOCOL ("Missing item: %s", type.to_nick ());
return result;
}
private bool read_item (out ItemHeader h, out unowned BufferReader payload) throws Error {
if (r.available == 0 || r.offset == current_end_item_offset) {
h = ItemHeader ();
payload = null;
return false;
}
h = read_header ();
payload = read_payload (h);
return true;
}
private ItemHeader read_header () throws Error {
if (r.available < HEADER_SIZE)
throw new Error.PROTOCOL ("KCDATA truncated at %zu (need header, avail=%zu)", r.offset, r.available);
var item_start = r.offset;
var h = read_item_header_fields (r);
var avail_payload = current_end_item_offset - r.offset;
var avail = size_t.min (r.available, avail_payload);
if (h.size > avail) {
throw new Error.PROTOCOL ("KCDATA truncated at %zu (type=0x%x size=%u avail=%zu)", item_start,
(uint32) h.type, h.size, avail);
}
return h;
}
private unowned BufferReader read_payload (ItemHeader h) throws Error {
unowned uint8[] payload = r.read_data (h.size);
payload_buf.reset_data (payload);
payload_r.reset (payload_buf);
r.align (ALIGNMENT_SIZE);
return payload_r;
}
private void enter_container_body (uint64 id) throws Error {
var body_start = r.offset;
size_t end_item_offset;
find_container_end (body_start, id, out end_item_offset);
var s = Scope ();
s.end_item_offset = end_item_offset;
s.end_id = id;
scopes.append_val (s);
current_end_item_offset = end_item_offset;
}
private void leave_container () throws Error {
var s = scopes.index (scopes.length - 1);
scopes.set_size (scopes.length - 1);
consume_container_end_at (s.end_item_offset, s.end_id);
if (scopes.length == 0)
current_end_item_offset = buf.bytes.get_size ();
else {
var parent = scopes.index (scopes.length - 1);
current_end_item_offset = parent.end_item_offset;
}
}
private void skip_container_body (uint64 id) throws Error {
var body_start = r.offset;
size_t end_item_offset;
find_container_end (body_start, id, out end_item_offset);
consume_container_end_at (end_item_offset, id);
}
private void consume_container_end_at (size_t end_item_offset, uint64 id) throws Error {
if (r.offset != end_item_offset)
r.seek (end_item_offset);
if (r.available < HEADER_SIZE)
throw new Error.PROTOCOL ("KCDATA truncated at %zu (need header, avail=%zu)", r.offset, r.available);
var item_start = r.offset;
var h = read_item_header_fields (r);
if (h.type != ItemType.CONTAINER_END || h.flags != id) {
throw new Error.PROTOCOL ("Malformed container end at %zu (want id=0x%016" + uint64.FORMAT_MODIFIER + "x)",
item_start, id);
}
if (h.size > r.available) {
throw new Error.PROTOCOL ("KCDATA truncated at %zu (type=0x%x size=%u avail=%zu)", item_start,
(uint32) h.type, h.size, r.available);
}
r.skip (h.size);
r.align (ALIGNMENT_SIZE);
}
private void find_container_end (size_t body_start, uint64 id, out size_t end_item_offset) throws Error {
scan_container_ids.set_size (0);
scan_r.seek (body_start);
while (true) {
if (scan_r.available < HEADER_SIZE) {
throw new Error.PROTOCOL ("KCDATA truncated at %zu (need header, avail=%zu)",
scan_r.offset, scan_r.available);
}
var item_start = scan_r.offset;
var h = read_item_header_fields (scan_r);
if (h.size > scan_r.available) {
throw new Error.PROTOCOL ("KCDATA truncated at %zu (type=0x%x size=%u avail=%zu)", item_start,
(uint32) h.type, h.size, scan_r.available);
}
scan_r.skip (h.size);
scan_r.align (ALIGNMENT_SIZE);
if (h.type == ItemType.CONTAINER_BEGIN) {
scan_container_ids.append_val (h.flags);
continue;
}
if (h.type == ItemType.CONTAINER_END) {
if (scan_container_ids.length != 0) {
var top = scan_container_ids.remove_index (scan_container_ids.length - 1);
if (top != h.flags) {
throw new Error.PROTOCOL ("Malformed container nesting at %zu (id=0x%016" +
uint64.FORMAT_MODIFIER + "x)", item_start, h.flags);
}
} else {
if (h.flags != id) {
throw new Error.PROTOCOL ("Malformed container end at %zu (id=0x%016" +
uint64.FORMAT_MODIFIER + "x)", item_start, h.flags);
}
end_item_offset = item_start;
return;
}
}
}
}
private ItemHeader read_item_header_fields (BufferReader r) throws Error {
var h = ItemHeader ();
h.type = (ItemType) r.read_uint32 ();
h.size = r.read_uint32 ();
h.flags = r.read_uint64 ();
return h;
}
}
}
+220
View File
@@ -0,0 +1,220 @@
[CCode (gir_namespace = "FridaFruity", gir_version = "1.0")]
namespace Frida.Fruity {
public enum KdebugClass {
MACH = 1,
FSYSTEM = 3,
BSD = 4,
TRACE = 7,
DYLD = 31,
PERF = 37,
ANY = 0xff;
public string to_nick () {
return Marshal.enum_to_nick<KdebugClass> (this);
}
}
public enum KdebugMachSubclass {
EXCP_SC = 12,
}
public enum KdebugFsystemSubclass {
FSRW = 1,
DKRW,
FSVN,
FSLOOOKUP,
JOURNAL,
IOCTL,
BOOTCACHE,
HFS,
APFS,
SMB,
MOUNT,
EXFAT = 14,
MSDOS,
ACFS,
THROTTLE,
DECMP,
VFS,
LIVEFS,
NFS;
public string to_nick () {
return Marshal.enum_to_nick<KdebugFsystemSubclass> (this);
}
}
public enum KdebugFsystemFsrwEvent {
LOOKUP = 36,
LOOKUP_DONE = 39;
public string to_nick () {
return Marshal.enum_to_nick<KdebugFsystemFsrwEvent> (this);
}
}
public enum KdebugBsdSubclass {
EXCP_SC = 12,
}
public enum KdebugTraceSubclass {
DATA,
STRING,
INFO;
public string to_nick () {
return Marshal.enum_to_nick<KdebugTraceSubclass> (this);
}
}
public enum KdebugTraceDataEvent {
NEWTHREAD = 1,
EXEC,
THREAD_TERMINATE,
THREAD_TERMINATE_PID;
public string to_nick () {
return Marshal.enum_to_nick<KdebugTraceDataEvent> (this);
}
}
public enum KdebugTraceStringEvent {
GLOBAL,
NEWTHREAD,
EXEC,
PROC_EXIT,
THREADNAME,
THREADNAME_PREV;
public string to_nick () {
return Marshal.enum_to_nick<KdebugTraceStringEvent> (this);
}
}
public enum KdebugDyldSubclass {
UUID = 5,
}
public enum KdebugDyldUuidEvent {
MAP_A,
MAP_B,
MAP_32_A,
MAP_32_B,
MAP_32_C,
UNMAP_A,
UNMAP_B,
UNMAP_32_A,
UNMAP_32_B,
UNMAP_32_C,
SHARED_CACHE_A,
SHARED_CACHE_B,
SHARED_CACHE_32_A,
SHARED_CACHE_32_B,
SHARED_CACHE_32_C,
AOT_MAP_A,
AOT_MAP_B;
public string to_nick () {
return Marshal.enum_to_nick<KdebugDyldUuidEvent> (this);
}
}
public enum KdebugPerfSubclass {
GENERIC,
THREADINFO,
CALLSTACK,
TIMER,
PET,
AST,
KPC,
KDBG,
TASK,
LAZY,
MEMINFO;
public string to_nick () {
return Marshal.enum_to_nick<KdebugPerfSubclass> (this);
}
}
public enum KdebugPerfCallstackEvent {
KSAMPLE,
UPEND,
USAMPLE,
KDATA,
UDATA,
KHDR,
UHDR,
ERROR,
BACKTRACE,
LOG,
EXHDR,
EXDATA,
EXSTACKHDR,
EXSTACK,
KEXOFFSET;
public string to_nick () {
return Marshal.enum_to_nick<KdebugPerfCallstackEvent> (this);
}
}
public const uint8 KDEBUG_SUBCLASS_ANY = 0xff;
public const uint16 KDEBUG_CODE_ANY = 0x3fff;
public enum KdebugFunctionQualifier {
NONE,
START,
END;
public string to_nick () {
return Marshal.enum_to_nick<KdebugFunctionQualifier> (this);
}
}
public struct KdebugCode {
public uint32 raw;
public KdebugCode (uint32 raw) {
this.raw = raw;
}
public KdebugCode.from_parts (
KdebugClass klass,
uint8 subclass = KDEBUG_SUBCLASS_ANY,
uint16 code = KDEBUG_CODE_ANY,
KdebugFunctionQualifier func_qual = NONE) {
raw =
(((uint32) klass & 0xff) << 24) |
(((uint32) subclass & 0xff) << 16) |
(((uint32) code & 0x3fff) << 2) |
((uint32) func_qual & 0x3);
}
public KdebugClass klass {
get {
return (KdebugClass) ((raw >> 24) & 0xff);
}
}
public uint8 subclass {
get {
return (uint8) ((raw >> 16) & 0xff);
}
}
public uint16 code {
get {
return (uint16) ((raw >> 2) & 0x3fff);
}
}
public KdebugFunctionQualifier func_qual {
get {
return (KdebugFunctionQualifier) (raw & 0x3);
}
}
}
}
+190 -8
View File
@@ -9,8 +9,20 @@ namespace Frida.Fruity {
return other == this;
}
public virtual string to_string () {
return "NSObject";
public string to_string (uint level = 0) {
var s = new StringBuilder.sized (256);
append_indent (s, level);
append_content (s, level);
return s.str;
}
protected virtual void append_content (StringBuilder s, uint level) {
s.append ("NSObject {}");
}
protected void append_indent (StringBuilder s, uint level) {
for (uint i = 0; i != level; i++)
s.append (" ");
}
public static uint hash_func (NSObject val) {
@@ -103,8 +115,19 @@ namespace Frida.Fruity {
return false;
}
public override string to_string () {
return integer.to_string ();
protected override void append_content (StringBuilder s, uint level) {
switch (kind) {
case BOOLEAN:
s.append (boolean ? "true" : "false");
break;
case INTEGER:
s.append_printf ("%" + int64.FORMAT, integer);
break;
case FLOAT:
case DOUBLE:
s.append_printf ("%f", number);
break;
}
}
}
@@ -129,8 +152,11 @@ namespace Frida.Fruity {
return other_string.str == str;
}
public override string to_string () {
return str;
protected override void append_content (StringBuilder s, uint level) {
s
.append_c ('"')
.append (str.replace ("\"", "\\\""))
.append_c ('"');
}
}
@@ -155,8 +181,8 @@ namespace Frida.Fruity {
return other_data.bytes.compare (bytes) == 0;
}
public override string to_string () {
return "NSData";
protected override void append_content (StringBuilder s, uint level) {
s.append_printf ("NSData { size = %" + size_t.FORMAT + " }", bytes.get_size ());
}
}
@@ -219,6 +245,25 @@ namespace Frida.Fruity {
public void set_value (string key, NSObject val) {
storage[key] = val;
}
protected override void append_content (StringBuilder s, uint level) {
if (storage.size == 0) {
s.append ("{}");
return;
}
s.append ("{\n");
foreach (var e in entries) {
append_indent (s, level + 1);
s
.append (e.key)
.append (": ");
e.value.append_content (s, level + 1);
s.append (",\n");
}
append_indent (s, level);
s.append_c ('}');
}
}
public sealed class NSDictionaryRaw : NSObject {
@@ -253,6 +298,24 @@ namespace Frida.Fruity {
? storage
: new Gee.HashMap<NSObject, NSObject> (NSObject.hash_func, NSObject.equal_func);
}
protected override void append_content (StringBuilder s, uint level) {
if (storage.size == 0) {
s.append ("{}");
return;
}
s.append ("{\n");
foreach (var e in entries) {
append_indent (s, level + 1);
e.key.append_content (s, level + 1);
s.append (": ");
e.value.append_content (s, level + 1);
s.append (",\n");
}
append_indent (s, level);
s.append_c ('}');
}
}
public sealed class NSArray : NSObject {
@@ -277,6 +340,56 @@ namespace Frida.Fruity {
public void add_object (NSObject obj) {
storage.add (obj);
}
protected override void append_content (StringBuilder s, uint level) {
if (storage.size == 0) {
s.append ("[]");
return;
}
s.append ("[\n");
foreach (var e in elements) {
append_indent (s, level + 1);
e.append_content (s, level + 1);
s.append (",\n");
}
append_indent (s, level);
s.append_c (']');
}
}
public sealed class NSSet : NSObject {
public Gee.Iterable<NSObject> items {
owned get {
return storage;
}
}
private Gee.HashSet<NSObject> storage;
public NSSet (Gee.HashSet<NSObject>? storage = null) {
this.storage = (storage != null) ? storage : new Gee.HashSet<NSObject> (NSObject.hash_func);
}
public void add_object (NSObject obj) {
storage.add (obj);
}
protected override void append_content (StringBuilder s, uint level) {
if (storage.size == 0) {
s.append ("{}");
return;
}
s.append ("{\n");
foreach (var e in items) {
append_indent (s, level + 1);
e.append_content (s, level + 1);
s.append (",\n");
}
append_indent (s, level);
s.append_c ('}');
}
}
public sealed class NSDate : NSObject {
@@ -296,6 +409,10 @@ namespace Frida.Fruity {
return new DateTime.from_unix_utc (MAC_EPOCH_DELTA_FROM_UNIX + whole_seconds)
.add_seconds (time - (double) whole_seconds);
}
protected override void append_content (StringBuilder s, uint level) {
s.append_printf ("NSDate { time = %f }", time);
}
}
public sealed class NSError : NSObject {
@@ -319,6 +436,35 @@ namespace Frida.Fruity {
this.code = code;
this.user_info = user_info;
}
protected override void append_content (StringBuilder s, uint level) {
s.append ("NSError { domain = ");
domain.append_content (s, level);
s.append_printf (", code = %" + uint64.FORMAT_MODIFIER + "d, user_info = ", code);
if (user_info.size == 0) {
user_info.append_content (s, level);
s.append (" }");
return;
}
s.append ("{\n");
append_indent (s, level + 1);
s.append ("domain: ");
domain.append_content (s, level + 1);
s.append (",\n");
append_indent (s, level + 1);
s.append_printf ("code: %" + uint64.FORMAT_MODIFIER + "d,\n", code);
append_indent (s, level + 1);
s.append ("user_info: ");
user_info.append_content (s, level + 1);
s.append_c ('\n');
append_indent (s, level);
s.append_c ('}');
}
}
public sealed class DTTapMessage : NSObject {
@@ -330,6 +476,25 @@ namespace Frida.Fruity {
public DTTapMessage (NSDictionary plist) {
this.plist = plist;
}
protected override void append_content (StringBuilder s, uint level) {
if (plist.size == 0) {
s.append ("DTTapMessage { plist: ");
plist.append_content (s, level);
s.append (" }");
return;
}
s.append ("DTTapMessage {\n");
append_indent (s, level + 1);
s.append ("plist: ");
plist.append_content (s, level + 1);
s.append_c ('\n');
append_indent (s, level);
s.append_c ('}');
}
}
namespace NSKeyedArchive {
@@ -338,6 +503,7 @@ namespace Frida.Fruity {
private const string[] DICTIONARY_CLASS = { "NSDictionary", "NSObject" };
private const string[] ARRAY_CLASS = { "NSArray", "NSObject" };
private const string[] SET_CLASS = { "NSSet", "NSObject" };
[CCode (has_target = false)]
private delegate PlistUid EncodeFunc (NSObject instance, EncodingContext ctx);
@@ -455,6 +621,7 @@ namespace Frida.Fruity {
encoders[typeof (NSString)] = encode_string;
encoders[typeof (NSDictionary)] = encode_dictionary;
encoders[typeof (NSArray)] = encode_array;
encoders[typeof (NSSet)] = encode_set;
}
private static void ensure_decoders_registered () {
@@ -619,6 +786,21 @@ namespace Frida.Fruity {
return uid;
}
private static PlistUid encode_set (NSObject instance, EncodingContext ctx) {
NSSet set = (NSSet) instance;
var object = new PlistDict ();
var uid = ctx.add_object (object);
var objs = new PlistArray ();
foreach (var element in set.items)
objs.add_uid (encode_value (element, ctx));
object.set_array ("NS.objects", objs);
object.set_uid ("$class", ctx.get_class (SET_CLASS));
return uid;
}
private static NSObject decode_array (PlistDict instance, DecodingContext ctx) throws Error, PlistError {
var objs = instance.get_array ("NS.objects");
+180
View File
@@ -0,0 +1,180 @@
[CCode (gir_namespace = "FridaFruity", gir_version = "1.0")]
namespace Frida.Fruity {
public delegate void KperfdataRecordVisitor (KdBuf rec) throws Error;
public sealed class KperfdataStreamParser : Object {
private ByteArray stash = new ByteArray ();
private size_t cursor = 0;
private bool have_header = false;
private uint32 thread_count = 0;
private size_t records_offset = 0;
private const uint32 RAW_VERSION2 = 0x55aa0200u;
private const size_t HEADER_FIXED_SIZE = 0x120;
private const size_t THREADMAP_ENTRY_SIZE = 0x20;
private const size_t PAGE_SIZE = 0x1000;
private const size_t KD_BUF_SIZE = 0x40;
public void reset () {
stash.set_size (0);
cursor = 0;
have_header = false;
thread_count = 0;
records_offset = 0;
}
public void push (Bytes chunk, KperfdataRecordVisitor visitor) throws Error {
stash.append (chunk.get_data ());
var stash_bytes = new Bytes.static (stash.data);
parse_bytes (stash_bytes, visitor);
compact ();
}
private void parse_bytes (Bytes bytes, KperfdataRecordVisitor visitor) throws Error {
var buf = new Frida.Buffer (bytes, LITTLE_ENDIAN);
var r = new Frida.BufferReader (buf);
while (true) {
if (!have_header) {
if (r.available < 8)
return;
size_t header_start = r.offset;
uint32 magic = r.read_uint32 ();
if (magic != RAW_VERSION2)
throw new Error.PROTOCOL ("Unknown kperfdata magic 0x%x", magic);
thread_count = r.read_uint32 ();
uint64 threadmaps_size_64 = thread_count * THREADMAP_ENTRY_SIZE;
size_t header_size = (size_t) (HEADER_FIXED_SIZE + threadmaps_size_64);
size_t aligned = align_up (header_size, PAGE_SIZE);
records_offset = aligned;
if ((r.offset - 8) != header_start)
throw new Error.PROTOCOL ("Internal offset bookkeeping error");
if ((stash.len - header_start) < records_offset) {
r.skip (header_start - r.offset);
return;
}
cursor = header_start + records_offset;
have_header = true;
r.skip (cursor - r.offset);
continue;
}
if (r.offset < cursor) {
if ((cursor - r.offset) > r.available)
return;
r.skip (cursor - r.offset);
}
if (r.available < KD_BUF_SIZE)
return;
KdBuf rec = KdBuf ();
rec.timestamp = r.read_uint64 ();
rec.arg1 = r.read_uint64 ();
rec.arg2 = r.read_uint64 ();
rec.arg3 = r.read_uint64 ();
rec.arg4 = r.read_uint64 ();
rec.arg5 = r.read_uint64 ();
rec.debugid = r.read_uint32 ();
rec.cpuid = r.read_uint32 ();
rec.unused = r.read_uint64 ();
visitor (rec);
cursor = r.offset;
}
}
private void compact () {
if (cursor == 0)
return;
if (cursor >= stash.len) {
stash.set_size (0);
cursor = 0;
return;
}
size_t remaining = stash.len - cursor;
Memory.move (stash.data, (uint8 *) stash.data + cursor, remaining);
stash.set_size ((uint) remaining);
cursor = 0;
}
private static size_t align_up (size_t val, size_t alignment) {
size_t mask = alignment - 1;
return (val + mask) & ~mask;
}
}
public struct KdBuf {
public uint64 timestamp;
public uint64 arg1;
public uint64 arg2;
public uint64 arg3;
public uint64 arg4;
public uint64 arg5;
public uint32 debugid;
public uint32 cpuid;
public uint64 unused;
public KdebugCode kcode {
get {
return KdebugCode (debugid);
}
}
public string to_string () {
var kc = kcode;
return (
"ts=0x%" + uint64.FORMAT_MODIFIER + "x "
+ "arg1=0x%" + uint64.FORMAT_MODIFIER + "x "
+ "arg2=0x%" + uint64.FORMAT_MODIFIER + "x "
+ "arg3=0x%" + uint64.FORMAT_MODIFIER + "x "
+ "arg4=0x%" + uint64.FORMAT_MODIFIER + "x "
+ "arg5=0x%" + uint64.FORMAT_MODIFIER + "x "
+ "debugid=0x%08x "
+ "klass=%s subclass=%u code=%u func=%s "
+ "cpuid=%u "
+ "unused=0x%" + uint64.FORMAT_MODIFIER + "x"
).printf (
timestamp,
arg1,
arg2,
arg3,
arg4,
arg5,
debugid,
kc.klass.to_nick (),
kc.subclass,
kc.code,
kc.func_qual.to_nick (),
cpuid,
unused
);
}
}
}
+19 -29
View File
@@ -36,8 +36,6 @@ namespace Frida.Fruity {
private uint16 ndp_fixed_header_size;
private VirtualNetworkStack? _netstack;
private Gee.Queue<Bytes> pending_input = new Gee.ArrayQueue<Bytes> ();
private bool input_flush_scheduled = false;
private Gee.Queue<Bytes> pending_output = new Gee.ArrayQueue<Bytes> ();
private size_t out_in_flight_count = 0;
private size_t out_in_flight_bytes = 0;
@@ -184,8 +182,20 @@ namespace Frida.Fruity {
}
try {
var frame = yield pending.poll ().future.wait_async (io_cancellable);
handle_ncm_frame (frame);
var datagrams = new Gee.ArrayList<Bytes> ();
while (true) {
var request = pending.peek ();
if (request == null)
break;
if (!datagrams.is_empty && !request.future.ready)
break;
var frame = yield pending.poll ().future.wait_async (io_cancellable);
datagrams.add_all (handle_ncm_frame (frame));
}
yield _netstack.handle_incoming_datagrams (datagrams);
} catch (GLib.Error e) {
return;
}
@@ -208,7 +218,7 @@ namespace Frida.Fruity {
}
}
private void handle_ncm_frame (Bytes frame) throws GLib.Error {
private Gee.List<Bytes> handle_ncm_frame (Bytes frame) throws GLib.Error {
var input = new DataInputStream (new MemoryInputStream.from_bytes (frame));
input.byte_order = LITTLE_ENDIAN;
@@ -222,6 +232,8 @@ namespace Frida.Fruity {
input.skip (6);
var ndp_index = input.read_uint16 ();
var datagrams = new Gee.ArrayList<Bytes> ();
do {
input.seek (ndp_index, SET);
input.read_all (raw_signature[:4], out bytes_read);
@@ -250,35 +262,13 @@ namespace Frida.Fruity {
notify_property ("remote-ipv6-address");
}
on_incoming_datagram (datagram);
datagrams.add (datagram);
}
ndp_index = next_ndp_index;
} while (ndp_index != 0);
}
private void on_incoming_datagram (Bytes datagram) {
pending_input.offer (datagram);
if (!input_flush_scheduled) {
var source = new IdleSource ();
source.set_callback (() => {
input_flush_scheduled = false;
flush_pending_input ();
return Source.REMOVE;
});
source.attach (MainContext.get_thread_default ());
input_flush_scheduled = true;
}
}
private void flush_pending_input () {
var datagrams = pending_input;
pending_input = new Gee.ArrayQueue<Bytes> ();
try {
_netstack.handle_incoming_datagrams (datagrams);
} catch (Error e) {
}
return datagrams;
}
private void on_netif_outgoing_datagrams (Gee.Collection<Bytes> datagrams) {
+21 -6
View File
@@ -283,14 +283,14 @@ namespace Frida.Fruity {
return new Ipv6UdpSocket (this);
}
public void handle_incoming_datagrams (Gee.Collection<Bytes> datagrams) throws Error {
public async void handle_incoming_datagrams (Gee.Collection<Bytes> datagrams) throws Error {
LWIP.ErrorCode err = OK;
check_started ();
check (perform_on_lwip_thread (() => {
schedule_on_lwip_thread (() => {
begin_output ();
LWIP.ErrorCode err = OK;
foreach (var d in datagrams) {
var pbuf = LWIP.PacketBuffer.alloc (RAW, (uint16) d.get_size (), POOL);
pbuf.take (d.get_data ());
@@ -304,8 +304,14 @@ namespace Frida.Fruity {
end_output ();
schedule_on_frida_thread (handle_incoming_datagrams.callback);
return err;
}));
});
yield;
check (err);
}
private static LWIP.ErrorCode on_netif_link_output (LWIP.NetworkInterface handle, LWIP.PacketBuffer pbuf) {
@@ -359,6 +365,15 @@ namespace Frida.Fruity {
}
internal LWIP.ErrorCode perform_on_lwip_thread (owned WorkFunc work) {
var req = submit_work ((owned) work);
return req.join ();
}
internal void schedule_on_lwip_thread (owned WorkFunc work) {
submit_work ((owned) work);
}
private Request submit_work (owned WorkFunc work) {
var req = new Request ((owned) work);
if (Thread.self<bool> () == lwip_thread) {
@@ -369,7 +384,7 @@ namespace Frida.Fruity {
LWIP.Runtime.schedule (perform_next_request);
}
return req.join ();
return req;
}
private void perform_next_request () {
+51 -41
View File
@@ -2044,8 +2044,6 @@ namespace Frida.Fruity {
private BufferedInputStream input;
private OutputStream output;
private Gee.Queue<Bytes> pending_input = new Gee.ArrayQueue<Bytes> ();
private bool input_flush_scheduled = false;
private Gee.Queue<Bytes> pending_output = new Gee.ArrayQueue<Bytes> ();
private bool writing = false;
@@ -2147,8 +2145,39 @@ namespace Frida.Fruity {
private async void process_incoming_messages () {
try {
while (true) {
var datagram = yield read_datagram (io_cancellable);
on_incoming_datagram (datagram);
var pending_input = new Gee.ArrayQueue<Bytes> ();
while (true) {
var size = peek_datagram_size ();
if (size == -1)
break;
var datagram = new uint8[size];
input.read (datagram, io_cancellable);
pending_input.offer (new Bytes.take ((owned) datagram));
}
if (pending_input.size != 0) {
try {
yield _tunnel_netstack.handle_incoming_datagrams (pending_input);
} catch (Error e) {
}
var source = new IdleSource ();
source.set_callback (process_incoming_messages.callback);
source.attach (MainContext.get_thread_default ());
yield;
}
ssize_t n;
try {
n = yield input.fill_async (-1, Priority.DEFAULT, io_cancellable);
} catch (GLib.Error e) {
throw new Error.TRANSPORT ("Connection closed");
}
if (n == 0)
throw new Error.TRANSPORT ("Connection closed");
}
} catch (GLib.Error e) {
}
@@ -2173,30 +2202,6 @@ namespace Frida.Fruity {
closed ();
}
private void on_incoming_datagram (Bytes datagram) {
pending_input.offer (datagram);
if (!input_flush_scheduled) {
var source = new IdleSource ();
source.set_callback (() => {
input_flush_scheduled = false;
flush_pending_input ();
return Source.REMOVE;
});
source.attach (MainContext.get_thread_default ());
input_flush_scheduled = true;
}
}
private void flush_pending_input () {
var datagrams = pending_input;
pending_input = new Gee.ArrayQueue<Bytes> ();
try {
_tunnel_netstack.handle_incoming_datagrams (datagrams);
} catch (Error e) {
}
}
private void post (Bytes datagram) {
var batch = new Gee.ArrayList<Bytes> ();
batch.add (datagram);
@@ -2269,24 +2274,21 @@ namespace Frida.Fruity {
return new JsonObjectReader (json);
}
private async Bytes read_datagram (Cancellable? cancellable) throws Error, IOError {
size_t header_size = 40;
private ssize_t peek_datagram_size () {
ssize_t header_size = 40;
if (input.get_available () < header_size)
yield fill_until_n_bytes_available (header_size, cancellable);
return -1;
uint16 payload_size = 0;
unowned uint8[] size_buf = ((uint8[]) &payload_size)[:2];
input.peek (size_buf, 4);
payload_size = uint16.from_big_endian (payload_size);
size_t full_size = header_size + payload_size;
ssize_t full_size = header_size + payload_size;
if (input.get_available () < full_size)
yield fill_until_n_bytes_available (full_size, cancellable);
return -1;
var datagram = new uint8[full_size];
input.read (datagram, cancellable);
return new Bytes.take ((owned) datagram);
return full_size;
}
private async void fill_until_n_bytes_available (size_t minimum, Cancellable? cancellable) throws Error, IOError {
@@ -2367,6 +2369,7 @@ namespace Frida.Fruity {
private Gee.Map<int64?, Stream> streams = new Gee.HashMap<int64?, Stream> (Numeric.int64_hash, Numeric.int64_equal);
private Gee.Queue<Bytes> pending_input = new Gee.ArrayQueue<Bytes> ();
private bool input_flush_scheduled = false;
private bool input_flush_happening = false;
private Gee.Queue<Bytes> pending_output = new Gee.ArrayQueue<Bytes> ();
private DatagramBasedSource? rx_source;
@@ -2842,7 +2845,7 @@ namespace Frida.Fruity {
var source = new IdleSource ();
source.set_callback (() => {
input_flush_scheduled = false;
flush_pending_input ();
flush_pending_input.begin ();
return Source.REMOVE;
});
source.attach (MainContext.get_thread_default ());
@@ -2852,13 +2855,20 @@ namespace Frida.Fruity {
return 0;
}
private void flush_pending_input () {
private async void flush_pending_input () {
if (input_flush_happening)
return;
input_flush_happening = true;
var datagrams = pending_input;
pending_input = new Gee.ArrayQueue<Bytes> ();
try {
_tunnel_netstack.handle_incoming_datagrams (datagrams);
} catch (Error e) {
yield _tunnel_netstack.handle_incoming_datagrams (datagrams);
} catch (GLib.Error e) {
}
input_flush_happening = false;
}
private static void on_rand (uint8[] dest, NGTcp2.RNGContext rand_ctx) {
+17 -13
View File
@@ -813,22 +813,23 @@ namespace Frida {
private const uint64 SOCK_CLOEXEC = 0x80000;
private sealed class InjectSession : SeizeSession {
private static ProcMapsSoEntry local_libc;
private static ProcMapsSnapshot.Mapping local_libc;
private static uint64 mmap_offset;
private static uint64 munmap_offset;
private static string fallback_ld;
private static string fallback_libc;
private static ProcMapsSoEntry? local_android_ld;
private static ProcMapsSnapshot.Mapping? local_android_ld;
static construct {
var libc = Gum.Process.get_libc_module ();
uint local_pid = Posix.getpid ();
local_libc = ProcMapsSoEntry.find_by_path (local_pid, libc.path);
var local_maps = ProcMapsSnapshot.from_pid (local_pid);
local_libc = local_maps.find_module_by_path (libc.path);
assert (local_libc != null);
mmap_offset = (uint64) (uintptr) libc.find_export_by_name ("mmap") - local_libc.base_address;
munmap_offset = (uint64) (uintptr) libc.find_export_by_name ("munmap") - local_libc.base_address;
mmap_offset = (uint64) (uintptr) libc.find_export_by_name ("mmap") - local_libc.start;
munmap_offset = (uint64) (uintptr) libc.find_export_by_name ("munmap") - local_libc.start;
try {
var program = new Gum.ElfModule.from_file ("/proc/self/exe");
@@ -846,7 +847,7 @@ namespace Frida {
}
#if ANDROID
local_android_ld = ProcMapsSoEntry.find_by_path (local_pid, fallback_ld);
local_android_ld = local_maps.find_module_by_path (fallback_ld);
#endif
}
@@ -1051,9 +1052,10 @@ namespace Frida {
uint64 allocation_base = 0;
size_t allocation_size = size_t.max (bootstrapper_size, loader_size) + stack_size;
var remote_maps = ProcMapsSnapshot.from_pid (pid);
var remote_libc = remote_maps.find_module_by_path (local_libc.path);
uint64 remote_mmap = 0;
uint64 remote_munmap = 0;
ProcMapsSoEntry? remote_libc = ProcMapsSoEntry.find_by_path (pid, local_libc.path);
#if ANDROID
bool same_libc = remote_libc != null
&& remote_libc.device.major == local_libc.device.major
@@ -1066,8 +1068,8 @@ namespace Frida {
&& remote_libc.path == local_libc.path;
#endif
if (same_libc) {
remote_mmap = remote_libc.base_address + mmap_offset;
remote_munmap = remote_libc.base_address + munmap_offset;
remote_mmap = remote_libc.start + mmap_offset;
remote_munmap = remote_libc.start + munmap_offset;
}
if (remote_mmap != 0) {
@@ -1165,7 +1167,9 @@ namespace Frida {
result.context.libc = &result.libc;
if (result.context.rtld_flavor == ANDROID && result.libc.dlopen == null) {
ProcMapsSoEntry? remote_ld = ProcMapsSoEntry.find_by_address (pid, (uintptr) result.context.rtld_base);
if (restart_after_libc_load)
remote_maps = ProcMapsSnapshot.from_pid (pid);
var remote_ld = remote_maps.find_mapping ((uintptr) result.context.rtld_base);
bool same_ld = remote_ld != null && local_android_ld != null
&& remote_ld.device.equals (local_android_ld.device)
&& remote_ld.inode == local_android_ld.inode;
@@ -1217,9 +1221,9 @@ namespace Frida {
}
}
private static void * rebase_pointer (uintptr local_ptr, ProcMapsSoEntry local_module, ProcMapsSoEntry remote_module) {
var offset = local_ptr - local_module.base_address;
return (void *) (remote_module.base_address + offset);
private static void * rebase_pointer (uintptr local_ptr, ProcMapsSnapshot.Mapping local, ProcMapsSnapshot.Mapping remote) {
var offset = local_ptr - local.start;
return (void *) (remote.start + offset);
}
private static string make_fallback_address () {
+11 -8
View File
@@ -19,7 +19,7 @@ endif
ifdef FRIDA_HOST
host_machine := $(FRIDA_HOST)
else
host_machine := $(shell basename $$(ls -1 $(BUILDDIR)/frida-linux-*.txt | tail -1) | cut -d"." -f1 | cut -d"-" -f2-)
host_machine := $(shell basename $$(ls -1 $(BUILDDIR)/*/frida-linux-*.txt | tail -1) | cut -d"." -f1 | cut -d"-" -f2-)
endif
host_arch := $(shell echo $(host_machine) | cut -d"-" -f2)
@@ -49,11 +49,11 @@ bpf_arch_pairs := \
build-native: ext/linux/tools/include/nolibc/nolibc.h
rm -rf build
$(MESON) setup --cross-file $(crossfile) -Db_lto=true build
$(MESON) compile -C build
install -m644 build/bootstrapper.bin $(native_outdir)/bootstrapper.bin
install -m644 build/loader.bin $(native_outdir)/loader.bin
[ -f build/zymbiote.bin ] && install -m644 build/zymbiote.bin $(native_outdir)/zymbiote.bin || true
$(MESON) setup --prefix /usr --cross-file $(crossfile) -Db_lto=true build
DESTDIR=$(abspath build/dist) $(MESON) install -C build
for f in build/dist/usr/share/frida-helpers/*; do \
install -m644 $$f $(native_outdir)/; \
done
bpf_targets :=
bpf_obj := $(build_dir)/module.o
@@ -66,6 +66,8 @@ linux_uapi_arch = $(strip \
$(if $(filter arm armbe,$1),arm, \
$(if $(filter arm64 arm64be,$1),arm64, \
$(if $(filter mips mipsel mips64 mips64el,$1),mips,unknown)))))
has_compat32 = $(strip \
$(if $(filter x86_64 arm64 arm64be,$(1)),1,))
kernel_headers_stamp = $(kernel_headers_dir)/$(1)/.stamp
kernel_headers_for = $(call kernel_headers_stamp,$(call linux_uapi_arch,$(1)))
@@ -95,6 +97,7 @@ define bpf_compile
$(BPF_CLANG) \
-target $(1) \
-D__TARGET_ARCH_$(2) \
$(if $(call has_compat32,$(3)),-DFRIDA_HAS_COMPAT32=1,) \
-O2 -g \
-I$(build_dir) \
-I$(libbpf_devel_dir) \
@@ -113,7 +116,7 @@ bpf_targets += $(foreach p,$(bpf_noarch_progs),$(bpf_outdir)/noarch-$(1)/$(p).el
$(bpf_outdir)/noarch-$(1)/%.elf: %.bpf.c $(call kernel_headers_stamp,$(noarch_uapi_arch)) $(libbpf_devel_dir)
$$(call recreate_build_dir)
$$(call bpf_compile,$(2),$(noarch_uapi_arch))
$$(call bpf_compile,$(2),$(noarch_uapi_arch),noarch)
endef
define declare_bpf_arch
@@ -139,7 +142,7 @@ $(bpf_outdir)/$(1)/%.elf: %.bpf.c $(call kernel_headers_for,$(1)) $(libbpf_devel
{ print } \
' frida-linux-syscalls.h > frida-linux-syscalls.h.tmp && \
mv frida-linux-syscalls.h.tmp frida-linux-syscalls.h
$$(call bpf_compile,$(2),$$(call linux_uapi_arch,$(1)))
$$(call bpf_compile,$(2),$$(call linux_uapi_arch,$(1)),$(1))
endef
pair_abi = $(word 1,$(subst :, ,$1))
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
View File
@@ -6,6 +6,7 @@ SECTIONS {
KEEP(*(.text.entrypoint))
*(.text*)
*(.rodata*)
*(.data*)
}
.dynstr : { *(.dynstr) }
+1 -5
View File
@@ -94,14 +94,10 @@ if host_machine.system() == 'android'
endif
zymbiote = shared_module('zymbiote', ['zymbiote.c'],
name_prefix: '',
name_suffix: 'elf',
c_args: zymbiote_flags + extra_flags,
link_args: extra_link_args,
link_depends: [helper_lds],
)
custom_target('zymbiote-bin',
input: [zymbiote],
output: ['zymbiote.bin'],
command: [objcopy, objcopy_flags, '@INPUT0@', '@OUTPUT0@'],
install_dir: 'share' / 'frida-helpers',
install: true,
)
+7 -3
View File
@@ -16,7 +16,6 @@ CURRENT_FILE="${BASH_SOURCE[0]}"
HELPERS_DIR="$(cd "$(dirname "$CURRENT_FILE")" && pwd)"
FRIDA_CORE_DIR="$(cd "$HELPERS_DIR/../../.." && pwd)"
RELENG_DIR="$FRIDA_CORE_DIR/releng"
BUILD_DIR="$FRIDA_CORE_DIR/build"
RELATIVE_TO_FRIDA_CORE_DIR=$(realpath --relative-to="$FRIDA_CORE_DIR" "$CURRENT_FILE")
TMP_MESON_DIR=$(mktemp -d)
@@ -86,9 +85,14 @@ build_arch () {
cd "$FRIDA_CORE_DIR"
rm -rf "$BUILD_DIR"
builddir=build/$FRIDA_HOST
rm -rf "$builddir"
mkdir -p "$builddir"
pushd "$builddir"
../../configure --host="$XTOOLS_HOST" "${EXTRA_FLAGS[@]}"
popd
# Note that $XTOOLS_HOST is set by the container.
./configure --host="$XTOOLS_HOST" "${EXTRA_FLAGS[@]}"
make -C src/linux/helpers
}
+166 -136
View File
@@ -13,12 +13,13 @@
#define MAX_TARGET_TGIDS 4096
#define MAX_TARGET_UIDS 256
#define MAX_EXCLUDED_SYSCALLS 1024
#define MAX_MAP_STATES 8192
#define MAX_STACK_ENTRIES 16384
#define MAX_INFLIGHT_COPIES 4096
#define MAX_STACK_DEPTH 16
#define MAX_PATH_DEPTH 20
#define MAX_PATH_DEPTH 18
#define MAX_PATH 256
#define MAX_STAT 512
#define MAX_SOCK 128
@@ -26,6 +27,14 @@
#define SYSCALL_NARGS 6
#ifdef FRIDA_HAS_COMPAT32
# if defined (__TARGET_ARCH_x86)
# define FRIDA_TIF_COMPAT32 29
# elif defined (__TARGET_ARCH_arm64)
# define FRIDA_TIF_COMPAT32 22
# endif
#endif
typedef struct _Event Event;
typedef __u16 EventType;
@@ -53,6 +62,7 @@ typedef struct _MapCreateEvent MapCreateEvent;
typedef struct _MapDestroyRangeEvent MapDestroyRangeEvent;
typedef struct _ProcessState ProcessState;
typedef __u32 Abi;
typedef struct _Inflight Inflight;
typedef struct _Stats Stats;
typedef struct _BufBuilder BufBuilder;
@@ -83,7 +93,8 @@ struct _AttachmentHeader
{
AttachmentType type;
__u16 arg_index;
__u32 len;
__u16 capacity;
__u16 size;
};
enum _AttachmentType
@@ -234,10 +245,17 @@ struct _MapDestroyRangeEvent
struct _ProcessState
{
__u8 abi;
Abi abi;
__u32 map_gen;
};
enum _Abi
{
ABI_INVALID,
ABI_NATIVE,
ABI_COMPAT32,
};
struct _Inflight
{
__s32 syscall_nr;
@@ -326,6 +344,15 @@ struct
}
target_uids SEC (".maps");
struct
{
__uint (type, BPF_MAP_TYPE_HASH);
__uint (max_entries, MAX_EXCLUDED_SYSCALLS);
__type (key, __u64);
__type (value, __u8);
}
excluded_syscalls SEC (".maps");
struct
{
__uint (type, BPF_MAP_TYPE_RINGBUF);
@@ -401,6 +428,16 @@ struct trace_event_raw_sys_exit
typedef __u32 dev_t;
struct thread_info
{
unsigned long flags;
} __attribute__ ((preserve_access_index));
struct task_struct
{
struct thread_info thread_info;
} __attribute__ ((preserve_access_index));
struct super_block
{
dev_t s_dev;
@@ -464,18 +501,9 @@ struct vm_area_struct
} __attribute__ ((preserve_access_index));
static bool should_trace_current (__u32 * out_tgid, __u32 * out_tid);
static SyscallEnterEventNone * reserve_enter_none (void);
static SyscallEnterEventTimespec * reserve_enter_timespec (void);
static SyscallEnterEventPath * reserve_enter_path (void);
static SyscallEnterEventPath2 * reserve_enter_path2 (void);
static SyscallEnterEventPath3 * reserve_enter_path3 (void);
static SyscallEnterEventSock * reserve_enter_sock (void);
static SyscallExitEventNone * reserve_exit_none (void);
static SyscallExitEventStrOut * reserve_exit_str_out (void);
static SyscallExitEventStatOut * reserve_exit_stat_out (void);
static SyscallExitEventSockOut * reserve_exit_sock_out (void);
static Abi get_current_abi (void);
static bool syscall_is_excluded (Abi abi, __s32 nr);
static __u64 make_excluded_key (Abi abi, __s32 nr);
static void * reserve_syscall_event (__u64 size);
@@ -483,8 +511,8 @@ static void fill_syscall_event (SyscallEvent * e, EventType type, __u32 tgid, __
void * ctx);
static void fill_enter_args (__u64 args[SYSCALL_NARGS], struct trace_event_raw_sys_enter * ctx);
static __u16 write_attach_str_arg (AttachmentHeader * h, __u16 arg_index, __u8 * dst, __u32 dst_cap, const void * user_str);
static __u16 write_attach_bytes_arg (AttachmentHeader * h, __u16 arg_index, __u8 * dst, __u32 dst_cap,
static void write_attach_str_arg (AttachmentHeader * h, __u16 arg_index, __u8 * dst, __u32 dst_cap, const void * user_str);
static void write_attach_bytes_arg (AttachmentHeader * h, __u16 arg_index, __u8 * dst, __u32 dst_cap,
const void * user_src, __u32 n);
static __u16 write_attach_dentry_path (AttachmentHeader * h, __u16 arg_index, __u8 * dst, __u32 dst_cap, struct file * file);
@@ -492,7 +520,7 @@ static void maybe_schedule_str_out_copy (__u32 tid, __s32 nr, __u16 arg_index, _
static void maybe_schedule_stat_out_copy (__u32 tid, __s32 nr, __u16 arg_index, __u64 user_ptr, __u32 len);
static void maybe_schedule_sock_out_copy (__u32 tid, __s32 nr, __u16 arg_index, __u64 user_ptr, __u64 user_len_ptr, __u32 max_len);
static __u32 ensure_map_gen (__u32 tgid, __u32 tid);
static bool ensure_process_state (__u32 tgid, __u32 tid, Abi abi, __u32 * out_map_gen);
static __u32 bump_map_gen (__u32 tgid);
static bool emit_need_snapshot (__u32 tgid, __u32 tid);
@@ -520,15 +548,22 @@ on_sys_enter (struct trace_event_raw_sys_enter * ctx)
if (!should_trace_current (&tgid, &tid))
return 0;
Abi abi = get_current_abi ();
__s32 nr = (__s32) ctx->id;
__u32 map_gen = ensure_map_gen (tgid, tid);
if (syscall_is_excluded (abi, nr))
return 0;
__u32 map_gen;
if (!ensure_process_state (tgid, tid, abi, &map_gen))
return 0;
if (nr == FRIDA_LINUX_SYSCALL_OPENAT ||
nr == FRIDA_LINUX_SYSCALL_FACCESSAT ||
nr == FRIDA_LINUX_SYSCALL_STATFS ||
nr == FRIDA_LINUX_SYSCALL_READLINKAT)
{
SyscallEnterEventPath * ev = reserve_enter_path ();
SyscallEnterEventPath * ev = reserve_syscall_event (sizeof (SyscallEnterEventPath));
if (ev == NULL)
return 0;
@@ -562,7 +597,7 @@ on_sys_enter (struct trace_event_raw_sys_enter * ctx)
#endif
nr == FRIDA_LINUX_SYSCALL_STATX)
{
SyscallEnterEventPath * ev = reserve_enter_path ();
SyscallEnterEventPath * ev = reserve_syscall_event (sizeof (SyscallEnterEventPath));
if (ev == NULL)
return 0;
@@ -594,7 +629,7 @@ on_sys_enter (struct trace_event_raw_sys_enter * ctx)
nr == FRIDA_LINUX_SYSCALL_FSTAT ||
nr == FRIDA_LINUX_SYSCALL_STATMOUNT)
{
SyscallEnterEventNone * ev = reserve_enter_none ();
SyscallEnterEventNone * ev = reserve_syscall_event (sizeof (SyscallEnterEventNone));
if (ev == NULL)
return 0;
@@ -639,7 +674,7 @@ on_sys_enter (struct trace_event_raw_sys_enter * ctx)
#endif
nr == FRIDA_LINUX_SYSCALL_SYMLINKAT)
{
SyscallEnterEventPath2 * ev = reserve_enter_path2 ();
SyscallEnterEventPath2 * ev = reserve_syscall_event (sizeof (SyscallEnterEventPath2));
if (ev == NULL)
return 0;
@@ -694,7 +729,7 @@ on_sys_enter (struct trace_event_raw_sys_enter * ctx)
if (nr == FRIDA_LINUX_SYSCALL_MOUNT)
{
SyscallEnterEventPath3 * ev = reserve_enter_path3 ();
SyscallEnterEventPath3 * ev = reserve_syscall_event (sizeof (SyscallEnterEventPath3));
if (ev == NULL)
return 0;
@@ -714,7 +749,7 @@ on_sys_enter (struct trace_event_raw_sys_enter * ctx)
if (nr == FRIDA_LINUX_SYSCALL_NANOSLEEP ||
nr == FRIDA_LINUX_SYSCALL_CLOCK_NANOSLEEP)
{
SyscallEnterEventTimespec * ev = reserve_enter_timespec ();
SyscallEnterEventTimespec * ev = reserve_syscall_event (sizeof (SyscallEnterEventTimespec));
if (ev == NULL)
return 0;
@@ -756,7 +791,7 @@ on_sys_enter (struct trace_event_raw_sys_enter * ctx)
nr == FRIDA_LINUX_SYSCALL_BIND ||
nr == FRIDA_LINUX_SYSCALL_SENDTO)
{
SyscallEnterEventSock * ev = reserve_enter_sock ();
SyscallEnterEventSock * ev = reserve_syscall_event (sizeof (SyscallEnterEventSock));
if (ev == NULL)
return 0;
@@ -793,7 +828,7 @@ on_sys_enter (struct trace_event_raw_sys_enter * ctx)
nr == FRIDA_LINUX_SYSCALL_GETPEERNAME ||
nr == FRIDA_LINUX_SYSCALL_RECVFROM)
{
SyscallEnterEventNone * ev = reserve_enter_none ();
SyscallEnterEventNone * ev = reserve_syscall_event (sizeof (SyscallEnterEventNone));
if (ev == NULL)
return 0;
@@ -814,7 +849,7 @@ on_sys_enter (struct trace_event_raw_sys_enter * ctx)
}
{
SyscallEnterEventNone * ev = reserve_enter_none ();
SyscallEnterEventNone * ev = reserve_syscall_event (sizeof (SyscallEnterEventNone));
if (ev == NULL)
return 0;
@@ -834,13 +869,20 @@ on_sys_exit (struct trace_event_raw_sys_exit * ctx)
if (!should_trace_current (&tgid, &tid))
return 0;
Abi abi = get_current_abi ();
__s32 nr = (__s32) ctx->id;
__u32 map_gen = ensure_map_gen (tgid, tid);
if (syscall_is_excluded (abi, nr))
return 0;
__u32 map_gen;
if (!ensure_process_state (tgid, tid, abi, &map_gen))
return 0;
Inflight * in = bpf_map_lookup_elem (&inflight, &tid);
if (in != NULL && in->kind == INFLIGHT_KIND_STR_OUT_COPY && in->syscall_nr == nr)
{
SyscallExitEventStrOut * ev = reserve_exit_str_out ();
SyscallExitEventStrOut * ev = reserve_syscall_event (sizeof (SyscallExitEventStrOut));
if (ev == NULL)
return 0;
@@ -851,30 +893,22 @@ on_sys_exit (struct trace_event_raw_sys_exit * ctx)
long n = ctx->ret;
if (n > 0)
{
__u32 maxn = in->u.str_out_copy.max_len;
if (maxn > MAX_PATH - 1)
maxn = MAX_PATH - 1;
__u32 to_copy = (__u32) n;
if (to_copy > maxn)
to_copy = maxn;
__u32 size = (__u32) n;
if (size > in->u.str_out_copy.max_len)
size = in->u.str_out_copy.max_len;
if (size >= MAX_PATH)
size = MAX_PATH - 1;
size &= MAX_PATH - 1;
barrier_var (size);
ev->attach.type = ATTACHMENT_STRING;
ev->attach.arg_index = in->u.str_out_copy.arg_index;
ev->attach.capacity = MAX_PATH;
ev->attach.size = size + 1;
if (to_copy == (MAX_PATH - 1))
{
ev->attach.len = (MAX_PATH - 1) + 1;
bpf_probe_read_user (&ev->data[0], MAX_PATH - 1, (void *) in->u.str_out_copy.user_ptr);
ev->data[MAX_PATH - 1] = '\0';
}
else
{
ev->attach.len = to_copy + 1;
if (to_copy != 0)
bpf_probe_read_user (&ev->data[0], to_copy, (void *) in->u.str_out_copy.user_ptr);
ev->data[to_copy] = '\0';
}
if (size > 0)
bpf_probe_read_user (&ev->data[0], size, (void *) in->u.str_out_copy.user_ptr);
ev->data[size] = '\0';
ev->parent.parent.parent.attachment_count = 1;
}
@@ -887,7 +921,7 @@ on_sys_exit (struct trace_event_raw_sys_exit * ctx)
if (in != NULL && in->kind == INFLIGHT_KIND_STAT_OUT_COPY && in->syscall_nr == nr)
{
SyscallExitEventStatOut * ev = reserve_exit_stat_out ();
SyscallExitEventStatOut * ev = reserve_syscall_event (sizeof (SyscallExitEventStatOut));
if (ev == NULL)
return 0;
@@ -927,10 +961,20 @@ on_sys_exit (struct trace_event_raw_sys_exit * ctx)
ev->attach.type = ATTACHMENT_BYTES;
ev->attach.arg_index = in->u.stat_out_copy.arg_index;
ev->attach.len = to_copy;
ev->attach.capacity = MAX_STAT;
if (to_copy != 0)
bpf_probe_read_user (&ev->data[0], to_copy, (void *) in->u.stat_out_copy.user_ptr);
if (to_copy == MAX_STAT)
{
ev->attach.size = MAX_STAT;
bpf_probe_read_user (&ev->data[0], MAX_STAT, (void *) in->u.stat_out_copy.user_ptr);
}
else
{
ev->attach.size = to_copy;
if (to_copy != 0)
bpf_probe_read_user (&ev->data[0], to_copy, (void *) in->u.stat_out_copy.user_ptr);
}
ev->parent.parent.parent.attachment_count = 1;
}
@@ -943,7 +987,7 @@ on_sys_exit (struct trace_event_raw_sys_exit * ctx)
if (in != NULL && in->kind == INFLIGHT_KIND_SOCK_OUT_COPY && in->syscall_nr == nr)
{
SyscallExitEventSockOut * ev = reserve_exit_sock_out ();
SyscallExitEventSockOut * ev = reserve_syscall_event (sizeof (SyscallExitEventSockOut));
if (ev == NULL)
return 0;
@@ -988,7 +1032,8 @@ on_sys_exit (struct trace_event_raw_sys_exit * ctx)
ev->attach.type = ATTACHMENT_BYTES;
ev->attach.arg_index = in->u.sock_out_copy.arg_index;
ev->attach.len = to_copy;
ev->attach.capacity = MAX_SOCK;
ev->attach.size = to_copy;
if (to_copy != 0)
bpf_probe_read_user (&ev->data[0], to_copy, (void *) in->u.sock_out_copy.user_ptr);
@@ -1003,7 +1048,7 @@ on_sys_exit (struct trace_event_raw_sys_exit * ctx)
}
{
SyscallExitEventNone * ev = reserve_exit_none ();
SyscallExitEventNone * ev = reserve_syscall_event (sizeof (SyscallExitEventNone));
if (ev == NULL)
return 0;
@@ -1125,67 +1170,34 @@ should_trace_current (__u32 * out_tgid, __u32 * out_tid)
return false;
}
static SyscallEnterEventNone *
reserve_enter_none (void)
static Abi
get_current_abi (void)
{
return reserve_syscall_event (sizeof (SyscallEnterEventNone));
#ifdef FRIDA_TIF_COMPAT32
struct task_struct * task = bpf_get_current_task_btf ();
unsigned long flags = BPF_CORE_READ (task, thread_info.flags);
if (flags & (1UL << FRIDA_TIF_COMPAT32))
return ABI_COMPAT32;
#endif
return ABI_NATIVE;
}
static SyscallEnterEventTimespec *
reserve_enter_timespec (void)
static bool
syscall_is_excluded (Abi abi, __s32 nr)
{
return reserve_syscall_event (sizeof (SyscallEnterEventTimespec));
__u64 k = make_excluded_key (abi, nr);
return bpf_map_lookup_elem (&excluded_syscalls, &k) != NULL;
}
static SyscallEnterEventPath *
reserve_enter_path (void)
static __u64
make_excluded_key (Abi abi, __s32 nr)
{
return reserve_syscall_event (sizeof (SyscallEnterEventPath));
return ((__u64) abi << 32) | (__u32) nr;
}
static SyscallEnterEventPath2 *
reserve_enter_path2 (void)
{
return reserve_syscall_event (sizeof (SyscallEnterEventPath2));
}
static SyscallEnterEventPath3 *
reserve_enter_path3 (void)
{
return reserve_syscall_event (sizeof (SyscallEnterEventPath3));
}
static SyscallEnterEventSock *
reserve_enter_sock (void)
{
return reserve_syscall_event (sizeof (SyscallEnterEventSock));
}
static SyscallExitEventNone *
reserve_exit_none (void)
{
return reserve_syscall_event (sizeof (SyscallExitEventNone));
}
static SyscallExitEventStrOut *
reserve_exit_str_out (void)
{
return reserve_syscall_event (sizeof (SyscallExitEventStrOut));
}
static SyscallExitEventStatOut *
reserve_exit_stat_out (void)
{
return reserve_syscall_event (sizeof (SyscallExitEventStatOut));
}
static SyscallExitEventSockOut *
reserve_exit_sock_out (void)
{
return reserve_syscall_event (sizeof (SyscallExitEventSockOut));
}
static void *
static __always_inline void *
reserve_syscall_event (__u64 size)
{
void * event = bpf_ringbuf_reserve (&syscall_events, size, 0);
@@ -1225,30 +1237,35 @@ fill_enter_args (__u64 args[SYSCALL_NARGS], struct trace_event_raw_sys_enter * c
args[5] = (__u64) ctx->args[5];
}
static __u16
static void
write_attach_str_arg (AttachmentHeader * h, __u16 arg_index, __u8 * dst, __u32 dst_cap, const void * user_str)
{
h->type = ATTACHMENT_STRING;
h->arg_index = arg_index;
h->len = 0;
h->capacity = dst_cap;
long r = bpf_probe_read_user_str (dst, dst_cap, user_str);
__u32 used = (r > 0) ? (__u32) r : 0;
h->len = used;
return (__u16) used;
if (r >= 1)
{
h->size = r;
}
else
{
h->size = 1;
dst[0] = '\0';
}
}
static __u16
static void
write_attach_bytes_arg (AttachmentHeader * h, __u16 arg_index, __u8 * dst, __u32 dst_cap, const void * user_src, __u32 n)
{
h->type = ATTACHMENT_BYTES;
h->arg_index = arg_index;
h->capacity = dst_cap;
if (n == 0)
{
h->len = 0;
return 0;
h->size = 0;
return;
}
if (n > dst_cap)
@@ -1256,9 +1273,7 @@ write_attach_bytes_arg (AttachmentHeader * h, __u16 arg_index, __u8 * dst, __u32
bpf_probe_read_user (dst, n, user_src);
h->len = n;
return (__u16) n;
h->size = n;
}
static __u16
@@ -1268,7 +1283,8 @@ write_attach_dentry_path (AttachmentHeader * h, __u16 arg_index, __u8 * dst, __u
h->type = ATTACHMENT_STRING;
h->arg_index = arg_index;
h->len = 0;
h->capacity = dst_cap;
h->size = 0;
__u32 key = 0;
ScratchArea * sa = bpf_map_lookup_elem (&scratch_area, &key);
@@ -1359,8 +1375,21 @@ write_attach_dentry_path (AttachmentHeader * h, __u16 arg_index, __u8 * dst, __u
break;
}
if (!bb_putc (b, '\0'))
b->buf[MAX_BUF_BUILDER_SIZE - 1] = '\0';
{
__u32 pos = b->pos;
if (pos >= MAX_BUF_BUILDER_SIZE - 1)
{
b->buf[MAX_BUF_BUILDER_SIZE - 1] = '\0';
}
else
{
pos &= (MAX_BUF_BUILDER_SIZE - 2);
barrier_var (pos);
b->buf[pos] = '\0';
b->pos = pos + 1;
}
}
flush:
n = b->pos;
@@ -1370,14 +1399,14 @@ flush:
if (n != 0)
bpf_probe_read_kernel (dst, n, b->buf);
h->len = n;
h->size = n;
return (__u16) n;
}
static void
maybe_schedule_str_out_copy (__u32 tid, __s32 nr, __u16 arg_index, __u64 user_ptr, __u32 max_len)
{
Inflight v;
Inflight v = {};
v.syscall_nr = nr;
v.kind = INFLIGHT_KIND_STR_OUT_COPY;
@@ -1396,7 +1425,7 @@ maybe_schedule_str_out_copy (__u32 tid, __s32 nr, __u16 arg_index, __u64 user_pt
static void
maybe_schedule_stat_out_copy (__u32 tid, __s32 nr, __u16 arg_index, __u64 user_ptr, __u32 len)
{
Inflight v;
Inflight v = {};
v.syscall_nr = nr;
v.kind = INFLIGHT_KIND_STAT_OUT_COPY;
@@ -1415,7 +1444,7 @@ maybe_schedule_stat_out_copy (__u32 tid, __s32 nr, __u16 arg_index, __u64 user_p
static void
maybe_schedule_sock_out_copy (__u32 tid, __s32 nr, __u16 arg_index, __u64 user_ptr, __u64 user_len_ptr, __u32 max_len)
{
Inflight v;
Inflight v = {};
v.syscall_nr = nr;
v.kind = INFLIGHT_KIND_SOCK_OUT_COPY;
@@ -1432,15 +1461,15 @@ maybe_schedule_sock_out_copy (__u32 tid, __s32 nr, __u16 arg_index, __u64 user_p
bpf_map_update_elem (&inflight, &tid, &v, BPF_ANY);
}
static __u32
ensure_map_gen (__u32 tgid, __u32 tid)
static bool
ensure_process_state (__u32 tgid, __u32 tid, Abi abi, __u32 * out_map_gen)
{
ProcessState * st = bpf_map_lookup_elem (&process_states, &tgid);
if (st == NULL)
{
ProcessState init;
ProcessState init = {};
init.abi = 0;
init.abi = abi;
init.map_gen = 0;
long r = bpf_map_update_elem (&process_states, &tgid, &init, BPF_NOEXIST);
@@ -1453,16 +1482,17 @@ ensure_map_gen (__u32 tgid, __u32 tid)
else
{
bpf_map_delete_elem (&process_states, &tgid);
return 0;
return false;
}
}
st = bpf_map_lookup_elem (&process_states, &tgid);
if (st == NULL)
return 0;
return false;
}
return st->map_gen;
*out_map_gen = st->map_gen;
return true;
}
static __u32
+155 -83
View File
@@ -2,18 +2,28 @@
#include <jni.h>
#include <signal.h>
#include <stdbool.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/un.h>
typedef struct _FridaApi FridaApi;
typedef struct _ZymbioteContext ZymbioteContext;
struct _FridaApi
struct _ZymbioteContext
{
char name[64];
char socket_path[64];
void ** art_method_slot;
void * payload_base;
size_t payload_size;
size_t payload_original_protection;
char * package_name;
int (* original_setcontext) (uid_t uid, bool is_system_server, const char * seinfo, const char * name);
void (* original_set_argv0) (JNIEnv * env, jobject clazz, jstring name);
int (* mprotect) (void * addr, size_t len, int prot);
char * (* strdup) (const char * s);
void (* free) (void * ptr);
int (* socket) (int domain, int type, int protocol);
int (* connect) (int sockfd, const struct sockaddr * addr, socklen_t addrlen);
int * (* __errno) (void);
@@ -25,12 +35,17 @@ struct _FridaApi
int (* raise) (int sig);
};
static volatile const FridaApi frida =
ZymbioteContext zymbiote =
{
.name = "/frida-zymbiote-00000000000000000000000000000000",
.socket_path = "/frida-zymbiote-00000000000000000000000000000000",
};
static int frida_stop_and_return (JNIEnv * env, jobject clazz, jstring name);
int frida_zymbiote_replacement_setargv0 (JNIEnv * env, jobject clazz, jstring name);
int frida_zymbiote_replacement_setcontext (uid_t uid, bool is_system_server, const char * seinfo, const char * name);
static void frida_wait_for_permission_to_resume (const char * package_name, bool * revert_now);
static int frida_stop_and_return_from_setargv0 (JNIEnv * env, jobject clazz, jstring name);
static int frida_get_errno (void);
@@ -42,19 +57,71 @@ static ssize_t frida_recv (int sockfd, void * buf, size_t len, int flags);
__attribute__ ((section (".text.entrypoint")))
__attribute__ ((visibility ("default")))
int
frida_zymbiote_replacement_set_argv0 (JNIEnv * env, jobject clazz, jstring name)
frida_zymbiote_replacement_setcontext (uid_t uid, bool is_system_server, const char * seinfo, const char * name)
{
int res;
res = zymbiote.original_setcontext (uid, is_system_server, seinfo, name);
if (res == -1)
return -1;
if (zymbiote.package_name == NULL)
{
zymbiote.mprotect (zymbiote.payload_base, zymbiote.payload_size, PROT_READ | PROT_WRITE | PROT_EXEC);
zymbiote.package_name = zymbiote.strdup (name);
}
return res;
}
__attribute__ ((section (".text.entrypoint")))
__attribute__ ((visibility ("default")))
int
frida_zymbiote_replacement_setargv0 (JNIEnv * env, jobject clazz, jstring name)
{
const char * name_utf8;
bool revert_now;
zymbiote.original_set_argv0 (env, clazz, name);
if (zymbiote.package_name != NULL)
name_utf8 = zymbiote.package_name;
else
name_utf8 = (*env)->GetStringUTFChars (env, name, NULL);
frida_wait_for_permission_to_resume (name_utf8, &revert_now);
if (zymbiote.package_name != NULL)
{
zymbiote.free (zymbiote.package_name);
zymbiote.package_name = NULL;
zymbiote.mprotect (zymbiote.payload_base, zymbiote.payload_size, zymbiote.payload_original_protection);
}
else
{
(*env)->ReleaseStringUTFChars (env, name, name_utf8);
}
if (revert_now)
{
__attribute__ ((musttail))
return frida_stop_and_return_from_setargv0 (env, clazz, name);
}
return 0;
}
static void
frida_wait_for_permission_to_resume (const char * package_name, bool * revert_now)
{
bool success = false;
int fd;
struct sockaddr_un addr;
socklen_t addrlen;
unsigned int name_len;
*frida.art_method_slot = frida.original_set_argv0;
*revert_now = false;
frida.original_set_argv0 (env, clazz, name);
fd = frida.socket (AF_UNIX, SOCK_STREAM, 0);
fd = zymbiote.socket (AF_UNIX, SOCK_STREAM, 0);
if (fd == -1)
goto beach;
@@ -62,15 +129,15 @@ frida_zymbiote_replacement_set_argv0 (JNIEnv * env, jobject clazz, jstring name)
addr.sun_path[0] = '\0';
name_len = 0;
for (unsigned int i = 0; i != sizeof (frida.name); i++)
for (unsigned int i = 0; i != sizeof (zymbiote.socket_path); i++)
{
if (frida.name[i] == '\0')
if (zymbiote.socket_path[i] == '\0')
break;
if (1u + i >= sizeof (addr.sun_path))
break;
addr.sun_path[1u + i] = frida.name[i];
addr.sun_path[1u + i] = zymbiote.socket_path[i];
name_len++;
}
@@ -80,7 +147,6 @@ frida_zymbiote_replacement_set_argv0 (JNIEnv * env, jobject clazz, jstring name)
goto beach;
{
const char * name_utf8;
struct
{
uint32_t pid;
@@ -89,25 +155,21 @@ frida_zymbiote_replacement_set_argv0 (JNIEnv * env, jobject clazz, jstring name)
} header;
struct iovec iov[2];
name_utf8 = (*env)->GetStringUTFChars (env, name, NULL);
header.pid = frida.getpid ();
header.ppid = frida.getppid ();
header.pid = zymbiote.getpid ();
header.ppid = zymbiote.getppid ();
header.package_name_len = 0;
while (name_utf8[header.package_name_len] != '\0')
while (package_name[header.package_name_len] != '\0')
header.package_name_len++;
iov[0].iov_base = &header;
iov[0].iov_len = sizeof (header);
iov[1].iov_base = (void *) name_utf8;
iov[1].iov_base = (void *) package_name;
iov[1].iov_len = header.package_name_len;
if (!frida_sendmsg_all (fd, iov, 2, MSG_NOSIGNAL))
goto beach;
(*env)->ReleaseStringUTFChars (env, name, name_utf8);
}
{
@@ -117,86 +179,96 @@ frida_zymbiote_replacement_set_argv0 (JNIEnv * env, jobject clazz, jstring name)
goto beach;
}
success = true;
*revert_now = true;
beach:
if (fd != -1)
frida.close (fd);
if (success)
{
__attribute__ ((musttail))
return frida_stop_and_return (env, clazz, name);
}
return 0;
zymbiote.close (fd);
}
__attribute__ ((naked, noinline))
static int
frida_stop_and_return (JNIEnv * env, jobject clazz, jstring name)
{
#if defined (__i386__)
__asm__ __volatile__ (
"movl $%c[sig], 4(%%esp)\n"
"call 1f\n"
"1: pop %%eax\n"
# define FRIDA_TAILCALL_TO_RAISE_SIGSTOP() \
__asm__ __volatile__ ( \
"movl $%c[sig], 4(%%esp)\n" \
\
"call 1f\n" \
"1: pop %%eax\n" \
\
"addl $(zymbiote-1b), %%eax\n" \
"movl %c[raise_off](%%eax), %%eax\n" \
\
"jmp *%%eax\n" \
: \
: [sig] "i" (SIGSTOP), \
[raise_off] "i" (offsetof (ZymbioteContext, raise)) \
: "eax", "memory" \
)
"addl $(frida-1b), %%eax\n"
"movl %c[raise_off](%%eax), %%eax\n"
"jmp *%%eax\n"
:
: [sig] "i" (SIGSTOP),
[raise_off] "i" (offsetof (FridaApi, raise))
: "eax", "memory");
#elif defined (__x86_64__)
__asm__ __volatile__ (
"mov $%c[sig], %%edi\n"
"leaq frida(%%rip), %%r11\n"
"movq %c[raise_off](%%r11), %%r11\n"
# define FRIDA_TAILCALL_TO_RAISE_SIGSTOP() \
__asm__ __volatile__ ( \
"mov $%c[sig], %%edi\n" \
\
"leaq zymbiote(%%rip), %%r11\n" \
"movq %c[raise_off](%%r11), %%r11\n" \
\
"jmp *%%r11\n" \
: \
: [sig] "i" (SIGSTOP), \
[raise_off] "i" (offsetof (ZymbioteContext, raise)) \
: "r11", "rdi", "memory" \
)
"jmp *%%r11\n"
:
: [sig] "i" (SIGSTOP),
[raise_off] "i" (offsetof (FridaApi, raise))
: "r11", "rdi", "memory");
#elif defined (__arm__)
__asm__ __volatile__ (
"mov r0, %[sig]\n"
"adr r12, frida\n"
"ldr r12, [r12, %[raise_off]]\n"
# define FRIDA_TAILCALL_TO_RAISE_SIGSTOP() \
__asm__ __volatile__ ( \
"mov r0, %[sig]\n" \
\
"adr r12, zymbiote\n" \
"ldr r12, [r12, %[raise_off]]\n" \
\
"bx r12\n" \
: \
: [sig] "i" (SIGSTOP), \
[raise_off] "i" (offsetof (ZymbioteContext, raise)) \
: "r12", "memory" \
)
"bx r12\n"
:
: [sig] "i" (SIGSTOP),
[raise_off] "i" (offsetof (FridaApi, raise))
: "r12", "memory");
#elif defined (__aarch64__)
__asm__ __volatile__ (
"mov w0, #%[sig]\n"
"adrp x16, frida\n"
"add x16, x16, :lo12:frida\n"
"ldr x16, [x16, %[raise_off]]\n"
# define FRIDA_TAILCALL_TO_RAISE_SIGSTOP() \
__asm__ __volatile__ ( \
"mov w0, #%[sig]\n" \
\
"adrp x16, zymbiote\n" \
"add x16, x16, :lo12:zymbiote\n" \
"ldr x16, [x16, %[raise_off]]\n" \
\
"br x16\n" \
: \
: [sig] "i" (SIGSTOP), \
[raise_off] "i" (offsetof (ZymbioteContext, raise)) \
: "x16", "memory" \
)
"br x16\n"
:
: [sig] "i" (SIGSTOP),
[raise_off] "i" (offsetof (FridaApi, raise))
: "x16", "memory");
#else
# error Unsupported architecture
#endif
__attribute__ ((naked, noinline))
static int
frida_stop_and_return_from_setargv0 (JNIEnv * env, jobject clazz, jstring name)
{
FRIDA_TAILCALL_TO_RAISE_SIGSTOP ();
}
static int
frida_get_errno (void)
{
return *frida.__errno ();
return *zymbiote.__errno ();
}
static int
@@ -204,7 +276,7 @@ frida_connect (int sockfd, const struct sockaddr * addr, socklen_t addrlen)
{
for (;;)
{
if (frida.connect (sockfd, addr, addrlen) == 0)
if (zymbiote.connect (sockfd, addr, addrlen) == 0)
return 0;
if (frida_get_errno () == EINTR)
@@ -219,7 +291,7 @@ frida_sendmsg (int sockfd, const struct msghdr * msg, int flags)
{
for (;;)
{
ssize_t n = frida.sendmsg (sockfd, msg, flags);
ssize_t n = zymbiote.sendmsg (sockfd, msg, flags);
if (n != -1)
return n;
@@ -283,7 +355,7 @@ frida_recv (int sockfd, void * buf, size_t len, int flags)
{
for (;;)
{
ssize_t n = frida.recv (sockfd, buf, len, flags);
ssize_t n = zymbiote.recv (sockfd, buf, len, flags);
if (n != -1)
return n;
File diff suppressed because it is too large. Load diff
+100 -71
View File
@@ -8,27 +8,42 @@ namespace Frida {
private Gee.List<Mapping> maps = new Gee.ArrayList<Mapping> ();
private const uint64 VM_READ = 1;
private const uint64 VM_WRITE = 2;
private const uint64 VM_EXEC = 4;
private const uint64 VM_SHARED = 8;
public class Mapping {
public uint64 start;
public uint64 end;
public size_t size {
get {
return (size_t) (end - start);
}
}
public uint64 file_offset;
public bool readable;
public bool writable;
public bool executable;
public bool shared;
public DevId device;
public uint64 inode;
public string module_id;
public string path;
public uint32 start_gen;
public uint32 end_gen;
}
public static ProcMapsSnapshot from_pid (uint32 pid) throws Error {
public static ProcMapsSnapshot from_pid (uint32 pid) {
var snap = new ProcMapsSnapshot ();
snap.build_from_pid (pid);
return snap;
}
private void build_from_pid (uint32 pid) throws Error {
private void build_from_pid (uint32 pid) {
maps.clear ();
var it = ProcMapsIter.for_pid (pid);
@@ -40,10 +55,16 @@ namespace Frida {
m.end = it.end_address;
m.file_offset = it.file_offset;
string flags = it.flags;
m.readable = flags[0] == 'r';
m.writable = flags[1] == 'w';
m.executable = flags[2] == 'x';
m.shared = flags[3] == 's';
m.device = it.device;
m.inode = it.inode;
m.module_id = normalize_module_id (it.path);
m.path = normalize_path (it.path);
m.start_gen = 1;
m.end_gen = 0;
@@ -52,17 +73,26 @@ namespace Frida {
}
}
public void apply_create (uint32 new_gen, uint64 start, uint64 end, uint64 file_offset, DevId device, uint64 inode,
string module_id) {
public void apply_create (uint32 new_gen, uint64 start, uint64 end, uint64 file_offset, uint64 vm_flags, DevId device,
uint64 inode, string path) {
end_range_at_gen (start, end, new_gen);
var m = new Mapping ();
m.start = start;
m.end = end;
m.file_offset = file_offset;
m.readable = (vm_flags & VM_READ) != 0;
m.writable = (vm_flags & VM_WRITE) != 0;
m.executable = (vm_flags & VM_EXEC) != 0;
m.shared = (vm_flags & VM_SHARED) != 0;
m.device = device;
m.inode = inode;
m.module_id = module_id;
m.path = path;
m.start_gen = new_gen;
m.end_gen = 0;
@@ -108,7 +138,7 @@ namespace Frida {
dead.file_offset = m.file_offset;
dead.device = m.device;
dead.inode = m.inode;
dead.module_id = m.module_id;
dead.path = m.path;
dead.start_gen = m.start_gen;
dead.end_gen = gen;
@@ -128,7 +158,7 @@ namespace Frida {
dead.file_offset = m.file_offset + (start - m.start);
dead.device = m.device;
dead.inode = m.inode;
dead.module_id = m.module_id;
dead.path = m.path;
dead.start_gen = m.start_gen;
dead.end_gen = gen;
@@ -146,7 +176,7 @@ namespace Frida {
dead.file_offset = m.file_offset + (start - m.start);
dead.device = m.device;
dead.inode = m.inode;
dead.module_id = m.module_id;
dead.path = m.path;
dead.start_gen = m.start_gen;
dead.end_gen = gen;
@@ -156,7 +186,7 @@ namespace Frida {
right.file_offset = m.file_offset + (end - m.start);
right.device = m.device;
right.inode = m.inode;
right.module_id = m.module_id;
right.path = m.path;
right.start_gen = m.start_gen;
right.end_gen = 0;
@@ -168,13 +198,21 @@ namespace Frida {
}
}
private static string normalize_module_id (string path) {
private static string normalize_path (string path) {
const string suffix = " (deleted)";
if (path.has_suffix (suffix))
return path.substring (0, path.length - suffix.length);
return path;
}
public Gee.Iterator<Mapping> iterator () {
return maps.iterator ();
}
public Mapping? find_mapping (uint64 addr) {
return find_mapping_at_gen (addr, gen);
}
public Mapping? find_mapping_at_gen (uint64 addr, uint32 gen) {
int lo = 0;
int hi = maps.size - 1;
@@ -224,92 +262,83 @@ namespace Frida {
bool not_ended = m.end_gen == 0 || gen < m.end_gen;
return started && not_ended;
}
}
public class ProcMapsSoEntry {
public uint64 base_address;
public string path;
public DevId device;
public uint64 inode;
private ProcMapsSoEntry (uint64 base_address, string path, DevId device, uint64 inode) {
this.base_address = base_address;
this.path = path;
this.device = device;
this.inode = inode;
public Mapping? find_module_by_path (string path) {
return find_module_by_path_at_gen (path, gen);
}
public static ProcMapsSoEntry? find_by_address (uint pid, uint64 address) {
var iter = ProcMapsIter.for_pid (pid);
while (iter.next ()) {
uint64 start = iter.start_address;
uint64 end = iter.end_address;
if (address >= start && address < end)
return new ProcMapsSoEntry (start, iter.path, iter.device, iter.inode);
}
public Mapping? find_module_by_path_at_gen (string path, uint32 at_gen) {
Mapping? best_base = null;
int best_score = int.MIN;
return null;
}
Mapping? cur_base = null;
uint cur_total = 0;
uint cur_exec = 0;
public static ProcMapsSoEntry? find_by_path (uint pid, string path) {
var candidates = new Gee.ArrayList<Candidate> ();
Candidate? latest_candidate = null;
var iter = ProcMapsIter.for_pid (pid);
#if ANDROID
unowned string libc_path = Gum.Process.get_libc_module ().path;
#endif
while (iter.next ()) {
string current_path = iter.path;
if (current_path == "[page size compat]")
for (int i = 0; i < maps.size; i++) {
var m = maps[i];
if (!mapping_alive_at (m, at_gen))
continue;
if (current_path != path) {
latest_candidate = null;
unowned string mp = m.path;
if (mp == "[page size compat]")
continue;
if (mp != path) {
consider_candidate (ref best_base, ref best_score, cur_base, cur_total, cur_exec);
cur_base = null;
cur_total = 0;
cur_exec = 0;
continue;
}
string flags = iter.flags;
#if ANDROID
if (current_path == libc_path && flags[3] == 's')
if (mp == libc_path && m.shared)
continue;
#endif
if (iter.file_offset == 0) {
latest_candidate = new Candidate () {
entry = new ProcMapsSoEntry (iter.start_address, current_path, iter.device, iter.inode),
total_ranges = 0,
executable_ranges = 0,
};
candidates.add (latest_candidate);
if (m.file_offset == 0) {
consider_candidate (ref best_base, ref best_score, cur_base, cur_total, cur_exec);
cur_base = m;
cur_total = 0;
cur_exec = 0;
}
if (latest_candidate != null) {
latest_candidate.total_ranges++;
if (flags[2] == 'x')
latest_candidate.executable_ranges++;
if (cur_base != null) {
cur_total++;
if (m.executable)
cur_exec++;
}
}
candidates.sort ((a, b) => b.score () - a.score ());
consider_candidate (ref best_base, ref best_score, cur_base, cur_total, cur_exec);
if (candidates.is_empty)
return null;
return candidates.first ().entry;
return best_base;
}
private class Candidate {
public ProcMapsSoEntry entry;
public uint total_ranges;
public uint executable_ranges;
private static void consider_candidate (ref Mapping? best_base, ref int best_score, Mapping? candidate_base, uint total,
uint exec) {
if (candidate_base == null)
return;
public int score () {
int result = (int) total_ranges;
if (executable_ranges == 0)
result = -result;
return result;
int score = score_candidate (total, exec);
if (score > best_score) {
best_score = score;
best_base = candidate_base;
}
}
private static int score_candidate (uint total, uint exec) {
int score = (int) total;
if (exec == 0)
score = -score;
return score;
}
}
public sealed class ProcMapsIter {
+9 -7
View File
@@ -12,6 +12,7 @@ public sealed class Frida.SymbolResolver : Object {
public uint64 end;
public uint64 file_offset;
public uint64 vm_flags;
public DevId device;
public uint64 inode;
public string? path;
@@ -34,12 +35,12 @@ public sealed class Frida.SymbolResolver : Object {
}
uint mod_idx;
if (!used_index.has_key (m.module_id)) {
if (!used_index.has_key (m.path)) {
mod_idx = used_modules.size;
used_index[m.module_id] = mod_idx;
used_modules.add (m.module_id);
used_index[m.path] = mod_idx;
used_modules.add (m.path);
} else {
mod_idx = used_index[m.module_id];
mod_idx = used_index[m.path];
}
uint64 rel64 = (addr - m.start) + m.file_offset;
@@ -92,6 +93,7 @@ public sealed class Frida.SymbolResolver : Object {
ev.start = start;
ev.end = end;
ev.file_offset = file_offset;
ev.vm_flags = vm_flags;
ev.device = device;
ev.inode = inode;
ev.path = path;
@@ -143,8 +145,8 @@ public sealed class Frida.SymbolResolver : Object {
q.unset (next_gen);
if (ev.is_create) {
string module_id = make_module_id (ev.device, ev.inode, ev.path);
snap.apply_create (next_gen, ev.start, ev.end, ev.file_offset, ev.device, ev.inode, module_id);
string path = make_path (ev.device, ev.inode, ev.path);
snap.apply_create (next_gen, ev.start, ev.end, ev.file_offset, ev.vm_flags, ev.device, ev.inode, path);
} else {
snap.apply_destroy_range (next_gen, ev.start, ev.end);
}
@@ -159,7 +161,7 @@ public sealed class Frida.SymbolResolver : Object {
cache.clear ();
}
private static string make_module_id (DevId device, uint64 inode, string? path) {
private static string make_path (DevId device, uint64 inode, string? path) {
if (path != null)
return path;
+12 -20
View File
@@ -21,6 +21,7 @@ public sealed class Frida.SyscallTracer : Object {
private BpfMap? target_tgids;
private BpfMap? target_uids;
private BpfMap? excluded_syscalls;
private BpfRingbufReader? syscall_events_reader;
private IOChannel? syscall_events_channel;
@@ -51,6 +52,7 @@ public sealed class Frida.SyscallTracer : Object {
target_tgids = obj.maps.get_by_name ("target_tgids");
target_uids = obj.maps.get_by_name ("target_uids");
excluded_syscalls = obj.maps.get_by_name ("excluded_syscalls");
var syscall_events = obj.maps.get_by_name ("syscall_events");
var map_events = obj.maps.get_by_name ("map_events");
stacks = obj.maps.get_by_name ("stacks");
@@ -94,6 +96,7 @@ public sealed class Frida.SyscallTracer : Object {
stats = null;
process_states = null;
stacks = null;
excluded_syscalls = null;
target_uids = null;
target_tgids = null;
@@ -116,6 +119,11 @@ public sealed class Frida.SyscallTracer : Object {
target_uids.remove_u32 (uid);
}
public void exclude_syscall (Abi abi, uint nr) throws Error {
uint64 key = ((uint64) abi << 32) | (uint64) nr;
excluded_syscalls.update_u64_u8 (key, 1);
}
public DrainStatus drain_events (SyscallEventHandler on_event) {
var status = syscall_events_reader.drain (payload => {
assert (payload.length >= sizeof (SyscallEvent));
@@ -226,7 +234,7 @@ public sealed class Frida.SyscallTracer : Object {
resolver.refresh_snapshot (ev->tgid);
var s = ProcessState ();
s.abi = compute_abi_from_pid (ev->tgid);
process_states.lookup_raw ((uint8[]) &ev->tgid, (uint8[]) &s);
s.map_gen = 1;
process_states.update_raw ((uint8[]) &ev->tgid, (uint8[]) &s);
} catch (GLib.Error e) {
@@ -282,23 +290,6 @@ public sealed class Frida.SyscallTracer : Object {
}
}
private static Abi compute_abi_from_pid (uint32 tgid) {
#if X86_64 || ARM64
try {
var cpu = Gum.Linux.cpu_type_from_pid ((Posix.pid_t) tgid);
#if X86_64
return (cpu == IA32) ? Abi.COMPAT32 : Abi.NATIVE;
#elif ARM64
return (cpu == ARM) ? Abi.COMPAT32 : Abi.NATIVE;
#endif
} catch (Gum.Error e) {
return NATIVE;
}
#else
return NATIVE;
#endif
}
public struct Event {
public uint64 time_ns;
public uint32 tgid;
@@ -321,7 +312,8 @@ public sealed class Frida.SyscallTracer : Object {
public struct AttachmentHeader {
public uint16 type;
public uint16 arg_index;
public uint32 len;
public uint16 capacity;
public uint16 size;
}
public enum AttachmentType {
@@ -374,7 +366,7 @@ public sealed class Frida.SyscallTracer : Object {
}
private struct ProcessState {
public uint8 abi;
public uint32 abi;
public uint32 map_gen;
}
+14 -5
View File
@@ -38,10 +38,10 @@ if host_os == 'android' or have_droidy_backend
input: [
'android.resources',
android_helper_dex,
fs.copyfile(helpers_native_prefix / 'x86' / 'zymbiote.bin', 'zymbiote-x86.bin'),
fs.copyfile(helpers_native_prefix / 'x86_64' / 'zymbiote.bin', 'zymbiote-x86_64.bin'),
fs.copyfile(helpers_native_prefix / 'arm' / 'zymbiote.bin', 'zymbiote-arm.bin'),
fs.copyfile(helpers_native_prefix / 'arm64' / 'zymbiote.bin', 'zymbiote-arm64.bin'),
fs.copyfile(helpers_native_prefix / 'x86' / 'zymbiote.elf', 'zymbiote-x86.elf'),
fs.copyfile(helpers_native_prefix / 'x86_64' / 'zymbiote.elf', 'zymbiote-x86_64.elf'),
fs.copyfile(helpers_native_prefix / 'arm' / 'zymbiote.elf', 'zymbiote-arm.elf'),
fs.copyfile(helpers_native_prefix / 'arm64' / 'zymbiote.elf', 'zymbiote-arm64.elf'),
],
output: [
'frida-data-android.vapi',
@@ -321,7 +321,12 @@ if have_local_backend
]
if host_os == 'android'
backend_vala_args_private += frida_selinux_vala_args
backend_vala_args_private += [
'--pkg=frida-gum-android-1.0',
'--pkg=android',
'--pkg=jni',
frida_selinux_vala_args,
]
backend_libs += frida_selinux
backend_deps += frida_selinux_dep
endif
@@ -570,6 +575,10 @@ if have_fruity_backend
'fruity' / 'plist.vala',
'fruity' / 'plist-service.vala',
'fruity' / 'opack.vala',
'fruity' / 'kcdata.vala',
'fruity' / 'kdebug.vala',
'fruity' / 'kperfdata.vala',
'fruity' / 'cs-signature.vala',
'fruity' / 'network-stack.vala',
'fruity' / 'usb.vala',
'fruity' / 'ncm.vala',
+1 -1
View File
@@ -1,6 +1,6 @@
[wrap-git]
url = https://github.com/frida/frida-gum.git
revision = bda339b66655f29b5e82277b68235addfbd8fac7
revision = 17.8.0
depth = 1
[provide]
+12 -12
View File
@@ -1764,9 +1764,9 @@ namespace Frida.HostSessionTest {
Variant? icon = prov.icon;
assert_nonnull (icon);
var dict = new VariantDict (icon);
int64 width, height;
assert_true (dict.lookup ("width", "x", out width));
assert_true (dict.lookup ("height", "x", out height));
uint16 width, height;
assert_true (dict.lookup ("width", "q", out width));
assert_true (dict.lookup ("height", "q", out height));
assert_true (width == 16);
assert_true (height == 16);
VariantIter image;
@@ -3296,9 +3296,9 @@ namespace Frida.HostSessionTest {
Variant? icon = prov.icon;
assert_nonnull (icon);
var dict = new VariantDict (icon);
int64 width, height;
assert_true (dict.lookup ("width", "x", out width));
assert_true (dict.lookup ("height", "x", out height));
uint16 width, height;
assert_true (dict.lookup ("width", "q", out width));
assert_true (dict.lookup ("height", "q", out height));
assert_true (width == 16);
assert_true (height == 16);
VariantIter image;
@@ -3572,9 +3572,9 @@ namespace Frida.HostSessionTest {
Variant? icon = prov.icon;
if (icon != null) {
var dict = new VariantDict (icon);
int64 width, height;
assert_true (dict.lookup ("width", "x", out width));
assert_true (dict.lookup ("height", "x", out height));
uint16 width, height;
assert_true (dict.lookup ("width", "q", out width));
assert_true (dict.lookup ("height", "q", out height));
assert_true (width == 16);
assert_true (height == 16);
VariantIter image;
@@ -4231,9 +4231,9 @@ namespace Frida.HostSessionTest {
Variant? icon = prov.icon;
assert_nonnull (icon);
var dict = new VariantDict (icon);
int64 width, height;
assert_true (dict.lookup ("width", "x", out width));
assert_true (dict.lookup ("height", "x", out height));
uint16 width, height;
assert_true (dict.lookup ("width", "q", out width));
assert_true (dict.lookup ("height", "q", out height));
assert_true (width == 16);
assert_true (height == 16);
VariantIter image;
+74
View File
@@ -0,0 +1,74 @@
[CCode (cprefix = "android_", gir_namespace = "Android", gir_version = "1.0")]
namespace Android {
[Compact]
[CCode (cheader_filename = "dlfcn.h", cname = "void", free_function = "dlclose")]
public class Module {
[CCode (cname = "dlopen")]
public static Module? open (string filename, DlOpenFlags flags);
[CCode (cheader_filename = "android/dlext.h", cname = "android_dlopen_ext")]
public static Module? open_ext (string filename, DlOpenFlags flags, DlExtInfo info);
[CCode (cname = "dlsym")]
public void * symbol (string name);
[CCode (cname = "dlerror")]
public static unowned string? get_last_error ();
}
[CCode (cheader_filename = "dlfcn.h", cname = "dlsym")]
public void * dlsym (void * handle, string symbol);
[Flags]
[CCode (cheader_filename = "dlfcn.h", cname = "int", cprefix = "RTLD_", has_type_id = false)]
public enum DlOpenFlags {
LOCAL,
LAZY,
NOW,
NOLOAD,
GLOBAL,
NODELETE,
}
[CCode (cheader_filename = "dlfcn.h", cname = "RTLD_DEFAULT")]
public void * RTLD_DEFAULT;
[CCode (cheader_filename = "dlfcn.h", cname = "RTLD_NEXT")]
public void * RTLD_NEXT;
[Flags]
[CCode (cheader_filename = "android/dlext.h", cprefix = "ANDROID_DLEXT_", has_type_id = false)]
public enum DlExtFlags {
RESERVED_ADDRESS,
RESERVED_ADDRESS_HINT,
WRITE_RELRO,
USE_RELRO,
USE_LIBRARY_FD,
USE_LIBRARY_FD_OFFSET,
FORCE_LOAD,
USE_NAMESPACE,
RESERVED_ADDRESS_RECURSIVE,
}
[CCode (cheader_filename = "android/dlext.h", cname = "android_dlextinfo", has_type_id = false)]
public struct DlExtInfo {
public DlExtFlags flags;
public void * reserved_addr;
public size_t reserved_size;
public int relro_fd;
public int library_fd;
public int64 library_fd_offset;
public Namespace * library_namespace;
}
[CCode (cheader_filename = "android/dlext.h", cname = "struct android_namespace_t", has_type_id = false)]
public struct Namespace {
}
[CCode (cheader_filename = "signal.h", cname = "NSIG")]
public const int NSIG;
}
+189
View File
@@ -0,0 +1,189 @@
[CCode (cheader_filename = "frida-jni.h", gir_namespace = "Jni", gir_version = "1.0")]
namespace JNI {
public const int VERSION_1_1;
public const int VERSION_1_2;
public const int VERSION_1_4;
public const int VERSION_1_6;
[CCode (cname = "jint", cprefix = "JNI_", has_type_id = false)]
public enum Result {
OK,
ERR,
EDETACHED,
EVERSION,
ENOMEM,
EEXIST,
EINVAL,
}
[CCode (cname = "JavaVMInitArgs", has_destroy_function = false)]
public struct VMInitArgs {
public int version;
[CCode (array_length_cname = "nOptions")]
public VMOption[] options;
[CCode (cname = "ignoreUnrecognized")]
public bool ignore_unrecognized;
}
[CCode (cname = "JavaVMOption", has_destroy_function = false)]
public struct VMOption {
[CCode (cname = "optionString")]
public string option_string;
[CCode (cname = "extraInfo")]
public void * extra_info;
}
[CCode (cname = "JavaVMAttachArgs", has_destroy_function = false)]
public struct VMAttachArgs {
public int version;
public string? name;
public ObjectRef * group;
}
[CCode (cname = "jobject", has_type_id = false)]
public struct ObjectRef {}
[CCode (cname = "jclass", has_type_id = false)]
public struct ClassRef {}
[CCode (cname = "jstring", has_type_id = false)]
public struct StringRef {}
[CCode (cname = "jboolean", has_type_id = false)]
public enum Boolean {
FALSE = 0,
TRUE = 1,
}
[CCode (cname = "jthrowable", has_type_id = false)]
public struct ThrowableRef {}
[CCode (cname = "jmethodID", has_type_id = false)]
public struct MethodID {}
[CCode (cname = "struct JNIInvokeInterface")]
public class InvokeInterface {
[CCode (cname = "DestroyJavaVM")]
public DestroyJavaVMFunc destroy_java_vm;
[CCode (cname = "AttachCurrentThread")]
public AttachCurrentThreadFunc attach_current_thread;
[CCode (cname = "DetachCurrentThread")]
public DetachCurrentThreadFunc detach_current_thread;
[CCode (cname = "GetEnv")]
public GetEnvFunc get_env;
[CCode (cname = "AttachCurrentThreadAsDaemon")]
public AttachCurrentThreadFunc attach_current_thread_as_daemon;
}
[CCode (has_target = false)]
public delegate Result DestroyJavaVMFunc (InvokeInterface ** vm);
[CCode (has_target = false)]
public delegate Result AttachCurrentThreadFunc (InvokeInterface ** vm, out NativeInterface ** env, VMAttachArgs * args);
[CCode (has_target = false)]
public delegate Result DetachCurrentThreadFunc (InvokeInterface ** vm);
[CCode (has_target = false)]
public delegate Result GetEnvFunc (InvokeInterface ** vm, out NativeInterface ** env, int version);
[CCode (cname = "struct JNINativeInterface")]
public class NativeInterface {
[CCode (cname = "FindClass")]
public FindClassFunc find_class;
[CCode (cname = "ExceptionOccurred")]
public ExceptionOccurredFunc exception_occurred;
[CCode (cname = "ExceptionClear")]
public ExceptionClearFunc exception_clear;
[CCode (cname = "PushLocalFrame")]
public PushLocalFrameFunc push_local_frame;
[CCode (cname = "PopLocalFrame")]
public PopLocalFrameFunc pop_local_frame;
[CCode (cname = "NewGlobalRef")]
public NewGlobalRefFunc new_global_ref;
[CCode (cname = "DeleteGlobalRef")]
public DeleteGlobalRefFunc delete_global_ref;
[CCode (cname = "DeleteLocalRef")]
public DeleteLocalRefFunc delete_local_ref;
[CCode (cname = "NewObject")]
public NewObjectFunc new_object;
[CCode (cname = "GetObjectClass")]
public GetObjectClassFunc get_object_class;
[CCode (cname = "GetMethodID")]
public GetMethodIDFunc get_method_id;
[CCode (cname = "CallObjectMethod")]
public CallObjectMethodFunc call_object_method;
[CCode (cname = "NewStringUTF")]
public NewStringUTFFunc new_string_utf;
[CCode (cname = "GetStringUTFChars")]
public GetStringUTFCharsFunc get_string_utf_chars;
[CCode (cname = "ReleaseStringUTFChars")]
public ReleaseStringUTFCharsFunc release_string_utf_chars;
}
[CCode (has_target = false)]
public delegate ClassRef * FindClassFunc (NativeInterface ** env, string name);
[CCode (has_target = false)]
public delegate ThrowableRef * ExceptionOccurredFunc (NativeInterface ** env);
[CCode (has_target = false)]
public delegate void ExceptionClearFunc (NativeInterface ** env);
[CCode (has_target = false)]
public delegate Result PushLocalFrameFunc (NativeInterface ** env, int capacity);
[CCode (has_target = false)]
public delegate ObjectRef * PopLocalFrameFunc (NativeInterface ** env, ObjectRef * result);
[CCode (has_target = false)]
public delegate ObjectRef * NewGlobalRefFunc (NativeInterface ** env, ObjectRef * obj);
[CCode (has_target = false)]
public delegate void DeleteGlobalRefFunc (NativeInterface ** env, ObjectRef * obj);
[CCode (has_target = false)]
public delegate void DeleteLocalRefFunc (NativeInterface ** env, ObjectRef * obj);
[CCode (has_target = false)]
public delegate ObjectRef * NewObjectFunc (NativeInterface ** env, ClassRef * klass, MethodID * method, ...);
[CCode (has_target = false)]
public delegate ClassRef * GetObjectClassFunc (NativeInterface ** env, ObjectRef * obj);
[CCode (has_target = false)]
public delegate MethodID * GetMethodIDFunc (NativeInterface ** env, ClassRef * klass, string name, string sig);
[CCode (has_target = false)]
public delegate ObjectRef * CallObjectMethodFunc (NativeInterface ** env, ObjectRef * obj, MethodID * method, ...);
[CCode (has_target = false)]
public delegate StringRef * NewStringUTFFunc (NativeInterface ** env, string utf8);
[CCode (has_target = false)]
public delegate unowned string GetStringUTFCharsFunc (NativeInterface ** env, StringRef * str, out Boolean is_copy = null);
[CCode (has_target = false)]
public delegate void ReleaseStringUTFCharsFunc (NativeInterface ** env, StringRef * str, string chars);
}