You've already forked PlayIntegrityFork
mirror of
https://github.com/osm0sis/PlayIntegrityFork.git
synced 2025-09-06 06:37:06 +00:00
Compare commits
339 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5cef27ffa9 | ||
|
|
6dffba43ab | ||
|
|
8558751cc7 | ||
|
|
0a216e0cd9 | ||
|
|
6506283874 | ||
|
|
8f06a06659 | ||
|
|
1b99917151 | ||
|
|
b92e80fbc6 | ||
|
|
ed8501d857 | ||
|
|
9c6f065bb6 | ||
|
|
ffd8d77d6f | ||
|
|
3c9c13e3ff | ||
|
|
bee383bb99 | ||
|
|
b4bdc5bafc | ||
|
|
58664b2294 | ||
|
|
cc74eebd33 | ||
|
|
b08dba14ea | ||
|
|
9cea06e64d | ||
|
|
4a14d97c24 | ||
|
|
dd44d2c1a8 | ||
|
|
a9eca199b6 | ||
|
|
abe81968db | ||
|
|
6cde52fc8a | ||
|
|
18eeb7d92d | ||
|
|
7ec4d37949 | ||
|
|
72e2124a8e | ||
|
|
8cd6155ffb | ||
|
|
c9d4064dfe | ||
|
|
a99ebc6689 | ||
|
|
ed312200cb | ||
|
|
0a964415f3 | ||
|
|
f12b85d67f | ||
|
|
59a1eea076 | ||
|
|
51619d2de4 | ||
|
|
fcb6a2df3e | ||
|
|
1afd4278be | ||
|
|
77d5ccdc99 | ||
|
|
a2f726b633 | ||
|
|
38631f685a | ||
|
|
39d2610579 | ||
|
|
0132ebb272 | ||
|
|
a82914221e | ||
|
|
4755f88180 | ||
|
|
62150ce6d4 | ||
|
|
88573ca743 | ||
|
|
89de098a83 | ||
|
|
c6739dfa42 | ||
|
|
a7dd416873 | ||
|
|
539ff7351a | ||
|
|
0cd56584df | ||
|
|
2cdee60781 | ||
|
|
7e376e5627 | ||
|
|
ec34417cd9 | ||
|
|
0b957b13b9 | ||
|
|
ec374a7d9b | ||
|
|
17db1e7177 | ||
|
|
451769c341 | ||
|
|
77f91e3a85 | ||
|
|
b4eae8a6b6 | ||
|
|
05520f7881 | ||
|
|
1745060524 | ||
|
|
512ed8a1f1 | ||
|
|
0d8d090014 | ||
|
|
0d03f99499 | ||
|
|
85dd219ea3 | ||
|
|
36cc9573ba | ||
|
|
d72fc9ee04 | ||
|
|
84adafc3ac | ||
|
|
cb49481c45 | ||
|
|
b5a9b26b70 | ||
|
|
39922653db | ||
|
|
58f2c2de57 | ||
|
|
e858134828 | ||
|
|
fafaf418e4 | ||
|
|
da758bc33c | ||
|
|
d66260c3f6 | ||
|
|
1a01e35862 | ||
|
|
028e94e71b | ||
|
|
9e04c5cc5b | ||
|
|
46e5e0a6d2 | ||
|
|
d2db871892 | ||
|
|
7e7812bede | ||
|
|
c2af0fcad5 | ||
|
|
1493650b65 | ||
|
|
3f62cb6a3a | ||
|
|
5daf1b933e | ||
|
|
e8375a02d1 | ||
|
|
fa937983e8 | ||
|
|
83b9d96ce4 | ||
|
|
4bcf51ccfd | ||
|
|
e653659895 | ||
|
|
11e2629a26 | ||
|
|
8805c3736d | ||
|
|
a52cc16b43 | ||
|
|
4740d2048d | ||
|
|
e2b8a3c4b0 | ||
|
|
4dbe12ae58 | ||
|
|
996981a8e7 | ||
|
|
d278b77ced | ||
|
|
a3f68d392e | ||
|
|
9b3801a117 | ||
|
|
df5d5b7ce9 | ||
|
|
b644573e52 | ||
|
|
3e30d553c9 | ||
|
|
8a64752923 | ||
|
|
264a218a79 | ||
|
|
59781b1682 | ||
|
|
a4c8aab031 | ||
|
|
abe69d201b | ||
|
|
da0fad725a | ||
|
|
d9794b2017 | ||
|
|
d08ca33633 | ||
|
|
a7ba40a36c | ||
|
|
140c32befd | ||
|
|
6fc3200df2 | ||
|
|
c3ee7e5c0a | ||
|
|
c635a9e3ba | ||
|
|
8ddab06840 | ||
|
|
16002e28c6 | ||
|
|
148dea0344 | ||
|
|
e01b3b5ada | ||
|
|
4666737242 | ||
|
|
cd32f0cb0a | ||
|
|
4e96fdef9d | ||
|
|
19d31cffea | ||
|
|
1edc85dec4 | ||
|
|
f351c97b2b | ||
|
|
0de5574d53 | ||
|
|
3f346f3735 | ||
|
|
b83de28f0b | ||
|
|
bc591c5732 | ||
|
|
7233c66f8a | ||
|
|
78dd16ae09 | ||
|
|
240a52b558 | ||
|
|
785622321e | ||
|
|
565d895a96 | ||
|
|
7dd9ed8f1d | ||
|
|
2e74733319 | ||
|
|
153aefbe57 | ||
|
|
91231e12f2 | ||
|
|
787936d94f | ||
|
|
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 | ||
|
|
594ac7c8ac | ||
|
|
b8e68d059e | ||
|
|
198c2e5486 | ||
|
|
919526bcd7 | ||
|
|
0b34f95282 | ||
|
|
63e4c571bf | ||
|
|
bdcfd283f1 | ||
|
|
dbd60afe68 | ||
|
|
e2cb4e1523 | ||
|
|
5901844ce3 | ||
|
|
efb8ee930a | ||
|
|
d36b35b7e9 | ||
|
|
4c08eb1e42 | ||
|
|
2fa007afa3 | ||
|
|
05c2474963 | ||
|
|
e0931c829d | ||
|
|
b57f46eed0 | ||
|
|
73d89d7a50 | ||
|
|
475185c3ee | ||
|
|
802c0a7617 | ||
|
|
9a24cd6f23 | ||
|
|
22e3a14a6f | ||
|
|
24db525cf3 | ||
|
|
21a309dd12 | ||
|
|
05927c60e1 | ||
|
|
008c0d0ada | ||
|
|
93ac718229 | ||
|
|
5aea2e877f | ||
|
|
d106e2a964 | ||
|
|
a9630901b3 | ||
|
|
d7090f3f73 | ||
|
|
3088f4b179 | ||
|
|
9673971b70 | ||
|
|
f6a9f855ef | ||
|
|
edcb94e179 | ||
|
|
a3cbed9a4e | ||
|
|
e9b7289950 | ||
|
|
63fab9cca7 | ||
|
|
c3ff39c00d | ||
|
|
29a97b49e3 | ||
|
|
38f8861f30 | ||
|
|
63e4191745 | ||
|
|
6f8706a817 | ||
|
|
89348bb75c | ||
|
|
dc10cae2b6 | ||
|
|
18ecfd6e32 | ||
|
|
676c5047b9 | ||
|
|
cff8ca8b61 |
32
.github/workflows/android.yml
vendored
32
.github/workflows/android.yml
vendored
@@ -1,37 +1,41 @@
|
||||
name: Android CI
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
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-15
|
||||
|
||||
steps:
|
||||
- name: Check out
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: "recursive"
|
||||
submodules: 'recursive'
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
java-version: 21
|
||||
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
|
||||
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew assembleRelease
|
||||
|
||||
run: ./gradlew --warning-mode all assembleRelease
|
||||
|
||||
- name: Upload CI module zip as artifact zip
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: PlayIntegrityFork-CI
|
||||
path: module/*
|
||||
name: PlayIntegrityFork-CI_#${{ github.run_number }}
|
||||
path: 'module/*'
|
||||
compression-level: 9
|
||||
|
||||
15
.gitmodules
vendored
15
.gitmodules
vendored
@@ -1,6 +1,9 @@
|
||||
[submodule "libcxx"]
|
||||
path = app/src/main/cpp/libcxx
|
||||
url = https://github.com/topjohnwu/libcxx.git
|
||||
[submodule "shadowhook"]
|
||||
path = app/src/main/cpp/shadowhook
|
||||
url = https://github.com/bytedance/android-inline-hook
|
||||
[submodule "Dobby"]
|
||||
path = app/src/main/cpp/Dobby
|
||||
url = https://github.com/JingMatrix/Dobby
|
||||
[submodule "local_cxa_atexit_finalize_impl"]
|
||||
path = app/src/main/cpp/local_cxa_atexit_finalize_impl
|
||||
url = https://github.com/5ec1cff/local_cxa_atexit_finalize_impl
|
||||
[submodule "json"]
|
||||
path = app/src/main/cpp/json
|
||||
url = https://github.com/nlohmann/json
|
||||
|
||||
2
.idea/compiler.xml
generated
2
.idea/compiler.xml
generated
@@ -3,4 +3,4 @@
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="17" />
|
||||
</component>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
2
.idea/deploymentTargetDropDown.xml
generated
2
.idea/deploymentTargetDropDown.xml
generated
@@ -7,4 +7,4 @@
|
||||
</entry>
|
||||
</value>
|
||||
</component>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
2
.idea/gradle.xml
generated
2
.idea/gradle.xml
generated
@@ -16,4 +16,4 @@
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
2
.idea/inspectionProfiles/Project_Default.xml
generated
2
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -7,4 +7,4 @@
|
||||
<option name="processComments" value="true" />
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
||||
</component>
|
||||
|
||||
2
.idea/inspectionProfiles/profiles_settings.xml
generated
2
.idea/inspectionProfiles/profiles_settings.xml
generated
@@ -3,4 +3,4 @@
|
||||
<option name="PROJECT_PROFILE" value="Default" />
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
</settings>
|
||||
</component>
|
||||
</component>
|
||||
|
||||
2
.idea/migrations.xml
generated
2
.idea/migrations.xml
generated
@@ -7,4 +7,4 @@
|
||||
</set>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -6,4 +6,4 @@
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="Android" />
|
||||
</component>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
4
.idea/vcs.xml
generated
4
.idea/vcs.xml
generated
@@ -2,6 +2,6 @@
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/app/src/main/cpp/libcxx" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/app/src/main/cpp/Dobby" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
36
CHANGELOG.md
36
CHANGELOG.md
@@ -1,16 +1,24 @@
|
||||
# Custom Fork v4
|
||||
- Very verbose logging (for now)
|
||||
- Allow spoofing literally any field from android.os.Build or android.os.Build.VERSION
|
||||
- Add BUILD_ID and VNDK_VERSION support to keep cross-fork API compatibility
|
||||
- Add exceptions for FIRST_API_VERSION (actually DEVICE_INITIAL_SDK_INT) and BUILD_ID (actually ID) for backwards API compatibility
|
||||
- Add empty example.pif.json with reference link
|
||||
- Fix GMS crashes if a null/bad value was read from json
|
||||
## Custom Fork v14
|
||||
|
||||
# Custom Fork v3
|
||||
- Combine system.prop (runs at post-fs-data) entries into service.sh so that they're only set if needed
|
||||
- Clean up GMS data pif.prop/pif.json files left over from previous releases to ensure they don't trigger detection
|
||||
- Use custom.pif.json for custom spoofing if it exists, self-contained in the module directory, and restore it after module updates
|
||||
- Move props that need to be changed earlier into post-fs-data.sh
|
||||
- Warn of possible conflict if MagiskHidePropsConfig (MHPC) is installed
|
||||
- Continue to use ShadowHook for now
|
||||
- Add cleaning modified custom ROM persist props on uninstall
|
||||
- Add opt-out props and detection for more PIH variants
|
||||
- Fix spoofSignature crash when built with AGP 8.9+
|
||||
- Add experimental spoofVendingSdk to Advanced Settings
|
||||
- Update Action and install migrate to show Advanced Settings
|
||||
- Improve Action to match device print on Pixel devices
|
||||
- Improve ROM overlay xml disabling support (PixelOS 15)
|
||||
- Add TS security_patch.txt Simple format support
|
||||
- Update Action for Strong since Pixel Beta no longer pass Device
|
||||
|
||||
## Custom Fork v13
|
||||
|
||||
- Improve Action on KSU/APatch, KSU-Next, MMRL
|
||||
- Remove unnecessary adb props spoof
|
||||
- Add all known opt-out props for PPU/PIH variants/hybrids
|
||||
- Add new verified boot error props deletion
|
||||
- Update killgms to killpi
|
||||
- Improve autopif2 to populate TS's optional security_patch.txt
|
||||
- Improve ROM overlay xml disabling support (YAAP)
|
||||
- Improve autopif2 for wget2 on arm
|
||||
|
||||
_[Full changelogs](https://github.com/osm0sis/PlayIntegrityFork/releases)_
|
||||
|
||||
192
README.md
192
README.md
@@ -1,77 +1,199 @@
|
||||
# Play Integrity Fork
|
||||
*PIF forked to bring back the custom.pif.json restore feature and develop more methodically*
|
||||
*PIF forked to be more futureproof and develop more methodically*
|
||||
|
||||
A Zygisk module which fixes "ctsProfileMatch" (SafetyNet) and "MEETS_DEVICE_INTEGRITY" (Play Integrity).
|
||||
[](https://github.com/osm0sis/PlayIntegrityFork/releases/latest)
|
||||
[](https://github.com/osm0sis/PlayIntegrityFork/releases)
|
||||
[](https://github.com/osm0sis/PlayIntegrityFork/releases/latest)
|
||||
[](https://github.com/osm0sis/PlayIntegrityFork/releases)
|
||||
|
||||
To use this module you must have one of the following:
|
||||
A Zygisk module which fixes "MEETS_DEVICE_INTEGRITY" for the Android <13 "deviceRecognitionVerdict" of the Play Integrity API. On Android 13+ ROMs it still helps to pass checks in Google Wallet and Google Messages RCS support.
|
||||
|
||||
- Magisk with Zygisk enabled.
|
||||
- KernelSU with [ZygiskNext](https://github.com/Dr-TSNG/ZygiskNext) module installed.
|
||||
To use this module you must have one of the following (latest versions):
|
||||
|
||||
- [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?tab=readme-ov-file#shamiko) or [Zygisk Assistant](https://github.com/snake-4/Zygisk-Assistant) or [NoHello](https://github.com/MhmRdd/NoHello), for best results)
|
||||
- [KernelSU](https://github.com/tiann/KernelSU) with [Zygisk Next](https://github.com/Dr-TSNG/ZygiskNext) or [ReZygisk](https://github.com/PerformanC/ReZygisk) or [NeoZygisk](https://github.com/JingMatrix/NeoZygisk) module installed
|
||||
- [KernelSU Next](https://github.com/KernelSU-Next/KernelSU-Next) with [Zygisk Next](https://github.com/Dr-TSNG/ZygiskNext) or [ReZygisk](https://github.com/PerformanC/ReZygisk) or [NeoZygisk](https://github.com/JingMatrix/NeoZygisk) module installed
|
||||
- [APatch](https://github.com/bmax121/APatch) with [Zygisk Next](https://github.com/Dr-TSNG/ZygiskNext) or [ReZygisk](https://github.com/PerformanC/ReZygisk) or [NeoZygisk](https://github.com/JingMatrix/NeoZygisk) 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 (Play Integrity) service.
|
||||
|
||||
The purpose of the module is to avoid hardware attestation.
|
||||
Note: Unless otherwise stated, verdicts here are all referring to the Android <13 Play Integrity "deviceRecognitionVerdict" (or "<A13 PI") which was formerly SafetyNet "ctsProfileMatch", not the Android 13+ Play Integrity "deviceRecognitionVerdict" (or "A13+ PI") which relies on locked bootloader checks to pass even DEVICE integrity.
|
||||
|
||||
## About 'custom.pif.json' file
|
||||
## Configuration
|
||||
|
||||
You can create this file in the module directory to spoof custom values to the GMS unstable process. It will be used instead of any included pif.json.
|
||||
The module is configured by editing json/list (text) files in the module directory (/data/adb/modules/playintegrityfix), by running one of the included scripts there, or by creating a file there to enable some advanced features. These are most easily done using the root file explorer app of your choice, as all should include a file editor and support script execution. The scripts also support command line arguments, which may be added when run from a root file explorer app, or when run in a root (su) shell from adb or a terminal emulator app. Unless otherwise stated, configuration changes will take effect after running the killpi.sh script to restart the Play Integrity (PI) processes, or you may also reboot.
|
||||
|
||||
You can't use values from recent devices due them triggering hardware backed 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) then rename it to custom.pif.json to spoof your own custom values. It will be used instead of any included pif.json (none included currently).
|
||||
|
||||
Note this is just a template with the current suggested default entries, 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 integrity now and in the future if the checks enforced by Play Integrity change.
|
||||
|
||||
As a general rule you can't use values from recent devices due to them only being allowed with full hardware backed attestation, but sets of these values can still be found which pass DEVICE integrity, and still others can also pass STRONG integrity when [setup correctly](#about-spoofing-advanced-settings). These are known as "private fingerprints" since widely publicly shared ones will get banned by Google. A script to extract a random latest Pixel Beta fingerprint is included with the module; see the autopif2 section below for usage and caveats, and expand 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 in the module directory with a custom.pif.json present by running migrate.sh with the `-a` or `--advanced` argument (to add Advanced Settings) in a file explorer app or with `sh migrate.sh --advanced` in a root shell, and `-f` or `--force` if desired.
|
||||
|
||||
<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
|
||||
|
||||
- Apps:
|
||||
- [FP BETA Checker](https://xdaforums.com/t/tricky-store-bootloader-keybox-spoofing.4683446/post-89754890) - Tasker App to check the estimated expiry of the Pixel Beta fingerprint and trigger autopif2.sh to update
|
||||
- [FP XEU Checker](https://xdaforums.com/t/module-play-integrity-fix-safetynet-fix.4607985/post-89390931) - Tasker App to check for a new Xiaomi.eu public fingerprint and trigger autopif.sh to update
|
||||
|
||||
</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) then rename it to custom.app_replace.list to systemlessly replace any additional conflicting custom ROM spoof injection app paths to disable them. Changes take effect after a reboot.
|
||||
|
||||
### About 'autopif2.sh' and 'killpi.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/expired within days of release 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 (since very few remain) then simply run the generation script from a root manager app that supports the module Action button, or by running autopif.sh with the `-s -p` or `--strong --preview` arguments in a file explorer app or with `sh autopif2.sh --strong --preview` in a root shell. For arm/x86 devices wget2 is required but may be installed via [addon module](https://xdaforums.com/t/tools-zips-scripts-osm0sis-odds-and-ends-multiple-devices-platforms.2239421/post-89991315).
|
||||
|
||||
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 custom ROMs may also get banned, or may be banned for RCS use while otherwise passing Play Integrity in that time. In addition, unfortunately Pixel Beta fingerprints have changed and no longer pass DEVICE integrity, so can now only be used for STRONG integrity [setups](#about-spoofing-advanced-settings). Notable advanced command line arguments are: `-m` or `--match` matches the Pixel Beta fingerprint to the device when run on a current Pixel device; `-p` or `--preview` forces not to ignore Android Platform Preview builds (Developer Previews and Betas); and `-d #` or `--depth #` chooses the depth to crawl down the QPR Betas list when there are multiple active Betas, e.g. when QPR2 is concurrent with QPR1 the default value of 1 would get the first listed (QPR2) and `-d 2` would force it to get the second listed (QPR1).
|
||||
|
||||
The killpi script forces the Google Play Services DroidGuard (com.google.android.gms.unstable) and Play Store (com.android.vending) processes to end, making them restart with the next attestation attempt; useful for testing out different fingerprints without requiring a reboot in between.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Failing BASIC verdict
|
||||
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.
|
||||
|
||||
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:
|
||||
Note: To test <A13 PI verdicts on an A13+ ROM the spoofVendingSdk option in the custom.pif.json Advanced Settings must be temporarily enabled. See the spoofing Advanced Settings section below.
|
||||
|
||||
### Failing BASIC integrity
|
||||
|
||||
If you are failing MEETS_BASIC_INTEGRITY something is wrong in your setup. Recommended steps in order to find the problem:
|
||||
|
||||
- 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 Google Play Services (GMS) processes (e.g. custom fonts).
|
||||
|
||||
### Failing DEVICE verdict (on KernelSU)
|
||||
### Failing DEVICE integrity (on KernelSU/KernelSU Next/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 integrity (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
|
||||
|
||||
- Flash the module in Magisk/KernelSU
|
||||
- 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)
|
||||
### Failing DEVICE integrity (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
|
||||
- Pixel Beta fingerprints and some private fingerprints appear to be exempt from this testkey ROM ban
|
||||
- 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
|
||||
|
||||
- Reflash the module in your root manager app
|
||||
- Clear Google Play Store (com.android.vending) and, if present, Google Play Protect Service (com.google.android.odad) cache and data
|
||||
- Reboot
|
||||
|
||||
### Failing Google Messages RCS setup or failing to send messages
|
||||
|
||||
- Reflash the module in your root manager app
|
||||
- Try a different (ideally known working) custom.pif.json
|
||||
- Clear Google Messages (com.google.android.apps.messaging) cache and data
|
||||
- Reboot
|
||||
|
||||
Note: RCS is most easily checked using Gemini in Messages and usually clearing Messages app data is not required.
|
||||
|
||||
### Failing Google Wallet Tap To Pay Setup Security Requirements
|
||||
|
||||
- Reflash the module in your root manager app
|
||||
- Ensure you are passing <A13 PI DEVICE or higher integrity. Wallet requires this verdict even on A13+ ROMs as it is checked/enforced in the background.
|
||||
- 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 Services (com.google.android.gms) cache and data, or, optionally skip clearing data and wait some time (24-72h) 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.
|
||||
|
||||
### Read module logs
|
||||
|
||||
You can read module logs using this command directly after boot:
|
||||
You can read module logs using one of these commands directly after boot:
|
||||
|
||||
```
|
||||
adb shell "logcat | grep 'PIF'"
|
||||
```
|
||||
`adb shell "logcat | grep 'PIF/'"` or `su -c "logcat | grep 'PIF/'"`
|
||||
|
||||
Adjust the Advanced Settings "verboseLogs" entry to a value of "0", "1", "2", "3" or "100" in your custom.pif.json to enable higher logging levels; "100" will dump all Build fields and all system properties that DroidGuard is checking.
|
||||
|
||||
## Can this module pass MEETS_STRONG_INTEGRITY?
|
||||
|
||||
No.
|
||||
[No...](#about-spoofing-advanced-settings)
|
||||
|
||||
## 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 to Play Integrity (PI), allowing one to disable the parts that may conflict with other kinds of spoofing modules, and provides options to force a device to use <A13 PI verdicts or work around the testkey ROM ban for those needing those features. See more in the Details area below.
|
||||
|
||||
<details>
|
||||
<summary><strong>Details</strong></summary>
|
||||
|
||||
- The Advanced Settings entries are present by default from autopif2 or migrate (during installation), but may be added to any fingerprint by running migrate.sh with the `-f -a` or `--force --advanced` arguments in a file explorer app or with `sh migrate.sh --force --advanced` in a root shell. They may also be configured directly for Tricky Store to achieve <A13 PI STRONG or A13+ PI DEVICE/STRONG integrity (see below) by running autopif2.sh with the `-s -p` or `--strong --preview` arguments in a file explorer app or with `sh autopif2.sh --strong --preview` in a root shell. 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; the "spoofSignature" entry (default 0) controls spoofing the ROM Signature, and the "spoofVendingSdk" entry (default 0) controls spoofing ROM SDK_INT/sdkVersion 32 to the Play Store (com.android.vending) to force Play Integrity to use the <A13 PI verdicts.
|
||||
|
||||
- Leaving spoofVendingSdk enabled is NOT recommended, it [will break](https://github.com/osm0sis/PlayIntegrityFork/pull/30) the behavior of the Play Store to some extent (back gesture/navbar button for all, account sign-in and downloads for higher original ROM SDK_INT) and could have other unintended effects like incorrect app variants being served, crashes, etc. Play Store must be fully set up before (and data not cleared during) enabling spoofVendingSdk or it and PI checks will only crash/hang. One possible use case is with the [spoofVendingSdk QSTile](https://xdaforums.com/t/tricky-store-bootloader-keybox-spoofing.4683446/post-90118016) Tasker App to quickly toggle it on only as needed, then toggle it off again afterward.
|
||||
|
||||
- For spoofing locked bootloader and attempting to pass <A13 PI STRONG integrity, or A13+ PI DEVICE or STRONG integrity, I only recommend using the latest official [Tricky Store](https://github.com/5ec1cff/TrickyStore) or [Tricky Store OSS](https://github.com/beakthoven/TrickyStoreOSS) release.
|
||||
|
||||
- Note: Using Tricky Store to achieve <A13 PI STRONG integrity (with an unrevoked hardware keybox.xml), requires the Advanced Settings "spoofProvider" disabled and sometimes the "\*.security_patch" entry commented out (often unless spoofing a matching OS Patch Level with system= or all= or Simple date in Tricky Store's security_patch.txt; autopif2 will do this automatically if security_patch.txt exists in the Tricky Store directory), and/or "\*api_level" entry set >25 (usually 26-32). To achieve <A13 PI DEVICE integrity (with Tricky Store default AOSP software keybox.xml) requires at least "spoofProps" enabled, and some fingerprints may also require "spoofProvider" enabled and/or "\*api_level" entry lowered to <26 (usually 21-25). More known working private fingerprints can achieve <A13 PI 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 <A13 PI DEVICE integrity. 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) or [NoHello](https://github.com/MhmRdd/NoHello). 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 skipping property deletion
|
||||
|
||||
An advanced feature (unrelated to Play Integrity) intended for those who also need to use apps which detect prop tampering. To avoid triggering these detections by skipping any `resetprop --delete` commands in the module scripts, manually opt-in by creating a file named skipdelprop in the module directory after installation, either from a root prompt with `touch /data/adb/modules/playintegrityfix/skipdelprop` or from a file explorer app, then reboot.
|
||||
|
||||
## About Play Integrity (SafetyNet has been shut down)
|
||||
|
||||
[Play Integrity API](https://xdaforums.com/t/info-play-integrity-api-replacement-for-safetynet.4479337/) - FAQ/information about PI (Play Integrity) replacing SN (SafetyNet)
|
||||
|
||||
[Play Integrity Improved Verdicts](https://developer.android.com/google/play/integrity/improvements) - Information about the more secure verdicts for Android 13+ ROMs (also see the spoofing Advanced Settings section above)
|
||||
|
||||
## Credits
|
||||
|
||||
Module scripts were adapted from those of kdrag0n/Displax's Universal SafetyNet Fix (USNF) module, please see the commit history of [Displax's USNF Fork](https://github.com/Displax/safetynet-fix/tree/dev/magisk) for proper attribution.
|
||||
Forked from chiteroman's [Play Integrity Fix (PIF)](https://github.com/chiteroman/PlayIntegrityFix) (no longer online).
|
||||
|
||||
Original concept and general mechanism of PIF from kdrag0n's [ProtonAOSP](https://protonaosp.org/) and [Universal SafetyNet Fix (USNF)](https://github.com/kdrag0n/safetynet-fix) projects.
|
||||
|
||||
Module boot scripts adapted from those of Displax's forked [Universal SafetyNet Fix (USNF MOD)](https://github.com/Displax/safetynet-fix); please see the module files [commit history](https://github.com/Displax/safetynet-fix/commits/dev/magisk) for proper attribution.
|
||||
|
||||
@@ -4,22 +4,38 @@ plugins {
|
||||
|
||||
android {
|
||||
namespace = "es.chiteroman.playintegrityfix"
|
||||
compileSdk = 34
|
||||
ndkVersion = "26.1.10909125"
|
||||
buildToolsVersion = "34.0.0"
|
||||
compileSdk = 36
|
||||
ndkVersion = "28.2.13676358"
|
||||
buildToolsVersion = "36.0.0"
|
||||
|
||||
buildFeatures {
|
||||
prefab = true
|
||||
}
|
||||
|
||||
packaging {
|
||||
jniLibs {
|
||||
excludes += "**/liblog.so"
|
||||
excludes += "**/libdobby.so"
|
||||
}
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "es.chiteroman.playintegrityfix"
|
||||
minSdk = 26
|
||||
targetSdk = 34
|
||||
targetSdk = 36
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
|
||||
externalNativeBuild {
|
||||
ndk {
|
||||
jobs = Runtime.getRuntime().availableProcessors()
|
||||
abiFilters += "armeabi-v7a"
|
||||
abiFilters += "arm64-v8a"
|
||||
cmake {
|
||||
arguments += "-DANDROID_STL=none"
|
||||
arguments += "-DCMAKE_BUILD_TYPE=Release"
|
||||
|
||||
cppFlags += "-std=c++23"
|
||||
cppFlags += "-fno-exceptions"
|
||||
cppFlags += "-fno-rtti"
|
||||
cppFlags += "-fvisibility=hidden"
|
||||
cppFlags += "-fvisibility-inlines-hidden"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,23 +49,29 @@ android {
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
sourceCompatibility = JavaVersion.VERSION_21
|
||||
targetCompatibility = JavaVersion.VERSION_21
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
path = file("src/main/cpp/Android.mk")
|
||||
cmake {
|
||||
path = file("src/main/cpp/CMakeLists.txt")
|
||||
version = "3.22.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
dependencies {
|
||||
implementation("org.lsposed.libcxx:libcxx:28.1.13356709")
|
||||
implementation("org.lsposed.hiddenapibypass:hiddenapibypass:6.1")
|
||||
}
|
||||
|
||||
tasks.register("copyFiles") {
|
||||
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/stripReleaseDebugSymbols/out/lib")
|
||||
|
||||
doLast {
|
||||
dexFile.copyTo(moduleFolder.resolve("classes.dex"), overwrite = true)
|
||||
|
||||
soDir.walk().filter { it.isFile && it.extension == "so" }.forEach { soFile ->
|
||||
|
||||
8
app/proguard-rules.pro
vendored
8
app/proguard-rules.pro
vendored
@@ -1,3 +1,5 @@
|
||||
-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.EntryPoint { public <methods>; }
|
||||
-keep class es.chiteroman.playintegrityfix.EntryPointVending { public <methods>; }
|
||||
-keepclassmembers class es.chiteroman.playintegrityfix.CustomKeyStoreSpi
|
||||
-keepclassmembers class es.chiteroman.playintegrityfix.CustomPackageInfoCreator { public <init>(...); }
|
||||
-keepclassmembers class es.chiteroman.playintegrityfix.CustomProvider
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := zygisk
|
||||
LOCAL_SRC_FILES := main.cpp
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)
|
||||
|
||||
LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/shadowhook/shadowhook/src/main/cpp/*.c)
|
||||
LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/shadowhook/shadowhook/src/main/cpp/common/*.c)
|
||||
LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/shadowhook/shadowhook/src/main/cpp/third_party/xdl/*.c)
|
||||
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/shadowhook/src/main/cpp
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/shadowhook/src/main/cpp/common
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/shadowhook/src/main/cpp/include
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/shadowhook/src/main/cpp/third_party/bsd
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/shadowhook/src/main/cpp/third_party/lss
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/shadowhook/src/main/cpp/third_party/xdl
|
||||
|
||||
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
|
||||
LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/shadowhook/shadowhook/src/main/cpp/arch/arm/*.c)
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/shadowhook/src/main/cpp/arch/arm
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
|
||||
LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/shadowhook/shadowhook/src/main/cpp/arch/arm64/*.c)
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/shadowhook/src/main/cpp/arch/arm64
|
||||
endif
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := libcxx
|
||||
LOCAL_LDLIBS := -llog
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
include $(LOCAL_PATH)/libcxx/Android.mk
|
||||
@@ -1,3 +0,0 @@
|
||||
APP_STL := none
|
||||
APP_CFLAGS := -Oz -fno-exceptions -fno-rtti -fvisibility=hidden -fvisibility-inlines-hidden
|
||||
APP_CPPFLAGS := -std=c++20
|
||||
@@ -1,15 +1,15 @@
|
||||
cmake_minimum_required(VERSION 3.22.1)
|
||||
|
||||
project(zygisk)
|
||||
project(playintegrityfix)
|
||||
|
||||
include_directories(${CMAKE_SOURCE_DIR}/libcxx/include)
|
||||
find_package(cxx REQUIRED CONFIG)
|
||||
|
||||
link_libraries(${CMAKE_SOURCE_DIR}/libcxx/${CMAKE_ANDROID_ARCH_ABI}.a)
|
||||
link_libraries(cxx::cxx)
|
||||
|
||||
add_library(${CMAKE_PROJECT_NAME} SHARED ${CMAKE_SOURCE_DIR}/main.cpp)
|
||||
add_library(${CMAKE_PROJECT_NAME} SHARED main.cpp local_cxa_atexit_finalize_impl/atexit.cpp)
|
||||
|
||||
add_subdirectory(Dobby)
|
||||
|
||||
SET_OPTION(Plugin.Android.BionicLinkerUtil ON)
|
||||
|
||||
target_compile_features(${CMAKE_PROJECT_NAME} PRIVATE c_std_23 cxx_std_23)
|
||||
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE log)
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE log dobby_static)
|
||||
|
||||
1
app/src/main/cpp/Dobby
Submodule
1
app/src/main/cpp/Dobby
Submodule
Submodule app/src/main/cpp/Dobby added at 05a09ac680
1
app/src/main/cpp/json
Submodule
1
app/src/main/cpp/json
Submodule
Submodule app/src/main/cpp/json added at 55f93686c0
File diff suppressed because it is too large
Load Diff
Submodule app/src/main/cpp/libcxx deleted from 12c8f4e93f
1
app/src/main/cpp/local_cxa_atexit_finalize_impl
Submodule
1
app/src/main/cpp/local_cxa_atexit_finalize_impl
Submodule
Submodule app/src/main/cpp/local_cxa_atexit_finalize_impl added at ab0dd0a64d
@@ -3,8 +3,8 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "zygisk.hpp"
|
||||
#include "shadowhook.h"
|
||||
#include "json.hpp"
|
||||
#include "json/single_include/nlohmann/json.hpp"
|
||||
#include "dobby.h"
|
||||
|
||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "PIF/Native", __VA_ARGS__)
|
||||
|
||||
@@ -13,52 +13,47 @@
|
||||
#define JSON_FILE_PATH "/data/adb/modules/playintegrityfix/pif.json"
|
||||
#define CUSTOM_JSON_FILE_PATH "/data/adb/modules/playintegrityfix/custom.pif.json"
|
||||
|
||||
static std::string FIRST_API_LEVEL, SECURITY_PATCH, BUILD_ID, VNDK_VERSION;
|
||||
#define VENDING_PACKAGE "com.android.vending"
|
||||
#define DROIDGUARD_PACKAGE "com.google.android.gms.unstable"
|
||||
|
||||
static int verboseLogs = 0;
|
||||
static int spoofBuild = 1;
|
||||
static int spoofProps = 1;
|
||||
static int spoofProvider = 1;
|
||||
static int spoofSignature = 0;
|
||||
static int spoofVendingFinger = 0;
|
||||
static int spoofVendingSdk = 0;
|
||||
|
||||
static std::map<std::string, std::string> jsonProps;
|
||||
|
||||
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;
|
||||
|
||||
if (cookie == nullptr || name == nullptr || value == nullptr ||
|
||||
!callbacks.contains(cookie))
|
||||
return;
|
||||
const char *oldValue = value;
|
||||
|
||||
std::string_view prop(name);
|
||||
std::string prop(name);
|
||||
|
||||
if (prop.ends_with("api_level")) {
|
||||
if (FIRST_API_LEVEL.empty()) {
|
||||
LOGD("FIRST_API_LEVEL is empty, ignoring it...");
|
||||
return;
|
||||
} else {
|
||||
value = FIRST_API_LEVEL.c_str();
|
||||
if (jsonProps.count(prop)) {
|
||||
// Exact property match
|
||||
value = jsonProps[prop].c_str();
|
||||
} else {
|
||||
// Leading * wildcard property match
|
||||
for (const auto &p: jsonProps) {
|
||||
if (p.first.starts_with("*") && prop.ends_with(p.first.substr(1))) {
|
||||
value = p.second.c_str();
|
||||
break;
|
||||
}
|
||||
}
|
||||
LOGD("[%s] -> %s", name, value);
|
||||
} else if (prop.ends_with("security_patch")) {
|
||||
if (SECURITY_PATCH.empty()) {
|
||||
LOGD("SECURITY_PATCH is empty, ignoring it...");
|
||||
return;
|
||||
} else {
|
||||
value = SECURITY_PATCH.c_str();
|
||||
}
|
||||
LOGD("[%s] -> %s", name, value);
|
||||
} else if (prop == "ro.build.id") {
|
||||
if (BUILD_ID.empty()) {
|
||||
LOGD("BUILD_ID is empty, ignoring it...");
|
||||
return;
|
||||
} else {
|
||||
value = BUILD_ID.c_str();
|
||||
}
|
||||
LOGD("[%s] -> %s", name, value);
|
||||
} else if (prop.ends_with("vndk.version")) {
|
||||
if (VNDK_VERSION.empty()) {
|
||||
LOGD("VNDK_VERSION is empty, ignoring it...");
|
||||
return;
|
||||
} else {
|
||||
value = VNDK_VERSION.c_str();
|
||||
}
|
||||
LOGD("[%s] -> %s", name, value);
|
||||
}
|
||||
|
||||
if (oldValue == value) {
|
||||
if (verboseLogs > 99) LOGD("[%s]: %s (unchanged)", name, oldValue);
|
||||
} else {
|
||||
LOGD("[%s]: %s -> %s", name, oldValue, value);
|
||||
}
|
||||
|
||||
return callbacks[cookie](cookie, name, value, serial);
|
||||
@@ -75,18 +70,14 @@ static void my_system_property_read_callback(const prop_info *pi, T_Callback cal
|
||||
}
|
||||
|
||||
static void doHook() {
|
||||
shadowhook_init(SHADOWHOOK_MODE_UNIQUE, false);
|
||||
void *handle = shadowhook_hook_sym_name(
|
||||
"libc.so",
|
||||
"__system_property_read_callback",
|
||||
reinterpret_cast<void *>(my_system_property_read_callback),
|
||||
reinterpret_cast<void **>(&o_system_property_read_callback)
|
||||
);
|
||||
void *handle = DobbySymbolResolver(nullptr, "__system_property_read_callback");
|
||||
if (handle == nullptr) {
|
||||
LOGD("Couldn't find '__system_property_read_callback' handle. Report to @chiteroman");
|
||||
LOGD("Couldn't find '__system_property_read_callback' handle");
|
||||
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));
|
||||
}
|
||||
|
||||
class PlayIntegrityFix : public zygisk::ModuleBase {
|
||||
@@ -97,32 +88,43 @@ public:
|
||||
}
|
||||
|
||||
void preAppSpecialize(zygisk::AppSpecializeArgs *args) override {
|
||||
bool isGms = false, isGmsUnstable = false;
|
||||
bool isGms = false, isDroidGuardOrVending = false;
|
||||
|
||||
auto rawProcess = env->GetStringUTFChars(args->nice_name, nullptr);
|
||||
auto rawDir = env->GetStringUTFChars(args->app_data_dir, nullptr);
|
||||
|
||||
if (rawProcess) {
|
||||
std::string_view process(rawProcess);
|
||||
|
||||
isGms = process.starts_with("com.google.android.gms");
|
||||
isGmsUnstable = process.compare("com.google.android.gms.unstable") == 0;
|
||||
// Prevent crash on apps with no data dir
|
||||
if (rawDir == nullptr) {
|
||||
env->ReleaseStringUTFChars(args->nice_name, rawProcess);
|
||||
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
|
||||
return;
|
||||
}
|
||||
|
||||
pkgName = rawProcess;
|
||||
std::string_view dir(rawDir);
|
||||
|
||||
isGms = dir.ends_with("/com.google.android.gms") || dir.ends_with("/com.android.vending");
|
||||
isDroidGuardOrVending = pkgName == DROIDGUARD_PACKAGE || pkgName == VENDING_PACKAGE;
|
||||
|
||||
env->ReleaseStringUTFChars(args->nice_name, rawProcess);
|
||||
env->ReleaseStringUTFChars(args->app_data_dir, rawDir);
|
||||
|
||||
if (!isGms) {
|
||||
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
|
||||
return;
|
||||
}
|
||||
|
||||
// We are in GMS now, force unmount
|
||||
api->setOption(zygisk::FORCE_DENYLIST_UNMOUNT);
|
||||
|
||||
if (!isGmsUnstable) {
|
||||
if (!isDroidGuardOrVending) {
|
||||
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<char> jsonVector;
|
||||
long dexSize = 0, jsonSize = 0;
|
||||
|
||||
int fd = api->connectCompanion();
|
||||
|
||||
read(fd, &dexSize, sizeof(long));
|
||||
@@ -130,34 +132,34 @@ public:
|
||||
|
||||
if (dexSize < 1) {
|
||||
close(fd);
|
||||
LOGD("Couldn't read classes.dex");
|
||||
LOGD("Couldn't read dex file");
|
||||
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
|
||||
return;
|
||||
}
|
||||
|
||||
if (jsonSize < 1) {
|
||||
close(fd);
|
||||
LOGD("Couldn't read pif.json");
|
||||
LOGD("Couldn't read json file");
|
||||
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
|
||||
return;
|
||||
}
|
||||
|
||||
LOGD("Read from file descriptor for 'dex' -> %ld bytes", dexSize);
|
||||
LOGD("Read from file descriptor for 'json' -> %ld bytes", jsonSize);
|
||||
|
||||
dexVector.resize(dexSize);
|
||||
read(fd, dexVector.data(), dexSize);
|
||||
|
||||
std::vector<char> jsonVector(jsonSize);
|
||||
jsonVector.resize(jsonSize);
|
||||
read(fd, jsonVector.data(), jsonSize);
|
||||
|
||||
close(fd);
|
||||
|
||||
LOGD("Read from file descriptor file 'classes.dex' -> %ld bytes", dexSize);
|
||||
LOGD("Read from file descriptor file 'pif.json' -> %ld bytes", jsonSize);
|
||||
|
||||
std::string data(jsonVector.cbegin(), jsonVector.cend());
|
||||
json = nlohmann::json::parse(data, nullptr, false, true);
|
||||
std::string jsonString(jsonVector.cbegin(), jsonVector.cend());
|
||||
json = nlohmann::json::parse(jsonString, nullptr, false, true);
|
||||
|
||||
jsonVector.clear();
|
||||
data.clear();
|
||||
jsonString.clear();
|
||||
}
|
||||
|
||||
void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override {
|
||||
@@ -165,9 +167,11 @@ public:
|
||||
|
||||
readJson();
|
||||
|
||||
doHook();
|
||||
if (pkgName == VENDING_PACKAGE) spoofBuild = spoofProps = spoofProvider = spoofSignature = 0;
|
||||
else spoofVendingFinger = spoofVendingSdk = 0;
|
||||
|
||||
inject();
|
||||
if (spoofProps > 0) doHook();
|
||||
if (spoofBuild + spoofProvider + spoofSignature + spoofVendingFinger + spoofVendingSdk > 0) inject();
|
||||
|
||||
dexVector.clear();
|
||||
json.clear();
|
||||
@@ -182,114 +186,163 @@ private:
|
||||
JNIEnv *env = nullptr;
|
||||
std::vector<char> dexVector;
|
||||
nlohmann::json json;
|
||||
std::string pkgName;
|
||||
std::string vendingFingerprintValue;
|
||||
|
||||
void readJson() {
|
||||
LOGD("JSON contains %d keys!", static_cast<int>(json.size()));
|
||||
|
||||
// Direct property spoofing workarounds
|
||||
if (json.contains("ID")) {
|
||||
if (json["ID"].is_null()) {
|
||||
LOGD("Key ID is null!");
|
||||
} else if (json["ID"].is_string()) {
|
||||
BUILD_ID = json["ID"].get<std::string>();
|
||||
// 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 ID!");
|
||||
LOGD("Error parsing verboseLogs!");
|
||||
}
|
||||
} else {
|
||||
LOGD("Key ID doesn't exist in JSON file!");
|
||||
}
|
||||
if (json.contains("SECURITY_PATCH")) {
|
||||
if (json["SECURITY_PATCH"].is_null()) {
|
||||
LOGD("Key SECURITY_PATCH is null!");
|
||||
} else if (json["SECURITY_PATCH"].is_string()) {
|
||||
SECURITY_PATCH = json["SECURITY_PATCH"].get<std::string>();
|
||||
} else {
|
||||
LOGD("Error parsing SECURITY_PATCH!");
|
||||
}
|
||||
} else {
|
||||
LOGD("Key SECURITY_PATCH doesn't exist in JSON file!");
|
||||
}
|
||||
if (json.contains("DEVICE_INITIAL_SDK_INT")) {
|
||||
if (json["DEVICE_INITIAL_SDK_INT"].is_null()) {
|
||||
LOGD("Key DEVICE_INITIAL_SDK_INT is null!");
|
||||
} else if (json["DEVICE_INITIAL_SDK_INT"].is_string()) {
|
||||
FIRST_API_LEVEL = json["DEVICE_INITIAL_SDK_INT"].get<std::string>();
|
||||
} else {
|
||||
LOGD("Error parsing DEVICE_INITIAL_SDK_INT!");
|
||||
}
|
||||
} else {
|
||||
LOGD("Key DEVICE_INITIAL_SDK_INT doesn't exist in JSON file!");
|
||||
json.erase("verboseLogs");
|
||||
}
|
||||
|
||||
// Backwards compatibility for chiteroman's alternate API naming
|
||||
if (json.contains("BUILD_ID")) {
|
||||
if (json["BUILD_ID"].is_null()) {
|
||||
LOGD("Key BUILD_ID is null!");
|
||||
} else if (json["BUILD_ID"].is_string()) {
|
||||
BUILD_ID = json["BUILD_ID"].get<std::string>();
|
||||
// Vending advanced spoofing settings
|
||||
if (json.contains("spoofVendingSdk")) {
|
||||
if (!json["spoofVendingSdk"].is_null() && json["spoofVendingSdk"].is_string() && json["spoofVendingSdk"] != "") {
|
||||
spoofVendingSdk = stoi(json["spoofVendingSdk"].get<std::string>());
|
||||
if (verboseLogs > 0) LOGD("Spoofing SDK Level in Play Store %s!", (spoofVendingSdk > 0) ? "enabled" : "disabled");
|
||||
} else {
|
||||
LOGD("Error parsing BUILD_ID!");
|
||||
LOGD("Error parsing spoofVendingSdk!");
|
||||
}
|
||||
} else {
|
||||
LOGD("Key BUILD_ID doesn't exist in JSON file!");
|
||||
json.erase("spoofVendingSdk");
|
||||
}
|
||||
if (json.contains("FIRST_API_LEVEL")) {
|
||||
if (json["FIRST_API_LEVEL"].is_null()) {
|
||||
LOGD("Key FIRST_API_LEVEL is null!");
|
||||
} else if (json["FIRST_API_LEVEL"].is_string()) {
|
||||
FIRST_API_LEVEL = json["FIRST_API_LEVEL"].get<std::string>();
|
||||
if (json.contains("spoofVendingFinger")) {
|
||||
if (!json["spoofVendingFinger"].is_null() && json["spoofVendingFinger"].is_string() && json["spoofVendingFinger"] != "") {
|
||||
if (json["spoofVendingFinger"].get<std::string>().find_first_not_of("01") != std::string::npos) {
|
||||
spoofVendingFinger = 1;
|
||||
vendingFingerprintValue = json["spoofVendingFinger"].get<std::string>();
|
||||
} else if (json.contains("FINGERPRINT") && !json["FINGERPRINT"].is_null() && json["FINGERPRINT"].is_string() && json["FINGERPRINT"] != "") {
|
||||
spoofVendingFinger = stoi(json["spoofVendingFinger"].get<std::string>());
|
||||
vendingFingerprintValue = json["FINGERPRINT"].get<std::string>();
|
||||
} else {
|
||||
LOGD("Error parsing spoofVendingFinger or FINGERPRINT field!");
|
||||
}
|
||||
if (verboseLogs > 0) LOGD("Spoofing Fingerprint in Play Store %s!", (spoofVendingFinger > 0) ? "enabled" : "disabled");
|
||||
} else {
|
||||
LOGD("Error parsing FIRST_API_LEVEL!");
|
||||
LOGD("Error parsing spoofVendingFinger!");
|
||||
}
|
||||
} else {
|
||||
LOGD("Key FIRST_API_LEVEL doesn't exist in JSON file!");
|
||||
json.erase("spoofVendingFinger");
|
||||
}
|
||||
if (json.contains("VNDK_VERSION")) {
|
||||
if (json["VNDK_VERSION"].is_null()) {
|
||||
LOGD("Key VNDK_VERSION is null!");
|
||||
} else if (json["VNDK_VERSION"].is_string()) {
|
||||
VNDK_VERSION = json["VNDK_VERSION"].get<std::string>();
|
||||
if (pkgName == VENDING_PACKAGE) {
|
||||
json.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// DroidGuard 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 VNDK_VERSION!");
|
||||
LOGD("Error parsing spoofBuild!");
|
||||
}
|
||||
json.erase("VNDK_VERSION"); // Doesn't exist in Build or Build.VERSION
|
||||
} else {
|
||||
LOGD("Key VNDK_VERSION doesn't exist in JSON file!");
|
||||
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 (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 (verboseLogs > 0) LOGD("Adding '%s' to properties list", jsonList.key().c_str());
|
||||
jsonProps[jsonList.key()] = jsonList.value();
|
||||
}
|
||||
} else {
|
||||
LOGD("Error parsing %s!", jsonList.key().c_str());
|
||||
}
|
||||
eraseKeys.push_back(jsonList.key());
|
||||
}
|
||||
}
|
||||
// Remove properties from parsed JSON
|
||||
for (auto key: eraseKeys) {
|
||||
if (json.contains(key)) json.erase(key);
|
||||
}
|
||||
}
|
||||
|
||||
void inject() {
|
||||
LOGD("get system classloader");
|
||||
const char* niceName = pkgName == VENDING_PACKAGE ? "PS" : "DG";
|
||||
|
||||
LOGD("JNI %s: Getting system classloader", niceName);
|
||||
auto clClass = env->FindClass("java/lang/ClassLoader");
|
||||
auto getSystemClassLoader = env->GetStaticMethodID(clClass, "getSystemClassLoader",
|
||||
"()Ljava/lang/ClassLoader;");
|
||||
auto getSystemClassLoader = env->GetStaticMethodID(clClass, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
|
||||
auto systemClassLoader = env->CallStaticObjectMethod(clClass, getSystemClassLoader);
|
||||
|
||||
LOGD("create class loader");
|
||||
LOGD("JNI %s: Creating module classloader", niceName);
|
||||
auto dexClClass = env->FindClass("dalvik/system/InMemoryDexClassLoader");
|
||||
auto dexClInit = env->GetMethodID(dexClClass, "<init>",
|
||||
"(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
|
||||
auto buffer = env->NewDirectByteBuffer(dexVector.data(),
|
||||
static_cast<jlong>(dexVector.size()));
|
||||
auto dexClInit = env->GetMethodID(dexClClass, "<init>", "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
|
||||
auto buffer = env->NewDirectByteBuffer(dexVector.data(), static_cast<jlong>(dexVector.size()));
|
||||
auto dexCl = env->NewObject(dexClClass, dexClInit, buffer, systemClassLoader);
|
||||
|
||||
LOGD("load class");
|
||||
auto loadClass = env->GetMethodID(clClass, "loadClass",
|
||||
"(Ljava/lang/String;)Ljava/lang/Class;");
|
||||
auto entryClassName = env->NewStringUTF("es.chiteroman.playintegrityfix.EntryPoint");
|
||||
LOGD("JNI %s: Loading module class", niceName);
|
||||
auto loadClass = env->GetMethodID(clClass, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
|
||||
const char* className = pkgName == VENDING_PACKAGE ? "es.chiteroman.playintegrityfix.EntryPointVending" : "es.chiteroman.playintegrityfix.EntryPoint";
|
||||
auto entryClassName = env->NewStringUTF(className);
|
||||
auto entryClassObj = env->CallObjectMethod(dexCl, loadClass, entryClassName);
|
||||
|
||||
auto entryClass = (jclass) entryClassObj;
|
||||
|
||||
LOGD("read json");
|
||||
auto readProps = env->GetStaticMethodID(entryClass, "readJson",
|
||||
"(Ljava/lang/String;)V");
|
||||
auto javaStr = env->NewStringUTF(json.dump().c_str());
|
||||
env->CallStaticVoidMethod(entryClass, readProps, javaStr);
|
||||
if (pkgName == VENDING_PACKAGE) {
|
||||
LOGD("JNI %s: Calling EntryPointVending.init", niceName);
|
||||
auto entryInit = env->GetStaticMethodID(entryClass, "init", "(IIILjava/lang/String;)V");
|
||||
auto javaStr = env->NewStringUTF(vendingFingerprintValue.c_str());
|
||||
env->CallStaticVoidMethod(entryClass, entryInit, verboseLogs, spoofVendingFinger, spoofVendingSdk, javaStr);
|
||||
env->DeleteLocalRef(javaStr);
|
||||
} else {
|
||||
LOGD("JNI %s: Sending JSON", niceName);
|
||||
auto receiveJson = env->GetStaticMethodID(entryClass, "receiveJson", "(Ljava/lang/String;)V");
|
||||
auto javaStr = env->NewStringUTF(json.dump().c_str());
|
||||
env->CallStaticVoidMethod(entryClass, receiveJson, javaStr);
|
||||
|
||||
LOGD("call init");
|
||||
auto entryInit = env->GetStaticMethodID(entryClass, "init", "()V");
|
||||
env->CallStaticVoidMethod(entryClass, entryInit);
|
||||
LOGD("JNI %s: Calling EntryPoint.init", niceName);
|
||||
auto entryInit = env->GetStaticMethodID(entryClass, "init", "(IIII)V");
|
||||
env->CallStaticVoidMethod(entryClass, entryInit, verboseLogs, spoofBuild, spoofProvider, spoofSignature);
|
||||
env->DeleteLocalRef(javaStr);
|
||||
}
|
||||
env->DeleteLocalRef(clClass);
|
||||
env->DeleteLocalRef(systemClassLoader);
|
||||
env->DeleteLocalRef(dexClClass);
|
||||
env->DeleteLocalRef(buffer);
|
||||
env->DeleteLocalRef(dexCl);
|
||||
env->DeleteLocalRef(entryClassName);
|
||||
env->DeleteLocalRef(entryClassObj);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Submodule app/src/main/cpp/shadowhook deleted from b2537df077
@@ -0,0 +1,42 @@
|
||||
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
|
||||
@SuppressWarnings("deprecation")
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,10 @@ public final class CustomProvider extends Provider {
|
||||
|
||||
@Override
|
||||
public synchronized Service getService(String type, String algorithm) {
|
||||
EntryPoint.spoofDevice();
|
||||
if (EntryPoint.getVerboseLogs() > 2) EntryPoint.LOG(String.format("Service: Caller type '%s' with algorithm '%s'", type, algorithm));
|
||||
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;
|
||||
@@ -16,14 +25,57 @@ import java.util.HashMap;
|
||||
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<>();
|
||||
|
||||
public static void init() {
|
||||
spoofProvider();
|
||||
spoofDevice();
|
||||
public static Integer getVerboseLogs() {
|
||||
return verboseLogs;
|
||||
}
|
||||
|
||||
public static void readJson(String data) {
|
||||
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();
|
||||
if (spoofProviderVal > 0) spoofProvider();
|
||||
if (spoofBuildVal > 0) spoofDevice();
|
||||
if (spoofSignatureVal > 0) spoofPackageManager();
|
||||
}
|
||||
|
||||
public static void receiveJson(String data) {
|
||||
try (JsonReader reader = new JsonReader(new StringReader(data))) {
|
||||
reader.beginObject();
|
||||
while (reader.hasNext()) {
|
||||
@@ -66,15 +118,65 @@ public final class EntryPoint {
|
||||
|
||||
static void spoofDevice() {
|
||||
for (String key : map.keySet()) {
|
||||
// Backwards compatibility for chiteroman's alternate API naming
|
||||
if (key.equals("BUILD_ID")) {
|
||||
setField("ID", map.get("BUILD_ID"));
|
||||
} else if (key.equals("FIRST_API_LEVEL")) {
|
||||
setField("DEVICE_INITIAL_SDK_INT", map.get("FIRST_API_LEVEL"));
|
||||
} else {
|
||||
setField(key, map.get(key));
|
||||
setField(key, map.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -86,7 +188,7 @@ public final class EntryPoint {
|
||||
|
||||
private static void setField(String name, String value) {
|
||||
if (value.isEmpty()) {
|
||||
LOG(String.format("%s is empty, skipping...", name));
|
||||
LOG(String.format("%s is empty, skipping", name));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -100,7 +202,7 @@ public final class EntryPoint {
|
||||
} else if (classContainsField(Build.VERSION.class, name)) {
|
||||
field = Build.VERSION.class.getDeclaredField(name);
|
||||
} else {
|
||||
LOG(String.format("Couldn't determine '%s' class name", name));
|
||||
if (verboseLogs > 1) LOG(String.format("Couldn't determine '%s' class name", name));
|
||||
return;
|
||||
}
|
||||
} catch (NoSuchFieldException e) {
|
||||
@@ -115,7 +217,7 @@ public final class EntryPoint {
|
||||
return;
|
||||
}
|
||||
if (value.equals(oldValue)) {
|
||||
LOG(String.format("[%s]: already '%s', skipping...", name, value));
|
||||
if (verboseLogs > 2) LOG(String.format("[%s]: %s (unchanged)", name, value));
|
||||
return;
|
||||
}
|
||||
Class<?> fieldType = field.getType();
|
||||
@@ -141,7 +243,28 @@ public final class EntryPoint {
|
||||
LOG(String.format("[%s]: %s -> %s", name, oldValue, value));
|
||||
}
|
||||
|
||||
private static String logParseField(Field field) {
|
||||
Object value = null;
|
||||
String type = field.getType().getName();
|
||||
String name = field.getName();
|
||||
try {
|
||||
value = field.get(null);
|
||||
} catch (IllegalAccessException|NullPointerException e) {
|
||||
return String.format("Couldn't access '%s' field value: " + e, name);
|
||||
}
|
||||
return String.format("<%s> %s: %s", type, name, String.valueOf(value));
|
||||
}
|
||||
|
||||
private static void logFields() {
|
||||
for (Field field : Build.class.getDeclaredFields()) {
|
||||
LOG("Build " + logParseField(field));
|
||||
}
|
||||
for (Field field : Build.VERSION.class.getDeclaredFields()) {
|
||||
LOG("Build.VERSION " + logParseField(field));
|
||||
}
|
||||
}
|
||||
|
||||
static void LOG(String msg) {
|
||||
Log.d("PIF/Java", msg);
|
||||
Log.d("PIF/Java:DG", msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
package es.chiteroman.playintegrityfix;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.Build;
|
||||
import java.lang.reflect.Field;
|
||||
import android.util.Log;
|
||||
|
||||
public final class EntryPointVending {
|
||||
|
||||
private static void LOG(String msg) {
|
||||
Log.d("PIF/Java:PS", msg);
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
public static void init(int verboseLogs, int spoofVendingFinger, int spoofVendingSdk, String vendingFingerprintValue) {
|
||||
// Only spoof FINGERPRINT to Play Store if not forcing Android <13 Play Integrity verdict
|
||||
if (spoofVendingSdk < 1) {
|
||||
if (spoofVendingFinger < 1) return;
|
||||
String oldValue;
|
||||
try {
|
||||
Field field = Build.class.getDeclaredField("FINGERPRINT");
|
||||
field.setAccessible(true);
|
||||
oldValue = String.valueOf(field.get(null));
|
||||
if (oldValue.equals(vendingFingerprintValue)) {
|
||||
if (verboseLogs > 2) LOG(String.format("[FINGERPRINT]: %s (unchanged)", oldValue));
|
||||
field.setAccessible(false);
|
||||
return;
|
||||
}
|
||||
field.set(null, vendingFingerprintValue);
|
||||
field.setAccessible(false);
|
||||
LOG(String.format("[FINGERPRINT]: %s -> %s", oldValue, vendingFingerprintValue));
|
||||
} catch (NoSuchFieldException e) {
|
||||
LOG("FINGERPRINT field not found: " + e);
|
||||
} catch (SecurityException | IllegalAccessException | IllegalArgumentException |
|
||||
NullPointerException | ExceptionInInitializerError e) {
|
||||
LOG("FINGERPRINT field not accessible: " + e);
|
||||
}
|
||||
} else {
|
||||
int requestSdk = spoofVendingSdk == 1 ? 32 : spoofVendingSdk;
|
||||
int targetSdk = Math.min(Build.VERSION.SDK_INT, requestSdk);
|
||||
int oldValue;
|
||||
try {
|
||||
Field field = Build.VERSION.class.getDeclaredField("SDK_INT");
|
||||
field.setAccessible(true);
|
||||
oldValue = field.getInt(null);
|
||||
if (oldValue == targetSdk) {
|
||||
if (verboseLogs > 2) LOG(String.format("[SDK_INT]: %d (unchanged)", oldValue));
|
||||
field.setAccessible(false);
|
||||
return;
|
||||
}
|
||||
field.set(null, targetSdk);
|
||||
field.setAccessible(false);
|
||||
LOG(String.format("[SDK_INT]: %d -> %d", oldValue, targetSdk));
|
||||
} catch (NoSuchFieldException e) {
|
||||
LOG("SDK_INT field not found: " + e);
|
||||
} catch (SecurityException | IllegalAccessException | IllegalArgumentException |
|
||||
NullPointerException | ExceptionInInitializerError e) {
|
||||
LOG("SDK_INT field not accessible: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
plugins {
|
||||
id("com.android.application") version "8.2.0" apply false
|
||||
id("com.android.application") version "8.13.0" apply false
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
# any settings specified in this file.
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Enable the configuration cache persistently
|
||||
org.gradle.configuration-cache=true
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
||||
|
||||
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-9.0.0-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
298
gradlew
vendored
298
gradlew
vendored
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env sh
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
# Copyright © 2015 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -15,81 +15,115 @@
|
||||
# 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\n' "$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
|
||||
CLASSPATH="\\\"\\\""
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
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 +132,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, 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" \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
||||
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=
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
|
||||
@@ -1 +1 @@
|
||||
#MAGISK
|
||||
#MAGISK
|
||||
|
||||
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 -s -m || exit 1
|
||||
|
||||
echo -e "\nDone!"
|
||||
|
||||
# warn since KernelSU/APatch's implementation automatically closes if successful
|
||||
if [ "$KSU" = "true" -o "$APATCH" = "true" ] && [ "$KSU_NEXT" != "true" ] && [ "$MMRL" != "true" ]; then
|
||||
echo -e "\nClosing dialog in 20 seconds ..."
|
||||
sleep 20
|
||||
fi
|
||||
204
module/autopif2.sh
Normal file
204
module/autopif2.sh
Normal file
@@ -0,0 +1,204 @@
|
||||
#!/system/bin/sh
|
||||
|
||||
if [ "$USER" != "root" -a "$(whoami 2>/dev/null)" != "root" ]; then
|
||||
echo "autopif2: need root permissions"; exit 1;
|
||||
fi;
|
||||
case "$HOME" in
|
||||
*termux*) echo "autopif2: need su root environment"; exit 1;;
|
||||
esac;
|
||||
|
||||
FORCE_TOP=1;
|
||||
FORCE_DEPTH=1;
|
||||
until [ -z "$1" ]; do
|
||||
case "$1" in
|
||||
-h|--help|help) echo "sh autopif2.sh [-a|-s] [-m] [-t #] [-d #]"; exit 0;;
|
||||
-a|--advanced|advanced) ARGS="-a"; shift;;
|
||||
-s|--strong|strong) ARGS="-a"; PATCH_COMMENT=1; spoofProvider=0; shift;;
|
||||
-m|--match|match) FORCE_MATCH=1; shift;;
|
||||
-t|--top|top) echo "$2" | grep -q '^[1-9]$' || exit 1; FORCE_TOP=$2; shift 2;;
|
||||
-d|--depth|depth) echo "$2" | grep -q '^[1-9]$' || exit 1; FORCE_DEPTH=$2; shift 2;;
|
||||
*) break;;
|
||||
esac;
|
||||
done;
|
||||
|
||||
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 wget2 >/dev/null; then
|
||||
wget() { wget2 "$@"; }
|
||||
elif ! 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 -qE "bad date|invalid option"; then
|
||||
if ! find_busybox; then
|
||||
die "date broken";
|
||||
else
|
||||
date() { $BUSYBOX date "$@"; }
|
||||
fi;
|
||||
fi;
|
||||
|
||||
if ! echo "A\nB" | grep -m1 -A1 "A" | grep -q "B"; then
|
||||
if ! find_busybox; then
|
||||
die "grep broken";
|
||||
else
|
||||
grep() { $BUSYBOX grep "$@"; }
|
||||
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_VERSIONS_HTML --no-check-certificate https://developer.android.com/about/versions 2>&1 || exit 1;
|
||||
wget -q -O PIXEL_LATEST_HTML --no-check-certificate $(grep -o 'https://developer.android.com/about/versions/.*[0-9]"' PIXEL_VERSIONS_HTML | sort -ru | cut -d\" -f1 | head -n$FORCE_TOP | tail -n1) 2>&1 || exit 1;
|
||||
wget -q -O PIXEL_OTA_HTML --no-check-certificate https://developer.android.com$(grep -o 'href=".*download-ota.*"' PIXEL_LATEST_HTML | grep 'qpr' | cut -d\" -f2 | head -n$FORCE_DEPTH | tail -n1) 2>&1 || exit 1;
|
||||
echo "$(grep -m1 -oE 'tooltip>Android .*[0-9]' PIXEL_OTA_HTML | cut -d\> -f2) $(grep -oE 'tooltip>QPR.* Beta' PIXEL_OTA_HTML | cut -d\> -f2 | head -n$FORCE_DEPTH | tail -n1)";
|
||||
|
||||
BETA_REL_DATE="$(date -D '%B %e, %Y' -d "$(grep -m1 -A1 'Release date' PIXEL_OTA_HTML | tail -n1 | sed 's;.*<td>\(.*\)</td>.*;\1;')" '+%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";
|
||||
|
||||
MODEL_LIST="$(grep -A1 'tr id=' PIXEL_OTA_HTML | grep 'td' | sed 's;.*<td>\(.*\)</td>;\1;')";
|
||||
PRODUCT_LIST="$(grep -o 'ota/.*_beta' PIXEL_OTA_HTML | cut -d\/ -f2)";
|
||||
OTA_LIST="$(grep 'ota/.*_beta' PIXEL_OTA_HTML | cut -d\" -f2)";
|
||||
|
||||
if [ "$FORCE_MATCH" ]; then
|
||||
DEVICE="$(getprop ro.product.device)";
|
||||
case "$PRODUCT_LIST" in
|
||||
*${DEVICE}_beta*)
|
||||
MODEL="$(getprop ro.product.model)";
|
||||
PRODUCT="${DEVICE}_beta";
|
||||
OTA="$(echo "$OTA_LIST" | grep "$PRODUCT")";
|
||||
;;
|
||||
esac;
|
||||
fi;
|
||||
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})";
|
||||
set -- $OTA_LIST;
|
||||
OTA="$(eval echo \${$list_rand})";
|
||||
DEVICE="$(echo "$PRODUCT" | sed 's/_beta//')";
|
||||
}
|
||||
set_random_beta;
|
||||
fi;
|
||||
echo "$MODEL ($PRODUCT)";
|
||||
|
||||
(ulimit -f 2; wget -q -O PIXEL_ZIP_METADATA --no-check-certificate $OTA) 2>/dev/null;
|
||||
FINGERPRINT="$(grep -am1 'post-build=' PIXEL_ZIP_METADATA 2>/dev/null | cut -d= -f2)";
|
||||
SECURITY_PATCH="$(grep -am1 'security-patch-level=' PIXEL_ZIP_METADATA 2>/dev/null | cut -d= -f2)";
|
||||
if [ -z "$FINGERPRINT" -o -z "$SECURITY_PATCH" ]; then
|
||||
case "$(getprop ro.product.cpu.abi)" in
|
||||
armeabi-v7a|x86) [ "$BUSYBOX" ] && ISBB32MSG=", install wget2";;
|
||||
esac;
|
||||
echo "\nError: Failed to extract information from metadata$ISBB32MSG!";
|
||||
exit 1;
|
||||
fi;
|
||||
|
||||
item "Dumping values to minimal pif.json ...";
|
||||
cat <<EOF | tee pif.json;
|
||||
{
|
||||
"MANUFACTURER": "Google",
|
||||
"MODEL": "$MODEL",
|
||||
"FINGERPRINT": "$FINGERPRINT",
|
||||
"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;
|
||||
if [ -f "$OLDJSON" ]; then
|
||||
grep -q '//"\*.security_patch"' $OLDJSON && PATCH_COMMENT=1;
|
||||
grep -qE "verboseLogs|VERBOSE_LOGS" $OLDJSON && ARGS="-a";
|
||||
fi;
|
||||
[ -f /data/adb/tricky_store/security_patch.txt ] && unset PATCH_COMMENT;
|
||||
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() { [ -f "$2" ] && grep -m1 "$1" $2 | cut -d\" -f4; }
|
||||
verboseLogs=$(grep_json "VERBOSE_LOGS" $OLDJSON);
|
||||
ADVSETTINGS="spoofBuild spoofProps spoofProvider spoofSignature spoofVendingFinger spoofVendingSdk 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;
|
||||
[ "$PATCH_COMMENT" ] && 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 ..;
|
||||
TS_SECPAT=/data/adb/tricky_store/security_patch.txt;
|
||||
if [ -f "$TS_SECPAT" ]; then
|
||||
item "Updating Tricky Store security_patch.txt ...";
|
||||
[ -s "$TS_SECPAT" ] || echo "all=" > $TS_SECPAT;
|
||||
grep -qE '^[0-9]{8}$' $TS_SECPAT && sed -i "s/^.*$/${SECURITY_PATCH//-}/" $TS_SECPAT;
|
||||
grep -qE '^[0-9]{4}-[0-9]{2}-[0-9]{2}$' $TS_SECPAT && sed -i "s/^.*$/$SECURITY_PATCH/" $TS_SECPAT;
|
||||
grep -q 'all=' $TS_SECPAT && sed -i "s/all=.*/all=$SECURITY_PATCH/" $TS_SECPAT;
|
||||
grep -q 'system=' $TS_SECPAT && sed -i "s/system=.*/system=$(echo ${SECURITY_PATCH//-} | cut -c-6)/" $TS_SECPAT;
|
||||
sed -i '$a\' $TS_SECPAT;
|
||||
cat $TS_SECPAT;
|
||||
fi;
|
||||
if [ -f /data/adb/modules/playintegrityfix/killpi.sh ]; then
|
||||
item "Killing any running GMS DroidGuard/Play Store processes ...";
|
||||
sh /data/adb/modules/playintegrityfix/killpi.sh 2>&1 || true;
|
||||
fi;
|
||||
fi;
|
||||
84
module/common_func.sh
Normal file
84
module/common_func.sh
Normal file
@@ -0,0 +1,84 @@
|
||||
SKIPDELPROP=false
|
||||
[ -f "$MODPATH/skipdelprop" ] && SKIPDELPROP=true
|
||||
|
||||
# delprop_if_exist <prop name>
|
||||
delprop_if_exist() {
|
||||
local NAME="$1"
|
||||
|
||||
[ -n "$(resetprop "$NAME")" ] && resetprop --delete "$NAME"
|
||||
}
|
||||
|
||||
# persistprop <prop name> <new value>
|
||||
persistprop() {
|
||||
local NAME="$1"
|
||||
local NEWVALUE="$2"
|
||||
local CURVALUE="$(resetprop "$NAME")"
|
||||
|
||||
if ! grep -q "$NAME" $MODPATH/uninstall.sh 2>/dev/null; then
|
||||
if [ "$CURVALUE" ]; then
|
||||
[ "$NEWVALUE" = "$CURVALUE" ] || echo "resetprop -n -p \"$NAME\" \"$CURVALUE\"" >> $MODPATH/uninstall.sh
|
||||
else
|
||||
echo "resetprop -p --delete \"$NAME\"" >> $MODPATH/uninstall.sh
|
||||
fi
|
||||
fi
|
||||
resetprop -n -p "$NAME" "$NEWVALUE"
|
||||
}
|
||||
|
||||
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
|
||||
-f|--force) local FORCE=1; shift;;
|
||||
esac
|
||||
|
||||
local NAME="$1"
|
||||
local NEWVALUE="$2"
|
||||
local CURVALUE="$(resetprop "$NAME")"
|
||||
|
||||
[ ! "$NEWVALUE" -o ! "$CURVALUE" ] && return 1
|
||||
[ "$NEWVALUE" = "$CURVALUE" -a ! "$FORCE" ] && return 2
|
||||
|
||||
local NEWLEN=${#NEWVALUE}
|
||||
if [ -f /dev/__properties__ ]; then
|
||||
local PROPFILE=/dev/__properties__
|
||||
else
|
||||
local PROPFILE="/dev/__properties__/$(resetprop -Z "$NAME")"
|
||||
fi
|
||||
[ ! -f "$PROPFILE" ] && return 3
|
||||
local NAMEOFFSET=$(echo $(strings -t d "$PROPFILE" | grep "$NAME") | cut -d\ -f1)
|
||||
|
||||
#<hex 2-byte change counter><flags byte><hex length of prop value><prop value + nul padding to 92 bytes><prop name>
|
||||
local NEWHEX="$(printf '%02x' "$NEWLEN")$(printf "$NEWVALUE" | od -A n -t x1 -v | tr -d ' \n')$(printf "%$((92-NEWLEN))s" | sed 's/ /00/g')"
|
||||
|
||||
printf "Patch '$NAME' to '$NEWVALUE' in '$PROPFILE' @ 0x%08x -> \n[0000??$NEWHEX]\n" $((NAMEOFFSET-96))
|
||||
|
||||
echo -ne "\x00\x00" \
|
||||
| dd obs=1 count=2 seek=$((NAMEOFFSET-96)) conv=notrunc of="$PROPFILE"
|
||||
echo -ne "$(printf "$NEWHEX" | sed -e 's/.\{2\}/&\\x/g' -e 's/^/\\x/' -e 's/\\x$//')" \
|
||||
| dd obs=1 count=93 seek=$((NAMEOFFSET-93)) conv=notrunc of="$PROPFILE"
|
||||
}
|
||||
|
||||
# resetprop_if_diff <prop name> <expected value>
|
||||
resetprop_if_diff() {
|
||||
local NAME="$1"
|
||||
local EXPECTED="$2"
|
||||
local CURRENT="$(resetprop "$NAME")"
|
||||
|
||||
[ -z "$CURRENT" ] || [ "$CURRENT" = "$EXPECTED" ] || $RESETPROP "$NAME" "$EXPECTED"
|
||||
}
|
||||
|
||||
# resetprop_if_match <prop name> <value match string> <new value>
|
||||
resetprop_if_match() {
|
||||
local NAME="$1"
|
||||
local CONTAINS="$2"
|
||||
local VALUE="$3"
|
||||
|
||||
[[ "$(resetprop "$NAME")" = *"$CONTAINS"* ]] && $RESETPROP "$NAME" "$VALUE"
|
||||
}
|
||||
|
||||
# stub for boot-time
|
||||
if [ "$(getprop sys.boot_completed)" != "1" ]; then
|
||||
ui_print() { return; }
|
||||
fi
|
||||
79
module/common_setup.sh
Normal file
79
module/common_setup.sh
Normal file
@@ -0,0 +1,79 @@
|
||||
# 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 'android.*overlay' | strings | tr -d '\n' | sed -e 's/^android//' -e 's/application//' -e 's;*http.*res/android;;' -e 's/manifest//' -e 's/overlay$//' | grep -oE '[[:alnum:].-_].*overlay' | cut -d\ -f2)
|
||||
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 custom ROM PropImitationHooks conflict when their persist props don't exist
|
||||
if [ -n "$(resetprop ro.aospa.version)" -o -n "$(resetprop net.pixelos.version)" -o -n "$(resetprop ro.afterlife.version)" -o -f /data/system/gms_certified_props.json ]; then
|
||||
for PROP in persist.sys.pihooks.first_api_level persist.sys.pihooks.security_patch; do
|
||||
resetprop | grep -q "\[$PROP\]" || persistprop "$PROP" ""
|
||||
done
|
||||
fi
|
||||
|
||||
# Work around supported custom ROM PropImitationHooks/PixelPropsUtils (and hybrids) conflict when spoofProvider is disabled
|
||||
if resetprop | grep -qE "persist.sys.pihooks|persist.sys.entryhooks|persist.sys.spoof|persist.sys.pixelprops" || [ -f /data/system/gms_certified_props.json ]; then
|
||||
persistprop persist.sys.pihooks.disable.gms_props true
|
||||
persistprop persist.sys.pihooks.disable.gms_key_attestation_block true
|
||||
persistprop persist.sys.entryhooks_enabled false
|
||||
persistprop persist.sys.spoof.gms false
|
||||
persistprop persist.sys.pixelprops.gms false
|
||||
persistprop persist.sys.pixelprops.gapps false
|
||||
persistprop persist.sys.pixelprops.google false
|
||||
persistprop persist.sys.pixelprops.pi false
|
||||
fi
|
||||
@@ -1,23 +1,54 @@
|
||||
# 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
|
||||
[ -f /data/adb/modules/playintegrityfix/uninstall.sh ] && sh /data/adb/modules/playintegrityfix/uninstall.sh
|
||||
rm -rf $MODPATH/action.sh $MODPATH/autopif2.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 \
|
||||
/data/adb/modules/playintegrityfix/uninstall.sh
|
||||
fi
|
||||
|
||||
# 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"
|
||||
# Copy any disabled app files to updated module
|
||||
if [ -d /data/adb/modules/playintegrityfix/system ]; then
|
||||
ui_print "- Restoring disabled ROM apps configuration"
|
||||
cp -afL /data/adb/modules/playintegrityfix/system $MODPATH
|
||||
fi
|
||||
|
||||
# Copy any supported custom files to updated module
|
||||
for FILE in custom.app_replace.list custom.pif.json skipdelprop uninstall.sh; do
|
||||
if [ -f "/data/adb/modules/playintegrityfix/$FILE" ]; then
|
||||
ui_print "- Restoring $FILE"
|
||||
cp -af /data/adb/modules/playintegrityfix/$FILE $MODPATH/$FILE
|
||||
fi
|
||||
done
|
||||
|
||||
# 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
|
||||
|
||||
# Copy any custom.pif.json to updated module
|
||||
if [ -f /data/adb/modules/playintegrityfix/custom.pif.json ]; then
|
||||
ui_print "- Restoring custom.pif.json"
|
||||
cp -af /data/adb/modules/playintegrityfix/custom.pif.json $MODPATH/custom.pif.json
|
||||
# Run common tasks for installation and boot-time
|
||||
if [ -d "$MODPATH/zygisk" ]; then
|
||||
. $MODPATH/common_func.sh
|
||||
. $MODPATH/common_setup.sh
|
||||
fi
|
||||
|
||||
# Migrate custom.pif.json to latest defaults if needed
|
||||
if [ -f "$MODPATH/custom.pif.json" ]; then
|
||||
if ! grep -q "api_level" $MODPATH/custom.pif.json || ! grep -q "verboseLogs" $MODPATH/custom.pif.json || ! grep -q "spoofVendingFinger" $MODPATH/custom.pif.json; then
|
||||
ui_print "- Running migration script on custom.pif.json:"
|
||||
ui_print " "
|
||||
chmod 755 $MODPATH/migrate.sh
|
||||
sh $MODPATH/migrate.sh --install --force --advanced $MODPATH/custom.pif.json
|
||||
ui_print " "
|
||||
fi
|
||||
fi
|
||||
|
||||
# Clean up any leftover files from previous deprecated methods
|
||||
rm -f /data/data/com.google.android.gms/cache/pif.prop /data/data/com.google.android.gms/pif.prop
|
||||
rm -f /data/data/com.google.android.gms/cache/pif.json /data/data/com.google.android.gms/pif.json
|
||||
rm -f /data/data/com.google.android.gms/cache/pif.prop /data/data/com.google.android.gms/pif.prop \
|
||||
/data/data/com.google.android.gms/cache/pif.json /data/data/com.google.android.gms/pif.json
|
||||
|
||||
25
module/example.app_replace.list
Normal file
25
module/example.app_replace.list
Normal file
@@ -0,0 +1,25 @@
|
||||
# Rename to custom.app_replace.list once customized
|
||||
#
|
||||
# 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
|
||||
/product/app/XiaomiEUInject-Stub
|
||||
|
||||
# EliteRoms
|
||||
/system/app/EliteDevelopmentModule
|
||||
/system/app/XInjectModule
|
||||
|
||||
# helluvaOS
|
||||
/system_ext/app/helluvaProductDevice*
|
||||
/system_ext/app/helluvaProductSecretStub
|
||||
|
||||
# hentaiOS
|
||||
/system_ext/app/hentaiLewdbSVTDummy
|
||||
|
||||
# Evolution X
|
||||
/system_ext/app/PifPrebuilt
|
||||
|
||||
# PixelOS, YAAP
|
||||
/system_ext/overlay/CertifiedPropsOverlay.apk
|
||||
@@ -1,20 +1,37 @@
|
||||
// Rename to custom.pif.json once completed
|
||||
//
|
||||
// See android.os.Build source for 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
|
||||
|
||||
{
|
||||
"MANUFACTURER": "",
|
||||
"MODEL": "",
|
||||
"FINGERPRINT": "",
|
||||
"BRAND": "",
|
||||
"PRODUCT": "",
|
||||
"DEVICE": "",
|
||||
"RELEASE": "",
|
||||
"ID": "",
|
||||
"INCREMENTAL": "",
|
||||
"TYPE": "",
|
||||
"TAGS": "",
|
||||
"SECURITY_PATCH": "",
|
||||
"DEVICE_INITIAL_SDK_INT": ""
|
||||
// Build Fields
|
||||
"MANUFACTURER": "",
|
||||
"MODEL": "",
|
||||
"FINGERPRINT": "",
|
||||
"BRAND": "",
|
||||
"PRODUCT": "",
|
||||
"DEVICE": "",
|
||||
"RELEASE": "",
|
||||
"ID": "",
|
||||
"INCREMENTAL": "",
|
||||
"TYPE": "",
|
||||
"TAGS": "",
|
||||
"SECURITY_PATCH": "",
|
||||
"DEVICE_INITIAL_SDK_INT": "",
|
||||
|
||||
// System Properties
|
||||
"*.build.id": "", // for ro.build.id
|
||||
"*.security_patch": "", // for ro.build.version.security_patch
|
||||
"*api_level": "", // for ro.board.api_level, ro.board.first_api_level, ro.product.first_api_level and ro.vendor.api_level
|
||||
|
||||
// Advanced Settings
|
||||
"spoofBuild": "1",
|
||||
"spoofProps": "1",
|
||||
"spoofProvider": "1",
|
||||
"spoofSignature": "0",
|
||||
"spoofVendingFinger": "0",
|
||||
"spoofVendingSdk": "0",
|
||||
"verboseLogs": "0"
|
||||
}
|
||||
|
||||
13
module/killpi.sh
Normal file
13
module/killpi.sh
Normal file
@@ -0,0 +1,13 @@
|
||||
#!/system/bin/sh
|
||||
# killpi.sh by osm0sis @ xda-developers
|
||||
#
|
||||
# Kill the Google Play services DroidGuard and Play Store processes
|
||||
# (com.google.android.gms.unstable and com.android.vending)
|
||||
|
||||
if [ "$USER" != "root" -a "$(whoami 2>/dev/null)" != "root" ]; then
|
||||
echo "killpi: need root permissions";
|
||||
exit 1;
|
||||
fi;
|
||||
|
||||
killall -v com.google.android.gms.unstable;
|
||||
killall -v com.android.vending;
|
||||
160
module/migrate.sh
Normal file
160
module/migrate.sh
Normal file
@@ -0,0 +1,160 @@
|
||||
#!/bin/sh
|
||||
|
||||
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";;
|
||||
esac;
|
||||
|
||||
item() { echo "- $@"; }
|
||||
die() { [ "$INSTALL" ] || echo "$N$N! $@"; exit 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- | sed 's|//|#|g')";
|
||||
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")" ];
|
||||
}
|
||||
|
||||
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";
|
||||
else
|
||||
case "$0" in
|
||||
*.sh) DIR="$0";;
|
||||
*) 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";
|
||||
|
||||
[ "$INSTALL" ] || item "Parsing fields ...";
|
||||
|
||||
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)\";
|
||||
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)";
|
||||
fi;
|
||||
|
||||
if [ -n "$SECURITY_PATCH" ] && ! grep_check_json security_patch; then
|
||||
item 'Simple entry SECURITY_PATCH found, changing to SECURITY_PATCH field and "*.security_patch" property ...';
|
||||
fi;
|
||||
|
||||
if grep_check_json VNDK_VERSION; then
|
||||
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" -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\" -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;
|
||||
|
||||
ADVSETTINGS="spoofBuild spoofProps spoofProvider spoofSignature spoofVendingFinger spoofVendingSdk verboseLogs";
|
||||
|
||||
spoofBuild=1;
|
||||
spoofProps=1;
|
||||
spoofProvider=1;
|
||||
spoofSignature=0;
|
||||
spoofVendingFinger=0;
|
||||
spoofVendingSdk=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 ...";
|
||||
[ "$ADVANCED" ] && item "Adding Advanced Settings entries ...";
|
||||
|
||||
(echo "{";
|
||||
echo " // Build Fields";
|
||||
for FIELD in $ALLFIELDS; do
|
||||
eval echo '\ \ \ \ \"$FIELD\": \"'\$$FIELD'\",';
|
||||
done;
|
||||
echo "$N // System Properties";
|
||||
echo ' "*.build.id": "'$ID'",';
|
||||
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=v4
|
||||
versionCode=4000
|
||||
version=v14
|
||||
versionCode=140001
|
||||
author=osm0sis & chiteroman @ xda-developers
|
||||
description=Fix CTS profile (SafetyNet) and DEVICE verdict (Play Integrity)
|
||||
description=Fix <A13 Play Integrity DEVICE verdict
|
||||
updateJson=https://raw.githubusercontent.com/osm0sis/PlayIntegrityFork/main/update.json
|
||||
|
||||
@@ -1,43 +1,49 @@
|
||||
# Remove Play Services from Magisk Denylist when set to enforcing
|
||||
if magisk --denylist status; then
|
||||
magisk --denylist rm com.google.android.gms
|
||||
fi
|
||||
MODPATH="${0%/*}"
|
||||
. $MODPATH/common_func.sh
|
||||
|
||||
# Remove conflicting modules if installed
|
||||
if [ -d /data/adb/modules/safetynet-fix ]; then
|
||||
touch /data/adb/modules/safetynet-fix/remove
|
||||
if [ -d "$MODPATH/zygisk" ]; then
|
||||
# Remove Play Services and Play Store from Magisk DenyList when set to Enforce in normal mode
|
||||
if magisk --denylist status; then
|
||||
magisk --denylist rm com.google.android.gms
|
||||
magisk --denylist rm com.android.vending
|
||||
fi
|
||||
# Run common tasks for installation and boot-time
|
||||
. $MODPATH/common_setup.sh
|
||||
else
|
||||
# Add Play Services DroidGuard and Play Store processes to Magisk DenyList for better results in scripts-only mode
|
||||
magisk --denylist add com.google.android.gms com.google.android.gms.unstable
|
||||
magisk --denylist add com.android.vending
|
||||
fi
|
||||
|
||||
# Conditional early sensitive properties
|
||||
|
||||
resetprop_if_diff() {
|
||||
local NAME=$1
|
||||
local EXPECTED=$2
|
||||
local CURRENT=$(resetprop $NAME)
|
||||
|
||||
[ -z "$CURRENT" ] || [ "$CURRENT" == "$EXPECTED" ] || resetprop $NAME $EXPECTED
|
||||
}
|
||||
resetprop_if_match() {
|
||||
local NAME=$1
|
||||
local CONTAINS=$2
|
||||
local VALUE=$3
|
||||
|
||||
[[ "$(resetprop $NAME)" == *"$CONTAINS"* ]] && resetprop $NAME $VALUE
|
||||
}
|
||||
|
||||
# RootBeer, Microsoft
|
||||
resetprop_if_diff ro.build.tags release-keys
|
||||
|
||||
# Samsung
|
||||
resetprop_if_diff ro.boot.warranty_bit 0
|
||||
resetprop_if_diff ro.vendor.boot.warranty_bit 0
|
||||
resetprop_if_diff ro.vendor.warranty_bit 0
|
||||
resetprop_if_diff ro.warranty_bit 0
|
||||
|
||||
# Realme
|
||||
resetprop_if_diff ro.boot.realmebootstate green
|
||||
|
||||
# OnePlus
|
||||
resetprop_if_diff ro.is_ever_orange 0
|
||||
|
||||
# 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
|
||||
if ! $SKIPDELPROP; then
|
||||
delprop_if_exist ro.boot.verifiedbooterror
|
||||
delprop_if_exist ro.boot.verifyerrorpart
|
||||
fi
|
||||
resetprop_if_diff ro.boot.veritymode.managed yes
|
||||
resetprop_if_diff ro.debuggable 0
|
||||
resetprop_if_diff ro.force.debuggable 0
|
||||
resetprop_if_diff ro.secure 1
|
||||
|
||||
@@ -1,53 +1,49 @@
|
||||
MODPATH="${0%/*}"
|
||||
. $MODPATH/common_func.sh
|
||||
|
||||
# Conditional sensitive properties
|
||||
|
||||
resetprop_if_diff() {
|
||||
local NAME=$1
|
||||
local EXPECTED=$2
|
||||
local CURRENT=$(resetprop $NAME)
|
||||
|
||||
[ -z "$CURRENT" ] || [ "$CURRENT" == "$EXPECTED" ] || resetprop $NAME $EXPECTED
|
||||
}
|
||||
resetprop_if_match() {
|
||||
local NAME=$1
|
||||
local CONTAINS=$2
|
||||
local VALUE=$3
|
||||
|
||||
[[ "$(resetprop $NAME)" == *"$CONTAINS"* ]] && resetprop $NAME $VALUE
|
||||
}
|
||||
|
||||
# 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
|
||||
if [ -n "$(resetprop ro.build.selinux)" ]; then
|
||||
resetprop --delete ro.build.selinux
|
||||
resetprop_if_diff ro.boot.selinux enforcing
|
||||
# use delete since it can be 0 or 1 for enforcing depending on OEM
|
||||
if ! $SKIPDELPROP; then
|
||||
delprop_if_exist 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
|
||||
|
||||
# SafetyNet/Play Integrity
|
||||
# Conditional late sensitive properties
|
||||
|
||||
# must be set after boot_completed for various OEMs
|
||||
{
|
||||
# late props which 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
|
||||
# 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": "v4",
|
||||
"versionCode": 4000,
|
||||
"zipUrl": "https://github.com/osm0sis/PlayIntegrityFork/releases/download/v4/PlayIntegrityFork-v4.zip",
|
||||
"version": "v14",
|
||||
"versionCode": 140000,
|
||||
"zipUrl": "https://github.com/osm0sis/PlayIntegrityFork/releases/download/v14/PlayIntegrityFork-v14.zip",
|
||||
"changelog": "https://raw.githubusercontent.com/osm0sis/PlayIntegrityFork/main/CHANGELOG.md"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user