This commit is contained in:
chiteroman 2023-11-25 02:13:22 +01:00
parent bed9055fd3
commit 27c00e2ce7
No known key found for this signature in database
GPG Key ID: 15FF53015D426D8E
15 changed files with 111 additions and 24798 deletions

View File

@ -2,16 +2,14 @@ cmake_minimum_required(VERSION 3.22.1)
project("playintegrityfix")
find_package(cxx REQUIRED CONFIG)
link_libraries(cxx::cxx)
add_library(${CMAKE_PROJECT_NAME} SHARED main.cpp)
add_subdirectory(Dobby)
SET_OPTION(Plugin.Android.BionicLinkerUtil ON)
find_package(cxx REQUIRED CONFIG)
target_link_libraries(dobby cxx::cxx)
target_link_libraries(dobby_static cxx::cxx)
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE cxx::cxx log dobby_static)
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE log dobby_static)

File diff suppressed because it is too large Load Diff

View File

@ -1,22 +1,18 @@
#include <android/log.h>
#include <sys/system_properties.h>
#include <unistd.h>
#include <string_view>
#include <map>
#include <vector>
#include "zygisk.hpp"
#include "dobby.h"
#include "json.hpp"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "PIF/Native", __VA_ARGS__)
#define DEX_FILE_PATH "/data/adb/modules/playintegrityfix/classes.dex"
#define FIRST_API_LEVEL "25"
#define PROP_FILE_PATH "/data/adb/modules/playintegrityfix/pif.json"
#define DEF_FIRST_API_LEVEL "23"
#define DEF_SECURITY_PATCH "2017-08-05"
static std::string SECURITY_PATCH, FIRST_API_LEVEL;
#define SECURITY_PATCH "2017-08-05"
typedef void (*T_Callback)(void *, const char *, const char *, uint32_t);
@ -31,21 +27,13 @@ static void modify_callback(void *cookie, const char *name, const char *value, u
std::string_view prop(name);
if (prop.ends_with("api_level")) {
if (FIRST_API_LEVEL.empty()) {
value = nullptr;
} else {
value = FIRST_API_LEVEL.c_str();
}
value = FIRST_API_LEVEL;
LOGD("[%s] -> %s", name, value);
} else if (prop.ends_with("security_patch")) {
if (SECURITY_PATCH.empty()) {
value = nullptr;
} else {
value = SECURITY_PATCH.c_str();
}
value = SECURITY_PATCH;
LOGD("[%s] -> %s", name, value);
}
if (!prop.starts_with("cache") && !prop.starts_with("debug")) LOGD("[%s] -> %s", name, value);
return callbacks[cookie](cookie, name, value, serial);
}
@ -102,41 +90,24 @@ public:
return;
}
auto rawDir = env->GetStringUTFChars(args->app_data_dir, nullptr);
path = rawDir;
env->ReleaseStringUTFChars(args->app_data_dir, rawDir);
int fd = api->connectCompanion();
write(fd, path.data(), path.size());
long size;
char buffer[1024];
read(fd, nullptr, 0);
while ((size = read(fd, buffer, sizeof(buffer))) > 0) {
moduleDex.insert(moduleDex.end(), buffer, buffer + size);
}
close(fd);
LOGD("Received from socket %lu bytes!", moduleDex.size());
}
void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override {
if (path.empty()) return;
if (moduleDex.empty()) return;
std::string prop(path + "/cache/pif.json");
if (std::filesystem::exists(prop)) {
FILE *file = fopen(prop.c_str(), "r");
nlohmann::json json = nlohmann::json::parse(file, nullptr, false);
fclose(file);
LOGD("Read %d props from pif.json", static_cast<int>(json.size()));
SECURITY_PATCH = json["SECURITY_PATCH"].get<std::string>();
FIRST_API_LEVEL = json["FIRST_API_LEVEL"].get<std::string>();
json.clear();
} else {
LOGD("File pif.json doesn't exist, using default values");
SECURITY_PATCH = DEF_SECURITY_PATCH;
FIRST_API_LEVEL = DEF_FIRST_API_LEVEL;
}
std::string dex(path + "/cache/classes.dex");
if (std::filesystem::exists(dex)) {
inject();
}
inject();
doHook();
}
@ -148,7 +119,7 @@ public:
private:
zygisk::Api *api = nullptr;
JNIEnv *env = nullptr;
std::string path;
std::vector<char> moduleDex;
void inject() {
LOGD("get system classloader");
@ -158,12 +129,12 @@ private:
auto systemClassLoader = env->CallStaticObjectMethod(clClass, getSystemClassLoader);
LOGD("create class loader");
auto pathClClass = env->FindClass("dalvik/system/PathClassLoader");
auto pathClInit = env->GetMethodID(pathClClass, "<init>",
"(Ljava/lang/String;Ljava/lang/ClassLoader;)V");
std::string dexPath(path + "/cache/classes.dex");
auto moduleDex = env->NewStringUTF(dexPath.c_str());
auto dexCl = env->NewObject(pathClClass, pathClInit, moduleDex, systemClassLoader);
auto dexClClass = env->FindClass("dalvik/system/InMemoryDexClassLoader");
auto dexClInit = env->GetMethodID(dexClClass, "<init>",
"(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
auto buffer = env->NewDirectByteBuffer(moduleDex.data(),
static_cast<jlong>(moduleDex.size()));
auto dexCl = env->NewObject(dexClClass, dexClInit, buffer, systemClassLoader);
LOGD("load class");
auto loadClass = env->GetMethodID(clClass, "loadClass",
@ -173,49 +144,34 @@ private:
auto entryClass = (jclass) entryClassObj;
LOGD("read props");
auto readProps = env->GetStaticMethodID(entryClass, "readProps", "(Ljava/lang/String;)V");
std::string prop(path + "/cache/pif.json");
auto javaPath = env->NewStringUTF(prop.c_str());
env->CallStaticVoidMethod(entryClass, readProps, javaPath);
LOGD("call init");
auto entryInit = env->GetStaticMethodID(entryClass, "init", "()V");
env->CallStaticVoidMethod(entryClass, entryInit);
path.clear();
moduleDex.clear();
}
};
static void companion(int fd) {
char buffer[256];
long size = read(fd, buffer, sizeof(buffer));
FILE *file = fopen("/data/adb/modules/playintegrityfix/classes.dex", "rb");
std::string path(buffer, size);
LOGD("[ROOT] Got GMS dir: %s", path.c_str());
std::string dex(path + "/cache/classes.dex");
std::string prop(path + "/cache/pif.json");
if (std::filesystem::copy_file(DEX_FILE_PATH, dex,
std::filesystem::copy_options::overwrite_existing)) {
std::filesystem::permissions(dex, std::filesystem::perms::owner_read |
std::filesystem::perms::group_read |
std::filesystem::perms::others_read);
if (file == nullptr) {
write(fd, nullptr, 0);
return;
}
if (!std::filesystem::exists(PROP_FILE_PATH)) {
std::filesystem::remove(prop);
}
fseek(file, 0, SEEK_END);
long size = ftell(file);
fseek(file, 0, SEEK_SET);
if (std::filesystem::copy_file(PROP_FILE_PATH, prop,
std::filesystem::copy_options::overwrite_existing)) {
std::filesystem::permissions(prop, std::filesystem::perms::owner_read |
std::filesystem::perms::group_read |
std::filesystem::perms::others_read);
}
std::vector<char> vector(size);
fread(vector.data(), 1, size, file);
write(fd, nullptr, 0);
fclose(file);
write(fd, vector.data(), size);
vector.clear();
}
REGISTER_ZYGISK_MODULE(PlayIntegrityFix)

View File

@ -1,54 +1,29 @@
package es.chiteroman.playintegrityfix;
import android.os.Build;
import android.util.JsonReader;
import android.util.Log;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Field;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.KeyStoreSpi;
import java.security.Provider;
import java.security.Security;
import java.util.HashMap;
import java.util.Map;
public final class EntryPoint {
private static final Map<String, String> map = new HashMap<>();
private static void defaultProps() {
map.putIfAbsent("PRODUCT", "bullhead");
map.putIfAbsent("DEVICE", "bullhead");
map.putIfAbsent("MANUFACTURER", "LGE");
map.putIfAbsent("BRAND", "google");
map.putIfAbsent("MODEL", "Nexus 5X");
map.putIfAbsent("FINGERPRINT", "google/bullhead/bullhead:8.0.0/OPR6.170623.013/4283548:user/release-keys");
map.putIfAbsent("SECURITY_PATCH", "2017-08-05");
}
private static final String PRODUCT = "sailfish";
private static final String DEVICE = "sailfish";
private static final String MANUFACTURER = "Google";
private static final String BRAND = "google";
private static final String MODEL = "Pixel";
private static final String FINGERPRINT = "google/sailfish/sailfish:7.1.2/NZH54D/4146044:user/release-keys";
private static final String SECURITY_PATCH = "2017-08-05";
public static void init() {
spoofProvider();
spoofDevice();
}
public static void readProps(String path) {
LOG("Read from Zygisk lib path: " + path);
File file = new File(path);
try (JsonReader reader = new JsonReader(new FileReader(file))) {
reader.beginObject();
while (reader.hasNext()) {
map.put(reader.nextName(), reader.nextString());
}
reader.endObject();
} catch (IOException e) {
LOG("Couldn't read pif.prop file: " + e);
defaultProps();
}
}
private static void spoofProvider() {
final String KEYSTORE = "AndroidKeyStore";
@ -76,14 +51,14 @@ public final class EntryPoint {
}
}
public static void spoofDevice() {
setProp("PRODUCT", map.get("PRODUCT"));
setProp("DEVICE", map.get("DEVICE"));
setProp("MANUFACTURER", map.get("MANUFACTURER"));
setProp("BRAND", map.get("BRAND"));
setProp("MODEL", map.get("MODEL"));
setProp("FINGERPRINT", map.get("FINGERPRINT"));
setVersionProp("SECURITY_PATCH", map.get("SECURITY_PATCH"));
static void spoofDevice() {
setProp("PRODUCT", PRODUCT);
setProp("DEVICE", DEVICE);
setProp("MANUFACTURER", MANUFACTURER);
setProp("BRAND", BRAND);
setProp("MODEL", MODEL);
setProp("FINGERPRINT", FINGERPRINT);
setVersionProp("SECURITY_PATCH", SECURITY_PATCH);
}
private static void setProp(String name, String value) {
@ -120,7 +95,7 @@ public final class EntryPoint {
}
}
public static void LOG(String msg) {
static void LOG(String msg) {
Log.d("PIF/Java", msg);
}
}

View File

@ -2,12 +2,16 @@ We have a Telegram channel!
If you want to share your knowledge join:
https://t.me/playintegrityfix
Also, if Google blacklist the fingerprint (again), you can post your custom pif.json and I will update the module.
# v13.7
# v13.6
- Removed custom resetprop.
- Removed custom props spoof.
- Removed weird code.
- New code!
- Added custom resetprop.
If you want an undetectable resetprop, use Kitsune Magisk.
If you want to spoof your own props, modify the props in source code and build by yourself.
Should work and don't crash nothing.
Can read a custom pif.json file to spoof device props.
Example file: module/pif.json on GitHub repo.
Maybe in a future I do a custom spoof version... But I won't release it as stable build.
I recommend to clear GMS data and cache before reboot.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -5,16 +5,6 @@ fi
# safetynet-fix module is incompatible
if [ -d "/data/adb/modules/safetynet-fix" ]; then
ui_print "!!! safetynet-fix module removed!"
touch "/data/adb/modules/safetynet-fix/remove"
ui_print "!!! safetynet-fix module removed!"
fi
# Backup old pif.prop
if [ -e "/data/adb/modules/playintegrityfix/pif.prop" ]; then
ui_print "- Backup old pif.prop."
mv "/data/adb/modules/playintegrityfix/pif.prop" "/data/adb/pif.prop.old"
fi
# use our resetprop
mv -f "$MODPATH/bin/$ABI/resetprop" "$MODPATH"
rm -rf "$MODPATH/bin"

View File

@ -1,7 +1,7 @@
id=playintegrityfix
name=Play Integrity Fix
version=v13.6
versionCode=136
version=v13.7
versionCode=137
author=chiteroman
description=Fix CTS profile (SafetyNet) and DEVICE verdict (Play Integrity).
updateJson=https://raw.githubusercontent.com/chiteroman/PlayIntegrityFix/main/update.json

View File

@ -1,10 +0,0 @@
{
"PRODUCT": "taimen",
"DEVICE": "taimen",
"MANUFACTURER": "Google",
"BRAND": "google",
"MODEL": "Pixel 2 XL",
"FINGERPRINT": "google/taimen/taimen:10/QQ2A.200501.001.B3/6396602:user/release-keys",
"SECURITY_PATCH": "2020-05-05",
"FIRST_API_LEVEL": "25"
}

View File

@ -1,23 +1,12 @@
# Sensitive properties
RESETPROP="${0%/*}/resetprop"
chmod 755 $RESETPROP
check_resetprop() {
local NAME=$1
local EXPECTED=$2
local VALUE=$(resetprop $NAME)
[ -z $VALUE ] || [ $VALUE = $EXPECTED ] || $RESETPROP -n $NAME $EXPECTED
}
maybe_set_prop() {
local prop="$1"
local contains="$2"
local value="$3"
if [[ "$(getprop "$prop")" == *"$contains"* ]]; then
$RESETPROP -n "$prop" "$value"
resetprop "$prop" "$value"
fi
}
@ -26,41 +15,32 @@ maybe_set_prop ro.bootmode recovery unknown
maybe_set_prop ro.boot.mode recovery unknown
maybe_set_prop vendor.boot.mode recovery unknown
# Reset props after boot completed to avoid breaking some weird devices/ROMs...
# Hiding SELinux | Permissive status
resetprop --delete ro.build.selinux
# Hiding SELinux | 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
# Late props which must be set after boot_completed
{
until [[ "$(getprop sys.boot_completed)" == "1" ]]; do
sleep 1
done
# SafetyNet/Play Integrity | Avoid breaking Realme fingerprint scanners
check_resetprop ro.boot.flash.locked 1
resetprop ro.boot.flash.locked 1
# SafetyNet/Play Integrity | Avoid breaking Oppo fingerprint scanners
check_resetprop ro.boot.vbmeta.device_state locked
resetprop ro.boot.vbmeta.device_state locked
# SafetyNet/Play Integrity | Avoid breaking OnePlus display modes/fingerprint scanners
check_resetprop vendor.boot.verifiedbootstate green
resetprop vendor.boot.verifiedbootstate green
# SafetyNet/Play Integrity | Avoid breaking OnePlus display modes/fingerprint scanners on OOS 12
check_resetprop ro.boot.verifiedbootstate green
check_resetprop ro.boot.veritymode enforcing
check_resetprop vendor.boot.vbmeta.device_state locked
# RootBeer, Microsoft
check_resetprop ro.build.tags release-keys
# Samsung
check_resetprop ro.boot.warranty_bit 0
check_resetprop ro.vendor.boot.warranty_bit 0
check_resetprop ro.vendor.warranty_bit 0
check_resetprop ro.warranty_bit 0
# OnePlus
check_resetprop ro.is_ever_orange 0
# Other
check_resetprop ro.build.type user
check_resetprop ro.debuggable 0
check_resetprop ro.secure 1
resetprop ro.boot.verifiedbootstate green
resetprop ro.boot.veritymode enforcing
resetprop vendor.boot.vbmeta.device_state locked
}&

16
module/system.prop Normal file
View File

@ -0,0 +1,16 @@
# RootBeer, Microsoft
ro.build.tags=release-keys
# Samsung
ro.boot.warranty_bit=0
ro.vendor.boot.warranty_bit=0
ro.vendor.warranty_bit=0
ro.warranty_bit=0
# OnePlus
ro.is_ever_orange=0
# Other
ro.build.type=user
ro.debuggable=0
ro.secure=1

View File

@ -1,6 +1,6 @@
{
"version": "v13.6",
"versionCode": 136,
"zipUrl": "https://github.com/chiteroman/PlayIntegrityFix/releases/download/v13.6/PlayIntegrityFix_v13.6.zip",
"version": "v13.7",
"versionCode": 137,
"zipUrl": "https://github.com/chiteroman/PlayIntegrityFix/releases/download/v13.7/PlayIntegrityFix_v13.7.zip",
"changelog": "https://raw.githubusercontent.com/chiteroman/PlayIntegrityFix/main/changelog.md"
}