diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 7ffadd2..eb7fab9 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -15,13 +15,6 @@ jobs: steps: - uses: actions/checkout@v3 - - name: setup ndk - uses: nttld/setup-ndk@v1 - id: setup-ndk - with: - ndk-version: r23 - add-to-path: true - - name: build dist run: | git submodule init && git submodule update @@ -35,3 +28,18 @@ jobs: artifacts: "adguardcert-*.zip" token: ${{ secrets.GITHUB_TOKEN }} generateReleaseNotes: true + + - name: write PR url + if: github.event_name == 'pull_request' + run: | + echo "${{ github.event.pull_request.html_url }}" > pull_request_url.txt + + - name: upload artifact + uses: actions/upload-artifact@v3 + if: github.event_name == 'pull_request' + with: + name: adguardcert module build + path: | + adguardcert-*.zip + README.md + pull_request_url.txt diff --git a/.gitmodules b/.gitmodules index b2f6d09..e69de29 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "zygisk_module/jni/libcxx"] - path = zygisk_module/jni/libcxx - url = https://github.com/topjohnwu/libcxx.git diff --git a/README.md b/README.md index dbe6f37..22feda9 100644 --- a/README.md +++ b/README.md @@ -5,15 +5,38 @@ Based on [Move Certificates](https://github.com/Magisk-Modules-Repo/movecert). This Magisk module supplements [AdGuard for Android][agandroid] and allows installing AdGuard's CA certificate to the System store on rooted devices. -## Why could you need it? +**Attention** +[Current version](https://github.com/AdguardTeam/adguardcert/releases/latest) +of this module is designed for Adguard for Android 4.2 and newer. + +If you're using AdGuard for Android v4.1 or older, please use the earlier version of +this magisk module: https://github.com/AdguardTeam/adguardcert/releases/tag/v1.2. + +## Explanation + +Chrome (and subsequently many other Chromium-based browsers) +has recently started requiring Certificate Transparency logs +for CA certs found in the **system certificate store**. + +If your device is rooted, and you want AdGuard's CA certificate to be installed +in the **system store** , then AdGuard will generate two CA certificates and ask you +to install both of them in the **user store**. This module moves one of them to the +**system store**. The certificate that is left in the **user store** is cross-signed +with the one that goes into the **system store**. This allows apps that don't trust +user certificates to still accept AdGuard's certificate, while apps that do trust +user certificates (like Chrome or other browsers) will construct a shorter validation +path to the certificate stored in the **user store**. And since it is stored in the +**user store**, they won't require CT logs. + +## Why would I want AdGuard's certificate in the system store? AdGuard for Android provides a feature called [HTTPS filtering][httpsfiltering]. It allows filtering of encrypted HTTPS traffic on your Android device. This feature requires adding the AdGuard's CA certificate to the list of trusted certificates. By default, on a non-rooted device only a limited subset of apps (mostly, browsers) -trust the CA certificates installed to the **User store**. The only option to allow -filtering of all other apps' traffic is to install the certificate to the **System store**. +trust the CA certificates installed to the **user store**. The only option to allow +filtering of all other apps' traffic is to install the certificate to the **system store**. Unfortunately, this is only possible on rooted devices. [agandroid]: https://adguard.com/adguard-android/overview.html @@ -21,26 +44,19 @@ Unfortunately, this is only possible on rooted devices. ## Usage -1. Enable HTTPS filtering in AdGuard for Android and save AdGuard's certificate to the User store. -2. Go to *Magisk -> Settings* and enable **Zygisk**. -3. Download the `.zip` file from the [latest release][latestrelease]. -4. Go to *Magisk -> Modules -> Install from storage* and select the downloaded `.zip` file. -5. Reboot. +1. Enable HTTPS filtering in AdGuard for Android and save AdGuard's certificate(s) to the User store +2. Download the `.zip` file from the [latest release][latestrelease]. +3. Go to *Magisk -> Modules -> Install from storage* and select the downloaded `.zip` file. +4. Reboot. -If a new version comes out, repeat steps 3-5 to update the module. +If a new version comes out, repeat steps 2-4 to update the module. -The module does its work during the system boot. If your AdGuard certificate changes, +The module does its work during the system boot. If your AdGuard certificate(s) change, you'll have to reboot the device for the new certificate to be copied to the system store.
Illustrated instruction -![Open Magisk settings](https://user-images.githubusercontent.com/5947035/161061257-680c784b-b476-432d-8dfd-2528fe239346.png) - -![Enable Zygisk](https://user-images.githubusercontent.com/5947035/161061268-3367d668-cbbd-441d-9e6d-a4cbc3978b3e.png) - -![Go back to Magisk main screen](https://user-images.githubusercontent.com/5947035/161061273-329e3f8a-c957-4005-a8f7-2056b1866b08.png) - ![Open Magisk modules](https://user-images.githubusercontent.com/5947035/161061277-1ada3a87-d0cb-44c0-9edd-77b00669759c.png) ![Install from storage](https://user-images.githubusercontent.com/5947035/161061283-8e3d6ed2-ca36-4825-bca4-fbb9f9185f68.png) @@ -51,7 +67,7 @@ you'll have to reboot the device for the new certificate to be copied to the sys
-Please note that in order for **Bromite** browser to work properly, you need to set flag "Allow user certificates" in `chrome://flags` to "Enabled" state. +Please note that in order for **Bromite** browser to work properly, you need to set the "Allow user certificates" flag in `chrome://flags` to "Enabled".
Bromite setup @@ -62,39 +78,11 @@ Please note that in order for **Bromite** browser to work properly, you need to [latestrelease]: https://github.com/AdguardTeam/adguardcert/releases/latest/ -## Chrome and Chromium-based browsers - -Chrome (and subsequently many other Chromium-based browsers) -has recently started requiring CT logs for CA certs found in the **System store**. -This module copies AdGuard's CA certificate from the **User store** to the **System store**. -It also contains a Zygisk module that reverts any modifications done by Magisk for -[certain browsers](./zygisk_module/jni/browsers.inc). -This way the browsers only find AdGuard's certificate in the User store -and don't complain about the missing CT log, while other apps continue to use the -same certificate from the System store. - ## Building - -Update git modules: - -```shell -git submodule init && git submodule update -``` - -You'll need an Android SDK with NDK installed (tested with NDK 22 and 23). Run: - ```shell -ANDROID_HOME= ./dist.sh +./dist.sh ``` How to release a new version: 1. Push a new tag with a name like `v*`. 2. A new release will be automatically created. - -## Advanced - -If you prefer to manage your Zygisk denylist yourself, simply remove the Zygisk part of the module: - -```shell -zip adguardcert-v1.0.zip -d "zygisk/*" -``` diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 8ca4829..0000000 --- a/build.gradle +++ /dev/null @@ -1,17 +0,0 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. -buildscript { - repositories { - google() - mavenCentral() - } - dependencies { - classpath "com.android.tools.build:gradle:7.0.3" - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - } -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/dist.sh b/dist.sh index ffdd090..4bdf8a3 100755 --- a/dist.sh +++ b/dist.sh @@ -1,27 +1,5 @@ #!/bin/bash -if [ -z "${ANDROID_HOME}" ]; then - echo "Specify the Android SDK directory through the ANDROID_HOME environment variable" - exit 1 -fi - -NDK_PATH=$(./ndk_path.py) - -if [ ! -d "${NDK_PATH}" ]; then - echo "NDK version ${NDK_VERSION} is required and was not found at ${NDK_PATH}" - exit 1 -fi - -NDK_BUILD="${NDK_PATH}/ndk-build" - -(cd ./zygisk_module && ${NDK_BUILD} -j8) || exit 1 - -mkdir ./module/zygisk - -for i in $(ls ./zygisk_module/libs); do - cp -f ./zygisk_module/libs/$i/*.so ./module/zygisk/$i.so -done - UPDATE_BINARY_URL="https://raw.githubusercontent.com/topjohnwu/Magisk/master/scripts/module_installer.sh" mkdir -p ./module/META-INF/com/google/android diff --git a/gradle.properties b/gradle.properties deleted file mode 100644 index 01b80d7..0000000 --- a/gradle.properties +++ /dev/null @@ -1,19 +0,0 @@ -# Project-wide Gradle settings. -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true -# AndroidX package structure to make it clearer which packages are bundled with the -# Android operating system, and which are packaged with your app"s APK -# https://developer.android.com/topic/libraries/support-library/androidx-rn -android.useAndroidX=true -# Automatically convert third-party libraries to use AndroidX -android.enableJetifier=true diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index e708b1c..0000000 Binary files a/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index f4bd034..0000000 --- a/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Sun Sep 26 02:13:18 PDT 2021 -distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip -distributionPath=wrapper/dists -zipStorePath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew deleted file mode 100755 index 4f906e0..0000000 --- a/gradlew +++ /dev/null @@ -1,185 +0,0 @@ -#!/usr/bin/env sh - -# -# Copyright 2015 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=`expr $i + 1` - done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat deleted file mode 100644 index ac1b06f..0000000 --- a/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/module/module.prop b/module/module.prop index 3e7d000..d73ed25 100644 --- a/module/module.prop +++ b/module/module.prop @@ -1,7 +1,7 @@ id=adguardcert name=AdGuard Certificate -version=v1.2 -versionCode=3 +version=v2.0 +versionCode=35 author=AdGuard -description=Copies AdGuard's CA certificate from the user certificate store to the system store and forces Zygisk unmount procedures for certain browsers. +description=Moves AdGuard's root CA certificate from the user certificate store to the system certificate store. updateJson=https://raw.githubusercontent.com/AdguardTeam/adguardcert/master/update.json diff --git a/module/post-fs-data.sh b/module/post-fs-data.sh index a823a50..3492e0f 100644 --- a/module/post-fs-data.sh +++ b/module/post-fs-data.sh @@ -1,33 +1,73 @@ #!/system/bin/sh + +exec > /data/local/tmp/adguardcert.log +exec 2>&1 + +set -x + MODDIR=${0%/*} +set_context() { + [ "$(getenforce)" = "Enforcing" ] || return 0 + + default_selinux_context=u:object_r:system_file:s0 + selinux_context=$(ls -Zd $1 | awk '{print $1}') + + if [ -n "$selinux_context" ] && [ "$selinux_context" != "?" ]; then + chcon -R $selinux_context $2 + else + chcon -R $default_selinux_context $2 + fi +} + # Android hashes the subject to get the filename, field order is significant. +# (`openssl x509 -in ... -noout -hash`) # AdGuard's certificate is "/C=EN/O=AdGuard/CN=AdGuard Personal CA". # The filename is then . where is an integer to disambiguate # different certs with the same hash (e.g. when the same cert is installed repeatedly). -# +# # Due to https://github.com/AdguardTeam/AdguardForAndroid/issues/2108 -# 1. Take the last cert with our hash from the user store. -# Assuming the last installed AdGuard's cert is the correct one. -# 2. Copy it to the system store under the name ".0". -# Apparently, some apps may ignore other certs. +# 1. Retrieve the most recent certificate with our hash from the user store. +# It is assumed that the last installed AdGuard's cert is the correct one. +# 2. Copy the AdGuard certificate to the system store under the name ".0". +# Note that some apps may ignore other certs. # 3. Remove all certs with our hash from the `cacerts-removed` directory. # They get there if a certificate is "disabled" in the security settings. # Apps will reject certs that are in the `cacerts-removed`. AG_CERT_HASH=0f4ed297 -AG_CERT_FILE=$(ls /data/misc/user/*/cacerts-added/${AG_CERT_HASH}.* | sort | tail -n1) -cp -f ${AG_CERT_FILE} ${MODDIR}/system/etc/security/cacerts/${AG_CERT_HASH}.0 +AG_CERT_FILE=$(ls /data/misc/user/*/cacerts-added/${AG_CERT_HASH}.* | (IFS=.; while read -r left right; do echo $right $left.$right; done) | sort -nr | (read -r left right; echo $right)) + +if ! [ -e "${AG_CERT_FILE}" ]; then + exit 0 +fi + rm -f /data/misc/user/*/cacerts-removed/${AG_CERT_HASH}.* +cp -f ${AG_CERT_FILE} ${MODDIR}/system/etc/security/cacerts/${AG_CERT_HASH}.0 chown -R 0:0 ${MODDIR}/system/etc/security/cacerts +set_context /system/etc/security/cacerts ${MODDIR}/system/etc/security/cacerts -[ "$(getenforce)" = "Enforcing" ] || exit 0 +# Android 14 support +# Since Magisk ignore /apex for module file injections, use non-Magisk way +if [ -d /apex/com.android.conscrypt/cacerts ]; then + # Clone directory into tmpfs + rm -f /data/local/tmp/adg-ca-copy + mkdir -p /data/local/tmp/adg-ca-copy + mount -t tmpfs tmpfs /data/local/tmp/adg-ca-copy + cp -f /apex/com.android.conscrypt/cacerts/* /data/local/tmp/adg-ca-copy/ -default_selinux_context=u:object_r:system_file:s0 -selinux_context=$(ls -Zd /system/etc/security/cacerts | awk '{print $1}') + # Do the same as in Magisk module + cp -f ${AG_CERT_FILE} /data/local/tmp/adg-ca-copy + chown -R 0:0 /data/local/tmp/adg-ca-copy + set_context /apex/com.android.conscrypt/cacerts /data/local/tmp/adg-ca-copy -if [ -n "$selinux_context" ] && [ "$selinux_context" != "?" ]; then - chcon -R $selinux_context $MODDIR/system/etc/security/cacerts -else - chcon -R $default_selinux_context $MODDIR/system/etc/security/cacerts + # Mount directory inside APEX if it is valid, and remove temporary one. + CERTS_NUM="$(ls -1 /data/local/tmp/adg-ca-copy | wc -l)" + if [ "$CERTS_NUM" -gt 10 ]; then + mount --bind /data/local/tmp/adg-ca-copy /apex/com.android.conscrypt/cacerts + else + echo "Cancelling replacing CA storage due to safety" + fi + umount /data/local/tmp/adg-ca-copy + rmdir /data/local/tmp/adg-ca-copy fi diff --git a/ndk_path.py b/ndk_path.py deleted file mode 100755 index 30f4a1c..0000000 --- a/ndk_path.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python3 - -import os - -def get_ndk_path(): - sdk_path = os.environ.get('ANDROID_HOME') - if os.path.isdir(sdk_path): - path = os.path.join(sdk_path, 'ndk') - if os.path.isdir(path): - # Android Studio can install multiple ndk versions in 'ndk'. - # Find the newest one. - ndk_version = None - for name in os.listdir(path): - if not ndk_version or ndk_version < name: - ndk_version = name - if ndk_version: - return os.path.join(path, ndk_version) - ndk_path = os.path.join(sdk_path, 'ndk-bundle') - if os.path.isdir(ndk_path): - return ndk_path - return None - -print(get_ndk_path()) diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index d0da8c5..0000000 --- a/settings.gradle +++ /dev/null @@ -1,8 +0,0 @@ -dependencyResolutionManagement { - repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) - repositories { - google() - mavenCentral() - } -} -include ':zygisk_module' diff --git a/zygisk_module/.gitignore b/zygisk_module/.gitignore deleted file mode 100644 index a264cd9..0000000 --- a/zygisk_module/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/build -/libs -/obj diff --git a/zygisk_module/build.gradle b/zygisk_module/build.gradle deleted file mode 100644 index c2019b7..0000000 --- a/zygisk_module/build.gradle +++ /dev/null @@ -1,14 +0,0 @@ -plugins { - id 'com.android.library' -} - -android { - compileSdkVersion 31 - ndkVersion "23.1.7779620" - - externalNativeBuild { - ndkBuild { - path("jni/Android.mk") - } - } -} diff --git a/zygisk_module/jni/Android.mk b/zygisk_module/jni/Android.mk deleted file mode 100644 index cc263e6..0000000 --- a/zygisk_module/jni/Android.mk +++ /dev/null @@ -1,19 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_MODULE := copycert -LOCAL_SRC_FILES := module.cpp companion.cpp common.cpp -LOCAL_STATIC_LIBRARIES := libcxx -LOCAL_LDLIBS := -llog -include $(BUILD_SHARED_LIBRARY) - -include jni/libcxx/Android.mk - -# If you do not want to use libc++, link to system stdc++ -# so that you can at least call the new operator in your code - -# include $(CLEAR_VARS) -# LOCAL_MODULE := example -# LOCAL_SRC_FILES := example.cpp -# LOCAL_LDLIBS := -llog -lstdc++ -# include $(BUILD_SHARED_LIBRARY) diff --git a/zygisk_module/jni/Application.mk b/zygisk_module/jni/Application.mk deleted file mode 100644 index 96948f8..0000000 --- a/zygisk_module/jni/Application.mk +++ /dev/null @@ -1,4 +0,0 @@ -APP_ABI := armeabi-v7a arm64-v8a x86 x86_64 -APP_CPPFLAGS := -std=c++17 -fno-exceptions -fno-rtti -fvisibility=hidden -fvisibility-inlines-hidden -APP_STL := none -APP_PLATFORM := android-21 diff --git a/zygisk_module/jni/browsers.inc b/zygisk_module/jni/browsers.inc deleted file mode 100644 index cf4d2bb..0000000 --- a/zygisk_module/jni/browsers.inc +++ /dev/null @@ -1,48 +0,0 @@ -"com.android.chrome", -"com.chrome.beta", -"com.chrome.canary", -"com.chrome.dev", -"org.chromium.chrome", -"com.brave.browser", -"com.hsv.freeadblockerbrowser", -"com.microsoft.emmx", -"com.microsoft.emmx.canary", -"com.yandex.browser", -"com.yandex.browser.alpha", -"com.yandex.browser.beta", -"com.sec.android.app.sbrowser", -"com.sec.android.app.sbrowser.beta", -"com.yandex.browser.lite", -"jp.co.fenrir.android.sleipnir", -"jp.co.fenrir.android.sleipnir_black", -"jp.co.fenrir.android.sleipnir_test", -"jp.hazuki.yuzubrowser", -"org.mozilla.fennec", -"org.mozilla.fennec_aurora", -"org.mozilla.fennec_fdroid", -"cn.mozilla.firefox", -"mobi.browser.flashfox", -"mobi.browser.flfoxpro", -"org.adblockplus.browser", -"org.iron.srware", -"org.mozilla.firefox", -"org.mozilla.firefox_beta", -"org.mozilla.fenix", -"com.android.browser", -"com.droid.browser", -"com.vionika.firephoenix", -"com.kiwibrowser.browser", -"org.bromite.bromite", -"com.vivaldi.browser", -"com.vivaldi.browser.snapshot", -"com.brave.browser", -"com.brave.browser_dev", -"com.brave.browser_beta", -"com.brave.browser_default", -"com.brave.browser_nightly", -"com.huawei.browser", -"io.github.forkmaintainers.iceraven", -"com.stoutner.privacybrowser.free", -"com.stoutner.privacybrowser.standard", -"com.naver.whale", -"us.spotco.mulch", diff --git a/zygisk_module/jni/common.cpp b/zygisk_module/jni/common.cpp deleted file mode 100644 index 4e0ba97..0000000 --- a/zygisk_module/jni/common.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "common.h" -#include - -int ag::read_int(int fd) { - int i; - if (read(fd, &i, sizeof(i)) != sizeof(i)) { - return INT_MIN; - } - return i; -} - -std::string ag::read_string(int fd) { - size_t size = 0; - if (read(fd, &size, sizeof(size)) != sizeof(size)) { - return ""; - } - std::string s; - s.resize(size); - if (read(fd, s.data(), s.size()) != s.size()) { - return ""; - } - return s; -} - -void ag::write_int(int fd, int v) { - write(fd, &v, sizeof(v)); -} - -void ag::write_string(int fd, std::string_view s) { - size_t size = s.size(); - write(fd, &size, sizeof(size)); - write(fd, s.data(), size); -} diff --git a/zygisk_module/jni/common.h b/zygisk_module/jni/common.h deleted file mode 100644 index 9d2968d..0000000 --- a/zygisk_module/jni/common.h +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include -#include -#include - -#include - -#include - -#define LOG_TAG "AdGuardCertificate" - -#ifndef NDEBUG -#define dbglog(fmt_, ...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "%s(): " fmt_, __func__, ##__VA_ARGS__) -#else -#define dbglog(fmt_, ...) ((void) fmt_) -#endif - -#define warnlog(fmt_, ...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, "%s(): " fmt_, __func__, ##__VA_ARGS__) - -namespace ag { - -template -using Ftor = std::integral_constant; -using Dir = std::unique_ptr>; - -int read_int(int fd); -std::string read_string(int fd); - -void write_int(int fd, int v); -void write_string(int fd, std::string_view s); - -} diff --git a/zygisk_module/jni/companion.cpp b/zygisk_module/jni/companion.cpp deleted file mode 100644 index 68cc9cc..0000000 --- a/zygisk_module/jni/companion.cpp +++ /dev/null @@ -1,97 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include - -#include "common.h" -#include "zygisk.hpp" - -#define APP_ID(uid) (uid % 100000) - -using Map = std::unordered_map; -static std::shared_ptr g_app_id_to_pkg; - -static void rescan_packages() { - struct stat st{}; - static std::atomic_int64_t packages_xml_ino{0}; - - stat("/data/system/packages.xml", &st); - - if (packages_xml_ino == st.st_ino) { - dbglog("Packages unchanged, no need to rescan"); - return; - } - - static std::mutex rescan_mutex; - std::scoped_lock l(rescan_mutex); - - if (packages_xml_ino == st.st_ino) { - dbglog("Packages unchanged, no need to rescan"); - return; - } - - dbglog("Rescanning packages"); - - packages_xml_ino = st.st_ino; - - ag::Dir data_dir; - data_dir.reset(opendir("/data/user_de")); - - if (!data_dir) { - dbglog("Failed to open /data/user_de"); - data_dir.reset(opendir("/data/user")); - if (!data_dir) { - warnlog("Failed to open /data/user, can't scan apps"); - return; - } - } - - Map app_id_to_pkg; - dirent *entry; - while ((entry = readdir(data_dir.get()))) { - // For each user - int dir_fd = openat(dirfd(data_dir.get()), entry->d_name, O_RDONLY); - if (ag::Dir dir{fdopendir(dir_fd)}) { - while ((entry = readdir(dir.get()))) { - // For each package - struct stat st{}; - fstatat(dir_fd, entry->d_name, &st, 0); - int uid = st.st_uid; - int app_id = APP_ID(uid); - if (app_id_to_pkg.count(app_id)) { - // This app ID has been handled - continue; - } - dbglog("uid: %d, app_id: %d, package: %s", uid, app_id, entry->d_name); - app_id_to_pkg.emplace(app_id, entry->d_name); - } - } else { - close(dir_fd); - } - } - - std::atomic_store(&g_app_id_to_pkg, std::make_shared(std::move(app_id_to_pkg))); -} - -static void companion_handler(int fd) { - rescan_packages(); - - auto app_id_to_pkg = std::atomic_load(&g_app_id_to_pkg); - - int uid = ag::read_int(fd); - - auto it = app_id_to_pkg->find(APP_ID(uid)); - if (it == app_id_to_pkg->end()) { - dbglog("uid: %d, app_id: %d, package not found", uid, APP_ID(uid)); - ag::write_string(fd, ""); - } else { - dbglog("uid: %d, app_id: %d, package: %s", uid, APP_ID(uid), it->second.c_str()); - ag::write_string(fd, it->second); - } -} - -REGISTER_ZYGISK_COMPANION(companion_handler) diff --git a/zygisk_module/jni/libcxx b/zygisk_module/jni/libcxx deleted file mode 160000 index 0aa67c3..0000000 --- a/zygisk_module/jni/libcxx +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0aa67c3ffea069bdb58fe3b5e7aad06934afb292 diff --git a/zygisk_module/jni/module.cpp b/zygisk_module/jni/module.cpp deleted file mode 100644 index 1467d67..0000000 --- a/zygisk_module/jni/module.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include - -#include - -#include "common.h" -#include "zygisk.hpp" - -static const std::unordered_set PACKAGES_TO_UNMOUNT = { -#include "browsers.inc" -}; - -class MyModule : public zygisk::ModuleBase { -public: - void onLoad(zygisk::Api *api, JNIEnv *env) override { - this->api = api; - this->env = env; - } - - void preAppSpecialize(zygisk::AppSpecializeArgs *args) override { - int fd = api->connectCompanion(); - if (fd < 0) { - warnlog("Failed to connect companion"); - return; - } - ag::write_int(fd, args->uid); - std::string package = ag::read_string(fd); - if (PACKAGES_TO_UNMOUNT.count(package)) { - dbglog("Forcing denylist unmount routines for package: %s", package.c_str()); - api->setOption(zygisk::Option::FORCE_DENYLIST_UNMOUNT); - } - api->setOption(zygisk::Option::DLCLOSE_MODULE_LIBRARY); - close(fd); - } - -private: - zygisk::Api *api; - JNIEnv *env; -}; - -REGISTER_ZYGISK_MODULE(MyModule) diff --git a/zygisk_module/jni/zygisk.hpp b/zygisk_module/jni/zygisk.hpp deleted file mode 100644 index 82d6601..0000000 --- a/zygisk_module/jni/zygisk.hpp +++ /dev/null @@ -1,328 +0,0 @@ -// This is the public API for Zygisk modules. -// DO NOT MODIFY ANY CODE IN THIS HEADER. - -#pragma once - -#include - -#define ZYGISK_API_VERSION 3 - -/* - -Define a class and inherit zygisk::ModuleBase to implement the functionality of your module. -Use the macro REGISTER_ZYGISK_MODULE(className) to register that class to Zygisk. - -Please note that modules will only be loaded after zygote has forked the child process. -THIS MEANS ALL OF YOUR CODE RUNS IN THE APP/SYSTEM SERVER PROCESS, NOT THE ZYGOTE DAEMON! - -Example code: - -static jint (*orig_logger_entry_max)(JNIEnv *env); -static jint my_logger_entry_max(JNIEnv *env) { return orig_logger_entry_max(env); } - -static void example_handler(int socket) { ... } - -class ExampleModule : public zygisk::ModuleBase { -public: - void onLoad(zygisk::Api *api, JNIEnv *env) override { - this->api = api; - this->env = env; - } - void preAppSpecialize(zygisk::AppSpecializeArgs *args) override { - JNINativeMethod methods[] = { - { "logger_entry_max_payload_native", "()I", (void*) my_logger_entry_max }, - }; - api->hookJniNativeMethods(env, "android/util/Log", methods, 1); - *(void **) &orig_logger_entry_max = methods[0].fnPtr; - } -private: - zygisk::Api *api; - JNIEnv *env; -}; - -REGISTER_ZYGISK_MODULE(ExampleModule) - -REGISTER_ZYGISK_COMPANION(example_handler) - -*/ - -namespace zygisk { - -struct Api; -struct AppSpecializeArgs; -struct ServerSpecializeArgs; - -class ModuleBase { -public: - - // This function is called when the module is loaded into the target process. - // A Zygisk API handle will be sent as an argument; call utility functions or interface - // with Zygisk through this handle. - virtual void onLoad([[maybe_unused]] Api *api, [[maybe_unused]] JNIEnv *env) {} - - // This function is called before the app process is specialized. - // At this point, the process just got forked from zygote, but no app specific specialization - // is applied. This means that the process does not have any sandbox restrictions and - // still runs with the same privilege of zygote. - // - // All the arguments that will be sent and used for app specialization is passed as a single - // AppSpecializeArgs object. You can read and overwrite these arguments to change how the app - // process will be specialized. - // - // If you need to run some operations as superuser, you can call Api::connectCompanion() to - // get a socket to do IPC calls with a root companion process. - // See Api::connectCompanion() for more info. - virtual void preAppSpecialize([[maybe_unused]] AppSpecializeArgs *args) {} - - // This function is called after the app process is specialized. - // At this point, the process has all sandbox restrictions enabled for this application. - // This means that this function runs as the same privilege of the app's own code. - virtual void postAppSpecialize([[maybe_unused]] const AppSpecializeArgs *args) {} - - // This function is called before the system server process is specialized. - // See preAppSpecialize(args) for more info. - virtual void preServerSpecialize([[maybe_unused]] ServerSpecializeArgs *args) {} - - // This function is called after the system server process is specialized. - // At this point, the process runs with the privilege of system_server. - virtual void postServerSpecialize([[maybe_unused]] const ServerSpecializeArgs *args) {} -}; - -struct AppSpecializeArgs { - // Required arguments. These arguments are guaranteed to exist on all Android versions. - jint &uid; - jint &gid; - jintArray &gids; - jint &runtime_flags; - jobjectArray &rlimits; - jint &mount_external; - jstring &se_info; - jstring &nice_name; - jstring &instruction_set; - jstring &app_data_dir; - - // Optional arguments. Please check whether the pointer is null before de-referencing - jintArray *const fds_to_ignore; - jboolean *const is_child_zygote; - jboolean *const is_top_app; - jobjectArray *const pkg_data_info_list; - jobjectArray *const whitelisted_data_info_list; - jboolean *const mount_data_dirs; - jboolean *const mount_storage_dirs; - - AppSpecializeArgs() = delete; -}; - -struct ServerSpecializeArgs { - jint &uid; - jint &gid; - jintArray &gids; - jint &runtime_flags; - jlong &permitted_capabilities; - jlong &effective_capabilities; - - ServerSpecializeArgs() = delete; -}; - -namespace internal { -struct api_table; -template void entry_impl(api_table *, JNIEnv *); -} - -// These values are used in Api::setOption(Option) -enum Option : int { - // Force Magisk's denylist unmount routines to run on this process. - // - // Setting this option only makes sense in preAppSpecialize. - // The actual unmounting happens during app process specialization. - // - // Set this option to force all Magisk and modules' files to be unmounted from the - // mount namespace of the process, regardless of the denylist enforcement status. - FORCE_DENYLIST_UNMOUNT = 0, - - // When this option is set, your module's library will be dlclose-ed after post[XXX]Specialize. - // Be aware that after dlclose-ing your module, all of your code will be unmapped from memory. - // YOU MUST NOT ENABLE THIS OPTION AFTER HOOKING ANY FUNCTIONS IN THE PROCESS. - DLCLOSE_MODULE_LIBRARY = 1, -}; - -// Bit masks of the return value of Api::getFlags() -enum StateFlag : uint32_t { - // The user has granted root access to the current process - PROCESS_GRANTED_ROOT = (1u << 0), - - // The current process was added on the denylist - PROCESS_ON_DENYLIST = (1u << 1), -}; - -// All API functions will stop working after post[XXX]Specialize as Zygisk will be unloaded -// from the specialized process afterwards. -struct Api { - - // Connect to a root companion process and get a Unix domain socket for IPC. - // - // This API only works in the pre[XXX]Specialize functions due to SELinux restrictions. - // - // The pre[XXX]Specialize functions run with the same privilege of zygote. - // If you would like to do some operations with superuser permissions, register a handler - // function that would be called in the root process with REGISTER_ZYGISK_COMPANION(func). - // Another good use case for a companion process is that if you want to share some resources - // across multiple processes, hold the resources in the companion process and pass it over. - // - // The root companion process is ABI aware; that is, when calling this function from a 32-bit - // process, you will be connected to a 32-bit companion process, and vice versa for 64-bit. - // - // Returns a file descriptor to a socket that is connected to the socket passed to your - // module's companion request handler. Returns -1 if the connection attempt failed. - int connectCompanion(); - - // Get the file descriptor of the root folder of the current module. - // - // This API only works in the pre[XXX]Specialize functions. - // Accessing the directory returned is only possible in the pre[XXX]Specialize functions - // or in the root companion process (assuming that you sent the fd over the socket). - // Both restrictions are due to SELinux and UID. - // - // Returns -1 if errors occurred. - int getModuleDir(); - - // Set various options for your module. - // Please note that this function accepts one single option at a time. - // Check zygisk::Option for the full list of options available. - void setOption(Option opt); - - // Get information about the current process. - // Returns bitwise-or'd zygisk::StateFlag values. - uint32_t getFlags(); - - // Hook JNI native methods for a class - // - // Lookup all registered JNI native methods and replace it with your own functions. - // The original function pointer will be saved in each JNINativeMethod's fnPtr. - // If no matching class, method name, or signature is found, that specific JNINativeMethod.fnPtr - // will be set to nullptr. - void hookJniNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int numMethods); - - // For ELFs loaded in memory matching `regex`, replace function `symbol` with `newFunc`. - // If `oldFunc` is not nullptr, the original function pointer will be saved to `oldFunc`. - void pltHookRegister(const char *regex, const char *symbol, void *newFunc, void **oldFunc); - - // For ELFs loaded in memory matching `regex`, exclude hooks registered for `symbol`. - // If `symbol` is nullptr, then all symbols will be excluded. - void pltHookExclude(const char *regex, const char *symbol); - - // Commit all the hooks that was previously registered. - // Returns false if an error occurred. - bool pltHookCommit(); - -private: - internal::api_table *impl; - template friend void internal::entry_impl(internal::api_table *, JNIEnv *); -}; - -// Register a class as a Zygisk module - -#define REGISTER_ZYGISK_MODULE(clazz) \ -void zygisk_module_entry(zygisk::internal::api_table *table, JNIEnv *env) { \ - zygisk::internal::entry_impl(table, env); \ -} - -// Register a root companion request handler function for your module -// -// The function runs in a superuser daemon process and handles a root companion request from -// your module running in a target process. The function has to accept an integer value, -// which is a socket that is connected to the target process. -// See Api::connectCompanion() for more info. -// -// NOTE: the function can run concurrently on multiple threads. -// Be aware of race conditions if you have a globally shared resource. - -#define REGISTER_ZYGISK_COMPANION(func) \ -void zygisk_companion_entry(int client) { func(client); } - -/************************************************************************************ - * All the code after this point is internal code used to interface with Zygisk - * and guarantee ABI stability. You do not have to understand what it is doing. - ************************************************************************************/ - -namespace internal { - -struct module_abi { - long api_version; - ModuleBase *_this; - - void (*preAppSpecialize)(ModuleBase *, AppSpecializeArgs *); - void (*postAppSpecialize)(ModuleBase *, const AppSpecializeArgs *); - void (*preServerSpecialize)(ModuleBase *, ServerSpecializeArgs *); - void (*postServerSpecialize)(ModuleBase *, const ServerSpecializeArgs *); - - module_abi(ModuleBase *module) : api_version(ZYGISK_API_VERSION), _this(module) { - preAppSpecialize = [](auto self, auto args) { self->preAppSpecialize(args); }; - postAppSpecialize = [](auto self, auto args) { self->postAppSpecialize(args); }; - preServerSpecialize = [](auto self, auto args) { self->preServerSpecialize(args); }; - postServerSpecialize = [](auto self, auto args) { self->postServerSpecialize(args); }; - } -}; - -struct api_table { - // These first 2 entries are permanent, shall never change - void *_this; - bool (*registerModule)(api_table *, module_abi *); - - // Utility functions - void (*hookJniNativeMethods)(JNIEnv *, const char *, JNINativeMethod *, int); - void (*pltHookRegister)(const char *, const char *, void *, void **); - void (*pltHookExclude)(const char *, const char *); - bool (*pltHookCommit)(); - - // Zygisk functions - int (*connectCompanion)(void * /* _this */); - void (*setOption)(void * /* _this */, Option); - int (*getModuleDir)(void * /* _this */); - uint32_t (*getFlags)(void * /* _this */); -}; - -template -void entry_impl(api_table *table, JNIEnv *env) { - ModuleBase *module = new T(); - if (!table->registerModule(table, new module_abi(module))) - return; - auto api = new Api(); - api->impl = table; - module->onLoad(api, env); -} - -} // namespace internal - -inline int Api::connectCompanion() { - return impl->connectCompanion ? impl->connectCompanion(impl->_this) : -1; -} -inline int Api::getModuleDir() { - return impl->getModuleDir ? impl->getModuleDir(impl->_this) : -1; -} -inline void Api::setOption(Option opt) { - if (impl->setOption) impl->setOption(impl->_this, opt); -} -inline uint32_t Api::getFlags() { - return impl->getFlags ? impl->getFlags(impl->_this) : 0; -} -inline void Api::hookJniNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int numMethods) { - if (impl->hookJniNativeMethods) impl->hookJniNativeMethods(env, className, methods, numMethods); -} -inline void Api::pltHookRegister(const char *regex, const char *symbol, void *newFunc, void **oldFunc) { - if (impl->pltHookRegister) impl->pltHookRegister(regex, symbol, newFunc, oldFunc); -} -inline void Api::pltHookExclude(const char *regex, const char *symbol) { - if (impl->pltHookExclude) impl->pltHookExclude(regex, symbol); -} -inline bool Api::pltHookCommit() { - return impl->pltHookCommit != nullptr && impl->pltHookCommit(); -} - -} // namespace zygisk - -[[gnu::visibility("default")]] [[gnu::used]] -extern "C" void zygisk_module_entry(zygisk::internal::api_table *, JNIEnv *); - -[[gnu::visibility("default")]] [[gnu::used]] -extern "C" void zygisk_companion_entry(int); diff --git a/zygisk_module/src/main/AndroidManifest.xml b/zygisk_module/src/main/AndroidManifest.xml deleted file mode 100644 index 3d76432..0000000 --- a/zygisk_module/src/main/AndroidManifest.xml +++ /dev/null @@ -1,2 +0,0 @@ - -