mirror of
https://github.com/frida/frida-core.git
synced 2026-11-08 17:12:49 -10:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0ada4a9ff |
No files matched your search
@@ -1,4 +0,0 @@
|
||||
set(VCPKG_TARGET_ARCHITECTURE arm64)
|
||||
set(VCPKG_CRT_LINKAGE dynamic)
|
||||
set(VCPKG_LIBRARY_LINKAGE dynamic)
|
||||
set(VCPKG_BUILD_TYPE release)
|
||||
@@ -1,4 +0,0 @@
|
||||
set(VCPKG_TARGET_ARCHITECTURE x64)
|
||||
set(VCPKG_CRT_LINKAGE dynamic)
|
||||
set(VCPKG_LIBRARY_LINKAGE dynamic)
|
||||
set(VCPKG_BUILD_TYPE release)
|
||||
+33
-157
@@ -20,8 +20,8 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- { id: windows-arm64, runner: '"windows-11-arm"', sys: CLANGARM64, pkg: 'mingw-w64-clang-aarch64-clang', opts: "'-Dfrida-gum:v8=disabled'" }
|
||||
- { id: windows-x86_64, runner: '"windows-latest"', sys: UCRT64, pkg: 'mingw-w64-ucrt-x86_64-gcc' }
|
||||
- { id: windows-arm64, runner: '"windows-11-arm"', sys: CLANGARM64, pkg: 'mingw-w64-clang-aarch64-clang' }
|
||||
- { id: windows-x86_64, runner: '"windows-latest"', sys: MINGW64, pkg: 'mingw-w64-x86_64-gcc' }
|
||||
- { id: windows-x86, runner: '"windows-latest"', sys: MINGW32, pkg: 'mingw-w64-i686-gcc' }
|
||||
- { id: macos-x86_64, runner: '"macos-latest"' }
|
||||
- { id: macos-arm64, runner: '"macos-latest"' }
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
runs-on: ${{ fromJSON(matrix.runner) }}
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Install MinGW toolchain for cgo support
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
msystem: ${{ matrix.sys }}
|
||||
install: ${{ matrix.pkg }}
|
||||
- name: Install Go toolchain
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: 'src/compiler/go.mod'
|
||||
cache-dependency-path: 'src/compiler/go.mod'
|
||||
@@ -61,17 +61,13 @@ jobs:
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install gcc-multilib lib32stdc++-13-dev
|
||||
- name: Install setuptools for distutils shim
|
||||
if: ${{ startsWith(matrix.id, 'windows-') }}
|
||||
run: pip install setuptools
|
||||
- name: Build
|
||||
if: ${{ startsWith(matrix.id, 'windows-') }}
|
||||
run: |
|
||||
.\configure `
|
||||
--host=${{ matrix.id }} `
|
||||
--enable-compiler-backend `
|
||||
${{ env.FRIDA_CORE_OPTIONS }} `
|
||||
-- --force-fallback-for=openssl ${{ matrix.opts }}
|
||||
${{ env.FRIDA_CORE_OPTIONS }}
|
||||
.\make
|
||||
env:
|
||||
MSYS2_LOCATION: ${{ steps.msys2.outputs.msys2-location }}
|
||||
@@ -95,40 +91,14 @@ jobs:
|
||||
make
|
||||
- name: Upload devkit
|
||||
if: ${{ !startsWith(matrix.id, 'linux-') }}
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: core-devkit-${{ matrix.id }}
|
||||
path: build/src/devkit/
|
||||
- name: Upload GObject introspection data
|
||||
if: ${{ matrix.id == 'linux-x86_64' }}
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: core-gir
|
||||
path: build/src/api/Frida-1.0.gir
|
||||
- name: Test
|
||||
if: ${{ matrix.id != 'windows-arm64' && !startsWith(matrix.id, 'macos-') }}
|
||||
run: make test
|
||||
|
||||
publish-gir:
|
||||
if: ${{ !cancelled() && github.ref_type == 'tag' && needs.native.result == 'success' }}
|
||||
needs:
|
||||
- native
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download GObject introspection data
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: core-gir
|
||||
path: gir
|
||||
- name: Attach to GitHub release
|
||||
uses: softprops/action-gh-release@v3
|
||||
with:
|
||||
files: |
|
||||
gir/Frida-1.0.gir
|
||||
prerelease: ${{ contains(github.ref_name, 'snapshot') }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
cross:
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -143,7 +113,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Install toolchain
|
||||
@@ -151,7 +121,7 @@ jobs:
|
||||
sudo apt-get update
|
||||
sudo apt-get install ${{ matrix.pkg }}
|
||||
- name: Install Go toolchain
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: 'src/compiler/go.mod'
|
||||
cache-dependency-path: 'src/compiler/go.mod'
|
||||
@@ -164,7 +134,7 @@ jobs:
|
||||
make
|
||||
- name: Upload devkit
|
||||
if: ${{ !startsWith(matrix.id, 'linux-') }}
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: core-devkit-${{ matrix.id }}
|
||||
path: build/src/devkit/
|
||||
@@ -178,11 +148,11 @@ jobs:
|
||||
container: ghcr.io/frida/x-tools-linux-${{ matrix.arch }}:latest
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Install Go toolchain
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: 'src/compiler/go.mod'
|
||||
cache-dependency-path: 'src/compiler/go.mod'
|
||||
@@ -194,7 +164,7 @@ jobs:
|
||||
${{ env.FRIDA_CORE_OPTIONS }}
|
||||
make
|
||||
- name: Upload devkit
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: core-devkit-linux-${{ matrix.arch }}
|
||||
path: build/src/devkit/
|
||||
@@ -211,7 +181,7 @@ jobs:
|
||||
container: ghcr.io/frida/x-tools-linux-${{ matrix.arch }}:latest
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build
|
||||
@@ -342,11 +312,11 @@ jobs:
|
||||
runs-on: ${{ startsWith(matrix.id, 'ios-') && 'macos-latest' || 'ubuntu-latest' }}
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Install Go toolchain
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: 'src/compiler/go.mod'
|
||||
cache-dependency-path: 'src/compiler/go.mod'
|
||||
@@ -361,7 +331,7 @@ jobs:
|
||||
if: startsWith(matrix.id, 'android-')
|
||||
id: setup-ndk
|
||||
with:
|
||||
ndk-version: r29
|
||||
ndk-version: r25c
|
||||
- name: Add NDK to env
|
||||
if: startsWith(matrix.id, 'android-')
|
||||
run: echo ANDROID_NDK_ROOT=${{ steps.setup-ndk.outputs.ndk-path }} >> $GITHUB_ENV
|
||||
@@ -373,7 +343,7 @@ jobs:
|
||||
${{ env.FRIDA_CORE_OPTIONS }}
|
||||
make
|
||||
- name: Upload devkit
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: core-devkit-${{ matrix.id }}
|
||||
path: build/src/devkit/
|
||||
@@ -432,7 +402,7 @@ jobs:
|
||||
container: ghcr.io/frida/qnx-tools:latest
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build
|
||||
@@ -441,7 +411,7 @@ jobs:
|
||||
./configure --host=arm-unknown-nto-qnx6.5.0eabi ${{ env.FRIDA_CORE_OPTIONS }}
|
||||
make
|
||||
- name: Upload devkit
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: core-devkit-qnx-armeabi
|
||||
path: build/src/devkit/
|
||||
@@ -451,17 +421,13 @@ jobs:
|
||||
cd build
|
||||
cp -a tests/frida-tests tests/labrats lib/agent/frida-agent.so /tmp/pkg/
|
||||
tar -C /tmp/pkg -cf /tmp/runner.tar .
|
||||
/opt/sabrelite/run.sh /tmp/runner.tar \
|
||||
"cp /opt/frida/frida-tests /opt/frida/frida-agent.so /tmp/ && \
|
||||
ln -sP /opt/frida/labrats /tmp/labrats && \
|
||||
/tmp/frida-tests"
|
||||
/opt/sabrelite/run.sh /tmp/runner.tar /opt/frida/frida-tests
|
||||
|
||||
# This job is used to check that the Linux helpers are built correctly for all
|
||||
# supported architectures. We do this because the binary artifacts are checked
|
||||
# in, and we want to ensure that they are up-to-date with respect to the source
|
||||
# for all architectures.
|
||||
check-linux-helpers:
|
||||
if: false
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86, x86_64, arm, armbe8, arm64, arm64be, arm64beilp32, mips, mipsel, mips64, mips64el]
|
||||
@@ -470,7 +436,7 @@ jobs:
|
||||
container: ghcr.io/frida/core-linux-helpers-${{ matrix.arch }}:latest
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build
|
||||
@@ -479,7 +445,7 @@ jobs:
|
||||
- name: Check for unexpected changes
|
||||
run: |
|
||||
git config --global --add safe.directory "$(realpath .)"
|
||||
status_output=$(git status --porcelain src/linux/helpers/artifacts)
|
||||
status_output=$(git status --porcelain tests/labrats/{resident-agent,simple-agent}-linux-${{ matrix.arch }}.so tests/labrats/{forker,sleeper,spawner}-linux-${{ matrix.arch }})
|
||||
if [ -n "$status_output" ]; then
|
||||
echo "Unexpected changes detected:"
|
||||
echo "$status_output"
|
||||
@@ -495,7 +461,6 @@ jobs:
|
||||
# in, and we want to ensure that they are up-to-date with respect to the source
|
||||
# for all architectures.
|
||||
check-labrats:
|
||||
if: false
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86, x86_64, arm, armbe8, arm64, arm64be, arm64beilp32, mips, mipsel, mips64, mips64el]
|
||||
@@ -504,7 +469,7 @@ jobs:
|
||||
container: ghcr.io/frida/core-linux-helpers-${{ matrix.arch }}:latest
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build
|
||||
@@ -513,7 +478,7 @@ jobs:
|
||||
- name: Check for unexpected changes
|
||||
run: |
|
||||
git config --global --add safe.directory "$(realpath .)"
|
||||
status_output=$(git status --porcelain tests/labrats/{resident-agent,simple-agent}-linux-${{ matrix.arch }}.so tests/labrats/{forker,sleeper,spawner}-linux-${{ matrix.arch }})
|
||||
status_output=$(git status --porcelain src/linux/helpers/{bootstrapper,loader}-${{ matrix.arch }}.bin)
|
||||
if [ -n "$status_output" ]; then
|
||||
echo "Unexpected changes detected:"
|
||||
echo "$status_output"
|
||||
@@ -526,31 +491,30 @@ jobs:
|
||||
|
||||
xcframework:
|
||||
name: Build FridaCore.xcframework
|
||||
if: ${{ !cancelled() }}
|
||||
runs-on: macos-latest
|
||||
needs:
|
||||
- native
|
||||
- mobile
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
- name: Download macOS/x86_64 devkit
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: core-devkit-macos-x86_64
|
||||
path: devkits/macos-x86_64
|
||||
- name: Download macOS/arm64 devkit
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: core-devkit-macos-arm64
|
||||
path: devkits/macos-arm64
|
||||
- name: Download iOS/arm64 devkit
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: core-devkit-ios-arm64
|
||||
path: devkits/ios-arm64
|
||||
- name: Download iOS/arm64-simulator devkit
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: core-devkit-ios-arm64-simulator
|
||||
path: devkits/ios-arm64-simulator
|
||||
@@ -613,19 +577,19 @@ jobs:
|
||||
-headers xcframework_headers/ios-arm64-simulator \
|
||||
-output FridaCore.xcframework
|
||||
- name: Upload FridaCore.xcframework
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: FridaCore.xcframework
|
||||
path: FridaCore.xcframework
|
||||
|
||||
publish-xcframework:
|
||||
if: ${{ !cancelled() && github.ref_type == 'tag' && needs.xcframework.result == 'success' }}
|
||||
if: github.ref_type == 'tag'
|
||||
runs-on: macos-latest
|
||||
needs:
|
||||
- xcframework
|
||||
steps:
|
||||
- name: Download FridaCore.xcframework artifact
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: FridaCore.xcframework
|
||||
path: dist
|
||||
@@ -648,98 +612,10 @@ jobs:
|
||||
cd dist
|
||||
zip -r FridaCore.xcframework.zip FridaCore.xcframework
|
||||
- name: Create GitHub release
|
||||
uses: softprops/action-gh-release@v3
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: |
|
||||
dist/FridaCore.xcframework.zip
|
||||
prerelease: ${{ contains(github.ref_name, 'snapshot') }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
windows-shared:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- { arch: x86_64, runner: windows-latest, msvc-arch: amd64, vcpkg-triplet: x64-windows-release }
|
||||
- { arch: arm64, runner: windows-11-arm, msvc-arch: arm64, vcpkg-triplet: arm64-windows-release, opts: "'-Dfrida-gum:v8=disabled'" }
|
||||
fail-fast: false
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up MSVC environment
|
||||
run: |
|
||||
$vs = & "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -products * -latest -property installationPath
|
||||
$before = @{}
|
||||
Get-ChildItem env: | ForEach-Object { $before[$_.Name] = $_.Value }
|
||||
cmd /c "`"$vs\VC\Auxiliary\Build\vcvarsall.bat`" ${{ matrix.msvc-arch }} >nul && set" | ForEach-Object {
|
||||
$name, $value = $_ -split '=', 2
|
||||
if ($before[$name] -ne $value) {
|
||||
"$name=$value" >> $env:GITHUB_ENV
|
||||
}
|
||||
}
|
||||
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Install build tools
|
||||
run: |
|
||||
pip install meson ninja setuptools
|
||||
choco install pkgconfiglite -y
|
||||
|
||||
- name: Restore vcpkg cache
|
||||
id: vcpkg-cache
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: C:\vcpkg\installed
|
||||
key: vcpkg-${{ matrix.vcpkg-triplet }}-v5
|
||||
|
||||
- name: Install dependencies via vcpkg
|
||||
if: steps.vcpkg-cache.outputs.cache-hit != 'true'
|
||||
run: >-
|
||||
vcpkg install
|
||||
--overlay-triplets=${{ github.workspace }}/.github/vcpkg-triplets
|
||||
--triplet ${{ matrix.vcpkg-triplet }}
|
||||
glib json-glib libsoup
|
||||
|
||||
- name: Save vcpkg cache
|
||||
if: steps.vcpkg-cache.outputs.cache-hit != 'true'
|
||||
uses: actions/cache/save@v5
|
||||
with:
|
||||
path: C:\vcpkg\installed
|
||||
key: vcpkg-${{ matrix.vcpkg-triplet }}-v5
|
||||
|
||||
- name: Set up vcpkg environment
|
||||
shell: bash
|
||||
run: |
|
||||
TRIPLET="${{ matrix.vcpkg-triplet }}"
|
||||
VCPKG_PREFIX="C:/vcpkg/installed/$TRIPLET"
|
||||
echo "$VCPKG_PREFIX/tools/pkgconf" >> $GITHUB_PATH
|
||||
echo "$VCPKG_PREFIX/bin" >> $GITHUB_PATH
|
||||
echo "$VCPKG_PREFIX/tools" >> $GITHUB_PATH
|
||||
echo "PKG_CONFIG_PATH=$VCPKG_PREFIX/lib/pkgconfig" >> $GITHUB_ENV
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
python -c "import sys; sys.path.insert(0, '.'); from releng.meson_configure import main; main()" `
|
||||
. `
|
||||
--host=windows-${{ matrix.arch }} `
|
||||
--enable-shared `
|
||||
--without-prebuilds=sdk `
|
||||
"--prefix=$env:RUNNER_TEMP\frida-prefix" `
|
||||
-- --force-fallback-for=openssl,libnghttp2 -Dcompiler_backend=disabled -Dtests=disabled ${{ matrix.opts }}
|
||||
|
||||
- name: Compile
|
||||
run: python releng/meson/meson.py compile -C build
|
||||
|
||||
- name: Install
|
||||
run: python releng/meson/meson.py install -C build --no-rebuild --skip-subprojects
|
||||
|
||||
- name: List installed files
|
||||
shell: bash
|
||||
run: find "$RUNNER_TEMP/frida-prefix" -type f | sort
|
||||
+1
-10
@@ -1,16 +1,7 @@
|
||||
/.cache/
|
||||
/build/
|
||||
/deps/
|
||||
/src/android-helper/build/
|
||||
/src/barebone/agent/linux/*.ko
|
||||
/src/barebone/agent/linux/*.mod
|
||||
/src/barebone/agent/linux/*.mod.c
|
||||
/src/barebone/agent/linux/*.o
|
||||
/src/barebone/agent/linux/*.o.bin
|
||||
/src/barebone/agent/linux/.*.cmd
|
||||
/src/barebone/agent/linux/Module.symvers
|
||||
/src/barebone/agent/linux/modules.order
|
||||
/src/barebone/agent/target*/
|
||||
/src/barebone/agent/target/
|
||||
/src/barebone/agent/xpacks/
|
||||
/src/barebone/helpers/memory-scanner/target/
|
||||
/src/barebone/helpers/target/
|
||||
|
||||
@@ -1,153 +0,0 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code)
|
||||
when working with code in this repository.
|
||||
|
||||
## What This Is
|
||||
|
||||
frida-core is the core library of the Frida dynamic
|
||||
instrumentation toolkit. It packages GumJS into a shared
|
||||
library, injects JavaScript instrumentation into target
|
||||
processes, provides bidirectional RPC communication with
|
||||
injected scripts, and enumerates apps/processes/devices.
|
||||
Written primarily in Vala with OS-specific glue in
|
||||
C/Objective-C/asm.
|
||||
|
||||
## Build Commands
|
||||
|
||||
```bash
|
||||
# First-time setup (fetches git submodules, configures build):
|
||||
./configure \
|
||||
--enable-compiler-backend \
|
||||
--with-devkits=core \
|
||||
--enable-tests
|
||||
|
||||
# Build:
|
||||
make
|
||||
|
||||
# Run tests:
|
||||
make test
|
||||
|
||||
# Rebuild after code changes
|
||||
make
|
||||
```
|
||||
|
||||
The `configure` script and `Makefile` are thin wrappers
|
||||
around `releng/meson_configure.py` and
|
||||
`releng/meson_make.py`. The actual build system is Meson
|
||||
(>=1.1.0).
|
||||
|
||||
Build artifacts go into `build/`. The triplet is
|
||||
platform-dependent (e.g. `linux-x86_64`).
|
||||
|
||||
## Build Requirements
|
||||
|
||||
- **Vala compiler**: Must be the Frida-optimized fork from
|
||||
https://github.com/frida-forks/vala (checks for `-frida` suffix
|
||||
in version)
|
||||
- **C/C++ standards**: gnu99/c99 for C, c++17 for C++
|
||||
- **Go >= 1.24**: Required for compiler backend
|
||||
- **Python 3**: Build scripts
|
||||
|
||||
## Architecture
|
||||
|
||||
### Backend System
|
||||
|
||||
The core abstraction is a pluggable backend system. Each
|
||||
backend implements `HostSessionBackend` and provides a
|
||||
`HostSessionProvider` to create sessions with target
|
||||
processes:
|
||||
|
||||
- **local** — Injects into processes on the local system
|
||||
(Linux, macOS, Windows, FreeBSD, QNX)
|
||||
- **fruity** — iOS/tvOS/xrOS devices via USB/network
|
||||
(QUIC, lockdown protocols)
|
||||
- **droidy** — Android devices via ADB/JDWP
|
||||
- **socket** — Remote devices via TCP (connects to
|
||||
frida-server, frida-gadget, frida-portal)
|
||||
- **barebone** — Minimal backend using QuickJS
|
||||
- **simmy** — macOS Simulator
|
||||
- **compiler** — TypeScript/ESBuild compilation backend
|
||||
(Go + TypeScript in `src/compiler/`)
|
||||
|
||||
Backends are selected at build time via meson options
|
||||
(e.g. `-Dlocal_backend=enabled`).
|
||||
|
||||
### Key Source Layout
|
||||
|
||||
- **`src/frida.vala`** — Public API: `DeviceManager`,
|
||||
`Device`, `Session`, `Script`
|
||||
- **`src/host-session-service.vala`** — Backend
|
||||
orchestration, provider registration
|
||||
- **`src/control-service.vala`** — the guts of frida-server
|
||||
- **`src/portal-service.vala`** — the guts of frida-portal,
|
||||
which looks like a frida-server that surfaces any joined
|
||||
processes (think aggregator/reverse proxy)
|
||||
- **`lib/base/`** — Core primitives: Session, RPC, streams,
|
||||
sockets, P2P, buffers
|
||||
- **`lib/agent/`** — In-process JavaScript agent runtime
|
||||
- **`lib/payload/`** — Payload compilation and embedding
|
||||
- **`lib/gadget/`** — Gadget (preloaded library)
|
||||
implementation
|
||||
- **`src/<platform>/`** — Platform-specific injectors and
|
||||
helpers (`linux/`, `darwin/`, `windows/`, `freebsd/`,
|
||||
`qnx/`)
|
||||
- **`src/fruity/`** — iOS device protocol stack (USB, QUIC,
|
||||
plist, XPC, LLDB)
|
||||
- **`src/droidy/`** — Android device protocol stack
|
||||
- **`src/compiler/`** — Go/TypeScript compiler backend
|
||||
|
||||
### Injection Flow
|
||||
|
||||
Each platform has its own injector (e.g. `Linjector` on
|
||||
Linux, `Fruitjector` on Darwin, `Winjector` on Windows). A
|
||||
helper process (`frida-helper`) performs privileged injection
|
||||
operations out-of-process. Helpers and agents can be embedded
|
||||
into the library or installed as separate files (controlled
|
||||
by the `assets` meson option).
|
||||
|
||||
### Deliverables
|
||||
|
||||
- **frida-server** (`server/`) — Standalone daemon exposing
|
||||
the full API over the network
|
||||
- **frida-portal** (`portal/`) — Cluster node for
|
||||
distributed instrumentation
|
||||
- **frida-inject** (`inject/`) — CLI tool for one-shot
|
||||
script injection
|
||||
- **frida-gadget** (`lib/gadget/`) — Shared library for
|
||||
preload-based instrumentation
|
||||
|
||||
### Resource Embedding
|
||||
|
||||
Build artifacts (frida-helper, frida-agent) are compiled
|
||||
into resource blobs via `tools/resource-compiler.vala` and
|
||||
embedding scripts (`src/embed-helper.py`,
|
||||
`src/embed-agent.py`). On non-MSVC toolchains these become
|
||||
`.S` assembly files; on MSVC they become `.obj` files.
|
||||
|
||||
## Tests
|
||||
|
||||
Tests are in `tests/` as Vala files using a custom async
|
||||
test harness (`tests/async-harness.vala`). Test binary is
|
||||
`tests/frida-tests`. Platform-specific runner scripts exist
|
||||
(e.g. `tests/run-linux-x86_64.sh`).
|
||||
|
||||
Test modules: `test-system`, `test-injector`, `test-agent`,
|
||||
`test-host-session`, `test-gadget`, `test-compiler`. Test
|
||||
helper programs ("labrats") are in `tests/labrats/`.
|
||||
|
||||
## Code Style
|
||||
|
||||
### Function Order
|
||||
|
||||
Use newspaper/stepdown order: high-level entry points
|
||||
first, low-level helpers and constants last. In C,
|
||||
`main()` is always first. When ordering siblings at the
|
||||
same level, use the chronological order of first use
|
||||
within their caller.
|
||||
|
||||
## Commit Style
|
||||
|
||||
- Subject line: max 50 characters
|
||||
- Body lines: wrap at 72 characters (use the full width, or
|
||||
slightly less if it avoids making the next line awkward)
|
||||
@@ -1,4 +1,4 @@
|
||||
PYTHON ?= $(shell command -v python3 >/dev/null && echo python3 || echo python)
|
||||
PYTHON ?= $(shell which python3 >/dev/null && echo python3 || echo python)
|
||||
|
||||
all $(MAKECMDGOALS):
|
||||
@$(PYTHON) \
|
||||
@@ -8,7 +8,7 @@ all $(MAKECMDGOALS):
|
||||
$(MAKECMDGOALS)
|
||||
|
||||
git-submodules:
|
||||
@if [ ! -f releng/meson/meson.py ] || git submodule status 2>/dev/null | grep -q '^-'; then \
|
||||
@if [ ! -f releng/meson/meson.py ]; then \
|
||||
git submodule update --init --recursive --depth 1; \
|
||||
fi
|
||||
-include git-submodules
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
# frida-core
|
||||
|
||||
Frida core library.
|
||||
Frida core library intended for static linking into bindings.
|
||||
|
||||
- Lets you inject your own JavaScript instrumentation code
|
||||
into other processes, optionally with your own [C code][]
|
||||
for performance-sensitive bits.
|
||||
- Acts as a logistics layer that packages up [GumJS][] into
|
||||
a shared library.
|
||||
- Provides a two-way communication channel for talking to
|
||||
your scripts, if needed, and later unload them.
|
||||
- Also lets you enumerate installed apps, running processes,
|
||||
and connected devices.
|
||||
- Written in [Vala][], with OS-specific glue code in
|
||||
C/Objective-C/asm.
|
||||
- Lets you inject your own JavaScript instrumentation code into other processes,
|
||||
optionally with your own [C code][] for performance-sensitive bits.
|
||||
- Acts as a logistics layer that packages up [GumJS][] into a shared library.
|
||||
- Provides a two-way communication channel for talking to your scripts,
|
||||
if needed, and later unload them.
|
||||
- Also lets you enumerate installed apps, running processes, and connected
|
||||
devices.
|
||||
- Written in [Vala][], with OS-specific glue code in C/Objective-C/asm.
|
||||
|
||||
## Binaries
|
||||
|
||||
@@ -32,43 +29,8 @@ $ pip install frida # Python bindings
|
||||
$ npm install frida # Node.js bindings
|
||||
```
|
||||
|
||||
Or, for static linking into your own project written in a
|
||||
C-compatible language, download a devkit from the Frida
|
||||
[releases][] page.
|
||||
|
||||
## Distro Packaging
|
||||
|
||||
For building a shared library suitable for distro packaging:
|
||||
|
||||
```console
|
||||
$ ./configure --enable-shared --without-prebuilds=sdk && make
|
||||
```
|
||||
|
||||
This builds `libfrida-core-1.0.so` against system dependencies,
|
||||
while `frida-agent.so` is built using Frida's SDK (with its GLib
|
||||
fork, needed for the agent's inject/unload lifecycle).
|
||||
|
||||
Prerequisites on Fedora:
|
||||
|
||||
```console
|
||||
$ sudo dnf install libgee-devel json-glib-devel \
|
||||
libsoup3-devel libunwind-devel libdwarf-devel \
|
||||
libnice-devel ngtcp2-crypto-ossl-devel
|
||||
```
|
||||
|
||||
Prerequisites on Ubuntu:
|
||||
|
||||
```console
|
||||
$ sudo apt install libgee-0.8-dev libjson-glib-dev \
|
||||
libsoup-3.0-dev libunwind-dev libdwarf-dev \
|
||||
libnice-dev libngtcp2-crypto-ossl-dev
|
||||
```
|
||||
|
||||
Prerequisites on macOS:
|
||||
|
||||
```console
|
||||
$ brew install libgee json-glib libsoup libnice capstone
|
||||
```
|
||||
Or, for static linking into your own project written in a C-compatible language,
|
||||
download a devkit from the Frida [releases][] page.
|
||||
|
||||
## Internals
|
||||
|
||||
|
||||
+73
-249
@@ -9,7 +9,6 @@ import os
|
||||
from pathlib import Path
|
||||
import pickle
|
||||
import platform
|
||||
import re
|
||||
import shlex
|
||||
import shutil
|
||||
import subprocess
|
||||
@@ -19,7 +18,7 @@ import traceback
|
||||
from typing import Any, Literal, Mapping, Optional, Sequence, Tuple
|
||||
|
||||
|
||||
REPO_ROOT = Path(__file__).absolute().parent.parent
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
NINJA = os.environ.get("NINJA", "ninja")
|
||||
|
||||
|
||||
@@ -36,7 +35,6 @@ def main(argv):
|
||||
command.add_argument("top_builddir", help="top build directory", type=Path)
|
||||
command.add_argument("frida_version", help="the Frida version")
|
||||
command.add_argument("host_os", help="operating system binaries are being built for")
|
||||
command.add_argument("host_os_family", help="operating system family, e.g. darwin")
|
||||
command.add_argument("host_arch", help="architecture binaries are being built for")
|
||||
command.add_argument("host_config", help="configuration binaries are being built for")
|
||||
command.add_argument("compat", help="support for targets with a different architecture",
|
||||
@@ -44,23 +42,17 @@ def main(argv):
|
||||
command.add_argument("assets", help="whether assets are embedded vs installed and loaded at runtime")
|
||||
command.add_argument("components", help="which components will be built",
|
||||
type=parse_array_option_value)
|
||||
command.add_argument("glib_flavor", help="upstream or frida", choices=["upstream", "frida"])
|
||||
command.add_argument("apple_tls", help="whether the parent build is using the Apple TLS backend",
|
||||
choices=["enabled", "disabled"])
|
||||
command.add_argument("compilers", help="compiler command arrays", nargs="+")
|
||||
command.set_defaults(func=lambda args: setup(args.role,
|
||||
args.builddir,
|
||||
args.top_builddir,
|
||||
args.frida_version,
|
||||
args.host_os,
|
||||
args.host_os_family,
|
||||
args.host_arch,
|
||||
args.host_config if args.host_config else None,
|
||||
args.compat,
|
||||
args.assets,
|
||||
args.components,
|
||||
args.glib_flavor,
|
||||
args.apple_tls,
|
||||
parse_compilers(args.compilers)))
|
||||
|
||||
command = subparsers.add_parser("compile", help="compile compatibility assets")
|
||||
@@ -121,14 +113,11 @@ def setup(role: Role,
|
||||
top_builddir: Path,
|
||||
frida_version: str,
|
||||
host_os: str,
|
||||
host_os_family: str,
|
||||
host_arch: str,
|
||||
host_config: Optional[str],
|
||||
compat: set[str],
|
||||
assets: str,
|
||||
components: set[str],
|
||||
glib_flavor: str,
|
||||
apple_tls: str,
|
||||
compilers: Compilers):
|
||||
try:
|
||||
outputs: Mapping[str, Sequence[Output]] = OrderedDict()
|
||||
@@ -160,20 +149,9 @@ def setup(role: Role,
|
||||
other_triplet: Optional[str] = None
|
||||
extra_environ: dict[str, str] = {}
|
||||
|
||||
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
|
||||
|
||||
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")
|
||||
elif host_os == "linux" and host_arch == "x86_64" and host_config is None:
|
||||
other_label = "x86"
|
||||
other_triplet = "i686-linux-gnu"
|
||||
@@ -201,26 +179,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 in {"x86_64", "x86"} and have_toolchain:
|
||||
group = OutputGroup(other_label, other_triplet, extra_environ)
|
||||
outputs[group] = []
|
||||
if "helper" in components:
|
||||
outputs[group] += [
|
||||
Output(identifier=f"helper_{other_kind}",
|
||||
name=HELPER_FILE_WINDOWS.name,
|
||||
file=HELPER_FILE_WINDOWS,
|
||||
target=HELPER_TARGET),
|
||||
]
|
||||
if "agent" in components:
|
||||
outputs[group] += [
|
||||
Output(identifier=f"agent_{other_kind}",
|
||||
name=AGENT_FILE_WINDOWS.name,
|
||||
file=AGENT_FILE_WINDOWS,
|
||||
target=AGENT_TARGET),
|
||||
]
|
||||
if host_os == "windows" and host_arch == "x86_64" and have_toolchain:
|
||||
group = OutputGroup("x86", other_triplet, extra_environ)
|
||||
outputs[group] = [
|
||||
Output(identifier="helper_legacy",
|
||||
name=HELPER_FILE_WINDOWS.name,
|
||||
file=HELPER_FILE_WINDOWS,
|
||||
target=HELPER_TARGET),
|
||||
Output(identifier="agent_legacy",
|
||||
name=AGENT_FILE_WINDOWS.name,
|
||||
file=AGENT_FILE_WINDOWS,
|
||||
target=AGENT_TARGET),
|
||||
]
|
||||
if "gadget" in components:
|
||||
outputs[group] += [
|
||||
Output(identifier=f"gadget_{other_kind}",
|
||||
Output(identifier="gadget_legacy",
|
||||
name=GADGET_FILE_WINDOWS.name,
|
||||
file=GADGET_FILE_WINDOWS,
|
||||
target=GADGET_TARGET),
|
||||
@@ -234,21 +207,16 @@ def setup(role: Role,
|
||||
other_arch = "arm64e"
|
||||
kind = "modern"
|
||||
group = OutputGroup(other_arch)
|
||||
outputs[group] = []
|
||||
if "helper" in components:
|
||||
outputs[group] += [
|
||||
Output(identifier=f"helper_{kind}",
|
||||
name=f"frida-helper-{other_arch}",
|
||||
file=HELPER_FILE_UNIX,
|
||||
target=HELPER_TARGET),
|
||||
]
|
||||
if "agent" in components:
|
||||
outputs[group] += [
|
||||
Output(identifier=f"agent_{kind}",
|
||||
name=f"frida-agent-{other_arch}.dylib",
|
||||
file=AGENT_FILE_DARWIN,
|
||||
target=AGENT_TARGET),
|
||||
]
|
||||
outputs[group] = [
|
||||
Output(identifier=f"helper_{kind}",
|
||||
name=f"frida-helper-{other_arch}",
|
||||
file=HELPER_FILE_UNIX,
|
||||
target=HELPER_TARGET),
|
||||
Output(identifier=f"agent_{kind}",
|
||||
name=f"frida-agent-{other_arch}.dylib",
|
||||
file=AGENT_FILE_DARWIN,
|
||||
target=AGENT_TARGET),
|
||||
]
|
||||
if "gadget" in components:
|
||||
outputs[group] += [
|
||||
Output(identifier=f"gadget_{kind}",
|
||||
@@ -266,21 +234,16 @@ def setup(role: Role,
|
||||
|
||||
if host_os == "linux" and host_arch == "x86_64" and have_toolchain:
|
||||
group = OutputGroup("x86", other_triplet, extra_environ)
|
||||
outputs[group] = []
|
||||
if "helper" in components:
|
||||
outputs[group] += [
|
||||
Output(identifier="helper_legacy",
|
||||
name=HELPER_FILE_UNIX.name,
|
||||
file=HELPER_FILE_UNIX,
|
||||
target=HELPER_TARGET),
|
||||
]
|
||||
if "agent" in components:
|
||||
outputs[group] += [
|
||||
Output(identifier="agent_legacy",
|
||||
name=AGENT_FILE_ELF.name,
|
||||
file=AGENT_FILE_ELF,
|
||||
target=AGENT_TARGET),
|
||||
]
|
||||
outputs[group] = [
|
||||
Output(identifier="helper_legacy",
|
||||
name=HELPER_FILE_UNIX.name,
|
||||
file=HELPER_FILE_UNIX,
|
||||
target=HELPER_TARGET),
|
||||
Output(identifier="agent_legacy",
|
||||
name=AGENT_FILE_ELF.name,
|
||||
file=AGENT_FILE_ELF,
|
||||
target=AGENT_TARGET),
|
||||
]
|
||||
if "gadget" in components:
|
||||
outputs[group] += [
|
||||
Output(identifier="gadget_legacy",
|
||||
@@ -291,21 +254,16 @@ def setup(role: Role,
|
||||
|
||||
if host_os == "android" and host_arch in {"arm64", "x86_64"}:
|
||||
group = OutputGroup("arm" if host_arch == "arm64" else "x86")
|
||||
outputs[group] = []
|
||||
if "helper" in components:
|
||||
outputs[group] += [
|
||||
Output(identifier="helper_legacy",
|
||||
name=HELPER_FILE_UNIX.name,
|
||||
file=HELPER_FILE_UNIX,
|
||||
target=HELPER_TARGET),
|
||||
]
|
||||
if "agent" in components:
|
||||
outputs[group] += [
|
||||
Output(identifier="agent_legacy",
|
||||
name=AGENT_FILE_ELF.name,
|
||||
file=AGENT_FILE_ELF,
|
||||
target=AGENT_TARGET),
|
||||
]
|
||||
outputs[group] = [
|
||||
Output(identifier="helper_legacy",
|
||||
name=HELPER_FILE_UNIX.name,
|
||||
file=HELPER_FILE_UNIX,
|
||||
target=HELPER_TARGET),
|
||||
Output(identifier="agent_legacy",
|
||||
name=AGENT_FILE_ELF.name,
|
||||
file=AGENT_FILE_ELF,
|
||||
target=AGENT_TARGET),
|
||||
]
|
||||
if "gadget" in components:
|
||||
outputs[group] += [
|
||||
Output(identifier="gadget_legacy",
|
||||
@@ -326,24 +284,18 @@ def setup(role: Role,
|
||||
continue
|
||||
else:
|
||||
emulated_triplet = None
|
||||
group = OutputGroup(emulated_arch, emulated_triplet, extra_environ)
|
||||
outputs[group] = []
|
||||
if "helper" in components:
|
||||
outputs[group] += [
|
||||
Output(identifier=f"helper_emulated_{kind}",
|
||||
name=HELPER_FILE_WINDOWS.name.replace(".exe", f"-{emulated_arch}.exe"),
|
||||
file=HELPER_FILE_WINDOWS,
|
||||
target=HELPER_TARGET),
|
||||
]
|
||||
if "agent" in components:
|
||||
outputs[group] += [
|
||||
Output(identifier=f"agent_emulated_{kind}",
|
||||
name=AGENT_FILE_WINDOWS.name.replace(".dll", f"-{emulated_arch}.dll"),
|
||||
file=AGENT_FILE_WINDOWS,
|
||||
target=AGENT_TARGET),
|
||||
]
|
||||
outputs[OutputGroup(emulated_arch, emulated_triplet, extra_environ)] = [
|
||||
Output(identifier=f"helper_emulated_{kind}",
|
||||
name=HELPER_FILE_WINDOWS.name.replace(".exe", f"-{emulated_arch}.exe"),
|
||||
file=HELPER_FILE_WINDOWS,
|
||||
target=HELPER_TARGET),
|
||||
Output(identifier=f"agent_emulated_{kind}",
|
||||
name=AGENT_FILE_WINDOWS.name.replace(".dll", f"-{emulated_arch}.dll"),
|
||||
file=AGENT_FILE_WINDOWS,
|
||||
target=AGENT_TARGET),
|
||||
]
|
||||
|
||||
if host_os == "android" and host_arch in {"x86_64", "x86"} and "agent" in components:
|
||||
if host_os == "android" and host_arch in {"x86_64", "x86"}:
|
||||
outputs[OutputGroup("arm")] = [
|
||||
Output(identifier="agent_emulated_legacy",
|
||||
name="frida-agent-arm.so",
|
||||
@@ -358,46 +310,10 @@ def setup(role: Role,
|
||||
target=AGENT_TARGET),
|
||||
]
|
||||
|
||||
if glib_flavor == "upstream":
|
||||
kind = "modern" if arch_is_modern(host_os, host_arch) else "legacy"
|
||||
_, agent_file, gadget_file = native_file_paths(host_os)
|
||||
group = OutputGroup(host_arch)
|
||||
outputs[group] = []
|
||||
if "agent" in components:
|
||||
outputs[group] += [
|
||||
Output(identifier=f"agent_{kind}",
|
||||
name=arch_suffixed_name(agent_file.name, host_arch),
|
||||
file=agent_file,
|
||||
target=AGENT_TARGET),
|
||||
]
|
||||
if "gadget" in components:
|
||||
outputs[group] += [
|
||||
Output(identifier=f"gadget_{kind}",
|
||||
name=arch_suffixed_name(gadget_file.name, host_arch),
|
||||
file=gadget_file,
|
||||
target=GADGET_TARGET),
|
||||
]
|
||||
elif apple_tls == "enabled" and "agent" in components:
|
||||
kind = "modern" if arch_is_modern(host_os, host_arch) else "legacy"
|
||||
_, agent_file, _ = native_file_paths(host_os)
|
||||
group = OutputGroup(host_arch)
|
||||
outputs.setdefault(group, [])
|
||||
outputs[group] += [
|
||||
Output(identifier=f"agent_{kind}",
|
||||
name=arch_suffixed_name(agent_file.name, host_arch),
|
||||
file=agent_file,
|
||||
target=AGENT_TARGET),
|
||||
]
|
||||
|
||||
outputs = OrderedDict((g, items) for g, items in outputs.items() if items)
|
||||
|
||||
raw_allowed_prebuilds = os.environ.get("FRIDA_ALLOWED_PREBUILDS")
|
||||
if raw_allowed_prebuilds is not None:
|
||||
allowed_prebuilds = set(filter(None, raw_allowed_prebuilds.split(",")))
|
||||
else:
|
||||
allowed_prebuilds = None
|
||||
allowed_prebuilds = set(raw_allowed_prebuilds.split(",")) if raw_allowed_prebuilds is not None else None
|
||||
|
||||
state = State(role, builddir, top_builddir, frida_version, host_os, host_os_family, host_config, glib_flavor, apple_tls, allowed_prebuilds, outputs)
|
||||
state = State(role, builddir, top_builddir, frida_version, host_os, host_config, allowed_prebuilds, outputs)
|
||||
serialized_state = base64.b64encode(pickle.dumps(state)).decode('ascii')
|
||||
|
||||
if missing:
|
||||
@@ -433,10 +349,7 @@ class State:
|
||||
top_builddir: Path
|
||||
frida_version: str
|
||||
host_os: str
|
||||
host_os_family: str
|
||||
host_config: Optional[str]
|
||||
glib_flavor: str
|
||||
apple_tls: str
|
||||
allowed_prebuilds: Optional[set[str]]
|
||||
outputs: Mapping[OutputGroup, Sequence[Output]]
|
||||
|
||||
@@ -516,35 +429,20 @@ def compile(privdir: Path, state: State):
|
||||
|
||||
host_machine = MachineSpec(state.host_os, group.arch, state.host_config, group.triplet)
|
||||
|
||||
if state.glib_flavor == "upstream":
|
||||
allowed = None
|
||||
else:
|
||||
allowed = state.allowed_prebuilds
|
||||
|
||||
if state.glib_flavor == "upstream":
|
||||
forwarded_options = [o for o in options if not is_stripped_compat_option(o)]
|
||||
forwarded_options += ["-Ddefault_library=static"]
|
||||
else:
|
||||
forwarded_options = [o for o in options if not is_overridden_compat_option(o)]
|
||||
if state.apple_tls == "enabled":
|
||||
forwarded_options += ["-Dapple_tls=disabled"]
|
||||
|
||||
configure(sourcedir=REPO_ROOT,
|
||||
builddir=workdir,
|
||||
host_machine=host_machine,
|
||||
environ={**build_env, **group.extra_environ},
|
||||
allowed_prebuilds=allowed,
|
||||
apple_min_os=detect_parent_apple_min_os(top_builddir, state.host_os, state.host_os_family),
|
||||
allowed_prebuilds=state.allowed_prebuilds,
|
||||
extra_meson_options=[
|
||||
"-Dcompiler_backend=disabled",
|
||||
"-Dassets=installed",
|
||||
"-Dhelper_modern=",
|
||||
"-Dhelper_legacy=",
|
||||
"-Dagent_modern=",
|
||||
"-Dagent_legacy=",
|
||||
"-Dagent_emulated_modern=",
|
||||
"-Dagent_emulated_legacy=",
|
||||
*forwarded_options,
|
||||
*options,
|
||||
],
|
||||
call_meson=call_internal_meson,
|
||||
on_progress=lambda progress: None)
|
||||
@@ -575,27 +473,13 @@ def compile(privdir: Path, state: State):
|
||||
(state.builddir / DEPFILE_FILENAME).write_text("\n".join(depfile_lines), encoding="utf-8")
|
||||
|
||||
|
||||
def is_stripped_compat_option(o: str) -> bool:
|
||||
if is_overridden_compat_option(o):
|
||||
return True
|
||||
name = o.split("=", 1)[0].removeprefix("-D")
|
||||
return name in STRIPPED_COMPAT_OPTIONS or name.endswith(":default_library")
|
||||
|
||||
|
||||
def is_overridden_compat_option(o: str) -> bool:
|
||||
name = o.split("=", 1)[0].removeprefix("-D")
|
||||
return name in OVERRIDDEN_COMPAT_OPTIONS
|
||||
|
||||
|
||||
def load_meson_options(top_builddir: Path,
|
||||
role: Role,
|
||||
subprojects: set[str]) -> Sequence[str]:
|
||||
from mesonbuild import coredata
|
||||
|
||||
optstore = coredata.load(top_builddir).optstore
|
||||
|
||||
return [f"-D{adapt_key(k, role)}={v.value}" for k, v in optstore.options.items()
|
||||
if option_should_be_forwarded(k, v, optstore, role, subprojects)]
|
||||
return [f"-D{adapt_key(k, role)}={v.value}" for k, v in coredata.load(top_builddir).options.items()
|
||||
if option_should_be_forwarded(k, v, role, subprojects)]
|
||||
|
||||
|
||||
def adapt_key(k: "OptionKey", role: Role) -> "OptionKey":
|
||||
@@ -605,46 +489,40 @@ def adapt_key(k: "OptionKey", role: Role) -> "OptionKey":
|
||||
|
||||
|
||||
def option_should_be_forwarded(k: "OptionKey",
|
||||
v: "options.UserOption[Any]",
|
||||
optstore: "options.OptionStore",
|
||||
v: "coredata.UserOption[Any]",
|
||||
role: Role,
|
||||
subprojects: set[str]) -> bool:
|
||||
from mesonbuild import options
|
||||
from mesonbuild.mesonlib import MachineChoice
|
||||
from mesonbuild import coredata
|
||||
|
||||
our_project_id = "frida-core" if role == "subproject" else ""
|
||||
is_for_us = k.subproject == our_project_id
|
||||
is_for_child = k.subproject in subprojects
|
||||
|
||||
if optstore.is_project_option(k):
|
||||
if k.is_project():
|
||||
if is_for_us:
|
||||
if k.name == "compiler_backend":
|
||||
return False
|
||||
tokens = k.name.split("_")
|
||||
if tokens[0] in {"helper", "agent"} and tokens[-1] in {"modern", "legacy"}:
|
||||
return False
|
||||
if k.subproject and k.machine is not MachineChoice.HOST:
|
||||
if k.subproject and k.machine is not coredata.MachineChoice.HOST:
|
||||
return False
|
||||
return is_for_us or is_for_child
|
||||
|
||||
if optstore.is_per_machine_option(k):
|
||||
# The compat build generates its own machine files, so forwarding the
|
||||
# parent's build-machine options would inject a foreign toolchain. In a
|
||||
# native compat build that conjures a compiler-less build machine and
|
||||
# breaks any native: true target.
|
||||
return False
|
||||
if coredata.CoreData.is_per_machine_option(k):
|
||||
return k.machine is coredata.MachineChoice.BUILD
|
||||
|
||||
if optstore.is_builtin_option(k):
|
||||
if k.is_builtin():
|
||||
if k.name in {"buildtype", "genvslite"}:
|
||||
return False
|
||||
if not str(v.value):
|
||||
return False
|
||||
if not is_for_child and role == "subproject" and k.subproject in {"", our_project_id}:
|
||||
if not options.BUILTIN_OPTIONS[k.evolve(subproject=None, machine=MachineChoice.HOST)].yielding:
|
||||
if not coredata.BUILTIN_OPTIONS[k.as_root()].yielding:
|
||||
return k.subproject == our_project_id
|
||||
return True
|
||||
|
||||
if k.get_module_prefix() == "python":
|
||||
if k.module == "python":
|
||||
if k.name == "install_env" and v.value == "prefix":
|
||||
return False
|
||||
if not str(v.value):
|
||||
@@ -704,19 +582,6 @@ def ensure_submodules_checked_out(releng_location: Path):
|
||||
check=True)
|
||||
|
||||
|
||||
def detect_parent_apple_min_os(top_builddir: Path,
|
||||
host_os: str,
|
||||
host_os_family: str) -> Optional[Mapping[str, str]]:
|
||||
if host_os_family != "darwin":
|
||||
return None
|
||||
pattern = re.compile(r"-target['\"],\s*['\"][^-]+-apple-" + re.escape(host_os) + r"([0-9.]+)")
|
||||
for native_file in top_builddir.glob(f"frida-{host_os}-*.txt"):
|
||||
match = pattern.search(native_file.read_text(encoding="utf-8"))
|
||||
if match is not None:
|
||||
return {host_os: match.group(1)}
|
||||
return None
|
||||
|
||||
|
||||
def detect_relevant_subprojects(releng_location: Path) -> dict[str, Path]:
|
||||
subprojects = detect_relevant_subprojects_in(REPO_ROOT, releng_location)
|
||||
gum_location = subprojects.get("frida-gum")
|
||||
@@ -767,48 +632,9 @@ def detect_mingw_toolchain_for(arch: str) -> Tuple[bool, Optional[str]]:
|
||||
return (found, triplet)
|
||||
|
||||
|
||||
def arch_is_modern(host_os: str, host_arch: str) -> bool:
|
||||
if host_os in {"macos", "ios", "tvos"} and host_arch == "arm64":
|
||||
return host_arch == "arm64e"
|
||||
return host_arch in MODERN_ARCHS
|
||||
|
||||
|
||||
def native_file_paths(host_os: str) -> Tuple[Path, Path, Path]:
|
||||
if host_os == "windows":
|
||||
return (HELPER_FILE_WINDOWS, AGENT_FILE_WINDOWS, GADGET_FILE_WINDOWS)
|
||||
elif host_os in {"macos", "ios", "tvos"}:
|
||||
return (HELPER_FILE_UNIX, AGENT_FILE_DARWIN, GADGET_FILE_DARWIN)
|
||||
else:
|
||||
return (HELPER_FILE_UNIX, AGENT_FILE_ELF, GADGET_FILE_ELF)
|
||||
|
||||
|
||||
def arch_suffixed_name(name: str, arch: str) -> str:
|
||||
stem, _, ext = name.partition(".")
|
||||
if ext:
|
||||
return f"{stem}-{arch}.{ext}"
|
||||
return f"{stem}-{arch}"
|
||||
|
||||
|
||||
STATE_FILENAME = "state.dat"
|
||||
DEPFILE_FILENAME = "compat.deps"
|
||||
|
||||
STRIPPED_COMPAT_OPTIONS = {
|
||||
"default_library",
|
||||
"frida-gum:gumjs",
|
||||
"frida-gum:inspector",
|
||||
}
|
||||
|
||||
OVERRIDDEN_COMPAT_OPTIONS = {
|
||||
"compiler_backend",
|
||||
"assets",
|
||||
"helper_modern",
|
||||
"helper_legacy",
|
||||
"agent_modern",
|
||||
"agent_legacy",
|
||||
"agent_emulated_modern",
|
||||
"agent_emulated_legacy",
|
||||
}
|
||||
|
||||
HELPER_TARGET = "frida-helper"
|
||||
HELPER_FILE_WINDOWS = Path("src") / "frida-helper.exe"
|
||||
HELPER_FILE_UNIX = Path("src") / "frida-helper"
|
||||
@@ -833,8 +659,6 @@ MSVS_ENVVARS = {
|
||||
"LIB",
|
||||
}
|
||||
|
||||
MODERN_ARCHS = {"x86_64", "arm64", "arm64e", "mips64", "riscv64"}
|
||||
|
||||
MINGW_ARCHS = {
|
||||
"x86": "i686",
|
||||
"arm64": "aarch64",
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
src = sys.argv[1]
|
||||
install_subdir = sys.argv[2]
|
||||
install_name = sys.argv[3]
|
||||
|
||||
destdir_prefix = os.environ["MESON_INSTALL_DESTDIR_PREFIX"]
|
||||
dst_dir = os.path.join(destdir_prefix, install_subdir)
|
||||
dst = os.path.join(dst_dir, install_name)
|
||||
|
||||
os.makedirs(dst_dir, exist_ok=True)
|
||||
shutil.copy2(src, dst)
|
||||
print(f"Installing {os.path.basename(src)} to {dst_dir}/{install_name}")
|
||||
+3
-47
@@ -8,7 +8,6 @@ helper_depends = []
|
||||
agent_modern = get_option('agent_modern')
|
||||
agent_legacy = get_option('agent_legacy')
|
||||
agent_compat = ''
|
||||
agent_host_compat = ''
|
||||
agent_emulated_modern = get_option('agent_emulated_modern')
|
||||
agent_emulated_legacy = get_option('agent_emulated_legacy')
|
||||
agent_depends = []
|
||||
@@ -29,9 +28,6 @@ if no_overridden_compat_bits
|
||||
build_py = [python, files('build.py')]
|
||||
|
||||
components = []
|
||||
if have_local_backend
|
||||
components += ['helper', 'agent']
|
||||
endif
|
||||
if build_gadget
|
||||
components += 'gadget'
|
||||
endif
|
||||
@@ -46,14 +42,11 @@ if no_overridden_compat_bits
|
||||
meson.global_build_root(),
|
||||
frida_version,
|
||||
host_os,
|
||||
host_os_family,
|
||||
host_abi,
|
||||
host_config,
|
||||
','.join(get_option('compat')),
|
||||
assets_mode,
|
||||
get_option('assets'),
|
||||
','.join(components),
|
||||
have_shared_glib ? 'upstream' : 'frida',
|
||||
use_apple_tls ? 'enabled' : 'disabled',
|
||||
'--',
|
||||
'>>>', cc.cmd_array(), '<<<',
|
||||
'>>>', cpp.cmd_array(), '<<<',
|
||||
@@ -71,27 +64,18 @@ if no_overridden_compat_bits
|
||||
depfile = lines[4]
|
||||
state = lines[5]
|
||||
|
||||
native_arch_suffix = '-' + host_abi
|
||||
|
||||
if host_os_family == 'darwin'
|
||||
install = false
|
||||
install_dir = asset_dir
|
||||
else
|
||||
install = true
|
||||
install_dir = []
|
||||
i = 0
|
||||
foreach varname : varnames
|
||||
output_name = outputs[i]
|
||||
needs_rename = output_name.contains(native_arch_suffix) or varname.contains('_emulated_')
|
||||
should_install = varname != 'arch_support_bundle' \
|
||||
and not needs_rename \
|
||||
and (assets_mode == 'installed' or varname.startswith('gadget_'))
|
||||
if should_install
|
||||
if varname != 'arch_support_bundle' and (get_option('assets') == 'installed' or varname.startswith('gadget_'))
|
||||
install_dir += varname.endswith('_modern') ? asset_dir_modern : asset_dir_legacy
|
||||
else
|
||||
install_dir += false
|
||||
endif
|
||||
i += 1
|
||||
endforeach
|
||||
endif
|
||||
|
||||
@@ -112,7 +96,6 @@ if no_overridden_compat_bits
|
||||
foreach output : arch_support.to_list()
|
||||
outpath = output.full_path()
|
||||
varname = varnames[i]
|
||||
output_name = outputs[i]
|
||||
|
||||
set_variable(varname, outpath)
|
||||
|
||||
@@ -120,11 +103,7 @@ if no_overridden_compat_bits
|
||||
helper_compat = outpath
|
||||
helper_depends += arch_support
|
||||
elif varname.startswith('agent_')
|
||||
if output_name.contains('-' + host_abi + '.')
|
||||
agent_host_compat = outpath
|
||||
else
|
||||
agent_compat = outpath
|
||||
endif
|
||||
agent_compat = outpath
|
||||
agent_depends += arch_support
|
||||
elif varname.startswith('gadget_')
|
||||
gadget_compat = outpath
|
||||
@@ -136,29 +115,6 @@ if no_overridden_compat_bits
|
||||
assert(false, f'unexpected variable name: @varname@')
|
||||
endif
|
||||
|
||||
if host_os_family != 'darwin'
|
||||
rename_target_dir = ''
|
||||
if output_name.contains(native_arch_suffix)
|
||||
rename_target_dir = asset_dir
|
||||
elif varname.contains('_emulated_')
|
||||
emulated_arch = output_name.split('-')[-1].split('.')[0]
|
||||
rename_target_dir = root_asset_dir / emulated_arch
|
||||
endif
|
||||
if rename_target_dir != ''
|
||||
install_name = output_name.replace(native_arch_suffix, '')
|
||||
foreach arch_suffix : ['-x86_64', '-x86', '-arm64', '-arm']
|
||||
install_name = install_name.replace(arch_suffix, '')
|
||||
endforeach
|
||||
if assets_mode == 'installed' or varname.startswith('gadget_')
|
||||
meson.add_install_script(python, files('install-renamed.py'),
|
||||
outpath,
|
||||
rename_target_dir,
|
||||
install_name,
|
||||
)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
i += 1
|
||||
endforeach
|
||||
else
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#!/bin/sh
|
||||
|
||||
[ -z "$PYTHON" ] && PYTHON=$(command -v python3 >/dev/null && echo python3 || echo python)
|
||||
[ -z "$PYTHON" ] && PYTHON=$(which python3 >/dev/null && echo python3 || echo python)
|
||||
|
||||
cd $(dirname $0)
|
||||
|
||||
srcroot=$(pwd)
|
||||
|
||||
if [ ! -f releng/meson/meson.py ] || git submodule status 2>/dev/null | grep -q '^-'; then
|
||||
if [ ! -f releng/meson/meson.py ]; then
|
||||
git submodule update --init --recursive --depth 1 || exit $?
|
||||
fi
|
||||
|
||||
|
||||
File renamed without changes.
File renamed without changes.
+15
-2
@@ -4,14 +4,27 @@ inject_sources = [
|
||||
]
|
||||
|
||||
system_vala_args = []
|
||||
|
||||
if host_os_family != 'windows'
|
||||
system_vala_args += ['--pkg=posix']
|
||||
endif
|
||||
|
||||
extra_link_args = []
|
||||
extra_link_depends = []
|
||||
if host_os_family == 'darwin'
|
||||
symlist = 'frida-inject.symbols'
|
||||
extra_link_args += ['-Wl,-exported_symbols_list,' + meson.current_source_dir() / symlist]
|
||||
extra_link_depends += [symlist]
|
||||
elif host_os_family != 'windows'
|
||||
symscript = 'frida-inject.version'
|
||||
extra_link_args += ['-Wl,--version-script,' + meson.current_source_dir() / symscript]
|
||||
extra_link_depends += [symscript]
|
||||
endif
|
||||
|
||||
raw_inject = executable('frida-inject-raw', inject_sources,
|
||||
vala_args: [core_vala_args, system_vala_args],
|
||||
link_args: executable_no_exports_link_args,
|
||||
link_depends: executable_no_exports_link_depends,
|
||||
link_args: extra_link_args,
|
||||
link_depends: extra_link_depends,
|
||||
dependencies: [json_glib_dep, core_dep],
|
||||
)
|
||||
|
||||
|
||||
+2
-46
@@ -9,48 +9,8 @@
|
||||
# include <signal.h>
|
||||
# endif
|
||||
#endif
|
||||
#if defined (HAVE_GIOAPPLE)
|
||||
# include <gioapple.h>
|
||||
#elif defined (HAVE_GIOOPENSSL)
|
||||
#ifdef HAVE_GIOOPENSSL
|
||||
# include <gioopenssl.h>
|
||||
#endif
|
||||
#ifdef HAVE_PROSPERO
|
||||
# include "frida-prospero.h"
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PROSPERO
|
||||
|
||||
FridaProsperoAgentArgs frida_prospero_agent_args = { .fifo_fd = -1 };
|
||||
|
||||
int
|
||||
main (int argc, char * argv[], char * envp[])
|
||||
{
|
||||
FridaProsperoAgentArgs * args = &frida_prospero_agent_args;
|
||||
FridaProsperoInjectorState injector_state;
|
||||
guint8 hello_byte = FRIDA_PROSPERO_HELLO_BYTE;
|
||||
FridaUnloadPolicy unload_policy = FRIDA_UNLOAD_POLICY_IMMEDIATE;
|
||||
guint8 policy_byte;
|
||||
guint32 worker_id;
|
||||
|
||||
injector_state.fifo_fd = args->fifo_fd;
|
||||
injector_state.agent_ctrlfd = args->agent_ctrlfd;
|
||||
injector_state.mapped_range = &args->mapped_range;
|
||||
|
||||
write (injector_state.fifo_fd, &hello_byte, sizeof (hello_byte));
|
||||
|
||||
frida_agent_main (GSIZE_TO_POINTER (args->agent_parameters), &unload_policy, &injector_state);
|
||||
|
||||
policy_byte = unload_policy;
|
||||
worker_id = gum_process_get_current_thread_id ();
|
||||
|
||||
write (injector_state.fifo_fd, &policy_byte, sizeof (policy_byte));
|
||||
write (injector_state.fifo_fd, &worker_id, sizeof (worker_id));
|
||||
close (injector_state.fifo_fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
@@ -71,9 +31,7 @@ _frida_agent_environment_init (void)
|
||||
|
||||
g_thread_set_garbage_handler (_frida_agent_on_pending_thread_garbage, NULL);
|
||||
|
||||
#if defined (HAVE_GIOAPPLE)
|
||||
g_io_module_apple_register ();
|
||||
#elif defined (HAVE_GIOOPENSSL)
|
||||
#ifdef HAVE_GIOOPENSSL
|
||||
g_io_module_openssl_register ();
|
||||
#endif
|
||||
|
||||
@@ -93,8 +51,6 @@ void
|
||||
_frida_agent_environment_deinit (void)
|
||||
{
|
||||
#ifndef HAVE_MUSL
|
||||
frida_libc_shim_prepare_to_deinit ();
|
||||
|
||||
gum_shutdown ();
|
||||
gio_shutdown ();
|
||||
glib_shutdown ();
|
||||
|
||||
+45
-443
@@ -1,5 +1,3 @@
|
||||
using Efni;
|
||||
|
||||
namespace Frida.Agent {
|
||||
public void main (string agent_parameters, ref Frida.UnloadPolicy unload_policy, void * injector_state) {
|
||||
if (Runner.shared_instance == null)
|
||||
@@ -80,7 +78,6 @@ namespace Frida.Agent {
|
||||
private ExitMonitor? exit_monitor;
|
||||
private Gum.Interceptor interceptor;
|
||||
private Gum.Exceptor? exceptor;
|
||||
private bool code_memory_delegated = false;
|
||||
|
||||
private uint child_gating_subscriber_count = 0;
|
||||
private ForkMonitor? fork_monitor;
|
||||
@@ -103,9 +100,6 @@ namespace Frida.Agent {
|
||||
private SpawnMonitor? spawn_monitor;
|
||||
private ThreadSuspendMonitor? thread_suspend_monitor;
|
||||
private UnwindSitter? unwind_sitter;
|
||||
#if ANDROID && (ARM || ARM64)
|
||||
private NativeCloakMirror? native_cloak_mirror;
|
||||
#endif
|
||||
|
||||
private delegate void CompletionNotify ();
|
||||
|
||||
@@ -123,48 +117,15 @@ namespace Frida.Agent {
|
||||
void * opaque_injector_state) {
|
||||
Environment._init ();
|
||||
|
||||
apply_linker_notifier_offsets (agent_parameters);
|
||||
|
||||
{
|
||||
Gum.MemoryRange? mapped_range = null;
|
||||
|
||||
#if WINDOWS
|
||||
var windows_state = (WindowsInjectorState *) opaque_injector_state;
|
||||
if (windows_state != null) {
|
||||
if (windows_state.mapped_range.size != 0)
|
||||
mapped_range = windows_state.mapped_range;
|
||||
Gum.Cloak.add_range (windows_state.worker_range);
|
||||
if (windows_state.dbghelp_range.size != 0) {
|
||||
Gum.Cloak.add_range (windows_state.dbghelp_range);
|
||||
Gum.Cloak.add_range (windows_state.symsrv_range);
|
||||
Gum.Windows.use_dbghelp_modules ((void *) windows_state.dbghelp_range.base_address,
|
||||
(void *) windows_state.symsrv_range.base_address);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DARWIN
|
||||
var injector_state = (DarwinInjectorState *) opaque_injector_state;
|
||||
if (injector_state != null)
|
||||
mapped_range = injector_state.mapped_range;
|
||||
#endif
|
||||
|
||||
#if LINUX
|
||||
var linux_state = (LinuxInjectorState *) opaque_injector_state;
|
||||
if (linux_state != null && linux_state.mapped_size != 0) {
|
||||
mapped_range = Gum.MemoryRange () {
|
||||
base_address = linux_state.mapped_base,
|
||||
size = linux_state.mapped_size,
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
#if PROSPERO
|
||||
var prospero_state = (ProsperoInjectorState *) opaque_injector_state;
|
||||
if (prospero_state != null)
|
||||
mapped_range = prospero_state.mapped_range;
|
||||
#endif
|
||||
|
||||
if (cached_agent_path == null) {
|
||||
cached_agent_range = detect_own_range_and_path (mapped_range, out cached_agent_path);
|
||||
Gum.Cloak.add_range (cached_agent_range);
|
||||
@@ -194,19 +155,6 @@ namespace Frida.Agent {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if PROSPERO
|
||||
string? agent_parameters_with_transport_uri = null;
|
||||
if (prospero_state != null) {
|
||||
int agent_ctrlfd = prospero_state.agent_ctrlfd;
|
||||
prospero_state.agent_ctrlfd = -1;
|
||||
|
||||
fdt_padder.move_descriptor_if_needed (ref agent_ctrlfd);
|
||||
|
||||
agent_parameters_with_transport_uri = "socket:%d%s".printf (agent_ctrlfd, agent_parameters);
|
||||
agent_parameters = agent_parameters_with_transport_uri;
|
||||
}
|
||||
#endif
|
||||
|
||||
var ignore_scope = new ThreadIgnoreScope (FRIDA_THREAD);
|
||||
|
||||
shared_instance = new Runner (agent_parameters, cached_agent_path, cached_agent_range);
|
||||
@@ -230,15 +178,6 @@ namespace Frida.Agent {
|
||||
return;
|
||||
} else {
|
||||
release_shared_instance ();
|
||||
#if WINDOWS
|
||||
if (windows_state != null) {
|
||||
Gum.Cloak.remove_range (windows_state.worker_range);
|
||||
if (windows_state.dbghelp_range.size != 0) {
|
||||
Gum.Cloak.remove_range (windows_state.dbghelp_range);
|
||||
Gum.Cloak.remove_range (windows_state.symsrv_range);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ignore_scope = null;
|
||||
@@ -247,25 +186,6 @@ namespace Frida.Agent {
|
||||
Environment._deinit ();
|
||||
}
|
||||
|
||||
private static void apply_linker_notifier_offsets (string agent_parameters) {
|
||||
foreach (unowned string token in agent_parameters.split ("|")) {
|
||||
if (!token.has_prefix ("linker-notifier-offsets:"))
|
||||
continue;
|
||||
|
||||
uint[] offsets = {};
|
||||
foreach (unowned string entry in token[24:].split (",")) {
|
||||
uint offset;
|
||||
if (uint.try_parse (entry, out offset))
|
||||
offsets += offset;
|
||||
}
|
||||
|
||||
if (offsets.length != 0)
|
||||
Gum.ModuleRegistry.set_rtld_notifier_offsets (offsets);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public static void resume_after_transition (ref Frida.UnloadPolicy unload_policy, void * opaque_injector_state) {
|
||||
{
|
||||
#if LINUX || FREEBSD
|
||||
@@ -325,12 +245,25 @@ namespace Frida.Agent {
|
||||
}
|
||||
|
||||
~Runner () {
|
||||
remove_instrumentation ();
|
||||
var interceptor = this.interceptor;
|
||||
interceptor.begin_transaction ();
|
||||
|
||||
if (code_memory_delegated)
|
||||
Gum.Memory.set_hooks (null);
|
||||
disable_child_gating ();
|
||||
|
||||
exceptor = null;
|
||||
|
||||
exit_monitor = null;
|
||||
|
||||
interceptor.end_transaction ();
|
||||
|
||||
interceptor.begin_transaction ();
|
||||
|
||||
thread_suspend_monitor = null;
|
||||
unwind_sitter = null;
|
||||
|
||||
invalidate_dbus_context ();
|
||||
|
||||
interceptor.end_transaction ();
|
||||
}
|
||||
|
||||
private void run (owned FileDescriptorTablePadder padder) throws Error {
|
||||
@@ -349,69 +282,58 @@ namespace Frida.Agent {
|
||||
private async void start (owned FileDescriptorTablePadder padder) {
|
||||
string[] tokens = agent_parameters.split ("|");
|
||||
unowned string transport_uri = tokens[0];
|
||||
var exceptor_mode = Gum.ExceptorMode.FULL;
|
||||
bool enable_unwind_broker = true;
|
||||
bool enable_exceptor = true;
|
||||
#if DARWIN
|
||||
enable_exceptor = !Gum.Darwin.query_hardened ();
|
||||
#endif
|
||||
bool enable_exit_monitor = true;
|
||||
bool enable_thread_suspend_monitor = true;
|
||||
#if ANDROID && (ARM || ARM64)
|
||||
bool in_emulated_realm = false;
|
||||
#endif
|
||||
bool enable_unwind_sitter = true;
|
||||
foreach (unowned string option in tokens[1:]) {
|
||||
if (option == "eternal")
|
||||
ensure_eternalized ();
|
||||
else if (option == "sticky")
|
||||
stop_thread_on_unload = false;
|
||||
else if (option == "exceptor:off")
|
||||
exceptor_mode = OFF;
|
||||
else if (option == "exceptor:handler-only")
|
||||
exceptor_mode = HANDLER_ONLY;
|
||||
else if (option == "unwind-broker:off")
|
||||
enable_unwind_broker = false;
|
||||
enable_exceptor = false;
|
||||
else if (option == "exit-monitor:off")
|
||||
enable_exit_monitor = false;
|
||||
else if (option == "thread-suspend-monitor:off")
|
||||
enable_thread_suspend_monitor = false;
|
||||
#if ANDROID && (ARM || ARM64)
|
||||
else if (option == "realm:emulated")
|
||||
in_emulated_realm = true;
|
||||
#endif
|
||||
else if (option == "unwind-sitter:off")
|
||||
enable_unwind_sitter = false;
|
||||
}
|
||||
|
||||
if (exceptor_mode != FULL)
|
||||
Gum.Exceptor.set_mode (exceptor_mode);
|
||||
if (!enable_exceptor)
|
||||
Gum.Exceptor.disable ();
|
||||
|
||||
interceptor = Gum.Interceptor.obtain ();
|
||||
{
|
||||
var interceptor = Gum.Interceptor.obtain ();
|
||||
interceptor.begin_transaction ();
|
||||
|
||||
if (enable_exit_monitor)
|
||||
exit_monitor = new ExitMonitor (this, main_context);
|
||||
|
||||
if (enable_thread_suspend_monitor)
|
||||
thread_suspend_monitor = new ThreadSuspendMonitor (this);
|
||||
|
||||
if (enable_unwind_sitter)
|
||||
unwind_sitter = new UnwindSitter (this);
|
||||
|
||||
this.interceptor = interceptor;
|
||||
this.exceptor = Gum.Exceptor.obtain ();
|
||||
|
||||
interceptor.end_transaction ();
|
||||
}
|
||||
|
||||
try {
|
||||
yield setup_connection_with_transport_uri (transport_uri);
|
||||
#if ANDROID && (ARM || ARM64)
|
||||
if (in_emulated_realm)
|
||||
yield connect_to_native_realm ();
|
||||
#endif
|
||||
} catch (Error e) {
|
||||
start_error = e;
|
||||
main_loop.quit ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!can_allocate_code ())
|
||||
delegate_code_memory_to_controller ();
|
||||
|
||||
interceptor.begin_transaction ();
|
||||
|
||||
if (enable_exit_monitor)
|
||||
exit_monitor = new ExitMonitor (this, main_context);
|
||||
|
||||
if (enable_thread_suspend_monitor)
|
||||
thread_suspend_monitor = new ThreadSuspendMonitor (this);
|
||||
|
||||
if (enable_unwind_broker)
|
||||
unwind_sitter = new UnwindSitter (this);
|
||||
|
||||
exceptor = Gum.Exceptor.obtain ();
|
||||
|
||||
interceptor.end_transaction ();
|
||||
|
||||
Gum.ScriptBackend.get_scheduler ().push_job_on_js_thread (Priority.DEFAULT, () => {
|
||||
schedule_idle (start.callback);
|
||||
});
|
||||
@@ -420,77 +342,6 @@ namespace Frida.Agent {
|
||||
padder = null;
|
||||
}
|
||||
|
||||
#if ANDROID && (ARM || ARM64)
|
||||
private async void connect_to_native_realm () throws Error {
|
||||
try {
|
||||
NativeCloak cloak = yield connection.get_proxy (null, ObjectPath.NATIVE_CLOAK, DO_NOT_LOAD_PROPERTIES,
|
||||
null);
|
||||
native_cloak_mirror = new NativeCloakMirror (cloak);
|
||||
native_cloak_mirror.activate ();
|
||||
|
||||
NativeThreadRegistry registry = yield connection.get_proxy (null, ObjectPath.NATIVE_THREAD_REGISTRY,
|
||||
DO_NOT_LOAD_PROPERTIES, null);
|
||||
Gum.ThreadRegistry.set_provider (new NativeThreadProvider (registry));
|
||||
} catch (GLib.Error e) {
|
||||
throw new Error.TRANSPORT ("%s", e.message);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private static bool can_allocate_code () {
|
||||
size_t page_size = Gum.query_page_size ();
|
||||
|
||||
void * page = Gum.Memory.allocate (null, page_size, page_size, READ | EXECUTE);
|
||||
if (page == null)
|
||||
return false;
|
||||
|
||||
Gum.Memory.free (page, page_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void delegate_code_memory_to_controller () {
|
||||
var hooks = Gum.MemoryHooks () {
|
||||
allocate = allocate_via_controller,
|
||||
protect = protect_via_controller,
|
||||
user_data = this,
|
||||
};
|
||||
Gum.Memory.set_hooks (hooks);
|
||||
|
||||
code_memory_delegated = true;
|
||||
}
|
||||
|
||||
private static void * allocate_via_controller (Gum.AddressSpec? spec, size_t size, size_t alignment,
|
||||
Gum.PageProtection prot, void * user_data) {
|
||||
unowned Runner self = (Runner) user_data;
|
||||
|
||||
uint64 near_address = 0;
|
||||
uint64 max_distance = 0;
|
||||
if (spec != null) {
|
||||
near_address = (uint64) spec.near_address;
|
||||
max_distance = spec.max_distance;
|
||||
}
|
||||
|
||||
try {
|
||||
return (void *) self.controller.allocate_memory (get_process_id (), near_address, max_distance, size,
|
||||
alignment, prot, null);
|
||||
} catch (GLib.Error e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool protect_via_controller (void * address, size_t size, Gum.PageProtection prot,
|
||||
void * user_data) {
|
||||
unowned Runner self = (Runner) user_data;
|
||||
|
||||
try {
|
||||
self.controller.protect_memory (get_process_id (), (uint64) address, size, prot, null);
|
||||
return true;
|
||||
} catch (GLib.Error e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void keep_running_eternalized () {
|
||||
agent_gthread = new Thread<bool> ("frida-eternal-agent", () => {
|
||||
var ignore_scope = new ThreadIgnoreScope (FRIDA_THREAD);
|
||||
@@ -1152,10 +1003,6 @@ namespace Frida.Agent {
|
||||
if (unloading)
|
||||
throw new Error.INVALID_OPERATION ("Agent is already unloading");
|
||||
unloading = true;
|
||||
|
||||
if (code_memory_delegated && !is_eternal)
|
||||
yield remove_instrumentation_while_delegated ();
|
||||
|
||||
perform_unload.begin ();
|
||||
}
|
||||
|
||||
@@ -1201,34 +1048,6 @@ namespace Frida.Agent {
|
||||
}
|
||||
}
|
||||
|
||||
private async void remove_instrumentation_while_delegated () {
|
||||
yield close_all_sessions ();
|
||||
|
||||
remove_instrumentation ();
|
||||
}
|
||||
|
||||
private void remove_instrumentation () {
|
||||
var interceptor = this.interceptor;
|
||||
interceptor.begin_transaction ();
|
||||
|
||||
disable_child_gating ();
|
||||
|
||||
exceptor = null;
|
||||
|
||||
exit_monitor = null;
|
||||
|
||||
interceptor.end_transaction ();
|
||||
|
||||
interceptor.begin_transaction ();
|
||||
|
||||
thread_suspend_monitor = null;
|
||||
unwind_sitter = null;
|
||||
|
||||
interceptor.end_transaction ();
|
||||
|
||||
Gum.shutdown ();
|
||||
}
|
||||
|
||||
private void ensure_eternalized () {
|
||||
if (!_is_eternal) {
|
||||
_is_eternal = true;
|
||||
@@ -1437,7 +1256,7 @@ namespace Frida.Agent {
|
||||
|
||||
private void on_connection_closed (DBusConnection connection, bool remote_peer_vanished, GLib.Error? error) {
|
||||
bool closed_by_us = !remote_peer_vanished && error == null;
|
||||
if (!closed_by_us && !code_memory_delegated)
|
||||
if (!closed_by_us)
|
||||
unload.begin (null);
|
||||
|
||||
Promise<bool> operation = null;
|
||||
@@ -1509,8 +1328,6 @@ namespace Frida.Agent {
|
||||
private Socket? emulated_socket;
|
||||
private BridgeState? emulated_bridge_state;
|
||||
private Thread<void>? emulated_worker;
|
||||
private NativeCloakService? native_cloak;
|
||||
private NativeThreadRegistryService? native_thread_registry;
|
||||
|
||||
private async AgentSessionProvider? try_get_emulated_provider (Cancellable? cancellable) throws IOError {
|
||||
if (get_emulated_request == null)
|
||||
@@ -1550,8 +1367,6 @@ namespace Frida.Agent {
|
||||
emulated_agent = nb_api.load_library_ext (emulated_agent_path, RTLD_LAZY, classloader_namespace);
|
||||
} else {
|
||||
emulated_agent = nb_api.load_library (emulated_agent_path, RTLD_LAZY);
|
||||
if (emulated_agent == null && nb_api.load_library_ext != null)
|
||||
emulated_agent = nb_api.load_library_ext (emulated_agent_path, RTLD_LAZY, null);
|
||||
}
|
||||
if (emulated_agent == null)
|
||||
throw new Error.NOT_SUPPORTED ("Process is not using emulation");
|
||||
@@ -1591,7 +1406,6 @@ namespace Frida.Agent {
|
||||
* code being discarded, which seems like an edge-case the translator doesn't handle.
|
||||
*/
|
||||
parameters.append ("|exceptor:off|exit-monitor:off");
|
||||
parameters.append ("|realm:emulated");
|
||||
|
||||
emulated_bridge_state = new BridgeState (parameters.str);
|
||||
|
||||
@@ -1600,13 +1414,6 @@ namespace Frida.Agent {
|
||||
var connection = yield new DBusConnection (stream, ServerGuid.HOST_SESSION_SERVICE,
|
||||
AUTHENTICATION_SERVER | AUTHENTICATION_ALLOW_ANONYMOUS, null, cancellable);
|
||||
|
||||
native_cloak = new NativeCloakService ();
|
||||
connection.register_object (ObjectPath.NATIVE_CLOAK, (NativeCloak) native_cloak);
|
||||
|
||||
native_thread_registry = new NativeThreadRegistryService ();
|
||||
connection.register_object (ObjectPath.NATIVE_THREAD_REGISTRY,
|
||||
(NativeThreadRegistry) native_thread_registry);
|
||||
|
||||
AgentSessionProvider provider = yield connection.get_proxy (null, ObjectPath.AGENT_SESSION_PROVIDER,
|
||||
DO_NOT_LOAD_PROPERTIES, cancellable);
|
||||
|
||||
@@ -1654,16 +1461,6 @@ namespace Frida.Agent {
|
||||
emulated_worker = null;
|
||||
}
|
||||
|
||||
if (native_thread_registry != null) {
|
||||
native_thread_registry.close ();
|
||||
native_thread_registry = null;
|
||||
}
|
||||
|
||||
if (native_cloak != null) {
|
||||
native_cloak.close ();
|
||||
native_cloak = null;
|
||||
}
|
||||
|
||||
emulated_socket = null;
|
||||
|
||||
if (emulated_agent != null) {
|
||||
@@ -1824,201 +1621,6 @@ namespace Frida.Agent {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ANDROID && (X86 || X86_64)
|
||||
private sealed class NativeCloakService : Object, NativeCloak, Gum.Cloak.Observer {
|
||||
private MainContext main_context = MainContext.ref_thread_default ();
|
||||
private bool observing = false;
|
||||
|
||||
public uint[] activate (Cancellable? cancellable) {
|
||||
Gum.Cloak.add_observer (this);
|
||||
observing = true;
|
||||
|
||||
uint[] threads = {};
|
||||
Gum.Cloak.enumerate_threads (id => {
|
||||
threads += (uint) id;
|
||||
return true;
|
||||
});
|
||||
return threads;
|
||||
}
|
||||
|
||||
public void close () {
|
||||
if (!observing)
|
||||
return;
|
||||
|
||||
Gum.Cloak.remove_observer (this);
|
||||
observing = false;
|
||||
}
|
||||
|
||||
public void thread_added (Gum.ThreadId id) {
|
||||
schedule (() => {
|
||||
thread_cloaked ((uint) id);
|
||||
return Source.REMOVE;
|
||||
});
|
||||
}
|
||||
|
||||
public void thread_removed (Gum.ThreadId id) {
|
||||
schedule (() => {
|
||||
thread_uncloaked ((uint) id);
|
||||
return Source.REMOVE;
|
||||
});
|
||||
}
|
||||
|
||||
private void schedule (owned SourceFunc function) {
|
||||
var source = new IdleSource ();
|
||||
source.set_callback ((owned) function);
|
||||
source.attach (main_context);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class NativeThreadRegistryService : Object, NativeThreadRegistry {
|
||||
private unowned Gum.ThreadRegistry? registry;
|
||||
private ulong added_handler = 0;
|
||||
private ulong removed_handler = 0;
|
||||
private ulong renamed_handler = 0;
|
||||
|
||||
public NativeThreadInfo[] activate (Cancellable? cancellable) {
|
||||
registry = Gum.ThreadRegistry.obtain ();
|
||||
|
||||
NativeThreadInfo[] threads = {};
|
||||
|
||||
registry.lock ();
|
||||
|
||||
added_handler = registry.thread_added.connect (on_thread_added);
|
||||
removed_handler = registry.thread_removed.connect (on_thread_removed);
|
||||
renamed_handler = registry.thread_renamed.connect (on_thread_renamed);
|
||||
|
||||
registry.enumerate_threads (thread => {
|
||||
threads += NativeThreadInfo ((uint) thread.id, thread.name ?? "");
|
||||
return true;
|
||||
});
|
||||
|
||||
registry.unlock ();
|
||||
|
||||
return threads;
|
||||
}
|
||||
|
||||
public void deactivate (Cancellable? cancellable) {
|
||||
close ();
|
||||
}
|
||||
|
||||
public void close () {
|
||||
if (registry == null)
|
||||
return;
|
||||
|
||||
registry.disconnect (added_handler);
|
||||
registry.disconnect (removed_handler);
|
||||
registry.disconnect (renamed_handler);
|
||||
registry = null;
|
||||
}
|
||||
|
||||
private void on_thread_added (Gum.ThreadDetails thread) {
|
||||
thread_added (NativeThreadInfo ((uint) thread.id, thread.name ?? ""));
|
||||
}
|
||||
|
||||
private void on_thread_removed (Gum.ThreadDetails thread) {
|
||||
thread_removed ((uint) thread.id);
|
||||
}
|
||||
|
||||
private void on_thread_renamed (Gum.ThreadDetails thread, string? previous_name) {
|
||||
thread_renamed ((uint) thread.id, thread.name ?? "");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ANDROID && (ARM || ARM64)
|
||||
private sealed class NativeCloakMirror : Object {
|
||||
public NativeCloak native_cloak {
|
||||
get;
|
||||
construct;
|
||||
}
|
||||
|
||||
public NativeCloakMirror (NativeCloak native_cloak) {
|
||||
Object (native_cloak: native_cloak);
|
||||
}
|
||||
|
||||
public void activate () throws GLib.Error {
|
||||
native_cloak.thread_cloaked.connect (on_thread_cloaked);
|
||||
native_cloak.thread_uncloaked.connect (on_thread_uncloaked);
|
||||
|
||||
foreach (uint id in native_cloak.activate (null))
|
||||
on_thread_cloaked (id);
|
||||
}
|
||||
|
||||
private void on_thread_cloaked (uint id) {
|
||||
if (!Gum.Cloak.has_thread (id))
|
||||
Gum.Cloak.add_thread (id);
|
||||
}
|
||||
|
||||
private void on_thread_uncloaked (uint id) {
|
||||
Gum.Cloak.remove_thread (id);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class NativeThreadProvider : Object, Gum.ThreadProvider {
|
||||
public NativeThreadRegistry native_registry {
|
||||
get;
|
||||
construct;
|
||||
}
|
||||
|
||||
private unowned Gum.ThreadRegistry registry;
|
||||
private ulong added_handler = 0;
|
||||
private ulong removed_handler = 0;
|
||||
private ulong renamed_handler = 0;
|
||||
|
||||
public NativeThreadProvider (NativeThreadRegistry native_registry) {
|
||||
Object (native_registry: native_registry);
|
||||
}
|
||||
|
||||
public void activate (Gum.ThreadRegistry registry) {
|
||||
this.registry = registry;
|
||||
|
||||
added_handler = native_registry.thread_added.connect (add_thread);
|
||||
removed_handler = native_registry.thread_removed.connect (on_thread_removed);
|
||||
renamed_handler = native_registry.thread_renamed.connect (on_thread_renamed);
|
||||
|
||||
NativeThreadInfo[] threads;
|
||||
try {
|
||||
threads = native_registry.activate (null);
|
||||
} catch (GLib.Error e) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var thread in threads)
|
||||
add_thread (thread);
|
||||
}
|
||||
|
||||
public void deactivate () {
|
||||
native_registry.disconnect (added_handler);
|
||||
native_registry.disconnect (removed_handler);
|
||||
native_registry.disconnect (renamed_handler);
|
||||
|
||||
try {
|
||||
native_registry.deactivate (null);
|
||||
} catch (GLib.Error e) {
|
||||
}
|
||||
}
|
||||
|
||||
private void add_thread (NativeThreadInfo thread) {
|
||||
var details = Gum.ThreadDetails ();
|
||||
details.id = thread.id;
|
||||
if (thread.name != "") {
|
||||
details.name = thread.name;
|
||||
details.flags = NAME;
|
||||
}
|
||||
|
||||
registry.register (details);
|
||||
}
|
||||
|
||||
private void on_thread_removed (uint id) {
|
||||
registry.unregister (id);
|
||||
}
|
||||
|
||||
private void on_thread_renamed (uint id, string name) {
|
||||
registry.rename (id, (name != "") ? name : null);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private sealed class LiveAgentSession : BaseAgentSession {
|
||||
public uint registration_id {
|
||||
get;
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
FRIDA_1.0 {
|
||||
global:
|
||||
frida_agent_main;
|
||||
|
||||
local:
|
||||
*;
|
||||
};
|
||||
|
||||
GLIBC_2.2.5 {
|
||||
local:
|
||||
fopen*;
|
||||
fseeko*;
|
||||
ftello*;
|
||||
} FRIDA_1.0;
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
global:
|
||||
frida_agent_main;
|
||||
frida_prospero_agent_args;
|
||||
|
||||
local:
|
||||
*;
|
||||
};
|
||||
+90
-124
@@ -1,132 +1,98 @@
|
||||
agent_sources = [
|
||||
'agent.vala',
|
||||
'agent-glue.c',
|
||||
]
|
||||
|
||||
force_cpp_linking = have_v8
|
||||
if force_cpp_linking
|
||||
agent_sources += ['dummy.cpp']
|
||||
endif
|
||||
|
||||
extra_vala_args = []
|
||||
extra_link_args = []
|
||||
extra_link_depends = []
|
||||
|
||||
if host_os_family != 'windows'
|
||||
extra_vala_args += '--pkg=posix'
|
||||
endif
|
||||
if host_os_family == 'darwin'
|
||||
extra_vala_args += '--pkg=frida-gum-darwin-1.0'
|
||||
endif
|
||||
|
||||
if host_os_family == 'windows'
|
||||
if host_toolchain != 'microsoft'
|
||||
symfile = (host_arch == 'x86') ? 'frida-agent-x86.symbols' : 'frida-agent.symbols'
|
||||
extra_link_args += '-Wl,--retain-symbols-file,' + meson.current_source_dir() / symfile
|
||||
extra_link_depends += symfile
|
||||
endif
|
||||
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'
|
||||
extra_link_args += '-Wl,--version-script,' + meson.current_source_dir() / symscript
|
||||
extra_link_depends += symscript
|
||||
endif
|
||||
|
||||
if host_os_family in ['linux', 'qnx']
|
||||
# For our libc shim to be effective.
|
||||
extra_link_args += '-Wl,-Bsymbolic'
|
||||
endif
|
||||
|
||||
raw_agent = shared_library('frida-agent-raw', agent_sources,
|
||||
name_prefix: 'lib',
|
||||
c_args: frida_component_cflags,
|
||||
vala_header: 'frida-agent.h',
|
||||
vala_args: [base_vala_args, payload_vala_args, extra_vala_args],
|
||||
link_args: extra_link_args,
|
||||
link_depends: extra_link_depends,
|
||||
vs_module_defs: 'frida-agent.def',
|
||||
override_options: ['b_asneeded=true'],
|
||||
dependencies: [gio_dep, gee_dep, gum_dep, gumjs_dep, base_dep, pipe_dep, tls_provider_dep, payload_dep],
|
||||
)
|
||||
|
||||
operations = ['--move', 'constructor', 'frida_libc_shim_init', 'first']
|
||||
if host_os_family != 'darwin'
|
||||
operations += ['--move', 'destructor', 'frida_libc_shim_deinit', 'first']
|
||||
endif
|
||||
modulated_agent = custom_target('frida-agent-modulated',
|
||||
input: raw_agent,
|
||||
output: 'libfrida-agent-modulated' + shlib_suffix,
|
||||
command: modulate + operations,
|
||||
)
|
||||
|
||||
need_universal_agent = host_os_family == 'darwin' \
|
||||
and assets_mode == 'installed' \
|
||||
and get_option('assets') == 'installed' \
|
||||
and agent_compat != ''
|
||||
|
||||
# When compat provides the host-arch agent (e.g. when use_apple_tls is on, so
|
||||
# the agent has to be built separately to avoid pulling in Apple frameworks),
|
||||
# skip building it here.
|
||||
build_agent = agent_host_compat == ''
|
||||
if host_os_family == 'darwin'
|
||||
identity = 'FridaAgent'
|
||||
else
|
||||
identity = agent_name
|
||||
endif
|
||||
agent = custom_target('frida-agent',
|
||||
input: modulated_agent,
|
||||
output: need_universal_agent ? f'@agent_name@-@host_abi@' : agent_name,
|
||||
command: post_process + ['shared-library', identity],
|
||||
build_by_default: true,
|
||||
install: get_option('assets') == 'installed' and not need_universal_agent,
|
||||
install_dir: asset_dir,
|
||||
)
|
||||
|
||||
if build_agent
|
||||
agent_sources = [
|
||||
'agent.vala',
|
||||
'agent-glue.c',
|
||||
]
|
||||
agent_dep = declare_dependency(link_with: agent)
|
||||
|
||||
force_cpp_linking = have_v8
|
||||
if force_cpp_linking
|
||||
agent_sources += ['dummy.cpp']
|
||||
endif
|
||||
|
||||
extra_vala_args = []
|
||||
extra_link_args = []
|
||||
extra_link_depends = []
|
||||
|
||||
if host_os_family != 'windows'
|
||||
extra_vala_args += '--pkg=posix'
|
||||
endif
|
||||
if host_os_family == 'windows'
|
||||
extra_vala_args += '--pkg=frida-gum-windows-1.0'
|
||||
endif
|
||||
if host_os_family == 'darwin'
|
||||
extra_vala_args += '--pkg=frida-gum-darwin-1.0'
|
||||
endif
|
||||
|
||||
if host_os_family == 'windows'
|
||||
if host_toolchain != 'microsoft'
|
||||
symfile = (host_arch == 'x86') ? 'frida-agent-x86.symbols' : 'frida-agent.symbols'
|
||||
extra_link_args += '-Wl,--retain-symbols-file,' + meson.current_source_dir() / symfile
|
||||
extra_link_depends += symfile
|
||||
endif
|
||||
elif host_os_family == 'darwin'
|
||||
extra_link_args += '-Wl,-exported_symbol,_frida_agent_main'
|
||||
else
|
||||
if libc == 'glibc'
|
||||
symscript = 'frida-agent-glibc.version'
|
||||
elif host_os == 'android'
|
||||
symscript = 'frida-agent-android.version'
|
||||
elif host_is_prospero
|
||||
symscript = 'frida-agent-prospero.version'
|
||||
else
|
||||
symscript = 'frida-agent.version'
|
||||
endif
|
||||
extra_link_args += '-Wl,--version-script,' + meson.current_source_dir() / symscript
|
||||
extra_link_depends += symscript
|
||||
endif
|
||||
|
||||
if host_os_family in ['linux', 'qnx']
|
||||
# For our libc shim to be effective.
|
||||
extra_link_args += '-Wl,-Bsymbolic'
|
||||
endif
|
||||
|
||||
extra_link_args += prospero_crt_link_args
|
||||
|
||||
raw_agent = shared_library('frida-agent-raw', agent_sources,
|
||||
name_prefix: 'lib',
|
||||
c_args: frida_component_cflags,
|
||||
vala_header: 'frida-agent.h',
|
||||
vala_args: [base_vala_args, payload_vala_args, extra_vala_args],
|
||||
link_args: extra_link_args,
|
||||
link_depends: extra_link_depends,
|
||||
vs_module_defs: 'frida-agent.def',
|
||||
override_options: ['b_asneeded=true'],
|
||||
dependencies: [gio_dep, gee_dep, gum_dep, gumjs_dep, base_dep, pipe_dep, tls_provider_dep, payload_dep],
|
||||
)
|
||||
|
||||
operations = ['--move', 'constructor', 'frida_libc_shim_init', 'first']
|
||||
if host_os_family != 'darwin'
|
||||
operations += ['--move', 'destructor', 'frida_libc_shim_deinit', 'first']
|
||||
endif
|
||||
modulated_agent = custom_target('frida-agent-modulated',
|
||||
input: raw_agent,
|
||||
output: 'libfrida-agent-modulated' + shlib_suffix,
|
||||
command: modulate + operations,
|
||||
)
|
||||
|
||||
if host_os_family == 'darwin'
|
||||
identity = 'FridaAgent'
|
||||
else
|
||||
identity = agent_name
|
||||
endif
|
||||
agent = custom_target('frida-agent',
|
||||
input: modulated_agent,
|
||||
output: need_universal_agent ? f'@agent_name@-@host_abi@' : agent_name,
|
||||
command: post_process + ['shared-library', identity],
|
||||
build_by_default: true,
|
||||
install: assets_mode == 'installed' and not need_universal_agent,
|
||||
if need_universal_agent
|
||||
custom_target('frida-agent-universal',
|
||||
input: agent,
|
||||
output: agent_name,
|
||||
command: [
|
||||
lipo,
|
||||
'@INPUT@',
|
||||
agent_compat,
|
||||
'-create',
|
||||
'-output', meson.current_build_dir() / agent_name,
|
||||
],
|
||||
depends: agent_depends,
|
||||
install: true,
|
||||
install_dir: asset_dir,
|
||||
)
|
||||
endif
|
||||
|
||||
if need_universal_agent
|
||||
if build_agent
|
||||
custom_target('frida-agent-universal',
|
||||
input: agent,
|
||||
output: agent_name,
|
||||
command: [
|
||||
lipo,
|
||||
'@INPUT@',
|
||||
agent_compat,
|
||||
'-create',
|
||||
'-output', meson.current_build_dir() / agent_name,
|
||||
],
|
||||
depends: agent_depends,
|
||||
install: true,
|
||||
install_dir: asset_dir,
|
||||
)
|
||||
else
|
||||
custom_target('frida-agent-universal',
|
||||
output: agent_name,
|
||||
command: [
|
||||
lipo,
|
||||
agent_host_compat,
|
||||
agent_compat,
|
||||
'-create',
|
||||
'-output', meson.current_build_dir() / agent_name,
|
||||
],
|
||||
depends: agent_depends,
|
||||
install: true,
|
||||
install_dir: asset_dir,
|
||||
)
|
||||
endif
|
||||
endif
|
||||
@@ -1,53 +0,0 @@
|
||||
namespace Frida {
|
||||
public class AssetLocation : Object {
|
||||
public string libdir {
|
||||
get;
|
||||
construct;
|
||||
}
|
||||
|
||||
public static AssetLocation detect () {
|
||||
string? module_path = null;
|
||||
Gum.Address our_address = Gum.Address.from_pointer (Gum.strip_code_pointer ((void *) detect));
|
||||
|
||||
Gum.Process.enumerate_modules ((details) => {
|
||||
var range = details.range;
|
||||
if (our_address >= range.base_address && our_address < range.base_address + range.size) {
|
||||
module_path = details.path;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
assert (module_path != null);
|
||||
|
||||
string libdir = Path.get_dirname (module_path);
|
||||
string basename = Path.get_basename (libdir).down ();
|
||||
if (basename == "bin" || basename == "sbin") {
|
||||
string parent = Path.get_dirname (libdir);
|
||||
string candidate = Path.build_filename (parent, Config.FRIDA_LIBDIR);
|
||||
if (FileUtils.test (candidate, IS_DIR))
|
||||
libdir = candidate;
|
||||
}
|
||||
|
||||
return new AssetLocation (libdir);
|
||||
}
|
||||
|
||||
private AssetLocation (string libdir) {
|
||||
Object (libdir: libdir);
|
||||
}
|
||||
|
||||
public string derive_asset_path (string arch, string filename) {
|
||||
string root = Path.build_filename (libdir, Config.FRIDA_LIBDIR_NAME);
|
||||
if (FileUtils.test (root, IS_DIR))
|
||||
#if DARWIN
|
||||
return Path.build_filename (root, filename);
|
||||
#else
|
||||
return Path.build_filename (root, arch, filename);
|
||||
#endif
|
||||
return Path.build_filename (libdir, filename);
|
||||
}
|
||||
|
||||
public string derive_plugin_path (string filename) {
|
||||
return Path.build_filename (libdir, Config.FRIDA_LIBDIR_NAME, "plugins", filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#include "frida-base.h"
|
||||
|
||||
GBytes *
|
||||
frida_make_bytes_with_owner (GType t_type,
|
||||
GBoxedCopyFunc t_dup_func,
|
||||
GDestroyNotify t_destroy_func,
|
||||
void * data,
|
||||
gsize size,
|
||||
gpointer owner)
|
||||
{
|
||||
return g_bytes_new_with_free_func (data, size, t_destroy_func, owner);
|
||||
}
|
||||
@@ -0,0 +1,662 @@
|
||||
namespace Frida {
|
||||
public sealed class BufferBuilder : Object {
|
||||
public ByteOrder byte_order {
|
||||
get;
|
||||
construct;
|
||||
}
|
||||
|
||||
public uint pointer_size {
|
||||
get;
|
||||
construct;
|
||||
}
|
||||
|
||||
public size_t offset {
|
||||
get {
|
||||
return cursor;
|
||||
}
|
||||
}
|
||||
|
||||
private ByteArray buffer = new ByteArray ();
|
||||
private size_t cursor = 0;
|
||||
|
||||
private uint64 base_address = 0;
|
||||
private Gee.List<LabelRef>? label_refs;
|
||||
private Gee.Map<string, uint>? label_defs;
|
||||
|
||||
public BufferBuilder (ByteOrder byte_order = HOST, uint pointer_size = (uint) sizeof (size_t)) {
|
||||
Object (
|
||||
byte_order: byte_order,
|
||||
pointer_size: pointer_size
|
||||
);
|
||||
}
|
||||
|
||||
public unowned BufferBuilder seek (size_t offset) {
|
||||
if (buffer.len < offset) {
|
||||
size_t n = offset - buffer.len;
|
||||
Memory.set (get_pointer (offset - n, n), 0, n);
|
||||
}
|
||||
cursor = offset;
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder skip (size_t n) {
|
||||
seek (cursor + n);
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder align (size_t n) {
|
||||
size_t remainder = cursor % n;
|
||||
if (remainder != 0)
|
||||
skip (n - remainder);
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder append_pointer (uint64 val) {
|
||||
write_pointer (cursor, val);
|
||||
cursor += pointer_size;
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder append_pointer_to_label (string name) {
|
||||
if (label_refs == null)
|
||||
label_refs = new Gee.ArrayList<LabelRef> ();
|
||||
label_refs.add (new LabelRef (name, cursor));
|
||||
return skip (pointer_size);
|
||||
}
|
||||
|
||||
public unowned BufferBuilder append_pointer_to_label_if (bool present, string name) {
|
||||
if (present)
|
||||
append_pointer_to_label (name);
|
||||
else
|
||||
append_pointer (0);
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder append_label (string name) throws Error {
|
||||
if (label_defs == null)
|
||||
label_defs = new Gee.HashMap<string, uint> ();
|
||||
if (label_defs.has_key (name))
|
||||
throw new Error.INVALID_ARGUMENT ("Label '%s' already exists", name);
|
||||
label_defs[name] = (uint) cursor;
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder append_size (uint64 val) {
|
||||
return append_pointer (val);
|
||||
}
|
||||
|
||||
public unowned BufferBuilder append_int8 (int8 val) {
|
||||
write_int8 (cursor, val);
|
||||
cursor += (uint) sizeof (int8);
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder append_uint8 (uint8 val) {
|
||||
write_uint8 (cursor, val);
|
||||
cursor += (uint) sizeof (uint8);
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder append_int16 (int16 val) {
|
||||
write_int16 (cursor, val);
|
||||
cursor += (uint) sizeof (int16);
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder append_uint16 (uint16 val) {
|
||||
write_uint16 (cursor, val);
|
||||
cursor += (uint) sizeof (uint16);
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder append_int32 (int32 val) {
|
||||
write_int32 (cursor, val);
|
||||
cursor += (uint) sizeof (int32);
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder append_uint32 (uint32 val) {
|
||||
write_uint32 (cursor, val);
|
||||
cursor += (uint) sizeof (uint32);
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder append_int64 (int64 val) {
|
||||
write_int64 (cursor, val);
|
||||
cursor += (uint) sizeof (int64);
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder append_uint64 (uint64 val) {
|
||||
write_uint64 (cursor, val);
|
||||
cursor += (uint) sizeof (uint64);
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder append_float (float val) {
|
||||
write_float (cursor, val);
|
||||
cursor += (uint) sizeof (float);
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder append_double (double val) {
|
||||
write_double (cursor, val);
|
||||
cursor += (uint) sizeof (double);
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder append_string (string val, StringTerminator terminator = NUL) {
|
||||
uint size = val.length;
|
||||
if (terminator == NUL)
|
||||
size++;
|
||||
Memory.copy (get_pointer (cursor, size), val, size);
|
||||
cursor += size;
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder append_bytes (Bytes bytes) {
|
||||
return append_data (bytes.get_data ());
|
||||
}
|
||||
|
||||
public unowned BufferBuilder append_data (uint8[] data) {
|
||||
write_data (cursor, data);
|
||||
cursor += data.length;
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder write_pointer (size_t offset, uint64 val) {
|
||||
if (pointer_size == 4)
|
||||
write_uint32 (offset, (uint32) val);
|
||||
else
|
||||
write_uint64 (offset, val);
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder write_size (size_t offset, uint64 val) {
|
||||
return write_pointer (offset, val);
|
||||
}
|
||||
|
||||
public unowned BufferBuilder write_int8 (size_t offset, int8 val) {
|
||||
*((int8 *) get_pointer (offset, sizeof (int8))) = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder write_uint8 (size_t offset, uint8 val) {
|
||||
*get_pointer (offset, sizeof (uint8)) = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder write_int16 (size_t offset, int16 val) {
|
||||
int16 target_val = (byte_order == BIG_ENDIAN)
|
||||
? val.to_big_endian ()
|
||||
: val.to_little_endian ();
|
||||
*((int16 *) get_pointer (offset, sizeof (int16))) = target_val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder write_uint16 (size_t offset, uint16 val) {
|
||||
uint16 target_val = (byte_order == BIG_ENDIAN)
|
||||
? val.to_big_endian ()
|
||||
: val.to_little_endian ();
|
||||
*((uint16 *) get_pointer (offset, sizeof (uint16))) = target_val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder write_int32 (size_t offset, int32 val) {
|
||||
int32 target_val = (byte_order == BIG_ENDIAN)
|
||||
? val.to_big_endian ()
|
||||
: val.to_little_endian ();
|
||||
*((int32 *) get_pointer (offset, sizeof (int32))) = target_val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder write_uint32 (size_t offset, uint32 val) {
|
||||
uint32 target_val = (byte_order == BIG_ENDIAN)
|
||||
? val.to_big_endian ()
|
||||
: val.to_little_endian ();
|
||||
*((uint32 *) get_pointer (offset, sizeof (uint32))) = target_val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder write_int64 (size_t offset, int64 val) {
|
||||
int64 target_val = (byte_order == BIG_ENDIAN)
|
||||
? val.to_big_endian ()
|
||||
: val.to_little_endian ();
|
||||
*((int64 *) get_pointer (offset, sizeof (int64))) = target_val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder write_uint64 (size_t offset, uint64 val) {
|
||||
uint64 target_val = (byte_order == BIG_ENDIAN)
|
||||
? val.to_big_endian ()
|
||||
: val.to_little_endian ();
|
||||
*((uint64 *) get_pointer (offset, sizeof (uint64))) = target_val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder write_float (size_t offset, float val) {
|
||||
return write_uint32 (offset, *((uint32 *) &val));
|
||||
}
|
||||
|
||||
public unowned BufferBuilder write_double (size_t offset, double val) {
|
||||
return write_uint64 (offset, *((uint64 *) &val));
|
||||
}
|
||||
|
||||
public unowned BufferBuilder write_string (size_t offset, string val) {
|
||||
uint size = val.length + 1;
|
||||
Memory.copy (get_pointer (offset, size), val, size);
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned BufferBuilder write_bytes (size_t offset, Bytes bytes) {
|
||||
return write_data (offset, bytes.get_data ());
|
||||
}
|
||||
|
||||
public unowned BufferBuilder write_data (size_t offset, uint8[] data) {
|
||||
Memory.copy (get_pointer (offset, data.length), data, data.length);
|
||||
return this;
|
||||
}
|
||||
|
||||
private uint8 * get_pointer (size_t offset, size_t n) {
|
||||
size_t minimum_size = offset + n;
|
||||
if (buffer.len < minimum_size)
|
||||
buffer.set_size ((uint) minimum_size);
|
||||
|
||||
return (uint8 *) buffer.data + offset;
|
||||
}
|
||||
|
||||
public Bytes try_build (uint64 base_address = 0) throws Error {
|
||||
this.base_address = base_address;
|
||||
|
||||
if (label_refs != null) {
|
||||
foreach (LabelRef r in label_refs)
|
||||
write_pointer (r.offset, address_of (r.name));
|
||||
}
|
||||
|
||||
return ByteArray.free_to_bytes ((owned) buffer);
|
||||
}
|
||||
|
||||
public Bytes build (uint64 base_address = 0) {
|
||||
try {
|
||||
return try_build (base_address);
|
||||
} catch (Error e) {
|
||||
assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
public uint64 address_of (string label) throws Error {
|
||||
if (label_defs == null || !label_defs.has_key (label))
|
||||
throw new Error.INVALID_OPERATION ("Label '%s' not defined", label);
|
||||
size_t offset = label_defs[label];
|
||||
return base_address + offset;
|
||||
}
|
||||
|
||||
private class LabelRef {
|
||||
public string name;
|
||||
public size_t offset;
|
||||
|
||||
public LabelRef (string name, size_t offset) {
|
||||
this.name = name;
|
||||
this.offset = offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum StringTerminator {
|
||||
NONE,
|
||||
NUL
|
||||
}
|
||||
|
||||
public sealed class Buffer : Object {
|
||||
public Bytes bytes {
|
||||
get;
|
||||
construct;
|
||||
}
|
||||
|
||||
public ByteOrder byte_order {
|
||||
get;
|
||||
construct;
|
||||
}
|
||||
|
||||
public uint pointer_size {
|
||||
get;
|
||||
construct;
|
||||
}
|
||||
|
||||
private unowned uint8 * data;
|
||||
private size_t size;
|
||||
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
construct {
|
||||
data = bytes.get_data ();
|
||||
size = bytes.get_size ();
|
||||
}
|
||||
|
||||
public uint64 read_pointer (size_t offset) {
|
||||
return (pointer_size == 4)
|
||||
? read_uint32 (offset)
|
||||
: read_uint64 (offset);
|
||||
}
|
||||
|
||||
public void write_pointer (size_t offset, uint64 val) {
|
||||
if (pointer_size == 4)
|
||||
write_uint32 (offset, (uint32) val);
|
||||
else
|
||||
write_uint64 (offset, val);
|
||||
}
|
||||
|
||||
public int8 read_int8 (size_t offset) {
|
||||
return *((int8 *) get_pointer (offset, sizeof (int8)));
|
||||
}
|
||||
|
||||
public unowned Buffer write_int8 (size_t offset, int8 val) {
|
||||
*((int8 *) get_pointer (offset, sizeof (int8))) = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public uint8 read_uint8 (size_t offset) {
|
||||
return *get_pointer (offset, sizeof (uint8));
|
||||
}
|
||||
|
||||
public unowned Buffer write_uint8 (size_t offset, uint8 val) {
|
||||
*((uint8 *) get_pointer (offset, sizeof (uint8))) = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int16 read_int16 (size_t offset) {
|
||||
int16 val = *((int16 *) get_pointer (offset, sizeof (int16)));
|
||||
return (byte_order == BIG_ENDIAN)
|
||||
? int16.from_big_endian (val)
|
||||
: int16.from_little_endian (val);
|
||||
}
|
||||
|
||||
public unowned Buffer write_int16 (size_t offset, int16 val) {
|
||||
int16 target_val = (byte_order == BIG_ENDIAN)
|
||||
? val.to_big_endian ()
|
||||
: val.to_little_endian ();
|
||||
*((int16 *) get_pointer (offset, sizeof (int16))) = target_val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public uint16 read_uint16 (size_t offset) {
|
||||
uint16 val = *((uint16 *) get_pointer (offset, sizeof (uint16)));
|
||||
return (byte_order == BIG_ENDIAN)
|
||||
? uint16.from_big_endian (val)
|
||||
: uint16.from_little_endian (val);
|
||||
}
|
||||
|
||||
public unowned Buffer write_uint16 (size_t offset, uint16 val) {
|
||||
uint16 target_val = (byte_order == BIG_ENDIAN)
|
||||
? val.to_big_endian ()
|
||||
: val.to_little_endian ();
|
||||
*((uint16 *) get_pointer (offset, sizeof (uint16))) = target_val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int32 read_int32 (size_t offset) {
|
||||
int32 val = *((int32 *) get_pointer (offset, sizeof (int32)));
|
||||
return (byte_order == BIG_ENDIAN)
|
||||
? int32.from_big_endian (val)
|
||||
: int32.from_little_endian (val);
|
||||
}
|
||||
|
||||
public unowned Buffer write_int32 (size_t offset, int32 val) {
|
||||
int32 target_val = (byte_order == BIG_ENDIAN)
|
||||
? val.to_big_endian ()
|
||||
: val.to_little_endian ();
|
||||
*((int32 *) get_pointer (offset, sizeof (int32))) = target_val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public uint32 read_uint32 (size_t offset) {
|
||||
uint32 val = *((uint32 *) get_pointer (offset, sizeof (uint32)));
|
||||
return (byte_order == BIG_ENDIAN)
|
||||
? uint32.from_big_endian (val)
|
||||
: uint32.from_little_endian (val);
|
||||
}
|
||||
|
||||
public unowned Buffer write_uint32 (size_t offset, uint32 val) {
|
||||
uint32 target_val = (byte_order == BIG_ENDIAN)
|
||||
? val.to_big_endian ()
|
||||
: val.to_little_endian ();
|
||||
*((uint32 *) get_pointer (offset, sizeof (uint32))) = target_val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int64 read_int64 (size_t offset) {
|
||||
int64 val = *((int64 *) get_pointer (offset, sizeof (int64)));
|
||||
return (byte_order == BIG_ENDIAN)
|
||||
? int64.from_big_endian (val)
|
||||
: int64.from_little_endian (val);
|
||||
}
|
||||
|
||||
public unowned Buffer write_int64 (size_t offset, int64 val) {
|
||||
int64 target_val = (byte_order == BIG_ENDIAN)
|
||||
? val.to_big_endian ()
|
||||
: val.to_little_endian ();
|
||||
*((int64 *) get_pointer (offset, sizeof (int64))) = target_val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public uint64 read_uint64 (size_t offset) {
|
||||
uint64 val = *((uint64 *) get_pointer (offset, sizeof (uint64)));
|
||||
return (byte_order == BIG_ENDIAN)
|
||||
? uint64.from_big_endian (val)
|
||||
: uint64.from_little_endian (val);
|
||||
}
|
||||
|
||||
public unowned Buffer write_uint64 (size_t offset, uint64 val) {
|
||||
uint64 target_val = (byte_order == BIG_ENDIAN)
|
||||
? val.to_big_endian ()
|
||||
: val.to_little_endian ();
|
||||
*((uint64 *) get_pointer (offset, sizeof (uint64))) = target_val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public float read_float (size_t offset) {
|
||||
uint32 bits = read_uint32 (offset);
|
||||
return *((float *) &bits);
|
||||
}
|
||||
|
||||
public double read_double (size_t offset) {
|
||||
uint64 bits = read_uint64 (offset);
|
||||
return *((double *) &bits);
|
||||
}
|
||||
|
||||
public string read_string (size_t offset) throws Error {
|
||||
string * start = (string *) get_pointer (offset, sizeof (char));
|
||||
size_t max_length = size - 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;
|
||||
}
|
||||
|
||||
[CCode (cname = "memchr", cheader_filename = "string.h")]
|
||||
private extern static string * memchr (string * s, int c, size_t n);
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
public unowned Buffer write_string (size_t offset, string val) {
|
||||
uint size = val.length + 1;
|
||||
Memory.copy (get_pointer (offset, size), val, size);
|
||||
return this;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public unowned Buffer write_bytes (size_t offset, Bytes bytes) {
|
||||
size_t size = bytes.get_size ();
|
||||
Memory.copy (get_pointer (offset, size), bytes.get_data (), size);
|
||||
return this;
|
||||
}
|
||||
|
||||
private uint8 * get_pointer (size_t offset, size_t n) {
|
||||
size_t minimum_size = offset + n;
|
||||
assert (size >= minimum_size);
|
||||
|
||||
return data + offset;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class BufferReader {
|
||||
public size_t offset {
|
||||
get {
|
||||
return _offset;
|
||||
}
|
||||
}
|
||||
|
||||
public size_t available {
|
||||
get {
|
||||
return buffer.bytes.get_size () - _offset;
|
||||
}
|
||||
}
|
||||
|
||||
private Buffer buffer;
|
||||
private size_t _offset = 0;
|
||||
|
||||
public BufferReader (Buffer buf) {
|
||||
buffer = buf;
|
||||
}
|
||||
|
||||
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 read_int8 () throws Error {
|
||||
check_available (sizeof (int8));
|
||||
var val = buffer.read_int8 (_offset);
|
||||
_offset += sizeof (int8);
|
||||
return val;
|
||||
}
|
||||
|
||||
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 skip (size_t n) throws Error {
|
||||
check_available (n);
|
||||
_offset += n;
|
||||
return this;
|
||||
}
|
||||
|
||||
private void check_available (size_t n) throws Error {
|
||||
if (available < n)
|
||||
throw new Error.PROTOCOL ("Malformed buffer: truncated");
|
||||
}
|
||||
}
|
||||
|
||||
public extern Bytes make_bytes_with_owner<T> (void * data, size_t size, owned T? owner = null);
|
||||
}
|
||||
+2
-14
@@ -1,13 +1,9 @@
|
||||
using Efni;
|
||||
|
||||
namespace Frida {
|
||||
public sealed class ChannelRegistry : Object {
|
||||
public signal void channel_closed (ChannelId id);
|
||||
|
||||
private Gee.Map<ChannelId?, weak IOStream> channels =
|
||||
new Gee.HashMap<ChannelId?, weak IOStream> (ChannelId.hash, ChannelId.equal);
|
||||
private Gee.Map<ChannelId?, IOStream> unlinked_channels =
|
||||
new Gee.HashMap<ChannelId?, IOStream> (ChannelId.hash, ChannelId.equal);
|
||||
|
||||
~ChannelRegistry () {
|
||||
clear ();
|
||||
@@ -20,33 +16,25 @@ namespace Frida {
|
||||
channel_stream.abandon ();
|
||||
}
|
||||
channels.clear ();
|
||||
unlinked_channels.clear ();
|
||||
}
|
||||
|
||||
public void register (ChannelId id, IOStream stream) {
|
||||
stream.set_data ("channel-registry-entry", new Entry (this, id));
|
||||
lock (channels) {
|
||||
lock (channels)
|
||||
channels[id] = stream;
|
||||
unlinked_channels[id] = stream;
|
||||
}
|
||||
}
|
||||
|
||||
public IOStream link (ChannelId id) throws Error {
|
||||
IOStream? stream;
|
||||
IOStream? unlinked_stream = null;
|
||||
lock (channels) {
|
||||
lock (channels)
|
||||
stream = channels[id];
|
||||
unlinked_channels.unset (id, out unlinked_stream);
|
||||
}
|
||||
if (stream == null)
|
||||
throw new Error.INVALID_ARGUMENT ("Invalid channel ID");
|
||||
return stream;
|
||||
}
|
||||
|
||||
public void unlink (ChannelId id) {
|
||||
IOStream? unlinked_stream = null;
|
||||
lock (channels) {
|
||||
unlinked_channels.unset (id, out unlinked_stream);
|
||||
if (!channels.unset (id))
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
using Efni;
|
||||
|
||||
namespace Frida {
|
||||
// We need to tease out GDBus' private MainContext as libnice needs to know the MainContext up front :(
|
||||
public async MainContext get_dbus_context () {
|
||||
|
||||
@@ -1,26 +1,18 @@
|
||||
#ifndef __FRIDA_ATOMICS_H__
|
||||
#define __FRIDA_ATOMICS_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
/* TODO: Add once needed. */
|
||||
|
||||
#else
|
||||
|
||||
typedef guint64 FridaAtomicU64 __attribute__ ((aligned (8)));
|
||||
|
||||
static inline guint64
|
||||
frida_atomics_load_u64_acquire (volatile FridaAtomicU64 * p)
|
||||
static inline guint64 frida_atomics_load_u64_acquire (volatile guint64 * p)
|
||||
{
|
||||
return __atomic_load_n (p, __ATOMIC_ACQUIRE);
|
||||
}
|
||||
|
||||
static inline void
|
||||
frida_atomics_store_u64_release (volatile FridaAtomicU64 * p, guint64 v)
|
||||
static inline void frida_atomics_store_u64_release (volatile guint64 * p, guint64 v)
|
||||
{
|
||||
__atomic_store_n (p, v, __ATOMIC_RELEASE);
|
||||
}
|
||||
@@ -32,6 +24,4 @@ static inline guint32 frida_atomics_load_u32_acquire (volatile guint32 * p)
|
||||
|
||||
#endif
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,6 @@
|
||||
[CCode (cheader_filename = "frida-atomics.h")]
|
||||
namespace Frida.Atomics {
|
||||
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);
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
#include "frida-darwin.h"
|
||||
|
||||
gpointer
|
||||
_frida_dispatch_retain (gpointer object)
|
||||
{
|
||||
dispatch_retain (object);
|
||||
return object;
|
||||
}
|
||||
|
||||
void
|
||||
_frida_xpc_connection_set_event_handler (xpc_connection_t connection, FridaXpcHandler handler, gpointer user_data)
|
||||
{
|
||||
xpc_connection_set_event_handler (connection, ^(xpc_object_t object)
|
||||
{
|
||||
handler (object, user_data);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
_frida_xpc_connection_send_message_with_reply (xpc_connection_t connection, xpc_object_t message, dispatch_queue_t replyq,
|
||||
FridaXpcHandler handler, gpointer user_data, GDestroyNotify notify)
|
||||
{
|
||||
xpc_connection_send_message_with_reply (connection, message, replyq, ^(xpc_object_t object)
|
||||
{
|
||||
handler (object, user_data);
|
||||
if (notify != NULL)
|
||||
notify (user_data);
|
||||
});
|
||||
}
|
||||
|
||||
gchar *
|
||||
_frida_xpc_object_to_string (xpc_object_t object)
|
||||
{
|
||||
gchar * result;
|
||||
char * str;
|
||||
|
||||
str = xpc_copy_description (object);
|
||||
result = g_strdup (str);
|
||||
free (str);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
gboolean
|
||||
_frida_xpc_dictionary_apply (xpc_object_t dict, FridaXpcDictionaryApplier applier, gpointer user_data)
|
||||
{
|
||||
return xpc_dictionary_apply (dict, ^bool (const char * key, xpc_object_t val)
|
||||
{
|
||||
return applier (key, val, user_data);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef __FRIDA_DARWIN_H__
|
||||
#define __FRIDA_DARWIN_H__
|
||||
|
||||
#ifdef HAVE_MACOS
|
||||
|
||||
#include <glib.h>
|
||||
#include <xpc/xpc.h>
|
||||
|
||||
typedef void (* FridaXpcHandler) (xpc_object_t object, gpointer user_data);
|
||||
typedef gboolean (* FridaXpcDictionaryApplier) (const gchar * key, xpc_object_t val, gpointer user_data);
|
||||
|
||||
gpointer _frida_dispatch_retain (gpointer object);
|
||||
|
||||
void _frida_xpc_connection_set_event_handler (xpc_connection_t connection, FridaXpcHandler handler, gpointer user_data);
|
||||
void _frida_xpc_connection_send_message_with_reply (xpc_connection_t connection, xpc_object_t message, dispatch_queue_t replyq,
|
||||
FridaXpcHandler handler, gpointer user_data, GDestroyNotify notify);
|
||||
gchar * _frida_xpc_object_to_string (xpc_object_t object);
|
||||
gboolean _frida_xpc_dictionary_apply (xpc_object_t dict, FridaXpcDictionaryApplier applier, gpointer user_data);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,41 +0,0 @@
|
||||
#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
|
||||
@@ -1,42 +0,0 @@
|
||||
#ifndef __FRIDA_PROSPERO_H__
|
||||
#define __FRIDA_PROSPERO_H__
|
||||
|
||||
#ifdef HAVE_PROSPERO
|
||||
|
||||
#include <gum/gum.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define FRIDA_PROSPERO_AGENT_ARGS_SYMBOL "frida_prospero_agent_args"
|
||||
#define FRIDA_PROSPERO_HELLO_BYTE 0xff
|
||||
|
||||
typedef struct _FridaProsperoAgentArgs FridaProsperoAgentArgs;
|
||||
|
||||
struct _FridaProsperoAgentArgs
|
||||
{
|
||||
GumAddress agent_parameters;
|
||||
gint fifo_fd;
|
||||
gint agent_ctrlfd;
|
||||
GumMemoryRange mapped_range;
|
||||
};
|
||||
|
||||
typedef struct _FridaProsperoAppLaunchContext FridaProsperoAppLaunchContext;
|
||||
|
||||
struct _FridaProsperoAppLaunchContext
|
||||
{
|
||||
guint32 size;
|
||||
guint32 user_id;
|
||||
guint32 app_opt;
|
||||
guint64 crash_report;
|
||||
guint32 check_flag;
|
||||
};
|
||||
|
||||
extern int sceUserServiceInitialize (void * params);
|
||||
extern int sceUserServiceGetForegroundUser (guint32 * user_id);
|
||||
extern int sceSystemServiceLaunchApp (const gchar * title_id, gchar ** argv, FridaProsperoAppLaunchContext * ctx);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,114 @@
|
||||
namespace Frida.FS {
|
||||
public void mkdirp (File dir, Cancellable? cancellable = null) throws Error {
|
||||
try {
|
||||
dir.make_directory_with_parents (cancellable);
|
||||
} catch (GLib.Error e) {
|
||||
if (!(e is IOError.EXISTS))
|
||||
throw new Error.PERMISSION_DENIED ("%s", e.message);
|
||||
}
|
||||
}
|
||||
|
||||
public void rmtree (File dir, Cancellable? cancellable = null) throws Error {
|
||||
rmtree_worker (dir, 0, cancellable);
|
||||
}
|
||||
|
||||
private void rmtree_worker (File dir, uint depth, Cancellable? cancellable = null) throws Error {
|
||||
FileEnumerator enumerator;
|
||||
try {
|
||||
enumerator = dir.enumerate_children (FileAttribute.STANDARD_NAME, NOFOLLOW_SYMLINKS, cancellable);
|
||||
} catch (GLib.Error e) {
|
||||
if (depth == 0 && e is IOError.NOT_FOUND)
|
||||
return;
|
||||
throw new Error.PERMISSION_DENIED ("%s", e.message);
|
||||
}
|
||||
|
||||
try {
|
||||
FileInfo? info;
|
||||
File? child;
|
||||
while (enumerator.iterate (out info, out child, cancellable) && info != null) {
|
||||
if (info == null)
|
||||
continue;
|
||||
if (info.get_file_type () == DIRECTORY)
|
||||
rmtree (child, cancellable);
|
||||
else
|
||||
child.delete (cancellable);
|
||||
}
|
||||
|
||||
dir.delete (cancellable);
|
||||
} catch (GLib.Error e) {
|
||||
if (!(e is IOError.EXISTS))
|
||||
throw new Error.PERMISSION_DENIED ("%s", e.message);
|
||||
}
|
||||
}
|
||||
|
||||
public async void rmtree_async (File dir, Cancellable? cancellable = null) throws Error, IOError {
|
||||
yield rmtree_async_worker (dir, 0, cancellable);
|
||||
}
|
||||
|
||||
private async void rmtree_async_worker (File dir, uint depth, Cancellable? cancellable = null) throws Error, IOError {
|
||||
int io_priority = Priority.DEFAULT;
|
||||
|
||||
FileEnumerator enumerator;
|
||||
try {
|
||||
enumerator = yield dir.enumerate_children_async (FileAttribute.STANDARD_NAME, NOFOLLOW_SYMLINKS, io_priority,
|
||||
cancellable);
|
||||
} catch (GLib.Error e) {
|
||||
if (depth == 0 && e is IOError.NOT_FOUND)
|
||||
return;
|
||||
throw new Error.PERMISSION_DENIED ("%s", e.message);
|
||||
}
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
var batch = yield enumerator.next_files_async (1000, io_priority, cancellable);
|
||||
if (batch.is_empty ())
|
||||
break;
|
||||
foreach (FileInfo info in batch) {
|
||||
File child = dir.get_child (info.get_name ());
|
||||
if (info.get_file_type () == DIRECTORY)
|
||||
yield rmtree_async_worker (child, depth + 1, cancellable);
|
||||
else
|
||||
yield child.delete_async (io_priority, cancellable);
|
||||
}
|
||||
}
|
||||
|
||||
yield dir.delete_async (io_priority, cancellable);
|
||||
} catch (GLib.Error e) {
|
||||
throw new Error.PERMISSION_DENIED ("%s", e.message);
|
||||
}
|
||||
}
|
||||
|
||||
public async string read_all_text (File f, Cancellable? cancellable) throws Error, IOError {
|
||||
Bytes b = yield read_all_bytes (f, cancellable);
|
||||
string text = (string) b.get_data ();
|
||||
if (!text.validate ())
|
||||
throw new Error.PROTOCOL ("Unable to read '%s': invalid UTF-8", f.get_parse_name ());
|
||||
return text;
|
||||
}
|
||||
|
||||
public async void write_all_text (File f, string t, Cancellable? cancellable) throws Error, IOError {
|
||||
yield write_all_bytes (f, new Bytes (t.data), cancellable);
|
||||
}
|
||||
|
||||
public async Bytes read_all_bytes (File f, Cancellable? cancellable) throws Error, IOError {
|
||||
try {
|
||||
return yield f.load_bytes_async (cancellable, null);
|
||||
} catch (GLib.Error e) {
|
||||
if (e is IOError.CANCELLED)
|
||||
throw (IOError) e;
|
||||
if (e is IOError.NOT_FOUND)
|
||||
throw new Error.INVALID_ARGUMENT ("%s", e.message);
|
||||
throw new Error.PERMISSION_DENIED ("%s", e.message);
|
||||
}
|
||||
}
|
||||
|
||||
public async void write_all_bytes (File f, Bytes b, Cancellable? cancellable) throws Error, IOError {
|
||||
try {
|
||||
yield f.replace_contents_bytes_async (b, null, false, FileCreateFlags.NONE, cancellable, null);
|
||||
} catch (GLib.Error e) {
|
||||
if (e is IOError.CANCELLED)
|
||||
throw (IOError) e;
|
||||
throw new Error.PERMISSION_DENIED ("%s", e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
-58
@@ -46,7 +46,7 @@ namespace Frida {
|
||||
public extern unowned LinuxSyscallSignature[]? get_compat32_syscall_signatures ();
|
||||
|
||||
public struct LinuxSyscallSignature {
|
||||
public int nr;
|
||||
public uint nr;
|
||||
public string name;
|
||||
public uint8 nargs;
|
||||
public LinuxSyscallArg args[6];
|
||||
@@ -123,21 +123,11 @@ namespace Frida {
|
||||
return fd;
|
||||
}
|
||||
|
||||
public static FileDescriptor with_size (string name, size_t size) {
|
||||
assert (is_supported ());
|
||||
|
||||
var fd = new FileDescriptor (memfd_create (name, 0));
|
||||
int res = Posix.ftruncate (fd.handle, (Posix.off_t) size);
|
||||
assert (res == 0);
|
||||
return fd;
|
||||
}
|
||||
|
||||
private int memfd_create (string name, uint flags) {
|
||||
return Linux.syscall (LinuxSyscall.MEMFD_CREATE, name, flags);
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_LOCAL_BACKEND
|
||||
public sealed class BpfObject {
|
||||
public Programs programs {
|
||||
get;
|
||||
@@ -148,35 +138,37 @@ namespace Frida {
|
||||
}
|
||||
|
||||
internal Libbpf.Object handle;
|
||||
private char[] kernel_log_buf;
|
||||
|
||||
public static BpfObject open (string name, uint8[] blob) throws Error {
|
||||
var log_buf = new char[64 * 1024];
|
||||
|
||||
var opts = Libbpf.Object.OpenOpts ();
|
||||
opts.sz = sizeof (Libbpf.Object.OpenOpts);
|
||||
opts.object_name = name;
|
||||
opts.kernel_log_buf = log_buf;
|
||||
|
||||
var log = new LibbpfLogScope ();
|
||||
var handle = Libbpf.Object.open_mem (blob, opts);
|
||||
if (handle == null)
|
||||
throw_libbpf_error (errno, log.take ());
|
||||
throw_libbpf_error (errno);
|
||||
|
||||
return new BpfObject ((owned) handle);
|
||||
return new BpfObject ((owned) handle, (owned) log_buf);
|
||||
}
|
||||
|
||||
private BpfObject (owned Libbpf.Object handle) {
|
||||
private BpfObject (owned Libbpf.Object handle, owned char[] kernel_log_buf) {
|
||||
this.handle = (owned) handle;
|
||||
this.kernel_log_buf = (owned) kernel_log_buf;
|
||||
|
||||
_programs = new Programs (this);
|
||||
_maps = new Maps (this);
|
||||
}
|
||||
|
||||
public void prepare () throws Error {
|
||||
var log = new LibbpfLogScope ();
|
||||
check_libbpf_result (handle.prepare (), log.take ());
|
||||
check_libbpf_result (handle.prepare ());
|
||||
}
|
||||
|
||||
public void load () throws Error {
|
||||
var log = new LibbpfLogScope ();
|
||||
check_libbpf_result (handle.load (), log.take ());
|
||||
check_libbpf_result (handle.load (), (string) kernel_log_buf);
|
||||
}
|
||||
|
||||
public sealed class Programs {
|
||||
@@ -356,18 +348,6 @@ 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);
|
||||
@@ -404,30 +384,6 @@ namespace Frida {
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class LibbpfLogScope {
|
||||
private static StringBuilder buffer;
|
||||
|
||||
public LibbpfLogScope () {
|
||||
if (buffer == null)
|
||||
buffer = new StringBuilder ();
|
||||
buffer.truncate ();
|
||||
Libbpf.set_print (on_message);
|
||||
}
|
||||
|
||||
~LibbpfLogScope () {
|
||||
Libbpf.set_print (null);
|
||||
}
|
||||
|
||||
public string take () {
|
||||
return buffer.str.chomp ();
|
||||
}
|
||||
|
||||
private static int on_message (Libbpf.PrintLevel level, string format, va_list args) {
|
||||
buffer.append_vprintf (format, args);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private int check_libbpf_result (int result, string details = "") throws Error {
|
||||
if (result < 0)
|
||||
throw_libbpf_error (result, details);
|
||||
@@ -554,7 +510,6 @@ namespace Frida {
|
||||
STOP,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace PerfEvent {
|
||||
public FileDescriptor open (PerfEventAttr * attr, int pid, int cpu, int group_fd, uint flags) throws Error {
|
||||
@@ -569,9 +524,7 @@ namespace Frida {
|
||||
throw new Error.NOT_SUPPORTED ("%s (errno=%d: %s)".printf (message, Posix.errno, Posix.strerror (Posix.errno)));
|
||||
}
|
||||
|
||||
#if HAVE_LOCAL_BACKEND
|
||||
private size_t round_up_8 (size_t x) {
|
||||
return (x + 7) & ~((size_t) 7);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
+28
-21
@@ -1,29 +1,38 @@
|
||||
base_sources = [
|
||||
'asset-location.vala',
|
||||
'promise.vala',
|
||||
'session.vala',
|
||||
'session-glue.c',
|
||||
'channel.vala',
|
||||
'service.vala',
|
||||
'stream.vala',
|
||||
'rpc.vala',
|
||||
'p2p.vala',
|
||||
'p2p-glue.c',
|
||||
'dbus.vala',
|
||||
'promise.vala',
|
||||
'fs.vala',
|
||||
'socket.vala',
|
||||
'socket-glue.c',
|
||||
'xnu-syscalls' / 'xnu-syscalls.vala',
|
||||
'xnu-syscalls' / 'xnu-syscalls-glue.c',
|
||||
'buffer.vala',
|
||||
'buffer-glue.c',
|
||||
'value.vala',
|
||||
]
|
||||
|
||||
extra_vala_args = []
|
||||
|
||||
if host_os == 'windows'
|
||||
base_sources += ['windows.vala', 'windows-glue.c']
|
||||
base_sources += 'windows.vala'
|
||||
else
|
||||
base_sources += 'posix.vala'
|
||||
extra_vala_args += '--pkg=posix'
|
||||
endif
|
||||
|
||||
if host_os == 'macos'
|
||||
base_sources += [
|
||||
'xpc.vala',
|
||||
'frida-darwin.c',
|
||||
]
|
||||
endif
|
||||
|
||||
if host_os_family == 'darwin'
|
||||
base_sources += 'corefoundation.vala'
|
||||
extra_vala_args += '--pkg=darwin-xnu'
|
||||
@@ -36,10 +45,8 @@ if host_os_family == 'linux'
|
||||
extra_vala_args += [
|
||||
'--pkg=linux',
|
||||
'--pkg=frida-atomics',
|
||||
'--pkg=libbpf',
|
||||
]
|
||||
if have_local_backend
|
||||
extra_vala_args += '--pkg=libbpf'
|
||||
endif
|
||||
|
||||
syscall_arch_from_abi = {
|
||||
'armbe': 'arm',
|
||||
@@ -66,7 +73,7 @@ extra_deps = []
|
||||
if host_os_family != 'windows'
|
||||
extra_deps += gio_unix_dep
|
||||
endif
|
||||
if host_os_family == 'linux' and have_local_backend
|
||||
if host_os_family == 'linux'
|
||||
extra_deps += libbpf_dep
|
||||
endif
|
||||
|
||||
@@ -82,6 +89,8 @@ endif
|
||||
if host_os_family == 'darwin'
|
||||
base_vala_args += [
|
||||
'--pkg=corefoundation',
|
||||
'--pkg=darwin-gcd',
|
||||
'--pkg=darwin-xpc',
|
||||
]
|
||||
endif
|
||||
if host_os_family == 'linux'
|
||||
@@ -100,25 +109,23 @@ base = static_library('frida-base-' + api_version, base_sources,
|
||||
vala_header: 'frida-base.h',
|
||||
vala_gir: base_gir_name,
|
||||
vala_vapi: f'frida-base-@[email protected]',
|
||||
dependencies: [glib_dep, gobject_dep, gio_dep, libsoup_dep, nice_dep, usrsctp_dep, gee_dep, json_glib_dep, gum_dep, openssl_dep, efni_dep] + extra_deps,
|
||||
install: have_in_tree_payloads,
|
||||
dependencies: [glib_dep, gobject_dep, gio_dep, libsoup_dep, nice_dep, usrsctp_dep, gee_dep, json_glib_dep, gum_dep, openssl_dep] + extra_deps,
|
||||
install: true,
|
||||
install_dir: [true, header_install_dir, true, false],
|
||||
)
|
||||
|
||||
base_dep = declare_dependency(
|
||||
include_directories: include_directories('.'),
|
||||
link_with: base,
|
||||
dependencies: [nice_dep, json_glib_dep, gum_dep, efni_dep] + extra_deps,
|
||||
dependencies: [nice_dep, json_glib_dep, gum_dep] + extra_deps,
|
||||
)
|
||||
|
||||
base_build_dir = meson.current_build_dir()
|
||||
|
||||
if have_in_tree_payloads
|
||||
pkg = import('pkgconfig')
|
||||
pkg.generate(base,
|
||||
filebase: f'frida-base-@api_version@',
|
||||
name: 'Frida Base Library',
|
||||
version: frida_version,
|
||||
description: 'Basic building blocks',
|
||||
)
|
||||
endif
|
||||
pkg = import('pkgconfig')
|
||||
pkg.generate(base,
|
||||
filebase: f'frida-base-@api_version@',
|
||||
name: 'Frida Base Library',
|
||||
version: frida_version,
|
||||
description: 'Basic building blocks',
|
||||
)
|
||||
+9
-417
@@ -1,432 +1,26 @@
|
||||
#ifdef HAVE_NICE
|
||||
|
||||
#define OPENSSL_SUPPRESS_DEPRECATED
|
||||
|
||||
#include "frida-base.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <usrsctp.h>
|
||||
|
||||
#ifdef HAVE_GIOAPPLE
|
||||
# include <CoreFoundation/CoreFoundation.h>
|
||||
# include <Security/Security.h>
|
||||
#else
|
||||
# define OPENSSL_SUPPRESS_DEPRECATED
|
||||
# include <openssl/asn1.h>
|
||||
# include <openssl/bio.h>
|
||||
# include <openssl/bn.h>
|
||||
# include <openssl/evp.h>
|
||||
# include <openssl/pem.h>
|
||||
# include <openssl/rsa.h>
|
||||
# include <openssl/x509.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GIOAPPLE
|
||||
static SecKeyRef frida_rsa_keypair_generate (void);
|
||||
static void frida_rsa_export_public_key (SecKeyRef private_key, GByteArray * out);
|
||||
static void frida_rsa_export_private_key (SecKeyRef private_key, GByteArray * out);
|
||||
static void frida_rsa_sign_sha256 (SecKeyRef private_key, const guint8 * message, gsize message_length, GByteArray * out);
|
||||
|
||||
static void frida_build_tbs_certificate (GByteArray * out, const GByteArray * subject_public_key);
|
||||
static void frida_build_name (GByteArray * out);
|
||||
static void frida_build_rdn (GByteArray * out, const guint8 * oid, gsize oid_length, guint8 value_tag, const gchar * value);
|
||||
static void frida_build_validity (GByteArray * out);
|
||||
static void frida_build_subject_public_key_info (GByteArray * out, const GByteArray * rsa_public_key);
|
||||
static void frida_build_signed_certificate (GByteArray * out, const GByteArray * tbs, const GByteArray * signature);
|
||||
static void frida_build_algorithm_identifier (GByteArray * out, const guint8 * oid, gsize oid_length);
|
||||
static void frida_build_pkcs8_private_key_info (GByteArray * out, const GByteArray * rsa_private_key);
|
||||
static gchar * frida_pem_encode (const gchar * type, const guint8 * der, gsize der_length);
|
||||
|
||||
static void frida_der_append_tlv (GByteArray * out, guint8 tag, const guint8 * value, gsize length);
|
||||
static void frida_der_append_length (GByteArray * out, gsize length);
|
||||
static void frida_der_append_integer_uint (GByteArray * out, guint64 value);
|
||||
static void frida_der_append_null (GByteArray * out);
|
||||
static void frida_der_append_oid (GByteArray * out, const guint8 * oid, gsize length);
|
||||
static void frida_der_append_utctime (GByteArray * out, time_t t);
|
||||
static void frida_der_append_bit_string (GByteArray * out, const guint8 * bytes, gsize length);
|
||||
|
||||
static const guint8 frida_oid_country[] = { 0x55, 0x04, 0x06 };
|
||||
static const guint8 frida_oid_organization[] = { 0x55, 0x04, 0x0a };
|
||||
static const guint8 frida_oid_common_name[] = { 0x55, 0x04, 0x03 };
|
||||
static const guint8 frida_oid_rsa_encryption[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 };
|
||||
static const guint8 frida_oid_sha256_with_rsa[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b };
|
||||
#else
|
||||
static gchar * frida_steal_bio_to_string (BIO ** bio);
|
||||
#endif
|
||||
|
||||
static int frida_on_connection_output (void * addr, void * buffer, size_t length, uint8_t tos, uint8_t set_df);
|
||||
static void frida_on_debug_printf (const char * format, ...);
|
||||
|
||||
static void frida_on_upcall (struct socket * sock, void * user_data, int flags);
|
||||
|
||||
#ifdef HAVE_GIOAPPLE
|
||||
|
||||
void
|
||||
_frida_generate_certificate (guint8 ** cert_der, gint * cert_der_length, gchar ** cert_pem, gchar ** key_pem)
|
||||
{
|
||||
SecKeyRef private_key;
|
||||
GByteArray * rsa_public_key, * rsa_private_key, * subject_public_key, * tbs, * signature, * certificate, * pkcs8;
|
||||
|
||||
*cert_der = NULL;
|
||||
*cert_der_length = 0;
|
||||
*cert_pem = NULL;
|
||||
*key_pem = NULL;
|
||||
|
||||
private_key = frida_rsa_keypair_generate ();
|
||||
|
||||
rsa_public_key = g_byte_array_new ();
|
||||
frida_rsa_export_public_key (private_key, rsa_public_key);
|
||||
|
||||
rsa_private_key = g_byte_array_new ();
|
||||
frida_rsa_export_private_key (private_key, rsa_private_key);
|
||||
|
||||
subject_public_key = g_byte_array_new ();
|
||||
frida_build_subject_public_key_info (subject_public_key, rsa_public_key);
|
||||
|
||||
tbs = g_byte_array_new ();
|
||||
frida_build_tbs_certificate (tbs, subject_public_key);
|
||||
|
||||
signature = g_byte_array_new ();
|
||||
frida_rsa_sign_sha256 (private_key, tbs->data, tbs->len, signature);
|
||||
|
||||
certificate = g_byte_array_new ();
|
||||
frida_build_signed_certificate (certificate, tbs, signature);
|
||||
|
||||
pkcs8 = g_byte_array_new ();
|
||||
frida_build_pkcs8_private_key_info (pkcs8, rsa_private_key);
|
||||
|
||||
*cert_der = g_memdup2 (certificate->data, certificate->len);
|
||||
*cert_der_length = certificate->len;
|
||||
*cert_pem = frida_pem_encode ("CERTIFICATE", certificate->data, certificate->len);
|
||||
*key_pem = frida_pem_encode ("PRIVATE KEY", pkcs8->data, pkcs8->len);
|
||||
|
||||
g_byte_array_unref (pkcs8);
|
||||
g_byte_array_unref (certificate);
|
||||
g_byte_array_unref (signature);
|
||||
g_byte_array_unref (tbs);
|
||||
g_byte_array_unref (subject_public_key);
|
||||
g_byte_array_unref (rsa_private_key);
|
||||
g_byte_array_unref (rsa_public_key);
|
||||
CFRelease (private_key);
|
||||
}
|
||||
|
||||
static SecKeyRef
|
||||
frida_rsa_keypair_generate (void)
|
||||
{
|
||||
SecKeyRef private_key;
|
||||
CFMutableDictionaryRef attrs;
|
||||
const int key_size_bits = 2048;
|
||||
CFNumberRef key_size;
|
||||
|
||||
attrs = CFDictionaryCreateMutable (kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
|
||||
key_size = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &key_size_bits);
|
||||
CFDictionarySetValue (attrs, kSecAttrKeyType, kSecAttrKeyTypeRSA);
|
||||
CFDictionarySetValue (attrs, kSecAttrKeySizeInBits, key_size);
|
||||
CFRelease (key_size);
|
||||
|
||||
private_key = SecKeyCreateRandomKey (attrs, NULL);
|
||||
g_assert (private_key != NULL);
|
||||
|
||||
CFRelease (attrs);
|
||||
|
||||
return private_key;
|
||||
}
|
||||
|
||||
static void
|
||||
frida_rsa_export_public_key (SecKeyRef private_key, GByteArray * out)
|
||||
{
|
||||
SecKeyRef public_key;
|
||||
CFDataRef data;
|
||||
|
||||
public_key = SecKeyCopyPublicKey (private_key);
|
||||
g_assert (public_key != NULL);
|
||||
|
||||
data = SecKeyCopyExternalRepresentation (public_key, NULL);
|
||||
g_assert (data != NULL);
|
||||
|
||||
g_byte_array_append (out, CFDataGetBytePtr (data), CFDataGetLength (data));
|
||||
|
||||
CFRelease (data);
|
||||
CFRelease (public_key);
|
||||
}
|
||||
|
||||
static void
|
||||
frida_rsa_export_private_key (SecKeyRef private_key, GByteArray * out)
|
||||
{
|
||||
CFDataRef data;
|
||||
|
||||
data = SecKeyCopyExternalRepresentation (private_key, NULL);
|
||||
g_assert (data != NULL);
|
||||
|
||||
g_byte_array_append (out, CFDataGetBytePtr (data), (guint) CFDataGetLength (data));
|
||||
|
||||
CFRelease (data);
|
||||
}
|
||||
|
||||
static void
|
||||
frida_rsa_sign_sha256 (SecKeyRef private_key, const guint8 * message, gsize message_length, GByteArray * out)
|
||||
{
|
||||
CFDataRef to_sign, signature;
|
||||
|
||||
to_sign = CFDataCreate (kCFAllocatorDefault, message, (CFIndex) message_length);
|
||||
|
||||
signature = SecKeyCreateSignature (private_key, kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256, to_sign, NULL);
|
||||
g_assert (signature != NULL);
|
||||
|
||||
g_byte_array_append (out, CFDataGetBytePtr (signature), (guint) CFDataGetLength (signature));
|
||||
|
||||
CFRelease (signature);
|
||||
CFRelease (to_sign);
|
||||
}
|
||||
|
||||
static void
|
||||
frida_build_tbs_certificate (GByteArray * out, const GByteArray * subject_public_key)
|
||||
{
|
||||
GByteArray * inner = g_byte_array_new ();
|
||||
|
||||
frida_der_append_integer_uint (inner, 1);
|
||||
frida_build_algorithm_identifier (inner, frida_oid_sha256_with_rsa, sizeof (frida_oid_sha256_with_rsa));
|
||||
frida_build_name (inner);
|
||||
frida_build_validity (inner);
|
||||
frida_build_name (inner);
|
||||
g_byte_array_append (inner, subject_public_key->data, subject_public_key->len);
|
||||
|
||||
frida_der_append_tlv (out, 0x30, inner->data, inner->len);
|
||||
|
||||
g_byte_array_unref (inner);
|
||||
}
|
||||
|
||||
static void
|
||||
frida_build_name (GByteArray * out)
|
||||
{
|
||||
GByteArray * inner = g_byte_array_new ();
|
||||
|
||||
frida_build_rdn (inner, frida_oid_country, sizeof (frida_oid_country), 0x13, "CA");
|
||||
frida_build_rdn (inner, frida_oid_organization, sizeof (frida_oid_organization), 0x0c, "Frida");
|
||||
frida_build_rdn (inner, frida_oid_common_name, sizeof (frida_oid_common_name), 0x0c, "lolcathost");
|
||||
|
||||
frida_der_append_tlv (out, 0x30, inner->data, inner->len);
|
||||
|
||||
g_byte_array_unref (inner);
|
||||
}
|
||||
|
||||
static void
|
||||
frida_build_rdn (GByteArray * out, const guint8 * oid, gsize oid_length, guint8 value_tag, const gchar * value)
|
||||
{
|
||||
GByteArray * atv, * rdn;
|
||||
|
||||
atv = g_byte_array_new ();
|
||||
rdn = g_byte_array_new ();
|
||||
|
||||
frida_der_append_oid (atv, oid, oid_length);
|
||||
frida_der_append_tlv (atv, value_tag, (const guint8 *) value, strlen (value));
|
||||
frida_der_append_tlv (rdn, 0x30, atv->data, atv->len);
|
||||
frida_der_append_tlv (out, 0x31, rdn->data, rdn->len);
|
||||
|
||||
g_byte_array_unref (rdn);
|
||||
g_byte_array_unref (atv);
|
||||
}
|
||||
|
||||
static void
|
||||
frida_build_validity (GByteArray * out)
|
||||
{
|
||||
const time_t lifetime_seconds = 15780000;
|
||||
GByteArray * inner;
|
||||
time_t not_before, not_after;
|
||||
|
||||
inner = g_byte_array_new ();
|
||||
|
||||
not_before = time (NULL);
|
||||
not_after = not_before + lifetime_seconds;
|
||||
|
||||
frida_der_append_utctime (inner, not_before);
|
||||
frida_der_append_utctime (inner, not_after);
|
||||
|
||||
frida_der_append_tlv (out, 0x30, inner->data, inner->len);
|
||||
|
||||
g_byte_array_unref (inner);
|
||||
}
|
||||
|
||||
static void
|
||||
frida_build_subject_public_key_info (GByteArray * out, const GByteArray * rsa_public_key)
|
||||
{
|
||||
GByteArray * inner = g_byte_array_new ();
|
||||
|
||||
frida_build_algorithm_identifier (inner, frida_oid_rsa_encryption, sizeof (frida_oid_rsa_encryption));
|
||||
frida_der_append_bit_string (inner, rsa_public_key->data, rsa_public_key->len);
|
||||
|
||||
frida_der_append_tlv (out, 0x30, inner->data, inner->len);
|
||||
|
||||
g_byte_array_unref (inner);
|
||||
}
|
||||
|
||||
static void
|
||||
frida_build_signed_certificate (GByteArray * out, const GByteArray * tbs, const GByteArray * signature)
|
||||
{
|
||||
GByteArray * inner = g_byte_array_new ();
|
||||
|
||||
g_byte_array_append (inner, tbs->data, tbs->len);
|
||||
frida_build_algorithm_identifier (inner, frida_oid_sha256_with_rsa, sizeof (frida_oid_sha256_with_rsa));
|
||||
frida_der_append_bit_string (inner, signature->data, signature->len);
|
||||
|
||||
frida_der_append_tlv (out, 0x30, inner->data, inner->len);
|
||||
|
||||
g_byte_array_unref (inner);
|
||||
}
|
||||
|
||||
static void
|
||||
frida_build_algorithm_identifier (GByteArray * out, const guint8 * oid, gsize oid_length)
|
||||
{
|
||||
GByteArray * inner = g_byte_array_new ();
|
||||
|
||||
frida_der_append_oid (inner, oid, oid_length);
|
||||
frida_der_append_null (inner);
|
||||
|
||||
frida_der_append_tlv (out, 0x30, inner->data, inner->len);
|
||||
|
||||
g_byte_array_unref (inner);
|
||||
}
|
||||
|
||||
static void
|
||||
frida_build_pkcs8_private_key_info (GByteArray * out, const GByteArray * rsa_private_key)
|
||||
{
|
||||
GByteArray * inner = g_byte_array_new ();
|
||||
|
||||
frida_der_append_integer_uint (inner, 0);
|
||||
frida_build_algorithm_identifier (inner, frida_oid_rsa_encryption, sizeof (frida_oid_rsa_encryption));
|
||||
frida_der_append_tlv (inner, 0x04, rsa_private_key->data, rsa_private_key->len);
|
||||
|
||||
frida_der_append_tlv (out, 0x30, inner->data, inner->len);
|
||||
|
||||
g_byte_array_unref (inner);
|
||||
}
|
||||
|
||||
static gchar *
|
||||
frida_pem_encode (const gchar * type, const guint8 * der, gsize der_length)
|
||||
{
|
||||
GString * pem;
|
||||
gchar * base64;
|
||||
gsize length, i;
|
||||
|
||||
base64 = g_base64_encode (der, der_length);
|
||||
length = strlen (base64);
|
||||
|
||||
pem = g_string_sized_new (length + 128);
|
||||
|
||||
g_string_append_printf (pem, "-----BEGIN %s-----\n", type);
|
||||
|
||||
for (i = 0; i < length; i += 64)
|
||||
{
|
||||
gsize chunk = MIN (64, length - i);
|
||||
g_string_append_len (pem, base64 + i, chunk);
|
||||
g_string_append_c (pem, '\n');
|
||||
}
|
||||
|
||||
g_string_append_printf (pem, "-----END %s-----\n", type);
|
||||
|
||||
g_free (base64);
|
||||
|
||||
return g_string_free (pem, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
frida_der_append_tlv (GByteArray * out, guint8 tag, const guint8 * value, gsize length)
|
||||
{
|
||||
g_byte_array_append (out, &tag, 1);
|
||||
frida_der_append_length (out, length);
|
||||
if (length > 0)
|
||||
g_byte_array_append (out, value, length);
|
||||
}
|
||||
|
||||
static void
|
||||
frida_der_append_length (GByteArray * out, gsize length)
|
||||
{
|
||||
gint i;
|
||||
guint8 buf[9], header;
|
||||
|
||||
if (length < 0x80)
|
||||
{
|
||||
guint8 b = (guint8) length;
|
||||
g_byte_array_append (out, &b, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (length > 0)
|
||||
{
|
||||
buf[++i] = (guint8) (length & 0xff);
|
||||
length >>= 8;
|
||||
}
|
||||
header = (guint8) (0x80 | i);
|
||||
g_byte_array_append (out, &header, 1);
|
||||
while (i > 0)
|
||||
{
|
||||
g_byte_array_append (out, &buf[i], 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
frida_der_append_integer_uint (GByteArray * out, guint64 value)
|
||||
{
|
||||
gint i;
|
||||
guint8 buf[9];
|
||||
gint start;
|
||||
|
||||
for (i = 7; i >= 0; i--)
|
||||
{
|
||||
buf[i + 1] = (guint8) (value & 0xff);
|
||||
value >>= 8;
|
||||
}
|
||||
buf[0] = 0;
|
||||
|
||||
start = 0;
|
||||
while (start < 8 && buf[start] == 0 && (buf[start + 1] & 0x80) == 0)
|
||||
start++;
|
||||
|
||||
frida_der_append_tlv (out, 0x02, buf + start, (gsize) (9 - start));
|
||||
}
|
||||
|
||||
static void
|
||||
frida_der_append_null (GByteArray * out)
|
||||
{
|
||||
frida_der_append_tlv (out, 0x05, NULL, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
frida_der_append_oid (GByteArray * out, const guint8 * oid, gsize length)
|
||||
{
|
||||
frida_der_append_tlv (out, 0x06, oid, length);
|
||||
}
|
||||
|
||||
static void
|
||||
frida_der_append_utctime (GByteArray * out, time_t t)
|
||||
{
|
||||
struct tm tm;
|
||||
gchar buf[16];
|
||||
|
||||
gmtime_r (&t, &tm);
|
||||
g_snprintf (buf, sizeof (buf), "%02d%02d%02d%02d%02d%02dZ",
|
||||
tm.tm_year % 100, tm.tm_mon + 1, tm.tm_mday,
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
|
||||
frida_der_append_tlv (out, 0x17, (const guint8 *) buf, strlen (buf));
|
||||
}
|
||||
|
||||
static void
|
||||
frida_der_append_bit_string (GByteArray * out, const guint8 * bytes, gsize length)
|
||||
{
|
||||
guint8 tag = 0x03;
|
||||
guint8 unused_bits = 0;
|
||||
|
||||
g_byte_array_append (out, &tag, 1);
|
||||
frida_der_append_length (out, length + 1);
|
||||
g_byte_array_append (out, &unused_bits, 1);
|
||||
if (length > 0)
|
||||
g_byte_array_append (out, bytes, length);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void
|
||||
_frida_generate_certificate (guint8 ** cert_der, gint * cert_der_length, gchar ** cert_pem, gchar ** key_pem)
|
||||
{
|
||||
@@ -496,8 +90,6 @@ frida_steal_bio_to_string (BIO ** bio)
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
_frida_sctp_connection_initialize_sctp_backend (void)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
using Efni;
|
||||
|
||||
#if HAVE_NICE
|
||||
namespace Frida {
|
||||
namespace PeerConnection {
|
||||
|
||||
@@ -220,128 +220,4 @@ namespace Frida {
|
||||
Posix.tcsetattr (fd, 0, tios);
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace ChildProcess {
|
||||
public async WaitResult wait_for_next_stop (uint pid, Cancellable? cancellable) throws Error, IOError {
|
||||
var main_context = MainContext.get_thread_default ();
|
||||
|
||||
bool timed_out = false;
|
||||
var timeout_source = new TimeoutSource.seconds (5);
|
||||
timeout_source.set_callback (() => {
|
||||
timed_out = true;
|
||||
return Source.REMOVE;
|
||||
});
|
||||
timeout_source.attach (main_context);
|
||||
|
||||
int status = 0;
|
||||
uint[] delays = { 0, 1, 2, 5, 10, 20, 50, 250 };
|
||||
|
||||
try {
|
||||
for (uint i = 0; !timed_out && !cancellable.set_error_if_cancelled (); i++) {
|
||||
int res = Posix.waitpid ((Posix.pid_t) pid, out status, Posix.WNOHANG);
|
||||
if (res == -1)
|
||||
throw new Error.NOT_SUPPORTED ("Unable to wait for next stop: %s", strerror (errno));
|
||||
if (res != 0)
|
||||
break;
|
||||
|
||||
uint delay_ms = (i < delays.length) ? delays[i] : delays[delays.length - 1];
|
||||
|
||||
var delay_source = new TimeoutSource (delay_ms);
|
||||
delay_source.set_callback (wait_for_next_stop.callback);
|
||||
delay_source.attach (main_context);
|
||||
|
||||
var cancel_source = new CancellableSource (cancellable);
|
||||
cancel_source.set_callback (wait_for_next_stop.callback);
|
||||
cancel_source.attach (main_context);
|
||||
|
||||
yield;
|
||||
|
||||
cancel_source.destroy ();
|
||||
delay_source.destroy ();
|
||||
}
|
||||
} finally {
|
||||
timeout_source.destroy ();
|
||||
}
|
||||
|
||||
if (timed_out)
|
||||
throw new Error.TIMED_OUT ("Unexpectedly timed out while waiting for stop from process with PID %u", pid);
|
||||
|
||||
return WaitResult (pid, status);
|
||||
}
|
||||
}
|
||||
|
||||
public struct WaitResult {
|
||||
public uint pid;
|
||||
public int status;
|
||||
|
||||
public WaitKind kind;
|
||||
|
||||
public uint exit_status;
|
||||
|
||||
public int term_signal;
|
||||
|
||||
public int stop_signal;
|
||||
|
||||
public WaitResult (uint pid, int status) {
|
||||
this.pid = pid;
|
||||
this.status = status;
|
||||
|
||||
kind = WaitKind.OTHER;
|
||||
exit_status = 0;
|
||||
term_signal = 0;
|
||||
stop_signal = 0;
|
||||
|
||||
if (PosixStatus.is_exit (status)) {
|
||||
kind = WaitKind.EXITED;
|
||||
exit_status = PosixStatus.parse_exit_status (status);
|
||||
} else if (PosixStatus.is_signaled (status)) {
|
||||
kind = WaitKind.SIGNALED;
|
||||
term_signal = PosixStatus.parse_termination_signal (status);
|
||||
} else if (PosixStatus.is_stopped (status)) {
|
||||
kind = WaitKind.STOPPED;
|
||||
|
||||
stop_signal = PosixStatus.parse_stop_signal (status);
|
||||
}
|
||||
}
|
||||
|
||||
public void check_stopped () throws Error {
|
||||
switch (kind) {
|
||||
case WaitKind.EXITED:
|
||||
throw new Error.NOT_SUPPORTED ("Target exited with status %u", exit_status);
|
||||
case WaitKind.SIGNALED:
|
||||
throw new Error.NOT_SUPPORTED ("Target terminated with signal %u", term_signal);
|
||||
case WaitKind.STOPPED:
|
||||
return;
|
||||
default:
|
||||
throw new Error.NOT_SUPPORTED ("Unexpected status: 0x%08x", status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum WaitKind {
|
||||
EXITED,
|
||||
SIGNALED,
|
||||
STOPPED,
|
||||
OTHER
|
||||
}
|
||||
|
||||
namespace PosixStatus {
|
||||
[CCode (cname = "WIFEXITED", cheader_filename = "sys/wait.h")]
|
||||
private extern bool is_exit (int status);
|
||||
|
||||
[CCode (cname = "WIFSIGNALED", cheader_filename = "sys/wait.h")]
|
||||
private extern bool is_signaled (int status);
|
||||
|
||||
[CCode (cname = "WIFSTOPPED", cheader_filename = "sys/wait.h")]
|
||||
private extern bool is_stopped (int status);
|
||||
|
||||
[CCode (cname = "WEXITSTATUS", cheader_filename = "sys/wait.h")]
|
||||
private extern uint parse_exit_status (int status);
|
||||
|
||||
[CCode (cname = "WTERMSIG", cheader_filename = "sys/wait.h")]
|
||||
private extern Posix.Signal parse_termination_signal (int status);
|
||||
|
||||
[CCode (cname = "WSTOPSIG", cheader_filename = "sys/wait.h")]
|
||||
private extern Posix.Signal parse_stop_signal (int status);
|
||||
}
|
||||
}
|
||||
+124
-58
@@ -1,18 +1,19 @@
|
||||
namespace Frida {
|
||||
public sealed class Promise<T> {
|
||||
private Efni.Promise<T> impl;
|
||||
private Future<T>? _future;
|
||||
private Impl<T> impl;
|
||||
|
||||
public Future<T> future {
|
||||
get {
|
||||
if (_future == null)
|
||||
_future = new FutureImpl<T> (impl.future);
|
||||
return _future;
|
||||
return impl;
|
||||
}
|
||||
}
|
||||
|
||||
public Promise () {
|
||||
impl = new Efni.Promise<T> ();
|
||||
impl = new Impl<T> ();
|
||||
}
|
||||
|
||||
~Promise () {
|
||||
impl.abandon ();
|
||||
}
|
||||
|
||||
public void resolve (T result) {
|
||||
@@ -23,84 +24,149 @@ namespace Frida {
|
||||
impl.reject (error);
|
||||
}
|
||||
|
||||
private class FutureImpl<T> : Object, Future<T> {
|
||||
private Efni.Future<T> inner;
|
||||
|
||||
private class Impl<T> : Object, Future<T> {
|
||||
public bool ready {
|
||||
get {
|
||||
return inner.ready;
|
||||
return _ready;
|
||||
}
|
||||
}
|
||||
private bool _ready = false;
|
||||
|
||||
public T? value {
|
||||
get {
|
||||
return inner.value;
|
||||
return _value;
|
||||
}
|
||||
}
|
||||
private T? _value;
|
||||
|
||||
public GLib.Error? error {
|
||||
get {
|
||||
return inner.error;
|
||||
return _error;
|
||||
}
|
||||
}
|
||||
private GLib.Error? _error;
|
||||
|
||||
public FutureImpl (Efni.Future<T> inner) {
|
||||
this.inner = inner;
|
||||
}
|
||||
private Gee.ArrayQueue<CompletionFuncEntry>? on_complete;
|
||||
private Gee.ArrayQueue<ThenHandlerEntry<T>>? on_then;
|
||||
|
||||
public async T wait_async (Cancellable? cancellable) throws Error, IOError {
|
||||
if (!inner.ready) {
|
||||
bool resumed = false;
|
||||
public async T wait_async (Cancellable? cancellable) throws Frida.Error, IOError {
|
||||
if (_ready)
|
||||
return get_result ();
|
||||
|
||||
var cancel_source = new CancellableSource (cancellable);
|
||||
cancel_source.set_callback (() => {
|
||||
if (!resumed) {
|
||||
resumed = true;
|
||||
wait_async.callback ();
|
||||
}
|
||||
return Source.REMOVE;
|
||||
});
|
||||
cancel_source.attach (MainContext.get_thread_default ());
|
||||
var entry = new CompletionFuncEntry (wait_async.callback);
|
||||
if (on_complete == null)
|
||||
on_complete = new Gee.ArrayQueue<CompletionFuncEntry> ();
|
||||
on_complete.offer (entry);
|
||||
|
||||
inner.then (f => {
|
||||
if (!resumed) {
|
||||
resumed = true;
|
||||
wait_async.callback ();
|
||||
}
|
||||
});
|
||||
var cancel_source = new CancellableSource (cancellable);
|
||||
cancel_source.set_callback (() => {
|
||||
on_complete.remove (entry);
|
||||
wait_async.callback ();
|
||||
return false;
|
||||
});
|
||||
cancel_source.attach (MainContext.get_thread_default ());
|
||||
|
||||
yield;
|
||||
yield;
|
||||
|
||||
cancel_source.destroy ();
|
||||
cancel_source.destroy ();
|
||||
|
||||
cancellable.set_error_if_cancelled ();
|
||||
}
|
||||
cancellable.set_error_if_cancelled ();
|
||||
|
||||
return get_result ();
|
||||
}
|
||||
|
||||
public void then (owned FutureCompletionHandler<T> handler) {
|
||||
inner.then (f => {
|
||||
handler (this);
|
||||
});
|
||||
}
|
||||
|
||||
public T get_result () throws Error, IOError {
|
||||
GLib.Error? e = inner.error;
|
||||
if (e != null) {
|
||||
if (e is Error)
|
||||
throw (Error) e;
|
||||
|
||||
if (e is Efni.Error)
|
||||
throw error_from_efni ((Efni.Error) e);
|
||||
|
||||
if (e is IOError.CANCELLED)
|
||||
throw (IOError) e;
|
||||
|
||||
throw new Error.TRANSPORT ("%s", e.message);
|
||||
if (_ready) {
|
||||
schedule (() => {
|
||||
handler (this);
|
||||
return Source.REMOVE;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
return inner.value;
|
||||
if (on_then == null)
|
||||
on_then = new Gee.ArrayQueue<ThenHandlerEntry<T>> ();
|
||||
on_then.offer (new ThenHandlerEntry<T> ((owned) handler));
|
||||
}
|
||||
|
||||
public T get_result () throws Frida.Error, IOError {
|
||||
if (error != null) {
|
||||
if (error is Frida.Error)
|
||||
throw (Frida.Error) error;
|
||||
|
||||
if (error is IOError.CANCELLED)
|
||||
throw (IOError) error;
|
||||
|
||||
throw new Frida.Error.TRANSPORT ("%s", error.message);
|
||||
}
|
||||
|
||||
return _value;
|
||||
}
|
||||
|
||||
internal void resolve (T value) {
|
||||
assert (!_ready);
|
||||
|
||||
_value = value;
|
||||
transition_to_ready ();
|
||||
}
|
||||
|
||||
internal void reject (GLib.Error error) {
|
||||
assert (!_ready);
|
||||
|
||||
_error = error;
|
||||
transition_to_ready ();
|
||||
}
|
||||
|
||||
internal void abandon () {
|
||||
if (!_ready) {
|
||||
reject (new Frida.Error.INVALID_OPERATION ("Promise abandoned"));
|
||||
}
|
||||
}
|
||||
|
||||
internal void transition_to_ready () {
|
||||
_ready = true;
|
||||
|
||||
if (on_complete != null || on_then != null) {
|
||||
schedule (() => {
|
||||
if (on_complete != null) {
|
||||
CompletionFuncEntry? entry;
|
||||
while ((entry = on_complete.poll ()) != null)
|
||||
entry.func ();
|
||||
on_complete = null;
|
||||
}
|
||||
|
||||
if (on_then != null) {
|
||||
ThenHandlerEntry? entry;
|
||||
while ((entry = on_then.poll ()) != null)
|
||||
entry.handler (this);
|
||||
on_then = null;
|
||||
}
|
||||
|
||||
return Source.REMOVE;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static void schedule (owned SourceFunc function) {
|
||||
var source = new IdleSource ();
|
||||
source.set_callback ((owned) function);
|
||||
source.attach (MainContext.get_thread_default ());
|
||||
}
|
||||
}
|
||||
|
||||
private class CompletionFuncEntry {
|
||||
public SourceFunc func;
|
||||
|
||||
public CompletionFuncEntry (owned SourceFunc func) {
|
||||
this.func = (owned) func;
|
||||
}
|
||||
}
|
||||
|
||||
private class ThenHandlerEntry<T> {
|
||||
public FutureCompletionHandler<T> handler;
|
||||
|
||||
public ThenHandlerEntry (owned FutureCompletionHandler<T> handler) {
|
||||
this.handler = (owned) handler;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,9 +175,9 @@ namespace Frida {
|
||||
public abstract bool ready { get; }
|
||||
public abstract T? value { get; }
|
||||
public abstract GLib.Error? error { get; }
|
||||
public abstract async T wait_async (Cancellable? cancellable) throws Error, IOError;
|
||||
public abstract async T wait_async (Cancellable? cancellable) throws Frida.Error, IOError;
|
||||
public abstract void then (owned FutureCompletionHandler<T> handler);
|
||||
public abstract T get_result () throws Error, IOError;
|
||||
public abstract T get_result () throws Frida.Error, IOError;
|
||||
}
|
||||
|
||||
public delegate void FutureCompletionHandler<T> (Future<T> future);
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
namespace Frida {
|
||||
/**
|
||||
* Issues RPC calls over a {@link RpcPeer}, matching responses to requests.
|
||||
*/
|
||||
public sealed class RpcClient : Object {
|
||||
/**
|
||||
* The peer used to send and receive RPC messages.
|
||||
*/
|
||||
public weak RpcPeer peer {
|
||||
get;
|
||||
construct;
|
||||
@@ -13,23 +7,10 @@ namespace Frida {
|
||||
|
||||
private Gee.HashMap<string, PendingResponse> pending_responses = new Gee.HashMap<string, PendingResponse> ();
|
||||
|
||||
/**
|
||||
* Creates an RPC client that talks over @peer.
|
||||
*
|
||||
* @param peer the peer to send and receive messages through
|
||||
*/
|
||||
public RpcClient (RpcPeer peer) {
|
||||
Object (peer: peer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a remote method and waits for its result.
|
||||
*
|
||||
* @param method the method name to invoke
|
||||
* @param args the JSON arguments
|
||||
* @param data binary data to accompany the call, if any
|
||||
* @return the method's JSON result
|
||||
*/
|
||||
public async Json.Node call (string method, Json.Node[] args, Bytes? data, Cancellable? cancellable) throws Error, IOError {
|
||||
string request_id = Uuid.string_random ();
|
||||
|
||||
@@ -88,13 +69,6 @@ namespace Frida {
|
||||
return pending.result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Feeds an incoming message to the client, matching it against pending
|
||||
* calls if it is an RPC response.
|
||||
*
|
||||
* @param json the incoming message as a JSON string
|
||||
* @return true if the message was an RPC message and was handled
|
||||
*/
|
||||
public bool try_handle_message (string json) {
|
||||
if (json.index_of ("\"frida:rpc\"") == -1)
|
||||
return false;
|
||||
@@ -183,17 +157,7 @@ namespace Frida {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A transport over which an {@link RpcClient} sends and receives RPC
|
||||
* messages.
|
||||
*/
|
||||
public interface RpcPeer : Object {
|
||||
/**
|
||||
* Posts an RPC message to the peer.
|
||||
*
|
||||
* @param json the message as a JSON string
|
||||
* @param data binary data to accompany the message, if any
|
||||
*/
|
||||
public abstract async void post_rpc_message (string json, Bytes? data, Cancellable? cancellable) throws Error, IOError;
|
||||
}
|
||||
}
|
||||
+39
-701
File diff suppressed because it is too large.
Load diff
@@ -1,5 +1,30 @@
|
||||
#include "frida-base.h"
|
||||
|
||||
#ifdef HAVE_WINDOWS
|
||||
# include <winsock2.h>
|
||||
#else
|
||||
# include <netinet/in.h>
|
||||
# include <netinet/tcp.h>
|
||||
#endif
|
||||
|
||||
void
|
||||
frida_unix_socket_tune_buffer_sizes (gint fd)
|
||||
{
|
||||
#ifndef HAVE_WINDOWS
|
||||
/* The defaults are typically as low as 4K. */
|
||||
const int buffer_size = 256 * 1024;
|
||||
|
||||
setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &buffer_size, sizeof (buffer_size));
|
||||
setsockopt (fd, SOL_SOCKET, SO_SNDBUF, &buffer_size, sizeof (buffer_size));
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
frida_tcp_enable_nodelay (GSocket * socket)
|
||||
{
|
||||
g_socket_set_option (socket, IPPROTO_TCP, TCP_NODELAY, TRUE, NULL);
|
||||
}
|
||||
|
||||
const gchar *
|
||||
_frida_version_string (void)
|
||||
{
|
||||
|
||||
+96
-270
@@ -1,96 +1,133 @@
|
||||
using Efni;
|
||||
|
||||
namespace Frida {
|
||||
public const uint16 DEFAULT_CONTROL_PORT = 27042;
|
||||
public const uint16 DEFAULT_CLUSTER_PORT = 27052;
|
||||
|
||||
public SocketConnectable parse_control_address (string? address, uint16 port = 0) throws Error {
|
||||
return parse_frida_address (address, port, DEFAULT_CONTROL_PORT);
|
||||
return parse_socket_address (address, port, "127.0.0.1", DEFAULT_CONTROL_PORT);
|
||||
}
|
||||
|
||||
public SocketConnectable parse_cluster_address (string? address, uint16 port = 0) throws Error {
|
||||
return parse_frida_address (address, port, DEFAULT_CLUSTER_PORT);
|
||||
return parse_socket_address (address, port, "127.0.0.1", DEFAULT_CLUSTER_PORT);
|
||||
}
|
||||
|
||||
private SocketConnectable parse_frida_address (string? address, uint16 port, uint16 default_port) throws Error {
|
||||
public SocketConnectable parse_socket_address (string? address, uint16 port, string default_address,
|
||||
uint16 default_port) throws Error {
|
||||
if (address == null)
|
||||
address = default_address;
|
||||
if (port == 0)
|
||||
port = default_port;
|
||||
|
||||
#if !WINDOWS
|
||||
if (address.has_prefix ("unix:")) {
|
||||
string path = address.substring (5);
|
||||
|
||||
UnixSocketAddressType type = UnixSocketAddress.abstract_names_supported ()
|
||||
? UnixSocketAddressType.ABSTRACT
|
||||
: UnixSocketAddressType.PATH;
|
||||
|
||||
return new UnixSocketAddress.with_type (path, -1, type);
|
||||
}
|
||||
#endif
|
||||
|
||||
try {
|
||||
return Efni.parse_socket_address (address, port, "127.0.0.1", default_port);
|
||||
} catch (Efni.Error e) {
|
||||
throw error_from_efni (e);
|
||||
return NetworkAddress.parse (address, port);
|
||||
} catch (GLib.Error e) {
|
||||
throw new Error.INVALID_ARGUMENT ("%s", e.message);
|
||||
}
|
||||
}
|
||||
|
||||
namespace UnixSocket {
|
||||
public extern void tune_buffer_sizes (int fd);
|
||||
}
|
||||
|
||||
namespace Tcp {
|
||||
public extern void enable_nodelay (Socket socket);
|
||||
}
|
||||
|
||||
namespace Udp {
|
||||
public size_t recv (uint8[] data, DatagramBased source, Cancellable? cancellable, out InetSocketAddress remote_address)
|
||||
throws Error, IOError {
|
||||
var v = InputVector ();
|
||||
v.buffer = data;
|
||||
v.size = data.length;
|
||||
|
||||
InputVector[] vectors = { v };
|
||||
|
||||
var m = InputMessage ();
|
||||
remote_address = null;
|
||||
m.address = &remote_address;
|
||||
m.vectors = vectors;
|
||||
m.num_vectors = vectors.length;
|
||||
|
||||
InputMessage[] messages = { m };
|
||||
|
||||
try {
|
||||
source.receive_messages (messages, 0, 0, cancellable);
|
||||
} catch (GLib.Error e) {
|
||||
throw new Error.TRANSPORT ("%s", e.message);
|
||||
}
|
||||
|
||||
return messages[0].bytes_received;
|
||||
}
|
||||
|
||||
public void send (uint8[] data, DatagramBased sink, Cancellable? cancellable) throws Error, IOError {
|
||||
send_to (data, null, sink, cancellable);
|
||||
}
|
||||
|
||||
public void send_to (uint8[] data, InetSocketAddress? dest_addr, DatagramBased sink, Cancellable? cancellable)
|
||||
throws Error, IOError {
|
||||
var v = OutputVector ();
|
||||
v.buffer = data;
|
||||
v.size = data.length;
|
||||
|
||||
OutputVector[] vectors = { v };
|
||||
|
||||
var m = OutputMessage ();
|
||||
m.address = dest_addr;
|
||||
m.vectors = vectors;
|
||||
m.num_vectors = vectors.length;
|
||||
|
||||
OutputMessage[] messages = { m };
|
||||
|
||||
try {
|
||||
sink.send_messages (messages, 0, 0, cancellable);
|
||||
} catch (GLib.Error e) {
|
||||
throw new Error.TRANSPORT ("%s", e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the network endpoint a {@link PortalService} or
|
||||
* {@link ControlService} listens on.
|
||||
*/
|
||||
public sealed class EndpointParameters : Object {
|
||||
/**
|
||||
* The address to bind to, or null for the default.
|
||||
*/
|
||||
public string? address {
|
||||
get;
|
||||
construct;
|
||||
}
|
||||
|
||||
/**
|
||||
* The port to listen on, or 0 for the default.
|
||||
*/
|
||||
public uint16 port {
|
||||
get;
|
||||
construct;
|
||||
}
|
||||
|
||||
/**
|
||||
* TLS certificate to serve, enabling TLS when set.
|
||||
*/
|
||||
public TlsCertificate? certificate {
|
||||
get;
|
||||
construct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Origin to require from connecting clients, if any.
|
||||
*/
|
||||
public string? origin {
|
||||
get;
|
||||
construct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Service used to authenticate connecting clients, if any.
|
||||
*/
|
||||
public AuthenticationService? auth_service {
|
||||
get;
|
||||
construct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Directory whose files are served as static web assets, if any.
|
||||
*/
|
||||
public File? asset_root {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler invoked for web requests, if any.
|
||||
*/
|
||||
public WebRequestHandler? request_handler {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates endpoint parameters.
|
||||
*
|
||||
* @param address the address to bind to, or null for the default
|
||||
* @param port the port to listen on, or 0 for the default
|
||||
* @param certificate TLS certificate to serve, or null for plaintext
|
||||
* @param origin origin to require from clients, or null
|
||||
* @param auth_service service used to authenticate clients, or null
|
||||
* @param asset_root directory of static assets to serve, or null
|
||||
*/
|
||||
public EndpointParameters (string? address = null, uint16 port = 0, TlsCertificate? certificate = null,
|
||||
string? origin = null, AuthenticationService? auth_service = null, File? asset_root = null) {
|
||||
Object (
|
||||
@@ -104,132 +141,6 @@ namespace Frida {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles web requests made to an endpoint's served assets.
|
||||
*/
|
||||
public interface WebRequestHandler : Object {
|
||||
/**
|
||||
* Handles a single web request.
|
||||
*
|
||||
* @param request the incoming request
|
||||
* @return the response to send, or null to fall through to the default
|
||||
* handling
|
||||
*/
|
||||
public abstract async WebResponse? handle_request (WebRequest request, Cancellable? cancellable) throws Error, IOError;
|
||||
}
|
||||
|
||||
/**
|
||||
* An incoming web request passed to a {@link WebRequestHandler}.
|
||||
*/
|
||||
public sealed class WebRequest : Object {
|
||||
/**
|
||||
* The HTTP method, such as `GET` or `POST`.
|
||||
*/
|
||||
public string method {
|
||||
get;
|
||||
construct;
|
||||
}
|
||||
|
||||
/**
|
||||
* The request path.
|
||||
*/
|
||||
public string path {
|
||||
get;
|
||||
construct;
|
||||
}
|
||||
|
||||
/**
|
||||
* The raw query string, if any.
|
||||
*/
|
||||
public string? query_string {
|
||||
get;
|
||||
construct;
|
||||
}
|
||||
|
||||
/**
|
||||
* The request body, if any.
|
||||
*/
|
||||
public Bytes? body {
|
||||
get;
|
||||
construct;
|
||||
}
|
||||
|
||||
private Soup.MessageHeaders raw_headers;
|
||||
|
||||
internal WebRequest (string method, string path, string? query_string, Soup.MessageHeaders headers, Bytes? body) {
|
||||
Object (method: method, path: path, query_string: query_string, body: body);
|
||||
raw_headers = headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes @func for each request header.
|
||||
*
|
||||
* @param func function called with each header's name and value
|
||||
*/
|
||||
public void foreach_header (WebRequestHeaderFunc func) {
|
||||
raw_headers.foreach ((name, val) => {
|
||||
func (name, val);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked for each header while iterating a {@link WebRequest}.
|
||||
*
|
||||
* @param name the header name
|
||||
* @param val the header value
|
||||
*/
|
||||
public delegate void WebRequestHeaderFunc (string name, string val);
|
||||
|
||||
/**
|
||||
* A response returned from a {@link WebRequestHandler}.
|
||||
*/
|
||||
public sealed class WebResponse : Object {
|
||||
/**
|
||||
* The HTTP status code.
|
||||
*/
|
||||
public uint status {
|
||||
get;
|
||||
construct;
|
||||
}
|
||||
|
||||
/**
|
||||
* The response body.
|
||||
*/
|
||||
public Bytes body {
|
||||
get;
|
||||
construct;
|
||||
}
|
||||
|
||||
private Soup.MessageHeaders raw_headers = new Soup.MessageHeaders (RESPONSE);
|
||||
|
||||
/**
|
||||
* Creates a response.
|
||||
*
|
||||
* @param status the HTTP status code
|
||||
* @param body the response body
|
||||
*/
|
||||
public WebResponse (uint status, Bytes body) {
|
||||
Object (status: status, body: body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a header to the response.
|
||||
*
|
||||
* @param name the header name
|
||||
* @param val the header value
|
||||
*/
|
||||
public void add_header (string name, string val) {
|
||||
raw_headers.append (name, val);
|
||||
}
|
||||
|
||||
internal void write_headers_to (Soup.MessageHeaders target) {
|
||||
raw_headers.foreach ((name, val) => {
|
||||
target.replace (name, val);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public async IOStream negotiate_connection (IOStream stream, WebServiceTransport transport, string host, string? origin,
|
||||
Cancellable? cancellable) throws Error, IOError {
|
||||
var input = (DataInputStream) Object.new (typeof (DataInputStream),
|
||||
@@ -557,14 +468,14 @@ namespace Frida {
|
||||
|
||||
server.add_websocket_handler ("/ws", endpoint_params.origin, null, on_websocket_opened);
|
||||
|
||||
if (endpoint_params.request_handler != null || endpoint_params.asset_root != null)
|
||||
server.add_handler (null, on_http_request);
|
||||
if (endpoint_params.asset_root != null)
|
||||
server.add_handler (null, on_asset_request);
|
||||
}
|
||||
|
||||
public void close () {
|
||||
io_cancellable.cancel ();
|
||||
|
||||
if (endpoint_params.request_handler != null || endpoint_params.asset_root != null)
|
||||
if (endpoint_params.asset_root != null)
|
||||
server.remove_handler ("/");
|
||||
server.remove_handler ("/ws");
|
||||
|
||||
@@ -649,8 +560,7 @@ namespace Frida {
|
||||
try {
|
||||
remote_address = sc.get_remote_address ();
|
||||
} catch (GLib.Error e) {
|
||||
remove_connection (peer);
|
||||
return;
|
||||
assert_not_reached ();
|
||||
}
|
||||
|
||||
incoming (peer, remote_address);
|
||||
@@ -665,77 +575,20 @@ namespace Frida {
|
||||
connections.remove (connection);
|
||||
}
|
||||
|
||||
private void on_http_request (Soup.Server server, Soup.ServerMessage msg, string path,
|
||||
private void on_asset_request (Soup.Server server, Soup.ServerMessage msg, string path,
|
||||
HashTable<string, string>? query) {
|
||||
msg.get_response_headers ().replace ("Server", "Frida/" + _version_string ());
|
||||
|
||||
msg.pause ();
|
||||
handle_http_request.begin (msg, path);
|
||||
}
|
||||
|
||||
private async void handle_http_request (Soup.ServerMessage msg, string path) {
|
||||
WebRequestHandler? handler = endpoint_params.request_handler;
|
||||
if (handler != null) {
|
||||
if (yield try_request_handler (handler, msg, path, io_cancellable))
|
||||
return;
|
||||
}
|
||||
|
||||
File? asset_root = endpoint_params.asset_root;
|
||||
if (asset_root != null) {
|
||||
unowned string method = msg.get_method ();
|
||||
if (method != "GET" && method != "HEAD") {
|
||||
msg.set_status (Soup.Status.METHOD_NOT_ALLOWED, null);
|
||||
msg.unpause ();
|
||||
return;
|
||||
}
|
||||
|
||||
File location = asset_root.resolve_relative_path (path.next_char ());
|
||||
yield handle_asset_request (path, location, msg);
|
||||
unowned string method = msg.get_method ();
|
||||
if (method != "GET" && method != "HEAD") {
|
||||
msg.set_status (Soup.Status.METHOD_NOT_ALLOWED, null);
|
||||
return;
|
||||
}
|
||||
|
||||
msg.set_status (Soup.Status.NOT_FOUND, null);
|
||||
msg.unpause ();
|
||||
}
|
||||
File location = endpoint_params.asset_root.resolve_relative_path (path.next_char ());
|
||||
|
||||
private static async bool try_request_handler (WebRequestHandler handler, Soup.ServerMessage msg, string path,
|
||||
Cancellable? cancellable) {
|
||||
var body = msg.get_request_body ();
|
||||
Bytes? request_body = (body.length != 0) ? body.flatten () : null;
|
||||
unowned Uri? uri = msg.get_uri ();
|
||||
string? query_string = (uri != null) ? uri.get_query () : null;
|
||||
var request = new WebRequest (msg.get_method (), path, query_string, msg.get_request_headers (),
|
||||
request_body);
|
||||
|
||||
WebResponse? response;
|
||||
try {
|
||||
response = yield handler.handle_request (request, cancellable);
|
||||
} catch (Error e) {
|
||||
msg.set_status (Soup.Status.INTERNAL_SERVER_ERROR, null);
|
||||
msg.set_response ("text/plain; charset=utf-8", Soup.MemoryUse.COPY, e.message.data);
|
||||
msg.unpause ();
|
||||
return true;
|
||||
} catch (IOError e) {
|
||||
msg.unpause ();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (response == null)
|
||||
return false;
|
||||
|
||||
apply_response (msg, response);
|
||||
msg.unpause ();
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void apply_response (Soup.ServerMessage msg, WebResponse response) {
|
||||
msg.set_status (response.status, null);
|
||||
|
||||
response.write_headers_to (msg.get_response_headers ());
|
||||
|
||||
Bytes body = response.body;
|
||||
if (body.length > 0)
|
||||
msg.get_response_body ().append_bytes (body);
|
||||
msg.pause ();
|
||||
handle_asset_request.begin (path, location, msg);
|
||||
}
|
||||
|
||||
private async void handle_asset_request (string path, File file, Soup.ServerMessage msg) {
|
||||
@@ -1040,9 +893,6 @@ namespace Frida {
|
||||
construct {
|
||||
websocket.max_incoming_payload_size = (256 * 1024) + 1; // XXX: There's an off-by-one error in libsoup
|
||||
|
||||
if (websocket.get_class ().find_property ("max-total-message-size") != null)
|
||||
websocket.set ("max-total-message-size", websocket.max_incoming_payload_size);
|
||||
|
||||
websocket.closed.connect (on_closed);
|
||||
websocket.message.connect (on_message);
|
||||
}
|
||||
@@ -1090,12 +940,6 @@ namespace Frida {
|
||||
Memory.copy (buffer, recv_queue.data, n);
|
||||
recv_queue.remove_range (0, (uint) n);
|
||||
|
||||
if (recv_queue.len == 0) {
|
||||
#if HAVE_SOUP_WEBSOCKET_BACKPRESSURE
|
||||
resume_websocket_input ();
|
||||
#endif
|
||||
}
|
||||
|
||||
update_pending_io ();
|
||||
} else {
|
||||
if (state == OPEN)
|
||||
@@ -1109,21 +953,6 @@ namespace Frida {
|
||||
return n;
|
||||
}
|
||||
|
||||
#if HAVE_SOUP_WEBSOCKET_BACKPRESSURE
|
||||
private void resume_websocket_input () {
|
||||
if (main_context.is_owner ()) {
|
||||
websocket.resume_input ();
|
||||
} else {
|
||||
var source = new IdleSource ();
|
||||
source.set_callback (() => {
|
||||
websocket.resume_input ();
|
||||
return Source.REMOVE;
|
||||
});
|
||||
source.attach (main_context);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public override ssize_t write (uint8[] buffer) {
|
||||
with_state_lock (() => {
|
||||
send_queue.append (buffer);
|
||||
@@ -1177,9 +1006,6 @@ namespace Frida {
|
||||
private void on_message (int type, Bytes message) {
|
||||
with_state_lock (() => {
|
||||
recv_queue.append (message.get_data ());
|
||||
#if HAVE_SOUP_WEBSOCKET_BACKPRESSURE
|
||||
websocket.pause_input ();
|
||||
#endif
|
||||
update_pending_io ();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,336 @@
|
||||
namespace Frida {
|
||||
public abstract class VirtualStream : IOStream {
|
||||
public override InputStream input_stream {
|
||||
get {
|
||||
return _input_stream;
|
||||
}
|
||||
}
|
||||
|
||||
public override OutputStream output_stream {
|
||||
get {
|
||||
return _output_stream;
|
||||
}
|
||||
}
|
||||
|
||||
public IOCondition pending_io {
|
||||
get {
|
||||
lock (state)
|
||||
return _pending_io;
|
||||
}
|
||||
}
|
||||
|
||||
protected State state = OPEN;
|
||||
|
||||
private VirtualInputStream _input_stream;
|
||||
private VirtualOutputStream _output_stream;
|
||||
|
||||
private IOCondition _pending_io;
|
||||
|
||||
private Gee.Map<unowned Source, IOCondition> sources = new Gee.HashMap<unowned Source, IOCondition> ();
|
||||
|
||||
protected Cancellable io_cancellable = new Cancellable ();
|
||||
|
||||
protected MainContext main_context;
|
||||
|
||||
protected enum State {
|
||||
CREATED,
|
||||
OPENING,
|
||||
OPEN,
|
||||
CLOSED
|
||||
}
|
||||
|
||||
protected delegate void WorkFunc ();
|
||||
|
||||
construct {
|
||||
_input_stream = new VirtualInputStream (this);
|
||||
_output_stream = new VirtualOutputStream (this);
|
||||
|
||||
main_context = MainContext.ref_thread_default ();
|
||||
|
||||
state = query_initial_state ();
|
||||
_pending_io = query_events ();
|
||||
}
|
||||
|
||||
public override void dispose () {
|
||||
_output_stream.detach ();
|
||||
_input_stream.detach ();
|
||||
|
||||
io_cancellable.cancel ();
|
||||
|
||||
base.dispose ();
|
||||
}
|
||||
|
||||
protected virtual State query_initial_state () {
|
||||
return OPEN;
|
||||
}
|
||||
|
||||
protected abstract IOCondition query_events ();
|
||||
|
||||
public override bool close (GLib.Cancellable? cancellable) throws IOError {
|
||||
_close ();
|
||||
return true;
|
||||
}
|
||||
|
||||
public override async bool close_async (int io_priority, GLib.Cancellable? cancellable) throws IOError {
|
||||
_close ();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void _close () {
|
||||
if (main_context.is_owner ()) {
|
||||
do_close ();
|
||||
} else {
|
||||
var source = new IdleSource ();
|
||||
source.set_callback (() => {
|
||||
do_close ();
|
||||
return Source.REMOVE;
|
||||
});
|
||||
source.attach (main_context);
|
||||
}
|
||||
}
|
||||
|
||||
private void do_close () {
|
||||
if (state == CLOSED)
|
||||
return;
|
||||
|
||||
handle_close ();
|
||||
}
|
||||
|
||||
protected abstract void handle_close ();
|
||||
|
||||
public virtual void shutdown_read () throws IOError {
|
||||
}
|
||||
|
||||
public virtual void shutdown_write () throws IOError {
|
||||
}
|
||||
|
||||
public abstract ssize_t read (uint8[] buffer) throws IOError;
|
||||
|
||||
public abstract ssize_t write (uint8[] buffer) throws IOError;
|
||||
|
||||
protected void with_state_lock (WorkFunc func) {
|
||||
lock (state)
|
||||
func ();
|
||||
}
|
||||
|
||||
public void register_source (Source source, IOCondition condition) {
|
||||
lock (state)
|
||||
sources[source] = condition | IOCondition.ERR | IOCondition.HUP;
|
||||
}
|
||||
|
||||
public void unregister_source (Source source) {
|
||||
lock (state)
|
||||
sources.unset (source);
|
||||
}
|
||||
|
||||
protected virtual void update_pending_io () {
|
||||
lock (state) {
|
||||
_pending_io = query_events ();
|
||||
|
||||
foreach (var entry in sources.entries) {
|
||||
unowned Source source = entry.key;
|
||||
IOCondition c = entry.value;
|
||||
if ((_pending_io & c) != 0)
|
||||
source.set_ready_time (0);
|
||||
}
|
||||
}
|
||||
|
||||
notify_property ("pending-io");
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class VirtualInputStream : InputStream, PollableInputStream {
|
||||
private weak VirtualStream stream;
|
||||
|
||||
public VirtualInputStream (VirtualStream stream) {
|
||||
Object ();
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
internal void detach () {
|
||||
stream = null;
|
||||
}
|
||||
|
||||
public override bool close (Cancellable? cancellable) throws IOError {
|
||||
if (stream != null)
|
||||
stream.shutdown_read ();
|
||||
return true;
|
||||
}
|
||||
|
||||
public override async bool close_async (int io_priority, Cancellable? cancellable) throws GLib.IOError {
|
||||
return close (cancellable);
|
||||
}
|
||||
|
||||
public override ssize_t read (uint8[] buffer, Cancellable? cancellable) throws IOError {
|
||||
if (stream == null)
|
||||
return 0;
|
||||
|
||||
if (!is_readable ()) {
|
||||
bool done = false;
|
||||
var mutex = Mutex ();
|
||||
var cond = Cond ();
|
||||
|
||||
ulong io_handler = stream.notify["pending-io"].connect ((obj, pspec) => {
|
||||
if (is_readable ()) {
|
||||
mutex.lock ();
|
||||
done = true;
|
||||
cond.signal ();
|
||||
mutex.unlock ();
|
||||
}
|
||||
});
|
||||
ulong cancellation_handler = 0;
|
||||
if (cancellable != null) {
|
||||
cancellation_handler = cancellable.connect (() => {
|
||||
mutex.lock ();
|
||||
done = true;
|
||||
cond.signal ();
|
||||
mutex.unlock ();
|
||||
});
|
||||
}
|
||||
|
||||
if (!is_readable ()) {
|
||||
mutex.lock ();
|
||||
while (!done)
|
||||
cond.wait (mutex);
|
||||
mutex.unlock ();
|
||||
}
|
||||
|
||||
if (cancellation_handler != 0)
|
||||
cancellable.disconnect (cancellation_handler);
|
||||
stream.disconnect (io_handler);
|
||||
|
||||
cancellable.set_error_if_cancelled ();
|
||||
}
|
||||
|
||||
return stream.read (buffer);
|
||||
}
|
||||
|
||||
public bool can_poll () {
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool is_readable () {
|
||||
if (stream == null)
|
||||
return true;
|
||||
return (stream.pending_io & IOCondition.IN) != 0;
|
||||
}
|
||||
|
||||
public PollableSource create_source (Cancellable? cancellable) {
|
||||
return new PollableSource.full (this, new VirtualIOSource (stream, IOCondition.IN), cancellable);
|
||||
}
|
||||
|
||||
public ssize_t read_nonblocking_fn (uint8[] buffer) throws GLib.Error {
|
||||
if (stream == null)
|
||||
return 0;
|
||||
return stream.read (buffer);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class VirtualOutputStream : OutputStream, PollableOutputStream {
|
||||
private weak VirtualStream? stream;
|
||||
|
||||
public VirtualOutputStream (VirtualStream stream) {
|
||||
Object ();
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
internal void detach () {
|
||||
stream = null;
|
||||
}
|
||||
|
||||
public override bool close (Cancellable? cancellable) throws IOError {
|
||||
if (stream != null)
|
||||
stream.shutdown_write ();
|
||||
return true;
|
||||
}
|
||||
|
||||
public override async bool close_async (int io_priority, Cancellable? cancellable) throws GLib.IOError {
|
||||
return close (cancellable);
|
||||
}
|
||||
|
||||
public override bool flush (GLib.Cancellable? cancellable) throws GLib.Error {
|
||||
return true;
|
||||
}
|
||||
|
||||
public override async bool flush_async (int io_priority, GLib.Cancellable? cancellable) throws GLib.Error {
|
||||
return true;
|
||||
}
|
||||
|
||||
public override ssize_t write (uint8[] buffer, Cancellable? cancellable) throws IOError {
|
||||
return stream.write (buffer);
|
||||
}
|
||||
|
||||
public bool can_poll () {
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool is_writable () {
|
||||
if (stream == null)
|
||||
return false;
|
||||
return (stream.pending_io & IOCondition.OUT) != 0;
|
||||
}
|
||||
|
||||
public PollableSource create_source (Cancellable? cancellable) {
|
||||
return new PollableSource.full (this, new VirtualIOSource (stream, IOCondition.OUT), cancellable);
|
||||
}
|
||||
|
||||
public ssize_t write_nonblocking_fn (uint8[]? buffer) throws GLib.Error {
|
||||
if (stream == null)
|
||||
throw new IOError.CLOSED ("Virtual is closed");
|
||||
return stream.write (buffer);
|
||||
}
|
||||
|
||||
public PollableReturn writev_nonblocking_fn (OutputVector[] vectors, out size_t bytes_written) throws GLib.Error {
|
||||
assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
private class VirtualIOSource : Source {
|
||||
public VirtualStream? stream;
|
||||
public IOCondition condition;
|
||||
|
||||
public VirtualIOSource (VirtualStream stream, IOCondition condition) {
|
||||
this.stream = stream;
|
||||
this.condition = condition;
|
||||
|
||||
if (stream != null)
|
||||
stream.register_source (this, condition);
|
||||
}
|
||||
|
||||
~VirtualIOSource () {
|
||||
if (stream != null)
|
||||
stream.unregister_source (this);
|
||||
}
|
||||
|
||||
protected override bool prepare (out int timeout) {
|
||||
timeout = -1;
|
||||
return is_ready ();
|
||||
}
|
||||
|
||||
protected override bool check () {
|
||||
return is_ready ();
|
||||
}
|
||||
|
||||
private bool is_ready () {
|
||||
IOCondition pending_io = (stream != null) ? stream.pending_io : IOCondition.IN;
|
||||
return (pending_io & condition) != 0;
|
||||
}
|
||||
|
||||
protected override bool dispatch (SourceFunc? callback) {
|
||||
set_ready_time (-1);
|
||||
|
||||
if (callback == null)
|
||||
return Source.REMOVE;
|
||||
|
||||
return callback ();
|
||||
}
|
||||
|
||||
protected static bool closure_callback (Closure closure) {
|
||||
var return_value = Value (typeof (bool));
|
||||
|
||||
closure.invoke (ref return_value, {});
|
||||
|
||||
return return_value.get_boolean ();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,407 @@
|
||||
namespace Frida {
|
||||
public interface ObjectBuilder : Object {
|
||||
public abstract unowned ObjectBuilder begin_dictionary ();
|
||||
public abstract unowned ObjectBuilder set_member_name (string name);
|
||||
public abstract unowned ObjectBuilder end_dictionary ();
|
||||
|
||||
public abstract unowned ObjectBuilder begin_array ();
|
||||
public abstract unowned ObjectBuilder end_array ();
|
||||
|
||||
public abstract unowned ObjectBuilder add_null_value ();
|
||||
public abstract unowned ObjectBuilder add_bool_value (bool val);
|
||||
public abstract unowned ObjectBuilder add_int64_value (int64 val);
|
||||
public abstract unowned ObjectBuilder add_uint64_value (uint64 val);
|
||||
public abstract unowned ObjectBuilder add_data_value (Bytes val);
|
||||
public abstract unowned ObjectBuilder add_string_value (string val);
|
||||
public abstract unowned ObjectBuilder add_uuid_value (uint8[] val);
|
||||
public abstract unowned ObjectBuilder add_raw_value (Bytes val);
|
||||
|
||||
public abstract Bytes build ();
|
||||
}
|
||||
|
||||
public interface ObjectReader : Object {
|
||||
public abstract bool has_member (string name) throws Error;
|
||||
public abstract unowned ObjectReader read_member (string name) throws Error;
|
||||
public abstract unowned ObjectReader end_member ();
|
||||
|
||||
public abstract uint count_elements () throws Error;
|
||||
public abstract unowned ObjectReader read_element (uint index) throws Error;
|
||||
public abstract unowned ObjectReader end_element () throws Error;
|
||||
|
||||
public abstract bool get_bool_value () throws Error;
|
||||
public abstract uint8 get_uint8_value () throws Error;
|
||||
public abstract uint16 get_uint16_value () throws Error;
|
||||
public abstract int64 get_int64_value () throws Error;
|
||||
public abstract uint64 get_uint64_value () throws Error;
|
||||
public abstract Bytes get_data_value () throws Error;
|
||||
public abstract unowned string get_string_value () throws Error;
|
||||
public abstract unowned string get_uuid_value () throws Error;
|
||||
}
|
||||
|
||||
public sealed class VariantReader : Object, ObjectReader {
|
||||
public Variant root_object {
|
||||
get {
|
||||
return scopes.peek_head ().val;
|
||||
}
|
||||
}
|
||||
|
||||
public Variant current_object {
|
||||
get {
|
||||
return scopes.peek_tail ().val;
|
||||
}
|
||||
}
|
||||
|
||||
private Gee.Deque<Scope> scopes = new Gee.ArrayQueue<Scope> ();
|
||||
|
||||
public VariantReader (Variant v) {
|
||||
push_scope (v);
|
||||
}
|
||||
|
||||
public string[] list_members () throws Error {
|
||||
var scope = peek_scope ();
|
||||
if (scope.dict == null)
|
||||
throw new Error.PROTOCOL ("Dictionary expected, but at %s", scope.val.print (true));
|
||||
|
||||
var members = new Gee.ArrayList<string> ();
|
||||
foreach (var item in scope.val) {
|
||||
string k;
|
||||
Variant v;
|
||||
item.get ("{sv}", out k, out v);
|
||||
|
||||
members.add (k);
|
||||
}
|
||||
return members.to_array ();
|
||||
}
|
||||
|
||||
public bool has_member (string name) throws Error {
|
||||
var scope = peek_scope ();
|
||||
if (scope.dict == null)
|
||||
throw new Error.PROTOCOL ("Dictionary expected, but at %s", scope.val.print (true));
|
||||
return scope.dict.contains (name);
|
||||
}
|
||||
|
||||
public unowned ObjectReader read_member (string name) throws Error {
|
||||
var scope = peek_scope ();
|
||||
if (scope.dict == null)
|
||||
throw new Error.PROTOCOL ("Dictionary expected, but at %s", scope.val.print (true));
|
||||
|
||||
Variant? v = scope.dict.lookup_value (name, null);
|
||||
if (v == null)
|
||||
throw new Error.PROTOCOL ("Key '%s' not found in dictionary: %s", name, scope.val.print (true));
|
||||
|
||||
push_scope (v);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned ObjectReader end_member () {
|
||||
pop_scope ();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public uint count_elements () throws Error {
|
||||
var scope = peek_scope ();
|
||||
scope.check_array ();
|
||||
return (uint) scope.val.n_children ();
|
||||
}
|
||||
|
||||
public unowned ObjectReader read_element (uint index) throws Error {
|
||||
var scope = peek_scope ();
|
||||
scope.check_array ();
|
||||
push_scope (scope.val.get_child_value (index).get_variant ());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned ObjectReader end_element () throws Error {
|
||||
pop_scope ();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public bool get_bool_value () throws Error {
|
||||
return peek_scope ().get_value (VariantType.BOOLEAN).get_boolean ();
|
||||
}
|
||||
|
||||
public uint8 get_uint8_value () throws Error {
|
||||
return peek_scope ().get_value (VariantType.BYTE).get_byte ();
|
||||
}
|
||||
|
||||
public uint16 get_uint16_value () throws Error {
|
||||
return peek_scope ().get_value (VariantType.UINT16).get_uint16 ();
|
||||
}
|
||||
|
||||
public int64 get_int64_value () throws Error {
|
||||
return peek_scope ().get_value (VariantType.INT64).get_int64 ();
|
||||
}
|
||||
|
||||
public uint64 get_uint64_value () throws Error {
|
||||
return peek_scope ().get_value (VariantType.UINT64).get_uint64 ();
|
||||
}
|
||||
|
||||
public Bytes get_data_value () throws Error {
|
||||
return peek_scope ().get_value (new VariantType.array (VariantType.BYTE)).get_data_as_bytes ();
|
||||
}
|
||||
|
||||
public unowned string get_string_value () throws Error {
|
||||
return peek_scope ().get_value (VariantType.STRING).get_string ();
|
||||
}
|
||||
|
||||
public unowned string get_uuid_value () throws Error {
|
||||
return peek_scope ().get_value (VariantType.STRING).get_string (); // TODO: Use a tuple to avoid ambiguity.
|
||||
}
|
||||
|
||||
private void push_scope (Variant v) {
|
||||
scopes.offer_tail (new Scope (v));
|
||||
}
|
||||
|
||||
private Scope peek_scope () {
|
||||
return scopes.peek_tail ();
|
||||
}
|
||||
|
||||
private Scope pop_scope () {
|
||||
return scopes.poll_tail ();
|
||||
}
|
||||
|
||||
private class Scope {
|
||||
public Variant val;
|
||||
public VariantDict? dict;
|
||||
public bool is_array = false;
|
||||
|
||||
public Scope (Variant v) {
|
||||
val = v;
|
||||
|
||||
VariantType t = v.get_type ();
|
||||
if (t.equal (VariantType.VARDICT))
|
||||
dict = new VariantDict (v);
|
||||
else if (t.is_subtype_of (VariantType.ARRAY))
|
||||
is_array = true;
|
||||
}
|
||||
|
||||
public Variant get_value (VariantType expected_type) throws Error {
|
||||
if (!val.get_type ().equal (expected_type)) {
|
||||
throw new Error.PROTOCOL ("Expected type '%s', got '%s'",
|
||||
(string) expected_type.peek_string (),
|
||||
(string) val.get_type ().peek_string ());
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
public void check_array () throws Error {
|
||||
if (!is_array)
|
||||
throw new Error.PROTOCOL ("Array expected, but at %s", val.print (true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class JsonObjectBuilder : Object, ObjectBuilder {
|
||||
private Json.Builder builder = new Json.Builder ();
|
||||
private Gee.Map<string, Bytes> raw_values = new Gee.HashMap<string, Bytes> ();
|
||||
|
||||
public unowned ObjectBuilder begin_dictionary () {
|
||||
builder.begin_object ();
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned ObjectBuilder set_member_name (string name) {
|
||||
builder.set_member_name (name);
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned ObjectBuilder end_dictionary () {
|
||||
builder.end_object ();
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned ObjectBuilder begin_array () {
|
||||
builder.begin_array ();
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned ObjectBuilder end_array () {
|
||||
builder.end_array ();
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned ObjectBuilder add_null_value () {
|
||||
builder.add_null_value ();
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned ObjectBuilder add_bool_value (bool val) {
|
||||
builder.add_boolean_value (val);
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned ObjectBuilder add_int64_value (int64 val) {
|
||||
builder.add_int_value (val);
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned ObjectBuilder add_uint64_value (uint64 val) {
|
||||
builder.add_int_value ((int64) val);
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned ObjectBuilder add_data_value (Bytes val) {
|
||||
builder.add_string_value (Base64.encode (val.get_data ()));
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned ObjectBuilder add_string_value (string val) {
|
||||
builder.add_string_value (val);
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned ObjectBuilder add_uuid_value (uint8[] val) {
|
||||
assert_not_reached ();
|
||||
}
|
||||
|
||||
public unowned ObjectBuilder add_raw_value (Bytes val) {
|
||||
string uuid = Uuid.string_random ();
|
||||
builder.add_string_value (uuid);
|
||||
raw_values[uuid] = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Bytes build () {
|
||||
string json = Json.to_string (builder.get_root (), false);
|
||||
|
||||
foreach (var e in raw_values.entries) {
|
||||
unowned string uuid = e.key;
|
||||
Bytes val = e.value;
|
||||
|
||||
unowned string raw_str = (string) val.get_data ();
|
||||
string str = raw_str[:(long) val.get_size ()];
|
||||
|
||||
json = json.replace ("\"" + uuid + "\"", str);
|
||||
}
|
||||
|
||||
return new Bytes (json.data);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class JsonObjectReader : Object, ObjectReader {
|
||||
private Json.Reader reader;
|
||||
|
||||
public JsonObjectReader (string json) throws Error {
|
||||
try {
|
||||
reader = new Json.Reader (Json.from_string (json));
|
||||
} catch (GLib.Error e) {
|
||||
throw new Error.INVALID_ARGUMENT ("%s", e.message);
|
||||
}
|
||||
}
|
||||
|
||||
public bool has_member (string name) throws Error {
|
||||
bool result = reader.read_member (name);
|
||||
reader.end_member ();
|
||||
return result;
|
||||
}
|
||||
|
||||
public unowned ObjectReader read_member (string name) throws Error {
|
||||
if (!reader.read_member (name))
|
||||
throw_dict_access_error ();
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned ObjectReader end_member () {
|
||||
reader.end_member ();
|
||||
return this;
|
||||
}
|
||||
|
||||
[NoReturn]
|
||||
private void throw_dict_access_error () throws Error {
|
||||
GLib.Error e = reader.get_error ();
|
||||
reader.end_member ();
|
||||
throw new Error.PROTOCOL ("%s", e.message);
|
||||
}
|
||||
|
||||
public uint count_elements () throws Error {
|
||||
int n = reader.count_elements ();
|
||||
if (n == -1)
|
||||
throw_array_access_error ();
|
||||
return n;
|
||||
}
|
||||
|
||||
public unowned ObjectReader read_element (uint index) throws Error {
|
||||
if (!reader.read_element (index)) {
|
||||
GLib.Error e = reader.get_error ();
|
||||
reader.end_element ();
|
||||
throw new Error.PROTOCOL ("%s", e.message);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned ObjectReader end_element () throws Error {
|
||||
reader.end_element ();
|
||||
return this;
|
||||
}
|
||||
|
||||
[NoReturn]
|
||||
private void throw_array_access_error () throws Error {
|
||||
GLib.Error e = reader.get_error ();
|
||||
reader.end_element ();
|
||||
throw new Error.PROTOCOL ("%s", e.message);
|
||||
}
|
||||
|
||||
public bool get_bool_value () throws Error {
|
||||
bool v = reader.get_boolean_value ();
|
||||
if (!v)
|
||||
maybe_throw_value_access_error ();
|
||||
return v;
|
||||
}
|
||||
|
||||
public uint8 get_uint8_value () throws Error {
|
||||
int64 v = get_int64_value ();
|
||||
if (v < 0 || v > uint8.MAX)
|
||||
throw new Error.PROTOCOL ("Invalid uint8");
|
||||
return (uint8) v;
|
||||
}
|
||||
|
||||
public uint16 get_uint16_value () throws Error {
|
||||
int64 v = get_int64_value ();
|
||||
if (v < 0 || v > uint16.MAX)
|
||||
throw new Error.PROTOCOL ("Invalid uint16");
|
||||
return (uint16) v;
|
||||
}
|
||||
|
||||
public int64 get_int64_value () throws Error {
|
||||
int64 v = reader.get_int_value ();
|
||||
if (v == 0)
|
||||
maybe_throw_value_access_error ();
|
||||
return v;
|
||||
}
|
||||
|
||||
public uint64 get_uint64_value () throws Error {
|
||||
int64 v = get_int64_value ();
|
||||
if (v < 0)
|
||||
throw new Error.PROTOCOL ("Invalid uint64");
|
||||
return v;
|
||||
}
|
||||
|
||||
public Bytes get_data_value () throws Error {
|
||||
return new Bytes (Base64.decode (get_string_value ()));
|
||||
}
|
||||
|
||||
public unowned string get_string_value () throws Error {
|
||||
unowned string? v = reader.get_string_value ();
|
||||
if (v == null)
|
||||
maybe_throw_value_access_error ();
|
||||
return v;
|
||||
}
|
||||
|
||||
public unowned string get_uuid_value () throws Error {
|
||||
return get_string_value ();
|
||||
}
|
||||
|
||||
private void maybe_throw_value_access_error () throws Error {
|
||||
GLib.Error? e = reader.get_error ();
|
||||
if (e == null)
|
||||
return;
|
||||
reader.end_member ();
|
||||
throw new Error.PROTOCOL ("%s", e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,376 +0,0 @@
|
||||
#include "frida-base.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#define FRIDA_TYPE_WINDOWS_HANDLE_STREAM (frida_windows_handle_stream_get_type ())
|
||||
#define FRIDA_TYPE_WINDOWS_HANDLE_INPUT_STREAM (frida_windows_handle_input_stream_get_type ())
|
||||
#define FRIDA_TYPE_WINDOWS_HANDLE_OUTPUT_STREAM (frida_windows_handle_output_stream_get_type ())
|
||||
|
||||
#define FRIDA_WINDOWS_HANDLE_STREAM(o) ((FridaWindowsHandleStream *) (o))
|
||||
#define FRIDA_WINDOWS_HANDLE_INPUT_STREAM(o) ((FridaWindowsHandleInputStream *) (o))
|
||||
#define FRIDA_WINDOWS_HANDLE_OUTPUT_STREAM(o) ((FridaWindowsHandleOutputStream *) (o))
|
||||
|
||||
typedef struct _FridaWindowsHandleStream FridaWindowsHandleStream;
|
||||
typedef struct _FridaWindowsHandleStreamClass FridaWindowsHandleStreamClass;
|
||||
typedef struct _FridaWindowsHandleInputStream FridaWindowsHandleInputStream;
|
||||
typedef struct _FridaWindowsHandleInputStreamClass FridaWindowsHandleInputStreamClass;
|
||||
typedef struct _FridaWindowsHandleOutputStream FridaWindowsHandleOutputStream;
|
||||
typedef struct _FridaWindowsHandleOutputStreamClass FridaWindowsHandleOutputStreamClass;
|
||||
|
||||
struct _FridaWindowsHandleStream
|
||||
{
|
||||
GIOStream parent;
|
||||
|
||||
HANDLE handle;
|
||||
HANDLE read_complete;
|
||||
HANDLE read_cancel;
|
||||
HANDLE write_complete;
|
||||
HANDLE write_cancel;
|
||||
|
||||
GInputStream * input;
|
||||
GOutputStream * output;
|
||||
};
|
||||
|
||||
struct _FridaWindowsHandleStreamClass
|
||||
{
|
||||
GIOStreamClass parent_class;
|
||||
};
|
||||
|
||||
struct _FridaWindowsHandleInputStream
|
||||
{
|
||||
GInputStream parent;
|
||||
|
||||
FridaWindowsHandleStream * stream;
|
||||
};
|
||||
|
||||
struct _FridaWindowsHandleInputStreamClass
|
||||
{
|
||||
GInputStreamClass parent_class;
|
||||
};
|
||||
|
||||
struct _FridaWindowsHandleOutputStream
|
||||
{
|
||||
GOutputStream parent;
|
||||
|
||||
FridaWindowsHandleStream * stream;
|
||||
};
|
||||
|
||||
struct _FridaWindowsHandleOutputStreamClass
|
||||
{
|
||||
GOutputStreamClass parent_class;
|
||||
};
|
||||
|
||||
static GIOStream * frida_windows_handle_stream_new (HANDLE handle);
|
||||
|
||||
static void frida_windows_handle_stream_finalize (GObject * object);
|
||||
static GInputStream * frida_windows_handle_stream_get_input_stream (GIOStream * stream);
|
||||
static GOutputStream * frida_windows_handle_stream_get_output_stream (GIOStream * stream);
|
||||
static gboolean frida_windows_handle_stream_close_fn (GIOStream * stream, GCancellable * cancellable, GError ** error);
|
||||
|
||||
static gssize frida_windows_handle_input_stream_read (GInputStream * base, void * buffer, gsize count,
|
||||
GCancellable * cancellable, GError ** error);
|
||||
static gboolean frida_windows_handle_input_stream_close (GInputStream * base, GCancellable * cancellable, GError ** error);
|
||||
|
||||
static gssize frida_windows_handle_output_stream_write (GOutputStream * base, const void * buffer, gsize count,
|
||||
GCancellable * cancellable, GError ** error);
|
||||
static gboolean frida_windows_handle_output_stream_close (GOutputStream * base, GCancellable * cancellable,
|
||||
GError ** error);
|
||||
|
||||
static gboolean frida_windows_handle_stream_await (FridaWindowsHandleStream * self, HANDLE complete, HANDLE cancel,
|
||||
GCancellable * cancellable, GError ** error);
|
||||
static void frida_windows_handle_stream_on_cancel (GCancellable * cancellable, gpointer user_data);
|
||||
|
||||
G_DEFINE_TYPE (FridaWindowsHandleStream, frida_windows_handle_stream, G_TYPE_IO_STREAM)
|
||||
G_DEFINE_TYPE (FridaWindowsHandleInputStream, frida_windows_handle_input_stream, G_TYPE_INPUT_STREAM)
|
||||
G_DEFINE_TYPE (FridaWindowsHandleOutputStream, frida_windows_handle_output_stream, G_TYPE_OUTPUT_STREAM)
|
||||
|
||||
GIOStream *
|
||||
frida_windows_named_pipe_open_client (const gchar * path, GError ** error)
|
||||
{
|
||||
HANDLE handle;
|
||||
WCHAR * path_utf16;
|
||||
DWORD last_error;
|
||||
|
||||
path_utf16 = (WCHAR *) g_utf8_to_utf16 (path, -1, NULL, NULL, NULL);
|
||||
if (path_utf16 == NULL)
|
||||
goto invalid_path;
|
||||
|
||||
handle = CreateFileW (path_utf16,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_OVERLAPPED,
|
||||
NULL);
|
||||
last_error = GetLastError ();
|
||||
g_free (path_utf16);
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
goto cannot_open;
|
||||
|
||||
return frida_windows_handle_stream_new (handle);
|
||||
|
||||
invalid_path:
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Invalid pipe path");
|
||||
return NULL;
|
||||
}
|
||||
cannot_open:
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
g_io_error_from_win32_error (last_error),
|
||||
"Unable to open %s (CreateFile returned 0x%08lx)",
|
||||
path, last_error);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static GIOStream *
|
||||
frida_windows_handle_stream_new (HANDLE handle)
|
||||
{
|
||||
FridaWindowsHandleStream * stream;
|
||||
FridaWindowsHandleInputStream * input;
|
||||
FridaWindowsHandleOutputStream * output;
|
||||
|
||||
stream = g_object_new (FRIDA_TYPE_WINDOWS_HANDLE_STREAM, NULL);
|
||||
stream->handle = handle;
|
||||
stream->read_complete = CreateEvent (NULL, TRUE, FALSE, NULL);
|
||||
stream->read_cancel = CreateEvent (NULL, TRUE, FALSE, NULL);
|
||||
stream->write_complete = CreateEvent (NULL, TRUE, FALSE, NULL);
|
||||
stream->write_cancel = CreateEvent (NULL, TRUE, FALSE, NULL);
|
||||
|
||||
input = g_object_new (FRIDA_TYPE_WINDOWS_HANDLE_INPUT_STREAM, NULL);
|
||||
input->stream = stream;
|
||||
stream->input = G_INPUT_STREAM (input);
|
||||
|
||||
output = g_object_new (FRIDA_TYPE_WINDOWS_HANDLE_OUTPUT_STREAM, NULL);
|
||||
output->stream = stream;
|
||||
stream->output = G_OUTPUT_STREAM (output);
|
||||
|
||||
return G_IO_STREAM (stream);
|
||||
}
|
||||
|
||||
static void
|
||||
frida_windows_handle_stream_class_init (FridaWindowsHandleStreamClass * klass)
|
||||
{
|
||||
GObjectClass * object_class = G_OBJECT_CLASS (klass);
|
||||
GIOStreamClass * stream_class = G_IO_STREAM_CLASS (klass);
|
||||
|
||||
object_class->finalize = frida_windows_handle_stream_finalize;
|
||||
|
||||
stream_class->get_input_stream = frida_windows_handle_stream_get_input_stream;
|
||||
stream_class->get_output_stream = frida_windows_handle_stream_get_output_stream;
|
||||
stream_class->close_fn = frida_windows_handle_stream_close_fn;
|
||||
}
|
||||
|
||||
static void
|
||||
frida_windows_handle_stream_init (FridaWindowsHandleStream * self)
|
||||
{
|
||||
self->handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
static void
|
||||
frida_windows_handle_stream_finalize (GObject * object)
|
||||
{
|
||||
FridaWindowsHandleStream * self = FRIDA_WINDOWS_HANDLE_STREAM (object);
|
||||
|
||||
g_clear_object (&self->input);
|
||||
g_clear_object (&self->output);
|
||||
|
||||
CloseHandle (self->read_complete);
|
||||
CloseHandle (self->read_cancel);
|
||||
CloseHandle (self->write_complete);
|
||||
CloseHandle (self->write_cancel);
|
||||
|
||||
if (self->handle != INVALID_HANDLE_VALUE)
|
||||
CloseHandle (self->handle);
|
||||
|
||||
G_OBJECT_CLASS (frida_windows_handle_stream_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static GInputStream *
|
||||
frida_windows_handle_stream_get_input_stream (GIOStream * stream)
|
||||
{
|
||||
return FRIDA_WINDOWS_HANDLE_STREAM (stream)->input;
|
||||
}
|
||||
|
||||
static GOutputStream *
|
||||
frida_windows_handle_stream_get_output_stream (GIOStream * stream)
|
||||
{
|
||||
return FRIDA_WINDOWS_HANDLE_STREAM (stream)->output;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
frida_windows_handle_stream_close_fn (GIOStream * stream, GCancellable * cancellable, GError ** error)
|
||||
{
|
||||
FridaWindowsHandleStream * self = FRIDA_WINDOWS_HANDLE_STREAM (stream);
|
||||
|
||||
SetEvent (self->read_cancel);
|
||||
SetEvent (self->write_cancel);
|
||||
|
||||
if (self->handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CancelIo (self->handle);
|
||||
CloseHandle (self->handle);
|
||||
self->handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
frida_windows_handle_input_stream_class_init (FridaWindowsHandleInputStreamClass * klass)
|
||||
{
|
||||
GInputStreamClass * stream_class = G_INPUT_STREAM_CLASS (klass);
|
||||
|
||||
stream_class->read_fn = frida_windows_handle_input_stream_read;
|
||||
stream_class->close_fn = frida_windows_handle_input_stream_close;
|
||||
}
|
||||
|
||||
static void
|
||||
frida_windows_handle_input_stream_init (FridaWindowsHandleInputStream * self)
|
||||
{
|
||||
}
|
||||
|
||||
static gssize
|
||||
frida_windows_handle_input_stream_read (GInputStream * base, void * buffer, gsize count, GCancellable * cancellable,
|
||||
GError ** error)
|
||||
{
|
||||
FridaWindowsHandleStream * stream = FRIDA_WINDOWS_HANDLE_INPUT_STREAM (base)->stream;
|
||||
OVERLAPPED overlapped = { 0, };
|
||||
DWORD bytes_transferred, last_error;
|
||||
|
||||
if (stream->handle == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
overlapped.hEvent = stream->read_complete;
|
||||
if (!ReadFile (stream->handle, buffer, count, NULL, &overlapped) && GetLastError () != ERROR_IO_PENDING)
|
||||
goto failure;
|
||||
|
||||
if (!frida_windows_handle_stream_await (stream, stream->read_complete, stream->read_cancel, cancellable, error))
|
||||
return -1;
|
||||
|
||||
if (!GetOverlappedResult (stream->handle, &overlapped, &bytes_transferred, FALSE))
|
||||
goto failure;
|
||||
|
||||
return bytes_transferred;
|
||||
|
||||
failure:
|
||||
{
|
||||
last_error = GetLastError ();
|
||||
if (last_error == ERROR_BROKEN_PIPE || last_error == ERROR_PIPE_NOT_CONNECTED)
|
||||
return 0;
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
g_io_error_from_win32_error (last_error),
|
||||
"Error reading from pipe");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
frida_windows_handle_input_stream_close (GInputStream * base, GCancellable * cancellable, GError ** error)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
frida_windows_handle_output_stream_class_init (FridaWindowsHandleOutputStreamClass * klass)
|
||||
{
|
||||
GOutputStreamClass * stream_class = G_OUTPUT_STREAM_CLASS (klass);
|
||||
|
||||
stream_class->write_fn = frida_windows_handle_output_stream_write;
|
||||
stream_class->close_fn = frida_windows_handle_output_stream_close;
|
||||
}
|
||||
|
||||
static void
|
||||
frida_windows_handle_output_stream_init (FridaWindowsHandleOutputStream * self)
|
||||
{
|
||||
}
|
||||
|
||||
static gssize
|
||||
frida_windows_handle_output_stream_write (GOutputStream * base, const void * buffer, gsize count,
|
||||
GCancellable * cancellable, GError ** error)
|
||||
{
|
||||
FridaWindowsHandleStream * stream = FRIDA_WINDOWS_HANDLE_OUTPUT_STREAM (base)->stream;
|
||||
OVERLAPPED overlapped = { 0, };
|
||||
DWORD bytes_transferred, last_error;
|
||||
|
||||
if (stream->handle == INVALID_HANDLE_VALUE)
|
||||
goto closed;
|
||||
|
||||
overlapped.hEvent = stream->write_complete;
|
||||
if (!WriteFile (stream->handle, buffer, count, NULL, &overlapped) && GetLastError () != ERROR_IO_PENDING)
|
||||
goto failure;
|
||||
|
||||
if (!frida_windows_handle_stream_await (stream, stream->write_complete, stream->write_cancel, cancellable, error))
|
||||
return -1;
|
||||
|
||||
if (!GetOverlappedResult (stream->handle, &overlapped, &bytes_transferred, FALSE))
|
||||
goto failure;
|
||||
|
||||
return bytes_transferred;
|
||||
|
||||
closed:
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED, "Pipe is closed");
|
||||
return -1;
|
||||
}
|
||||
failure:
|
||||
{
|
||||
last_error = GetLastError ();
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
g_io_error_from_win32_error (last_error),
|
||||
"Error writing to pipe");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
frida_windows_handle_output_stream_close (GOutputStream * base, GCancellable * cancellable, GError ** error)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
frida_windows_handle_stream_await (FridaWindowsHandleStream * self, HANDLE complete, HANDLE cancel,
|
||||
GCancellable * cancellable, GError ** error)
|
||||
{
|
||||
gulong handler_id = 0;
|
||||
HANDLE events[2];
|
||||
|
||||
if (cancellable != NULL)
|
||||
handler_id = g_cancellable_connect (cancellable, G_CALLBACK (frida_windows_handle_stream_on_cancel), cancel, NULL);
|
||||
|
||||
events[0] = complete;
|
||||
events[1] = cancel;
|
||||
WaitForMultipleObjects (G_N_ELEMENTS (events), events, FALSE, INFINITE);
|
||||
|
||||
if (cancellable != NULL)
|
||||
{
|
||||
g_cancellable_disconnect (cancellable, handler_id);
|
||||
if (g_cancellable_set_error_if_cancelled (cancellable, error))
|
||||
{
|
||||
CancelIo (self->handle);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (WaitForSingleObject (cancel, 0) == WAIT_OBJECT_0)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED, "Pipe is closed");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
frida_windows_handle_stream_on_cancel (GCancellable * cancellable, gpointer user_data)
|
||||
{
|
||||
HANDLE cancel = (HANDLE) user_data;
|
||||
|
||||
SetEvent (cancel);
|
||||
}
|
||||
@@ -1,8 +1,4 @@
|
||||
namespace Frida {
|
||||
namespace WindowsNamedPipe {
|
||||
public extern IOStream open_client (string path) throws GLib.Error;
|
||||
}
|
||||
|
||||
public sealed class StdioPipes : Object {
|
||||
public OutputStream input {
|
||||
get;
|
||||
|
||||
@@ -1,860 +0,0 @@
|
||||
#!/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())
|
||||
@@ -1,542 +0,0 @@
|
||||
/* 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;
|
||||
}
|
||||
@@ -1,545 +0,0 @@
|
||||
// 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* The XNU Mach trap numbers, as used on Apple platforms.
|
||||
*/
|
||||
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,
|
||||
}
|
||||
|
||||
/**
|
||||
* The XNU BSD syscall numbers, as used on Apple platforms.
|
||||
*/
|
||||
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,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
namespace Frida {
|
||||
public sealed class XpcClient : Object {
|
||||
public signal void message (Darwin.Xpc.Object obj);
|
||||
|
||||
public State state {
|
||||
get {
|
||||
return _state;
|
||||
}
|
||||
}
|
||||
|
||||
public Darwin.Xpc.Connection connection {
|
||||
get;
|
||||
construct;
|
||||
}
|
||||
|
||||
public Darwin.GCD.DispatchQueue queue {
|
||||
get;
|
||||
construct;
|
||||
}
|
||||
|
||||
private State _state;
|
||||
private string? close_reason;
|
||||
private MainContext main_context;
|
||||
|
||||
public enum State {
|
||||
OPEN,
|
||||
CLOSING,
|
||||
CLOSED,
|
||||
}
|
||||
|
||||
public static XpcClient make_for_mach_service (string name, Darwin.GCD.DispatchQueue queue) {
|
||||
return new XpcClient (Darwin.Xpc.Connection.create_mach_service (name, queue, 0), queue);
|
||||
}
|
||||
|
||||
public XpcClient (Darwin.Xpc.Connection connection, Darwin.GCD.DispatchQueue queue) {
|
||||
Object (connection: connection, queue: queue);
|
||||
}
|
||||
|
||||
construct {
|
||||
main_context = MainContext.ref_thread_default ();
|
||||
|
||||
connection.set_event_handler (on_event);
|
||||
connection.activate ();
|
||||
}
|
||||
|
||||
public override void dispose () {
|
||||
if (close_reason != null) {
|
||||
change_state (CLOSED);
|
||||
} else {
|
||||
change_state (CLOSING);
|
||||
this.ref ();
|
||||
connection.cancel ();
|
||||
}
|
||||
|
||||
base.dispose ();
|
||||
}
|
||||
|
||||
public async Darwin.Xpc.Object request (Darwin.Xpc.Object message, Cancellable? cancellable) throws Error, IOError {
|
||||
Darwin.Xpc.Object? reply = null;
|
||||
connection.send_message_with_reply (message, queue, r => {
|
||||
schedule_on_frida_thread (() => {
|
||||
reply = r;
|
||||
request.callback ();
|
||||
return Source.REMOVE;
|
||||
});
|
||||
});
|
||||
|
||||
var cancel_source = new CancellableSource (cancellable);
|
||||
cancel_source.set_callback (() => {
|
||||
connection.cancel ();
|
||||
return Source.REMOVE;
|
||||
});
|
||||
cancel_source.attach (main_context);
|
||||
|
||||
yield;
|
||||
|
||||
cancel_source.destroy ();
|
||||
|
||||
if (reply.type == Darwin.Xpc.Error.TYPE) {
|
||||
var e = (Darwin.Xpc.Error) reply;
|
||||
throw new Error.NOT_SUPPORTED ("%s", e.get_string (Darwin.Xpc.Error.KEY_DESCRIPTION));
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
public void post (Darwin.Xpc.Object message) throws Error, IOError {
|
||||
connection.send_message (message);
|
||||
}
|
||||
|
||||
private void change_state (State new_state) {
|
||||
_state = new_state;
|
||||
notify_property ("state");
|
||||
}
|
||||
|
||||
private void on_event (Darwin.Xpc.Object obj) {
|
||||
schedule_on_frida_thread (() => {
|
||||
if (obj.type == Darwin.Xpc.Error.TYPE) {
|
||||
var e = (Darwin.Xpc.Error) obj;
|
||||
close_reason = e.get_string (Darwin.Xpc.Error.KEY_DESCRIPTION);
|
||||
switch (state) {
|
||||
case OPEN:
|
||||
change_state (CLOSED);
|
||||
break;
|
||||
case CLOSING:
|
||||
change_state (CLOSED);
|
||||
unref ();
|
||||
break;
|
||||
case CLOSED:
|
||||
assert_not_reached ();
|
||||
}
|
||||
} else {
|
||||
message (obj);
|
||||
}
|
||||
return Source.REMOVE;
|
||||
});
|
||||
}
|
||||
|
||||
private void schedule_on_frida_thread (owned SourceFunc function) {
|
||||
var source = new IdleSource ();
|
||||
source.set_callback ((owned) function);
|
||||
source.attach (main_context);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class XpcObjectReader {
|
||||
public Darwin.Xpc.Object root_object {
|
||||
get {
|
||||
return scopes.peek_head ().object;
|
||||
}
|
||||
}
|
||||
|
||||
public Darwin.Xpc.Object current_object {
|
||||
get {
|
||||
return scopes.peek_tail ().object;
|
||||
}
|
||||
}
|
||||
|
||||
public delegate int TranslateErrorFunc (string domain, int code, string description);
|
||||
|
||||
private Gee.Deque<Scope> scopes = new Gee.ArrayQueue<Scope> ();
|
||||
|
||||
public XpcObjectReader (Darwin.Xpc.Object obj) {
|
||||
push_scope (obj);
|
||||
}
|
||||
|
||||
public bool has_member (string name) throws Error {
|
||||
return peek_scope ().get_dictionary ().get_value (name) != null;
|
||||
}
|
||||
|
||||
public bool try_read_member (string name) throws Error {
|
||||
var scope = peek_scope ();
|
||||
var dict = scope.get_dictionary ();
|
||||
var val = dict.get_value (name);
|
||||
if (val == null)
|
||||
return false;
|
||||
|
||||
push_scope (val);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public unowned XpcObjectReader read_member (string name) throws Error {
|
||||
var scope = peek_scope ();
|
||||
var dict = scope.get_dictionary ();
|
||||
var val = dict.get_value (name);
|
||||
if (val == null)
|
||||
throw new Error.PROTOCOL ("Key '%s' not found in dictionary: %s", name, scope.object.to_string ());
|
||||
|
||||
push_scope (val);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned XpcObjectReader end_member () {
|
||||
pop_scope ();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public size_t count_elements () throws Error {
|
||||
return peek_scope ().get_array ().count;
|
||||
}
|
||||
|
||||
public unowned XpcObjectReader read_element (size_t index) throws Error {
|
||||
push_scope (peek_scope ().get_array ().get_value (index));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public unowned XpcObjectReader end_element () throws Error {
|
||||
pop_scope ();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public bool get_bool_value () throws Error {
|
||||
return peek_scope ().get_object<Darwin.Xpc.Bool> (Darwin.Xpc.Bool.TYPE).get_value ();
|
||||
}
|
||||
|
||||
public int64 get_int64_value () throws Error {
|
||||
return peek_scope ().get_object<Darwin.Xpc.Int64> (Darwin.Xpc.Int64.TYPE).get_value ();
|
||||
}
|
||||
|
||||
public uint64 get_uint64_value () throws Error {
|
||||
return peek_scope ().get_object<Darwin.Xpc.UInt64> (Darwin.Xpc.UInt64.TYPE).get_value ();
|
||||
}
|
||||
|
||||
public unowned uint8[] get_data_value () throws Error {
|
||||
var data = peek_scope ().get_object<Darwin.Xpc.Data> (Darwin.Xpc.Data.TYPE);
|
||||
unowned uint8[] buf = (uint8[]) data.get_bytes_ptr ();
|
||||
buf.length = (int) data.get_length ();
|
||||
return buf;
|
||||
}
|
||||
|
||||
public unowned string get_string_value () throws Error {
|
||||
return peek_scope ().get_object<Darwin.Xpc.String> (Darwin.Xpc.String.TYPE).get_string_ptr ();
|
||||
}
|
||||
|
||||
public unowned uint8[] get_uuid_value () throws Error {
|
||||
return peek_scope ().get_object<Darwin.Xpc.Uuid> (Darwin.Xpc.Uuid.TYPE).get_bytes ()[:16];
|
||||
}
|
||||
|
||||
public unowned string get_error_description () throws Error {
|
||||
var error = peek_scope ().get_object<Darwin.Xpc.Error> (Darwin.Xpc.Error.TYPE);
|
||||
return error.get_string (Darwin.Xpc.Error.KEY_DESCRIPTION);
|
||||
}
|
||||
|
||||
public void check_nserror (TranslateErrorFunc translate_error) throws Error {
|
||||
if (!has_member ("error"))
|
||||
return;
|
||||
|
||||
read_member ("error");
|
||||
|
||||
unowned string domain = read_member ("domain").get_string_value ();
|
||||
end_member ();
|
||||
|
||||
var code = (int) read_member ("code").get_int64_value ();
|
||||
end_member ();
|
||||
|
||||
string description = read_member ("userInfo").read_member ("NSLocalizedDescription").get_string_value ();
|
||||
if (description.has_suffix ("."))
|
||||
description = description[:description.length - 1];
|
||||
|
||||
throw (Error) new GLib.Error.literal (
|
||||
Quark.from_string ("frida-error-quark"),
|
||||
translate_error (domain, code, description),
|
||||
description);
|
||||
}
|
||||
|
||||
public unowned Darwin.Xpc.Object get_object_value (Darwin.Xpc.Type expected_type) throws Error {
|
||||
return peek_scope ().get_object<Darwin.Xpc.Object> (expected_type);
|
||||
}
|
||||
|
||||
private void push_scope (Darwin.Xpc.Object obj) {
|
||||
scopes.offer_tail (new Scope (obj));
|
||||
}
|
||||
|
||||
private Scope peek_scope () {
|
||||
return scopes.peek_tail ();
|
||||
}
|
||||
|
||||
private Scope pop_scope () {
|
||||
return scopes.poll_tail ();
|
||||
}
|
||||
|
||||
private class Scope {
|
||||
public Darwin.Xpc.Object object;
|
||||
private unowned Darwin.Xpc.Type type;
|
||||
|
||||
public Scope (Darwin.Xpc.Object obj) {
|
||||
object = obj;
|
||||
type = obj.type;
|
||||
}
|
||||
|
||||
public unowned T get_object<T> (Darwin.Xpc.Type expected_type) throws Error {
|
||||
if (type != expected_type)
|
||||
throw new Error.PROTOCOL ("Expected type '%s', got '%s'", expected_type.name, type.name);
|
||||
return object;
|
||||
}
|
||||
|
||||
public unowned Darwin.Xpc.Array get_array () throws Error {
|
||||
return get_object<Darwin.Xpc.Array> (Darwin.Xpc.Array.TYPE);
|
||||
}
|
||||
|
||||
public unowned Darwin.Xpc.Dictionary get_dictionary () throws Error {
|
||||
return get_object<Darwin.Xpc.Dictionary> (Darwin.Xpc.Dictionary.TYPE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
FRIDA_1.0 {
|
||||
local:
|
||||
*;
|
||||
};
|
||||
|
||||
GLIBC_2.2.5 {
|
||||
local:
|
||||
fopen*;
|
||||
fseeko*;
|
||||
ftello*;
|
||||
} FRIDA_1.0;
|
||||
@@ -144,8 +144,10 @@ frida_gadget_environment_ensure_debugger_breakpoints_only (void)
|
||||
|
||||
interceptor = gum_interceptor_obtain ();
|
||||
|
||||
gum_interceptor_attach (interceptor, exceptions_set, frida_dont_steal_my_breakpoints, NULL);
|
||||
gum_interceptor_attach (interceptor, exceptions_swap, frida_dont_steal_my_breakpoints, NULL);
|
||||
gum_interceptor_attach (interceptor, exceptions_set, frida_dont_steal_my_breakpoints,
|
||||
NULL, GUM_ATTACH_FLAGS_NONE);
|
||||
gum_interceptor_attach (interceptor, exceptions_swap, frida_dont_steal_my_breakpoints,
|
||||
NULL, GUM_ATTACH_FLAGS_NONE);
|
||||
|
||||
g_object_unref (interceptor);
|
||||
}
|
||||
|
||||
@@ -9,9 +9,7 @@
|
||||
# include <signal.h>
|
||||
#endif
|
||||
#include <gumjs/gumscriptbackend.h>
|
||||
#if defined (HAVE_GIOAPPLE)
|
||||
# include <gioapple.h>
|
||||
#elif defined (HAVE_GIOOPENSSL)
|
||||
#ifdef HAVE_GIOOPENSSL
|
||||
# include <gioopenssl.h>
|
||||
#endif
|
||||
|
||||
@@ -93,9 +91,7 @@ frida_gadget_environment_init (void)
|
||||
|
||||
g_thread_set_garbage_handler (_frida_gadget_on_pending_thread_garbage, NULL);
|
||||
|
||||
#if defined (HAVE_GIOAPPLE)
|
||||
g_io_module_apple_register ();
|
||||
#elif defined (HAVE_GIOOPENSSL)
|
||||
#ifdef HAVE_GIOOPENSSL
|
||||
g_io_module_openssl_register ();
|
||||
#endif
|
||||
|
||||
@@ -122,8 +118,6 @@ 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,5 +1,3 @@
|
||||
using Efni;
|
||||
|
||||
namespace Frida.Gadget {
|
||||
private sealed class Config : Object, Json.Serializable {
|
||||
public Object interaction {
|
||||
@@ -1812,11 +1810,6 @@ namespace Frida.Gadget {
|
||||
throw new Error.NOT_SUPPORTED ("Not possible when embedded");
|
||||
}
|
||||
|
||||
public async void enable_spawn_gating_with_options (HashTable<string, Variant> options,
|
||||
Cancellable? cancellable) throws Error, IOError {
|
||||
throw new Error.NOT_SUPPORTED ("Not possible when embedded");
|
||||
}
|
||||
|
||||
public async void disable_spawn_gating (Cancellable? cancellable) throws Error, IOError {
|
||||
throw new Error.NOT_SUPPORTED ("Not possible when embedded");
|
||||
}
|
||||
|
||||
@@ -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 = (libc == 'glibc') ? 'frida-gadget-glibc.version' : 'frida-gadget.version'
|
||||
symscript = 'frida-gadget.version'
|
||||
extra_link_args += '-Wl,--version-script,' + meson.current_source_dir() / symscript
|
||||
extra_link_depends += symscript
|
||||
endif
|
||||
@@ -55,10 +55,6 @@ if host_os_family in ['linux', 'qnx']
|
||||
extra_link_args += ['-Wl,-Bsymbolic']
|
||||
endif
|
||||
|
||||
if host_is_prospero
|
||||
extra_link_args += [prospero_crt_link_args, '-Wl,--defsym=main=0']
|
||||
endif
|
||||
|
||||
raw_gadget = shared_library('frida-gadget-raw', gadget_sources,
|
||||
name_prefix: 'lib',
|
||||
vala_args: [base_vala_args, payload_vala_args, extra_vala_args],
|
||||
|
||||
+2
-4
@@ -4,12 +4,10 @@ endif
|
||||
subdir('base')
|
||||
subdir('netif')
|
||||
subdir('pipe')
|
||||
if have_in_tree_payloads
|
||||
subdir('payload')
|
||||
endif
|
||||
subdir('payload')
|
||||
if have_local_backend
|
||||
subdir('agent')
|
||||
endif
|
||||
if have_in_tree_payloads and build_gadget
|
||||
if build_gadget
|
||||
subdir('gadget')
|
||||
endif
|
||||
@@ -8,6 +8,7 @@ extra_link_args = []
|
||||
if host_os in ['ios', 'tvos']
|
||||
extra_vala_args += [
|
||||
'--pkg=corefoundation',
|
||||
'--pkg=darwin-gcd',
|
||||
'--pkg=darwin-systemconfiguration',
|
||||
]
|
||||
extra_link_args += '-Wl,-framework,SystemConfiguration'
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
using Efni;
|
||||
|
||||
namespace Frida {
|
||||
public abstract class BaseAgentSession : Object, AgentSession {
|
||||
public signal void closed ();
|
||||
@@ -181,18 +179,6 @@ namespace Frida {
|
||||
yield script_engine.load_script (script_id);
|
||||
}
|
||||
|
||||
public async void interrupt_script (AgentScriptId script_id, Cancellable? cancellable) throws Error, IOError {
|
||||
check_open ();
|
||||
|
||||
script_engine.interrupt_script (script_id);
|
||||
}
|
||||
|
||||
public async void terminate_script (AgentScriptId script_id, Cancellable? cancellable) throws Error, IOError {
|
||||
check_open ();
|
||||
|
||||
yield script_engine.terminate_script (script_id);
|
||||
}
|
||||
|
||||
public async void eternalize_script (AgentScriptId script_id, Cancellable? cancellable) throws Error, IOError {
|
||||
check_open ();
|
||||
|
||||
|
||||
@@ -35,21 +35,15 @@ namespace Frida {
|
||||
interceptor.attach ((void *) Gum.Process.find_module_by_name ("kernel32.dll").find_export_by_name ("ExitProcess"),
|
||||
listener);
|
||||
#else
|
||||
var libc = Gum.Process.get_libc_module ();
|
||||
const string[] apis = {
|
||||
"exit",
|
||||
"_exit",
|
||||
"abort",
|
||||
};
|
||||
#if PROSPERO
|
||||
foreach (var symbol in apis) {
|
||||
interceptor.attach ((void *) Gum.Module.find_global_export_by_name (symbol), listener);
|
||||
}
|
||||
#else
|
||||
var libc = Gum.Process.get_libc_module ();
|
||||
foreach (var symbol in apis) {
|
||||
interceptor.attach ((void *) libc.find_export_by_name (symbol), listener);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -65,9 +65,7 @@ namespace Frida {
|
||||
if (runtime != null) {
|
||||
var set_argv0 = (void *) runtime.find_export_by_name ("_Z27android_os_Process_setArgV0P7_JNIEnvP8_jobjectP8_jstring");
|
||||
if (set_argv0 != null) {
|
||||
var set_argv0_options = Gum.AttachOptions ();
|
||||
set_argv0_options.listener_function_data = (void *) HookId.SET_ARGV0;
|
||||
interceptor.attach (set_argv0, listener, set_argv0_options);
|
||||
interceptor.attach (set_argv0, listener, (void *) HookId.SET_ARGV0);
|
||||
child_recovery_behavior = DEFERRED_UNTIL_SET_ARGV0;
|
||||
}
|
||||
}
|
||||
@@ -75,11 +73,8 @@ namespace Frida {
|
||||
var selinux = Gum.Process.find_module_by_name ("libselinux.so");
|
||||
if (selinux != null) {
|
||||
var setcontext = (void *) selinux.find_export_by_name ("selinux_android_setcontext");
|
||||
if (setcontext != null) {
|
||||
var setcontext_options = Gum.AttachOptions ();
|
||||
setcontext_options.listener_function_data = (void *) HookId.SET_CTX;
|
||||
interceptor.attach (setcontext, listener, setcontext_options);
|
||||
}
|
||||
if (setcontext != null)
|
||||
interceptor.attach (setcontext, listener, (void *) HookId.SET_CTX);
|
||||
}
|
||||
}
|
||||
} catch (FileError e) {
|
||||
@@ -87,9 +82,7 @@ namespace Frida {
|
||||
}
|
||||
#endif
|
||||
|
||||
var fork_options = Gum.AttachOptions ();
|
||||
fork_options.listener_function_data = (void *) HookId.FORK;
|
||||
interceptor.attach (fork_impl, listener, fork_options);
|
||||
interceptor.attach (fork_impl, listener, (void *) HookId.FORK);
|
||||
interceptor.replace (vfork_impl, fork_impl);
|
||||
}
|
||||
|
||||
|
||||
+51
-432
@@ -10,7 +10,6 @@
|
||||
# include <assert.h>
|
||||
# include <fcntl.h>
|
||||
# include <unistd.h>
|
||||
# include <wchar.h>
|
||||
#endif
|
||||
#if defined (HAVE_DARWIN)
|
||||
# include <sys/attr.h>
|
||||
@@ -24,51 +23,23 @@
|
||||
# include <xlocale.h>
|
||||
#endif
|
||||
|
||||
#undef __srget
|
||||
#undef feof
|
||||
#undef ferror
|
||||
#undef fgetwc
|
||||
#undef fileno
|
||||
#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 setbuf
|
||||
#undef setbuffer
|
||||
#undef setlinebuf
|
||||
#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
|
||||
@@ -99,9 +70,6 @@ __attribute__ ((destructor)) static
|
||||
void
|
||||
frida_libc_shim_deinit (void)
|
||||
{
|
||||
if (!frida_deinit_expected)
|
||||
return;
|
||||
|
||||
# ifdef HAVE_ASAN
|
||||
gum_deinit ();
|
||||
# else
|
||||
@@ -166,18 +134,16 @@ struct _FridaFile
|
||||
int err;
|
||||
|
||||
guint8 * rbuf;
|
||||
gboolean owns_rbuf;
|
||||
size_t rcap;
|
||||
size_t rpos;
|
||||
size_t rlen;
|
||||
|
||||
guint8 * wbuf;
|
||||
gboolean owns_wbuf;
|
||||
size_t wcap;
|
||||
size_t wlen;
|
||||
|
||||
guint8 ungot_buf[8];
|
||||
guint ungot_len;
|
||||
int ungot;
|
||||
gboolean has_ungot;
|
||||
};
|
||||
|
||||
struct _FridaFileHandle
|
||||
@@ -205,17 +171,12 @@ 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
|
||||
static void frida_stdio_register_dir (DIR * dirp);
|
||||
static void frida_stdio_unregister_dir (DIR * dirp);
|
||||
#endif
|
||||
static void frida_stdio_ensure_registries (void);
|
||||
static void frida_flush_all_streams (int * result);
|
||||
|
||||
static FridaFile * frida_file_get_impl (FILE * stream);
|
||||
@@ -232,8 +193,6 @@ 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);
|
||||
@@ -253,13 +212,7 @@ static ssize_t frida_write_nointr (int fd, const void * buf, size_t count);
|
||||
static int frida_close_nointr (int fd);
|
||||
static off_t frida_lseek_nointr (int fd, off_t offset, int whence);
|
||||
|
||||
#if defined (HAVE_QNX)
|
||||
G_GNUC_INTERNAL FILE _Stdin, _Stdout, _Stderr;
|
||||
|
||||
G_GNUC_INTERNAL FILE * stdin = &_Stdin;
|
||||
G_GNUC_INTERNAL FILE * stdout = &_Stdout;
|
||||
G_GNUC_INTERNAL FILE * stderr = &_Stderr;
|
||||
#elif !defined (FRIDA_STDIO_OPAQUE_FILE)
|
||||
#ifndef FRIDA_STDIO_OPAQUE_FILE
|
||||
G_GNUC_INTERNAL FILE __sF[3];
|
||||
|
||||
G_GNUC_INTERNAL FILE * stdin = &__sF[0];
|
||||
@@ -309,18 +262,33 @@ frida_libc_shim_init (void)
|
||||
|
||||
G_LOCK (frida_stdio);
|
||||
|
||||
frida_stdio_ensure_registries ();
|
||||
frida_streams = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
#ifdef HAVE_FRIDA_DIR
|
||||
frida_dirs = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
#endif
|
||||
|
||||
G_UNLOCK (frida_stdio);
|
||||
|
||||
f0 = frida_file_new (0, FALSE, _IOFBF);
|
||||
frida_file_bind_slot (stdin, f0);
|
||||
#ifndef FRIDA_STDIO_OPAQUE_FILE
|
||||
frida_file_bind_slot (&__sF[0], f0);
|
||||
#else
|
||||
frida_file_bind_slot ((FILE *) &frida_stdio[0], f0);
|
||||
#endif
|
||||
|
||||
f1 = frida_file_new (1, FALSE, _IOLBF);
|
||||
frida_file_bind_slot (stdout, f1);
|
||||
#ifndef FRIDA_STDIO_OPAQUE_FILE
|
||||
frida_file_bind_slot (&__sF[1], f1);
|
||||
#else
|
||||
frida_file_bind_slot ((FILE *) &frida_stdio[1], f1);
|
||||
#endif
|
||||
|
||||
f2 = frida_file_new (2, FALSE, _IONBF);
|
||||
frida_file_bind_slot (stderr, f2);
|
||||
#ifndef FRIDA_STDIO_OPAQUE_FILE
|
||||
frida_file_bind_slot (&__sF[2], f2);
|
||||
#else
|
||||
frida_file_bind_slot ((FILE *) &frida_stdio[2], f2);
|
||||
#endif
|
||||
|
||||
frida_libc_shim_initialized = TRUE;
|
||||
}
|
||||
@@ -349,9 +317,6 @@ frida_libc_shim_deinit (void)
|
||||
|
||||
fflush (NULL);
|
||||
|
||||
if (!frida_deinit_expected)
|
||||
return;
|
||||
|
||||
G_LOCK (frida_stdio);
|
||||
|
||||
g_hash_table_iter_init (&iter, frida_streams);
|
||||
@@ -631,7 +596,7 @@ __vsnprintf_chk (char * string, size_t size, int flags, size_t len, const char *
|
||||
return gum_vsnprintf (string, size, format, args);
|
||||
}
|
||||
|
||||
#if defined (HAVE_XLOCALE_H) && !defined (HAVE_PROSPERO)
|
||||
#ifdef HAVE_XLOCALE_H
|
||||
|
||||
G_GNUC_INTERNAL int
|
||||
sprintf_l (char * string, locale_t loc, const char * format, ...)
|
||||
@@ -674,34 +639,8 @@ 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;
|
||||
@@ -775,17 +714,8 @@ setvbuf (FILE * stream, char * buf, int mode, size_t size)
|
||||
|
||||
if (mode == _IONBF)
|
||||
{
|
||||
if (f->owns_rbuf)
|
||||
g_clear_pointer (&f->rbuf, g_free);
|
||||
else
|
||||
f->rbuf = NULL;
|
||||
f->owns_rbuf = FALSE;
|
||||
|
||||
if (f->owns_wbuf)
|
||||
g_clear_pointer (&f->wbuf, g_free);
|
||||
else
|
||||
f->wbuf = NULL;
|
||||
f->owns_wbuf = FALSE;
|
||||
g_clear_pointer (&f->rbuf, g_free);
|
||||
g_clear_pointer (&f->wbuf, g_free);
|
||||
|
||||
f->rcap = 0;
|
||||
f->wcap = 0;
|
||||
@@ -797,40 +727,13 @@ setvbuf (FILE * stream, char * buf, int mode, size_t size)
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
size = BUFSIZ;
|
||||
|
||||
if (!f->owns_rbuf)
|
||||
{
|
||||
f->rbuf = NULL;
|
||||
f->rcap = 0;
|
||||
}
|
||||
size = FRIDA_STDIO_BUFSIZE;
|
||||
|
||||
f->rbuf = g_realloc (f->rbuf, size);
|
||||
f->owns_rbuf = TRUE;
|
||||
f->wbuf = g_realloc (f->wbuf, size);
|
||||
|
||||
f->rcap = size;
|
||||
|
||||
if (buf != NULL)
|
||||
{
|
||||
if (f->owns_wbuf)
|
||||
g_clear_pointer (&f->wbuf, g_free);
|
||||
|
||||
f->wbuf = (guint8 *) buf;
|
||||
f->owns_wbuf = FALSE;
|
||||
f->wcap = size;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!f->owns_wbuf)
|
||||
{
|
||||
f->wbuf = NULL;
|
||||
f->wcap = 0;
|
||||
}
|
||||
|
||||
f->wbuf = g_realloc (f->wbuf, size);
|
||||
f->owns_wbuf = TRUE;
|
||||
f->wcap = size;
|
||||
}
|
||||
|
||||
f->wcap = size;
|
||||
f->rpos = 0;
|
||||
f->rlen = 0;
|
||||
f->wlen = 0;
|
||||
@@ -838,39 +741,6 @@ setvbuf (FILE * stream, char * buf, int mode, size_t size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
G_GNUC_INTERNAL void
|
||||
setbuf (FILE * stream, char * buf)
|
||||
{
|
||||
if (buf == NULL)
|
||||
(void) setvbuf (stream, NULL, _IONBF, 0);
|
||||
else
|
||||
(void) setvbuf (stream, buf, _IOFBF, BUFSIZ);
|
||||
}
|
||||
|
||||
#if defined (HAVE_DARWIN) || defined (HAVE_ANDROID) || defined (HAVE_FREEBSD)
|
||||
G_GNUC_INTERNAL int
|
||||
setlinebuf (FILE * stream)
|
||||
{
|
||||
return setvbuf (stream, NULL, _IOLBF, 0);
|
||||
}
|
||||
#else
|
||||
G_GNUC_INTERNAL void
|
||||
setlinebuf (FILE * stream)
|
||||
{
|
||||
setvbuf (stream, NULL, _IOLBF, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
G_GNUC_INTERNAL void
|
||||
#if defined (HAVE_DARWIN) || defined (HAVE_ANDROID) || defined (HAVE_FREEBSD)
|
||||
setbuffer (FILE * stream, char * buf, int size)
|
||||
#else
|
||||
setbuffer (FILE * stream, char * buf, size_t size)
|
||||
#endif
|
||||
{
|
||||
(void) setvbuf (stream, buf, (buf != NULL) ? _IOFBF : _IONBF, size);
|
||||
}
|
||||
|
||||
G_GNUC_INTERNAL int
|
||||
fflush (FILE * stream)
|
||||
{
|
||||
@@ -931,8 +801,11 @@ getc_unlocked (FILE * stream)
|
||||
|
||||
f = frida_file_get_impl (stream);
|
||||
|
||||
if (f->ungot_len != 0)
|
||||
return f->ungot_buf[--f->ungot_len];
|
||||
if (f->has_ungot)
|
||||
{
|
||||
f->has_ungot = FALSE;
|
||||
return f->ungot;
|
||||
}
|
||||
|
||||
if (f->buf_mode == _IONBF)
|
||||
{
|
||||
@@ -973,64 +846,6 @@ getc (FILE * stream)
|
||||
return getc_unlocked (stream);
|
||||
}
|
||||
|
||||
G_GNUC_INTERNAL int
|
||||
__srget (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)
|
||||
{
|
||||
@@ -1041,46 +856,16 @@ ungetc (int c, FILE * stream)
|
||||
if (c == EOF)
|
||||
return EOF;
|
||||
|
||||
if (f->ungot_len == G_N_ELEMENTS (f->ungot_buf))
|
||||
if (f->has_ungot)
|
||||
return EOF;
|
||||
|
||||
f->ungot_buf[f->ungot_len++] = c;
|
||||
f->ungot = c;
|
||||
f->has_ungot = TRUE;
|
||||
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)
|
||||
{
|
||||
@@ -1099,9 +884,10 @@ fread (void * ptr, size_t size, size_t nmemb, FILE * stream)
|
||||
|
||||
while (got != want)
|
||||
{
|
||||
if (f->ungot_len != 0)
|
||||
if (f->has_ungot)
|
||||
{
|
||||
out[got++] = f->ungot_buf[--f->ungot_len];
|
||||
out[got++] = (guint8) f->ungot;
|
||||
f->has_ungot = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1220,12 +1006,6 @@ 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)
|
||||
{
|
||||
@@ -1239,37 +1019,6 @@ 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)
|
||||
{
|
||||
@@ -1313,84 +1062,6 @@ 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;
|
||||
@@ -1402,10 +1073,10 @@ frida_fseek_impl (FILE * stream, off_t offset, int whence)
|
||||
|
||||
f->rpos = 0;
|
||||
f->rlen = 0;
|
||||
f->ungot_len = 0;
|
||||
f->has_ungot = FALSE;
|
||||
f->eof = FALSE;
|
||||
|
||||
r = frida_lseek_nointr (f->fd, offset, whence);
|
||||
r = frida_lseek_nointr (f->fd, (off_t) offset, whence);
|
||||
if (r == (off_t) -1)
|
||||
{
|
||||
f->err = errno;
|
||||
@@ -1415,8 +1086,8 @@ frida_fseek_impl (FILE * stream, off_t offset, int whence)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static off_t
|
||||
frida_ftell_impl (FILE * stream)
|
||||
G_GNUC_INTERNAL long
|
||||
ftell (FILE * stream)
|
||||
{
|
||||
FridaFile * f;
|
||||
off_t pos;
|
||||
@@ -1433,9 +1104,10 @@ frida_ftell_impl (FILE * stream)
|
||||
if (f->buf_mode != _IONBF)
|
||||
pos -= (off_t) (f->rlen - f->rpos);
|
||||
|
||||
pos -= f->ungot_len;
|
||||
if (f->has_ungot)
|
||||
pos -= 1;
|
||||
|
||||
return pos;
|
||||
return (long) pos;
|
||||
}
|
||||
|
||||
G_GNUC_INTERNAL void
|
||||
@@ -1897,7 +1569,6 @@ frida_stdio_register_stream (FILE * stream)
|
||||
{
|
||||
G_LOCK (frida_stdio);
|
||||
|
||||
frida_stdio_ensure_registries ();
|
||||
g_hash_table_add (frida_streams, stream);
|
||||
|
||||
G_UNLOCK (frida_stdio);
|
||||
@@ -1920,7 +1591,6 @@ frida_stdio_register_dir (DIR * dirp)
|
||||
{
|
||||
G_LOCK (frida_stdio);
|
||||
|
||||
frida_stdio_ensure_registries ();
|
||||
g_hash_table_add (frida_dirs, dirp);
|
||||
|
||||
G_UNLOCK (frida_stdio);
|
||||
@@ -1938,18 +1608,6 @@ frida_stdio_unregister_dir (DIR * dirp)
|
||||
|
||||
#endif
|
||||
|
||||
static void
|
||||
frida_stdio_ensure_registries (void)
|
||||
{
|
||||
if (frida_streams != NULL)
|
||||
return;
|
||||
|
||||
frida_streams = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
#ifdef HAVE_FRIDA_DIR
|
||||
frida_dirs = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
frida_flush_all_streams (int * result)
|
||||
{
|
||||
@@ -2060,12 +1718,10 @@ frida_file_new (int fd, gboolean close_fd, int buf_mode)
|
||||
if (buf_mode != _IONBF)
|
||||
{
|
||||
f->rcap = FRIDA_STDIO_BUFSIZE;
|
||||
f->rbuf = g_malloc (f->rcap);
|
||||
f->owns_rbuf = TRUE;
|
||||
|
||||
f->wcap = FRIDA_STDIO_BUFSIZE;
|
||||
|
||||
f->rbuf = g_malloc (f->rcap);
|
||||
f->wbuf = g_malloc (f->wcap);
|
||||
f->owns_wbuf = TRUE;
|
||||
}
|
||||
|
||||
return f;
|
||||
@@ -2077,15 +1733,8 @@ frida_file_free (FridaFile * f)
|
||||
if (f == NULL)
|
||||
return;
|
||||
|
||||
if (f->owns_rbuf)
|
||||
g_clear_pointer (&f->rbuf, g_free);
|
||||
else
|
||||
f->rbuf = NULL;
|
||||
|
||||
if (f->owns_wbuf)
|
||||
g_clear_pointer (&f->wbuf, g_free);
|
||||
else
|
||||
f->wbuf = NULL;
|
||||
g_clear_pointer (&f->rbuf, g_free);
|
||||
g_clear_pointer (&f->wbuf, g_free);
|
||||
|
||||
g_free (f);
|
||||
}
|
||||
@@ -2217,36 +1866,6 @@ 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,5 +1,3 @@
|
||||
using Efni;
|
||||
|
||||
namespace Frida {
|
||||
public sealed class PortalClient : Object, AgentSessionProvider {
|
||||
public signal void resume ();
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using Efni;
|
||||
|
||||
namespace Frida {
|
||||
public extern void libc_shim_prepare_to_deinit ();
|
||||
#if DARWIN
|
||||
public extern void libc_shim_deinit ();
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
using Efni;
|
||||
|
||||
namespace Frida {
|
||||
public sealed class ScriptEngine : Object {
|
||||
public signal void message_from_script (AgentScriptId script_id, string json, Bytes? data);
|
||||
@@ -168,14 +166,6 @@ namespace Frida {
|
||||
yield get_instance (script_id).load ();
|
||||
}
|
||||
|
||||
public void interrupt_script (AgentScriptId script_id) throws Error {
|
||||
get_instance (script_id).interrupt ();
|
||||
}
|
||||
|
||||
public async void terminate_script (AgentScriptId script_id) throws Error {
|
||||
yield get_instance (script_id).terminate ();
|
||||
}
|
||||
|
||||
public Gum.Script eternalize_script (AgentScriptId script_id) throws Error {
|
||||
var instance = get_instance (script_id);
|
||||
|
||||
@@ -364,16 +354,6 @@ namespace Frida {
|
||||
load_request.resolve (true);
|
||||
}
|
||||
|
||||
public void interrupt () {
|
||||
script.interrupt ();
|
||||
}
|
||||
|
||||
public async void terminate () {
|
||||
script.interrupt ();
|
||||
|
||||
yield close ();
|
||||
}
|
||||
|
||||
private Promise<bool> unload () {
|
||||
var request = new Promise<bool> ();
|
||||
|
||||
|
||||
@@ -59,9 +59,7 @@ namespace Frida {
|
||||
|
||||
interceptor.attach ((void *) posix_spawn, this);
|
||||
|
||||
var replace_options = Gum.ReplaceOptions ();
|
||||
replace_options.replacement_data = this;
|
||||
interceptor.replace (execve, (void *) replacement_execve, null, replace_options);
|
||||
interceptor.replace (execve, (void *) replacement_execve, this);
|
||||
#else
|
||||
Gum.Address execve = 0;
|
||||
#if ANDROID
|
||||
|
||||
@@ -31,11 +31,9 @@ namespace Frida {
|
||||
thread_suspend = (ThreadSuspendFunc) kernel.find_export_by_name ("thread_suspend");
|
||||
thread_resume = (ThreadResumeFunc) kernel.find_export_by_name ("thread_resume");
|
||||
|
||||
var replace_options = Gum.ReplaceOptions ();
|
||||
replace_options.replacement_data = this;
|
||||
interceptor.replace ((void *) task_threads, (void *) replacement_task_threads, null, replace_options);
|
||||
interceptor.replace ((void *) thread_suspend, (void *) replacement_thread_suspend, null, replace_options);
|
||||
interceptor.replace ((void *) thread_resume, (void *) replacement_thread_resume, null, replace_options);
|
||||
interceptor.replace ((void *) task_threads, (void *) replacement_task_threads, this);
|
||||
interceptor.replace ((void *) thread_suspend, (void *) replacement_thread_suspend, this);
|
||||
interceptor.replace ((void *) thread_resume, (void *) replacement_thread_resume, this);
|
||||
}
|
||||
|
||||
public override void dispose () {
|
||||
|
||||
@@ -2,14 +2,29 @@
|
||||
|
||||
#ifdef HAVE_DARWIN
|
||||
|
||||
#include <capstone.h>
|
||||
#include <gum/gumdarwin.h>
|
||||
#include <gum/gummemory.h>
|
||||
#include <ptrauth.h>
|
||||
|
||||
#define FRIDA_MH_MAGIC_64 0xfeedfacf
|
||||
#define FRIDA_LIBUNWIND_PATH "/usr/lib/system/libunwind.dylib"
|
||||
#define FRIDA_UNWIND_CURSOR_VTABLE_OFFSET_SET_INFO 0x68
|
||||
#define FRIDA_UNWIND_CURSOR_VTABLE_OFFSET_GET_REG 0x18
|
||||
#define FRIDA_FP_TO_SP(fp) (fp + 0x10)
|
||||
#ifdef HAVE_ARM64
|
||||
# define FRIDA_UNWIND_CURSOR_unwindInfoMissing 0x268
|
||||
# define FRIDA_UNWAARCH64_X29 29
|
||||
# define FRIDA_STRIP_MASK 0x0000007fffffffffULL
|
||||
#else
|
||||
# define FRIDA_UNWIND_CURSOR_unwindInfoMissing 0x100
|
||||
# define FRIDA_UNWX86_64_RBP 6
|
||||
#endif
|
||||
|
||||
typedef struct _FridaFillInfoContext FridaFillInfoContext;
|
||||
typedef struct _FridaDyldUnwindSections FridaDyldUnwindSections;
|
||||
typedef struct _FridaCreateArgs FridaCreateArgs;
|
||||
typedef struct _FridaUnwindHookState FridaUnwindHookState;
|
||||
|
||||
struct _FridaFillInfoContext
|
||||
{
|
||||
@@ -32,9 +47,37 @@ struct _FridaCreateArgs
|
||||
GumAddress range_end;
|
||||
};
|
||||
|
||||
struct _FridaUnwindHookState
|
||||
{
|
||||
gpointer vtable;
|
||||
gssize shift;
|
||||
gpointer * set_info_slot;
|
||||
gpointer set_info_original;
|
||||
void (* set_info) (gpointer cursor, gint is_return_address);
|
||||
gpointer (* get_reg) (gpointer cursor, gint reg);
|
||||
GumInterceptor * interceptor;
|
||||
};
|
||||
|
||||
#if __has_feature (ptrauth_calls)
|
||||
# define FRIDA_RESIGN_PTR(x) GSIZE_TO_POINTER (gum_sign_code_address (gum_strip_code_address (GUM_ADDRESS (x))))
|
||||
#else
|
||||
# define FRIDA_RESIGN_PTR(x) (x)
|
||||
#endif
|
||||
|
||||
static FridaDyldUnwindSections * frida_get_cached_sections (GumAddress range_start, GumAddress range_end);
|
||||
static FridaDyldUnwindSections * frida_create_cached_sections (FridaCreateArgs * args);
|
||||
static gboolean frida_fill_info (const GumMachoSectionDetails * details, FridaFillInfoContext * ctx);
|
||||
static gboolean frida_fill_info (const GumDarwinSectionDetails * details, FridaFillInfoContext * ctx);
|
||||
static void frida_unwind_cursor_set_info_replacement (gpointer cursor, gint is_return_address);
|
||||
static gpointer frida_find_vtable (void);
|
||||
static gboolean frida_compute_vtable_shift (gpointer vtable, gssize * shift);
|
||||
#ifdef HAVE_ARM64
|
||||
static gboolean frida_find_bss_range (const GumSectionDetails * details, GumMemoryRange * range);
|
||||
#else
|
||||
static gboolean frida_is_empty_function (GumAddress address);
|
||||
static gboolean frida_has_first_match (GumAddress address, gsize size, gboolean * matches);
|
||||
#endif
|
||||
|
||||
static FridaUnwindHookState * state = NULL;
|
||||
|
||||
void
|
||||
_frida_unwind_sitter_fill_unwind_sections (GumAddress invader_start, GumAddress invader_end, void * info)
|
||||
@@ -49,6 +92,63 @@ _frida_unwind_sitter_fill_unwind_sections (GumAddress invader_start, GumAddress
|
||||
memcpy (unwind_sections, cached, sizeof (FridaDyldUnwindSections));
|
||||
}
|
||||
|
||||
void
|
||||
_frida_unwind_sitter_hook_libunwind (void)
|
||||
{
|
||||
#if GLIB_SIZEOF_VOID_P == 8
|
||||
gpointer * set_info_slot;
|
||||
gpointer get_reg_impl;
|
||||
|
||||
if (state != NULL)
|
||||
return;
|
||||
|
||||
state = g_slice_new0 (FridaUnwindHookState);
|
||||
if (state == NULL)
|
||||
return;
|
||||
|
||||
state->vtable = frida_find_vtable ();
|
||||
if (state->vtable == NULL)
|
||||
goto unsupported_version;
|
||||
|
||||
if (!frida_compute_vtable_shift (state->vtable, &state->shift))
|
||||
goto unsupported_version;
|
||||
|
||||
set_info_slot = (gpointer *) (GUM_ADDRESS (state->vtable) + FRIDA_UNWIND_CURSOR_VTABLE_OFFSET_SET_INFO + state->shift);
|
||||
get_reg_impl = *(gpointer *) (GUM_ADDRESS (state->vtable) + FRIDA_UNWIND_CURSOR_VTABLE_OFFSET_GET_REG + state->shift);
|
||||
|
||||
state->set_info_slot = set_info_slot;
|
||||
state->set_info_original = *set_info_slot;
|
||||
state->set_info = FRIDA_RESIGN_PTR (state->set_info_original);
|
||||
state->get_reg = FRIDA_RESIGN_PTR (get_reg_impl);
|
||||
|
||||
state->interceptor = gum_interceptor_obtain ();
|
||||
|
||||
if (gum_interceptor_replace (state->interceptor, state->set_info_original, frida_unwind_cursor_set_info_replacement, NULL, NULL)
|
||||
!= GUM_REPLACE_OK)
|
||||
goto unsupported_version;
|
||||
|
||||
return;
|
||||
|
||||
unsupported_version:
|
||||
g_slice_free (FridaUnwindHookState, state);
|
||||
state = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
_frida_unwind_sitter_unhook_libunwind (void)
|
||||
{
|
||||
if (state == NULL)
|
||||
return;
|
||||
|
||||
gum_interceptor_revert (state->interceptor, state->set_info_original);
|
||||
|
||||
g_object_unref (state->interceptor);
|
||||
|
||||
g_slice_free (FridaUnwindHookState, state);
|
||||
state = NULL;
|
||||
}
|
||||
|
||||
static FridaDyldUnwindSections *
|
||||
frida_get_cached_sections (GumAddress range_start, GumAddress range_end)
|
||||
{
|
||||
@@ -70,7 +170,7 @@ frida_create_cached_sections (FridaCreateArgs * args)
|
||||
gsize page_size;
|
||||
gpointer header;
|
||||
GumPageProtection prot;
|
||||
GumMachoModule * module;
|
||||
GumDarwinModule * module;
|
||||
FridaFillInfoContext ctx;
|
||||
|
||||
page_size = gum_query_page_size ();
|
||||
@@ -87,14 +187,13 @@ frida_create_cached_sections (FridaCreateArgs * args)
|
||||
cached_sections = g_slice_new0 (FridaDyldUnwindSections);
|
||||
cached_sections->mh = header;
|
||||
|
||||
module = gum_macho_module_new_from_memory ("Frida", mach_task_self (), GPOINTER_TO_SIZE (header),
|
||||
GUM_MACHO_MODULE_FLAGS_NONE, NULL);
|
||||
module = gum_darwin_module_new_from_memory ("Frida", mach_task_self (), GPOINTER_TO_SIZE (header), GUM_DARWIN_MODULE_FLAGS_NONE, NULL);
|
||||
if (module == NULL)
|
||||
return cached_sections;
|
||||
|
||||
ctx.info = cached_sections;
|
||||
ctx.missing_info = 2;
|
||||
gum_macho_module_enumerate_sections (module, (GumFoundMachoSectionFunc) frida_fill_info, &ctx);
|
||||
gum_darwin_module_enumerate_sections (module, (GumFoundDarwinSectionFunc) frida_fill_info, &ctx);
|
||||
|
||||
g_object_unref (module);
|
||||
|
||||
@@ -102,7 +201,7 @@ frida_create_cached_sections (FridaCreateArgs * args)
|
||||
}
|
||||
|
||||
static gboolean
|
||||
frida_fill_info (const GumMachoSectionDetails * details, FridaFillInfoContext * ctx)
|
||||
frida_fill_info (const GumDarwinSectionDetails * details, FridaFillInfoContext * ctx)
|
||||
{
|
||||
if (strcmp ("__TEXT", details->segment_name) != 0)
|
||||
return TRUE;
|
||||
@@ -123,4 +222,308 @@ frida_fill_info (const GumMachoSectionDetails * details, FridaFillInfoContext *
|
||||
return ctx->missing_info > 0;
|
||||
}
|
||||
|
||||
static void
|
||||
frida_unwind_cursor_set_info_replacement (gpointer self, gint is_return_address)
|
||||
{
|
||||
gboolean missing_info;
|
||||
GumAddress fp, stored_pc;
|
||||
gpointer * stored_pc_slot;
|
||||
#if defined (HAVE_ARM64) && !__has_feature (ptrauth_calls)
|
||||
gboolean was_signed = FALSE;
|
||||
#endif
|
||||
|
||||
if (state == NULL)
|
||||
return;
|
||||
|
||||
state->set_info (self, is_return_address);
|
||||
|
||||
#ifdef HAVE_ARM64
|
||||
fp = GUM_ADDRESS (state->get_reg (self, FRIDA_UNWAARCH64_X29));
|
||||
#else
|
||||
fp = GUM_ADDRESS (state->get_reg (self, FRIDA_UNWX86_64_RBP));
|
||||
#endif
|
||||
if (fp == 0 || fp == -1)
|
||||
return;
|
||||
|
||||
missing_info = *((guint8 *) self + FRIDA_UNWIND_CURSOR_unwindInfoMissing);
|
||||
|
||||
stored_pc_slot = GSIZE_TO_POINTER (fp + GLIB_SIZEOF_VOID_P);
|
||||
stored_pc = GUM_ADDRESS (*stored_pc_slot);
|
||||
#if __has_feature (ptrauth_calls)
|
||||
stored_pc = gum_strip_code_address (stored_pc);
|
||||
#elif defined (HAVE_ARM64)
|
||||
was_signed = (stored_pc & ~FRIDA_STRIP_MASK) != 0ULL;
|
||||
if (was_signed)
|
||||
stored_pc &= FRIDA_STRIP_MASK;
|
||||
#endif
|
||||
|
||||
if (!missing_info)
|
||||
{
|
||||
GumAddress translated;
|
||||
|
||||
translated = GUM_ADDRESS (gum_invocation_stack_translate (gum_interceptor_get_current_stack (), GSIZE_TO_POINTER (stored_pc)));
|
||||
if (translated != stored_pc)
|
||||
{
|
||||
#if __has_feature (ptrauth_calls)
|
||||
*stored_pc_slot = ptrauth_sign_unauthenticated (
|
||||
ptrauth_strip (GSIZE_TO_POINTER (translated), ptrauth_key_asia), ptrauth_key_asib, FRIDA_FP_TO_SP (fp));
|
||||
#elif defined (HAVE_ARM64)
|
||||
if (was_signed)
|
||||
{
|
||||
GumAddress resigned;
|
||||
|
||||
asm volatile (
|
||||
"mov x17, %1\n\t"
|
||||
"mov x16, %2\n\t"
|
||||
".byte 0x5f, 0x21, 0x03, 0xd5\n\t" /* pacib1716 */
|
||||
"mov %0, x17\n\t"
|
||||
: "=r" (resigned)
|
||||
: "r" (translated & FRIDA_STRIP_MASK),
|
||||
"r" (FRIDA_FP_TO_SP (fp))
|
||||
: "x16", "x17"
|
||||
);
|
||||
|
||||
*stored_pc_slot = GSIZE_TO_POINTER (resigned);
|
||||
}
|
||||
else
|
||||
{
|
||||
*stored_pc_slot = GSIZE_TO_POINTER (translated);
|
||||
}
|
||||
#else
|
||||
*stored_pc_slot = GSIZE_TO_POINTER (translated);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gpointer
|
||||
frida_find_vtable (void)
|
||||
{
|
||||
GumAddress result = 0;
|
||||
GumModule * libunwind;
|
||||
GumAddress export;
|
||||
uint64_t address;
|
||||
G_GNUC_UNUSED cs_err err;
|
||||
csh capstone;
|
||||
cs_insn * insn = NULL;
|
||||
const uint8_t * code;
|
||||
size_t size;
|
||||
const size_t max_size = 2048;
|
||||
|
||||
libunwind = gum_process_find_module_by_name (FRIDA_LIBUNWIND_PATH);
|
||||
if (libunwind == NULL)
|
||||
goto beach;
|
||||
|
||||
export = gum_module_find_export_by_name (libunwind, "unw_init_local");
|
||||
if (export == 0)
|
||||
export = gum_module_find_export_by_name (libunwind, "_Unwind_RaiseException");
|
||||
if (export == 0)
|
||||
goto beach;
|
||||
export = gum_strip_code_address (export);
|
||||
address = export;
|
||||
|
||||
#ifdef HAVE_ARM64
|
||||
cs_arch_register_arm64 ();
|
||||
err = cs_open (CS_ARCH_ARM64, CS_MODE_LITTLE_ENDIAN, &capstone);
|
||||
#else
|
||||
cs_arch_register_x86 ();
|
||||
err = cs_open (CS_ARCH_X86, CS_MODE_64, &capstone);
|
||||
#endif
|
||||
g_assert (err == CS_ERR_OK);
|
||||
|
||||
err = cs_option (capstone, CS_OPT_DETAIL, CS_OPT_ON);
|
||||
g_assert (err == CS_ERR_OK);
|
||||
|
||||
insn = cs_malloc (capstone);
|
||||
code = GSIZE_TO_POINTER (export);
|
||||
size = max_size;
|
||||
|
||||
#ifdef HAVE_ARM64
|
||||
{
|
||||
GumAddress last_adrp;
|
||||
guint last_adrp_reg;
|
||||
GumMemoryRange bss_range;
|
||||
|
||||
bss_range.base_address = 0;
|
||||
gum_module_enumerate_sections (libunwind, (GumFoundSectionFunc) frida_find_bss_range, &bss_range);
|
||||
|
||||
while (cs_disasm_iter (capstone, &code, &size, &address, insn))
|
||||
{
|
||||
if (insn->id == ARM64_INS_RET || insn->id == ARM64_INS_RETAA || insn->id == ARM64_INS_RETAB)
|
||||
break;
|
||||
if (insn->id == ARM64_INS_ADRP)
|
||||
{
|
||||
if (result != 0)
|
||||
break;
|
||||
last_adrp = (GumAddress) insn->detail->arm64.operands[1].imm;
|
||||
last_adrp_reg = insn->detail->arm64.operands[0].reg;
|
||||
}
|
||||
else if (insn->id == ARM64_INS_ADD && insn->detail->arm64.operands[0].reg == last_adrp_reg)
|
||||
{
|
||||
GumAddress candidate;
|
||||
gboolean is_bss;
|
||||
|
||||
candidate = last_adrp + (GumAddress) insn->detail->arm64.operands[2].imm;
|
||||
|
||||
is_bss = bss_range.base_address != 0 &&
|
||||
bss_range.base_address <= candidate &&
|
||||
candidate < bss_range.base_address + bss_range.size;
|
||||
if (!is_bss)
|
||||
{
|
||||
if (result == 0)
|
||||
{
|
||||
result = candidate;
|
||||
last_adrp = candidate;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (result != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
while (cs_disasm_iter (capstone, &code, &size, &address, insn))
|
||||
{
|
||||
if (insn->id == X86_INS_RET)
|
||||
break;
|
||||
if (insn->id == X86_INS_LEA)
|
||||
{
|
||||
const cs_x86_op * op = &insn->detail->x86.operands[1];
|
||||
if (op->type == X86_OP_MEM && op->mem.base == X86_REG_RIP)
|
||||
{
|
||||
result = address + op->mem.disp * op->mem.scale;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (insn != NULL)
|
||||
cs_free (insn, 1);
|
||||
cs_close (&capstone);
|
||||
|
||||
beach:
|
||||
g_clear_object (&libunwind);
|
||||
|
||||
return GSIZE_TO_POINTER (result);
|
||||
}
|
||||
|
||||
#ifdef HAVE_ARM64
|
||||
|
||||
static gboolean
|
||||
frida_find_bss_range (const GumSectionDetails * details, GumMemoryRange * range)
|
||||
{
|
||||
if (strcmp (details->name, "__bss") == 0)
|
||||
{
|
||||
range->base_address = details->address;
|
||||
range->size = details->size;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
frida_compute_vtable_shift (gpointer vtable, gssize * shift)
|
||||
{
|
||||
gboolean result = FALSE;
|
||||
G_GNUC_UNUSED cs_err err;
|
||||
csh capstone;
|
||||
cs_insn * insn = NULL;
|
||||
const uint8_t * code;
|
||||
uint64_t address;
|
||||
size_t size = 4;
|
||||
|
||||
cs_arch_register_arm64 ();
|
||||
err = cs_open (CS_ARCH_ARM64, CS_MODE_LITTLE_ENDIAN, &capstone);
|
||||
g_assert (err == CS_ERR_OK);
|
||||
|
||||
insn = cs_malloc (capstone);
|
||||
code = gum_strip_code_pointer (*(gpointer *) vtable);
|
||||
address = GPOINTER_TO_SIZE (code);
|
||||
|
||||
if (cs_disasm_iter (capstone, &code, &size, &address, insn))
|
||||
{
|
||||
if (insn->id == ARM64_INS_RET || insn->id == ARM64_INS_RETAA || insn->id == ARM64_INS_RETAB)
|
||||
*shift = 0;
|
||||
else
|
||||
*shift = -2 * GLIB_SIZEOF_VOID_P;
|
||||
|
||||
result = TRUE;
|
||||
}
|
||||
|
||||
if (insn != NULL)
|
||||
cs_free (insn, 1);
|
||||
cs_close (&capstone);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static gboolean
|
||||
frida_compute_vtable_shift (gpointer vtable, gssize * shift)
|
||||
{
|
||||
GumAddress cursor = GPOINTER_TO_SIZE (vtable);
|
||||
GumAddress error = cursor + 16 * GLIB_SIZEOF_VOID_P;
|
||||
|
||||
while (cursor < error && *(gpointer *) GSIZE_TO_POINTER (cursor) == NULL)
|
||||
cursor += GLIB_SIZEOF_VOID_P;
|
||||
if (cursor == error)
|
||||
return FALSE;
|
||||
|
||||
if (frida_is_empty_function (GUM_ADDRESS (*(gpointer *) GSIZE_TO_POINTER (cursor))) &&
|
||||
frida_is_empty_function (GUM_ADDRESS (*(gpointer *) GSIZE_TO_POINTER (cursor + GLIB_SIZEOF_VOID_P))))
|
||||
{
|
||||
*shift = cursor - GPOINTER_TO_SIZE (vtable);
|
||||
}
|
||||
else
|
||||
{
|
||||
*shift = cursor - GPOINTER_TO_SIZE (vtable) - 2 * GLIB_SIZEOF_VOID_P;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
frida_is_empty_function (GumAddress address)
|
||||
{
|
||||
gboolean matches = FALSE;
|
||||
GumMemoryRange range;
|
||||
GumMatchPattern * pattern;
|
||||
|
||||
range.base_address = address;
|
||||
range.size = 6;
|
||||
|
||||
/*
|
||||
* 55 push rbp
|
||||
* 4889e5 mov rbp, rsp
|
||||
* 5d pop rbp
|
||||
* c3 ret
|
||||
*/
|
||||
pattern = gum_match_pattern_new_from_string ("55 48 89 e5 5d c3");
|
||||
|
||||
gum_memory_scan (&range, pattern, (GumMemoryScanMatchFunc) frida_has_first_match, &matches);
|
||||
|
||||
gum_match_pattern_unref (pattern);
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
frida_has_first_match (GumAddress address, gsize size, gboolean * matches)
|
||||
{
|
||||
*matches = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,41 +1,65 @@
|
||||
namespace Frida {
|
||||
#if DARWIN
|
||||
public sealed class UnwindSitter : Object, Gum.UnwindSectionsProvider {
|
||||
public sealed class UnwindSitter : Object {
|
||||
public weak ProcessInvader invader {
|
||||
get;
|
||||
construct;
|
||||
}
|
||||
|
||||
public unowned Gum.MemoryRange? range {
|
||||
get { return _range; }
|
||||
}
|
||||
private DyldFindUnwindSectionsFunc dyld_find_unwind_sections;
|
||||
|
||||
private Gum.MemoryRange? _range;
|
||||
private Gum.UnwindBroker broker;
|
||||
private const string LIBDYLD = "/usr/lib/system/libdyld.dylib";
|
||||
|
||||
[CCode (has_target = false)]
|
||||
private delegate int DyldFindUnwindSectionsFunc (void * addr, void * info);
|
||||
|
||||
public UnwindSitter (ProcessInvader invader) {
|
||||
Object (invader: invader);
|
||||
}
|
||||
|
||||
construct {
|
||||
_range = invader.get_memory_range ();
|
||||
var interceptor = Gum.Interceptor.obtain ();
|
||||
|
||||
broker = Gum.UnwindBroker.obtain ();
|
||||
broker.add_sections_provider (this);
|
||||
dyld_find_unwind_sections = (DyldFindUnwindSectionsFunc)
|
||||
Gum.Process.find_module_by_name (LIBDYLD).find_export_by_name ("_dyld_find_unwind_sections");
|
||||
|
||||
interceptor.replace ((void *) dyld_find_unwind_sections, (void *) replacement_dyld_find_unwind_sections, this);
|
||||
|
||||
_hook_libunwind ();
|
||||
}
|
||||
|
||||
public override void dispose () {
|
||||
broker.remove_sections_provider (this);
|
||||
var interceptor = Gum.Interceptor.obtain ();
|
||||
|
||||
_unhook_libunwind ();
|
||||
interceptor.revert ((void *) dyld_find_unwind_sections);
|
||||
|
||||
base.dispose ();
|
||||
}
|
||||
|
||||
public bool fill (Gum.Address address, void * info) {
|
||||
_fill_unwind_sections (_range.base_address, _range.base_address + _range.size, info);
|
||||
return true;
|
||||
private static int replacement_dyld_find_unwind_sections (void * addr, void * info) {
|
||||
unowned Gum.InvocationContext context = Gum.Interceptor.get_current_invocation ();
|
||||
unowned UnwindSitter sitter = (UnwindSitter) context.get_replacement_data ();
|
||||
|
||||
Gum.MemoryRange range = sitter.invader.get_memory_range ();
|
||||
var range_end = range.base_address + range.size;
|
||||
|
||||
var address = Gum.Address.from_pointer (addr);
|
||||
#if ARM64
|
||||
address &= 0x7ffffffffULL;
|
||||
#endif
|
||||
var is_ours = address >= range.base_address && address < range_end;
|
||||
if (!is_ours)
|
||||
return sitter.dyld_find_unwind_sections (addr, info);
|
||||
|
||||
_fill_unwind_sections (range.base_address, range_end, info);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public extern static void _fill_unwind_sections (Gum.Address invader_start, Gum.Address invader_end, void * info);
|
||||
public extern static void _hook_libunwind ();
|
||||
public extern static void _unhook_libunwind ();
|
||||
}
|
||||
#else
|
||||
public sealed class UnwindSitter : Object {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include "pipe-glue.h"
|
||||
|
||||
#include <efni.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
@@ -67,7 +66,7 @@ _frida_pipe_transport_create_backend (gchar ** local_address, gchar ** remote_ad
|
||||
|
||||
fcntl (fd, F_SETFD, FD_CLOEXEC);
|
||||
setsockopt (fd, SOL_SOCKET, SO_NOSIGPIPE, &no_sigpipe, sizeof (no_sigpipe));
|
||||
efni_unix_socket_tune_buffer_sizes (fd);
|
||||
frida_unix_socket_tune_buffer_sizes (fd);
|
||||
}
|
||||
|
||||
status = fileport_makeport (sockets[0], &local_wrapper);
|
||||
|
||||
+2
-15
@@ -12,27 +12,14 @@ frida_pipe_get_sddl_string_for_pipe (void)
|
||||
#define DACL_ACE_EVERYONE_RW L"(A;;GRGW;;;WD)"
|
||||
#define SACL_START L"S:"
|
||||
#define SACL_ACE_LOWINTEGRITY_NORW L"(ML;;NWNR;;;LW)"
|
||||
#define DACL_ACE_SYSTEM_RW L"(A;;GRGW;;;SY)"
|
||||
#define DACL_ACE_ADMINS_RW L"(A;;GRGW;;;BA)"
|
||||
|
||||
if (frida_pipe_is_windows_8_or_greater ())
|
||||
{
|
||||
return DACL_START_NOINHERIT
|
||||
DACL_ACE_APPCONTAINER_RW
|
||||
DACL_ACE_EVERYONE_RW
|
||||
DACL_ACE_SYSTEM_RW
|
||||
DACL_ACE_ADMINS_RW
|
||||
SACL_START
|
||||
SACL_ACE_LOWINTEGRITY_NORW;
|
||||
return DACL_START_NOINHERIT DACL_ACE_APPCONTAINER_RW DACL_ACE_EVERYONE_RW SACL_START SACL_ACE_LOWINTEGRITY_NORW;
|
||||
}
|
||||
else if (frida_pipe_is_windows_vista_or_greater ())
|
||||
{
|
||||
return DACL_START_NOINHERIT
|
||||
DACL_ACE_EVERYONE_RW
|
||||
DACL_ACE_SYSTEM_RW
|
||||
DACL_ACE_ADMINS_RW
|
||||
SACL_START
|
||||
SACL_ACE_LOWINTEGRITY_NORW;
|
||||
return DACL_START_NOINHERIT DACL_ACE_EVERYONE_RW SACL_START SACL_ACE_LOWINTEGRITY_NORW;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+1
-3
@@ -1,5 +1,3 @@
|
||||
using Efni;
|
||||
|
||||
namespace Frida {
|
||||
public sealed class PipeTransport : Object {
|
||||
public string local_address {
|
||||
@@ -159,7 +157,7 @@ namespace Frida {
|
||||
UnixSocketAddressType type = UnixSocketAddress.abstract_names_supported ()
|
||||
? UnixSocketAddressType.ABSTRACT
|
||||
: UnixSocketAddressType.PATH;
|
||||
var server_address = new UnixSocketAddress.with_type (path.to_utf8 (), type);
|
||||
var server_address = new UnixSocketAddress.with_type (path, -1, type);
|
||||
|
||||
if (role == "server") {
|
||||
var socket = new Socket (SocketFamily.UNIX, SocketType.STREAM, SocketProtocol.DEFAULT);
|
||||
|
||||
+89
-341
@@ -14,7 +14,7 @@ if not meson.get_compiler('vala').version().endswith('-frida')
|
||||
Frida currently relies on features not yet upstream. Grab the Frida-optimized
|
||||
Vala sources from:
|
||||
|
||||
https://github.com/frida-forks/vala
|
||||
https://github.com/frida/vala
|
||||
|
||||
and compile them with Meson.''')
|
||||
endif
|
||||
@@ -130,10 +130,6 @@ if host_os_family == 'darwin'
|
||||
add_languages('objc', 'objcpp', native: false)
|
||||
endif
|
||||
|
||||
if meson.is_cross_build()
|
||||
add_languages('c', 'cpp', 'vala', native: true)
|
||||
endif
|
||||
|
||||
python = import('python').find_installation()
|
||||
|
||||
if cc.get_argument_syntax() == 'msvc'
|
||||
@@ -228,21 +224,15 @@ helper_name = 'frida-helper' + exe_suffix
|
||||
agent_name = 'frida-agent' + shlib_suffix
|
||||
gadget_name = 'frida-gadget' + shlib_suffix
|
||||
|
||||
frida_libdir_name = f'frida-@api_version@'
|
||||
root_asset_dir = get_option('libdir') / frida_libdir_name
|
||||
root_asset_dir = get_option('libdir') / 'frida'
|
||||
if host_os_family == 'darwin'
|
||||
asset_dir = root_asset_dir
|
||||
default_asset_path_template = get_option('prefix') / get_option('libdir') / frida_libdir_name
|
||||
elif host_os_family == 'windows'
|
||||
asset_dir = root_asset_dir / host_abi
|
||||
asset_dir_modern = root_asset_dir / 'x86_64'
|
||||
asset_dir_legacy = root_asset_dir / 'x86'
|
||||
default_asset_path_template = get_option('prefix') / get_option('libdir') / frida_libdir_name / '<arch>'
|
||||
default_asset_path_template = get_option('prefix') / get_option('libdir') / 'frida'
|
||||
else
|
||||
asset_dir = root_asset_dir / host_cpu_mode
|
||||
asset_dir_modern = root_asset_dir / '64'
|
||||
asset_dir_legacy = root_asset_dir / '32'
|
||||
default_asset_path_template = get_option('prefix') / get_option('libdir') / frida_libdir_name / '<arch>'
|
||||
default_asset_path_template = get_option('prefix') / get_option('libdir') / 'frida' / '<arch>'
|
||||
endif
|
||||
|
||||
asset_path_template = get_option('asset_path_template')
|
||||
@@ -250,22 +240,11 @@ if asset_path_template == ''
|
||||
asset_path_template = default_asset_path_template
|
||||
endif
|
||||
|
||||
is_shared = get_option('default_library') == 'shared'
|
||||
|
||||
assets_mode = get_option('assets')
|
||||
if assets_mode == 'auto'
|
||||
assets_mode = is_shared ? 'installed' : 'embedded'
|
||||
endif
|
||||
|
||||
cdata.set_quoted('FRIDA_LIBDIR', get_option('libdir'))
|
||||
cdata.set_quoted('FRIDA_LIBDIR_NAME', frida_libdir_name)
|
||||
|
||||
if assets_mode == 'embedded'
|
||||
cdata.set('HAVE_EMBEDDED_ASSETS', 1)
|
||||
if get_option('assets') == 'embedded'
|
||||
vala_flags += '--define=HAVE_EMBEDDED_ASSETS'
|
||||
else
|
||||
cdata.set_quoted('FRIDA_HELPER_NAME', helper_name)
|
||||
cdata.set_quoted('FRIDA_AGENT_NAME', agent_name)
|
||||
cdata.set_quoted('FRIDA_HELPER_PATH', asset_path_template / helper_name)
|
||||
cdata.set_quoted('FRIDA_AGENT_PATH', asset_path_template / agent_name)
|
||||
endif
|
||||
|
||||
cdata.set('HAVE_' + host_os_family.to_upper(), 1)
|
||||
@@ -273,15 +252,6 @@ if host_os != host_os_family
|
||||
cdata.set('HAVE_' + host_os.to_upper(), 1)
|
||||
endif
|
||||
|
||||
host_is_prospero = host_os_family == 'freebsd' and cc.get_define('__PROSPERO__') != ''
|
||||
prospero_crt_link_args = []
|
||||
if host_is_prospero
|
||||
cdata.set('HAVE_PROSPERO', 1)
|
||||
vala_flags += '--define=PROSPERO'
|
||||
prospero_crt_link_args += \
|
||||
run_command(cc.cmd_array(), '-print-file-name=crt1.o', check: true).stdout().strip()
|
||||
endif
|
||||
|
||||
cpu_defines = [
|
||||
['x86', 'HAVE_I386'],
|
||||
['x86_64', 'HAVE_I386'],
|
||||
@@ -332,30 +302,28 @@ 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'
|
||||
cdata.set('HAVE_ASAN', 1)
|
||||
endif
|
||||
|
||||
gum_dep = dependency('frida-gum-1.0', default_options: [
|
||||
f'frida_version=@frida_version@',
|
||||
'gumjs=enabled',
|
||||
])
|
||||
gumjs_dep = dependency('frida-gumjs-1.0')
|
||||
gumjs_inspector_dep = dependency('frida-gumjs-inspector-1.0')
|
||||
|
||||
glib_version_req = '>=2.74'
|
||||
glib_options = [
|
||||
'default_library=static',
|
||||
'cocoa=disabled',
|
||||
'selinux=disabled',
|
||||
'xattr=false',
|
||||
'libmount=disabled',
|
||||
'sysprof=disabled',
|
||||
'tests=false',
|
||||
'nls=disabled',
|
||||
]
|
||||
if host_os_family in ['darwin', 'qnx', 'none'] or host_os == 'android' or libc == 'uclibc'
|
||||
glib_options += 'iconv=external'
|
||||
endif
|
||||
if optimize_for_prod
|
||||
glib_options += [
|
||||
'glib_debug=disabled',
|
||||
@@ -364,75 +332,27 @@ if optimize_for_prod
|
||||
]
|
||||
endif
|
||||
|
||||
glib_dep = dependency('glib-2.0', version: glib_version_req, default_options: glib_options)
|
||||
if glib_dep.type_name() == 'internal'
|
||||
have_shared_glib = get_option('default_library') != 'static'
|
||||
else
|
||||
glib_flavor_src = '''
|
||||
#include <glib.h>
|
||||
|
||||
#ifdef GLIB_STATIC_COMPILATION
|
||||
# error GLib is static
|
||||
#endif
|
||||
'''
|
||||
have_shared_glib = cc.compiles(glib_flavor_src, name: 'compiling with shared GLib', dependencies: [glib_dep])
|
||||
endif
|
||||
have_frida_glib = glib_dep.type_name() == 'internal' or cc.has_function('g_thread_set_callbacks', dependencies: [glib_dep])
|
||||
if have_frida_glib
|
||||
cdata.set('HAVE_FRIDA_GLIB', 1)
|
||||
vala_flags += '--define=HAVE_FRIDA_GLIB'
|
||||
endif
|
||||
|
||||
have_in_tree_payloads = not have_shared_glib
|
||||
gum_dep = dependency('frida-gum-1.0', default_options: [
|
||||
'default_library=static',
|
||||
f'frida_version=@frida_version@',
|
||||
'gumjs=' + (have_in_tree_payloads ? 'enabled' : 'disabled'),
|
||||
'inspector=enabled',
|
||||
])
|
||||
if have_in_tree_payloads
|
||||
gumjs_dep = dependency('frida-gumjs-1.0', default_options: ['default_library=static'])
|
||||
endif
|
||||
gumjs_inspector_dep = dependency('frida-gumjs-inspector-1.0', default_options: ['default_library=static'])
|
||||
|
||||
gee_options = [
|
||||
'default_library=static',
|
||||
'disable-introspection=true',
|
||||
]
|
||||
if optimize_for_prod
|
||||
gee_options += 'disable-internal-asserts=true'
|
||||
endif
|
||||
|
||||
glib_dep = dependency('glib-2.0', version: glib_version_req, default_options: glib_options)
|
||||
gobject_dep = dependency('gobject-2.0')
|
||||
gmodule_dep = dependency('gmodule-2.0')
|
||||
gio_dep = dependency('gio-2.0')
|
||||
gee_dep = dependency('gee-0.8', default_options: gee_options)
|
||||
json_glib_dep = dependency('json-glib-1.0', version: '>=1.8', default_options: [
|
||||
'default_library=static',
|
||||
'introspection=disabled',
|
||||
'gtk_doc=disabled',
|
||||
'tests=false',
|
||||
'nls=disabled',
|
||||
])
|
||||
efni_dep = dependency('efni-1.0', default_options: ['default_library=static'])
|
||||
efni_libs = []
|
||||
if efni_dep.type_name() == 'internal'
|
||||
efni_libs += subproject('efni').get_variable('efni')
|
||||
endif
|
||||
efni_vapidir = efni_dep.get_variable('vapidir', default_value: '')
|
||||
if efni_vapidir != ''
|
||||
vala_flags += '--vapidir=' + efni_vapidir
|
||||
endif
|
||||
foreach pkg : efni_dep.get_variable('vala_packages', default_value: '').split()
|
||||
vala_flags += '--pkg=' + pkg
|
||||
endforeach
|
||||
libsoup_dep = dependency('libsoup-3.0', default_options: [
|
||||
'default_library=static',
|
||||
'sqlite:default_library=static',
|
||||
'gssapi=disabled',
|
||||
'ntlm=disabled',
|
||||
'brotli=disabled',
|
||||
'zstd=disabled',
|
||||
'tls_check=false',
|
||||
'introspection=disabled',
|
||||
'vapi=disabled',
|
||||
@@ -441,54 +361,19 @@ libsoup_dep = dependency('libsoup-3.0', default_options: [
|
||||
'tests=false',
|
||||
'sysprof=disabled',
|
||||
])
|
||||
if libsoup_dep.type_name() == 'internal' \
|
||||
or cc.has_function('soup_websocket_connection_pause_input', dependencies: [libsoup_dep])
|
||||
vala_flags += '--define=HAVE_SOUP_WEBSOCKET_BACKPRESSURE'
|
||||
endif
|
||||
brotlidec_dep = dependency('libbrotlidec', default_options: ['default_library=static'])
|
||||
capstone_dep = dependency('capstone', default_options: [
|
||||
'default_library=static',
|
||||
'archs=all',
|
||||
'use_arch_registration=true',
|
||||
'x86_att_disable=true',
|
||||
'cli=disabled',
|
||||
])
|
||||
if capstone_dep.type_name() != 'internal' \
|
||||
and not cc.has_function('cs_arch_register_x86', dependencies: [capstone_dep])
|
||||
add_project_arguments(
|
||||
'-Dcs_arch_register_x86()=',
|
||||
'-Dcs_arch_register_arm()=',
|
||||
'-Dcs_arch_register_arm64()=',
|
||||
'-Dcs_arch_register_mips()=',
|
||||
language: ['c', 'objc'],
|
||||
)
|
||||
endif
|
||||
brotlidec_dep = dependency('libbrotlidec')
|
||||
quickjs_dep = dependency('quickjs', required: get_option('barebone_backend'), default_options: [
|
||||
'default_library=static',
|
||||
'libc=false',
|
||||
'bignum=true',
|
||||
'atomics=disabled',
|
||||
'stack_check=' + ((host_os_family == 'none') ? 'enabled' : 'disabled'),
|
||||
'stack_mode=' + ((host_os_family == 'none') ? 'optimize' : 'default'),
|
||||
'stack_check=disabled',
|
||||
])
|
||||
lzfse_dep = dependency('lzfse', required: false, default_options: ['default_library=static'])
|
||||
lzfse_from_system = false
|
||||
if not lzfse_dep.found() and not meson.is_cross_build()
|
||||
if cc.has_header_symbol('lzfse.h', 'lzfse_decode_buffer')
|
||||
lzfse_lib = cc.find_library('lzfse', required: false)
|
||||
if lzfse_lib.found()
|
||||
lzfse_dep = declare_dependency(dependencies: lzfse_lib)
|
||||
lzfse_from_system = true
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
if not lzfse_dep.found()
|
||||
lzfse_dep = dependency('lzfse', required: get_option('barebone_backend'), default_options: ['default_library=static'])
|
||||
endif
|
||||
lzfse_dep = dependency('lzfse', required: get_option('barebone_backend'))
|
||||
|
||||
native_glib_dep = dependency('glib-2.0', version: glib_version_req, native: true, default_options: glib_options)
|
||||
native_gio_dep = dependency('gio-2.0', native: true)
|
||||
native_gee_dep = dependency('gee-0.8', native: true, default_options: gee_options)
|
||||
native_brotlienc_dep = dependency('libbrotlienc', native: true, default_options: ['default_library=static'])
|
||||
native_brotlienc_dep = dependency('libbrotlienc', native: true)
|
||||
|
||||
if host_os_family == 'windows'
|
||||
gio_windows_dep = dependency('gio-windows-2.0')
|
||||
@@ -496,15 +381,12 @@ else
|
||||
gio_unix_dep = dependency('gio-unix-2.0')
|
||||
endif
|
||||
|
||||
have_local_backend = get_option('local_backend').allowed()
|
||||
|
||||
if host_os_family == 'linux' and have_local_backend
|
||||
libbpf_dep = dependency('libbpf', default_options: ['default_library=static'])
|
||||
if host_os_family == 'linux'
|
||||
libbpf_dep = dependency('libbpf')
|
||||
endif
|
||||
|
||||
if host_os == 'android'
|
||||
minizip_dep = dependency('minizip', required: false, default_options: [
|
||||
'default_library=static',
|
||||
'zlib=enabled',
|
||||
'lzma=disabled',
|
||||
])
|
||||
@@ -548,6 +430,7 @@ else
|
||||
codesign = ''
|
||||
endif
|
||||
|
||||
have_local_backend = get_option('local_backend').allowed()
|
||||
have_simmy_backend = get_option('simmy_backend') \
|
||||
.disable_auto_if(host_os != 'macos') \
|
||||
.require(host_os == 'macos', error_message: 'Simmy backend is only available on macOS') \
|
||||
@@ -561,12 +444,11 @@ have_droidy_backend = get_option('droidy_backend') \
|
||||
have_socket_backend = get_option('socket_backend').allowed()
|
||||
have_barebone_backend = get_option('barebone_backend') \
|
||||
.disable_if(not (quickjs_dep.found() and lzfse_dep.found())) \
|
||||
.disable_auto_if(not host_docks_mobile_devices and host_os != 'android') \
|
||||
.disable_auto_if(not host_docks_mobile_devices) \
|
||||
.allowed()
|
||||
compiler_backend_opt = get_option('compiler_backend') \
|
||||
.disable_auto_if(host_os == 'watchos')
|
||||
have_compiler_backend = false
|
||||
compiler_backend_mode = ''
|
||||
if compiler_backend_opt.allowed()
|
||||
go = find_program('go', native: true, required: false)
|
||||
if go.found()
|
||||
@@ -577,13 +459,9 @@ if compiler_backend_opt.allowed()
|
||||
files('tools' / 'cgo' / 'detect.py'),
|
||||
go,
|
||||
host_os,
|
||||
host_os_family,
|
||||
host_abi,
|
||||
libc,
|
||||
exe_suffix,
|
||||
shlib_suffix,
|
||||
cc.get_id(),
|
||||
assets_mode,
|
||||
'>>>', cc.cmd_array(), '<<<',
|
||||
'>>>', ar, '<<<',
|
||||
'>>>', nm, '<<<',
|
||||
@@ -596,33 +474,12 @@ if compiler_backend_opt.allowed()
|
||||
status = lines[0]
|
||||
if status == 'ok'
|
||||
have_compiler_backend = true
|
||||
cdata.set('HAVE_COMPILER_BACKEND', 1)
|
||||
compiler_backend_mode = lines[1]
|
||||
go_config = configure_file(
|
||||
input: 'tools' / 'cgo' / 'go-config.json.in',
|
||||
output: 'go-config.json',
|
||||
configuration: {'GO_CONFIG': lines[2]},
|
||||
)
|
||||
|
||||
if compiler_backend_mode == 'c-archive'
|
||||
vala_flags += '--define=COMPILER_BACKEND_LINKED'
|
||||
cdata.set('HAVE_COMPILER_BACKEND_LINKED', 1)
|
||||
elif compiler_backend_mode == 'c-shared'
|
||||
if assets_mode == 'installed'
|
||||
vala_flags += '--define=COMPILER_BACKEND_INSTALLED_LIBRARY'
|
||||
cdata.set_quoted('FRIDA_COMPILER_BACKEND_NAME', 'frida-compiler-backend' + shlib_suffix)
|
||||
else
|
||||
vala_flags += '--define=COMPILER_BACKEND_EMBEDDED_LIBRARY'
|
||||
endif
|
||||
elif compiler_backend_mode == 'pie'
|
||||
if assets_mode == 'installed'
|
||||
vala_flags += '--define=COMPILER_BACKEND_INSTALLED_EXECUTABLE'
|
||||
cdata.set_quoted('FRIDA_COMPILER_BACKEND_NAME', 'frida-compiler-backend' + exe_suffix)
|
||||
else
|
||||
vala_flags += '--define=COMPILER_BACKEND_EMBEDDED_EXECUTABLE'
|
||||
endif
|
||||
else
|
||||
error('Unsupported compiler backend mode: ' + compiler_backend_mode)
|
||||
tokens = lines[1].split(' ')
|
||||
go_mode = tokens[0]
|
||||
go_config = tokens[1]
|
||||
compiler_backend_static_compilation = go_mode == 'c-archive'
|
||||
if compiler_backend_static_compilation
|
||||
vala_flags += '--define=COMPILER_BACKEND_STATIC_COMPILATION'
|
||||
endif
|
||||
else
|
||||
error_message = lines[1]
|
||||
@@ -633,9 +490,9 @@ if compiler_backend_opt.allowed()
|
||||
endif
|
||||
endif
|
||||
elif compiler_backend_opt.enabled()
|
||||
error('Need Go >= 1.26 to build the Compiler backend powered by ESBuild and typescript-go')
|
||||
error('Need Go >= 1.24 to build the Compiler backend powered by ESBuild and typescript-go')
|
||||
else
|
||||
warning('Building without Compiler backend: Go >= 1.26 not found')
|
||||
warning('Building without Compiler backend: Go >= 1.24 not found')
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -691,10 +548,8 @@ endif
|
||||
gi_dep = dependency('gobject-introspection-1.0', required: false)
|
||||
if gi_dep.found()
|
||||
girdir = gi_dep.get_variable('girdir')
|
||||
typelibdir = gi_dep.get_variable('typelibdir')
|
||||
else
|
||||
girdir = get_option('prefix') / get_option('datadir') / 'gir-1.0'
|
||||
typelibdir = get_option('prefix') / get_option('libdir') / 'girepository-1.0'
|
||||
endif
|
||||
|
||||
vapidir = get_option('prefix') / get_option('datadir') / 'vala' / 'vapi'
|
||||
@@ -703,15 +558,12 @@ gum_vala_args = [
|
||||
'--pkg=frida-gum-1.0',
|
||||
'--vapidir=' + gum_dep.get_variable('frida_vapidir'),
|
||||
]
|
||||
gumjs_vala_args = ['--pkg=frida-gumjs-1.0', '--pkg=gio-2.0', gum_vala_args]
|
||||
gumjs_inspector_vala_args = ['--pkg=frida-gumjs-inspector-1.0', gum_vala_args]
|
||||
|
||||
if have_in_tree_payloads
|
||||
gumjs_vala_args = ['--pkg=frida-gumjs-1.0', '--pkg=gio-2.0', gum_vala_args]
|
||||
|
||||
have_v8 = gumjs_dep.get_variable('gumjs_v8') == 'enabled'
|
||||
if have_v8
|
||||
vala_flags += ['--define=HAVE_V8']
|
||||
endif
|
||||
have_v8 = gumjs_dep.get_variable('gumjs_v8') == 'enabled'
|
||||
if have_v8
|
||||
vala_flags += ['--define=HAVE_V8']
|
||||
endif
|
||||
|
||||
backend_deps_private = []
|
||||
@@ -719,39 +571,37 @@ backend_reqs_private = []
|
||||
backend_libs_private = []
|
||||
|
||||
openssl_options = [
|
||||
'default_library=static',
|
||||
'cli=disabled',
|
||||
]
|
||||
if host_os_family == 'windows' and cc.get_argument_syntax() != 'msvc'
|
||||
openssl_options += 'asm=disabled'
|
||||
endif
|
||||
openssl_dep = dependency('openssl',
|
||||
required: get_option('connectivity').enabled(),
|
||||
required: have_fruity_backend or get_option('connectivity').enabled(),
|
||||
modules: cc.get_argument_syntax() == 'msvc' ? ['OpenSSL::SSL'] : [],
|
||||
default_options: openssl_options,
|
||||
)
|
||||
|
||||
idun_libs = []
|
||||
have_idund_blob = false
|
||||
if have_fruity_backend
|
||||
idun_dep = dependency('idun-1.0', default_options: ['default_library=static'])
|
||||
backend_reqs_private += 'idun-1.0'
|
||||
if idun_dep.type_name() == 'internal'
|
||||
idun_sp = subproject('idun')
|
||||
idun_libs += idun_sp.get_variable('idun')
|
||||
if assets_mode == 'embedded' and idun_sp.get_variable('build_daemon')
|
||||
idund_raw = idun_sp.get_variable('idund')
|
||||
have_idund_blob = true
|
||||
vala_flags += '--define=HAVE_IDUND_BLOB'
|
||||
endif
|
||||
endif
|
||||
idun_vapidir = idun_dep.get_variable('vapidir', default_value: '')
|
||||
if idun_vapidir != ''
|
||||
vala_flags += '--vapidir=' + idun_vapidir
|
||||
endif
|
||||
foreach pkg : idun_dep.get_variable('vala_packages', default_value: '').split()
|
||||
vala_flags += '--pkg=' + pkg
|
||||
foreach dep : ['libnghttp2', 'libngtcp2', 'libngtcp2_crypto_quictls', 'libusb-1.0']
|
||||
backend_deps_private += dependency(dep)
|
||||
backend_reqs_private += dep
|
||||
endforeach
|
||||
|
||||
lwip_options = [
|
||||
'ipv4=disabled',
|
||||
'ipv6=enabled',
|
||||
'dns=disabled',
|
||||
'arp=disabled',
|
||||
'ethernet=enabled',
|
||||
]
|
||||
if optimize_for_prod
|
||||
lwip_options += 'lwip_debug=disabled'
|
||||
else
|
||||
lwip_options += 'lwip_debug=enabled'
|
||||
endif
|
||||
backend_deps_private += dependency('lwip', default_options: lwip_options)
|
||||
backend_reqs_private += 'lwip'
|
||||
endif
|
||||
|
||||
if quickjs_dep.found()
|
||||
@@ -761,117 +611,57 @@ endif
|
||||
|
||||
if lzfse_dep.found()
|
||||
backend_deps_private += lzfse_dep
|
||||
if lzfse_from_system
|
||||
backend_libs_private += '-llzfse'
|
||||
else
|
||||
backend_reqs_private += 'lzfse'
|
||||
endif
|
||||
backend_reqs_private += 'lzfse'
|
||||
endif
|
||||
|
||||
if host_os_family == 'linux' and have_local_backend
|
||||
if host_os_family == 'linux'
|
||||
backend_deps_private += libbpf_dep
|
||||
backend_reqs_private += 'libbpf'
|
||||
endif
|
||||
|
||||
if host_os_family == 'darwin' \
|
||||
or (host_os_family == 'freebsd' and not host_is_prospero) \
|
||||
or (host_os_family == 'linux' and cc.has_function('openpty', prefix: '#include <pty.h>'))
|
||||
if host_os_family in ['darwin', 'freebsd'] or (host_os_family == 'linux' and cc.has_function('openpty', prefix: '#include <pty.h>'))
|
||||
vala_flags += '--define=HAVE_OPENPTY'
|
||||
endif
|
||||
|
||||
if host_os == 'android'
|
||||
termux_elf_cleaner = find_program('termux-elf-cleaner', native: true)
|
||||
selinux_options = [
|
||||
'default_library=static',
|
||||
'regex=disabled',
|
||||
]
|
||||
libselinux_dep = dependency('libselinux', version: '>=3.0', default_options: selinux_options)
|
||||
libsepol_dep = dependency('libsepol', version: '>=3.0', default_options: selinux_options)
|
||||
libselinux_dep = dependency('libselinux', version: '>=3.0')
|
||||
libsepol_dep = dependency('libsepol', version: '>=3.0')
|
||||
backend_deps_private += [libselinux_dep, libsepol_dep]
|
||||
backend_reqs_private += ['libselinux', 'libsepol']
|
||||
else
|
||||
termux_elf_cleaner = []
|
||||
endif
|
||||
|
||||
tls_provider_dep = dependency('gioopenssl', required: get_option('connectivity'), default_options: [
|
||||
'gnutls=disabled',
|
||||
'openssl=enabled',
|
||||
'libproxy=disabled',
|
||||
'gnome_proxy=disabled',
|
||||
'tests=false',
|
||||
])
|
||||
tls_provider_vala_args = []
|
||||
use_apple_tls = false
|
||||
if have_shared_glib
|
||||
tls_provider_dep = gio_dep
|
||||
else
|
||||
apple_tls_opt = get_option('apple_tls')
|
||||
if host_os_family == 'darwin' and not apple_tls_opt.disabled()
|
||||
apple_tls_deployment_check = '''
|
||||
#include <Availability.h>
|
||||
|
||||
#if defined (__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 150000
|
||||
# error macOS deployment target below 15.0
|
||||
#endif
|
||||
#if defined (__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 180000
|
||||
# error iOS deployment target below 18.0
|
||||
#endif
|
||||
#if defined (__TV_OS_VERSION_MIN_REQUIRED) && __TV_OS_VERSION_MIN_REQUIRED < 180000
|
||||
# error tvOS deployment target below 18.0
|
||||
#endif
|
||||
#if defined (__WATCH_OS_VERSION_MIN_REQUIRED) && __WATCH_OS_VERSION_MIN_REQUIRED < 110000
|
||||
# error watchOS deployment target below 11.0
|
||||
#endif
|
||||
'''
|
||||
use_apple_tls = cc.compiles(apple_tls_deployment_check, name: 'Apple TLS backend deployment target')
|
||||
if apple_tls_opt.enabled() and not use_apple_tls
|
||||
error('apple_tls explicitly enabled but deployment target is too old')
|
||||
endif
|
||||
elif apple_tls_opt.enabled()
|
||||
error('apple_tls is only supported on Darwin hosts')
|
||||
endif
|
||||
if use_apple_tls
|
||||
tls_provider_name = 'gioapple'
|
||||
tls_provider_define_name = 'HAVE_GIOAPPLE'
|
||||
tls_provider_backend_options = [
|
||||
'gnutls=disabled',
|
||||
'openssl=disabled',
|
||||
'apple=enabled',
|
||||
]
|
||||
else
|
||||
tls_provider_name = 'gioopenssl'
|
||||
tls_provider_define_name = 'HAVE_GIOOPENSSL'
|
||||
tls_provider_backend_options = [
|
||||
'gnutls=disabled',
|
||||
'openssl=enabled',
|
||||
'apple=disabled',
|
||||
]
|
||||
endif
|
||||
tls_provider_dep = dependency(tls_provider_name,
|
||||
required: get_option('connectivity'),
|
||||
default_options: tls_provider_backend_options + [
|
||||
'libproxy=disabled',
|
||||
'gnome_proxy=disabled',
|
||||
'tests=false',
|
||||
],
|
||||
)
|
||||
if tls_provider_dep.found()
|
||||
tls_provider_vala_args += [
|
||||
'--pkg=' + tls_provider_name,
|
||||
'--vapidir=' + tls_provider_dep.get_variable('vapidir'),
|
||||
]
|
||||
cdata.set(tls_provider_define_name, 1)
|
||||
vala_flags += ['--define=' + tls_provider_define_name]
|
||||
backend_deps_private += tls_provider_dep
|
||||
backend_reqs_private += tls_provider_name
|
||||
endif
|
||||
if tls_provider_dep.found()
|
||||
tls_provider_vala_args += [
|
||||
'--pkg=gioopenssl',
|
||||
'--vapidir=' + tls_provider_dep.get_variable('vapidir'),
|
||||
]
|
||||
cdata.set('HAVE_GIOOPENSSL', 1)
|
||||
vala_flags += ['--define=HAVE_GIOOPENSSL']
|
||||
backend_deps_private += tls_provider_dep
|
||||
backend_reqs_private += 'gioopenssl'
|
||||
endif
|
||||
|
||||
nice_dep = dependency('nice', required: get_option('connectivity'), default_options: [
|
||||
'default_library=static',
|
||||
'gupnp=disabled',
|
||||
'gstreamer=disabled',
|
||||
'crypto-library=auto',
|
||||
'crypto-library=openssl',
|
||||
'examples=disabled',
|
||||
'tests=disabled',
|
||||
'introspection=disabled',
|
||||
])
|
||||
if nice_dep.found()
|
||||
usrsctp_dep = dependency('usrsctp', default_options: [
|
||||
'default_library=static',
|
||||
'sctp_inet=false',
|
||||
'sctp_inet6=false',
|
||||
'sctp_build_programs=false',
|
||||
@@ -879,12 +669,8 @@ if nice_dep.found()
|
||||
|
||||
cdata.set('HAVE_NICE', 1)
|
||||
vala_flags += ['--define=HAVE_NICE']
|
||||
backend_deps_private += [nice_dep, usrsctp_dep]
|
||||
backend_reqs_private += ['nice', 'usrsctp']
|
||||
if host_os != 'macos'
|
||||
backend_deps_private += openssl_dep
|
||||
backend_reqs_private += 'openssl'
|
||||
endif
|
||||
backend_deps_private += [nice_dep, openssl_dep, usrsctp_dep]
|
||||
backend_reqs_private += ['nice', 'openssl', 'usrsctp']
|
||||
|
||||
if host_os_family in ['darwin', 'freebsd', 'qnx']
|
||||
cdata.set('HAVE_SCONN_LEN', 1)
|
||||
@@ -894,26 +680,20 @@ else
|
||||
endif
|
||||
|
||||
if host_os_family == 'windows'
|
||||
backend_libs_private += ['-lsetupapi', '-lshlwapi']
|
||||
backend_libs_private += ['-lsetupapi']
|
||||
endif
|
||||
if host_os_family == 'darwin'
|
||||
backend_libs_private += ['-Wl,-framework,Foundation', '-Wl,-framework,CoreFoundation', '-lbsm']
|
||||
backend_libs_private += ['-Wl,-framework,Foundation', '-lbsm']
|
||||
endif
|
||||
if host_os == 'macos'
|
||||
backend_libs_private += ['-Wl,-framework,AppKit']
|
||||
if have_compiler_backend
|
||||
backend_libs_private += ['-Wl,-framework,CoreServices']
|
||||
endif
|
||||
endif
|
||||
if host_os in ['ios', 'tvos']
|
||||
backend_libs_private += ['-Wl,-framework,CoreGraphics', '-Wl,-framework,UIKit']
|
||||
endif
|
||||
if host_os_family == 'freebsd' and not host_is_prospero
|
||||
if host_os_family == 'freebsd'
|
||||
backend_libs_private += ['-lutil']
|
||||
endif
|
||||
if host_is_prospero
|
||||
backend_libs_private += ['-lSceSystemService', '-lSceUserService']
|
||||
endif
|
||||
|
||||
if get_option('devkits').length() != 0
|
||||
if get_option('default_library') != 'static'
|
||||
@@ -973,30 +753,16 @@ post_process = [
|
||||
'@INPUT0@',
|
||||
]
|
||||
|
||||
executable_no_exports_link_args = []
|
||||
executable_no_exports_link_depends = []
|
||||
if host_os_family == 'darwin'
|
||||
script = meson.project_source_root() / 'tools' / 'executable-no-exports.symbols'
|
||||
executable_no_exports_link_args = ['-Wl,-exported_symbols_list,' + script]
|
||||
executable_no_exports_link_depends = [script]
|
||||
elif host_os_family != 'windows'
|
||||
script_name = (host_os == 'freebsd' and not host_is_prospero) ? 'executable-no-exports-freebsd.version' : 'executable-no-exports.version'
|
||||
script = meson.project_source_root() / 'tools' / script_name
|
||||
executable_no_exports_link_args = ['-Wl,--version-script,' + script]
|
||||
executable_no_exports_link_depends = [script]
|
||||
endif
|
||||
|
||||
compile_js_agent = files('tools' / 'compile-js-agent.py')
|
||||
|
||||
mapper_opt = get_option('mapper')
|
||||
if mapper_opt.auto()
|
||||
have_mapper = host_os_family in ['windows', 'darwin', 'linux']
|
||||
have_mapper = host_os_family == 'darwin'
|
||||
else
|
||||
have_mapper = mapper_opt.enabled()
|
||||
endif
|
||||
if have_mapper
|
||||
cdata.set('HAVE_MAPPER', 1)
|
||||
vala_flags += '--define=HAVE_MAPPER'
|
||||
endif
|
||||
|
||||
configure_file(
|
||||
@@ -1017,20 +783,11 @@ if cc.get_id() == 'gcc' and cc.compiles('#if __GNUC__ >= 5\n#error NOTNEEDED\n#e
|
||||
add_project_arguments('-w', language: 'c')
|
||||
endif
|
||||
|
||||
local_vapidir = meson.current_source_dir() / 'vapi'
|
||||
vapidir = meson.current_source_dir() / 'vapi'
|
||||
vala_flags += [
|
||||
'--vapidir=' + local_vapidir,
|
||||
'--vapidir=' + vapidir,
|
||||
'--pkg', 'config',
|
||||
]
|
||||
if gee_dep.type_name() not in ['internal', 'cmake']
|
||||
gee_prefix = gee_dep.get_variable('prefix', default_value: '')
|
||||
if gee_prefix != ''
|
||||
gee_vapidir = gee_prefix / 'share' / 'vala' / 'vapi'
|
||||
if fs.is_dir(gee_vapidir)
|
||||
vala_flags += '--vapidir=' + gee_vapidir
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
vala_flags += '--define=' + host_os_family.to_upper()
|
||||
if host_os != host_os_family
|
||||
@@ -1042,22 +799,13 @@ if host_abi != host_arch
|
||||
endif
|
||||
vala_flags += '--define=' + host_machine.endian().to_upper() + '_ENDIAN'
|
||||
add_project_arguments(vala_flags, language: 'vala')
|
||||
add_project_arguments('-I' + local_vapidir, language: 'c')
|
||||
add_project_arguments('-I' + vapidir, language: 'c')
|
||||
|
||||
native_vala_flags = [
|
||||
'--vapidir=' + local_vapidir,
|
||||
'--vapidir=' + meson.current_source_dir() / 'vapi',
|
||||
]
|
||||
if native_gee_dep.type_name() not in ['internal', 'cmake']
|
||||
native_gee_prefix = native_gee_dep.get_variable('prefix', default_value: '')
|
||||
if native_gee_prefix != ''
|
||||
native_gee_vapidir = native_gee_prefix / 'share' / 'vala' / 'vapi'
|
||||
if fs.is_dir(native_gee_vapidir)
|
||||
native_vala_flags += '--vapidir=' + native_gee_vapidir
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
add_project_arguments(native_vala_flags, language: 'vala', native: true)
|
||||
add_project_arguments('-I' + local_vapidir, language: 'c', native: true)
|
||||
add_project_arguments('-I' + vapidir, language: 'c', native: true)
|
||||
|
||||
subdir('compat')
|
||||
subdir('tools')
|
||||
@@ -1092,7 +840,7 @@ summary(
|
||||
summary(
|
||||
{
|
||||
'compat': compat_summary,
|
||||
'assets': assets_mode,
|
||||
'assets': get_option('assets'),
|
||||
'mapper': have_mapper,
|
||||
'connectivity': tls_provider_dep.found(),
|
||||
'gadget': build_gadget,
|
||||
|
||||
+2
-8
@@ -48,8 +48,8 @@ option('compiler_backend',
|
||||
|
||||
option('assets',
|
||||
type: 'combo',
|
||||
choices: ['auto', 'embedded', 'installed'],
|
||||
value: 'auto',
|
||||
choices: ['embedded', 'installed'],
|
||||
value: 'embedded',
|
||||
description: 'Whether assets such as frida-agent should be embedded vs installed and loaded at runtime'
|
||||
)
|
||||
|
||||
@@ -143,12 +143,6 @@ option('connectivity',
|
||||
description: 'Internet connectivity features (TLS and ICE support)'
|
||||
)
|
||||
|
||||
option('apple_tls',
|
||||
type: 'feature',
|
||||
value: 'auto',
|
||||
description: 'Use the Apple TLS backend (requires recent deployment targets); auto-detected when on a Darwin host'
|
||||
)
|
||||
|
||||
option('mapper',
|
||||
type: 'feature',
|
||||
value: 'auto',
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
# No exported symbols.
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
global:
|
||||
# FreeBSD needs these two:
|
||||
__progname;
|
||||
environ;
|
||||
|
||||
local:
|
||||
*;
|
||||
};
|
||||
+14
-2
@@ -2,6 +2,18 @@ portal_sources = [
|
||||
'portal.vala',
|
||||
]
|
||||
|
||||
extra_link_args = []
|
||||
extra_link_depends = []
|
||||
if host_os_family == 'darwin'
|
||||
symlist = 'frida-portal.symbols'
|
||||
extra_link_args += ['-Wl,-exported_symbols_list,' + meson.current_source_dir() / symlist]
|
||||
extra_link_depends += [symlist]
|
||||
elif host_os_family != 'windows'
|
||||
symscript = 'frida-portal.version'
|
||||
extra_link_args += ['-Wl,--version-script,' + meson.current_source_dir() / symscript]
|
||||
extra_link_depends += [symscript]
|
||||
endif
|
||||
|
||||
extra_deps = []
|
||||
if tls_provider_dep.found()
|
||||
extra_deps += tls_provider_dep
|
||||
@@ -9,8 +21,8 @@ endif
|
||||
|
||||
raw_portal = executable('frida-portal-raw', portal_sources,
|
||||
vala_args: [core_vala_args, tls_provider_vala_args, '--pkg=posix'],
|
||||
link_args: executable_no_exports_link_args,
|
||||
link_depends: executable_no_exports_link_depends,
|
||||
link_args: extra_link_args,
|
||||
link_depends: extra_link_depends,
|
||||
dependencies: [core_dep] + extra_deps,
|
||||
)
|
||||
|
||||
|
||||
+1
-3
@@ -39,9 +39,7 @@ namespace Frida.Portal {
|
||||
};
|
||||
|
||||
private static int main (string[] args) {
|
||||
#if HAVE_GIOAPPLE
|
||||
GIOApple.register ();
|
||||
#elif HAVE_GIOOPENSSL
|
||||
#if HAVE_GIOOPENSSL
|
||||
GIOOpenSSL.register ();
|
||||
#endif
|
||||
|
||||
|
||||
+1
-1
Submodule releng updated: 164a6a4117...7ed66fe687.
@@ -1,11 +0,0 @@
|
||||
{
|
||||
global:
|
||||
# FreeBSD needs these two:
|
||||
__progname;
|
||||
environ;
|
||||
# Allow users to load the server as a shared library with dlopen() and call main() directly
|
||||
main;
|
||||
|
||||
local:
|
||||
*;
|
||||
};
|
||||
@@ -1,2 +1 @@
|
||||
# Allow users to load the server as a shared library with dlopen() and call main() directly
|
||||
_main
|
||||
# No exported symbols.
|
||||
@@ -1,5 +1,8 @@
|
||||
{
|
||||
global:
|
||||
# FreeBSD needs these two:
|
||||
__progname;
|
||||
environ;
|
||||
# Allow users to load the server as a shared library with dlopen() and call main() directly
|
||||
main;
|
||||
|
||||
|
||||
@@ -359,11 +359,5 @@
|
||||
<true/>
|
||||
<key>com.apple.private.amfi.can-execute-cdhash</key>
|
||||
<true/>
|
||||
<key>com.apple.private.FairPlayIOKitUserClient.access</key>
|
||||
<true/>
|
||||
<key>com.apple.security.iokit-user-client-class</key>
|
||||
<array>
|
||||
<string>com_apple_driver_FairPlayIOKitUserClient</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
+3
-8
@@ -19,7 +19,7 @@ if host_os_family == 'darwin'
|
||||
extra_link_args += ['-Wl,-exported_symbols_list,' + meson.current_source_dir() / symlist]
|
||||
extra_link_depends += [symlist]
|
||||
elif host_os_family != 'windows'
|
||||
symscript = (host_os == 'freebsd' and not host_is_prospero) ? 'frida-server-freebsd.version' : 'frida-server.version'
|
||||
symscript = 'frida-server.version'
|
||||
extra_link_args += ['-Wl,--version-script,' + meson.current_source_dir() / symscript]
|
||||
extra_link_depends += [symscript]
|
||||
endif
|
||||
@@ -29,20 +29,15 @@ if host_os == 'macos'
|
||||
extra_link_depends += [server_plist]
|
||||
endif
|
||||
|
||||
server_deps = [core_dep]
|
||||
if host_os_family == 'darwin'
|
||||
server_deps += dependency('appleframeworks', modules: ['CoreFoundation'])
|
||||
endif
|
||||
|
||||
raw_server = executable('frida-server-raw', server_sources,
|
||||
vala_args: [core_vala_args, '--pkg=posix'],
|
||||
link_args: extra_link_args,
|
||||
link_depends: extra_link_depends,
|
||||
dependencies: server_deps,
|
||||
dependencies: [core_dep],
|
||||
)
|
||||
|
||||
server_name = 'frida-server' + exe_suffix
|
||||
need_universal_server = assets_mode == 'installed' and server_compat != ''
|
||||
need_universal_server = get_option('assets') == 'installed' and server_compat != ''
|
||||
|
||||
server = custom_target('frida-server',
|
||||
input: [raw_server, 'frida-server.xcent'],
|
||||
|
||||
@@ -29,8 +29,6 @@ void CFLog (CFLogLevel level, CFStringRef format, ...);
|
||||
|
||||
#elif defined (HAVE_ANDROID)
|
||||
# include <android/log.h>
|
||||
#elif defined (HAVE_PROSPERO)
|
||||
# include <ps5/klog.h>
|
||||
#else
|
||||
# include <stdio.h>
|
||||
#endif
|
||||
@@ -139,13 +137,6 @@ frida_server_on_log_message (const gchar * log_domain, GLogLevelFlags log_level,
|
||||
}
|
||||
|
||||
__android_log_write (priority, log_domain, message);
|
||||
#elif defined (HAVE_PROSPERO)
|
||||
(void) user_data;
|
||||
|
||||
if (log_domain != NULL)
|
||||
klog_printf ("%s: %s\n", log_domain, message);
|
||||
else
|
||||
klog_printf ("%s\n", message);
|
||||
#else
|
||||
FILE * file = NULL;
|
||||
const gchar * severity = NULL;
|
||||
|
||||
+4
-4
@@ -1,5 +1,3 @@
|
||||
using Efni;
|
||||
|
||||
namespace Frida.Server {
|
||||
private static Application application;
|
||||
|
||||
@@ -106,8 +104,9 @@ namespace Frida.Server {
|
||||
return true;
|
||||
});
|
||||
int prefix_pos = program_path.last_index_of (Config.FRIDA_PREFIX + "/");
|
||||
if (prefix_pos != -1 && prefix_pos != 0)
|
||||
TemporaryDirectory.use_sysroot (program_path[:prefix_pos]);
|
||||
if (prefix_pos != -1 && prefix_pos != 0) {
|
||||
options.sysroot = program_path[:prefix_pos];
|
||||
}
|
||||
#endif
|
||||
|
||||
PolicySoftenerFlavor softener_flavor = SYSTEM;
|
||||
@@ -200,6 +199,7 @@ namespace Frida.Server {
|
||||
private static int run_application (string? device_id, EndpointParameters endpoint_params, ControlServiceOptions options,
|
||||
ReadyHandler on_ready) {
|
||||
TemporaryDirectory.always_use ((directory != null) ? directory : DEFAULT_DIRECTORY);
|
||||
TemporaryDirectory.use_sysroot (options.sysroot);
|
||||
|
||||
application = new Application (device_id, endpoint_params, options);
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
using Efni;
|
||||
|
||||
namespace Frida {
|
||||
public sealed class AgentContainer : Object, AgentSessionProvider {
|
||||
public DBusConnection connection {
|
||||
@@ -11,7 +9,9 @@ namespace Frida {
|
||||
[CCode (has_target = false)]
|
||||
private delegate void AgentMainFunc (string data, ref UnloadPolicy unload_policy, void * injector_state);
|
||||
private AgentMainFunc main_impl;
|
||||
#if !LINUX
|
||||
#if LINUX
|
||||
private FileDescriptor agent_ctrlfd_for_peer;
|
||||
#else
|
||||
private PipeTransport transport;
|
||||
#endif
|
||||
private string transport_address;
|
||||
@@ -38,7 +38,8 @@ namespace Frida {
|
||||
if (Posix.socketpair (Posix.AF_UNIX, Posix.SOCK_STREAM, 0, agent_ctrlfds) != 0)
|
||||
throw new Error.NOT_SUPPORTED ("Unable to allocate socketpair");
|
||||
var agent_ctrlfd = new FileDescriptor (agent_ctrlfds[0]);
|
||||
container.transport_address = "socket:%d".printf (agent_ctrlfds[1]);
|
||||
container.agent_ctrlfd_for_peer = new FileDescriptor (agent_ctrlfds[1]);
|
||||
container.transport_address = "";
|
||||
|
||||
try {
|
||||
Socket socket = new Socket.from_fd (agent_ctrlfd.handle);
|
||||
@@ -113,10 +114,18 @@ namespace Frida {
|
||||
|
||||
private bool run () {
|
||||
UnloadPolicy unload_policy = IMMEDIATE;
|
||||
void * injector_state = null;
|
||||
|
||||
#if LINUX
|
||||
var s = LinuxInjectorState ();
|
||||
s.frida_ctrlfd = -1;
|
||||
s.agent_ctrlfd = agent_ctrlfd_for_peer.steal ();
|
||||
injector_state = &s;
|
||||
#endif
|
||||
|
||||
string agent_parameters = transport_address + "|exit-monitor:off|thread-suspend-monitor:off";
|
||||
|
||||
main_impl (agent_parameters, ref unload_policy, null);
|
||||
main_impl (agent_parameters, ref unload_policy, injector_state);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ helper.dex: build/frida-helper.jar
|
||||
$<
|
||||
mv build/classes.dex $@
|
||||
|
||||
build/frida-helper.jar: re/frida/Helper.java re/frida/HelperBackend.java
|
||||
build/frida-helper.jar: re/frida/Helper.java
|
||||
javac \
|
||||
-cp .:$(android_jar) \
|
||||
-bootclasspath $(android_jar) \
|
||||
|
||||
+63
-163
@@ -1,96 +1,66 @@
|
||||
using Efni;
|
||||
|
||||
namespace Frida {
|
||||
public sealed class AndroidHelperClient : Object {
|
||||
public AndroidHelperTransport transport {
|
||||
public sealed class AndroidHelperClient : Object, AsyncInitable {
|
||||
public signal void closed ();
|
||||
|
||||
public IOStream stream {
|
||||
get;
|
||||
construct;
|
||||
}
|
||||
|
||||
private AdbShellSession? shell;
|
||||
private BufferedInputStream input;
|
||||
private OutputStream output;
|
||||
private Cancellable io_cancellable = new Cancellable ();
|
||||
|
||||
public AndroidHelperClient (AndroidHelperTransport transport) {
|
||||
Object (transport: transport);
|
||||
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
|
||||
}
|
||||
|
||||
public static async AndroidHelperClient open (string serial, Cancellable? cancellable) throws Error, IOError {
|
||||
string instance_id = Uuid.string_random ().replace ("-", "");
|
||||
string helper_path = "/data/local/tmp/frida-helper-" + instance_id + ".dex";
|
||||
private const uint32 MAX_RESPONSE_SIZE = 100 * 1024 * 1024;
|
||||
|
||||
var helper_dex = new MemoryInputStream.from_bytes (
|
||||
new Bytes.static (Frida.Data.Android.get_helper_dex_blob ().data));
|
||||
var helper_meta = new AdbFileMetadata ();
|
||||
helper_meta.mode = 0100644;
|
||||
helper_meta.time_modified = new DateTime.now_utc ();
|
||||
yield AdbFileSync.send (helper_dex, helper_meta, helper_path, serial, cancellable);
|
||||
public AndroidHelperClient (IOStream stream) {
|
||||
Object (stream: stream);
|
||||
}
|
||||
|
||||
var shell = new AdbShellSession ();
|
||||
try {
|
||||
var output = new StringBuilder ();
|
||||
bool waiting = false;
|
||||
var output_handler = shell.output.connect ((pipe, bytes) => {
|
||||
if (pipe == STDOUT) {
|
||||
output.append ((string) bytes.get_data ());
|
||||
if (waiting)
|
||||
open.callback ();
|
||||
}
|
||||
});
|
||||
try {
|
||||
yield shell.open (serial, cancellable);
|
||||
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 ();
|
||||
|
||||
shell.send_command (("CLASSPATH=%s app_process /data/local/tmp " +
|
||||
"--nice-name=re.frida.helper re.frida.Helper %s; rm -f %s; echo BYE.")
|
||||
.printf (helper_path, instance_id, helper_path));
|
||||
state = OPEN;
|
||||
|
||||
while (!output.str.has_prefix ("READY.\n")) {
|
||||
waiting = true;
|
||||
yield;
|
||||
waiting = false;
|
||||
|
||||
if (output.str.has_prefix ("BYE.\n"))
|
||||
throw new Error.NOT_SUPPORTED ("Unable to start helper");
|
||||
}
|
||||
} finally {
|
||||
shell.disconnect (output_handler);
|
||||
}
|
||||
|
||||
var client = yield AdbClient.open (cancellable);
|
||||
try {
|
||||
yield client.request ("host:transport:" + serial, cancellable);
|
||||
yield client.request_protocol_change ("localabstract:/frida-helper-" + instance_id,
|
||||
cancellable);
|
||||
} catch (GLib.Error e) {
|
||||
client.close.begin ();
|
||||
throw e;
|
||||
}
|
||||
|
||||
var helper = new AndroidHelperClient (new AndroidHelperStreamTransport (client.stream));
|
||||
helper.shell = shell;
|
||||
helper.transport.closed.connect (helper.release_shell);
|
||||
|
||||
return helper;
|
||||
} catch (GLib.Error e) {
|
||||
shell.close.begin ();
|
||||
if (e is IOError.CANCELLED)
|
||||
throw (IOError) e;
|
||||
throw new Error.NOT_SUPPORTED ("%s", e.message);
|
||||
}
|
||||
process_incoming_responses.begin ();
|
||||
}
|
||||
|
||||
public async void close (Cancellable? cancellable) throws IOError {
|
||||
yield transport.close (cancellable);
|
||||
io_cancellable.cancel ();
|
||||
|
||||
if (shell != null) {
|
||||
yield shell.close (cancellable);
|
||||
shell = null;
|
||||
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 release_shell () {
|
||||
if (shell != null) {
|
||||
shell.close.begin ();
|
||||
shell = null;
|
||||
}
|
||||
private void ensure_closed () {
|
||||
if (state == CLOSED)
|
||||
return;
|
||||
state = CLOSED;
|
||||
closed ();
|
||||
}
|
||||
|
||||
public async HostApplicationInfo get_frontmost_application (FrontmostQueryOptions options,
|
||||
@@ -102,12 +72,12 @@ namespace Frida {
|
||||
.add_string_value (options.scope.to_nick ())
|
||||
.end_array ();
|
||||
|
||||
Json.Node response = yield transport.request (stanza.get_root (), cancellable);
|
||||
Json.Node response = yield request (stanza.get_root (), cancellable);
|
||||
|
||||
if (response.is_null ())
|
||||
return HostApplicationInfo.empty ();
|
||||
|
||||
Json.Reader reader = make_json_reader_taking_node ((owned) response);
|
||||
Json.Reader reader = new Json.Reader (response);
|
||||
|
||||
string? identifier = null;
|
||||
string? name = null;
|
||||
@@ -157,9 +127,9 @@ namespace Frida {
|
||||
.add_string_value (options.scope.to_nick ())
|
||||
.end_array ();
|
||||
|
||||
Json.Node response = yield transport.request (stanza.get_root (), cancellable);
|
||||
Json.Node response = yield request (stanza.get_root (), cancellable);
|
||||
|
||||
Json.Reader reader = make_json_reader_taking_node ((owned) response);
|
||||
Json.Reader reader = new Json.Reader (response);
|
||||
|
||||
int num_apps = reader.count_elements ();
|
||||
if (num_apps == -1)
|
||||
@@ -223,9 +193,9 @@ namespace Frida {
|
||||
.add_string_value (options.scope.to_nick ())
|
||||
.end_array ();
|
||||
|
||||
Json.Node response = yield transport.request (stanza.get_root (), cancellable);
|
||||
Json.Node response = yield request (stanza.get_root (), cancellable);
|
||||
|
||||
Json.Reader reader = make_json_reader_taking_node ((owned) response);
|
||||
Json.Reader reader = new Json.Reader (response);
|
||||
|
||||
int num_processes = reader.count_elements ();
|
||||
if (num_processes == -1)
|
||||
@@ -277,9 +247,9 @@ namespace Frida {
|
||||
.add_int_value (uid)
|
||||
.end_array ();
|
||||
|
||||
Json.Node response = yield transport.request (stanza.get_root (), cancellable);
|
||||
Json.Node response = yield request (stanza.get_root (), cancellable);
|
||||
|
||||
var r = make_json_reader_taking_node ((owned) response);
|
||||
var r = new Json.Reader (response);
|
||||
parse_envelope_or_throw (r);
|
||||
|
||||
r.read_element (1);
|
||||
@@ -347,9 +317,9 @@ namespace Frida {
|
||||
.add_int_value (uid)
|
||||
.end_array ();
|
||||
|
||||
Json.Node response = yield transport.request (stanza.get_root (), cancellable);
|
||||
Json.Node response = yield request (stanza.get_root (), cancellable);
|
||||
|
||||
var r = make_json_reader_taking_node ((owned) response);
|
||||
var r = new Json.Reader (response);
|
||||
parse_envelope_or_throw (r);
|
||||
}
|
||||
|
||||
@@ -361,9 +331,9 @@ namespace Frida {
|
||||
.add_int_value ((int) pid)
|
||||
.end_array ();
|
||||
|
||||
Json.Node response = yield transport.request (stanza.get_root (), cancellable);
|
||||
Json.Node response = yield request (stanza.get_root (), cancellable);
|
||||
|
||||
var r = make_json_reader_taking_node ((owned) response);
|
||||
var r = new Json.Reader (response);
|
||||
parse_envelope_or_throw (r);
|
||||
|
||||
r.read_element (1);
|
||||
@@ -373,13 +343,6 @@ 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 = make_json_reader_taking_node ((owned) 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 ();
|
||||
@@ -489,76 +452,6 @@ namespace Frida {
|
||||
|
||||
throw new Error.PROTOCOL ("Unexpected JSON type: %s", type.name ());
|
||||
}
|
||||
}
|
||||
|
||||
public interface AndroidHelperTransport : Object {
|
||||
public signal void closed ();
|
||||
|
||||
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 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)
|
||||
@@ -594,6 +487,13 @@ 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
File diff suppressed because it is too large.
Load diff
+50
-484
@@ -21,60 +21,59 @@ CORE_TAG_FIELD = f"{{{CORE_NAMESPACE}}}field"
|
||||
CORE_TAG_CONSTRUCTOR = f"{{{CORE_NAMESPACE}}}constructor"
|
||||
CORE_TAG_METHOD = f"{{{CORE_NAMESPACE}}}method"
|
||||
|
||||
INTERNAL_INTERFACES = {
|
||||
"Frida.HostSessionHub",
|
||||
"Frida.AgentMessageSink",
|
||||
"FridaBase.AgentMessageSink",
|
||||
"Json.Serializable",
|
||||
}
|
||||
|
||||
OBJECT_TYPE_PATTERN = re.compile(r"\bpublic\s+(sealed |abstract )?(class|interface)\s+(\w+)\b")
|
||||
|
||||
TOPLEVEL_NAMES = [
|
||||
"frida.vala",
|
||||
"linux-kernel-image.vala",
|
||||
"xnu-kernelcache.vala",
|
||||
"package-manager.vala",
|
||||
"control-service.vala",
|
||||
"portal-service.vala",
|
||||
"file-monitor.vala",
|
||||
Path("compiler") / "compiler.vala",
|
||||
]
|
||||
OBJECT_TYPE_PATTERN = re.compile(r"\bpublic\s+(sealed )?(class|interface)\s+(\w+)\b")
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Generate refined Frida API definitions")
|
||||
parser.add_argument('--output', dest='output_type', choices=['bundle', 'header', 'gir', 'vapi', 'vapi-stamp', 'symbol-maps'], default='bundle')
|
||||
parser.add_argument('--output', dest='output_type', choices=['bundle', 'header', 'gir', 'vapi', 'vapi-stamp'], default='bundle')
|
||||
parser.add_argument('frida_version', metavar='frida-version', type=str)
|
||||
parser.add_argument('frida_major_version', metavar='frida-major-version', type=str)
|
||||
parser.add_argument('frida_minor_version', metavar='frida-minor-version', type=str)
|
||||
parser.add_argument('frida_micro_version', metavar='frida-micro-version', type=str)
|
||||
parser.add_argument('frida_nano_version', metavar='frida-nano-version', type=str)
|
||||
parser.add_argument('api_version', metavar='api-version', type=str)
|
||||
parser.add_argument('core_header', metavar='/path/to/frida-core.h', type=argparse.FileType('r', encoding='utf-8'))
|
||||
parser.add_argument('core_gir', metavar='/path/to/Frida-x.y.gir', type=argparse.FileType('r', encoding='utf-8'))
|
||||
parser.add_argument('core_vapi', metavar='/path/to/frida-core.vapi', type=argparse.FileType('r', encoding='utf-8'))
|
||||
parser.add_argument('base_header', metavar='/path/to/frida-base.h', type=argparse.FileType('r', encoding='utf-8'))
|
||||
parser.add_argument('base_gir', metavar='/path/to/FridaBase-x.y.gir', type=argparse.FileType('r', encoding='utf-8'))
|
||||
parser.add_argument('base_vapi', metavar='/path/to/frida-base.vapi', type=argparse.FileType('r', encoding='utf-8'))
|
||||
parser.add_argument('output_dir', metavar='/output/dir')
|
||||
parser.add_argument('extra_args', nargs='*')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
output_type = args.output_type
|
||||
frida_version = args.frida_version
|
||||
frida_version_components = (
|
||||
args.frida_major_version,
|
||||
args.frida_minor_version,
|
||||
args.frida_micro_version,
|
||||
args.frida_nano_version,
|
||||
)
|
||||
api_version = args.api_version
|
||||
core_header = args.core_header.read()
|
||||
core_gir = args.core_gir.read()
|
||||
core_vapi = args.core_vapi.read()
|
||||
base_header = args.base_header.read()
|
||||
base_gir = args.base_gir.read()
|
||||
base_vapi = args.base_vapi.read()
|
||||
output_dir = Path(args.output_dir)
|
||||
|
||||
if output_type == 'symbol-maps':
|
||||
emit_symbol_maps_from_source(output_dir)
|
||||
return
|
||||
|
||||
extra = args.extra_args
|
||||
frida_version = extra[0]
|
||||
frida_version_components = tuple(extra[1:5])
|
||||
api_version = extra[5]
|
||||
|
||||
if output_type == 'vapi-stamp':
|
||||
(output_dir / f"frida-core-{api_version}.vapi.stamp").write_bytes(b"")
|
||||
return
|
||||
|
||||
core_header = Path(extra[6]).read_text(encoding='utf-8')
|
||||
core_gir = Path(extra[7]).read_text(encoding='utf-8')
|
||||
core_vapi = Path(extra[8]).read_text(encoding='utf-8')
|
||||
base_header = Path(extra[9]).read_text(encoding='utf-8')
|
||||
base_gir = Path(extra[10]).read_text(encoding='utf-8')
|
||||
base_vapi = Path(extra[11]).read_text(encoding='utf-8')
|
||||
|
||||
toplevel_names = [
|
||||
"frida.vala",
|
||||
"package-manager.vala",
|
||||
"control-service.vala",
|
||||
"portal-service.vala",
|
||||
"file-monitor.vala",
|
||||
Path("compiler") / "compiler.vala",
|
||||
]
|
||||
toplevel_sources = []
|
||||
src_dir = Path(__file__).parent.parent.resolve()
|
||||
for name in TOPLEVEL_NAMES:
|
||||
for name in toplevel_names:
|
||||
toplevel_sources.append((src_dir / name).read_text(encoding='utf-8'))
|
||||
toplevel_code = "\n".join(toplevel_sources)
|
||||
|
||||
@@ -98,7 +97,7 @@ def main():
|
||||
emit_header(api, output_dir)
|
||||
|
||||
if enable_gir:
|
||||
emit_gir(api, core_gir, base_gir, output_dir, build_doc_index(src_dir))
|
||||
emit_gir(api, core_gir, base_gir, output_dir)
|
||||
|
||||
if enable_vapi:
|
||||
emit_vapi(api, output_dir)
|
||||
@@ -140,7 +139,6 @@ def emit_header(api, output_dir):
|
||||
|
||||
output_header_file.write("\n\n/* Library lifetime */")
|
||||
output_header_file.write("\nvoid frida_init (void);")
|
||||
output_header_file.write("\nvoid frida_init_with_runtime (FridaRuntime runtime);")
|
||||
output_header_file.write("\nvoid frida_shutdown (void);")
|
||||
output_header_file.write("\nvoid frida_deinit (void);")
|
||||
output_header_file.write("\nGMainContext * frida_get_main_context (void);")
|
||||
@@ -205,7 +203,7 @@ def emit_header(api, output_dir):
|
||||
|
||||
output_header_file.write("\n\n#endif\n")
|
||||
|
||||
def emit_gir(api: ApiSpec, core_gir: str, base_gir: str, output_dir: Path, docs: DocIndex) -> str:
|
||||
def emit_gir(api: ApiSpec, core_gir: str, base_gir: str, output_dir: Path) -> str:
|
||||
ET.register_namespace("", CORE_NAMESPACE)
|
||||
ET.register_namespace("c", C_NAMESPACE)
|
||||
ET.register_namespace("glib", GLIB_NAMESPACE)
|
||||
@@ -240,10 +238,10 @@ def emit_gir(api: ApiSpec, core_gir: str, base_gir: str, output_dir: Path, docs:
|
||||
for elem in core_elements + base_elements:
|
||||
if tag_name == "class":
|
||||
for child in list(elem):
|
||||
if (child.tag == CORE_TAG_IMPLEMENTS and child.get("name") in INTERNAL_INTERFACES) \
|
||||
if (child.tag == CORE_TAG_IMPLEMENTS and child.get("name") in {"Frida.HostSessionHub", "Frida.AgentMessageSink",
|
||||
"FridaBase.AgentMessageSink"}) \
|
||||
or child.tag == CORE_TAG_FIELD \
|
||||
or child.get("name").startswith("_") \
|
||||
or (child.tag == CORE_TAG_CONSTRUCTOR and is_async_constructor(child)):
|
||||
or child.get("name").startswith("_"):
|
||||
elem.remove(child)
|
||||
merged_namespace.append(elem)
|
||||
|
||||
@@ -251,38 +249,6 @@ def emit_gir(api: ApiSpec, core_gir: str, base_gir: str, output_dir: Path, docs:
|
||||
merge_and_transform_elements("interface", object_type_names)
|
||||
merge_and_transform_elements("enumeration", enum_type_names | error_type_names)
|
||||
|
||||
function_names = {func.name for func in api.functions}
|
||||
for source_root in [core_root, base_root]:
|
||||
source_namespace = source_root.find("namespace", GIR_NAMESPACES)
|
||||
for function in source_namespace.findall("function", GIR_NAMESPACES):
|
||||
if function.get("name") in function_names:
|
||||
merged_namespace.append(function)
|
||||
|
||||
for source_root in [core_root, base_root]:
|
||||
for record in source_root.findall(".//record", GIR_NAMESPACES):
|
||||
owner = record.get(f"{{{GLIB_NAMESPACE}}}is-gtype-struct-for")
|
||||
if owner is not None and owner in object_type_names:
|
||||
merged_namespace.append(record)
|
||||
|
||||
known_names = object_type_names | enum_type_names | error_type_names
|
||||
referenced_names = set()
|
||||
for elem in merged_namespace.iter():
|
||||
type_name = elem.get("name")
|
||||
if type_name is None:
|
||||
continue
|
||||
for prefix in ("Frida.", "FridaBase."):
|
||||
if type_name.startswith(prefix):
|
||||
referenced_names.add(type_name[len(prefix):])
|
||||
break
|
||||
needed_names = referenced_names - known_names
|
||||
for source_root in [core_root, base_root]:
|
||||
source_namespace = source_root.find("namespace", GIR_NAMESPACES)
|
||||
for callback in source_namespace.findall("callback", GIR_NAMESPACES):
|
||||
if callback.get("name") in needed_names:
|
||||
merged_namespace.append(callback)
|
||||
|
||||
inject_documentation(merged_namespace, docs)
|
||||
|
||||
ET.indent(merged_root, space=" ")
|
||||
result = ET.tostring(merged_root,
|
||||
encoding="unicode",
|
||||
@@ -294,347 +260,15 @@ def emit_gir(api: ApiSpec, core_gir: str, base_gir: str, output_dir: Path, docs:
|
||||
def filter_elements(elements: List[ET.Element], spec_set: Set[str]):
|
||||
return [elem for elem in elements if elem.get("name") in spec_set]
|
||||
|
||||
def is_async_constructor(constructor: ET.Element) -> bool:
|
||||
for type_elem in constructor.iter(f"{{{CORE_NAMESPACE}}}type"):
|
||||
if type_elem.get("name") == "Gio.Cancellable":
|
||||
return True
|
||||
return False
|
||||
|
||||
@dataclass
|
||||
class DocComment:
|
||||
body: str
|
||||
params: dict
|
||||
returns: str
|
||||
filename: str = "<generated>"
|
||||
line: int = 0
|
||||
|
||||
@dataclass
|
||||
class DocIndex:
|
||||
types: dict # type_name -> DocComment
|
||||
members: dict # (type_name, member_name) -> DocComment
|
||||
enum_members: dict # (enum_name, member_name) -> DocComment
|
||||
|
||||
DOC_TYPE_PATTERN = re.compile(r"public\s+(?:sealed\s+|abstract\s+)?(class|interface|enum|errordomain)\s+(\w+)")
|
||||
DOC_SIGNAL_PATTERN = re.compile(r"public\s+signal\s+\S.*?\b(\w+)\s*\(")
|
||||
DOC_PROPERTY_PATTERN = re.compile(r"public\s+(?:unowned\s+)?\S.*?\b(\w+)\s*\{")
|
||||
DOC_METHOD_PATTERN = re.compile(r"public\s+\S.*?\b(\w+)\s*\(")
|
||||
DOC_ENUM_MEMBER_PATTERN = re.compile(r"([A-Z][A-Z0-9_]*)\b")
|
||||
|
||||
def build_doc_index(src_dir: Path) -> DocIndex:
|
||||
repo_root = src_dir.parent
|
||||
sources = []
|
||||
for name in TOPLEVEL_NAMES:
|
||||
path = src_dir / name
|
||||
if path.exists():
|
||||
sources.append(path)
|
||||
base_dir = src_dir.parent / "lib" / "base"
|
||||
if base_dir.is_dir():
|
||||
sources.extend(sorted(base_dir.rglob("*.vala")))
|
||||
|
||||
index = DocIndex(types={}, members={}, enum_members={})
|
||||
for path in sources:
|
||||
try:
|
||||
filename = path.relative_to(repo_root).as_posix()
|
||||
except ValueError:
|
||||
filename = path.name
|
||||
_collect_docs_from_source(path.read_text(encoding="utf-8"), index, filename)
|
||||
return index
|
||||
|
||||
def _collect_docs_from_source(source: str, index: DocIndex, filename: str):
|
||||
lines = source.split("\n")
|
||||
pending = None
|
||||
current_type = None
|
||||
current_is_enum = False
|
||||
i = 0
|
||||
n = len(lines)
|
||||
while i < n:
|
||||
line = lines[i]
|
||||
stripped = line.strip()
|
||||
|
||||
if stripped.startswith("/**"):
|
||||
start_line = i + 1
|
||||
block = [line]
|
||||
while "*/" not in lines[i]:
|
||||
i += 1
|
||||
block.append(lines[i])
|
||||
pending = _parse_doc_block(block)
|
||||
pending.filename = filename
|
||||
pending.line = start_line
|
||||
i += 1
|
||||
continue
|
||||
|
||||
if stripped == "" or stripped.startswith("//") or stripped.startswith("["):
|
||||
i += 1
|
||||
continue
|
||||
|
||||
indent = len(line) - len(line.lstrip("\t"))
|
||||
|
||||
type_match = DOC_TYPE_PATTERN.match(stripped)
|
||||
if indent == 1 and type_match is not None:
|
||||
current_type = type_match.group(2)
|
||||
current_is_enum = type_match.group(1) in ("enum", "errordomain")
|
||||
if pending is not None:
|
||||
index.types[current_type] = pending
|
||||
pending = None
|
||||
i += 1
|
||||
continue
|
||||
|
||||
if pending is not None and current_type is not None and indent >= 2:
|
||||
if current_is_enum:
|
||||
member_match = DOC_ENUM_MEMBER_PATTERN.match(stripped)
|
||||
if member_match is not None:
|
||||
index.enum_members[(current_type, member_match.group(1))] = pending
|
||||
else:
|
||||
name = _parse_member_name(stripped, current_type)
|
||||
if name is not None:
|
||||
index.members[(current_type, name)] = pending
|
||||
pending = None
|
||||
i += 1
|
||||
continue
|
||||
|
||||
pending = None
|
||||
i += 1
|
||||
|
||||
def _parse_member_name(stripped: str, type_name: str):
|
||||
if not stripped.startswith("public"):
|
||||
return None
|
||||
signal_match = DOC_SIGNAL_PATTERN.match(stripped)
|
||||
if signal_match is not None:
|
||||
return signal_match.group(1)
|
||||
brace = stripped.find("{")
|
||||
if brace != -1 and "(" not in stripped[:brace]:
|
||||
property_match = DOC_PROPERTY_PATTERN.match(stripped)
|
||||
if property_match is not None:
|
||||
return property_match.group(1)
|
||||
ctor_match = re.match(r"public\s+" + re.escape(type_name) + r"(?:\.(\w+))?\s*\(", stripped)
|
||||
if ctor_match is not None:
|
||||
return "new" if ctor_match.group(1) is None else ctor_match.group(1)
|
||||
method_match = DOC_METHOD_PATTERN.match(stripped)
|
||||
if method_match is not None:
|
||||
return method_match.group(1)
|
||||
return None
|
||||
|
||||
def _parse_doc_block(block: List[str]) -> DocComment:
|
||||
text_lines = []
|
||||
for raw in block:
|
||||
s = raw.strip()
|
||||
if s.startswith("/**"):
|
||||
s = s[3:]
|
||||
if s.endswith("*/"):
|
||||
s = s[:-2]
|
||||
s = s.strip()
|
||||
if s.startswith("*"):
|
||||
s = s[1:]
|
||||
if s.startswith(" "):
|
||||
s = s[1:]
|
||||
text_lines.append(s.rstrip())
|
||||
|
||||
# Valadoc block tags: "@param <name> <description>" and "@return <description>".
|
||||
body_lines = []
|
||||
params = {}
|
||||
returns_lines = []
|
||||
target = body_lines
|
||||
for line in text_lines:
|
||||
param_match = re.match(r"@param\s+(\w+)\s*(.*)", line)
|
||||
return_match = re.match(r"@returns?\s*(.*)", line)
|
||||
if param_match is not None:
|
||||
params[param_match.group(1)] = [param_match.group(2)]
|
||||
target = params[param_match.group(1)]
|
||||
continue
|
||||
if return_match is not None:
|
||||
returns_lines = [return_match.group(1)]
|
||||
target = returns_lines
|
||||
continue
|
||||
target.append(line)
|
||||
|
||||
def finish(lines):
|
||||
return _valadoc_to_markdown("\n".join(lines).strip())
|
||||
|
||||
return DocComment(
|
||||
body=finish(body_lines),
|
||||
params={k: finish(v) for k, v in params.items()},
|
||||
returns=finish(returns_lines),
|
||||
)
|
||||
|
||||
def _valadoc_to_markdown(text: str) -> str:
|
||||
if not text:
|
||||
return text
|
||||
# Code blocks: {{{ ... }}} -> fenced ``` blocks.
|
||||
def code_block(match):
|
||||
code = match.group(1).strip("\n")
|
||||
return "\n```\n" + code + "\n```\n"
|
||||
text = re.sub(r"\{\{\{(.*?)\}\}\}", code_block, text, flags=re.DOTALL)
|
||||
# Note: {@link ...} cross-references are resolved later, at injection time,
|
||||
# where the full symbol table is available (see inject_documentation).
|
||||
# Inline monospace: ``x`` -> `x` (valadoc) is already markdown-compatible.
|
||||
# Bold: ''x'' -> **x**.
|
||||
text = re.sub(r"''(.+?)''", r"**\1**", text)
|
||||
# Italic: //x// -> *x*, but leave protocol-relative URLs (://) alone.
|
||||
text = re.sub(r"(?<![:/])//(?!/)(.+?)//", r"*\1*", text)
|
||||
return text
|
||||
|
||||
def inject_documentation(merged_namespace: ET.Element, docs: DocIndex):
|
||||
glib_signal_tag = f"{{{GLIB_NAMESPACE}}}signal"
|
||||
callable_tags = {
|
||||
f"{{{CORE_NAMESPACE}}}method",
|
||||
f"{{{CORE_NAMESPACE}}}constructor",
|
||||
f"{{{CORE_NAMESPACE}}}function",
|
||||
f"{{{CORE_NAMESPACE}}}virtual-method",
|
||||
glib_signal_tag,
|
||||
}
|
||||
property_tag = f"{{{CORE_NAMESPACE}}}property"
|
||||
member_tag = f"{{{CORE_NAMESPACE}}}member"
|
||||
doc_tag = f"{{{CORE_NAMESPACE}}}doc"
|
||||
|
||||
# Build a symbol table so {@link ...} can be turned into real gi-docgen
|
||||
# cross-references. Keys use Vala-style names (underscores); values carry the
|
||||
# gi-docgen link kind and the GIR name (dashes for properties/signals).
|
||||
type_kinds = {} # type_name -> gi-docgen kind ("class"/"iface"/"enum"/"error")
|
||||
member_kinds = {} # (type_name, vala_member) -> (kind, gir_name)
|
||||
for type_elem in list(merged_namespace):
|
||||
type_name = type_elem.get("name")
|
||||
if type_name is None:
|
||||
continue
|
||||
tag = type_elem.tag.split("}")[-1]
|
||||
if tag == "class":
|
||||
type_kinds[type_name] = "class"
|
||||
elif tag == "interface":
|
||||
type_kinds[type_name] = "iface"
|
||||
elif tag == "enumeration":
|
||||
type_kinds[type_name] = "error" \
|
||||
if type_elem.get(f"{{{GLIB_NAMESPACE}}}error-domain") is not None \
|
||||
else "enum"
|
||||
for child in list(type_elem):
|
||||
cname = child.get("name")
|
||||
if cname is None:
|
||||
continue
|
||||
if child.tag == f"{{{CORE_NAMESPACE}}}method":
|
||||
member_kinds[(type_name, cname)] = ("method", cname)
|
||||
elif child.tag == f"{{{CORE_NAMESPACE}}}constructor":
|
||||
member_kinds[(type_name, cname)] = ("ctor", cname)
|
||||
elif child.tag == property_tag:
|
||||
member_kinds[(type_name, cname.replace("-", "_"))] = ("property", cname)
|
||||
elif child.tag == glib_signal_tag:
|
||||
member_kinds[(type_name, cname.replace("-", "_"))] = ("signal", cname)
|
||||
|
||||
def resolve_links(text: str) -> str:
|
||||
def repl(match):
|
||||
target = re.sub(r"^Frida\.", "", match.group(1).strip())
|
||||
parts = target.split(".")
|
||||
if len(parts) == 1:
|
||||
kind = type_kinds.get(parts[0])
|
||||
if kind is not None:
|
||||
return f"[{kind}@Frida.{parts[0]}]"
|
||||
elif len(parts) == 2:
|
||||
info = member_kinds.get((parts[0], parts[1]))
|
||||
if info is not None:
|
||||
kind, gir_name = info
|
||||
if kind == "method":
|
||||
return f"[method@Frida.{parts[0]}.{gir_name}]"
|
||||
if kind == "ctor":
|
||||
return f"[ctor@Frida.{parts[0]}.{gir_name}]"
|
||||
if kind == "property":
|
||||
return f"[property@Frida.{parts[0]}:{gir_name}]"
|
||||
if kind == "signal":
|
||||
return f"[signal@Frida.{parts[0]}::{gir_name}]"
|
||||
return "`" + target + "`"
|
||||
return re.sub(r"\{@link\s+([^}]+)\}", repl, text)
|
||||
|
||||
def set_doc(elem: ET.Element, text: str, filename: str = "<generated>",
|
||||
line: int = 0):
|
||||
if not text:
|
||||
return
|
||||
if elem.find(doc_tag) is not None:
|
||||
return
|
||||
doc = ET.Element(doc_tag)
|
||||
doc.set("xml:space", "preserve")
|
||||
# gi-docgen accesses filename/line unconditionally, so always emit them,
|
||||
# mirroring what g-ir-scanner produces for hand-written C.
|
||||
doc.set("filename", filename)
|
||||
doc.set("line", str(line))
|
||||
doc.text = resolve_links(text)
|
||||
elem.insert(0, doc)
|
||||
|
||||
def member_doc(type_name: str, name: str):
|
||||
comment = docs.members.get((type_name, name))
|
||||
if comment is None:
|
||||
for suffix in ("_finish", "_sync"):
|
||||
if name.endswith(suffix):
|
||||
comment = docs.members.get((type_name, name[: -len(suffix)]))
|
||||
if comment is not None:
|
||||
break
|
||||
return comment
|
||||
|
||||
def apply_callable(elem: ET.Element, comment: DocComment):
|
||||
set_doc(elem, comment.body, comment.filename, comment.line)
|
||||
if comment.returns:
|
||||
rv = elem.find(f"{{{CORE_NAMESPACE}}}return-value")
|
||||
if rv is not None:
|
||||
set_doc(rv, comment.returns, comment.filename, comment.line)
|
||||
params_elem = elem.find(f"{{{CORE_NAMESPACE}}}parameters")
|
||||
if params_elem is not None and comment.params:
|
||||
for param in params_elem.findall(f"{{{CORE_NAMESPACE}}}parameter"):
|
||||
text = comment.params.get(param.get("name"))
|
||||
if text:
|
||||
set_doc(param, text, comment.filename, comment.line)
|
||||
|
||||
for type_elem in list(merged_namespace):
|
||||
type_name = type_elem.get("name")
|
||||
if type_name is None:
|
||||
continue
|
||||
tag = type_elem.tag.split("}")[-1]
|
||||
|
||||
type_comment = docs.types.get(type_name)
|
||||
if type_comment is not None and tag in ("class", "interface", "enumeration"):
|
||||
set_doc(type_elem, type_comment.body, type_comment.filename,
|
||||
type_comment.line)
|
||||
|
||||
for child in list(type_elem):
|
||||
child_name = child.get("name")
|
||||
if child_name is None:
|
||||
continue
|
||||
if child.tag in callable_tags:
|
||||
lookup = child_name.replace("-", "_") if child.tag == glib_signal_tag \
|
||||
else child_name
|
||||
comment = member_doc(type_name, lookup)
|
||||
if comment is not None:
|
||||
apply_callable(child, comment)
|
||||
elif child.tag == f"{{{CORE_NAMESPACE}}}constructor" \
|
||||
and child_name == "new":
|
||||
# Vala's implicit default constructor; give it a sensible
|
||||
# description rather than leaving it bare.
|
||||
set_doc(child, f"Creates a new [class@Frida.{type_name}].")
|
||||
elif child.tag == property_tag:
|
||||
vala_name = child_name.replace("-", "_")
|
||||
comment = docs.members.get((type_name, vala_name))
|
||||
if comment is not None:
|
||||
set_doc(child, comment.body, comment.filename, comment.line)
|
||||
# The C API also exposes the property through getter/setter
|
||||
# methods; give them the same description.
|
||||
accessors = {"get_" + vala_name, "set_" + vala_name}
|
||||
for sibling in type_elem:
|
||||
if sibling.tag == f"{{{CORE_NAMESPACE}}}method" \
|
||||
and sibling.get("name") in accessors:
|
||||
set_doc(sibling, comment.body, comment.filename,
|
||||
comment.line)
|
||||
elif child.tag == member_tag:
|
||||
comment = docs.enum_members.get((type_name, child_name.upper()))
|
||||
if comment is not None:
|
||||
set_doc(child, comment.body, comment.filename, comment.line)
|
||||
|
||||
def emit_vapi(api, output_dir):
|
||||
with OutputFile(output_dir / f"frida-core-{api.version}.vapi") as output_vapi_file:
|
||||
output_vapi_file.write("[CCode (cheader_filename = \"frida-core.h\", cprefix = \"Frida\", lower_case_cprefix = \"frida_\")]")
|
||||
output_vapi_file.write("\nnamespace Frida {")
|
||||
output_vapi_file.write("\n\tpublic static void init ();")
|
||||
output_vapi_file.write("\n\tpublic static void init_with_runtime (Frida.Runtime runtime);")
|
||||
output_vapi_file.write("\n\tpublic static void shutdown ();")
|
||||
output_vapi_file.write("\n\tpublic static void deinit ();")
|
||||
output_vapi_file.write("\n\tpublic static unowned GLib.MainContext get_main_context ();")
|
||||
|
||||
for delegate in referenced_delegates(api):
|
||||
output_vapi_file.write("\n\t" + delegate)
|
||||
|
||||
for object_type in api.object_types:
|
||||
output_vapi_file.write("\n\n\t%s" % object_type.vapi_declaration)
|
||||
sections = []
|
||||
@@ -669,46 +303,6 @@ def emit_vapi(api, output_dir):
|
||||
output_deps_file.write("glib-2.0\n")
|
||||
output_deps_file.write("gobject-2.0\n")
|
||||
output_deps_file.write("gio-2.0\n")
|
||||
output_deps_file.write("json-glib-1.0\n")
|
||||
|
||||
def referenced_delegates(api) -> List[str]:
|
||||
members = []
|
||||
for object_type in api.object_types:
|
||||
members.extend(object_type.vapi_properties)
|
||||
members.extend(object_type.vapi_methods)
|
||||
members.extend(object_type.vapi_signals)
|
||||
if object_type.vapi_constructor is not None:
|
||||
members.append(object_type.vapi_constructor)
|
||||
for func in api.functions:
|
||||
members.append(func.vapi_declaration)
|
||||
text = "\n".join(members)
|
||||
|
||||
return [declaration for name, declaration in api.delegates
|
||||
if re.search(r"\bFrida\." + name + r"\b", text) is not None]
|
||||
|
||||
def strip_internal_interfaces(declaration: str) -> str:
|
||||
head, sep, rest = declaration.partition(" : ")
|
||||
if not sep:
|
||||
return declaration
|
||||
|
||||
bases_part, brace_sep, tail = rest.partition("{")
|
||||
|
||||
kept = [b.strip() for b in bases_part.split(",") if b.strip() not in INTERNAL_INTERFACES]
|
||||
if not kept:
|
||||
return f"{head} {brace_sep}{tail}"
|
||||
|
||||
return f"{head} : {', '.join(kept)} {brace_sep}{tail}"
|
||||
|
||||
def emit_symbol_maps_from_source(output_dir: Path):
|
||||
with OutputFile(output_dir / 'frida-core.version') as f:
|
||||
f.write("{\n")
|
||||
f.write(" global:\n")
|
||||
f.write(" frida_*;\n")
|
||||
f.write(" _frida_*;\n")
|
||||
f.write("\n")
|
||||
f.write(" local:\n")
|
||||
f.write(" *;\n")
|
||||
f.write("};\n")
|
||||
|
||||
def parse_api(frida_version, frida_version_components, api_version, toplevel_code, core_header, core_vapi, base_header, base_vapi):
|
||||
all_headers = core_header + "\n" + base_header
|
||||
@@ -717,7 +311,6 @@ def parse_api(frida_version, frida_version_components, api_version, toplevel_cod
|
||||
enum_types = []
|
||||
|
||||
base_public_types = {
|
||||
"SpawnGatingOptions": "ProcessMatchOptions",
|
||||
"FrontmostQueryOptions": "SpawnOptions",
|
||||
"ApplicationQueryOptions": "FrontmostQueryOptions",
|
||||
"ProcessQueryOptions": "ApplicationQueryOptions",
|
||||
@@ -732,9 +325,6 @@ def parse_api(frida_version, frida_version_components, api_version, toplevel_cod
|
||||
"EndpointParameters": "PortalService",
|
||||
"AuthenticationService": "EndpointParameters",
|
||||
"StaticAuthenticationService": "AuthenticationService",
|
||||
"WebRequestHandler": "StaticAuthenticationService",
|
||||
"WebRequest": "WebRequestHandler",
|
||||
"WebResponse": "WebRequest",
|
||||
}
|
||||
internal_type_prefixes = [
|
||||
"AgentMessageKind",
|
||||
@@ -829,7 +419,7 @@ def parse_api(frida_version, frida_version_components, api_version, toplevel_cod
|
||||
object_type.c_method_prototypes.append(method_cprototype)
|
||||
elif method_name == 'get_type':
|
||||
object_type.c_get_type = method_cprototype.replace("G_GNUC_CONST ;", "G_GNUC_CONST;")
|
||||
for d in re.finditer(r"^typedef.+?\(\*(" + object_type.c_name + r".+?)\) \(.+\);$", all_headers, re.MULTILINE):
|
||||
for d in re.finditer(r"^typedef.+?\(\*(" + object_type.c_name + r".+?)\) \(.+\);$", core_header, re.MULTILINE):
|
||||
delegate_cname = d.group(1)
|
||||
if delegate_cname not in seen_cdelegates:
|
||||
seen_cdelegates.add(delegate_cname)
|
||||
@@ -856,7 +446,8 @@ def parse_api(frida_version, frida_version_components, api_version, toplevel_cod
|
||||
if stripped_line == "}":
|
||||
ignoring = False
|
||||
else:
|
||||
if stripped_line.startswith("public class Promise") \
|
||||
if stripped_line.startswith("public abstract") \
|
||||
or stripped_line.startswith("public class Promise") \
|
||||
or stripped_line.startswith("public interface Future") \
|
||||
or stripped_line.startswith("public class CF"):
|
||||
ignoring = True
|
||||
@@ -876,7 +467,7 @@ def parse_api(frida_version, frida_version_components, api_version, toplevel_cod
|
||||
ignoring = True
|
||||
else:
|
||||
current_object_type = object_type_by_name[name]
|
||||
current_object_type.vapi_declaration = strip_internal_interfaces(stripped_line)
|
||||
current_object_type.vapi_declaration = stripped_line
|
||||
elif stripped_line == "}":
|
||||
current_enum = None
|
||||
current_object_type = None
|
||||
@@ -905,31 +496,20 @@ def parse_api(frida_version, frida_version_components, api_version, toplevel_cod
|
||||
enum.vapi_declaration = m.group(1)
|
||||
enum.vapi_members.extend([line.lstrip() for line in m.group(2).strip().split("\n")])
|
||||
|
||||
functions = [f for f in parse_vapi_functions(core_vapi + base_vapi) if function_is_public(f.name)]
|
||||
functions = [f for f in parse_vapi_functions(base_vapi) if function_is_public(f.name)]
|
||||
for f in functions:
|
||||
m = re.search(r"^(?:VALA_EXTERN )?[\w\*]+ frida_{}.+?;".format(f.name), all_headers, re.MULTILINE | re.DOTALL)
|
||||
prototype = beautify_cprototype(m.group(0))
|
||||
if prototype.startswith("VALA_EXTERN "):
|
||||
prototype = prototype[12:]
|
||||
f.c_prototype = prototype
|
||||
m = re.search(r"^[\w\*]+ frida_{}.+?;".format(f.name), all_headers, re.MULTILINE | re.DOTALL)
|
||||
f.c_prototype = beautify_cprototype(m.group(0))
|
||||
|
||||
delegates = [(m.group(1), m.group(0).strip())
|
||||
for m in re.finditer(r"^\tpublic delegate .+?\b(\w+) \(.*\);$", core_vapi + base_vapi, re.MULTILINE)]
|
||||
|
||||
return ApiSpec(frida_version, frida_version_components, api_version, object_types, functions, enum_types, error_types,
|
||||
delegates)
|
||||
return ApiSpec(frida_version, frida_version_components, api_version, object_types, functions, enum_types, error_types)
|
||||
|
||||
def function_is_public(name):
|
||||
return not name.startswith("_") and \
|
||||
not name.startswith("throw_") and \
|
||||
name not in MANUALLY_DECLARED_FUNCTIONS and \
|
||||
name not in {
|
||||
"on_pending_garbage",
|
||||
"generate_certificate",
|
||||
"get_dbus_context",
|
||||
"invalidate_dbus_context",
|
||||
"make_json_reader",
|
||||
"make_json_reader_taking_node",
|
||||
"make_parameters_dict",
|
||||
"compute_system_parameters",
|
||||
"parse_control_address",
|
||||
@@ -939,23 +519,10 @@ 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",
|
||||
}
|
||||
|
||||
MANUALLY_DECLARED_FUNCTIONS = {
|
||||
"init",
|
||||
"init_with_runtime",
|
||||
"shutdown",
|
||||
"deinit",
|
||||
"get_main_context",
|
||||
"unref",
|
||||
"version",
|
||||
"version_string",
|
||||
}
|
||||
|
||||
def parse_vala_object_types(source) -> List[ApiObjectType]:
|
||||
return [ApiObjectType(m.group(3), m.group(2)) for m in OBJECT_TYPE_PATTERN.finditer(source, re.MULTILINE)]
|
||||
|
||||
@@ -971,7 +538,6 @@ class ApiSpec:
|
||||
functions: List[ApiFunction]
|
||||
enum_types: List[ApiEnum]
|
||||
error_types: List[ApiEnum]
|
||||
delegates: List[tuple]
|
||||
|
||||
class ApiEnum:
|
||||
def __init__(self, name):
|
||||
|
||||
+39
-82
@@ -3,7 +3,6 @@ fs = import('fs')
|
||||
generate_api = [python, files('generate.py')]
|
||||
|
||||
generate_api_args = [
|
||||
meson.current_build_dir(),
|
||||
frida_version,
|
||||
frida_major_version.to_string(),
|
||||
frida_minor_version.to_string(),
|
||||
@@ -16,6 +15,7 @@ generate_api_args = [
|
||||
base_build_dir / 'frida-base.h',
|
||||
base_build_dir / base_gir_name,
|
||||
base_build_dir / f'frida-base-@[email protected]',
|
||||
meson.current_build_dir(),
|
||||
]
|
||||
|
||||
core_api = custom_target('frida-core-api',
|
||||
@@ -44,24 +44,6 @@ glib_gir = fs.copyfile('GLib-2.0.gir', install: install_glib_girs, install_dir:
|
||||
gobject_gir = fs.copyfile('GObject-2.0.gir', install: install_glib_girs, install_dir: girdir)
|
||||
gio_gir = fs.copyfile('Gio-2.0.gir', install: install_glib_girs, install_dir: girdir)
|
||||
|
||||
g_ir_compiler = find_program('g-ir-compiler', required: false)
|
||||
if g_ir_compiler.found()
|
||||
custom_target('frida-core-typelib',
|
||||
command: [
|
||||
g_ir_compiler,
|
||||
'--output', '@OUTPUT@',
|
||||
'--includedir=' + girdir,
|
||||
'--includedir=' + meson.current_source_dir(),
|
||||
'@INPUT@',
|
||||
],
|
||||
input: core_public_gir,
|
||||
output: f'Frida-@[email protected]',
|
||||
depends: core,
|
||||
install: true,
|
||||
install_dir: typelibdir,
|
||||
)
|
||||
endif
|
||||
|
||||
core_public_vapi_stamp = custom_target('frida-core-vapi-stamp',
|
||||
input: core_public_vapi,
|
||||
output: f'frida-core-@[email protected]',
|
||||
@@ -72,26 +54,22 @@ core_public_vapi_stamp = custom_target('frida-core-vapi-stamp',
|
||||
],
|
||||
)
|
||||
|
||||
if is_shared
|
||||
core_public_lib = core
|
||||
else
|
||||
core_public_lib = custom_target('frida-core-library',
|
||||
input: [core] + internal_libs,
|
||||
output: f'libfrida-core-@[email protected]',
|
||||
command: [
|
||||
python,
|
||||
files('merge.py'),
|
||||
lib,
|
||||
libtool,
|
||||
ar,
|
||||
meson.current_build_dir(),
|
||||
'@OUTPUT@',
|
||||
'@INPUT@'
|
||||
],
|
||||
install: true,
|
||||
install_dir: get_option('libdir'),
|
||||
)
|
||||
endif
|
||||
core_public_lib = custom_target('frida-core-library',
|
||||
input: [core] + internal_libs,
|
||||
output: f'libfrida-core-@[email protected]',
|
||||
command: [
|
||||
python,
|
||||
files('merge.py'),
|
||||
lib,
|
||||
libtool,
|
||||
ar,
|
||||
meson.current_build_dir(),
|
||||
'@OUTPUT@',
|
||||
'@INPUT@'
|
||||
],
|
||||
install: true,
|
||||
install_dir: get_option('libdir'),
|
||||
)
|
||||
|
||||
core_public_extra_headers = []
|
||||
if host_os == 'android'
|
||||
@@ -118,50 +96,29 @@ installed_variables = {
|
||||
'frida_vapidir': vapidir,
|
||||
}
|
||||
|
||||
core_public_dep_kwargs = {
|
||||
'sources': [core_public_h, core_public_gir, glib_gir, gobject_gir, gio_gir, core_public_vapi_stamp] + core_public_extra_headers,
|
||||
'include_directories': include_directories('.'),
|
||||
'link_with': core_public_lib,
|
||||
'dependencies': core_deps,
|
||||
'variables': uninstalled_variables,
|
||||
}
|
||||
if not is_shared
|
||||
core_public_dep_kwargs += {
|
||||
'link_args': backend_libs_private,
|
||||
}
|
||||
endif
|
||||
core_public_dep = declare_dependency(kwargs: core_public_dep_kwargs)
|
||||
|
||||
core_public_reqs = ['glib-2.0', 'gobject-2.0', 'gio-2.0', 'json-glib-1.0']
|
||||
if host_os_family == 'windows'
|
||||
core_public_reqs += 'gio-windows-2.0'
|
||||
else
|
||||
core_public_reqs += 'gio-unix-2.0'
|
||||
endif
|
||||
core_public_dep = declare_dependency(
|
||||
sources: [core_public_h, core_public_gir, glib_gir, gobject_gir, gio_gir, core_public_vapi_stamp, core_public_extra_headers],
|
||||
include_directories: include_directories('.'),
|
||||
link_args: backend_libs_private,
|
||||
link_with: core_public_lib,
|
||||
dependencies: core_deps,
|
||||
variables: uninstalled_variables,
|
||||
)
|
||||
|
||||
pkg = import('pkgconfig')
|
||||
pkg_kwargs = {
|
||||
'filebase': f'frida-core-@api_version@',
|
||||
'name': 'Frida Core Library',
|
||||
'version': frida_version,
|
||||
'description': 'Instrumentation toolkit for developers, reverse-engineers, and security researchers',
|
||||
'requires': core_public_reqs,
|
||||
'subdirs': f'frida-@api_version@',
|
||||
'extra_cflags': ['-I${frida_includedir}'],
|
||||
'variables': installed_variables,
|
||||
'uninstalled_variables': uninstalled_variables,
|
||||
}
|
||||
if is_shared
|
||||
pkg_kwargs += {
|
||||
'libraries': ['-L${libdir}', f'-lfrida-core-@api_version@'],
|
||||
}
|
||||
else
|
||||
pkg_kwargs += {
|
||||
'libraries': core_public_lib,
|
||||
'requires_private': ['gmodule-2.0', 'gee-0.8', 'libsoup-3.0', 'efni-1.0', 'frida-gum-1.0', 'frida-gumjs-inspector-1.0', 'libbrotlidec'] + backend_reqs_private,
|
||||
'libraries_private': backend_libs_private,
|
||||
}
|
||||
endif
|
||||
pkg.generate(kwargs: pkg_kwargs)
|
||||
pkg.generate(
|
||||
filebase: f'frida-core-@api_version@',
|
||||
name: 'Frida Core Library',
|
||||
version: frida_version,
|
||||
description: 'Instrumentation toolkit for developers, reverse-engineers, and security researchers',
|
||||
requires: ['glib-2.0', 'gobject-2.0', 'gio-2.0', 'json-glib-1.0'],
|
||||
requires_private: ['gmodule-2.0', 'gee-0.8', 'libsoup-3.0', 'frida-gum-1.0', 'frida-gumjs-inspector-1.0', 'libbrotlidec'] + backend_reqs_private,
|
||||
subdirs: f'frida-@api_version@',
|
||||
libraries: core_public_lib,
|
||||
libraries_private: backend_libs_private,
|
||||
extra_cflags: ['-I${frida_includedir}'],
|
||||
variables: installed_variables,
|
||||
uninstalled_variables: uninstalled_variables,
|
||||
)
|
||||
|
||||
meson.override_dependency(f'frida-core-@api_version@', core_public_dep)
|
||||
+211
-1175
File diff suppressed because it is too large.
Load diff
Generated
+4
-4
@@ -13,9 +13,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.72.1"
|
||||
version = "0.72.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
|
||||
checksum = "4f72209734318d0b619a5e0f5129918b848c416e122a3c4ce054e03cb87b726f"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cexpr",
|
||||
@@ -63,9 +63,9 @@ checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.9.1"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "157a8ba7b480713b56f4c09fd13fc3e0a22a5dfab8097ba61cbc5feef950788a"
|
||||
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
|
||||
@@ -4,31 +4,6 @@ version = "1.0.0"
|
||||
edition = "2024"
|
||||
build = "build.rs"
|
||||
|
||||
[lib]
|
||||
name = "frida_barebone_agent"
|
||||
path = "src/lib.rs"
|
||||
crate-type = ["rlib", "staticlib"]
|
||||
|
||||
# The XNU flavour is a freestanding executable the host injects and calls into.
|
||||
# The Linux flavour is the staticlib above, linked into a .ko by linux/Kbuild.
|
||||
[[bin]]
|
||||
name = "frida-barebone-agent"
|
||||
path = "src/main.rs"
|
||||
required-features = ["blob"]
|
||||
|
||||
[features]
|
||||
# Flavors the host injects and calls into, as opposed to the module Linux loads.
|
||||
blob = []
|
||||
# The XNU flavour itself, and the two ways it is packaged: a blob the host injects
|
||||
# into a running kernel, and a kext that kernel loads.
|
||||
xnu-core = []
|
||||
xnu = ["xnu-core", "blob"]
|
||||
xnu-kext = ["xnu-core"]
|
||||
win9x = ["blob"]
|
||||
winnt = ["blob"]
|
||||
linux = []
|
||||
linux-injected = ["blob"]
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
opt-level = "z"
|
||||
|
||||
@@ -1,75 +1,30 @@
|
||||
## Getting the SDK and the devkit
|
||||
## Getting the C toolchain
|
||||
|
||||
The agent is built against the bare soft-float SDK, which carries picolibc and the
|
||||
compiler runtime, and against a GumJS devkit built for the same machine. Which machine
|
||||
is the target's, listed under Targets below; this walks through the XNU one. The SDK
|
||||
is published prebuilt, and the devkit is built from frida-gum:
|
||||
npm install -g xpm
|
||||
xpm install
|
||||
export PATH=$PWD/xpacks/.bin:$PATH
|
||||
|
||||
machine=none-arm64-softfloat_pic
|
||||
## How to build Gum
|
||||
|
||||
sdk=~/sdk-$machine
|
||||
releng/deps.py sync sdk $machine $sdk
|
||||
|
||||
gum=~/src/frida-gum
|
||||
mkdir -p $gum/build/$machine
|
||||
(cd $gum/build/$machine \
|
||||
&& CC=clang CXX=clang++ ../../configure --host=$machine --enable-gumjs \
|
||||
--with-devkits=gumjs --with-devkit-symbol-scope=original \
|
||||
&& make)
|
||||
./configure \
|
||||
--host=aarch64-none-elf \
|
||||
--enable-gumjs \
|
||||
--with-devkits=gum,gumjs \
|
||||
--with-devkit-symbol-scope=original
|
||||
make
|
||||
export GUMJS_DEVKIT_DIR=$PWD/build/bindings/gumjs/devkit
|
||||
|
||||
## Building
|
||||
|
||||
export GUMJS_DEVKIT_DIR=$gum/build/$machine/bindings/gumjs/devkit
|
||||
export CC="clang -I$sdk/include -I$sdk/include/glib-2.0 -I$sdk/lib/glib-2.0/include \
|
||||
-I$sdk/include/capstone -I$sdk/include/json-glib-1.0"
|
||||
export RUSTFLAGS="-L native=$sdk/lib"
|
||||
|
||||
RUSTC_BOOTSTRAP=1 cargo build --release --features xnu \
|
||||
--target ./aarch64-unknown-none-pic.json -Z json-target-spec \
|
||||
--target-dir target-xnu -Z build-std=core,alloc,compiler_builtins
|
||||
|
||||
Every flavor names its target by path, as Rust has no built-in one for a
|
||||
position-independent bare-metal image. The others differ only in feature, machine
|
||||
and target spec, listed under Targets below.
|
||||
|
||||
## Targets
|
||||
|
||||
The agent supports four kernels. One of them has to be picked; none is a default,
|
||||
since none follows from the host you build on:
|
||||
|
||||
- `xnu` — a freestanding ELF executable that the Barebone backend
|
||||
injects into a running kernel from the outside, over a remote stub.
|
||||
- `win9x` — the same, for a 32-bit Windows 9x guest.
|
||||
- `winnt` — the same, for a Windows NT guest, either word size, on x86 or arm64.
|
||||
- `linux` — a static library that becomes a kernel module, loaded from the
|
||||
inside. See `linux/README.md`.
|
||||
|
||||
Each flavor has an SDK and a devkit of its own, since the addressing differs: an
|
||||
image the host places goes in position-independent, a Linux module is absolute,
|
||||
and NT's 64-bit half is called in the Microsoft ABI.
|
||||
|
||||
| Flavor | Machine | Rust target |
|
||||
|---------|-----------------------------------|----------------------------------|
|
||||
| `xnu` | `none-arm64-softfloat_pic` | `aarch64-unknown-none-pic.json` |
|
||||
| `win9x` | `none-x86-softfloat_pic` | `i686-unknown-none-pic.json` |
|
||||
| `winnt` | `none-x86-softfloat_pic` | `i686-unknown-none-pic.json` |
|
||||
| `winnt` | `none-x86_64-softfloat_pic_msabi` | `x86_64-unknown-none-pic.json` |
|
||||
| `winnt` | `none-arm64-softfloat_pic` | `aarch64-unknown-none-pic.json` |
|
||||
| `linux` | `none-<arch>-softfloat_nopic` | see `linux/README.md` |
|
||||
|
||||
Everything above the `kernel` module is shared; each backend supplies the same
|
||||
set of primitives (logging, allocation, threads, waiting, time, symbols) plus its
|
||||
half of Gum's platform backend (`gum_xnu.rs` / `gum_windows.rs` / `gum_linux.rs`).
|
||||
export PATH=$PWD/xpacks/.bin:$PATH
|
||||
export CC_aarch64_unknown_none=aarch64-none-elf-gcc
|
||||
export AR_aarch64_unknown_none=aarch64-none-elf-ar
|
||||
export RANLIB_aarch64_unknown_none=aarch64-none-elf-ranlib
|
||||
|
||||
## Development loop
|
||||
|
||||
export FRIDA_BAREBONE_CONFIG=$PWD/etc/xnu.json
|
||||
RUSTC_BOOTSTRAP=1 cargo build --release --features xnu \
|
||||
--target ./aarch64-unknown-none-pic.json -Z json-target-spec \
|
||||
--target-dir target-xnu -Z build-std=core,alloc,compiler_builtins \
|
||||
&& make -C ~/src/frida-python \
|
||||
&& killall -9 qemu-system-aarch64 && sleep 2 \
|
||||
&& frida -D barebone -p 0
|
||||
cargo build --release && make -C ~/src/frida-python && killall -9 qemu-system-aarch64 && sleep 2 && frida -D barebone -p 0
|
||||
|
||||
## Speeding up loop
|
||||
|
||||
@@ -77,7 +32,6 @@ half of Gum's platform backend (`gum_xnu.rs` / `gum_windows.rs` / `gum_linux.rs`
|
||||
-- \
|
||||
-Dfrida-core:compat=disabled \
|
||||
-Dfrida-core:local_backend=disabled \
|
||||
-Dfrida-core:simmy_backend=disabled \
|
||||
-Dfrida-core:fruity_backend=disabled \
|
||||
-Dfrida-core:droidy_backend=disabled \
|
||||
-Dfrida-core:socket_backend=disabled \
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"abi": "softfloat",
|
||||
"arch": "aarch64",
|
||||
"crt-objects-fallback": "false",
|
||||
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32",
|
||||
"disable-redzone": true,
|
||||
"features": "+v8a,+strict-align,-neon,+reserve-x18",
|
||||
"linker": "rust-lld",
|
||||
"linker-flavor": "gnu-lld",
|
||||
"llvm-target": "aarch64-unknown-none",
|
||||
"max-atomic-width": 128,
|
||||
"panic-strategy": "abort",
|
||||
"plt-by-default": false,
|
||||
"position-independent-executables": true,
|
||||
"relocation-model": "pic",
|
||||
"rustc-abi": "softfloat",
|
||||
"stack-probes": {
|
||||
"kind": "inline"
|
||||
},
|
||||
"target-pointer-width": 64
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
SECTIONS {
|
||||
.text : {
|
||||
*(.text.entrypoint)
|
||||
*(.text*)
|
||||
}
|
||||
.rel.dyn : {
|
||||
_agent_relocs_start = .;
|
||||
*(.rel.dyn)
|
||||
_agent_relocs_end = .;
|
||||
}
|
||||
.rodata : {
|
||||
*(.rodata*)
|
||||
}
|
||||
.kernel_addrs : ALIGN(4) {
|
||||
. = ALIGN(4);
|
||||
__printk = .; . += 4;
|
||||
_printk = .; . += 4;
|
||||
_panic = .; . += 4;
|
||||
_kthread_create_on_node = .; . += 4;
|
||||
_wake_up_process = .; . += 4;
|
||||
_fget = .; . += 4;
|
||||
_kernel_read = .; . += 4;
|
||||
_filp_open = .; . += 4;
|
||||
_kernel_write = .; . += 4;
|
||||
___kmalloc_noprof = .; . += 4;
|
||||
_kmalloc = .; . += 4;
|
||||
___kmalloc = .; . += 4;
|
||||
_kfree = .; . += 4;
|
||||
_vmalloc = .; . += 4;
|
||||
_execmem_alloc = .; . += 4;
|
||||
_set_memory_rw = .; . += 4;
|
||||
_set_memory_ro = .; . += 4;
|
||||
_set_memory_x = .; . += 4;
|
||||
_set_memory_nx = .; . += 4;
|
||||
_modules = .; . += 4;
|
||||
_register_module_notifier = .; . += 4;
|
||||
_unregister_module_notifier = .; . += 4;
|
||||
_execmem_free = .; . += 4;
|
||||
_module_alloc = .; . += 4;
|
||||
_module_memfree = .; . += 4;
|
||||
___init_waitqueue_head = .; . += 4;
|
||||
_prepare_to_wait_event = .; . += 4;
|
||||
_finish_wait = .; . += 4;
|
||||
___wake_up = .; . += 4;
|
||||
_autoremove_wake_function = .; . += 4;
|
||||
_schedule_hrtimeout_range = .; . += 4;
|
||||
_pci_get_domain_bus_and_slot = .; . += 4;
|
||||
_pci_irq_vector = .; . += 4;
|
||||
_of_irq_parse_and_map_pci = .; . += 4;
|
||||
_pci_dev_put = .; . += 4;
|
||||
_schedule = .; . += 4;
|
||||
_ktime_get_mono_fast_ns = .; . += 4;
|
||||
_ktime_get_real_ts64 = .; . += 4;
|
||||
_getnstimeofday64 = .; . += 4;
|
||||
_send_sig = .; . += 4;
|
||||
_free_irq = .; . += 4;
|
||||
_request_threaded_irq = .; . += 4;
|
||||
_vmap = .; . += 4;
|
||||
___pv_offset = .; . += 4;
|
||||
_pgprot_kernel = .; . += 4;
|
||||
_ioremap = .; . += 4;
|
||||
_of_find_node_opts_by_path = .; . += 4;
|
||||
_of_irq_get = .; . += 4;
|
||||
_of_node_put = .; . += 4;
|
||||
_init_task = .; . += 4;
|
||||
_tasklist_lock = .; . += 4;
|
||||
__raw_read_lock = .; . += 4;
|
||||
__raw_read_unlock = .; . += 4;
|
||||
__raw_read_lock_irqsave = .; . += 4;
|
||||
__raw_read_unlock_irqrestore = .; . += 4;
|
||||
__raw_write_lock = .; . += 4;
|
||||
__raw_write_unlock = .; . += 4;
|
||||
__raw_write_lock_irqsave = .; . += 4;
|
||||
__raw_write_unlock_irqrestore = .; . += 4;
|
||||
_detach_pid = .; . += 4;
|
||||
_free_pids = .; . += 4;
|
||||
_get_task_exe_file = .; . += 4;
|
||||
_file_path = .; . += 4;
|
||||
_fput = .; . += 4;
|
||||
_copy_from_kernel_nofault = .; . += 4;
|
||||
_get_task_mm = .; . += 4;
|
||||
_kthread_use_mm = .; . += 4;
|
||||
_kthread_unuse_mm = .; . += 4;
|
||||
_mmput = .; . += 4;
|
||||
_vm_mmap = .; . += 4;
|
||||
_vm_munmap = .; . += 4;
|
||||
_tracepoint_probe_register = .; . += 4;
|
||||
_tracepoint_probe_unregister = .; . += 4;
|
||||
___tracepoint_sched_process_fork = .; . += 4;
|
||||
___tracepoint_sched_process_exit = .; . += 4;
|
||||
___tracepoint_sched_process_exec = .; . += 4;
|
||||
___tracepoint_task_rename = .; . += 4;
|
||||
___set_task_comm = .; . += 4;
|
||||
_vunmap = .; . += 4;
|
||||
_arm_copy_to_user = .; . += 4;
|
||||
_down_read = .; . += 4;
|
||||
_up_read = .; . += 4;
|
||||
_get_user_pages_unlocked = .; . += 4;
|
||||
_get_user_pages_remote = .; . += 4;
|
||||
_user_mode_thread = .; . += 4;
|
||||
_fget_task = .; . += 4;
|
||||
_find_task_by_vpid = .; . += 4;
|
||||
___start_BTF = .; . += 4;
|
||||
___stop_BTF = .; . += 4;
|
||||
_call_usermodehelper_setup = .; . += 4;
|
||||
_call_usermodehelper_exec = .; . += 4;
|
||||
_arm_copy_from_user = .; . += 4;
|
||||
_fixup_exception = .; . += 4;
|
||||
_init_net = .; . += 4;
|
||||
_sock_create_kern = .; . += 4;
|
||||
_kernel_connect = .; . += 4;
|
||||
_kernel_sendmsg = .; . += 4;
|
||||
_kernel_recvmsg = .; . += 4;
|
||||
_sock_release = .; . += 4;
|
||||
_patch_text = .; . += 4;
|
||||
}
|
||||
/* Everything above is only ever read, so a process being instrumented can be shown the very
|
||||
same pages; everything below it each copy needs its own of. */
|
||||
. = ALIGN(4096);
|
||||
_agent_private_start = .;
|
||||
.data.rel.ro : {
|
||||
*(.data.rel.ro*)
|
||||
}
|
||||
.got : {
|
||||
*(.got*)
|
||||
}
|
||||
.init_array : {
|
||||
_agent_init_start = .;
|
||||
*(.init_array*)
|
||||
_agent_init_end = .;
|
||||
}
|
||||
.data : {
|
||||
*(.data*)
|
||||
}
|
||||
.bss : {
|
||||
*(.bss*)
|
||||
}
|
||||
. = ALIGN(4);
|
||||
_heap_start = .;
|
||||
}
|
||||
|
||||
VERSION {
|
||||
{
|
||||
global:
|
||||
_start;
|
||||
|
||||
local:
|
||||
*;
|
||||
};
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
SECTIONS {
|
||||
.text : {
|
||||
*(.text.entrypoint)
|
||||
*(.text*)
|
||||
}
|
||||
.rela.dyn : {
|
||||
_agent_relocs_start = .;
|
||||
*(.rela.dyn)
|
||||
_agent_relocs_end = .;
|
||||
}
|
||||
.rodata : {
|
||||
*(.rodata*)
|
||||
}
|
||||
.kernel_addrs : ALIGN(8) {
|
||||
. = ALIGN(8);
|
||||
__printk = .; . += 8;
|
||||
_printk = .; . += 8;
|
||||
_panic = .; . += 8;
|
||||
_kthread_create_on_node = .; . += 8;
|
||||
_wake_up_process = .; . += 8;
|
||||
_fget = .; . += 8;
|
||||
_kernel_read = .; . += 8;
|
||||
_filp_open = .; . += 8;
|
||||
_kernel_write = .; . += 8;
|
||||
___kmalloc_noprof = .; . += 8;
|
||||
_kmalloc = .; . += 8;
|
||||
___kmalloc = .; . += 8;
|
||||
_kfree = .; . += 8;
|
||||
_vmalloc = .; . += 8;
|
||||
_execmem_alloc = .; . += 8;
|
||||
_set_memory_rw = .; . += 8;
|
||||
_set_memory_ro = .; . += 8;
|
||||
_set_memory_x = .; . += 8;
|
||||
_set_memory_nx = .; . += 8;
|
||||
_modules = .; . += 8;
|
||||
_register_module_notifier = .; . += 8;
|
||||
_unregister_module_notifier = .; . += 8;
|
||||
_execmem_free = .; . += 8;
|
||||
_module_alloc = .; . += 8;
|
||||
_module_memfree = .; . += 8;
|
||||
___init_waitqueue_head = .; . += 8;
|
||||
_prepare_to_wait_event = .; . += 8;
|
||||
_finish_wait = .; . += 8;
|
||||
___wake_up = .; . += 8;
|
||||
_autoremove_wake_function = .; . += 8;
|
||||
_schedule_hrtimeout_range = .; . += 8;
|
||||
_pci_get_domain_bus_and_slot = .; . += 8;
|
||||
_pci_irq_vector = .; . += 8;
|
||||
_of_irq_parse_and_map_pci = .; . += 8;
|
||||
_pci_dev_put = .; . += 8;
|
||||
_schedule = .; . += 8;
|
||||
_ktime_get_mono_fast_ns = .; . += 8;
|
||||
_ktime_get_real_ts64 = .; . += 8;
|
||||
_getnstimeofday64 = .; . += 8;
|
||||
_send_sig = .; . += 8;
|
||||
_free_irq = .; . += 8;
|
||||
_request_threaded_irq = .; . += 8;
|
||||
_generic_ioremap_prot = .; . += 8;
|
||||
___ioremap = .; . += 8;
|
||||
_vmap = .; . += 8;
|
||||
_memstart_addr = .; . += 8;
|
||||
_init_task = .; . += 8;
|
||||
_tasklist_lock = .; . += 8;
|
||||
__raw_read_lock = .; . += 8;
|
||||
__raw_read_unlock = .; . += 8;
|
||||
__raw_read_lock_irqsave = .; . += 8;
|
||||
__raw_read_unlock_irqrestore = .; . += 8;
|
||||
__raw_write_lock = .; . += 8;
|
||||
__raw_write_unlock = .; . += 8;
|
||||
__raw_write_lock_irqsave = .; . += 8;
|
||||
__raw_write_unlock_irqrestore = .; . += 8;
|
||||
_detach_pid = .; . += 8;
|
||||
_free_pids = .; . += 8;
|
||||
_get_task_exe_file = .; . += 8;
|
||||
_file_path = .; . += 8;
|
||||
_fput = .; . += 8;
|
||||
_copy_from_kernel_nofault = .; . += 8;
|
||||
_get_task_mm = .; . += 8;
|
||||
_kthread_use_mm = .; . += 8;
|
||||
_kthread_unuse_mm = .; . += 8;
|
||||
_mmput = .; . += 8;
|
||||
_vm_mmap = .; . += 8;
|
||||
_vm_munmap = .; . += 8;
|
||||
_tracepoint_probe_register = .; . += 8;
|
||||
_tracepoint_probe_unregister = .; . += 8;
|
||||
___tracepoint_sched_process_fork = .; . += 8;
|
||||
___tracepoint_sched_process_exit = .; . += 8;
|
||||
___tracepoint_sched_process_exec = .; . += 8;
|
||||
___tracepoint_task_rename = .; . += 8;
|
||||
___set_task_comm = .; . += 8;
|
||||
_vunmap = .; . += 8;
|
||||
___arch_copy_to_user = .; . += 8;
|
||||
_down_read = .; . += 8;
|
||||
_up_read = .; . += 8;
|
||||
_get_user_pages_unlocked = .; . += 8;
|
||||
_get_user_pages_remote = .; . += 8;
|
||||
___arch_copy_from_user = .; . += 8;
|
||||
_do_futex = .; . += 8;
|
||||
_user_mode_thread = .; . += 8;
|
||||
_apply_to_existing_page_range = .; . += 8;
|
||||
_caches_clean_inval_pou = .; . += 8;
|
||||
_do_madvise = .; . += 8;
|
||||
_fget_task = .; . += 8;
|
||||
_find_task_by_vpid = .; . += 8;
|
||||
___start_BTF = .; . += 8;
|
||||
___stop_BTF = .; . += 8;
|
||||
_call_usermodehelper_setup = .; . += 8;
|
||||
_call_usermodehelper_exec = .; . += 8;
|
||||
_access_process_vm = .; . += 8;
|
||||
_fixup_exception = .; . += 8;
|
||||
_aarch64_insn_patch_text_nosync = .; . += 8;
|
||||
_aarch64_insn_patch_text = .; . += 8;
|
||||
_kthread_worker_fn = .; . += 8;
|
||||
_vring_interrupt = .; . += 8;
|
||||
_init_net = .; . += 8;
|
||||
_sock_create_kern = .; . += 8;
|
||||
_kernel_connect = .; . += 8;
|
||||
_kernel_sendmsg = .; . += 8;
|
||||
_kernel_recvmsg = .; . += 8;
|
||||
_sock_release = .; . += 8;
|
||||
_sock_def_readable = .; . += 8;
|
||||
}
|
||||
/* Everything above is only ever read, so a process being instrumented can be shown the very
|
||||
same pages; everything below it each copy needs its own of. */
|
||||
. = ALIGN(4096);
|
||||
_agent_private_start = .;
|
||||
.data.rel.ro : {
|
||||
*(.data.rel.ro*)
|
||||
}
|
||||
.got : {
|
||||
*(.got*)
|
||||
}
|
||||
.init_array : {
|
||||
_agent_init_start = .;
|
||||
*(.init_array*)
|
||||
_agent_init_end = .;
|
||||
}
|
||||
.data : {
|
||||
*(.data*)
|
||||
}
|
||||
.bss : {
|
||||
*(.bss*)
|
||||
}
|
||||
. = ALIGN(8);
|
||||
_heap_start = .;
|
||||
}
|
||||
|
||||
VERSION {
|
||||
{
|
||||
global:
|
||||
_start;
|
||||
|
||||
local:
|
||||
*;
|
||||
};
|
||||
}
|
||||
Loaded 100 of 524 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user