diff --git a/README.md b/README.md index b6ca294f72..53311e7d80 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ GameHub Lite is a community-maintained modified version of GameHub for education ## GameHub Lite Patcher -A patching system that transforms GameHub 5.1.0 into GameHub Lite. A privacy-focused, lightweight version with telemetry removed and offline support added. +A patching system that transforms GameHub 5.3.5 into GameHub Lite. A privacy-focused, lightweight version with telemetry removed and offline support added. ## What is GameHub Lite? @@ -55,7 +55,7 @@ stop using windows ### Patching -1. Download GameHub 5.1.0 APK and place it at `apk/GameHub-5.1.0.apk` +1. Download GameHub 5.3.5 APK and place it at `apk/GameHub-5.3.5.apk` 2. Run the patcher: @@ -216,7 +216,7 @@ patches/ If patches fail due to APK version mismatch: -- Ensure you're using GameHub 5.1.0 exactly +- Ensure you're using GameHub 5.3.5 exactly - Check the MD5 hash matches expected value - Try regenerating patches with your APK version @@ -235,8 +235,8 @@ If patches fail due to APK version mismatch: | GameHub Version | Patcher Version | Status | | --------------- | --------------- | -------------- | -| 5.1.0 | 1.0 | Supported | -| 5.3.3 | - | in development | +| 5.1.0 | 1.0 | Deprecated | +| 5.3.5 | 1.0 | Supported | ## Alternative: ReVanced Patches (WORK IN PROGRESS) @@ -245,7 +245,7 @@ This doesn't currently support all features of the Lite APK, but you are free to ```bash cd revanced -./apply-patches.sh ../apk/GameHub-5.1.0.apk +./apply-patches.sh ../apk/GameHub-5.3.5.apk ``` See [revanced/README.md](revanced/README.md) for details. diff --git a/generate-patches.sh b/generate-patches.sh index fd2da95eeb..5b18159d8b 100755 --- a/generate-patches.sh +++ b/generate-patches.sh @@ -18,7 +18,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" DECOMPILED_DIR="$SCRIPT_DIR/decompiled" PATCHES_DIR="$SCRIPT_DIR/patches" -ORIGINAL_APK="${1:-$SCRIPT_DIR/apk/GameHub-5.1.0.apk}" +ORIGINAL_APK="${1:-$SCRIPT_DIR/apk/GameHub-5.3.5.apk}" LITE_APK="${2:-$SCRIPT_DIR/apk/GameHub-Lite.apk}" print_step() { diff --git a/patch.sh b/patch.sh index bcac06b22a..8aff9e13c7 100755 --- a/patch.sh +++ b/patch.sh @@ -1,7 +1,7 @@ #!/bin/bash # # GameHub Lite Patcher -# Applies patches to GameHub 5.1.0 APK to create GameHub Lite +# Applies patches to GameHub 5.3.5 APK to create GameHub Lite # set -e @@ -52,7 +52,7 @@ get_variant_package() { } # Source APK (can be overridden) -SOURCE_APK="${1:-$SCRIPT_DIR/apk/GameHub-5.1.0.apk}" +SOURCE_APK="${1:-$SCRIPT_DIR/apk/GameHub-5.3.5.apk}" OUTPUT_APK="$OUTPUT_DIR/GameHub-Lite.apk" print_step() { @@ -78,7 +78,7 @@ extract_version() { VERSION=$(grep "versionName:" "$WORK_DIR/decompiled/apktool.yml" | head -1 | awk -F': ' '{print $2}' | tr -d "'" | tr -d ' ') fi # Default fallback - VERSION="${VERSION:-5.1.0}" + VERSION="${VERSION:-5.3.5}" print_success "Version: $VERSION" } @@ -171,34 +171,42 @@ verify_source_apk() { if [ ! -f "$SOURCE_APK" ]; then print_error "Source APK not found: $SOURCE_APK" echo "" - echo "Please provide GameHub 5.1.0 APK as first argument or place it at:" - echo " $SCRIPT_DIR/apk/GameHub-5.1.0.apk" + echo "Please provide GameHub 5.3.5 APK as first argument or place it at:" + echo " $SCRIPT_DIR/apk/GameHub-5.3.5.apk" exit 1 fi - # Calculate MD5 of source APK - local md5 - if command -v md5sum &>/dev/null; then - md5=$(md5sum "$SOURCE_APK" | awk '{print $1}') + # Calculate SHA-256 of source APK + local sha256 + local -a sha256_cmd + if command -v sha256sum &>/dev/null; then + sha256_cmd=(sha256sum) + elif command -v shasum &>/dev/null; then + sha256_cmd=(shasum -a 256) else - md5=$(md5 -q "$SOURCE_APK") + print_error "Neither sha256sum nor shasum is available." + exit 1 fi + sha256=$("${sha256_cmd[@]}" "$SOURCE_APK" | awk '{print $1}') - # Expected MD5 for GameHub 5.1.0 - local expected_md5="42db81116bf3c74e52e6f6afb4ec9f91" # Replace with actual MD5 if you are intentionally using a different APK + # Expected SHA-256 for GameHub 5.3.5 (set via env for flexibility) + local expected_sha256="${EXPECTED_SHA256:-}" print_success "Source APK found: $(basename "$SOURCE_APK")" - echo " MD5: $md5" - if [ "$md5" != "$expected_md5" ]; then - print_warning "MD5 checksum does not match expected value." + echo " SHA-256: $sha256" + + if [ -n "$expected_sha256" ] && [ "$sha256" != "$expected_sha256" ]; then + print_warning "SHA-256 checksum does not match expected value." print_warning "Proceeding may lead to unexpected results." - read -pr "Do you want to continue? (y/N): " choice + read -r -p "Do you want to continue? (y/N): " choice if [[ ! "$choice" =~ ^[Yy]$ ]]; then print_error "Aborting." exit 1 fi + elif [ -n "$expected_sha256" ]; then + print_success "SHA-256 checksum verified." else - print_success "MD5 checksum verified." + print_warning "SHA-256 verification skipped; EXPECTED_SHA256 is not set." fi } diff --git a/patches/diffs/apktool.yml.patch b/patches/diffs/apktool.yml.patch index d5ef58bafb..feff447f1f 100644 --- a/patches/diffs/apktool.yml.patch +++ b/patches/diffs/apktool.yml.patch @@ -10,10 +10,8 @@ @@ -10,16 +10,14 @@ forcedPackageId: 127 versionInfo: -- versionCode: 60 -+ versionCode: 61 -- versionName: 5.1.0 -+ versionName: 5.1.4 + versionCode: 60 + versionName: 5.3.5 doNotCompress: - arsc - gif diff --git a/revanced/README.md b/revanced/README.md index d8a95d369b..693c220eaa 100644 --- a/revanced/README.md +++ b/revanced/README.md @@ -47,10 +47,10 @@ This is an **alternative** to the diff-based patching system in the parent direc ```bash # Using the helper script -./apply-patches.sh path/to/GameHub-5.1.0.apk +./apply-patches.sh path/to/GameHub-5.3.5.apk # With custom output -./apply-patches.sh GameHub-5.1.0.apk -o GameHub-Lite.apk +./apply-patches.sh GameHub-5.3.5.apk -o GameHub-Lite.apk # List available patches ./apply-patches.sh -l @@ -66,7 +66,7 @@ This is an **alternative** to the diff-based patching system in the parent direc java -jar tools/revanced-cli.jar patch \ --patch-bundle build/libs/gamehub-lite-patches.jar \ --out GameHub-Lite.apk \ - GameHub-5.1.0.apk + GameHub-5.3.5.apk ``` ### Using ReVanced Manager @@ -137,7 +137,7 @@ revanced/ name = "My Patch", description = "Does something useful", ) { - compatibleWith("com.xiaoji.egggame"("5.1.0")) + compatibleWith("com.xiaoji.egggame"("5.3.5")) execute { myFingerprint.method.addInstructions(0, "return-void") @@ -149,7 +149,7 @@ revanced/ ```bash # Build and apply in one step -./gradlew build && ./apply-patches.sh ../apk/GameHub-5.1.0.apk +./gradlew build && ./apply-patches.sh ../apk/GameHub-5.3.5.apk # Install on device adb install output/GameHub-Lite.apk @@ -201,7 +201,7 @@ gpr.key=ghp_xxxxxxxxxxxx Ensure the fingerprint matches the target method. Use jadx to inspect the APK: ```bash -jadx GameHub-5.1.0.apk -d jadx-output +jadx GameHub-5.3.5.apk -d jadx-output ``` ### APK Won't Install diff --git a/revanced/apply-patches.sh b/revanced/apply-patches.sh index e406d5bd08..117886d68c 100755 --- a/revanced/apply-patches.sh +++ b/revanced/apply-patches.sh @@ -1,7 +1,7 @@ #!/bin/bash # # GameHub Lite - ReVanced Patch Applier -# Applies ReVanced patches to GameHub 5.1.0 APK +# Applies ReVanced patches to GameHub 5.3.5 APK # set -e @@ -44,9 +44,9 @@ show_usage() { echo " -h, --help Show this help message" echo "" echo "Examples:" - echo " $0 GameHub-5.1.0.apk" - echo " $0 GameHub-5.1.0.apk -o my-output.apk" - echo " $0 GameHub-5.1.0.apk -p \"Disable All Telemetry,GameHub Lite\"" + echo " $0 GameHub-5.3.5.apk" + echo " $0 GameHub-5.3.5.apk -o my-output.apk" + echo " $0 GameHub-5.3.5.apk -p \"Disable All Telemetry,GameHub Lite\"" } check_dependencies() { @@ -75,12 +75,12 @@ download_cli() { mkdir -p "$SCRIPT_DIR/tools" # Get latest ReVanced CLI release - local cli_url="https://github.com/ReVanced/revanced-cli/releases/latest/download/revanced-cli-all.jar" + local cli_url="https://github.com/ReVanced/revanced-cli/releases/download/v5.0.1/revanced-cli-5.0.1-all.jar" print_step "Downloading ReVanced CLI..." - curl -L -o "$CLI_JAR" "$cli_url" + curl -fL --retry 3 --connect-timeout 15 -o "$CLI_JAR" "$cli_url" - if [ -f "$CLI_JAR" ]; then + if [ -s "$CLI_JAR" ]; then print_success "ReVanced CLI downloaded" else print_error "Failed to download ReVanced CLI" @@ -94,7 +94,7 @@ build_patches() { cd "$SCRIPT_DIR" if [ -f "gradlew" ]; then - ./gradlew build + ./gradlew build jar else print_error "Gradle wrapper not found. Run 'gradle wrapper' first" exit 1 @@ -112,7 +112,7 @@ list_patches() { print_step "Available patches:" java -jar "$CLI_JAR" list-patches \ - --patch-bundle "$PATCHES_JAR" + -p "$PATCHES_JAR" } apply_patches() { @@ -129,21 +129,19 @@ apply_patches() { print_step "Applying patches to $(basename "$input_apk")..." - local cmd="java -jar $CLI_JAR patch" - cmd="$cmd --patch-bundle $PATCHES_JAR" - cmd="$cmd --out $output_apk" + local cmd=(java -jar "$CLI_JAR" patch -p "$PATCHES_JAR" -o "$output_apk") if [ -n "$patch_list" ]; then # Apply specific patches IFS=',' read -ra PATCHES <<< "$patch_list" for patch in "${PATCHES[@]}"; do - cmd="$cmd --include \"$patch\"" + cmd+=(-e "$patch") done fi - cmd="$cmd $input_apk" + cmd+=("$input_apk") - eval "$cmd" + "${cmd[@]}" if [ -f "$output_apk" ]; then print_success "Patched APK created: $output_apk" diff --git a/revanced/gradle/wrapper/gradle-wrapper.jar b/revanced/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..d997cfc60f Binary files /dev/null and b/revanced/gradle/wrapper/gradle-wrapper.jar differ diff --git a/revanced/gradle/wrapper/gradle-wrapper.properties b/revanced/gradle/wrapper/gradle-wrapper.properties index 1af9e0930b..dbc3ce4a04 100644 --- a/revanced/gradle/wrapper/gradle-wrapper.properties +++ b/revanced/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/revanced/gradlew b/revanced/gradlew new file mode 100755 index 0000000000..0262dcbd52 --- /dev/null +++ b/revanced/gradlew @@ -0,0 +1,248 @@ +#!/bin/sh + +# +# Copyright © 2015 the original 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. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/b631911858264c0b6e4d6603d677ff5218766cee/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# 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 ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + + + +# 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 + if ! command -v java >/dev/null 2>&1 + then + 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 +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# 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"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/revanced/gradlew.bat b/revanced/gradlew.bat new file mode 100644 index 0000000000..8967d00546 --- /dev/null +++ b/revanced/gradlew.bat @@ -0,0 +1,93 @@ +@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 +@rem SPDX-License-Identifier: Apache-2.0 +@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=. +@rem This is normally unused +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% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%\bin\java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 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! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/revanced/patches/api/patches.api b/revanced/patches/api/patches.api new file mode 100644 index 0000000000..47925fdcd2 --- /dev/null +++ b/revanced/patches/api/patches.api @@ -0,0 +1,22 @@ +public final class app/revanced/patches/gamehub/misc/GameHubLitePatchKt { + public static final fun getGameHubLitePatch ()Lapp/revanced/patcher/patch/ResourcePatch; +} + +public final class app/revanced/patches/gamehub/misc/RemoveTrackingResourcesPatchKt { + public static final fun getRemoveTrackingResourcesPatch ()Lapp/revanced/patcher/patch/ResourcePatch; + public static final fun getRemoveTrackingSdksPatch ()Lapp/revanced/patcher/patch/ResourcePatch; +} + +public final class app/revanced/patches/gamehub/shared/ManifestUtils { + public static final field INSTANCE Lapp/revanced/patches/gamehub/shared/ManifestUtils; + public final fun removeManifestTags (Lorg/w3c/dom/Document;Ljava/util/List;Lkotlin/jvm/functions/Function1;)V +} + +public final class app/revanced/patches/gamehub/telemetry/DisableAllTelemetryPatchKt { + public static final fun getDisableAllTelemetryPatch ()Lapp/revanced/patcher/patch/BytecodePatch; +} + +public final class app/revanced/patches/gamehub/telemetry/DisableTelemetryPatchKt { + public static final fun getDisableJPushPatch ()Lapp/revanced/patcher/patch/BytecodePatch; +} + diff --git a/revanced/patches/build.gradle.kts b/revanced/patches/build.gradle.kts index d4ba193999..3158e9b804 100644 --- a/revanced/patches/build.gradle.kts +++ b/revanced/patches/build.gradle.kts @@ -11,3 +11,9 @@ patches { license = "GNU General Public License v3.0" } } + +tasks.withType().configureEach { + kotlinOptions { + freeCompilerArgs += "-Xcontext-receivers" + } +} diff --git a/revanced/patches/src/main/kotlin/app/revanced/patches/gamehub/misc/GameHubLitePatch.kt b/revanced/patches/src/main/kotlin/app/revanced/patches/gamehub/misc/GameHubLitePatch.kt index 1f0fa0276f..0bcc051b5b 100644 --- a/revanced/patches/src/main/kotlin/app/revanced/patches/gamehub/misc/GameHubLitePatch.kt +++ b/revanced/patches/src/main/kotlin/app/revanced/patches/gamehub/misc/GameHubLitePatch.kt @@ -2,9 +2,9 @@ package app.revanced.patches.gamehub.misc import app.revanced.patcher.patch.resourcePatch import app.revanced.patches.gamehub.telemetry.disableAllTelemetryPatch -import app.revanced.util.get -import app.revanced.util.set + import org.w3c.dom.Element +import app.revanced.patches.gamehub.shared.ManifestUtils /** * Main patch that transforms GameHub into GameHub Lite. @@ -20,33 +20,51 @@ val gameHubLitePatch = resourcePatch( name = "GameHub Lite", description = "Transform GameHub into a privacy-focused lightweight version", ) { - compatibleWith("com.xiaoji.egggame"("5.1.0")) + compatibleWith("com.xiaoji.egggame"("5.3.5")) dependsOn( disableAllTelemetryPatch, removeTrackingSdksPatch, ) - execute { context -> + execute { // Change package name in AndroidManifest.xml - context.document["AndroidManifest.xml"].use { document -> + document("AndroidManifest.xml").use { document -> val manifest = document.getElementsByTagName("manifest").item(0) as Element // Change package name manifest.setAttribute("package", "gamehub.lite") + // Strip split APK requirements to allow standalone install + manifest.removeAttribute("android:isSplitRequired") + manifest.removeAttribute("android:requiredSplitTypes") + manifest.removeAttribute("android:splitTypes") + // Update application attributes val application = document.getElementsByTagName("application").item(0) as Element // Add hardware acceleration application.setAttribute("android:hardwareAccelerated", "true") - // Update app name (optional - can be done via string resources) - // application.setAttribute("android:label", "GameHub Lite") + // 1. Remove Play Store splits metadata + ManifestUtils.removeManifestTags(document, listOf("meta-data")) { tag -> + val name = tag.getAttribute("android:name") + name.startsWith("com.android.vending.splits") || name.startsWith("com.android.vending.derived") + } + + // 2. Remove PairIP DRM components + ManifestUtils.removeManifestTags(document, listOf("activity", "service", "provider", "receiver")) { tag -> + tag.getAttribute("android:name").startsWith("com.pairip.") + } + + // 3. Remove Check License permission + ManifestUtils.removeManifestTags(document, listOf("uses-permission")) { tag -> + tag.getAttribute("android:name") == "com.android.vending.CHECK_LICENSE" + } } // Update string resources if needed - context.document["res/values/strings.xml"].use { document -> + document("res/values/strings.xml").use { document -> val strings = document.getElementsByTagName("string") for (i in 0 until strings.length) { val string = strings.item(i) as Element diff --git a/revanced/patches/src/main/kotlin/app/revanced/patches/gamehub/misc/RemoveTrackingResourcesPatch.kt b/revanced/patches/src/main/kotlin/app/revanced/patches/gamehub/misc/RemoveTrackingResourcesPatch.kt index a28dad3e4f..68f276cc68 100644 --- a/revanced/patches/src/main/kotlin/app/revanced/patches/gamehub/misc/RemoveTrackingResourcesPatch.kt +++ b/revanced/patches/src/main/kotlin/app/revanced/patches/gamehub/misc/RemoveTrackingResourcesPatch.kt @@ -1,10 +1,10 @@ package app.revanced.patches.gamehub.misc import app.revanced.patcher.patch.resourcePatch -import app.revanced.util.get -import app.revanced.util.set + import org.w3c.dom.Element import java.io.File +import app.revanced.patches.gamehub.shared.ManifestUtils /** * Resource patch that removes tracking-related permissions and components from AndroidManifest.xml @@ -13,11 +13,11 @@ val removeTrackingResourcesPatch = resourcePatch( name = "Remove Tracking Resources", description = "Removes tracking permissions, services, and receivers from the manifest", ) { - compatibleWith("com.xiaoji.egggame"("5.1.0")) + compatibleWith("com.xiaoji.egggame"("5.3.5")) - execute { context -> + execute { // Modify AndroidManifest.xml to remove tracking permissions - context.document["AndroidManifest.xml"].use { document -> + document("AndroidManifest.xml").use { document -> val manifest = document.getElementsByTagName("manifest").item(0) as Element // Permissions to remove @@ -34,52 +34,19 @@ val removeTrackingResourcesPatch = resourcePatch( ) // Remove unwanted permissions - val usesPermissions = document.getElementsByTagName("uses-permission") - val toRemove = mutableListOf() - - for (i in 0 until usesPermissions.length) { - val permission = usesPermissions.item(i) as Element - val permName = permission.getAttribute("android:name") - if (permissionsToRemove.contains(permName)) { - toRemove.add(permission) - } + ManifestUtils.removeManifestTags(document, listOf("uses-permission")) { tag -> + permissionsToRemove.contains(tag.getAttribute("android:name")) } - toRemove.forEach { it.parentNode.removeChild(it) } - // Remove JPush and Firebase components - val application = document.getElementsByTagName("application").item(0) as Element - val componentsToRemove = mutableListOf() - - // Find services/receivers related to tracking - val services = application.getElementsByTagName("service") - for (i in 0 until services.length) { - val service = services.item(i) as Element - val name = service.getAttribute("android:name") - if (name.contains("jpush") || - name.contains("jiguang") || - name.contains("firebase") || - name.contains("umeng") || - name.contains("analytics") - ) { - componentsToRemove.add(service) - } + ManifestUtils.removeManifestTags(document, listOf("service", "receiver")) { tag -> + val name = tag.getAttribute("android:name") + name.contains("jpush") || + name.contains("jiguang") || + name.contains("firebase") || + name.contains("umeng") || + (tag.tagName == "service" && name.contains("analytics")) } - - val receivers = application.getElementsByTagName("receiver") - for (i in 0 until receivers.length) { - val receiver = receivers.item(i) as Element - val name = receiver.getAttribute("android:name") - if (name.contains("jpush") || - name.contains("jiguang") || - name.contains("firebase") || - name.contains("umeng") - ) { - componentsToRemove.add(receiver) - } - } - - componentsToRemove.forEach { it.parentNode.removeChild(it) } } } } @@ -90,23 +57,14 @@ val removeTrackingResourcesPatch = resourcePatch( */ val removeTrackingSdksPatch = resourcePatch( name = "Remove Tracking SDKs", - description = "Removes entire tracking SDK packages from the APK", + description = "Removes tracking-related assets and native libraries from the APK", ) { - compatibleWith("com.xiaoji.egggame"("5.1.0")) + compatibleWith("com.xiaoji.egggame"("5.3.5")) dependsOn(removeTrackingResourcesPatch) - execute { context -> - // Packages to remove (these will be handled by bytecode removal) - val packagesToRemove = listOf( - "com/umeng/", - "cn/jiguang/", - "cn/jpush/", - "com/tencent/connect/", - "com/tencent/mm/", - "com/tencent/open/", - "com/tencent/tauth/", - ) + execute { + // DEX class removal must be done via a bytecode patch instead. // Remove unused assets val assetsToRemove = listOf( @@ -118,9 +76,9 @@ val removeTrackingSdksPatch = resourcePatch( ) assetsToRemove.forEach { asset -> - val assetFile = context["assets/$asset"] - if (assetFile.exists()) { - assetFile.delete() + val assetFile = get("assets/$asset") + if (assetFile.exists() && !assetFile.delete()) { + error("Failed to delete asset: ${assetFile.path}") } } @@ -137,9 +95,9 @@ val removeTrackingSdksPatch = resourcePatch( val libDirs = listOf("lib/arm64-v8a", "lib/armeabi-v7a", "lib/x86", "lib/x86_64") libDirs.forEach { libDir -> nativeLibsToRemove.forEach { lib -> - val libFile = context["$libDir/$lib"] - if (libFile.exists()) { - libFile.delete() + val libFile = get("$libDir/$lib") + if (libFile.exists() && !libFile.delete()) { + error("Failed to delete native library: ${libFile.path}") } } } diff --git a/revanced/patches/src/main/kotlin/app/revanced/patches/gamehub/shared/Fingerprints.kt b/revanced/patches/src/main/kotlin/app/revanced/patches/gamehub/shared/Fingerprints.kt index fec99cb9ec..94118a1cbe 100644 --- a/revanced/patches/src/main/kotlin/app/revanced/patches/gamehub/shared/Fingerprints.kt +++ b/revanced/patches/src/main/kotlin/app/revanced/patches/gamehub/shared/Fingerprints.kt @@ -7,7 +7,6 @@ import app.revanced.patcher.fingerprint * This is the main entry point where analytics services are initialized */ internal val appOnCreateFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC) returns("V") parameters() custom { method, classDef -> @@ -19,7 +18,6 @@ internal val appOnCreateFingerprint = fingerprint { * Fingerprint for PushApp.b(Application) - JPush initialization */ internal val pushAppInitFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("Landroid/app/Application;") custom { method, classDef -> @@ -31,7 +29,6 @@ internal val pushAppInitFingerprint = fingerprint { * Fingerprint for JPushInterface.init() call */ internal val jpushInitFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("V") parameters("Landroid/content/Context;", "Lcn/jpush/android/data/JPushConfig;") custom { method, classDef -> @@ -43,7 +40,6 @@ internal val jpushInitFingerprint = fingerprint { * Fingerprint for IUmengService.a(Context) - Umeng initialization */ internal val umengServiceInitFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.ABSTRACT) returns("V") parameters("Landroid/content/Context;") custom { method, classDef -> @@ -55,7 +51,6 @@ internal val umengServiceInitFingerprint = fingerprint { * Fingerprint for FirebaseAuthLoginUtils.Companion.a(Context) */ internal val firebaseAuthInitFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("Landroid/content/Context;") custom { method, classDef -> @@ -68,7 +63,6 @@ internal val firebaseAuthInitFingerprint = fingerprint { * Fingerprint for CommonApp.Companion.i() initialization */ internal val commonAppInitFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("Z", "Ljava/lang/String;", "Ljava/lang/String;") custom { method, classDef -> diff --git a/revanced/patches/src/main/kotlin/app/revanced/patches/gamehub/shared/ManifestUtils.kt b/revanced/patches/src/main/kotlin/app/revanced/patches/gamehub/shared/ManifestUtils.kt new file mode 100644 index 0000000000..1398869360 --- /dev/null +++ b/revanced/patches/src/main/kotlin/app/revanced/patches/gamehub/shared/ManifestUtils.kt @@ -0,0 +1,39 @@ +package app.revanced.patches.gamehub.shared + +import org.w3c.dom.Document +import org.w3c.dom.Element + +/** + * Shared utility methods for safely mutating the AndroidManifest.xml Document. + */ +object ManifestUtils { + /** + * Safely collects and removes matching elements from a DOM Document to avoid concurrent + * modification exceptions while iterating over live NodeLists. + * + * @param document The DOM Document to modify + * @param tagNames List of element tag names to search for (e.g. "meta-data", "service") + * @param predicate Lambda condition that returns true if the element should be removed + */ + fun removeManifestTags( + document: Document, + tagNames: List, + predicate: (Element) -> Boolean + ) { + val tagsToRemove = mutableListOf() + + for (tagName in tagNames) { + val elements = document.getElementsByTagName(tagName) + for (i in 0 until elements.length) { + val element = elements.item(i) as Element + if (predicate(element)) { + tagsToRemove.add(element) + } + } + } + + for (tag in tagsToRemove) { + tag.parentNode.removeChild(tag) + } + } +} diff --git a/revanced/patches/src/main/kotlin/app/revanced/patches/gamehub/telemetry/DisableAllTelemetryPatch.kt b/revanced/patches/src/main/kotlin/app/revanced/patches/gamehub/telemetry/DisableAllTelemetryPatch.kt index cf8438a6fe..cc570a1c06 100644 --- a/revanced/patches/src/main/kotlin/app/revanced/patches/gamehub/telemetry/DisableAllTelemetryPatch.kt +++ b/revanced/patches/src/main/kotlin/app/revanced/patches/gamehub/telemetry/DisableAllTelemetryPatch.kt @@ -21,7 +21,7 @@ val disableAllTelemetryPatch = bytecodePatch( name = "Disable All Telemetry", description = "Removes all tracking, analytics, and telemetry services from GameHub", ) { - compatibleWith("com.xiaoji.egggame"("5.1.0")) + compatibleWith("com.xiaoji.egggame"("5.3.5")) dependsOn(disableJPushPatch) @@ -31,34 +31,7 @@ val disableAllTelemetryPatch = bytecodePatch( // 1. IUmengService.a(context) - Umeng init // 2. FirebaseAuthLoginUtils.Companion.a(context) - Firebase init - appOnCreateFingerprint.method.apply { - val instructions = implementation!!.instructions - // Find and patch Umeng service call - // Pattern: invoke-interface {v0, p0}, Lcom/xj/common/service/IUmengService;->a(Landroid/content/Context;)V - for (i in instructions.indices) { - val instruction = instructions[i] - if (instruction.opcode.name.startsWith("invoke")) { - val invokeInstruction = getInstruction(i) - val reference = invokeInstruction.reference.toString() - - // Skip Umeng initialization - if (reference.contains("IUmengService;->a(Landroid/content/Context;)V")) { - // Replace with nop by removing the instruction - // Note: We can't just remove as it would break indices - // Instead we'll make the null check always fail - // The pattern is: if-eqz v0, :cond_2 (skip if null) - // We want to always skip, so we don't need to modify anything - // as the service lookup returns null when the SDK is removed - } - - // Skip Firebase initialization - if (reference.contains("FirebaseAuthLoginUtils\$Companion;->a(Landroid/content/Context;)V")) { - // Similar approach - Firebase init will fail gracefully when SDK is removed - } - } - } - } // Patch FirebaseAuthLoginUtils.Companion.a() to return immediately firebaseAuthInitFingerprint.method.addInstructions( diff --git a/revanced/patches/src/main/kotlin/app/revanced/patches/gamehub/telemetry/DisableTelemetryPatch.kt b/revanced/patches/src/main/kotlin/app/revanced/patches/gamehub/telemetry/DisableTelemetryPatch.kt index df3495bf08..044b743a05 100644 --- a/revanced/patches/src/main/kotlin/app/revanced/patches/gamehub/telemetry/DisableTelemetryPatch.kt +++ b/revanced/patches/src/main/kotlin/app/revanced/patches/gamehub/telemetry/DisableTelemetryPatch.kt @@ -14,7 +14,7 @@ val disableJPushPatch = bytecodePatch( name = "Disable JPush", description = "Disables JPush push notification service and its tracking", ) { - compatibleWith("com.xiaoji.egggame"("5.1.0")) + compatibleWith("com.xiaoji.egggame"("5.3.5")) execute { // Method 1: Make JPushInterface.init() return immediately