Repository: cuynu/gphotos-unlimited-zygisk
Branch: master
Commit: f717ec1f123a
Files: 31
Total size: 50.7 KB
Directory structure:
gitextract_tqli54zh/
├── LICENSE
├── META-INF/
│ └── com/
│ └── google/
│ └── android/
│ ├── update-binary
│ └── updater-script
├── README.md
├── customize.sh
├── module.prop
├── system/
│ ├── etc/
│ │ └── sysconfig/
│ │ ├── pixel_2017_exclusive.xml
│ │ ├── pixel_2018_exclusive.xml
│ │ └── pixel_2019_exclusive.xml
│ └── product/
│ └── etc/
│ └── sysconfig/
│ ├── pixel_2016_exclusive.xml
│ ├── pixel_2017_exclusive.xml
│ ├── pixel_2018_exclusive.xml
│ ├── pixel_2019_exclusive.xml
│ ├── pixel_experience_2017.xml
│ ├── pixel_experience_2018.xml
│ ├── pixel_experience_2019.xml
│ ├── pixel_experience_2019_midyear.xml
│ ├── pixel_experience_2020.xml
│ ├── pixel_experience_2020_midyear.xml
│ ├── pixel_experience_2021.xml
│ ├── pixel_experience_2021_midyear.xml
│ ├── pixel_experience_2022.xml
│ ├── pixel_experience_2022_midyear.xml
│ └── pixelify_experience.xml
└── zygisk_build/
├── build.gradle
└── src/
└── main/
├── AndroidManifest.xml
└── cpp/
├── CMakeLists.txt
├── module.h
├── pixelify.cpp
├── tensor.cpp
└── zygisk.hpp
================================================
FILE CONTENTS
================================================
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2025 Cuynu
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: META-INF/com/google/android/update-binary
================================================
#!/sbin/sh
#################
# Initialization
#################
umask 022
# echo before loading util_functions
ui_print() { echo "$1"; }
require_new_magisk() {
ui_print "*******************************"
ui_print " Please install Magisk v20.4+! "
ui_print "*******************************"
exit 1
}
#########################
# Load util_functions.sh
#########################
OUTFD=$2
ZIPFILE=$3
mount /data 2>/dev/null
[ -f /data/adb/magisk/util_functions.sh ] || require_new_magisk
. /data/adb/magisk/util_functions.sh
[ $MAGISK_VER_CODE -lt 20400 ] && require_new_magisk
install_module
exit 0
================================================
FILE: META-INF/com/google/android/updater-script
================================================
#MAGISK
================================================
FILE: README.md
================================================
# Google Photos unlimited backup module
Adds Photos features and unlimited original backup
Current version : **1.1-stable** [Download from releases](https://git.disroot.org/cuynu/gphotos-unlimited-zygisk/releases)
### [Chuyển ngôn ngữ Tiếng Việt](https://git.disroot.org/cuynu/gphotos-unlimited-zygisk/wiki/VI)
# Introduction
Based from Pixelify GitHub. This module will spoof your device info to Pixel XL on Google apps and Google Photos to get unlimited backup storage at original quality !
# Warning !
Module will only works with Zygisk, it will not works with Riru, Shamiko, etc !!
Some modules could break and prevent this module from running, if module does not work, try disable some modules and see.
# Usage
Download module from [release page](https://git.disroot.org/cuynu/gphotos-unlimited-zygisk/releases), enable Zygisk then install with Magisk v24.3+ and reboot.
For KernelSU/KernelSU-Next/RKSU/APatch users, **DON'T use ZygiskNext 1.0.0+** !. Instead, use [ReZygisk](https://github.com/PerformanC/ReZygisk/releases).
- Tested with : `Magisk v25.2+` `Magisk Delta/Kitsune` `KernelSU` `KernelSU-Next `APatch`
# Known issues
- **Some Xiaomi devices with MIUI 14 when this module is active, its will cause Bootloop with SystemUI crash exception**
- When use with `Magisk-GApps` module, it will conflict and cause lose the ability to backup unlimited at original quality (Still able to backup unlimited at storage saver quality)
# Tested devices
- Sony Xperia XZ2 (Stock Android 10, LineageOS 18.1,19.1,20.0,21.0,22.2)
- Redmi Note 7 (MIUI 12.5 CN, Nusantara EOL A10)
- Google Pixel 2 (Android 11 stock)
- Masstel_X9 (Stock Android 9, LineageOS 18.1/19.1)
- LG G7 ThinQ (Stock Android 10, LineageOS 21.0/22.2)
- Vsmart Joy 2+ (LineageOS 20.0)
# ToDo
- Rewrite hook library in C++ and take it away from Pixelify (as long as i learn C++ :>)
# Build zygisk binary
`git clone https://git.disroot.org/cuynu/gphotos-unlimited-zygisk.git`
Import folder zygisk_build to Android Studio or Gradle and build then copy compiled zygisk library to zygisk folder (not zygisk_build)
================================================
FILE: customize.sh
================================================
for i in /system/product/etc/sysconfig/*; do
file=$i
file=${file/\/system\/product\/etc\/sysconfig\//}
if [ ! -z "$(grep PIXEL_2020_ $i)" ] || [ ! -z "$(grep PIXEL_2021_ $i)" ] || [ ! -z "$(grep PIXEL_2019_PRELOAD $i)" ] || [ ! -z "$(grep PIXEL_2018_PRELOAD $i)" ] || [ ! -z "$(grep PIXEL_2017_PRELOAD $i)" ] || [ ! -z "$(grep PIXEL_2022_ $i)" ]; then
[ ! -f $MODPATH/system/product/etc/sysconfig/$file ] && cat /system/product/etc/sysconfig/$file | grep -v PIXEL_2020_ | grep -v PIXEL_2021_ | grep -v PIXEL_2022_ | grep -v PIXEL_2018_PRELOAD | grep -v PIXEL_2019_PRELOAD >$MODPATH/system/product/etc/sysconfig/$file
fi
done
for i in /system/etc/sysconfig/*; do
file=$i
file=${file/\/system\/etc\/sysconfig\//}
if [ ! -z "$(grep PIXEL_2020_ $i)" ] || [ ! -z "$(grep PIXEL_2021_ $i)" ] || [ ! -z "$(grep PIXEL_2019_PRELOAD $i)" ] || [ ! -z "$(grep PIXEL_2018_PRELOAD $i)" ] || [ ! -z "$(grep PIXEL_2017_PRELOAD $i)" ] || [ ! -z "$(grep PIXEL_2022_ $i)" ]; then
[ ! -f $MODPATH/system/product/etc/sysconfig/$file ] && cat /system/etc/sysconfig/$file | grep -v PIXEL_2020_ | grep -v PIXEL_2021_ | grep -v PIXEL_2022_ | grep -v PIXEL_2018_PRELOAD | grep -v PIXEL_2019_PRELOAD | grep -v PIXEL_2017_PRELOAD >$MODPATH/system/etc/sysconfig/$file
fi
done
if [ -d /data/adb/modules/PixelifyPhotos/system/product/etc/sysconfig ]; then
for i in /data/adb/modules/PixelifyPhotos/system/product/etc/sysconfig/*; do
file=$i
file=${file/\/data\/adb\/modules\/PixelifyPhotos\/system\/product\/etc\/sysconfig\//}
if [ ! -f $MODPATH/system/product/etc/sysconfig/$file ]; then
cp -f /data/adb/modules/PixelifyPhotos/system/product/etc/sysconfig/$file $MODPATH/system/product/etc/sysconfig/$file
fi
done
fi
if [ -d /data/adb/modules/PixelifyPhotos/system/etc/sysconfig ]; then
for i in /data/adb/modules/PixelifyPhotos/system/etc/sysconfig/*; do
file=$i
file=${file/\/data\/adb\/modules\/PixelifyPhotos\/system\/etc\/sysconfig\//}
if [ ! -f $MODPATH/system/etc/sysconfig/$file ]; then
cp -f /data/adb/modules/PixelifyPhotos/system/etc/sysconfig/$file $MODPATH/system/etc/sysconfig/$file
fi
done
fi
================================================
FILE: module.prop
================================================
id=PixelifyPhotos
name=Google Photos Unlimited backup
version=1.1-stable
versionCode=002
author=cuynu
description=Adds Photos features and unlimited Google Photos original backup quality by spoof device info to Pixel XL only on Photos app.
================================================
FILE: system/etc/sysconfig/pixel_2017_exclusive.xml
================================================
================================================
FILE: system/etc/sysconfig/pixel_2018_exclusive.xml
================================================
================================================
FILE: system/etc/sysconfig/pixel_2019_exclusive.xml
================================================
================================================
FILE: system/product/etc/sysconfig/pixel_2016_exclusive.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<!-- These are configurations that should exist on Google's 2016 Pixel devices. -->
<config>
<!-- Both versions of this string are needed due to a miscommunication. b/29978934 -->
<feature name="com.google.android.apps.photos.NEXUS_PRELOAD" />
<feature name="com.google.android.apps.photos.nexus_preload" />
</config>
================================================
FILE: system/product/etc/sysconfig/pixel_2017_exclusive.xml
================================================
================================================
FILE: system/product/etc/sysconfig/pixel_2018_exclusive.xml
================================================
================================================
FILE: system/product/etc/sysconfig/pixel_2019_exclusive.xml
================================================
================================================
FILE: system/product/etc/sysconfig/pixel_experience_2017.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<!-- These are configurations that should exist on Google's 2017 and newer Nexus devices. -->
<config>
<!-- This is meant to be the canonical feature identifying 2017 and newer Nexus devices. -->
<feature name="com.google.android.feature.PIXEL_2017_EXPERIENCE" />
<!--
This is the canonical feature identifying devices which bundle Google Fi support. The
Fi app and associated apps will be bundled (but may be disabled until a matching SIM
is inserted).
This feature may not be present before Android S.
-->
<feature name="com.google.android.feature.GOOGLE_FI_BUNDLED" />
<!-- Allow SCONE JobIntentService & Services to run in background -->
<allow-in-power-save package="com.google.android.apps.scone" />
<!-- Allow Flipendo in power save. Will be present on pre-2020 devices for dogfooding. -->
<allow-in-power-save-except-idle package="com.google.android.flipendo" />
<!-- Allow Better Bug to take bug report. -->
<bugreport-whitelisted package="com.google.android.apps.betterbug" />
<bugreport-whitelisted package="com.google.android.apps.internal.betterbug" />
<bugreport-whitelisted package="com.google.android.apps.betterbug.partners" />
<!-- Allow Pixel modem service to run in background -->
<allow-in-power-save package="com.google.modemservice" />
<!-- Allow MDS ExperimentService to run in background -->
<allow-in-power-save package="com.google.mds" />
<!-- Allow Exo services to run in background -->
<allow-in-power-save package="com.google.pixel.exo" />
<allow-in-power-save package="com.google.ambient.streaming" />
<!-- Allow OMA DM to run in background -->
<allow-in-power-save package="com.android.omadm.service" />
<allow-in-power-save package="com.android.sdm.plugins.connmo" />
<allow-in-power-save package="com.android.sdm.plugins.dcmo" />
<allow-in-power-save package="com.android.sdm.plugins.diagmon" />
<allow-in-power-save package="com.android.vzwomatrigger" />
<allow-in-power-save package="com.android.sdm.plugins.usccdm" />
<!-- Allow Gate runners to run in background -->
<allow-in-power-save package="com.google.pixel.gate.android.pysupport" />
<allow-in-power-save package="com.google.pixel.gate.android.daemon" />
<!-- Hide DocumentsUi Launcher/Downloads intent handling. DocumentsUi
PrebootReceiver does not properly hide the launcher in work profile,
so we need to include this as well. -->
<component-override package="com.google.android.documentsui" >
<component class="com.android.documentsui.LauncherActivity" enabled="false" />
<component class="com.android.documentsui.ViewDownloadsActivity" enabled="false" />
</component-override>
<!-- ACTION_MANAGE_STORAGE handled by Files by Google -->
<component-override package="com.google.android.storagemanager" >
<component class="com.android.storagemanager.deletionhelper.DeletionHelperActivity" enabled="false" />
</component-override>
<!-- Make sure photos/video previews are handled by Photos. -->
<component-override package="com.google.android.apps.nbu.files" >
<component class="com.google.android.apps.nbu.files.gateway.preview.PreviewActivity" enabled="false" />
</component-override>
<component-override package="com.android.settings" >
<!-- Display regulatory info in settings. -->
<component class=".RegulatoryInfoDisplayActivity" enabled="true" />
</component-override>
<!-- Feature flag on RVC builds for AER requirements, b/159247801 -->
<feature name="com.google.android.feature.AER_OPTIMIZED" />
</config>
================================================
FILE: system/product/etc/sysconfig/pixel_experience_2018.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<!-- These are configurations that should exist on Google's 2018 and newer Pixel devices. -->
<config>
<!-- Allow Pixel modem service in background -->
<allow-in-power-save package="com.google.modemservice" />
<!-- Allow PixelLogger LoggingService to run in background -->
<allow-in-power-save package="com.android.pixellogger" />
<!-- Allow Pixel Logger to take bug report. -->
<bugreport-whitelisted package="com.android.pixellogger" />
<!-- Allow Flipendo in power save. Will be present on pre-2020 devices for dogfooding. -->
<allow-in-power-save-except-idle package="com.google.android.flipendo" />
<!-- The AI services open-source network component can bind to the odad package. -->
<allow-association target="com.google.android.as.oss" allowed="com.google.android.odad" />
<!-- The odad package can only bind to the AI services open-source network component. -->
<allow-association target="com.google.android.odad" allowed="com.google.android.as.oss" />
<!-- This is meant to be the canonical feature identifying 2018 and newer Pixel devices. -->
<feature name="com.google.android.feature.PIXEL_2018_EXPERIENCE" />
</config>
================================================
FILE: system/product/etc/sysconfig/pixel_experience_2019.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<!-- These are configurations that should exist on Google's 2019 and newer devices. -->
<config>
<!-- This is meant to be the canonical feature identifying 2019 and newer devices. -->
<feature name="com.google.android.feature.PIXEL_2019_EXPERIENCE" />
<!-- Allow Flipendo in power save. Will be present on pre-2020 devices for dogfooding. -->
<allow-in-power-save-except-idle package="com.google.android.flipendo" />
</config>
================================================
FILE: system/product/etc/sysconfig/pixel_experience_2019_midyear.xml
================================================
================================================
FILE: system/product/etc/sysconfig/pixel_experience_2020.xml
================================================
================================================
FILE: system/product/etc/sysconfig/pixel_experience_2020_midyear.xml
================================================
================================================
FILE: system/product/etc/sysconfig/pixel_experience_2021.xml
================================================
================================================
FILE: system/product/etc/sysconfig/pixel_experience_2021_midyear.xml
================================================
================================================
FILE: system/product/etc/sysconfig/pixel_experience_2022.xml
================================================
================================================
FILE: system/product/etc/sysconfig/pixel_experience_2022_midyear.xml
================================================
================================================
FILE: system/product/etc/sysconfig/pixelify_experience.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<!-- These are configurations that should exist on Pixelify devices. -->
<config>
<!-- This is meant to be the canonical feature identifying 2016 and newer Nexus devices. -->
<feature name="com.google.android.feature.PIXEL_EXPERIENCE" />
<!-- google KidsHome feature -->
<!-- <feature name="com.google.android.feature.KIDS_HOME_EXPERIENCE" /> -->
<!-- Starting from Android R and above, the device with the system feature included would get Dialer call recording. -->
<feature name="com.google.android.apps.dialer.call_recording_audio" />
<!-- <feature name="com.google.android.feature.PREMIER_TIER" /> -->
<system-user-whitelisted-app package="com.google.android.tts" />
<!-- TODO: This is a temporary workaround for allowing GmsCore to receive this broadcast.
This can be removed once OneTimeInitializer functionality is moved to GmsCore. -->
<!-- <allow-implicit-broadcast action="com.google.android.onetimeinitializer.ONE_TIME_INITIALIZED" /> -->
<!-- <feature name="com.google.android.feature.EEA_DEVICE" /> -->
<!-- <feature name="com.google.android.feature.EEA_V2_DEVICE" /> -->
<!-- <feature name="com.google.android.paid.search" /> -->
<!-- <feature name="com.google.android.paid.chrome" /> -->
<!-- <feature name="com.google.android.feature.ASI_PIXEL6" /> -->
</config>
================================================
FILE: zygisk_build/build.gradle
================================================
import org.apache.tools.ant.filters.FixCrLfFilter
import org.apache.tools.ant.filters.ReplaceTokens
import java.security.MessageDigest
plugins {
id 'com.android.library'
}
apply from: file(rootProject.file('module.gradle'))
android {
compileSdk target_sdk
defaultConfig {
minSdk min_sdk
targetSdk target_sdk
externalNativeBuild {
// ndkBuild {
// path("src/main/cpp/external/Android.mk")
// }
cmake {
arguments "-DMODULE_NAME:STRING=$moduleLibraryName";
}
}
}
buildFeatures {
prefab false
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
}
}
}
afterEvaluate {
android.libraryVariants.forEach { variant ->
def variantCapped = variant.name.capitalize()
def variantLowered = variant.name.toLowerCase()
def zipName = "${magiskModuleId.replace('_', '-')}-${moduleVersion}.zip"
def zipNamenovk = "${magiskModuleId.replace('_', '-')}-${moduleVersion}-no-VK.zip"
def magiskDir = file("$outDir/magisk_module_$variantLowered")
def templatePath = "$rootDir/module"
def types = [Instance1: 'arm64-v8a', Instance2: 'armeabi-v7a',Instance3: 'x86',Instance4: 'x86_64']
task("prepareMagiskFiles${variantCapped}", type: Sync) {
dependsOn("assemble$variantCapped")
def nativeOutDir = file("$rootDir/riru/build/intermediates/cmake/$variant.name/obj")
into magiskDir
from(templatePath) {
exclude 'module.prop', 'files/system'
}
from(templatePath) {
include 'module.prop'
expand([
id : magiskModuleId,
name : moduleName,
version : moduleVersion,
versionCode: moduleVersionCode.toString(),
author : moduleAuthor,
description: moduleDescription,
volType: "1",
])
filter(FixCrLfFilter.class,
eol: FixCrLfFilter.CrLf.newInstance("lf"))
}
types.each { instance, resourceDir ->
from("$buildDir/intermediates/stripped_native_libs/$variantLowered/out/lib/$resourceDir") {
into 'lib/zygisk'
exclude "**/libpixelify-tensor.so"
rename 'libpixelify.so', "${resourceDir}.so"
}
from("$buildDir/intermediates/stripped_native_libs/$variantLowered/out/lib/$resourceDir") {
into 'lib/zygisk_tensor'
exclude "**/libpixelify.so"
rename 'libpixelify-tensor.so', "${resourceDir}.so"
}
}
doLast {
copy {
from "$nativeOutDir"
into "$magiskDir/lib/riru"
exclude "**/*.txt" , "**/libpixelify-tensor.so"
}
copy {
from "$nativeOutDir"
into "$magiskDir/lib/riru_tensor"
exclude "**/*.txt" , "**/libpixelify.so"
rename "libpixelify-tensor.so" , "$variant.name"
}
}
}
task("novk${variantCapped}", type: Sync) {
dependsOn("assemble$variantCapped")
def nativeOutDir = file("$rootDir/riru/build/intermediates/cmake/$variant.name/obj")
into magiskDir
from(templatePath) {
exclude 'module.prop', 'files/system'
}
from(templatePath) {
include 'module.prop'
expand([
id : magiskModuleId,
name : moduleName,
version : moduleVersion,
versionCode: moduleVersionCode.toString(),
author : moduleAuthor,
description: moduleDescription,
volType: "0",
])
filter(FixCrLfFilter.class,
eol: FixCrLfFilter.CrLf.newInstance("lf"))
}
types.each { instance, resourceDir ->
from("$buildDir/intermediates/stripped_native_libs/$variantLowered/out/lib/$resourceDir") {
into 'lib/zygisk'
exclude "**/libpixelify-tensor.so"
rename 'libpixelify.so', "${resourceDir}.so"
}
from("$buildDir/intermediates/stripped_native_libs/$variantLowered/out/lib/$resourceDir") {
into 'lib/zygisk_tensor'
exclude "**/libpixelify.so"
rename 'libpixelify-tensor.so', "${resourceDir}.so"
}
}
doLast {
copy {
from "$nativeOutDir"
into "$magiskDir/lib/riru"
exclude "**/*.txt" , "**/libpixelify-tensor.so"
}
copy {
from "$nativeOutDir"
into "$magiskDir/lib/riru_tensor"
exclude "**/*.txt" , "**/libpixelify.so"
rename "libpixelify-tensor.so" , "libpixelify.so"
}
}
}
task("zip${variantCapped}", type: Zip) {
dependsOn("prepareMagiskFiles${variantCapped}")
from magiskDir
archiveName zipName
destinationDir outDir
}
task("novkzip${variantCapped}", type: Zip) {
dependsOn("zip${variantCapped}")
dependsOn("novk${variantCapped}")
tasks.findByName("novk${variantCapped}").mustRunAfter "zip${variantCapped}"
from magiskDir
archiveName zipNamenovk
destinationDir outDir
doLast {
delete {
from "$outDir"
include "config.prop"
}
copy {
from "$templatePath"
into "$outDir"
include "config.prop"
}
}
}
task("push${variantCapped}", type: Exec) {
dependsOn("zip${variantCapped}")
workingDir outDir
commandLine android.adbExecutable, "push", zipName, "/data/local/tmp/"
}
task("flash${variantCapped}", type: Exec) {
dependsOn("push${variantCapped}")
commandLine android.adbExecutable, "shell", "su", "-c",
"magisk --install-module /data/local/tmp/${zipName}"
}
task("flashAndReboot${variantCapped}", type: Exec) {
dependsOn("flash${variantCapped}")
commandLine android.adbExecutable, "shell", "reboot"
}
variant.assembleProvider.get().finalizedBy("novkzip${variantCapped}")
}
}
================================================
FILE: zygisk_build/src/main/AndroidManifest.xml
================================================
<manifest package="zygisk.template" />
================================================
FILE: zygisk_build/src/main/cpp/CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.4.1)
if (NOT DEFINED MODULE_NAME)
message(FATAL_ERROR "MODULE_NAME is not set")
else ()
project(${MODULE_NAME})
endif ()
message("Build type: ${CMAKE_BUILD_TYPE}")
set(CMAKE_CXX_STANDARD 17)
set(LINKER_FLAGS "-ffixed-x18 -Wl,--hash-style=both")
set(C_FLAGS "-Werror=format -fdata-sections -ffunction-sections")
set(CXX_FLAGS "${CXX_FLAGS} -fno-exceptions -fno-rtti")
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
set(C_FLAGS "${C_FLAGS} -O2 -fvisibility=hidden -fvisibility-inlines-hidden")
set(LINKER_FLAGS "${LINKER_FLAGS} -Wl,-exclude-libs,ALL -Wl,--gc-sections -Wl,--strip-all")
else ()
set(C_FLAGS "${C_FLAGS} -O0")
endif ()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${C_FLAGS} ${CXX_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
# find_package(REQUIRED CONFIG)
add_library(${MODULE_NAME} SHARED
pixelify.cpp
module.h)
target_link_libraries(${MODULE_NAME} log)
add_library(${MODULE_NAME}-tensor SHARED
tensor.cpp
module.h)
target_link_libraries(${MODULE_NAME}-tensor log)
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
add_custom_command(TARGET ${MODULE_NAME} POST_BUILD
COMMAND ${CMAKE_STRIP} --strip-all --remove-section=.comment "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/lib${MODULE_NAME}.so")
endif ()
================================================
FILE: zygisk_build/src/main/cpp/module.h
================================================
#include "errno.h"
#include "android/log.h"
#pragma once
namespace pixelifytag {
#ifndef TAG
#define TAG "Pixelify"
#endif
#ifdef NDEBUG
#define LOGD(...)
#else
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#endif
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
#define LOGERRNO(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__ ": %d (%s)", errno, strerror(errno))
}
================================================
FILE: zygisk_build/src/main/cpp/pixelify.cpp
================================================
#include <cstdlib>
#include <unistd.h>
#include <fcntl.h>
#include <string>
#include <vector>
#include <android/log.h>
#include "module.h"
#include "zygisk.hpp"
using zygisk::Api;
using zygisk::AppSpecializeArgs;
using zygisk::ServerSpecializeArgs;
// Spoofing apps
static std::vector<std::string> P1 = {"com.google.android.apps.photos", "com.google.ar.core", "com.google.vr.apps.ornament"};
static std::vector<std::string> P5 = {"com.google.android.tts", "com.google.android.apps.wearables.maestro.companion", "com.nothing.smartcenter","com.google.android.googlequicksearchbox:interactor"};
static std::vector<std::string> P6 = {"com.google"};
static std::vector<std::string> P7 = {"com.google.pixel.livewallpaper", "com.google.android.apps.subscriptions.red", "com.breel.wallpaper", "com.snapchat.android", "com.google.android.gms", "com.google.android.googlequicksearchbox","com.google.process.gapps","com.google.process.gservices"};
static std::vector<std::string> PFold = {"com.google.android.apps.subscriptions.red"};
static std::vector<std::string> keep = {"com.google.android.apps.recorder", "com.google.android.GoogleCamera", "com.google.android.apps.motionsense.bridge", "com.google.android.gms.chimera", "com.google.android.gms.update", "com.android.camera", "com.google.android.xx", "com.google.android.googlequicksearchbox:HotwordDetectionService","com.google.android.as:nonpersistent","com.google.android.apps.mesagging:rcs","com.google.android.googlequicksearchbox:assistant"};
// Fingerprint
const char P1_FP[256] = "google/marlin/marlin:10/QP1A.191005.007.A3/5972272:user/release-keys";
const char P5_FP[256] = "google/redfin/redfin:13/TQ2A.230305.008.C1/9619669:user/release-keys";
const char P6_FP[256] = "google/raven/raven:13/TQ1A.230105.002/9325679:user/release-keys";
const char P7_FP[256] = "google/cheetah/cheetah:13/TQ2A.230305.008.C1/9619669:user/release-keys";
bool DEBUG = true;
char package_name[256];
static int spoof_type;
// Changed by magisk module
const char INTERNAL_SPOOFING[256] = "INTERNAL_SPOOFING_NOT_SUPPORTED";
class pixelify : public zygisk::ModuleBase
{
public:
void onLoad(Api *api, JNIEnv *env) override
{
this->api = api;
this->env = env;
}
void preAppSpecialize(AppSpecializeArgs *args) override
{
// Use JNI to fetch our process name
const char *process = env->GetStringUTFChars(args->nice_name, nullptr);
spoof_type = getSpoof(process);
strcpy(package_name, process);
env->ReleaseStringUTFChars(args->nice_name, process);
}
void postAppSpecialize(const AppSpecializeArgs *) override
{
switch (spoof_type)
{
case 1:
injectBuild("Pixel XL", "marlin", P1_FP);
//Register_Has_system_feature();
break;
case 2:
injectBuild("Pixel 5", "redfin", P5_FP);
break;
case 3:
injectBuild("Pixel 6 Pro", "raven", P6_FP);
break;
case 4:
injectBuild("Pixel 7 Pro", "cheetah", P7_FP);
break;
case 5:
injectBuild("Pixel XL", "marlin", P1_FP);
// N_MR1 (7.1.2) SDK Version is 25
injectversion(25);
break;
case 6:
injectBuild("Pixel Fold", "felix", P7_FP);
break;
case 7:
if (strcmp(INTERNAL_SPOOFING, "INTERNAL_SPOOFING_SUPPORTED") == 0)
{
disablespoofinghack();
}
break;
default:
break;
}
}
private:
Api *api;
JNIEnv *env;
void injectBuild(const char *model1, const char *product1, const char *finger1)
{
if (env == nullptr)
{
LOGW("failed to inject android.os.Build for %s due to env is null", package_name);
return;
}
jclass build_class = env->FindClass("android/os/Build");
if (build_class == nullptr)
{
LOGW("failed to inject android.os.Build for %s due to build is null", package_name);
return;
}
else if (DEBUG)
{
LOGI("inject android.os.Build for %s with \nPRODUCT:%s \nMODEL:%s \nFINGERPRINT:%s", package_name, product1, model1, finger1);
}
jstring product = env->NewStringUTF(product1);
jstring model = env->NewStringUTF(model1);
jstring brand = env->NewStringUTF("google");
jstring manufacturer = env->NewStringUTF("Google");
jstring finger = env->NewStringUTF(finger1);
jfieldID brand_id = env->GetStaticFieldID(build_class, "BRAND", "Ljava/lang/String;");
if (brand_id != nullptr)
{
env->SetStaticObjectField(build_class, brand_id, brand);
}
jfieldID manufacturer_id = env->GetStaticFieldID(build_class, "MANUFACTURER", "Ljava/lang/String;");
if (manufacturer_id != nullptr)
{
env->SetStaticObjectField(build_class, manufacturer_id, manufacturer);
}
jfieldID product_id = env->GetStaticFieldID(build_class, "PRODUCT", "Ljava/lang/String;");
if (product_id != nullptr)
{
env->SetStaticObjectField(build_class, product_id, product);
}
jfieldID device_id = env->GetStaticFieldID(build_class, "DEVICE", "Ljava/lang/String;");
if (device_id != nullptr)
{
env->SetStaticObjectField(build_class, device_id, product);
}
jfieldID model_id = env->GetStaticFieldID(build_class, "MODEL", "Ljava/lang/String;");
if (model_id != nullptr)
{
env->SetStaticObjectField(build_class, model_id, model);
}
if (strcmp(finger1, "") != 0)
{
jfieldID finger_id = env->GetStaticFieldID(build_class, "FINGERPRINT", "Ljava/lang/String;");
if (finger_id != nullptr)
{
env->SetStaticObjectField(build_class, finger_id, finger);
}
}
if (env->ExceptionCheck())
{
env->ExceptionClear();
}
env->DeleteLocalRef(brand);
env->DeleteLocalRef(manufacturer);
env->DeleteLocalRef(product);
env->DeleteLocalRef(model);
env->DeleteLocalRef(finger);
}
void injectversion(const int inc_c)
{
if (env == nullptr)
{
LOGW("failed to inject android.os.Build for %s due to env is null", package_name);
return;
}
jclass build_class = env->FindClass("android/os/Build$VERSION");
if (build_class == nullptr)
{
LOGW("failed to inject android.os.Build.VERSION for %s due to build is null", package_name);
return;
}
jint inc = (jint)inc_c;
jfieldID inc_id = env->GetStaticFieldID(build_class, "DEVICE_INITIAL_SDK_INT", "I");
if (inc_id != nullptr)
{
env->SetStaticIntField(build_class, inc_id, inc);
}
if (env->ExceptionCheck())
{
env->ExceptionClear();
}
}
void disablespoofinghack()
{
if (env == nullptr)
{
LOGW("failed to inject android.os.Build for %s due to env is null", package_name);
return;
}
jclass pixel_prop_class = env->FindClass("com/android/internal/util/custom/PixelPropsUtils");
if (pixel_prop_class == nullptr)
{
LOGW("failed to inject PixelPropUtils for %s due to build is null", package_name);
return;
}
jstring pixelify = env->NewStringUTF("ro.pixelify.device");
jfieldID device_id = env->GetStaticFieldID(pixel_prop_class, "DEVICE", "Ljava/lang/String;");
if (device_id != nullptr)
{
env->SetStaticObjectField(pixel_prop_class, device_id, pixelify);
}
env->DeleteLocalRef(pixelify);
}
int getSpoof(const char *process)
{
std::string package = process;
if (strcmp(process, "com.google.android.gms.unstable") == 0)
return 5;
else if (strcmp(process, "system_server") == 0)
return 7;
for (auto &s : keep)
{
if (package.find(s) != std::string::npos)
return 0;
}
for (auto &s : P1)
{
if (package.find(s) != std::string::npos)
return 1;
}
for (auto &s : P5)
{
if (package.find(s) != std::string::npos)
return 2;
}
for (auto &s : P7)
{
if (package.find(s) != std::string::npos)
return 4;
}
for (auto &s : PFold)
{
if (package.find(s) != std::string::npos)
return 6;
}
for (auto &s : P6)
{
if (package.find(s) != std::string::npos)
return 3;
}
return 0;
}
};
REGISTER_ZYGISK_MODULE(pixelify)
================================================
FILE: zygisk_build/src/main/cpp/tensor.cpp
================================================
#include <cstdlib>
#include <unistd.h>
#include <string>
#include <vector>
#include <fcntl.h>
#include <android/log.h>
#include "zygisk.hpp"
#include "module.h"
using zygisk::Api;
using zygisk::AppSpecializeArgs;
using zygisk::ServerSpecializeArgs;
class pixelify : public zygisk::ModuleBase
{
public:
void onLoad(Api *api, JNIEnv *env) override
{
this->api = api;
this->env = env;
}
void preAppSpecialize(AppSpecializeArgs *args) override
{
// Use JNI to fetch our process name
const char *process = env->GetStringUTFChars(args->nice_name, nullptr);
preSpecialize(process);
env->ReleaseStringUTFChars(args->nice_name, process);
}
void preServerSpecialize(ServerSpecializeArgs *args) override
{
preSpecialize("system_server");
}
void injectBuild(const char *package_name, const char *model1, const char *product1, const char *finger1)
{
if (env == nullptr)
{
LOGW("failed to inject android.os.Build for %s due to env is null", package_name);
return;
}
jclass build_class = env->FindClass("android/os/Build");
if (build_class == nullptr)
{
LOGW("failed to inject android.os.Build for %s due to build is null", package_name);
return;
}
else
{
LOGI("inject android.os.Build for %s with \nPRODUCT:%s \nMODEL:%s \nFINGERPRINT:%s", package_name, product1, model1, finger1);
}
jstring product = env->NewStringUTF(product1);
jstring model = env->NewStringUTF(model1);
jstring brand = env->NewStringUTF("google");
jstring manufacturer = env->NewStringUTF("Google");
jstring finger = env->NewStringUTF(finger1);
jfieldID brand_id = env->GetStaticFieldID(build_class, "BRAND", "Ljava/lang/String;");
if (brand_id != nullptr)
{
env->SetStaticObjectField(build_class, brand_id, brand);
}
jfieldID manufacturer_id = env->GetStaticFieldID(build_class, "MANUFACTURER", "Ljava/lang/String;");
if (manufacturer_id != nullptr)
{
env->SetStaticObjectField(build_class, manufacturer_id, manufacturer);
}
jfieldID product_id = env->GetStaticFieldID(build_class, "PRODUCT", "Ljava/lang/String;");
if (product_id != nullptr)
{
env->SetStaticObjectField(build_class, product_id, product);
}
jfieldID device_id = env->GetStaticFieldID(build_class, "DEVICE", "Ljava/lang/String;");
if (device_id != nullptr)
{
env->SetStaticObjectField(build_class, device_id, product);
}
jfieldID model_id = env->GetStaticFieldID(build_class, "MODEL", "Ljava/lang/String;");
if (model_id != nullptr)
{
env->SetStaticObjectField(build_class, model_id, model);
}
if (strcmp(finger1, "") != 0)
{
jfieldID finger_id = env->GetStaticFieldID(build_class, "FINGERPRINT", "Ljava/lang/String;");
if (finger_id != nullptr)
{
env->SetStaticObjectField(build_class, finger_id, finger);
}
}
if (env->ExceptionCheck())
{
env->ExceptionClear();
}
env->DeleteLocalRef(brand);
env->DeleteLocalRef(manufacturer);
env->DeleteLocalRef(product);
env->DeleteLocalRef(model);
if (strcmp(finger1, "") != 0)
{
env->DeleteLocalRef(finger);
}
}
private:
Api *api;
JNIEnv *env;
void preSpecialize(const char *process)
{
unsigned r = 0;
int fd = api->connectCompanion();
read(fd, &r, sizeof(r));
close(fd);
int need_p6 = 0;
std::string package_name = process;
if (package_name.find("com.google.android.apps.photos") != std::string::npos)
{
injectBuild(process, "Pixel XL", "marlin", "google/marlin/marlin:10/QP1A.191005.007.A3/5972272:user/release-keys");
}
api->setOption(zygisk::Option::DLCLOSE_MODULE_LIBRARY);
}
};
static int urandom = -1;
static void companion_handler(int i)
{
if (urandom < 0)
{
urandom = open("/dev/urandom", O_RDONLY);
}
unsigned r;
read(urandom, &r, sizeof(r));
LOGD("example: companion r=[%u]\n", r);
write(i, &r, sizeof(r));
}
REGISTER_ZYGISK_MODULE(pixelify)
REGISTER_ZYGISK_COMPANION(companion_handler)
================================================
FILE: zygisk_build/src/main/cpp/zygisk.hpp
================================================
/* Copyright 2022-2023 John "topjohnwu" Wu
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
// This is the public API for Zygisk modules.
// DO NOT MODIFY ANY CODE IN THIS HEADER.
#pragma once
#include <jni.h>
#define ZYGISK_API_VERSION 4
/*
***************
* Introduction
***************
On Android, all app processes are forked from a special daemon called "Zygote".
For each new app process, zygote will fork a new process and perform "specialization".
This specialization operation enforces the Android security sandbox on the newly forked
process to make sure that 3rd party application code is only loaded after it is being
restricted within a sandbox.
On Android, there is also this special process called "system_server". This single
process hosts a significant portion of system services, which controls how the
Android operating system and apps interact with each other.
The Zygisk framework provides a way to allow developers to build modules and run custom
code before and after system_server and any app processes' specialization.
This enable developers to inject code and alter the behavior of system_server and app processes.
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!
*********************
* Development Guide
*********************
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.
Example code:
static jint (*orig_logger_entry_max)(JNIEnv *env);
static jint my_logger_entry_max(JNIEnv *env) { return orig_logger_entry_max(env); }
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)
-----------------------------------------------------------------------------------------
Since your module class's code runs with either Zygote's privilege in pre[XXX]Specialize,
or runs in the sandbox of the target process in post[XXX]Specialize, the code in your class
never runs in a true superuser environment.
If your module require access to superuser permissions, you can create and register
a root companion handler function. This function runs in a separate root companion
daemon process, and an Unix domain socket is provided to allow you to perform IPC between
your target process and the root companion process.
Example code:
static void example_handler(int socket) { ... }
REGISTER_ZYGISK_COMPANION(example_handler)
*/
namespace zygisk {
struct Api;
struct AppSpecializeArgs;
struct ServerSpecializeArgs;
class ModuleBase {
public:
// This method is called as soon as the module is loaded into the target process.
// A Zygisk API handle will be passed as an argument.
virtual void onLoad([[maybe_unused]] Api *api, [[maybe_unused]] JNIEnv *env) {}
// This method 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 method 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 method runs with the same privilege of the app's own code.
virtual void postAppSpecialize([[maybe_unused]] const AppSpecializeArgs *args) {}
// This method is called before the system server process is specialized.
// See preAppSpecialize(args) for more info.
virtual void preServerSpecialize([[maybe_unused]] ServerSpecializeArgs *args) {}
// This method 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 <class T> 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 methods 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 methods due to SELinux restrictions.
//
// The pre[XXX]Specialize methods 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 method 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 methods.
// Accessing the directory returned is only possible in the pre[XXX]Specialize methods
// 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 method 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();
// Exempt the provided file descriptor from being automatically closed.
//
// This API only make sense in preAppSpecialize; calling this method in any other situation
// is either a no-op (returns true) or an error (returns false).
//
// When false is returned, the provided file descriptor will eventually be closed by zygote.
bool exemptFd(int fd);
// Hook JNI native methods for a class
//
// Lookup all registered JNI native methods and replace it with your own methods.
// 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);
// Hook functions in the PLT (Procedure Linkage Table) of ELFs loaded in memory.
//
// Parsing /proc/[PID]/maps will give you the memory map of a process. As an example:
//
// <address> <perms> <offset> <dev> <inode> <pathname>
// 56b4346000-56b4347000 r-xp 00002000 fe:00 235 /system/bin/app_process64
// (More details: https://man7.org/linux/man-pages/man5/proc.5.html)
//
// The `dev` and `inode` pair uniquely identifies a file being mapped into memory.
// For matching ELFs loaded in memory, replace function `symbol` with `newFunc`.
// If `oldFunc` is not nullptr, the original function pointer will be saved to `oldFunc`.
void pltHookRegister(dev_t dev, ino_t inode, const char *symbol, void *newFunc, void **oldFunc);
// Commit all the hooks that was previously registered.
// Returns false if an error occurred.
bool pltHookCommit();
private:
internal::api_table *tbl;
template <class T> 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<clazz>(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 Unix domain 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 globally shared resources.
#define REGISTER_ZYGISK_COMPANION(func) \
void zygisk_companion_entry(int client) { func(client); }
/*********************************************************
* The following is internal ABI implementation detail.
* You do not have to understand what it is doing.
*********************************************************/
namespace internal {
struct module_abi {
long api_version;
ModuleBase *impl;
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), impl(module) {
preAppSpecialize = [](auto m, auto args) { m->preAppSpecialize(args); };
postAppSpecialize = [](auto m, auto args) { m->postAppSpecialize(args); };
preServerSpecialize = [](auto m, auto args) { m->preServerSpecialize(args); };
postServerSpecialize = [](auto m, auto args) { m->postServerSpecialize(args); };
}
};
struct api_table {
// Base
void *impl;
bool (*registerModule)(api_table *, module_abi *);
void (*hookJniNativeMethods)(JNIEnv *, const char *, JNINativeMethod *, int);
void (*pltHookRegister)(dev_t, ino_t, const char *, void *, void **);
bool (*exemptFd)(int);
bool (*pltHookCommit)();
int (*connectCompanion)(void * /* impl */);
void (*setOption)(void * /* impl */, Option);
int (*getModuleDir)(void * /* impl */);
uint32_t (*getFlags)(void * /* impl */);
};
template <class T>
void entry_impl(api_table *table, JNIEnv *env) {
static Api api;
api.tbl = table;
static T module;
ModuleBase *m = &module;
static module_abi abi(m);
if (!table->registerModule(table, &abi)) return;
m->onLoad(&api, env);
}
} // namespace internal
inline int Api::connectCompanion() {
return tbl->connectCompanion ? tbl->connectCompanion(tbl->impl) : -1;
}
inline int Api::getModuleDir() {
return tbl->getModuleDir ? tbl->getModuleDir(tbl->impl) : -1;
}
inline void Api::setOption(Option opt) {
if (tbl->setOption) tbl->setOption(tbl->impl, opt);
}
inline uint32_t Api::getFlags() {
return tbl->getFlags ? tbl->getFlags(tbl->impl) : 0;
}
inline bool Api::exemptFd(int fd) {
return tbl->exemptFd != nullptr && tbl->exemptFd(fd);
}
inline void Api::hookJniNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int numMethods) {
if (tbl->hookJniNativeMethods) tbl->hookJniNativeMethods(env, className, methods, numMethods);
}
inline void Api::pltHookRegister(dev_t dev, ino_t inode, const char *symbol, void *newFunc, void **oldFunc) {
if (tbl->pltHookRegister) tbl->pltHookRegister(dev, inode, symbol, newFunc, oldFunc);
}
inline bool Api::pltHookCommit() {
return tbl->pltHookCommit != nullptr && tbl->pltHookCommit();
}
} // namespace zygisk
extern "C" {
[[gnu::visibility("default"), maybe_unused]]
void zygisk_module_entry(zygisk::internal::api_table *, JNIEnv *);
[[gnu::visibility("default"), maybe_unused]]
void zygisk_companion_entry(int);
} // extern "C"
gitextract_tqli54zh/
├── LICENSE
├── META-INF/
│ └── com/
│ └── google/
│ └── android/
│ ├── update-binary
│ └── updater-script
├── README.md
├── customize.sh
├── module.prop
├── system/
│ ├── etc/
│ │ └── sysconfig/
│ │ ├── pixel_2017_exclusive.xml
│ │ ├── pixel_2018_exclusive.xml
│ │ └── pixel_2019_exclusive.xml
│ └── product/
│ └── etc/
│ └── sysconfig/
│ ├── pixel_2016_exclusive.xml
│ ├── pixel_2017_exclusive.xml
│ ├── pixel_2018_exclusive.xml
│ ├── pixel_2019_exclusive.xml
│ ├── pixel_experience_2017.xml
│ ├── pixel_experience_2018.xml
│ ├── pixel_experience_2019.xml
│ ├── pixel_experience_2019_midyear.xml
│ ├── pixel_experience_2020.xml
│ ├── pixel_experience_2020_midyear.xml
│ ├── pixel_experience_2021.xml
│ ├── pixel_experience_2021_midyear.xml
│ ├── pixel_experience_2022.xml
│ ├── pixel_experience_2022_midyear.xml
│ └── pixelify_experience.xml
└── zygisk_build/
├── build.gradle
└── src/
└── main/
├── AndroidManifest.xml
└── cpp/
├── CMakeLists.txt
├── module.h
├── pixelify.cpp
├── tensor.cpp
└── zygisk.hpp
SYMBOL INDEX (40 symbols across 4 files)
FILE: zygisk_build/src/main/cpp/module.h
function namespace (line 6) | namespace pixelifytag {
FILE: zygisk_build/src/main/cpp/pixelify.cpp
class pixelify (line 36) | class pixelify : public zygisk::ModuleBase
method onLoad (line 39) | void onLoad(Api *api, JNIEnv *env) override
method preAppSpecialize (line 44) | void preAppSpecialize(AppSpecializeArgs *args) override
method postAppSpecialize (line 52) | void postAppSpecialize(const AppSpecializeArgs *) override
method injectBuild (line 92) | void injectBuild(const char *model1, const char *product1, const char ...
method injectversion (line 166) | void injectversion(const int inc_c)
method disablespoofinghack (line 194) | void disablespoofinghack()
method getSpoof (line 215) | int getSpoof(const char *process)
FILE: zygisk_build/src/main/cpp/tensor.cpp
class pixelify (line 15) | class pixelify : public zygisk::ModuleBase
method onLoad (line 18) | void onLoad(Api *api, JNIEnv *env) override
method preAppSpecialize (line 24) | void preAppSpecialize(AppSpecializeArgs *args) override
method preServerSpecialize (line 32) | void preServerSpecialize(ServerSpecializeArgs *args) override
method injectBuild (line 37) | void injectBuild(const char *package_name, const char *model1, const c...
method preSpecialize (line 119) | void preSpecialize(const char *process)
function companion_handler (line 138) | static void companion_handler(int i)
FILE: zygisk_build/src/main/cpp/zygisk.hpp
type zygisk (line 98) | namespace zygisk {
type Api (line 100) | struct Api
type AppSpecializeArgs (line 101) | struct AppSpecializeArgs
method AppSpecializeArgs (line 161) | AppSpecializeArgs() = delete;
type ServerSpecializeArgs (line 102) | struct ServerSpecializeArgs
method ServerSpecializeArgs (line 172) | ServerSpecializeArgs() = delete;
class ModuleBase (line 104) | class ModuleBase {
method onLoad (line 109) | virtual void onLoad([[maybe_unused]] Api *api, [[maybe_unused]] JNIE...
method preAppSpecialize (line 123) | virtual void preAppSpecialize([[maybe_unused]] AppSpecializeArgs *ar...
method postAppSpecialize (line 128) | virtual void postAppSpecialize([[maybe_unused]] const AppSpecializeA...
method preServerSpecialize (line 132) | virtual void preServerSpecialize([[maybe_unused]] ServerSpecializeAr...
method postServerSpecialize (line 136) | virtual void postServerSpecialize([[maybe_unused]] const ServerSpeci...
type AppSpecializeArgs (line 139) | struct AppSpecializeArgs {
method AppSpecializeArgs (line 161) | AppSpecializeArgs() = delete;
type ServerSpecializeArgs (line 164) | struct ServerSpecializeArgs {
method ServerSpecializeArgs (line 172) | ServerSpecializeArgs() = delete;
type internal (line 175) | namespace internal {
type api_table (line 176) | struct api_table
type module_abi (line 311) | struct module_abi {
method module_abi (line 320) | module_abi(ModuleBase *module) : api_version(ZYGISK_API_VERSION), ...
type api_table (line 328) | struct api_table {
function entry_impl (line 344) | void entry_impl(api_table *table, JNIEnv *env) {
type Option (line 181) | enum Option : int {
type StateFlag (line 198) | enum StateFlag : uint32_t {
type Api (line 208) | struct Api {
type internal (line 309) | namespace internal {
type api_table (line 176) | struct api_table
type module_abi (line 311) | struct module_abi {
method module_abi (line 320) | module_abi(ModuleBase *module) : api_version(ZYGISK_API_VERSION), ...
type api_table (line 328) | struct api_table {
function entry_impl (line 344) | void entry_impl(api_table *table, JNIEnv *env) {
Condensed preview — 31 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (56K chars).
[
{
"path": "LICENSE",
"chars": 1062,
"preview": "MIT License\n\nCopyright (c) 2025 Cuynu\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
},
{
"path": "META-INF/com/google/android/update-binary",
"chars": 612,
"preview": "#!/sbin/sh\n\n#################\n# Initialization\n#################\n\numask 022\n\n# echo before loading util_functions\nui_pri"
},
{
"path": "META-INF/com/google/android/updater-script",
"chars": 7,
"preview": "#MAGISK"
},
{
"path": "README.md",
"chars": 2094,
"preview": "# Google Photos unlimited backup module\nAdds Photos features and unlimited original backup\n\nCurrent version : **1.1-stab"
},
{
"path": "customize.sh",
"chars": 2229,
"preview": "for i in /system/product/etc/sysconfig/*; do\n file=$i\n file=${file/\\/system\\/product\\/etc\\/sysconfig\\//}\n if [ "
},
{
"path": "module.prop",
"chars": 240,
"preview": "id=PixelifyPhotos\nname=Google Photos Unlimited backup\nversion=1.1-stable\nversionCode=002\nauthor=cuynu\ndescription=Adds P"
},
{
"path": "system/etc/sysconfig/pixel_2017_exclusive.xml",
"chars": 0,
"preview": ""
},
{
"path": "system/etc/sysconfig/pixel_2018_exclusive.xml",
"chars": 0,
"preview": ""
},
{
"path": "system/etc/sysconfig/pixel_2019_exclusive.xml",
"chars": 0,
"preview": ""
},
{
"path": "system/product/etc/sysconfig/pixel_2016_exclusive.xml",
"chars": 370,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!-- These are configurations that should exist on Google's 2016 Pixel devices. "
},
{
"path": "system/product/etc/sysconfig/pixel_2017_exclusive.xml",
"chars": 0,
"preview": ""
},
{
"path": "system/product/etc/sysconfig/pixel_2018_exclusive.xml",
"chars": 0,
"preview": ""
},
{
"path": "system/product/etc/sysconfig/pixel_2019_exclusive.xml",
"chars": 1,
"preview": "\n"
},
{
"path": "system/product/etc/sysconfig/pixel_experience_2017.xml",
"chars": 3731,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!-- These are configurations that should exist on Google's 2017 and newer Nexus"
},
{
"path": "system/product/etc/sysconfig/pixel_experience_2018.xml",
"chars": 1234,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!-- These are configurations that should exist on Google's 2018 and newer Pixel"
},
{
"path": "system/product/etc/sysconfig/pixel_experience_2019.xml",
"chars": 484,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!-- These are configurations that should exist on Google's 2019 and newer devic"
},
{
"path": "system/product/etc/sysconfig/pixel_experience_2019_midyear.xml",
"chars": 0,
"preview": ""
},
{
"path": "system/product/etc/sysconfig/pixel_experience_2020.xml",
"chars": 0,
"preview": ""
},
{
"path": "system/product/etc/sysconfig/pixel_experience_2020_midyear.xml",
"chars": 0,
"preview": ""
},
{
"path": "system/product/etc/sysconfig/pixel_experience_2021.xml",
"chars": 0,
"preview": ""
},
{
"path": "system/product/etc/sysconfig/pixel_experience_2021_midyear.xml",
"chars": 0,
"preview": ""
},
{
"path": "system/product/etc/sysconfig/pixel_experience_2022.xml",
"chars": 0,
"preview": ""
},
{
"path": "system/product/etc/sysconfig/pixel_experience_2022_midyear.xml",
"chars": 0,
"preview": ""
},
{
"path": "system/product/etc/sysconfig/pixelify_experience.xml",
"chars": 1395,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!-- These are configurations that should exist on Pixelify devices. -->\n<config"
},
{
"path": "zygisk_build/build.gradle",
"chars": 7111,
"preview": "import org.apache.tools.ant.filters.FixCrLfFilter\nimport org.apache.tools.ant.filters.ReplaceTokens\n\nimport java.securit"
},
{
"path": "zygisk_build/src/main/AndroidManifest.xml",
"chars": 39,
"preview": "<manifest package=\"zygisk.template\" />\n"
},
{
"path": "zygisk_build/src/main/cpp/CMakeLists.txt",
"chars": 1493,
"preview": "cmake_minimum_required(VERSION 3.4.1)\n\nif (NOT DEFINED MODULE_NAME)\n message(FATAL_ERROR \"MODULE_NAME is not set\")\nel"
},
{
"path": "zygisk_build/src/main/cpp/module.h",
"chars": 609,
"preview": "#include \"errno.h\"\n#include \"android/log.h\"\n\n#pragma once\n\nnamespace pixelifytag {\n\n#ifndef TAG\n#define TAG \"Pixelify"
},
{
"path": "zygisk_build/src/main/cpp/pixelify.cpp",
"chars": 8995,
"preview": "#include <cstdlib>\n#include <unistd.h>\n#include <fcntl.h>\n#include <string>\n#include <vector>\n#include <android/log.h>\n\n"
},
{
"path": "zygisk_build/src/main/cpp/tensor.cpp",
"chars": 4525,
"preview": "#include <cstdlib>\n#include <unistd.h>\n#include <string>\n#include <vector>\n#include <fcntl.h>\n#include <android/log.h>\n\n"
},
{
"path": "zygisk_build/src/main/cpp/zygisk.hpp",
"chars": 15711,
"preview": "/* Copyright 2022-2023 John \"topjohnwu\" Wu\n *\n * Permission to use, copy, modify, and/or distribute this software for an"
}
]
About this extraction
This page contains the full source code of the cuynu/gphotos-unlimited-zygisk GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 31 files (50.7 KB), approximately 13.5k tokens, and a symbol index with 40 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.