This commit is contained in:
chiteroman 2024-02-16 02:50:50 +01:00
parent 3753ee5ca7
commit 6a9f5f88a0
14 changed files with 220 additions and 191 deletions

3
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

View File

@ -12,8 +12,8 @@ android {
applicationId = "es.chiteroman.playintegrityfix"
minSdk = 26
targetSdk = 34
versionCode = 15702
versionName = "v15.7.2"
versionCode = 15800
versionName = "v15.8"
multiDexEnabled = false
buildFeatures {
@ -30,14 +30,23 @@ android {
externalNativeBuild {
cmake {
arguments += "-DANDROID_STL=none"
arguments += "-DCMAKE_BUILD_TYPE=MinSizeRel"
arguments += "-DCMAKE_BUILD_TYPE=Release"
arguments += "-DPlugin.Android.BionicLinkerUtil=ON"
cFlags += "-fvisibility=hidden"
cFlags += "-fvisibility-inlines-hidden"
cFlags += "-flto"
cFlags += "-O3"
cFlags += "-mllvm -polly"
cppFlags += "-std=c++20"
cppFlags += "-fno-exceptions"
cppFlags += "-fno-rtti"
cppFlags += "-fvisibility=hidden"
cppFlags += "-fvisibility-inlines-hidden"
cppFlags += "-flto"
cppFlags += "-O3"
cppFlags += "-mllvm -polly"
}
}
}

View File

@ -10,4 +10,4 @@ add_library(${CMAKE_PROJECT_NAME} SHARED main.cpp)
add_subdirectory(Dobby)
target_link_libraries(${CMAKE_PROJECT_NAME} PUBLIC log dobby_static)
target_link_libraries(${CMAKE_PROJECT_NAME} log dobby_static)

View File

@ -26,7 +26,7 @@ option(Plugin.SymbolResolver "Enable symbol resolver" ON)
option(Plugin.ImportTableReplace "Enable import table replace " OFF)
option(Plugin.Android.BionicLinkerUtil "Enable android bionic linker util" OFF)
option(Plugin.Android.BionicLinkerUtil "Enable android bionic linker util" ON)
option(DOBBY_BUILD_EXAMPLE "Build example" OFF)

View File

@ -1,5 +1,7 @@
#include <android/log.h>
#include <unistd.h>
#include <fstream>
#include <filesystem>
#include "dobby.h"
#include "json.hpp"
#include "zygisk.hpp"
@ -108,6 +110,11 @@ public:
auto name = env->GetStringUTFChars(args->nice_name, nullptr);
if (name == nullptr) {
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
return;
}
bool isGmsUnstable = std::string_view(name) == "com.google.android.gms.unstable";
env->ReleaseStringUTFChars(args->nice_name, name);
@ -151,16 +158,16 @@ public:
close(fd);
json = nlohmann::json::parse(jsonVector, nullptr, false, true);
parseJson();
}
void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override {
if (dexVector.empty() || json.empty()) return;
parseJson();
injectDex();
doHook();
injectDex();
}
void preServerSpecialize(zygisk::ServerSpecializeArgs *args) override {
@ -274,31 +281,36 @@ static void companion(int fd) {
std::vector<char> dexVector, jsonVector;
FILE *dexFile = fopen(CLASSES_DEX, "rb");
std::ifstream dexFile(CLASSES_DEX, std::ios::binary);
if (dexFile) {
fseek(dexFile, 0, SEEK_END);
dexSize = ftell(dexFile);
fseek(dexFile, 0, SEEK_SET);
if (dexFile.is_open()) {
dexFile.seekg(0, std::ios::end);
dexSize = dexFile.tellg();
dexFile.seekg(0, std::ios::beg);
dexVector.resize(dexSize);
fread(dexVector.data(), 1, dexSize, dexFile);
fclose(dexFile);
dexFile.read(dexVector.data(), dexSize);
dexFile.close();
}
FILE *jsonFile = fopen(PIF_JSON, "rb");
if (jsonFile == nullptr) jsonFile = fopen(PIF_JSON_DEFAULT, "rb");
std::ifstream jsonFile;
if (jsonFile) {
fseek(jsonFile, 0, SEEK_END);
jsonSize = ftell(jsonFile);
fseek(jsonFile, 0, SEEK_SET);
if (std::filesystem::exists(PIF_JSON)) {
jsonFile = std::ifstream(PIF_JSON);
} else if (std::filesystem::exists(PIF_JSON_DEFAULT)) {
jsonFile = std::ifstream(PIF_JSON_DEFAULT);
} else {
LOGD("Couldn't open pif.json file. Did you remove it?");
}
if (jsonFile.is_open()) {
jsonFile.seekg(0, std::ios::end);
jsonSize = jsonFile.tellg();
jsonFile.seekg(0, std::ios::beg);
jsonVector.resize(jsonSize);
fread(jsonVector.data(), 1, jsonSize, jsonFile);
fclose(jsonFile);
jsonFile.read(jsonVector.data(), jsonSize);
jsonFile.close();
}
write(fd, &dexSize, sizeof(long));

View File

@ -10,12 +10,15 @@ import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.Enumeration;
import java.util.Locale;
public final class CustomKeyStoreSpi extends KeyStoreSpi {
public static volatile KeyStoreSpi keyStoreSpi = null;
public static KeyStoreSpi keyStoreSpi = null;
private static final String EAT_OID = "1.3.6.1.4.1.11129.2.1.25";
private static final String ASN1_OID = "1.3.6.1.4.1.11129.2.1.17";
private static final String KNOX_OID = "1.3.6.1.4.1.236.11.3.23.7";
@Override
public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException, UnrecoverableKeyException {
@ -24,13 +27,21 @@ public final class CustomKeyStoreSpi extends KeyStoreSpi {
@Override
public Certificate[] engineGetCertificateChain(String alias) {
for (StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) {
if (stackTraceElement.getClassName().toLowerCase(Locale.US).contains("droidguard")) {
EntryPoint.LOG("DroidGuard call certificate chain! Throw exception.");
Certificate[] certificates = keyStoreSpi.engineGetCertificateChain(alias);
// This shouldn't happen...
if (certificates == null) {
throw new UnsupportedOperationException();
}
// Is certificate chain ?
if (certificates.length > 1) {
if (certificates[0] instanceof X509Certificate x509Certificate) {
if (x509Certificate.getExtensionValue(EAT_OID) != null || x509Certificate.getExtensionValue(ASN1_OID) != null || x509Certificate.getExtensionValue(KNOX_OID) != null) {
EntryPoint.LOG("Certificate chain with dangerous extensions. Throw exception!");
throw new UnsupportedOperationException();
}
}
return keyStoreSpi.engineGetCertificateChain(alias);
}
return certificates;
}
@Override

View File

@ -4,19 +4,17 @@ import java.security.Provider;
public final class CustomProvider extends Provider {
public CustomProvider(Provider provider, boolean spoof) {
public CustomProvider(Provider provider) {
super(provider.getName(), provider.getVersion(), provider.getInfo());
putAll(provider);
if (spoof) put("KeyStore.AndroidKeyStore", CustomKeyStoreSpi.class.getName());
put("KeyStore.AndroidKeyStore", CustomKeyStoreSpi.class.getName());
}
@Override
public synchronized Service getService(String type, String algorithm) {
EntryPoint.LOG(String.format("Service: '%s' | Algorithm: '%s'", type, algorithm));
if ("AndroidKeyStore".equals(algorithm)) EntryPoint.spoofFields();
new Thread(EntryPoint::spoofFields).start();
return super.getService(type, algorithm);
}

View File

@ -17,24 +17,21 @@ public final class EntryPoint {
private static final Map<Field, String> map = new HashMap<>();
static {
boolean spoof = false;
try {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
Field keyStoreSpi = keyStore.getClass().getDeclaredField("keyStoreSpi");
Field field = keyStore.getClass().getDeclaredField("keyStoreSpi");
field.setAccessible(true);
keyStoreSpi.setAccessible(true);
CustomKeyStoreSpi.keyStoreSpi = (KeyStoreSpi) field.get(keyStore);
if (CustomKeyStoreSpi.keyStoreSpi != null) spoof = true;
CustomKeyStoreSpi.keyStoreSpi = (KeyStoreSpi) keyStoreSpi.get(keyStore);
} catch (Throwable t) {
LOG("Error spoofing AndroidKeyStore: " + t);
LOG("Couldn't get keyStoreSpi: " + t);
}
Provider provider = Security.getProvider("AndroidKeyStore");
Provider customProvider = new CustomProvider(provider, spoof);
Provider customProvider = new CustomProvider(provider);
Security.removeProvider("AndroidKeyStore");
Security.insertProviderAt(customProvider, 1);
@ -74,10 +71,11 @@ public final class EntryPoint {
map.forEach((field, s) -> {
try {
if (s.equals(field.get(null))) return;
field.setAccessible(true);
field.set(null, s);
LOG("Set " + field.getName() + " field value: " + s);
} catch (IllegalAccessException e) {
LOG("Couldn't access " + field.getName() + " value " + s + " | Exception: " + e);
} catch (Throwable t) {
LOG(t.toString());
}
});
}

View File

@ -6,13 +6,7 @@ Device verdict should pass by default.
If not, try removing /data/adb/pif.json file.
DO NOT REMOVE pif.json in module's folder!
# v15.7.1
# v15.8
- Fix crash issue when JSON file have comments.
- Fix hooking in older Android versions.
- Fix CTS profile / Device verdict failures in few devices due bad spoofing code.
- Fix spoofing Provider issue.
- Added post-fs-data.sh script.
- Using latest (compileable) version of Dobby.
- Using RikkaW libcxx prefab.
- Update Gradle.
- Correctly detect attestation certificate chain and block it.
- Misc improvements.

View File

@ -62,3 +62,18 @@ if [ -d "/system/app/EliteDevelopmentModule" ]; then
ui_print "- EliteDevelopmentModule app removed."
fi
if [ -f "/data/adb/pif.json" ]; then
mv -f "/data/adb/pif.json" "/data/adb/pif.json.old"
ui_print "- Backup old pif.json file"
ui_print "- Module will use the default one"
ui_print "- If you want to use your custom fingerprint, remove .old extension"
fi
ui_print "! If you don't pass DEVICE verdict after install (and reboot)"
ui_print "! Check kernel release name (In Shell run: 'uname -r')"
ui_print "! Google banned few strings in kernel to avoid users using custom kernels"
ui_print "! Try to use stock kernel or not banned one"
ui_print "! Kernels with 'bad' strings like 'lineageos' are banned!"
ui_print "! Check official XDA post to know more about this"
ui_print "! If you are using stock ROM without custom kernel just ignore this"

View File

@ -1,7 +1,7 @@
id=playintegrityfix
name=Play Integrity Fix
version=v15.7.2
versionCode=15702
version=v15.8
versionCode=15800
author=chiteroman
description=Universal modular fix for Play Integrity (and SafetyNet) on devices running Android 8+.
description=Universal modular fix for Play Integrity (and SafetyNet) on devices running Android 8-14.
updateJson=https://raw.githubusercontent.com/chiteroman/PlayIntegrityFix/main/update.json

View File

@ -17,21 +17,20 @@ resetprop_if_diff() {
[ -z "$CURRENT" ] || [ "$CURRENT" = "$EXPECTED" ] || resetprop "$NAME" "$EXPECTED"
}
# Conditional early sensitive properties
# 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
# OnePlus
resetprop_if_diff ro.is_ever_orange 0
# Microsoft, RootBeer
resetprop_if_diff ro.build.tags release-keys
# Other
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
resetprop_if_diff ro.is_ever_orange 0
resetprop_if_diff ro.build.type user
resetprop_if_diff ro.debuggable 0
resetprop_if_diff ro.secure 1

View File

@ -22,43 +22,33 @@ resetprop_if_match ro.boot.mode recovery unknown
resetprop_if_match vendor.boot.mode recovery unknown
# SELinux
resetprop_if_diff ro.boot.selinux enforcing
# use delete since it can be 0 or 1 for enforcing depending on OEM
if [ -n "$(resetprop ro.build.selinux)" ]; then
resetprop --delete ro.build.selinux
fi
# use toybox to protect *stat* access time reading
if [ "$(toybox cat /sys/fs/selinux/enforce)" == "0" ]; then
if [ "$(toybox cat /sys/fs/selinux/enforce)" = "0" ]; then
chmod 640 /sys/fs/selinux/enforce
chmod 440 /sys/fs/selinux/policy
fi
# Conditional late sensitive properties
# SafetyNet/Play Integrity
# Late props which must be set after boot_completed
{
# must be set after boot_completed for various OEMs
until [ "$(getprop sys.boot_completed)" = "1" ]; do
sleep 1
done
# avoid breaking Realme fingerprint scanners
resetprop_if_diff ro.boot.flash.locked 1
resetprop_if_diff ro.boot.realme.lockstate 1
# avoid breaking Oppo fingerprint scanners
resetprop_if_diff ro.boot.vbmeta.device_state locked
# avoid breaking OnePlus display modes/fingerprint scanners
resetprop_if_diff ro.boot.verifiedbootstate green
resetprop_if_diff ro.boot.veritymode enforcing
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
# Xiaomi
resetprop_if_diff ro.secureboot.lockstate locked
# Realme
resetprop_if_diff ro.boot.realmebootstate green
}&

View File

@ -1,6 +1,6 @@
{
"version": "v15.7.2",
"versionCode": 15702,
"zipUrl": "https://github.com/chiteroman/PlayIntegrityFix/releases/download/v15.7.2/PlayIntegrityFix_v15.7.2.zip",
"version": "v15.8",
"versionCode": 15800,
"zipUrl": "https://github.com/chiteroman/PlayIntegrityFix/releases/download/v15.8/PlayIntegrityFix_v15.8.zip",
"changelog": "https://raw.githubusercontent.com/chiteroman/PlayIntegrityFix/main/changelog.md"
}