Skip to content
Snippets Groups Projects
Unverified Commit c950e21a authored by chiteroman's avatar chiteroman
Browse files

Stable version v13.8

parent 4dcf53b3
No related branches found
No related tags found
No related merge requests found
Showing
with 29 additions and 24972 deletions
# Default ignored files
/shelf/
/workspace.xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="17" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="jbr-17" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>
\ No newline at end of file
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
<option name="processCode" value="true" />
<option name="processLiterals" value="true" />
<option name="processComments" value="true" />
</inspection_tool>
</profile>
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
\ No newline at end of file
...@@ -28,11 +28,6 @@ It injects a classes.dex file to modify few fields in android.os.Build class. Al ...@@ -28,11 +28,6 @@ It injects a classes.dex file to modify few fields in android.os.Build class. Al
it creates a hook to modify system properties. it creates a hook to modify system properties.
The purpose of the module is to avoid a hardware attestation. The purpose of the module is to avoid a hardware attestation.
## About 'pif.json' file
You can modify this file to spoof android.os.Build fields in GMS unstable process and try to pass Device verdict.
You can't use values from recent devices due this devices must use a hardware attestation.
## Failing BASIC verdict ## Failing BASIC verdict
If you are failing basicIntegrity (SafetyNet) or MEETS_BASIC_INTEGRITY (Play Integrity) something is If you are failing basicIntegrity (SafetyNet) or MEETS_BASIC_INTEGRITY (Play Integrity) something is
......
...@@ -42,33 +42,4 @@ android { ...@@ -42,33 +42,4 @@ android {
path = file("src/main/cpp/Android.mk") path = file("src/main/cpp/Android.mk")
} }
} }
}
tasks.register("copyFiles") {
doLast {
val moduleFolder = project.rootDir.resolve("module")
val dexFile = project.buildDir.resolve("intermediates/dex/release/minifyReleaseWithR8/classes.dex")
val soDir = project.buildDir.resolve("intermediates/stripped_native_libs/release/out/lib")
dexFile.copyTo(moduleFolder.resolve("classes.dex"), overwrite = true)
soDir.walk().filter { it.isFile && it.extension == "so" }.forEach { soFile ->
val abiFolder = soFile.parentFile.name
val destination = moduleFolder.resolve("zygisk/$abiFolder.so")
soFile.copyTo(destination, overwrite = true)
}
}
}
tasks.register<Zip>("zip") {
dependsOn("copyFiles")
archiveFileName.set("PlayIntegrityFix.zip")
destinationDirectory.set(project.rootDir.resolve("out"))
from(project.rootDir.resolve("module"))
}
afterEvaluate {
tasks["assembleRelease"].finalizedBy("copyFiles", "zip")
} }
\ No newline at end of file
This diff is collapsed.
#include <android/log.h> #include <android/log.h>
#include <sys/system_properties.h> #include <sys/system_properties.h>
#include <unistd.h> #include <map>
#include <fstream> #include <string_view>
#include "zygisk.hpp" #include "zygisk.hpp"
#include "shadowhook.h" #include "shadowhook.h"
#include "json.hpp" #include "classes_dex.h"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "PIF/Native", __VA_ARGS__) #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 JSON_FILE_PATH "/data/adb/modules/playintegrityfix/pif.json" #define SECURITY_PATCH "2018-07-05"
static std::string FIRST_API_LEVEL, SECURITY_PATCH;
typedef void (*T_Callback)(void *, const char *, const char *, uint32_t); typedef void (*T_Callback)(void *, const char *, const char *, uint32_t);
...@@ -28,18 +26,10 @@ static void modify_callback(void *cookie, const char *name, const char *value, u ...@@ -28,18 +26,10 @@ static void modify_callback(void *cookie, const char *name, const char *value, u
std::string_view prop(name); std::string_view prop(name);
if (prop.ends_with("api_level")) { if (prop.ends_with("api_level")) {
if (FIRST_API_LEVEL == "nullptr") { value = FIRST_API_LEVEL;
value = nullptr;
} else {
value = FIRST_API_LEVEL.c_str();
}
LOGD("[%s] -> %s", name, value); LOGD("[%s] -> %s", name, value);
} else if (prop.ends_with("security_patch")) { } else if (prop.ends_with("security_patch")) {
if (SECURITY_PATCH == "nullptr") { value = SECURITY_PATCH;
value = nullptr;
} else {
value = SECURITY_PATCH.c_str();
}
LOGD("[%s] -> %s", name, value); LOGD("[%s] -> %s", name, value);
} }
...@@ -85,67 +75,23 @@ public: ...@@ -85,67 +75,23 @@ public:
std::string_view process(rawProcess); std::string_view process(rawProcess);
bool isGms = process.starts_with("com.google.android.gms"); bool isGms = process.starts_with("com.google.android.gms");
bool isGmsUnstable = process.compare("com.google.android.gms.unstable") == 0; isGmsUnstable = process.compare("com.google.android.gms.unstable") == 0;
env->ReleaseStringUTFChars(args->nice_name, rawProcess); env->ReleaseStringUTFChars(args->nice_name, rawProcess);
if (!isGms) { if (isGms) api->setOption(zygisk::FORCE_DENYLIST_UNMOUNT);
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
return;
}
api->setOption(zygisk::FORCE_DENYLIST_UNMOUNT);
if (!isGmsUnstable) {
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
return;
}
int dexSize = 0;
int jsonSize = 0;
int fd = api->connectCompanion();
read(fd, &dexSize, sizeof(int));
read(fd, &jsonSize, sizeof(int));
if (dexSize < 1) { if (isGmsUnstable) return;
close(fd);
LOGD("Couldn't read classes.dex");
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
return;
}
if (jsonSize < 1) { api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
close(fd);
LOGD("Couldn't read pif.json");
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
return;
}
dexVector.resize(dexSize);
jsonVector.resize(jsonSize);
read(fd, dexVector.data(), dexSize);
read(fd, jsonVector.data(), jsonSize);
close(fd);
LOGD("Read from file descriptor file 'classes.dex' -> %d bytes", dexSize);
LOGD("Read from file descriptor file 'pif.json' -> %d bytes", jsonSize);
} }
void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override { void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override {
if (dexVector.empty() || jsonVector.empty()) return; if (!isGmsUnstable) return;
readJson();
doHook(); doHook();
inject(); inject();
dexVector.clear();
jsonVector.clear();
} }
void preServerSpecialize(zygisk::ServerSpecializeArgs *args) override { void preServerSpecialize(zygisk::ServerSpecializeArgs *args) override {
...@@ -155,38 +101,7 @@ public: ...@@ -155,38 +101,7 @@ public:
private: private:
zygisk::Api *api = nullptr; zygisk::Api *api = nullptr;
JNIEnv *env = nullptr; JNIEnv *env = nullptr;
std::vector<char> dexVector, jsonVector; bool isGmsUnstable = false;
void readJson() {
std::string data(jsonVector.cbegin(), jsonVector.cend());
nlohmann::json json = nlohmann::json::parse(data, nullptr, false, true);
if (json.contains("SECURITY_PATCH")) {
if (json["SECURITY_PATCH"].is_null()) {
SECURITY_PATCH = "nullptr";
} 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("FIRST_API_LEVEL")) {
if (json["FIRST_API_LEVEL"].is_null()) {
FIRST_API_LEVEL = "nullptr";
} else if (json["FIRST_API_LEVEL"].is_string()) {
FIRST_API_LEVEL = json["FIRST_API_LEVEL"].get<std::string>();
} else {
LOGD("Error parsing FIRST_API_LEVEL!");
}
} else {
LOGD("Key FIRST_API_LEVEL doesn't exist in JSON file!");
}
json.clear();
}
void inject() { void inject() {
LOGD("get system classloader"); LOGD("get system classloader");
...@@ -199,8 +114,7 @@ private: ...@@ -199,8 +114,7 @@ private:
auto dexClClass = env->FindClass("dalvik/system/InMemoryDexClassLoader"); auto dexClClass = env->FindClass("dalvik/system/InMemoryDexClassLoader");
auto dexClInit = env->GetMethodID(dexClClass, "<init>", auto dexClInit = env->GetMethodID(dexClClass, "<init>",
"(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V"); "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
auto buffer = env->NewDirectByteBuffer(dexVector.data(), auto buffer = env->NewDirectByteBuffer(classes_dex, classes_dex_len);
static_cast<jlong>(dexVector.size()));
auto dexCl = env->NewObject(dexClClass, dexClInit, buffer, systemClassLoader); auto dexCl = env->NewObject(dexClClass, dexClInit, buffer, systemClassLoader);
LOGD("load class"); LOGD("load class");
...@@ -211,38 +125,10 @@ private: ...@@ -211,38 +125,10 @@ private:
auto entryClass = (jclass) entryClassObj; auto entryClass = (jclass) entryClassObj;
LOGD("read json");
auto readProps = env->GetStaticMethodID(entryClass, "readJson",
"(Ljava/lang/String;)V");
std::string data(jsonVector.cbegin(), jsonVector.cend());
auto javaStr = env->NewStringUTF(data.c_str());
env->CallStaticVoidMethod(entryClass, readProps, javaStr);
LOGD("call init"); LOGD("call init");
auto entryInit = env->GetStaticMethodID(entryClass, "init", "()V"); auto entryInit = env->GetStaticMethodID(entryClass, "init", "()V");
env->CallStaticVoidMethod(entryClass, entryInit); env->CallStaticVoidMethod(entryClass, entryInit);
} }
}; };
static void companion(int fd) { REGISTER_ZYGISK_MODULE(PlayIntegrityFix)
std::ifstream dex(DEX_FILE_PATH, std::ios::binary); \ No newline at end of file
std::ifstream json(JSON_FILE_PATH);
std::vector<char> dexVector((std::istreambuf_iterator<char>(dex)),
std::istreambuf_iterator<char>());
std::vector<char> jsonVector((std::istreambuf_iterator<char>(json)),
std::istreambuf_iterator<char>());
int dexSize = static_cast<int>(dexVector.size());
int jsonSize = static_cast<int>(jsonVector.size());
write(fd, &dexSize, sizeof(int));
write(fd, &jsonSize, sizeof(int));
write(fd, dexVector.data(), dexSize);
write(fd, jsonVector.data(), jsonSize);
}
REGISTER_ZYGISK_MODULE(PlayIntegrityFix)
REGISTER_ZYGISK_COMPANION(companion)
\ No newline at end of file
package es.chiteroman.playintegrityfix; package es.chiteroman.playintegrityfix;
import android.os.Build; import android.os.Build;
import android.util.JsonReader;
import android.util.Log; import android.util.Log;
import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.security.KeyStore; import java.security.KeyStore;
import java.security.KeyStoreException; import java.security.KeyStoreException;
import java.security.KeyStoreSpi; import java.security.KeyStoreSpi;
import java.security.Provider; import java.security.Provider;
import java.security.Security; import java.security.Security;
import java.util.HashMap;
import java.util.Map;
public final class EntryPoint { public final class EntryPoint {
private static final Map<String, String> map = new HashMap<>(); 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:8.1.0/OPM4.171019.021.P1/4820305:user/release-keys";
private static final String SECURITY_PATCH = "2018-07-05";
public static void init() { public static void init() {
spoofProvider(); spoofProvider();
spoofDevice(); spoofDevice();
} }
public static void readJson(String data) {
try (JsonReader reader = new JsonReader(new StringReader(data))) {
reader.beginObject();
while (reader.hasNext()) {
map.put(reader.nextName(), reader.nextString());
}
reader.endObject();
} catch (IOException e) {
LOG("Couldn't read JSON from Zygisk: " + e);
}
}
private static void spoofProvider() { private static void spoofProvider() {
final String KEYSTORE = "AndroidKeyStore"; final String KEYSTORE = "AndroidKeyStore";
...@@ -63,15 +52,13 @@ public final class EntryPoint { ...@@ -63,15 +52,13 @@ public final class EntryPoint {
} }
static void spoofDevice() { static void spoofDevice() {
if (map.isEmpty()) return; setProp("PRODUCT", PRODUCT);
setProp("DEVICE", DEVICE);
setProp("PRODUCT", map.get("PRODUCT")); setProp("MANUFACTURER", MANUFACTURER);
setProp("DEVICE", map.get("DEVICE")); setProp("BRAND", BRAND);
setProp("MANUFACTURER", map.get("MANUFACTURER")); setProp("MODEL", MODEL);
setProp("BRAND", map.get("BRAND")); setProp("FINGERPRINT", FINGERPRINT);
setProp("MODEL", map.get("MODEL")); setVersionProp("SECURITY_PATCH", SECURITY_PATCH);
setProp("FINGERPRINT", map.get("FINGERPRINT"));
setVersionProp("SECURITY_PATCH", map.get("SECURITY_PATCH"));
} }
private static void setProp(String name, String value) { private static void setProp(String name, String value) {
......
#!/sbin/sh
#################
# Initialization
#################
umask 022
# echo before loading util_functions
ui_print() { echo "$1"; }
require_new_magisk() {
ui_print "*******************************"
ui_print " Please install Magisk v20.4+! "
ui_print "*******************************"
exit 1
}
#########################
# Load util_functions.sh
#########################
OUTFD=$2
ZIPFILE=$3
mount /data 2>/dev/null
[ -f /data/adb/magisk/util_functions.sh ] || require_new_magisk
. /data/adb/magisk/util_functions.sh
[ $MAGISK_VER_CODE -lt 20400 ] && require_new_magisk
install_module
exit 0
#MAGISK
# Error on < Android 8
if [ "$API" -lt 26 ]; then
abort "!!! You can't use this module on Android < 8.0."
fi
# safetynet-fix module is incompatible
if [ -d "/data/adb/modules/safetynet-fix" ]; then
touch "/data/adb/modules/safetynet-fix/remove"
ui_print "- 'safetynet-fix' module will be removed in next reboot."
fi
\ No newline at end of file
id=playintegrityfix
name=Play Integrity Fix
version=PROPS-v2.0
versionCode=2000
author=chiteroman
description=Fix CTS profile (SafetyNet) and DEVICE verdict (Play Integrity).
updateJson=https://raw.githubusercontent.com/chiteroman/PlayIntegrityFix/main/update.json
\ No newline at end of file
{
"PRODUCT": "taimen",
"DEVICE": "taimen",
"MANUFACTURER": "Google",
"BRAND": "google",
"MODEL": "Pixel 2 XL",
"FINGERPRINT": "google/taimen/taimen:8.1.0/OPM4.171019.021.R1/4833808:user/release-keys",
"SECURITY_PATCH": "2018-07-05",
"FIRST_API_LEVEL": "25"
}
\ No newline at end of file
# Remove Play Services from the Magisk Denylist when set to enforcing
if magisk --denylist status; then
magisk --denylist rm com.google.android.gms
fi
# Check if safetynet-fix is installed
if [ -d "/data/adb/modules/safetynet-fix" ]; then
touch "/data/adb/modules/safetynet-fix/remove"
fi
\ No newline at end of file
# Sensitive properties
maybe_set_prop() {
local prop="$1"
local contains="$2"
local value="$3"
if [[ "$(getprop "$prop")" == *"$contains"* ]]; then
resetprop "$prop" "$value"
fi
}
# Magisk recovery mode
maybe_set_prop ro.bootmode recovery unknown
maybe_set_prop ro.boot.mode recovery unknown
maybe_set_prop vendor.boot.mode recovery unknown
# 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
resetprop ro.boot.flash.locked 1
# SafetyNet/Play Integrity | Avoid breaking Oppo fingerprint scanners
resetprop ro.boot.vbmeta.device_state locked
# SafetyNet/Play Integrity | Avoid breaking OnePlus display modes/fingerprint scanners
resetprop vendor.boot.verifiedbootstate green
# SafetyNet/Play Integrity | Avoid breaking OnePlus display modes/fingerprint scanners on OOS 12
resetprop ro.boot.verifiedbootstate green
resetprop ro.boot.veritymode enforcing
resetprop vendor.boot.vbmeta.device_state locked
}&
# 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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment