You've already forked PlayIntegrityFork
mirror of
https://github.com/osm0sis/PlayIntegrityFork.git
synced 2025-09-06 06:37:06 +00:00
Compare commits
150 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe57017255 | ||
|
|
0d05112f38 | ||
|
|
d8ff58d9ca | ||
|
|
ea65aef097 | ||
|
|
ebdbccdad2 | ||
|
|
08e3fb4d29 | ||
|
|
a671c3b0d3 | ||
|
|
c13a7b1299 | ||
|
|
629de14990 | ||
|
|
bd4fdcf0c3 | ||
|
|
8c216e2d40 | ||
|
|
27fc24337b | ||
|
|
796f776534 | ||
|
|
c972637347 | ||
|
|
b10828f199 | ||
|
|
726aecb2be | ||
|
|
a790f2c0db | ||
|
|
165d370bc8 | ||
|
|
915b87e6be | ||
|
|
1255a49274 | ||
|
|
6cc82e3e7b | ||
|
|
87fde1f4ca | ||
|
|
d535747c91 | ||
|
|
98bb23460e | ||
|
|
027e5855a0 | ||
|
|
8d2d1ecbd2 | ||
|
|
3775b5448e | ||
|
|
00023fb111 | ||
|
|
481491758c | ||
|
|
b42773671a | ||
|
|
3d55dc59c1 | ||
|
|
33f4fa2ce0 | ||
|
|
2857e3d2f8 | ||
|
|
4b8d6497d0 | ||
|
|
f3a7f3d5e9 | ||
|
|
bee755d8f3 | ||
|
|
dd4db53ca2 | ||
|
|
c30b3ab8a8 | ||
|
|
9d0a67d119 | ||
|
|
667efdd6a6 | ||
|
|
6e7377b3de | ||
|
|
98ab70a0b6 | ||
|
|
418e7306e3 | ||
|
|
44420c89ab | ||
|
|
adcdd80d65 | ||
|
|
096c8941b9 | ||
|
|
a926c520f2 | ||
|
|
9ef7a7f04e | ||
|
|
e9c1ec1d5d | ||
|
|
a7c2f348ea | ||
|
|
a5d9980ea7 | ||
|
|
58db03d596 | ||
|
|
64e412c351 | ||
|
|
914750104f | ||
|
|
1db82e2ccb | ||
|
|
f20c2dff1e | ||
|
|
620581b4de | ||
|
|
ebfd0c292a | ||
|
|
3e58be1e24 | ||
|
|
662b9c59c7 | ||
|
|
0bc9a4543a | ||
|
|
e3e4bbb95f | ||
|
|
7c3d0bd8dd | ||
|
|
b26b043a02 | ||
|
|
5aabd4b6b5 | ||
|
|
6d173fb3a1 | ||
|
|
efa3e98a94 | ||
|
|
8756c3963a | ||
|
|
6109918511 | ||
|
|
0386e085b5 | ||
|
|
b24d538e82 | ||
|
|
dc1ac51008 | ||
|
|
e0d288ac10 | ||
|
|
36084324bc | ||
|
|
07effe41b7 | ||
|
|
7b058d9bef | ||
|
|
ae1322b907 | ||
|
|
ee8e56b401 | ||
|
|
96a1475ac7 | ||
|
|
2dd7a17ac2 | ||
|
|
c7b87b944f | ||
|
|
31adf6b3b9 | ||
|
|
2027b7ba74 | ||
|
|
bbfdc87724 | ||
|
|
4d116c6a42 | ||
|
|
afddeaf340 | ||
|
|
61b018ae21 | ||
|
|
c7c8b549df | ||
|
|
7f1bdf69c5 | ||
|
|
95e6cbe53b | ||
|
|
ee714d1e21 | ||
|
|
6aa58bbc5e | ||
|
|
63bcb3c3f6 | ||
|
|
25262ce07e | ||
|
|
b4821fb03e | ||
|
|
8e4e7d1cef | ||
|
|
58e04392bf | ||
|
|
2c13b924ed | ||
|
|
8215587745 | ||
|
|
8414785806 | ||
|
|
75cf629015 | ||
|
|
36ce25f154 | ||
|
|
af7063d055 | ||
|
|
ecbf6d1db8 | ||
|
|
287ce1ee9b | ||
|
|
77653d25cb | ||
|
|
009815692c | ||
|
|
c0618cf9d8 | ||
|
|
7d216c30f1 | ||
|
|
d620dcdecb | ||
|
|
d0acafd34a | ||
|
|
f99696e894 | ||
|
|
12b55630fb | ||
|
|
5703c9bca1 | ||
|
|
ffd510aee5 | ||
|
|
b30b43f2ae | ||
|
|
affe99b5ae | ||
|
|
e2bb20b077 | ||
|
|
79052ff455 | ||
|
|
4ab07b71f8 | ||
|
|
34966f58a0 | ||
|
|
0299c76061 | ||
|
|
163678c49a | ||
|
|
f61fd571e0 | ||
|
|
26979bd73e | ||
|
|
c19224b138 | ||
|
|
ccb696d334 | ||
|
|
8014d71934 | ||
|
|
52edfcfb7c | ||
|
|
938ae86c8e | ||
|
|
bdd846add6 | ||
|
|
1a7c5103d1 | ||
|
|
686af702dc | ||
|
|
18f8277f16 | ||
|
|
484ab2aa63 | ||
|
|
87eb713cbd | ||
|
|
fa418290b3 | ||
|
|
608e60adbb | ||
|
|
fae28159b9 | ||
|
|
71b40dcb09 | ||
|
|
1f0c921773 | ||
|
|
3b00a7249b | ||
|
|
48014b9450 | ||
|
|
3451dd72ec | ||
|
|
9cc8451c90 | ||
|
|
7997954f74 | ||
|
|
fc8e5108de | ||
|
|
3ec6a4b039 | ||
|
|
5b9d0dfdd3 | ||
|
|
278cbf1732 |
19
.github/workflows/android.yml
vendored
19
.github/workflows/android.yml
vendored
@@ -2,27 +2,29 @@ name: Android CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
branches: main
|
||||
paths-ignore: '**.md'
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
branches: main
|
||||
paths-ignore: '**.md'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- name: Check out
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: "recursive"
|
||||
submodules: 'recursive'
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up JDK 17
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
java-version: 17
|
||||
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
@@ -31,7 +33,8 @@ jobs:
|
||||
run: ./gradlew assembleRelease
|
||||
|
||||
- name: Upload CI module zip as artifact zip
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: PlayIntegrityFork-CI_#${{ github.run_number }}
|
||||
path: module/*
|
||||
path: 'module/*'
|
||||
compression-level: 9
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +1,6 @@
|
||||
[submodule "Dobby"]
|
||||
path = app/src/main/cpp/Dobby
|
||||
url = https://github.com/jmpews/Dobby
|
||||
[submodule "json"]
|
||||
path = app/src/main/cpp/json
|
||||
url = https://github.com/nlohmann/json
|
||||
|
||||
33
CHANGELOG.md
33
CHANGELOG.md
@@ -1,17 +1,22 @@
|
||||
## Custom Fork v7
|
||||
- Fix ROM non-/system spoof injection app replacement
|
||||
- Add missing XiaomiEUInject-Stub to the default/example replace list
|
||||
- Improve code, scripts and logging
|
||||
- Fix ROM injection when using KernelSU and APatch
|
||||
- Spoof init.svc.adbd to DroidGuard by default to further hide USB Debugging
|
||||
- Improve hiding from detection by user apps
|
||||
## Custom Fork v11
|
||||
- Improve autopif busybox tests, default api_level 32, pass --advanced arg
|
||||
- Improve scripts for special configs with Tricky Store
|
||||
- Fix resetprop fallback Magisk check
|
||||
- Add Action button support to run autopif in root managers
|
||||
- Fix root check for Termux/KSU/APatch
|
||||
- Improve PixelPropsUtils workaround on more setups
|
||||
- Replace autopif with autopif2 to generate a random print from latest Pixel Beta
|
||||
|
||||
## Custom Fork v6
|
||||
- Improve migration script to be more portable, e.g. for desktop use
|
||||
- Add custom function to hack global props without increasing the change counter
|
||||
- Add missing Xiaomi, Realme and SELinux global props
|
||||
- Add customizable example.app_replace.list file to replace conflicting custom ROM apps
|
||||
- Improve VERBOSE_LOGS to be any json entry, and dump full Build fields at 100
|
||||
- Change DroidGuard prop spoof hooking method to Dobby for now
|
||||
## Custom Fork v10
|
||||
- Work around Shamiko 1.1 bug causing DenyList app hangs
|
||||
- Keep killgms in Scripts-only mode for testing
|
||||
- Add missing global props, fix all tags/type props
|
||||
- Use newer resetprop, fall back to custom func
|
||||
- Add ROM sig spoof to Advanced, default off
|
||||
- Add granular spoof to Advanced for Tricky Store
|
||||
- Improve scripts to keep Advanced values
|
||||
- Improve autopif to catch Magisk Canary busybox regression
|
||||
- Fix bootloop on some Xiaomi devices
|
||||
- Work around PixelPropsUtils conflict
|
||||
|
||||
_[Previous changelogs](https://github.com/osm0sis/PlayIntegrityFork/releases)_
|
||||
|
||||
118
README.md
118
README.md
@@ -8,43 +8,66 @@
|
||||
|
||||
A Zygisk module which fixes "ctsProfileMatch" (SafetyNet) and "MEETS_DEVICE_INTEGRITY" (Play Integrity).
|
||||
|
||||
To use this module you must have one of the following:
|
||||
To use this module you must have one of the following (latest versions):
|
||||
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk) with Zygisk (and, if not also using Shamiko, Enforce DenyList) enabled
|
||||
- [KernelSU](https://github.com/tiann/KernelSU) with [ZygiskNext](https://github.com/Dr-TSNG/ZygiskNext) module installed
|
||||
- [APatch](https://github.com/bmax121/APatch) with [ZygiskNext MOD](https://github.com/Yervant7/ZygiskNext) module installed
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk) with Zygisk enabled (and Enforce DenyList enabled if NOT also using [Shamiko](https://github.com/LSPosed/LSPosed.github.io/releases) or [Zygisk Assistant](https://github.com/snake-4/Zygisk-Assistant), for best results)
|
||||
- [KernelSU](https://github.com/tiann/KernelSU) with [Zygisk Next](https://github.com/Dr-TSNG/ZygiskNext) module installed
|
||||
- [APatch](https://github.com/bmax121/APatch) with [Zygisk Next](https://github.com/Dr-TSNG/ZygiskNext) module installed
|
||||
|
||||
## About module
|
||||
|
||||
It injects a classes.dex file to modify a few fields in the android.os.Build class. Also, it creates a hook in the native code to modify system properties. These are spoofed only to Google Play Services' DroidGuard (SafetyNet/Play Integrity) service.
|
||||
It injects a classes.dex file to modify fields in the android.os.Build class. Also, it creates a hook in the native code to modify system properties. These are spoofed only to Google Play Services' DroidGuard (SafetyNet/Play Integrity) service.
|
||||
|
||||
The purpose of the module is to avoid hardware attestation.
|
||||
|
||||
## About 'custom.pif.json' file
|
||||
|
||||
You can fill out the included template [example.pif.json](https://raw.githubusercontent.com/osm0sis/PlayIntegrityFork/main/module/example.pif.json) from the module directory then rename it to custom.pif.json to spoof custom values to the GMS unstable process. It will be used instead of any included pif.json (none included currently).
|
||||
You can fill out the included template [example.pif.json](https://raw.githubusercontent.com/osm0sis/PlayIntegrityFork/main/module/example.pif.json) from the module directory (/data/adb/modules/playintegrityfix) then rename it to custom.pif.json to spoof custom values to the GMS unstable process. It will be used instead of any included pif.json (none included currently).
|
||||
|
||||
As a general rule you can't use values from recent devices due to them only being allowed with full hardware backed attestation.
|
||||
Note this is just a template with the current suggested defaults, but with this fork you can include as few or as many android.os.Build class fields and Android system properties as needed to pass DEVICE verdict now and in the future if the enforced checks by Play Integrity change.
|
||||
|
||||
Older formatted custom.pif.json files from cross-forks and previous releases will be automatically migrated to the latest format.
|
||||
As a general rule you can't use values from recent devices due to them only being allowed with full hardware backed attestation. A script to extract the latest Pixel Beta fingerprint is included with the module; see the autopif section below for usage and caveats, and see the Resources below for information and scripts to help find a working private fingerprint.
|
||||
|
||||
Older formatted custom.pif.json files from cross-forks and previous releases will be automatically migrated to the latest format. Simply ensure the filename is custom.pif.json and place it in the module directory before upgrading.
|
||||
|
||||
A migration may also be performed manually with `sh migrate.sh` and custom.pif.json in the same directory, or from a file explorer app that supports script execution.
|
||||
|
||||
<details>
|
||||
<summary>Resources</summary>
|
||||
<summary><strong>Resources</strong></summary>
|
||||
|
||||
- [How-To Guide - Info to help find build.prop files, then create and use a custom.pif.json](https://xdaforums.com/t/module-play-integrity-fix-safetynet-fix.4607985/post-89189572)
|
||||
- [gen_pif_custom.sh - Script to generate a custom.pif.json from device dump build.prop files](https://xdaforums.com/t/tools-zips-scripts-osm0sis-odds-and-ends-multiple-devices-platforms.2239421/post-89173470)
|
||||
- [UI Workflow Guide - Build, edit and test custom.pif.json using PixelFlasher on PC](https://xdaforums.com/t/module-play-integrity-fix-safetynet-fix.4607985/post-89189970)
|
||||
- FAQ:
|
||||
- [PIF FAQ](https://xdaforums.com/t/pif-faq.4653307/) - Frequently Asked Questions (READ FIRST!)
|
||||
|
||||
- Guides:
|
||||
- [How-To Guide](https://xdaforums.com/t/module-play-integrity-fix-safetynet-fix.4607985/post-89189572) - Info to help find build.prop files, then manually create and use a custom.pif.json
|
||||
- [Complete Noobs' Guide](https://xdaforums.com/t/how-to-search-find-your-own-fingerprints-noob-friendly-a-comprehensive-guide-w-tips-discussion-for-complete-noobs-from-one.4645816/) - A more in-depth basic explainer of the How-To Guide above
|
||||
- [UI Workflow Guide](https://xdaforums.com/t/pixelflasher-a-gui-tool-for-flashing-updating-rooting-managing-pixel-phones.4415453/post-87412305) - Build/find, edit, and test custom.pif.json using PixelFlasher on PC
|
||||
- [Tasker PIF Testing Helper](https://xdaforums.com/t/pif-testing-helper-tasker-profile-for-testing-fingerprints.4644827/) - Test custom.pif.json using Tasker on device
|
||||
|
||||
- Scripts:
|
||||
- [gen_pif_custom.sh](https://xdaforums.com/t/tools-zips-scripts-osm0sis-odds-and-ends-multiple-devices-platforms.2239421/post-89173470) - Script to generate a custom.pif.json from device dump build.prop files
|
||||
- [autopif.sh](https://xdaforums.com/t/module-play-integrity-fix-safetynet-fix.4607985/post-89233630) - Script to extract the latest working Xiaomi.eu public fingerprint (though frequently banned and may be banned for RCS use while otherwise passing) to test an initial setup
|
||||
- [pif-test-json-file.sh](https://xdaforums.com/t/module-play-integrity-fix-safetynet-fix.4607985/post-89561228) - Script to automate generating and testing json files to attempt to find working fingerprints
|
||||
- [install-random-fp.sh](https://xdaforums.com/t/script-for-randomly-installing-custom-device-fingerprints.4647408/) - Script to randomly switch between multiple working fingerprints found by the user
|
||||
|
||||
</details>
|
||||
|
||||
## About 'custom.app_replace.list' file
|
||||
|
||||
You can customize the included default [example.app_replace.list](https://raw.githubusercontent.com/osm0sis/PlayIntegrityFork/main/module/example.app_replace.list) from the module directory then rename it to custom.app_replace.list to systemlessly replace any additional conflicting custom ROM spoof injection app paths to disable them.
|
||||
You can customize the included default [example.app_replace.list](https://raw.githubusercontent.com/osm0sis/PlayIntegrityFork/main/module/example.app_replace.list) from the module directory (/data/adb/modules/playintegrityfix) then rename it to custom.app_replace.list to systemlessly replace any additional conflicting custom ROM spoof injection app paths to disable them.
|
||||
|
||||
## About 'autopif2.sh' and 'killgms.sh' script files
|
||||
|
||||
There's intentionally no pif.json in the module because the goal remains to be futureproof, and including something that may be banned and obsolete within days would be contrary to that goal. If you don't care to have your own private fingerprint to use or don't have time to look for one currently then simply run the generation script from a root manager app that supports the module Action button, a root prompt with `sh autopif2.sh` in the module directory (/data/adb/modules/playintegrityfix), or from a file explorer app that supports script execution.
|
||||
|
||||
The autopif2 script generates a random device fingerprint from the latest Pixel Beta, ideally only to test an initial setup, since they expire roughly every 6 weeks from the Pixel Beta release date (dates included in the generated fingerprint), and the public mass-used ones from other modules or ROMs may also get banned or may be banned for RCS use while otherwise passing Play Integrity and SafetyNet in that time.
|
||||
|
||||
The killgms script forces the Google Play Services DroidGuard process (com.google.android.gms.unstable) to end, making it restart with the next attestation attempt; useful for testing out different fingerprints without requiring a reboot in between.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
Make sure Google Play Services (com.google.android.gms) is NOT on the Magisk DenyList if Enforce DenyList is enabled since this interferes with the module; the module does prevent this using scripts but it only happens once during each reboot.
|
||||
|
||||
### Failing BASIC verdict
|
||||
|
||||
If you are failing basicIntegrity (SafetyNet) or MEETS_BASIC_INTEGRITY (Play Integrity) something is wrong in your setup. Recommended steps in order to find the problem:
|
||||
@@ -52,22 +75,34 @@ If you are failing basicIntegrity (SafetyNet) or MEETS_BASIC_INTEGRITY (Play Int
|
||||
- Disable all modules except this one
|
||||
- Try a different (ideally known working) custom.pif.json
|
||||
|
||||
Some modules which modify system can trigger DroidGuard detection, never hook GMS processes.
|
||||
Note: Some modules which modify system (e.g. Xposed) can trigger DroidGuard detections, as can any which hook GMS processes (e.g. custom fonts).
|
||||
|
||||
### Failing DEVICE verdict (on KernelSU/APatch)
|
||||
|
||||
- Disable ZygiskNext
|
||||
- Disable Zygisk Next
|
||||
- Reboot
|
||||
- Enable ZygiskNext
|
||||
- Enable Zygisk Next
|
||||
- Reboot again
|
||||
|
||||
### Play Protect/Store Certification and Google Wallet Tap To Pay Setup Security Requirements
|
||||
### Failing DEVICE verdict (on custom kernel/ROM)
|
||||
|
||||
Follow these steps:
|
||||
- Check the kernel release string with command `adb shell uname -r` or `uname -r`
|
||||
- If it's on the [Known Banned Kernel List](https://xdaforums.com/t/module-play-integrity-fix-safetynet-fix.4607985/post-89308909) then inform your kernel developer/ROM maintainer to remove their branding for their next build
|
||||
- You may also try a different custom kernel, or go back to the default kernel for your ROM, if available/possible
|
||||
|
||||
### Failing DEVICE verdict (on custom ROM)
|
||||
|
||||
- Check the ROM signing keys with command `adb shell unzip -l /system/etc/security/otacerts.zip` or `unzip -l /system/etc/security/otacerts.zip`
|
||||
- If the output shows the ROM is signed with the AOSP testkey then inform your ROM maintainer to start signing their builds with a private key for their next build and ideally also provide a ROM signature migration build to allow users to update to it without requiring a data wipe
|
||||
- There is an experimental advanced feature to attempt to work around this by spoofing the ROM signature in Package Manager, see the spoofing Advanced Settings section below
|
||||
- You may also try a different custom ROM, or go back to the stock ROM for your device, if available/possible
|
||||
|
||||
### Failing Play Protect/Store Certification and/or Google Wallet Tap To Pay Setup Security Requirements
|
||||
|
||||
- Reflash the module in your root manager app
|
||||
- Clear Google Wallet cache (if you have it)
|
||||
- Clear Google Play Store cache and data
|
||||
- Clear Google Play Services (com.google.android.gms) cache and data (Optionally skip clearing data and wait some time, ~24h, for it to resolve on its own)
|
||||
- Clear Google Wallet (com.google.android.apps.walletnfcrel) and/or Google Pay (com.google.android.apps.nbu.paisa.user) cache, if you have them installed
|
||||
- Clear Google Play Store (com.android.vending) and, if present, Google Play Protect Service (com.google.android.odad) cache and data
|
||||
- Clear Google Play Services (com.google.android.gms) cache and data, or, optionally skip clearing data and wait some time (~24h) for it to resolve on its own
|
||||
- Reboot
|
||||
|
||||
Note: Clearing Google Play Services app ***data*** will then require you to reset any WearOS devices paired to your device.
|
||||
@@ -78,16 +113,47 @@ You can read module logs using one of these commands directly after boot:
|
||||
|
||||
`adb shell "logcat | grep 'PIF/'"` or `su -c "logcat | grep 'PIF/'"`
|
||||
|
||||
Add a "VERBOSE_LOGS" entry with a value of "0", "1", "2", "3" or "100" to your custom.pif.json to enable higher logging levels; "100" will dump all Build fields, and all the system properties that DroidGuard is checking.
|
||||
Add a "verboseLogs" entry with a value of "0", "1", "2", "3" or "100" to your custom.pif.json to enable higher logging levels; "100" will dump all Build fields, and all the system properties that DroidGuard is checking. Adding the entry can also be done using the migration script with the `sh migrate.sh --force --advanced` or `sh migrate.sh -f -a` command.
|
||||
|
||||
## Can this module pass MEETS_STRONG_INTEGRITY?
|
||||
|
||||
No.
|
||||
No...
|
||||
|
||||
## About Play Integrity, SafetyNet is deprecated
|
||||
## About spoofing Advanced Settings
|
||||
|
||||
You can read more
|
||||
here: [Play Integrity API Info - XDA Forums](https://xdaforums.com/t/info-play-integrity-api-replacement-for-safetynet.4479337/)
|
||||
The advanced spoofing options add granular control over what exactly gets spoofed, allowing one to disable the parts that may conflict with other kinds of spoofing modules, and provide an option to work around the testkey ROM ban for those needing that feature. See more in the Details area below.
|
||||
|
||||
<details>
|
||||
<summary><strong>Details</strong></summary>
|
||||
|
||||
- Adding the Advanced Settings entries is best done using the migration script with the `sh migrate.sh --force --advanced` or `sh migrate.sh -f -a` command. Other than for the "verboseLogs" entry (see above), they are all 0 (disabled) or 1 (enabled).
|
||||
|
||||
- The "spoofBuild" entry (default 1) controls spoofing the Build Fields from the fingerprint; the "spoofProps" entry (default 1) controls spoofing the System Properties from the fingerprint; the "spoofProvider" entry (default 1) controls spoofing the Keystore Provider, and the "spoofSignature" entry (default 0) controls spoofing the ROM Signature.
|
||||
|
||||
- For spoofing locked bootloader and attempting to pass Play Integrity STRONG verdict I only recommend using the latest official [Tricky Store](https://github.com/5ec1cff/TrickyStore) build.
|
||||
|
||||
- Note: Using Tricky Store to achieve STRONG integrity (with an unrevoked hardware keybox.xml) requires the Advanced Settings "spoofProvider" disabled and either "spoofProps" disabled or the "*.security_patch" entry commented out, but to achieve DEVICE integrity (with Tricky Store default AOSP software keybox.xml or a revoked keybox.xml) requires at least "spoofProps" enabled, and some fingerprints may also require "spoofProvider". More known working private fingerprints can achieve DEVICE/STRONG integrity on more devices using these Advanced Settings in conjunction with Tricky Store than was possible with Tricky Store alone since they require fingerprint props spoofing.
|
||||
|
||||
</details>
|
||||
|
||||
## About Scripts-only mode
|
||||
|
||||
An advanced feature intended for older Android <10 ROMs, mostly stock ROMs or those with stock-like values, (and some other rare special cases), since they generally only need a few prop changes to pass Play Integrity DEVICE verdict. Due to this the majority of the previous information does not apply to or contradicts that of Scripts-only mode, so to avoid confusion it's contained in the Details area below.
|
||||
|
||||
<details>
|
||||
<summary><strong>Details</strong></summary>
|
||||
|
||||
- Manually opt-in by creating a file named scripts-only-mode in the module directory, either from a root prompt with `mkdir -p /data/adb/modules/playintegrityfix; touch /data/adb/modules/playintegrityfix/scripts-only-mode` or from a file explorer app, and then re/flashing the module. Scripts-only mode will remain enabled until this file is removed and the module is reflashed again.
|
||||
|
||||
- During install all unused default mode files (including custom.pif.json) are removed from the module directory, effectively disabling the Zygisk components of PIF: attestation fallback and device spoofing. You'll see "Scripts-only mode" indicated in the module description in your root manager app.
|
||||
|
||||
- For best results, you should still most likely enable Magisk's Enforce DenyList option if NOT also using [Shamiko](https://github.com/LSPosed/LSPosed.github.io/releases) or [Zygisk Assistant](https://github.com/snake-4/Zygisk-Assistant). The module will automatically add the Google Play Services DroidGuard process (com.google.android.gms.unstable) to the Magisk DenyList, if missing, since for Scripts-only mode it's necessary on some configurations (generally Android 9).
|
||||
|
||||
</details>
|
||||
|
||||
## About Play Integrity (SafetyNet is deprecated)
|
||||
|
||||
[Play Integrity API](https://xdaforums.com/t/info-play-integrity-api-replacement-for-safetynet.4479337/) - FAQ/information about PI (Play Integrity) replacing SN (SafetyNet)
|
||||
|
||||
## Credits
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ plugins {
|
||||
android {
|
||||
namespace = "es.chiteroman.playintegrityfix"
|
||||
compileSdk = 34
|
||||
ndkVersion = "26.1.10909125"
|
||||
ndkVersion = "27.1.12297006"
|
||||
buildToolsVersion = "34.0.0"
|
||||
|
||||
buildFeatures {
|
||||
@@ -62,14 +62,15 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("dev.rikka.ndk.thirdparty:cxx:1.2.0")
|
||||
implementation("org.lsposed.libcxx:libcxx:27.0.12077973")
|
||||
implementation("org.lsposed.hiddenapibypass:hiddenapibypass:4.3")
|
||||
}
|
||||
|
||||
tasks.register("copyFiles") {
|
||||
doLast {
|
||||
val moduleFolder = project.rootDir.resolve("module")
|
||||
val dexFile = project.layout.buildDirectory.get().asFile.resolve("intermediates/dex/release/minifyReleaseWithR8/classes.dex")
|
||||
val soDir = project.layout.buildDirectory.get().asFile.resolve("intermediates/stripped_native_libs/release/out/lib")
|
||||
val soDir = project.layout.buildDirectory.get().asFile.resolve("intermediates/stripped_native_libs/release/stripReleaseDebugSymbols/out/lib")
|
||||
|
||||
dexFile.copyTo(moduleFolder.resolve("classes.dex"), overwrite = true)
|
||||
|
||||
|
||||
1
app/proguard-rules.pro
vendored
1
app/proguard-rules.pro
vendored
@@ -1,3 +1,4 @@
|
||||
-keep class es.chiteroman.playintegrityfix.EntryPoint {public <methods>;}
|
||||
-keep class es.chiteroman.playintegrityfix.CustomProvider
|
||||
-keep class es.chiteroman.playintegrityfix.CustomKeyStoreSpi
|
||||
-keep class es.chiteroman.playintegrityfix.CustomPackageInfoCreator
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.22.1)
|
||||
|
||||
project(zygisk)
|
||||
project(playintegrityfix)
|
||||
|
||||
find_package(cxx REQUIRED CONFIG)
|
||||
|
||||
|
||||
1
app/src/main/cpp/json
Submodule
1
app/src/main/cpp/json
Submodule
Submodule app/src/main/cpp/json added at 9cca280a4d
File diff suppressed because it is too large
Load Diff
@@ -3,8 +3,8 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "zygisk.hpp"
|
||||
#include "json/single_include/nlohmann/json.hpp"
|
||||
#include "dobby.h"
|
||||
#include "json.hpp"
|
||||
|
||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "PIF/Native", __VA_ARGS__)
|
||||
|
||||
@@ -13,7 +13,11 @@
|
||||
#define JSON_FILE_PATH "/data/adb/modules/playintegrityfix/pif.json"
|
||||
#define CUSTOM_JSON_FILE_PATH "/data/adb/modules/playintegrityfix/custom.pif.json"
|
||||
|
||||
static int VERBOSE_LOGS = 0;
|
||||
static int verboseLogs = 0;
|
||||
static int spoofBuild = 1;
|
||||
static int spoofProps = 1;
|
||||
static int spoofProvider = 1;
|
||||
static int spoofSignature = 0;
|
||||
|
||||
static std::map<std::string, std::string> jsonProps;
|
||||
|
||||
@@ -22,7 +26,6 @@ typedef void (*T_Callback)(void *, const char *, const char *, uint32_t);
|
||||
static std::map<void *, T_Callback> callbacks;
|
||||
|
||||
static void modify_callback(void *cookie, const char *name, const char *value, uint32_t serial) {
|
||||
|
||||
if (cookie == nullptr || name == nullptr || value == nullptr || !callbacks.contains(cookie)) return;
|
||||
|
||||
const char *oldValue = value;
|
||||
@@ -50,7 +53,7 @@ static void modify_callback(void *cookie, const char *name, const char *value, u
|
||||
}
|
||||
|
||||
if (oldValue == value) {
|
||||
if (VERBOSE_LOGS > 99) LOGD("[%s]: %s (unchanged)", name, value);
|
||||
if (verboseLogs > 99) LOGD("[%s]: %s (unchanged)", name, oldValue);
|
||||
} else {
|
||||
LOGD("[%s]: %s -> %s", name, oldValue, value);
|
||||
}
|
||||
@@ -75,11 +78,8 @@ static void doHook() {
|
||||
return;
|
||||
}
|
||||
LOGD("Found '__system_property_read_callback' handle at %p", handle);
|
||||
DobbyHook(
|
||||
handle,
|
||||
reinterpret_cast<dobby_dummy_func_t>(my_system_property_read_callback),
|
||||
reinterpret_cast<dobby_dummy_func_t *>(&o_system_property_read_callback)
|
||||
);
|
||||
DobbyHook(handle, reinterpret_cast<dobby_dummy_func_t>(my_system_property_read_callback),
|
||||
reinterpret_cast<dobby_dummy_func_t *>(&o_system_property_read_callback));
|
||||
}
|
||||
|
||||
class PlayIntegrityFix : public zygisk::ModuleBase {
|
||||
@@ -168,7 +168,7 @@ public:
|
||||
if (dexVector.empty() || json.empty()) return;
|
||||
|
||||
readJson();
|
||||
doHook();
|
||||
if (spoofProps > 0) doHook();
|
||||
inject();
|
||||
|
||||
dexVector.clear();
|
||||
@@ -188,27 +188,65 @@ private:
|
||||
void readJson() {
|
||||
LOGD("JSON contains %d keys!", static_cast<int>(json.size()));
|
||||
|
||||
// Verbose logging if VERBOSE_LOGS with level number is present
|
||||
if (json.contains("VERBOSE_LOGS")) {
|
||||
if (!json["VERBOSE_LOGS"].is_null() && json["VERBOSE_LOGS"].is_string() && json["VERBOSE_LOGS"] != "") {
|
||||
VERBOSE_LOGS = stoi(json["VERBOSE_LOGS"].get<std::string>());
|
||||
if (VERBOSE_LOGS > 0) LOGD("Verbose logging (level %d) enabled!", VERBOSE_LOGS);
|
||||
// Verbose logging level
|
||||
if (json.contains("verboseLogs")) {
|
||||
if (!json["verboseLogs"].is_null() && json["verboseLogs"].is_string() && json["verboseLogs"] != "") {
|
||||
verboseLogs = stoi(json["verboseLogs"].get<std::string>());
|
||||
if (verboseLogs > 0) LOGD("Verbose logging (level %d) enabled!", verboseLogs);
|
||||
} else {
|
||||
LOGD("Error parsing VERBOSE_LOGS!");
|
||||
LOGD("Error parsing verboseLogs!");
|
||||
}
|
||||
json.erase("VERBOSE_LOGS");
|
||||
json.erase("verboseLogs");
|
||||
}
|
||||
|
||||
// Advanced spoofing settings
|
||||
if (json.contains("spoofBuild")) {
|
||||
if (!json["spoofBuild"].is_null() && json["spoofBuild"].is_string() && json["spoofBuild"] != "") {
|
||||
spoofBuild = stoi(json["spoofBuild"].get<std::string>());
|
||||
if (verboseLogs > 0) LOGD("Spoofing Build Fields %s!", (spoofBuild > 0) ? "enabled" : "disabled");
|
||||
} else {
|
||||
LOGD("Error parsing spoofBuild!");
|
||||
}
|
||||
json.erase("spoofBuild");
|
||||
}
|
||||
if (json.contains("spoofProps")) {
|
||||
if (!json["spoofProps"].is_null() && json["spoofProps"].is_string() && json["spoofProps"] != "") {
|
||||
spoofProps = stoi(json["spoofProps"].get<std::string>());
|
||||
if (verboseLogs > 0) LOGD("Spoofing System Properties %s!", (spoofProps > 0) ? "enabled" : "disabled");
|
||||
} else {
|
||||
LOGD("Error parsing spoofProps!");
|
||||
}
|
||||
json.erase("spoofProps");
|
||||
}
|
||||
if (json.contains("spoofProvider")) {
|
||||
if (!json["spoofProvider"].is_null() && json["spoofProvider"].is_string() && json["spoofProvider"] != "") {
|
||||
spoofProvider = stoi(json["spoofProvider"].get<std::string>());
|
||||
if (verboseLogs > 0) LOGD("Spoofing Keystore Provider %s!", (spoofProvider > 0) ? "enabled" : "disabled");
|
||||
} else {
|
||||
LOGD("Error parsing spoofProvider!");
|
||||
}
|
||||
json.erase("spoofProvider");
|
||||
}
|
||||
if (json.contains("spoofSignature")) {
|
||||
if (!json["spoofSignature"].is_null() && json["spoofSignature"].is_string() && json["spoofSignature"] != "") {
|
||||
spoofSignature = stoi(json["spoofSignature"].get<std::string>());
|
||||
if (verboseLogs > 0) LOGD("Spoofing ROM Signature %s!", (spoofSignature > 0) ? "enabled" : "disabled");
|
||||
} else {
|
||||
LOGD("Error parsing spoofSignature!");
|
||||
}
|
||||
json.erase("spoofSignature");
|
||||
}
|
||||
|
||||
std::vector<std::string> eraseKeys;
|
||||
for (auto &jsonList: json.items()) {
|
||||
if (VERBOSE_LOGS > 1) LOGD("Parsing %s", jsonList.key().c_str());
|
||||
if (verboseLogs > 1) LOGD("Parsing %s", jsonList.key().c_str());
|
||||
if (jsonList.key().find_first_of("*.") != std::string::npos) {
|
||||
// Name contains . or * (wildcard) so assume real property name
|
||||
if (!jsonList.value().is_null() && jsonList.value().is_string()) {
|
||||
if (jsonList.value() == "") {
|
||||
LOGD("%s is empty, skipping", jsonList.key().c_str());
|
||||
} else {
|
||||
if (VERBOSE_LOGS > 0) LOGD("Adding '%s' to properties list", jsonList.key().c_str());
|
||||
if (verboseLogs > 0) LOGD("Adding '%s' to properties list", jsonList.key().c_str());
|
||||
jsonProps[jsonList.key()] = jsonList.value();
|
||||
}
|
||||
} else {
|
||||
@@ -248,8 +286,8 @@ private:
|
||||
env->CallStaticVoidMethod(entryClass, receiveJson, javaStr);
|
||||
|
||||
LOGD("JNI: Calling init");
|
||||
auto entryInit = env->GetStaticMethodID(entryClass, "init", "(I)V");
|
||||
env->CallStaticVoidMethod(entryClass, entryInit, VERBOSE_LOGS);
|
||||
auto entryInit = env->GetStaticMethodID(entryClass, "init", "(IIII)V");
|
||||
env->CallStaticVoidMethod(entryClass, entryInit, verboseLogs, spoofBuild, spoofProvider, spoofSignature);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package es.chiteroman.playintegrityfix;
|
||||
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.Signature;
|
||||
import android.os.Build;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
public class CustomPackageInfoCreator implements Parcelable.Creator<PackageInfo> {
|
||||
private final Parcelable.Creator<PackageInfo> originalCreator;
|
||||
private final Signature spoofedSignature;
|
||||
|
||||
public CustomPackageInfoCreator(Parcelable.Creator<PackageInfo> originalCreator, Signature spoofedSignature) {
|
||||
this.originalCreator = originalCreator;
|
||||
this.spoofedSignature = spoofedSignature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PackageInfo createFromParcel(Parcel source) {
|
||||
PackageInfo packageInfo = originalCreator.createFromParcel(source);
|
||||
if (packageInfo.packageName.equals("android")) {
|
||||
if (packageInfo.signatures != null && packageInfo.signatures.length > 0) {
|
||||
packageInfo.signatures[0] = spoofedSignature;
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
if (packageInfo.signingInfo != null) {
|
||||
Signature[] signaturesArray = packageInfo.signingInfo.getApkContentsSigners();
|
||||
if (signaturesArray != null && signaturesArray.length > 0) {
|
||||
signaturesArray[0] = spoofedSignature;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return packageInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PackageInfo[] newArray(int size) {
|
||||
return originalCreator.newArray(size);
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,9 @@ public final class CustomProvider extends Provider {
|
||||
@Override
|
||||
public synchronized Service getService(String type, String algorithm) {
|
||||
if (EntryPoint.getVerboseLogs() > 2) EntryPoint.LOG(String.format("Service: Caller type '%s' with algorithm '%s'", type, algorithm));
|
||||
if (type.equals("KeyStore")) EntryPoint.spoofDevice();
|
||||
if (EntryPoint.getSpoofBuildEnabled() > 0) {
|
||||
if (type.equals("KeyStore")) EntryPoint.spoofDevice();
|
||||
}
|
||||
return super.getService(type, algorithm);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
package es.chiteroman.playintegrityfix;
|
||||
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.Signature;
|
||||
import android.os.Build;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.Base64;
|
||||
import android.util.JsonReader;
|
||||
import android.util.Log;
|
||||
|
||||
import org.lsposed.hiddenapibypass.HiddenApiBypass;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.KeyStoreSpi;
|
||||
@@ -17,6 +26,35 @@ import java.util.Map;
|
||||
|
||||
public final class EntryPoint {
|
||||
private static Integer verboseLogs = 0;
|
||||
private static Integer spoofBuildEnabled = 1;
|
||||
|
||||
private static final String signatureData = "MIIFyTCCA7GgAwIBAgIVALyxxl+zDS9SL68SzOr48309eAZyMA0GCSqGSIb3DQEBCwUAMHQxCzAJ\n" +
|
||||
"BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQw\n" +
|
||||
"EgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAg\n" +
|
||||
"Fw0yMjExMDExODExMzVaGA8yMDUyMTEwMTE4MTEzNVowdDELMAkGA1UEBhMCVVMxEzARBgNVBAgT\n" +
|
||||
"CkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC0dvb2dsZSBJbmMu\n" +
|
||||
"MRAwDgYDVQQLEwdBbmRyb2lkMRAwDgYDVQQDEwdBbmRyb2lkMIICIjANBgkqhkiG9w0BAQEFAAOC\n" +
|
||||
"Ag8AMIICCgKCAgEAsqtalIy/nctKlrhd1UVoDffFGnDf9GLi0QQhsVoJkfF16vDDydZJOycG7/kQ\n" +
|
||||
"ziRZhFdcoMrIYZzzw0ppBjsSe1AiWMuKXwTBaEtxN99S1xsJiW4/QMI6N6kMunydWRMsbJ6aAxi1\n" +
|
||||
"lVq0bxSwr8Sg/8u9HGVivfdG8OpUM+qjuV5gey5xttNLK3BZDrAlco8RkJZryAD40flmJZrWXJmc\n" +
|
||||
"r2HhJJUnqG4Z3MSziEgW1u1JnnY3f/BFdgYsA54SgdUGdQP3aqzSjIpGK01/vjrXvifHazSANjvl\n" +
|
||||
"0AUE5i6AarMw2biEKB2ySUDp8idC5w12GpqDrhZ/QkW8yBSa87KbkMYXuRA2Gq1fYbQx3YJraw0U\n" +
|
||||
"gZ4M3fFKpt6raxxM5j0sWHlULD7dAZMERvNESVrKG3tQ7B39WAD8QLGYc45DFEGOhKv5Fv8510h5\n" +
|
||||
"sXK502IvGpI4FDwz2rbtAgJ0j+16db5wCSW5ThvNPhCheyciajc8dU1B5tJzZN/ksBpzne4Xf9gO\n" +
|
||||
"LZ9ZU0+3Z5gHVvTS/YpxBFwiFpmL7dvGxew0cXGSsG5UTBlgr7i0SX0WhY4Djjo8IfPwrvvA0QaC\n" +
|
||||
"FamdYXKqBsSHgEyXS9zgGIFPt2jWdhaS+sAa//5SXcWro0OdiKPuwEzLgj759ke1sHRnvO735dYn\n" +
|
||||
"5whVbzlGyLBh3L0CAwEAAaNQME4wDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQUU1eXQ7NoYKjvOQlh\n" +
|
||||
"5V8jHQMoxA8wHwYDVR0jBBgwFoAUU1eXQ7NoYKjvOQlh5V8jHQMoxA8wDQYJKoZIhvcNAQELBQAD\n" +
|
||||
"ggIBAHFIazRLs3itnZKllPnboSd6sHbzeJURKehx8GJPvIC+xWlwWyFO5+GHmgc3yh/SVd3Xja/k\n" +
|
||||
"8Ud59WEYTjyJJWTw0Jygx37rHW7VGn2HDuy/x0D+els+S8HeLD1toPFMepjIXJn7nHLhtmzTPlDW\n" +
|
||||
"DrhiaYsls/k5Izf89xYnI4euuOY2+1gsweJqFGfbznqyqy8xLyzoZ6bvBJtgeY+G3i/9Be14HseS\n" +
|
||||
"Na4FvI1Oze/l2gUu1IXzN6DGWR/lxEyt+TncJfBGKbjafYrfSh3zsE4N3TU7BeOL5INirOMjre/j\n" +
|
||||
"VgB1YQG5qLVaPoz6mdn75AbBBm5a5ahApLiKqzy/hP+1rWgw8Ikb7vbUqov/bnY3IlIU6XcPJTCD\n" +
|
||||
"b9aRZQkStvYpQd82XTyxD/T0GgRLnUj5Uv6iZlikFx1KNj0YNS2T3gyvL++J9B0Y6gAkiG0EtNpl\n" +
|
||||
"z7Pomsv5pVdmHVdKMjqWw5/6zYzVmu5cXFtR384Ti1qwML1xkD6TC3VIv88rKIEjrkY2c+v1frh9\n" +
|
||||
"fRJ2OmzXmML9NgHTjEiJR2Ib2iNrMKxkuTIs9oxKZgrJtJKvdU9qJJKM5PnZuNuHhGs6A/9gt9Oc\n" +
|
||||
"cetYeQvVSqeEmQluWfcunQn9C9Vwi2BJIiVJh4IdWZf5/e2PlSSQ9CJjz2bKI17pzdxOmjQfE0JS\n" +
|
||||
"F7Xt\n";
|
||||
|
||||
private static final Map<String, String> map = new HashMap<>();
|
||||
|
||||
@@ -24,11 +62,17 @@ public final class EntryPoint {
|
||||
return verboseLogs;
|
||||
}
|
||||
|
||||
public static void init(int level) {
|
||||
verboseLogs = level;
|
||||
public static Integer getSpoofBuildEnabled() {
|
||||
return spoofBuildEnabled;
|
||||
}
|
||||
|
||||
public static void init(int logLevel, int spoofBuildVal, int spoofProviderVal, int spoofSignatureVal) {
|
||||
verboseLogs = logLevel;
|
||||
spoofBuildEnabled = spoofBuildVal;
|
||||
if (verboseLogs > 99) logFields();
|
||||
spoofProvider();
|
||||
spoofDevice();
|
||||
if (spoofProviderVal > 0) spoofProvider();
|
||||
if (spoofBuildVal > 0) spoofDevice();
|
||||
if (spoofSignatureVal > 0) spoofPackageManager();
|
||||
}
|
||||
|
||||
public static void receiveJson(String data) {
|
||||
@@ -78,6 +122,63 @@ public final class EntryPoint {
|
||||
}
|
||||
}
|
||||
|
||||
private static void spoofPackageManager() {
|
||||
Signature spoofedSignature = new Signature(Base64.decode(signatureData, Base64.DEFAULT));
|
||||
Parcelable.Creator<PackageInfo> originalCreator = PackageInfo.CREATOR;
|
||||
Parcelable.Creator<PackageInfo> customCreator = new CustomPackageInfoCreator(originalCreator, spoofedSignature);
|
||||
|
||||
try {
|
||||
Field creatorField = findField(PackageInfo.class, "CREATOR");
|
||||
creatorField.setAccessible(true);
|
||||
creatorField.set(null, customCreator);
|
||||
} catch (Exception e) {
|
||||
LOG("Couldn't replace PackageInfoCreator: " + e);
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
HiddenApiBypass.addHiddenApiExemptions("Landroid/os/Parcel;", "Landroid/content/pm", "Landroid/app");
|
||||
}
|
||||
|
||||
try {
|
||||
Field cacheField = findField(PackageManager.class, "sPackageInfoCache");
|
||||
cacheField.setAccessible(true);
|
||||
Object cache = cacheField.get(null);
|
||||
Method clearMethod = cache.getClass().getMethod("clear");
|
||||
clearMethod.invoke(cache);
|
||||
} catch (Exception e) {
|
||||
LOG("Couldn't clear PackageInfoCache: " + e);
|
||||
}
|
||||
|
||||
try {
|
||||
Field creatorsField = findField(Parcel.class, "mCreators");
|
||||
creatorsField.setAccessible(true);
|
||||
Map<?, ?> mCreators = (Map<?, ?>) creatorsField.get(null);
|
||||
mCreators.clear();
|
||||
} catch (Exception e) {
|
||||
LOG("Couldn't clear Parcel mCreators: " + e);
|
||||
}
|
||||
|
||||
try {
|
||||
Field creatorsField = findField(Parcel.class, "sPairedCreators");
|
||||
creatorsField.setAccessible(true);
|
||||
Map<?, ?> sPairedCreators = (Map<?, ?>) creatorsField.get(null);
|
||||
sPairedCreators.clear();
|
||||
} catch (Exception e) {
|
||||
LOG("Couldn't clear Parcel sPairedCreators: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Field findField(Class<?> currentClass, String fieldName) throws NoSuchFieldException {
|
||||
while (currentClass != null && !currentClass.equals(Object.class)) {
|
||||
try {
|
||||
return currentClass.getDeclaredField(fieldName);
|
||||
} catch (NoSuchFieldException e) {
|
||||
currentClass = currentClass.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException("Field '" + fieldName + "' not found in class hierarchy of " + currentClass.getName());
|
||||
}
|
||||
|
||||
private static boolean classContainsField(Class className, String fieldName) {
|
||||
for (Field field : className.getDeclaredFields()) {
|
||||
if (field.getName().equals(fieldName)) return true;
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
plugins {
|
||||
id("com.android.application") version "8.2.1" apply false
|
||||
id("com.android.application") version "8.7.0" apply false
|
||||
}
|
||||
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
5
gradle/wrapper/gradle-wrapper.properties
vendored
5
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,7 @@
|
||||
#Tue Oct 31 00:21:30 CET 2023
|
||||
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-8.10.2-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
297
gradlew
vendored
297
gradlew
vendored
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env sh
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
# Copyright © 2015-2021 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.
|
||||
@@ -15,69 +15,104 @@
|
||||
# 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 UN*X
|
||||
##
|
||||
#
|
||||
# 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/HEAD/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
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
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
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
# 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
|
||||
' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
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
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
@@ -87,9 +122,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
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"
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
@@ -98,88 +133,120 @@ Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
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" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
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
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
# Collect all arguments for the java command, 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.
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
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, 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" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# 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" "$@"
|
||||
|
||||
183
gradlew.bat
vendored
183
gradlew.bat
vendored
@@ -1,89 +1,94 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@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
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% 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
|
||||
|
||||
15
module/action.sh
Normal file
15
module/action.sh
Normal file
@@ -0,0 +1,15 @@
|
||||
MODPATH="${0%/*}"
|
||||
|
||||
# ensure not running in busybox ash standalone shell
|
||||
set +o standalone
|
||||
unset ASH_STANDALONE
|
||||
|
||||
sh $MODPATH/autopif2.sh || exit 1
|
||||
|
||||
echo -e "\nDone!"
|
||||
|
||||
# warn since Magisk's implementation automatically closes if successful
|
||||
if [ "$KSU" != "true" -a "$APATCH" != "true" ]; then
|
||||
echo -e "\nClosing dialog in 20 seconds ..."
|
||||
sleep 20
|
||||
fi
|
||||
164
module/autopif2.sh
Normal file
164
module/autopif2.sh
Normal file
@@ -0,0 +1,164 @@
|
||||
#!/system/bin/sh
|
||||
|
||||
if [ "$USER" != "root" -a "$(whoami 2>/dev/null)" != "root" ]; then
|
||||
echo "autopif2: need root permissions";
|
||||
exit 1;
|
||||
fi;
|
||||
|
||||
case "$1" in
|
||||
-h|--help|help) echo "sh autopif2.sh [-a]"; exit 0;;
|
||||
-a|--advanced|advanced) ARGS="-a"; shift;;
|
||||
esac;
|
||||
|
||||
echo "Pixel Beta pif.json generator script \
|
||||
\n by osm0sis @ xda-developers";
|
||||
|
||||
case "$0" in
|
||||
*.sh) DIR="$0";;
|
||||
*) DIR="$(lsof -p $$ 2>/dev/null | grep -o '/.*autopif2.sh$')";;
|
||||
esac;
|
||||
DIR=$(dirname "$(readlink -f "$DIR")");
|
||||
|
||||
item() { echo "\n- $@"; }
|
||||
die() { echo "\nError: $@, install busybox!"; exit 1; }
|
||||
|
||||
find_busybox() {
|
||||
[ -n "$BUSYBOX" ] && return 0;
|
||||
local path;
|
||||
for path in /data/adb/modules/busybox-ndk/system/*/busybox /data/adb/magisk/busybox /data/adb/ksu/bin/busybox /data/adb/ap/bin/busybox; do
|
||||
if [ -f "$path" ]; then
|
||||
BUSYBOX="$path";
|
||||
return 0;
|
||||
fi;
|
||||
done;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ! which wget >/dev/null || grep -q "wget-curl" $(which wget); then
|
||||
if ! find_busybox; then
|
||||
die "wget not found";
|
||||
elif $BUSYBOX ping -c1 -s2 android.com 2>&1 | grep -q "bad address"; then
|
||||
die "wget broken";
|
||||
else
|
||||
wget() { $BUSYBOX wget "$@"; }
|
||||
fi;
|
||||
fi;
|
||||
|
||||
if date -D '%s' -d "$(date '+%s')" 2>&1 | grep -q "bad date"; then
|
||||
if ! find_busybox; then
|
||||
die "date broken";
|
||||
else
|
||||
date() { $BUSYBOX date "$@"; }
|
||||
fi;
|
||||
fi;
|
||||
|
||||
if [ "$DIR" = /data/adb/modules/playintegrityfix ]; then
|
||||
DIR=$DIR/autopif2;
|
||||
mkdir -p $DIR;
|
||||
fi;
|
||||
cd "$DIR";
|
||||
|
||||
item "Crawling Android Developers for latest Pixel Beta ...";
|
||||
wget -q -O PIXEL_GSI_HTML --no-check-certificate https://developer.android.com/topic/generic-system-image/releases 2>&1 || exit 1;
|
||||
grep -m1 -o 'li>.*(Beta)' PIXEL_GSI_HTML | cut -d\> -f2;
|
||||
|
||||
BETA_REL_DATE="$(date -D '%B %e, %Y' -d "$(grep -m1 -o 'Date:.*' PIXEL_GSI_HTML | cut -d\ -f2-4)" '+%Y-%m-%d')";
|
||||
BETA_EXP_DATE="$(date -D '%s' -d "$(($(date -D '%Y-%m-%d' -d "$BETA_REL_DATE" '+%s') + 60 * 60 * 24 * 7 * 6))" '+%Y-%m-%d')";
|
||||
echo "Beta Released: $BETA_REL_DATE \
|
||||
\nEstimated Expiry: $BETA_EXP_DATE";
|
||||
|
||||
RELEASE="$(grep -m1 'corresponding Google Pixel builds' PIXEL_GSI_HTML | grep -o '/versions/.*' | cut -d\/ -f3)";
|
||||
ID="$(grep -m1 -o 'Build:.*' PIXEL_GSI_HTML | cut -d\ -f2)";
|
||||
INCREMENTAL="$(grep -m1 -o "$ID-.*-" PIXEL_GSI_HTML | cut -d- -f2)";
|
||||
|
||||
wget -q -O PIXEL_GET_HTML --no-check-certificate https://developer.android.com$(grep -m1 'corresponding Google Pixel builds' PIXEL_GSI_HTML | grep -o 'href.*' | cut -d\" -f2) 2>&1 || exit 1;
|
||||
wget -q -O PIXEL_BETA_HTML --no-check-certificate https://developer.android.com$(grep -m1 'Factory images for Google Pixel' PIXEL_GET_HTML | grep -o 'href.*' | cut -d\" -f2) 2>&1 || exit 1;
|
||||
|
||||
MODEL_LIST="$(grep -A1 'tr id=' PIXEL_BETA_HTML | grep 'td' | sed 's;.*<td>\(.*\)</td>;\1;')";
|
||||
PRODUCT_LIST="$(grep -o 'factory/.*_beta' PIXEL_BETA_HTML | cut -d\/ -f2)";
|
||||
|
||||
wget -q -O PIXEL_SECBULL_HTML --no-check-certificate https://source.android.com/docs/security/bulletin/pixel 2>&1 || exit 1;
|
||||
|
||||
SECURITY_PATCH="$(grep -A15 "$(grep -m1 -o 'Security patch level:.*' PIXEL_GSI_HTML | cut -d\ -f4-)" PIXEL_SECBULL_HTML | grep -m1 -B1 '</tr>' | grep 'td' | sed 's;.*<td>\(.*\)</td>;\1;')";
|
||||
|
||||
case "$1" in
|
||||
-m)
|
||||
DEVICE="$(getprop ro.product.device)";
|
||||
case "$PRODUCT_LIST" in
|
||||
*${DEVICE}_beta*)
|
||||
MODEL="$(getprop ro.product.model)";
|
||||
PRODUCT="${DEVICE}_beta";
|
||||
;;
|
||||
esac;
|
||||
;;
|
||||
esac;
|
||||
item "Selecting Pixel Beta device ...";
|
||||
if [ -z "$PRODUCT" ]; then
|
||||
set_random_beta() {
|
||||
local list_count="$(echo "$MODEL_LIST" | wc -l)";
|
||||
local list_rand="$((RANDOM % $list_count + 1))";
|
||||
local IFS=$'\n';
|
||||
set -- $MODEL_LIST;
|
||||
MODEL="$(eval echo \${$list_rand})";
|
||||
set -- $PRODUCT_LIST;
|
||||
PRODUCT="$(eval echo \${$list_rand})";
|
||||
DEVICE="$(echo "$PRODUCT" | sed 's/_beta//')";
|
||||
}
|
||||
set_random_beta;
|
||||
fi;
|
||||
echo "$MODEL ($PRODUCT)";
|
||||
|
||||
item "Dumping values to minimal pif.json ...";
|
||||
cat <<EOF | tee pif.json;
|
||||
{
|
||||
"MANUFACTURER": "Google",
|
||||
"MODEL": "$MODEL",
|
||||
"FINGERPRINT": "google/$PRODUCT/$DEVICE:$RELEASE/$ID/$INCREMENTAL:user/release-keys",
|
||||
"PRODUCT": "$PRODUCT",
|
||||
"DEVICE": "$DEVICE",
|
||||
"SECURITY_PATCH": "$SECURITY_PATCH",
|
||||
"DEVICE_INITIAL_SDK_INT": "32"
|
||||
}
|
||||
EOF
|
||||
|
||||
for MIGRATE in migrate.sh /data/adb/modules/playintegrityfix/migrate.sh; do
|
||||
[ -f "$MIGRATE" ] && break;
|
||||
done;
|
||||
if [ -f "$MIGRATE" ]; then
|
||||
OLDJSON=/data/adb/modules/playintegrityfix/custom.pif.json;
|
||||
[ -f "$OLDJSON" ] && grep -qE "verboseLogs|VERBOSE_LOGS" $OLDJSON && ARGS="-a";
|
||||
item "Converting pif.json to custom.pif.json with migrate.sh:";
|
||||
rm -f custom.pif.json;
|
||||
sh $MIGRATE -i $ARGS pif.json;
|
||||
if [ -n "$ARGS" ]; then
|
||||
grep_json() { grep -m1 "$1" $2 | cut -d\" -f4; }
|
||||
verboseLogs=$(grep_json "VERBOSE_LOGS" $OLDJSON);
|
||||
ADVSETTINGS="spoofBuild spoofProps spoofProvider spoofSignature verboseLogs";
|
||||
for SETTING in $ADVSETTINGS; do
|
||||
eval [ -z \"\$$SETTING\" ] \&\& $SETTING=$(grep_json "$SETTING" $OLDJSON);
|
||||
eval TMPVAL=\$$SETTING;
|
||||
[ -n "$TMPVAL" ] && sed -i "s;\($SETTING\": \"\).;\1$TMPVAL;" custom.pif.json;
|
||||
done;
|
||||
fi;
|
||||
grep -q '//"\*.security_patch"' $OLDJSON && sed -i 's;"\*.security_patch";//"\*.security_patch";' custom.pif.json;
|
||||
sed -i "s;};\n // Beta Released: $BETA_REL_DATE\n // Estimated Expiry: $BETA_EXP_DATE\n};" custom.pif.json;
|
||||
cat custom.pif.json;
|
||||
fi;
|
||||
|
||||
if [ "$DIR" = /data/adb/modules/playintegrityfix/autopif2 ]; then
|
||||
if [ -f /data/adb/modules/playintegrityfix/migrate.sh ]; then
|
||||
NEWNAME="custom.pif.json";
|
||||
else
|
||||
NEWNAME="pif.json";
|
||||
fi;
|
||||
if [ -f "../$NEWNAME" ]; then
|
||||
item "Renaming old file to $NEWNAME.bak ...";
|
||||
mv -fv ../$NEWNAME ../$NEWNAME.bak;
|
||||
fi;
|
||||
item "Installing new json ...";
|
||||
cp -fv $NEWNAME ..;
|
||||
if [ -f /data/adb/modules/playintegrityfix/killgms.sh ]; then
|
||||
item "Killing any running GMS DroidGuard process ...";
|
||||
sh /data/adb/modules/playintegrityfix/killgms.sh 2>&1 || true;
|
||||
fi;
|
||||
fi;
|
||||
@@ -1,3 +1,6 @@
|
||||
RESETPROP="resetprop -n"
|
||||
[ -f /data/adb/magisk/util_functions.sh ] && [ "$(grep MAGISK_VER_CODE /data/adb/magisk/util_functions.sh | cut -d= -f2)" -lt 27003 ] && RESETPROP=resetprop_hexpatch
|
||||
|
||||
# resetprop_hexpatch [-f|--force] <prop name> <new value>
|
||||
resetprop_hexpatch() {
|
||||
case "$1" in
|
||||
@@ -37,7 +40,7 @@ resetprop_if_diff() {
|
||||
local EXPECTED="$2"
|
||||
local CURRENT="$(resetprop "$NAME")"
|
||||
|
||||
[ -z "$CURRENT" ] || [ "$CURRENT" = "$EXPECTED" ] || resetprop_hexpatch "$NAME" "$EXPECTED"
|
||||
[ -z "$CURRENT" ] || [ "$CURRENT" = "$EXPECTED" ] || $RESETPROP "$NAME" "$EXPECTED"
|
||||
}
|
||||
|
||||
# resetprop_if_match <prop name> <value match string> <new value>
|
||||
@@ -46,5 +49,8 @@ resetprop_if_match() {
|
||||
local CONTAINS="$2"
|
||||
local VALUE="$3"
|
||||
|
||||
[[ "$(resetprop "$NAME")" = *"$CONTAINS"* ]] && resetprop_hexpatch "$NAME" "$VALUE"
|
||||
[[ "$(resetprop "$NAME")" = *"$CONTAINS"* ]] && $RESETPROP "$NAME" "$VALUE"
|
||||
}
|
||||
|
||||
# stub for boot-time
|
||||
ui_print() { return; }
|
||||
74
module/common_setup.sh
Normal file
74
module/common_setup.sh
Normal file
@@ -0,0 +1,74 @@
|
||||
# Remove any definitely conflicting modules that are installed
|
||||
if [ -d /data/adb/modules/safetynet-fix ]; then
|
||||
touch /data/adb/modules/safetynet-fix/remove
|
||||
ui_print "! Universal SafetyNet Fix (USNF) module will be removed on next reboot"
|
||||
fi
|
||||
|
||||
# Replace/hide conflicting custom ROM injection app folders/files to disable them
|
||||
LIST=$MODPATH/example.app_replace.list
|
||||
[ -f "$MODPATH/custom.app_replace.list" ] && LIST=$MODPATH/custom.app_replace.list
|
||||
for APP in $(grep -v '^#' $LIST); do
|
||||
if [ -e "$APP" ]; then
|
||||
case $APP in
|
||||
/system/*) ;;
|
||||
*) PREFIX=/system;;
|
||||
esac
|
||||
HIDEPATH=$MODPATH$PREFIX$APP
|
||||
if [ -d "$APP" ]; then
|
||||
mkdir -p $HIDEPATH
|
||||
if [ "$KSU" = "true" -o "$APATCH" = "true" ]; then
|
||||
setfattr -n trusted.overlay.opaque -v y $HIDEPATH
|
||||
else
|
||||
touch $HIDEPATH/.replace
|
||||
fi
|
||||
else
|
||||
mkdir -p $(dirname $HIDEPATH)
|
||||
if [ "$KSU" = "true" -o "$APATCH" = "true" ]; then
|
||||
mknod $HIDEPATH c 0 0
|
||||
else
|
||||
touch $HIDEPATH
|
||||
fi
|
||||
fi
|
||||
case $APP in
|
||||
*/overlay/*)
|
||||
CFG=$(echo $APP | grep -oE '.*/overlay')/config/config.xml
|
||||
if [ -f "$CFG" ]; then
|
||||
if [ -d "$APP" ]; then
|
||||
APK=$(readlink -f $APP/*.apk);
|
||||
elif [[ "$APP" = *".apk" ]]; then
|
||||
APK=$(readlink -f $APP);
|
||||
fi
|
||||
if [ -s "$APK" ]; then
|
||||
PKGNAME=$(unzip -p $APK AndroidManifest.xml | tr -d '\0' | grep -oE '[[:alnum:].-_]+\*http' | cut -d\* -f1)
|
||||
if [ "$PKGNAME" ] && grep -q "overlay package=\"$PKGNAME" $CFG; then
|
||||
HIDECFG=$MODPATH$PREFIX$CFG
|
||||
if [ ! -f "$HIDECFG" ]; then
|
||||
mkdir -p $(dirname $HIDECFG)
|
||||
cp -af $CFG $HIDECFG
|
||||
fi
|
||||
sed -i 's;<overlay \(package="'"$PKGNAME"'".*\) />;<!-- overlay \1 -->;' $HIDECFG
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
if [[ -d "$APP" || "$APP" = *".apk" ]]; then
|
||||
ui_print "! $(basename $APP .apk) ROM app disabled, please uninstall any user app versions/updates after next reboot"
|
||||
[ "$HIDECFG" ] && ui_print "! + $PKGNAME entry commented out in copied overlay config"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Work around AOSPA PropImitationHooks conflict when their persist props don't exist
|
||||
if [ -n "$(resetprop ro.aospa.version)" ]; then
|
||||
for PROP in persist.sys.pihooks.first_api_level persist.sys.pihooks.security_patch; do
|
||||
resetprop | grep -q "\[$PROP\]" || resetprop -n -p "$PROP" ""
|
||||
done
|
||||
fi
|
||||
|
||||
# Work around supported custom ROM PixelPropsUtils conflict when spoofProvider is disabled
|
||||
if [ -n "$(resetprop persist.sys.pixelprops.pi)" ]; then
|
||||
resetprop -n -p persist.sys.pixelprops.pi false
|
||||
resetprop -n -p persist.sys.pixelprops.gapps false
|
||||
resetprop -n -p persist.sys.pixelprops.gms false
|
||||
fi
|
||||
@@ -1,6 +1,19 @@
|
||||
# Error on < Android 8
|
||||
if [ "$API" -lt 26 ]; then
|
||||
abort "! You can't use this module on Android < 8.0"
|
||||
# Allow a scripts-only mode for older Android (<10) which may not require the Zygisk components
|
||||
if [ -f /data/adb/modules/playintegrityfix/scripts-only-mode ]; then
|
||||
ui_print "! Installing global scripts only; Zygisk attestation fallback and device spoofing disabled"
|
||||
touch $MODPATH/scripts-only-mode
|
||||
sed -i 's/\(description=\)\(.*\)/\1[Scripts-only mode] \2/' $MODPATH/module.prop
|
||||
rm -rf $MODPATH/autopif.sh $MODPATH/classes.dex $MODPATH/common_setup.sh \
|
||||
$MODPATH/custom.pif.json $MODPATH/example.app_replace.list $MODPATH/example.pif.json \
|
||||
$MODPATH/migrate.sh $MODPATH/pif.json $MODPATH/zygisk \
|
||||
/data/adb/modules/playintegrityfix/custom.app_replace.list \
|
||||
/data/adb/modules/playintegrityfix/custom.pif.json /data/adb/modules/playintegrityfix/system
|
||||
fi
|
||||
|
||||
# Copy any disabled app files to updated module
|
||||
if [ -d /data/adb/modules/playintegrityfix/system ]; then
|
||||
ui_print "- Restoring disabled ROM apps configuration"
|
||||
cp -arf /data/adb/modules/playintegrityfix/system $MODPATH
|
||||
fi
|
||||
|
||||
# Copy any supported custom files to updated module
|
||||
@@ -11,33 +24,13 @@ for FILE in custom.app_replace.list custom.pif.json; do
|
||||
fi
|
||||
done
|
||||
|
||||
# Remove/warn if conflicting modules are installed
|
||||
if [ -d /data/adb/modules/safetynet-fix ]; then
|
||||
touch /data/adb/modules/safetynet-fix/remove
|
||||
ui_print "! Universal SafetyNet Fix (USNF) module will be removed on next reboot"
|
||||
fi
|
||||
# Warn if potentially conflicting modules are installed
|
||||
if [ -d /data/adb/modules/MagiskHidePropsConf ]; then
|
||||
ui_print "! MagiskHidePropsConfig (MHPC) module may cause issues with PIF"
|
||||
fi
|
||||
|
||||
# Replace conflicting custom ROM injection app folders to disable them
|
||||
LIST=$MODPATH/example.app_replace.list
|
||||
[ -f "$MODPATH/custom.app_replace.list" ] && LIST=$MODPATH/custom.app_replace.list
|
||||
for APP in $(grep -v '^#' $LIST); do
|
||||
if [ -d "$APP" ]; then
|
||||
case $APP in
|
||||
/system/*) HIDEDIR=$MODPATH/$APP;;
|
||||
*) HIDEDIR=$MODPATH/system/$APP;;
|
||||
esac
|
||||
mkdir -p $HIDEDIR
|
||||
if [ "$KSU" = "true" -o "$APATCH" = "true" ]; then
|
||||
setfattr -n trusted.overlay.opaque -v y $HIDEDIR
|
||||
else
|
||||
touch $HIDEDIR/.replace
|
||||
fi
|
||||
ui_print "! $(basename $APP) ROM app disabled, please uninstall any user app versions/updates after next reboot"
|
||||
fi
|
||||
done
|
||||
# Run common tasks for installation and boot-time
|
||||
[ -d "$MODPATH/zygisk" ] && . $MODPATH/common_setup.sh
|
||||
|
||||
# Migrate custom.pif.json to latest defaults if needed
|
||||
if [ -f "$MODPATH/custom.pif.json" ] && ! grep -q "api_level" $MODPATH/custom.pif.json; then
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Rename to custom.app_replace.list once customized
|
||||
#
|
||||
# Add conflicting custom ROM injection app folder paths to this list
|
||||
# and they will be replaced systemlessly to disable them
|
||||
# Add conflicting custom ROM injection app folder/file paths to this list
|
||||
# and they will be replaced/hidden systemlessly to disable them
|
||||
|
||||
# Xiaomi.eu
|
||||
/product/app/XiaomiEUInject
|
||||
@@ -10,3 +10,12 @@
|
||||
# EliteRoms
|
||||
/system/app/EliteDevelopmentModule
|
||||
/system/app/XInjectModule
|
||||
|
||||
# hentaiOS
|
||||
/system_ext/app/hentaiLewdbSVTDummy
|
||||
|
||||
# Evolution X
|
||||
/system_ext/app/PifPrebuilt
|
||||
|
||||
# PixelOS
|
||||
/system_ext/overlay/CertifiedPropsOverlay.apk
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Rename to custom.pif.json once completed
|
||||
//
|
||||
// See android.os.Build source for field value corresponding properties:
|
||||
// These are the current suggested defaults but you may add as many other fields/properties as needed
|
||||
//
|
||||
// See android.os.Build source for all fields and field values' corresponding properties:
|
||||
// https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/os/Build.java
|
||||
|
||||
{
|
||||
@@ -22,5 +24,5 @@
|
||||
// System Properties
|
||||
"*.build.id": "", // for ro.build.id
|
||||
"*.security_patch": "", // for ro.build.version.security_patch
|
||||
"*api_level": "" // for ro.board.first_api_level, ro.product.first_api_level and ro.vendor.api_level
|
||||
"*api_level": "" // for ro.board.api_level, ro.board.first_api_level, ro.product.first_api_level and ro.vendor.api_level
|
||||
}
|
||||
|
||||
12
module/killgms.sh
Normal file
12
module/killgms.sh
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/system/bin/sh
|
||||
# killgms.sh by osm0sis @ xda-developers
|
||||
#
|
||||
# Kill the Google Play services DroidGuard process
|
||||
# (com.google.android.gms.unstable)
|
||||
|
||||
if [ "$USER" != "root" -a "$(whoami 2>/dev/null)" != "root" ]; then
|
||||
echo "killgms: need root permissions";
|
||||
exit 1;
|
||||
fi;
|
||||
|
||||
killall -v com.google.android.gms.unstable;
|
||||
@@ -1,40 +1,53 @@
|
||||
#!/bin/sh
|
||||
|
||||
case "$1" in
|
||||
-h|--help|help) echo "sh migrate.sh [-f] [file]"; exit 0;;
|
||||
esac;
|
||||
|
||||
N="
|
||||
";
|
||||
|
||||
case "$1" in
|
||||
-h|--help|help) echo "sh migrate.sh [-f] [-o] [-a] [in-file] [out-file]"; exit 0;;
|
||||
-i|--install|install) INSTALL=1; shift;;
|
||||
*) echo "custom.pif.json migration script \
|
||||
$N by osm0sis @ xda-developers $N";;
|
||||
$N by osm0sis @ xda-developers $N";;
|
||||
esac;
|
||||
|
||||
item() { echo "- $@"; }
|
||||
die() { [ "$INSTALL" ] || echo "$N$N! $@"; exit 1; }
|
||||
grep_get_json() { grep "$1" "$FILE" | cut -d\" -f4; }
|
||||
grep_check_json() { grep -q "$1" "$FILE" && [ "$(grep_get_json "$1")" ]; }
|
||||
grep_get_json() {
|
||||
local target="$FILE";
|
||||
[ -n "$2" ] && target="$2";
|
||||
eval set -- "$(cat "$target" | tr -d '\r\n' | grep -m1 -o "$1"'".*' | cut -d: -f2-)";
|
||||
echo "$1" | sed -e 's|"|\\\\\\"|g' -e 's|[,}]*$||';
|
||||
}
|
||||
grep_check_json() {
|
||||
local target="$FILE";
|
||||
[ -n "$2" ] && target="$2";
|
||||
grep -q "$1" "$target" && [ "$(grep_get_json $1 "$target")" ];
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
-f|--force|force) FORCE=1; shift;;
|
||||
esac;
|
||||
until [ -z "$1" -o -f "$1" ]; do
|
||||
case "$1" in
|
||||
-f|--force|force) FORCE=1; shift;;
|
||||
-o|--override|override) OVERRIDE=1; shift;;
|
||||
-a|--advanced|advanced) ADVANCED=1; shift;;
|
||||
*) die "Invalid argument/file not found: $1";;
|
||||
esac;
|
||||
done;
|
||||
|
||||
if [ -f "$1" ]; then
|
||||
FILE="$1";
|
||||
DIR="$1";
|
||||
shift;
|
||||
else
|
||||
case "$0" in
|
||||
*.sh) DIR="$0";;
|
||||
*) DIR="$(lsof -p $$ 2>/dev/null | grep -o '/.*migrate.sh$')";;
|
||||
*) DIR="$(lsof -p $$ 2>/dev/null | grep -o '/.*migrate.sh$')";;
|
||||
esac;
|
||||
fi;
|
||||
DIR=$(dirname "$(readlink -f "$DIR")");
|
||||
[ -z "$FILE" ] && FILE="$DIR/custom.pif.json";
|
||||
|
||||
OUT="$2";
|
||||
[ -z "$OUT" ] && OUT="$DIR/custom.pif.json";
|
||||
|
||||
[ -f "$FILE" ] || die "No json file found";
|
||||
|
||||
grep_check_json api_level && [ ! "$FORCE" ] && die "No migration required";
|
||||
@@ -45,9 +58,13 @@ FPFIELDS="BRAND PRODUCT DEVICE RELEASE ID INCREMENTAL TYPE TAGS";
|
||||
ALLFIELDS="MANUFACTURER MODEL FINGERPRINT $FPFIELDS SECURITY_PATCH DEVICE_INITIAL_SDK_INT";
|
||||
|
||||
for FIELD in $ALLFIELDS; do
|
||||
eval $FIELD=\"$(grep_get_json \"$FIELD\")\";
|
||||
eval $FIELD=\"$(grep_get_json $FIELD)\";
|
||||
done;
|
||||
|
||||
if [ -n "$ID" ] && ! grep_check_json build.id; then
|
||||
item 'Simple entry ID found, changing to ID field and "*.build.id" property ...';
|
||||
fi;
|
||||
|
||||
if [ -z "$ID" ] && grep_check_json BUILD_ID; then
|
||||
item 'Deprecated entry BUILD_ID found, changing to ID field and "*.build.id" property ...';
|
||||
ID="$(grep_get_json BUILD_ID)";
|
||||
@@ -58,35 +75,64 @@ if [ -n "$SECURITY_PATCH" ] && ! grep_check_json security_patch; then
|
||||
fi;
|
||||
|
||||
if grep_check_json VNDK_VERSION; then
|
||||
item 'Deprecated entry VNDK_VERSION found, changing to "*.vndk_version" property ...';
|
||||
item 'Deprecated entry VNDK_VERSION found, changing to "*.vndk.version" property ...';
|
||||
VNDK_VERSION="$(grep_get_json VNDK_VERSION)";
|
||||
fi;
|
||||
|
||||
if [ -n "$DEVICE_INITIAL_SDK_INT" ] && ! grep_check_json api_level; then
|
||||
item 'Simple entry DEVICE_INITIAL_SDK_INT found, changing to DEVICE_INITIAL_SDK_INT field and "*api_level" property ...';
|
||||
fi;
|
||||
|
||||
if [ -z "$DEVICE_INITIAL_SDK_INT" ] && grep_check_json FIRST_API_LEVEL; then
|
||||
item 'Deprecated entry FIRST_API_LEVEL found, changing to DEVICE_INITIAL_SDK_INT field and "*api_level" property ...';
|
||||
DEVICE_INITIAL_SDK_INT="$(grep_get_json FIRST_API_LEVEL)";
|
||||
fi;
|
||||
|
||||
if [ -z "$RELEASE" -o -z "$INCREMENTAL" -o -z "$TYPE" -o -z "$TAGS" ]; then
|
||||
item "Missing default fields found, deriving from FINGERPRINT ...";
|
||||
if [ -z "$RELEASE" -o -z "$INCREMENTAL" -o -z "$TYPE" -o -z "$TAGS" -o "$OVERRIDE" ]; then
|
||||
if [ "$OVERRIDE" ]; then
|
||||
item "Overriding values for fields derivable from FINGERPRINT ...";
|
||||
else
|
||||
item "Missing default fields found, deriving from FINGERPRINT ...";
|
||||
fi;
|
||||
IFS='/:' read F1 F2 F3 F4 F5 F6 F7 F8 <<EOF
|
||||
$(grep_get_json FINGERPRINT)
|
||||
EOF
|
||||
i=1;
|
||||
for FIELD in $FPFIELDS; do
|
||||
eval [ -z "\$$FIELD" ] \&\& $FIELD=\"\$F$i\";
|
||||
eval [ -z \"\$$FIELD\" -o \"$OVERRIDE\" ] \&\& $FIELD=\"\$F$i\";
|
||||
i=$((i+1));
|
||||
done;
|
||||
fi;
|
||||
|
||||
if [ -z "$SECURITY_PATCH" -o "$SECURITY_PATCH" = "null" ]; then
|
||||
item 'Missing required SECURITY_PATCH field and "*.security_patch" property value found, leaving empty ...';
|
||||
unset SECURITY_PATCH;
|
||||
fi;
|
||||
|
||||
if [ -z "$DEVICE_INITIAL_SDK_INT" -o "$DEVICE_INITIAL_SDK_INT" = "null" ]; then
|
||||
item 'Missing required DEVICE_INITIAL_SDK_INT field and "*api_level" property value found, setting to 25 ...';
|
||||
DEVICE_INITIAL_SDK_INT=25;
|
||||
fi;
|
||||
|
||||
if [ -f "$DIR/custom.pif.json" ]; then
|
||||
item "Renaming old file to custom.pif.json.bak ...";
|
||||
mv -f "$DIR/custom.pif.json" "$DIR/custom.pif.json.bak";
|
||||
ADVSETTINGS="spoofBuild spoofProps spoofProvider spoofSignature verboseLogs";
|
||||
|
||||
spoofBuild=1;
|
||||
spoofProps=1;
|
||||
spoofProvider=1;
|
||||
spoofSignature=0;
|
||||
verboseLogs=0;
|
||||
|
||||
if [ -f "$OUT" ]; then
|
||||
item "Renaming old file to $(basename "$OUT").bak ...";
|
||||
mv -f "$OUT" "$OUT.bak";
|
||||
if grep -qE "verboseLogs|VERBOSE_LOGS" "$OUT.bak"; then
|
||||
ADVANCED=1;
|
||||
grep_check_json VERBOSE_LOGS "$OUT.bak" && verboseLogs="$(grep_get_json VERBOSE_LOGS "$OUT.bak")";
|
||||
for SETTING in $ADVSETTINGS; do
|
||||
eval grep_check_json $SETTING \"$OUT.bak\" \&\& $SETTING=\"$(grep_get_json $SETTING "$OUT.bak")\";
|
||||
done;
|
||||
grep -q '//"\*.security_patch"' "$OUT.bak" && SECURITY_COMMENT='//';
|
||||
fi;
|
||||
fi;
|
||||
|
||||
[ "$INSTALL" ] || item "Writing fields and properties to updated custom.pif.json ...";
|
||||
@@ -98,10 +144,14 @@ for FIELD in $ALLFIELDS; do
|
||||
done;
|
||||
echo "$N // System Properties";
|
||||
echo ' "*.build.id": "'$ID'",';
|
||||
echo ' "*.security_patch": "'$SECURITY_PATCH'",';
|
||||
[ -z "$VNDK_VERSION" ] || echo ' "*.vndk_version": "'$VNDK_VERSION'",';
|
||||
echo ' "*api_level": "'$DEVICE_INITIAL_SDK_INT'"';
|
||||
echo "}") > "$DIR/custom.pif.json";
|
||||
|
||||
[ "$INSTALL" ] || cat "$DIR/custom.pif.json";
|
||||
echo " $SECURITY_COMMENT"'"*.security_patch": "'$SECURITY_PATCH'",';
|
||||
[ -z "$VNDK_VERSION" ] || echo ' "*.vndk.version": "'$VNDK_VERSION'",';
|
||||
echo ' "*api_level": "'$DEVICE_INITIAL_SDK_INT'",';
|
||||
if [ "$ADVANCED" ]; then
|
||||
echo "$N // Advanced Settings";
|
||||
for SETTING in $ADVSETTINGS; do
|
||||
eval echo '\ \ \ \ \"$SETTING\": \"'\$$SETTING'\",';
|
||||
done;
|
||||
fi) | sed '$s/,/\n}/' > "$OUT";
|
||||
|
||||
[ "$INSTALL" ] || cat "$OUT";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
id=playintegrityfix
|
||||
name=Play Integrity Fork
|
||||
version=v7
|
||||
versionCode=70000
|
||||
version=v11
|
||||
versionCode=110000
|
||||
author=osm0sis & chiteroman @ xda-developers
|
||||
description=Fix CTS profile (SafetyNet) and DEVICE verdict (Play Integrity)
|
||||
description=Fix ctsProfile (SafetyNet) and DEVICE (Play Integrity) verdicts
|
||||
updateJson=https://raw.githubusercontent.com/osm0sis/PlayIntegrityFork/main/update.json
|
||||
|
||||
@@ -1,33 +1,17 @@
|
||||
MODDIR="${0%/*}"
|
||||
. "$MODDIR/common.sh"
|
||||
MODPATH="${0%/*}"
|
||||
. $MODPATH/common_func.sh
|
||||
|
||||
# Remove Play Services from Magisk Denylist when set to enforcing
|
||||
if magisk --denylist status; then
|
||||
magisk --denylist rm com.google.android.gms
|
||||
fi
|
||||
|
||||
# Remove conflicting modules if installed
|
||||
if [ -d /data/adb/modules/safetynet-fix ]; then
|
||||
touch /data/adb/modules/safetynet-fix/remove
|
||||
fi
|
||||
|
||||
# Replace conflicting custom ROM injection app folders to disable them
|
||||
LIST=$MODDIR/example.app_replace.list
|
||||
[ -f "$MODDIR/custom.app_replace.list" ] && LIST=$MODDIR/custom.app_replace.list
|
||||
for APP in $(grep -v '^#' $LIST); do
|
||||
if [ -d "$APP" ]; then
|
||||
case $APP in
|
||||
/system/*) HIDEDIR=$MODDIR/$APP;;
|
||||
*) HIDEDIR=$MODDIR/system/$APP;;
|
||||
esac
|
||||
mkdir -p $HIDEDIR
|
||||
if [ "$KSU" = "true" -o "$APATCH" = "true" ]; then
|
||||
setfattr -n trusted.overlay.opaque -v y $HIDEDIR
|
||||
else
|
||||
touch $HIDEDIR/.replace
|
||||
fi
|
||||
if [ -d "$MODPATH/zygisk" ]; then
|
||||
# Remove Play Services from Magisk DenyList when set to Enforce in normal mode
|
||||
if magisk --denylist status; then
|
||||
magisk --denylist rm com.google.android.gms
|
||||
fi
|
||||
done
|
||||
# Run common tasks for installation and boot-time
|
||||
. $MODPATH/common_setup.sh
|
||||
else
|
||||
# Add Play Services DroidGuard process to Magisk DenyList for better results in scripts-only mode
|
||||
magisk --denylist add com.google.android.gms com.google.android.gms.unstable
|
||||
fi
|
||||
|
||||
# Conditional early sensitive properties
|
||||
|
||||
@@ -37,19 +21,22 @@ resetprop_if_diff ro.vendor.boot.warranty_bit 0
|
||||
resetprop_if_diff ro.vendor.warranty_bit 0
|
||||
resetprop_if_diff ro.warranty_bit 0
|
||||
|
||||
# Xiaomi
|
||||
resetprop_if_diff ro.secureboot.lockstate locked
|
||||
|
||||
# Realme
|
||||
resetprop_if_diff ro.boot.realmebootstate green
|
||||
|
||||
# OnePlus
|
||||
resetprop_if_diff ro.is_ever_orange 0
|
||||
|
||||
# Microsoft, RootBeer
|
||||
resetprop_if_diff ro.build.tags release-keys
|
||||
# Microsoft
|
||||
for PROP in $(resetprop | grep -oE 'ro.*.build.tags'); do
|
||||
resetprop_if_diff $PROP release-keys
|
||||
done
|
||||
|
||||
# Other
|
||||
resetprop_if_diff ro.build.type user
|
||||
for PROP in $(resetprop | grep -oE 'ro.*.build.type'); do
|
||||
resetprop_if_diff $PROP user
|
||||
done
|
||||
resetprop_if_diff ro.adb.secure 1
|
||||
resetprop_if_diff ro.debuggable 0
|
||||
resetprop_if_diff ro.force.debuggable 0
|
||||
resetprop_if_diff ro.secure 1
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
MODDIR="${0%/*}"
|
||||
. "$MODDIR/common.sh"
|
||||
MODPATH="${0%/*}"
|
||||
. $MODPATH/common_func.sh
|
||||
|
||||
# Conditional sensitive properties
|
||||
|
||||
# Magisk recovery mode
|
||||
resetprop_if_match ro.bootmode recovery unknown
|
||||
# Magisk Recovery Mode
|
||||
resetprop_if_match ro.boot.mode recovery unknown
|
||||
resetprop_if_match ro.bootmode recovery unknown
|
||||
resetprop_if_match vendor.boot.mode recovery unknown
|
||||
|
||||
# SELinux
|
||||
@@ -14,33 +14,36 @@ resetprop_if_diff ro.boot.selinux enforcing
|
||||
if [ -n "$(resetprop ro.build.selinux)" ]; then
|
||||
resetprop --delete ro.build.selinux
|
||||
fi
|
||||
# use toybox to protect *stat* access time reading
|
||||
if [ "$(toybox cat /sys/fs/selinux/enforce)" == "0" ]; then
|
||||
# use toybox to protect stat access time reading
|
||||
if [ "$(toybox cat /sys/fs/selinux/enforce)" = "0" ]; then
|
||||
chmod 640 /sys/fs/selinux/enforce
|
||||
chmod 440 /sys/fs/selinux/policy
|
||||
fi
|
||||
|
||||
# Conditional late sensitive properties
|
||||
|
||||
# SafetyNet/Play Integrity
|
||||
# must be set after boot_completed for various OEMs
|
||||
{
|
||||
# must be set after boot_completed for various OEMs
|
||||
until [ "$(getprop sys.boot_completed)" == "1" ]; do
|
||||
sleep 1
|
||||
done
|
||||
until [ "$(getprop sys.boot_completed)" = "1" ]; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# avoid breaking Realme fingerprint scanners
|
||||
resetprop_if_diff ro.boot.flash.locked 1
|
||||
resetprop_if_diff ro.boot.realme.lockstate 1
|
||||
# SafetyNet/Play Integrity + OEM
|
||||
# avoid bootloop on some Xiaomi devices
|
||||
resetprop_if_diff ro.secureboot.lockstate locked
|
||||
# avoid breaking Realme fingerprint scanners
|
||||
resetprop_if_diff ro.boot.flash.locked 1
|
||||
resetprop_if_diff ro.boot.realme.lockstate 1
|
||||
# avoid breaking Oppo fingerprint scanners
|
||||
resetprop_if_diff ro.boot.vbmeta.device_state locked
|
||||
# avoid breaking OnePlus display modes/fingerprint scanners
|
||||
resetprop_if_diff vendor.boot.verifiedbootstate green
|
||||
# avoid breaking OnePlus/Oppo fingerprint scanners on OOS/ColorOS 12+
|
||||
resetprop_if_diff ro.boot.verifiedbootstate green
|
||||
resetprop_if_diff ro.boot.veritymode enforcing
|
||||
resetprop_if_diff vendor.boot.vbmeta.device_state locked
|
||||
|
||||
# avoid breaking Oppo fingerprint scanners
|
||||
resetprop_if_diff ro.boot.vbmeta.device_state locked
|
||||
# Other
|
||||
resetprop_if_diff sys.oem_unlock_allowed 0
|
||||
|
||||
# avoid breaking OnePlus display modes/fingerprint scanners
|
||||
resetprop_if_diff vendor.boot.verifiedbootstate green
|
||||
|
||||
# avoid breaking OnePlus/Oppo display fingerprint scanners on OOS/ColorOS 12+
|
||||
resetprop_if_diff ro.boot.verifiedbootstate green
|
||||
resetprop_if_diff ro.boot.veritymode enforcing
|
||||
resetprop_if_diff vendor.boot.vbmeta.device_state locked
|
||||
}&
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"version": "v7",
|
||||
"versionCode": 70000,
|
||||
"zipUrl": "https://github.com/osm0sis/PlayIntegrityFork/releases/download/v7/PlayIntegrityFork-v7.zip",
|
||||
"version": "v11",
|
||||
"versionCode": 110000,
|
||||
"zipUrl": "https://github.com/osm0sis/PlayIntegrityFork/releases/download/v11/PlayIntegrityFork-v11.zip",
|
||||
"changelog": "https://raw.githubusercontent.com/osm0sis/PlayIntegrityFork/main/CHANGELOG.md"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user