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

Custom props!

parent 27c00e2c
No related branches found
No related tags found
No related merge requests found
......@@ -28,7 +28,7 @@ It injects a classes.dex file to modify few fields in android.os.Build class. Al
it creates a hook to modify system properties.
The purpose of the module is to avoid a hardware attestation.
## About 'pif.prop' file
## 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.
......
This diff is collapsed.
#include <android/log.h>
#include <sys/system_properties.h>
#include <unistd.h>
#include <string_view>
#include <map>
#include <vector>
#include <fstream>
#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 PROP_FILE_PATH "/data/adb/modules/playintegrityfix/pif.json"
#define FIRST_API_LEVEL "25"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "PIF/Native", __VA_ARGS__)
#define SECURITY_PATCH "2017-08-05"
static std::string FIRST_API_LEVEL, SECURITY_PATCH;
typedef void (*T_Callback)(void *, const char *, const char *, uint32_t);
......@@ -27,10 +28,18 @@ static void modify_callback(void *cookie, const char *name, const char *value, u
std::string_view prop(name);
if (prop.ends_with("api_level")) {
value = FIRST_API_LEVEL;
if (FIRST_API_LEVEL == "NULL") {
value = nullptr;
} else {
value = FIRST_API_LEVEL.c_str();
}
LOGD("[%s] -> %s", name, value);
} else if (prop.ends_with("security_patch")) {
value = SECURITY_PATCH;
if (SECURITY_PATCH == "NULL") {
value = nullptr;
} else {
value = SECURITY_PATCH.c_str();
}
LOGD("[%s] -> %s", name, value);
}
......@@ -90,23 +99,44 @@ public:
return;
}
ssize_t size;
char buffer[10000];
int fd = api->connectCompanion();
long size;
char buffer[1024];
size = read(fd, buffer, sizeof(buffer));
while ((size = read(fd, buffer, sizeof(buffer))) > 0) {
if (size > 0) {
moduleDex.insert(moduleDex.end(), buffer, buffer + size);
} else {
LOGD("Couldn't load classes.dex file in memory");
close(fd);
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
return;
}
lseek(fd, 0, SEEK_SET);
size = read(fd, buffer, sizeof(buffer));
if (size > 0) {
jsonStr.insert(jsonStr.end(), buffer, buffer + size);
} else {
LOGD("Couldn't load pif.json file in memory");
}
close(fd);
LOGD("Received from socket %lu bytes!", moduleDex.size());
LOGD("Received 'classes.dex' file from socket: %d bytes",
static_cast<int>(moduleDex.size()));
LOGD("Received 'pif.json' file from socket: %d bytes", static_cast<int>(jsonStr.size()));
}
void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override {
if (moduleDex.empty()) return;
readJson();
inject();
doHook();
......@@ -120,6 +150,21 @@ private:
zygisk::Api *api = nullptr;
JNIEnv *env = nullptr;
std::vector<char> moduleDex;
std::string jsonStr;
void readJson() {
nlohmann::json json = nlohmann::json::parse(jsonStr, nullptr, false);
auto getStringFromJson = [&json](const std::string &key) {
return json.contains(key) && !json[key].is_null() ? json[key].get<std::string>()
: "NULL";
};
SECURITY_PATCH = getStringFromJson("SECURITY_PATCH");
FIRST_API_LEVEL = getStringFromJson("FIRST_API_LEVEL");
json.clear();
}
void inject() {
LOGD("get system classloader");
......@@ -144,34 +189,34 @@ private:
auto entryClass = (jclass) entryClassObj;
LOGD("read json");
auto readProps = env->GetStaticMethodID(entryClass, "readJson",
"(Ljava/lang/String;)V");
auto javaStr = env->NewStringUTF(jsonStr.c_str());
env->CallStaticVoidMethod(entryClass, readProps, javaStr);
LOGD("call init");
auto entryInit = env->GetStaticMethodID(entryClass, "init", "()V");
env->CallStaticVoidMethod(entryClass, entryInit);
moduleDex.clear();
jsonStr.clear();
}
};
static void companion(int fd) {
FILE *file = fopen("/data/adb/modules/playintegrityfix/classes.dex", "rb");
if (file == nullptr) {
write(fd, nullptr, 0);
return;
}
fseek(file, 0, SEEK_END);
long size = ftell(file);
fseek(file, 0, SEEK_SET);
std::vector<char> vector(size);
fread(vector.data(), 1, size, file);
std::ifstream dex(DEX_FILE_PATH, std::ios::binary);
std::ifstream prop(PROP_FILE_PATH);
fclose(file);
std::vector<char> dexVector((std::istreambuf_iterator<char>(dex)),
std::istreambuf_iterator<char>());
write(fd, vector.data(), size);
std::vector<char> propVector((std::istreambuf_iterator<char>(prop)),
std::istreambuf_iterator<char>());
vector.clear();
write(fd, dexVector.data(), dexVector.size());
lseek(fd, 0, SEEK_SET);
write(fd, propVector.data(), propVector.size());
}
REGISTER_ZYGISK_MODULE(PlayIntegrityFix)
......
package es.chiteroman.playintegrityfix;
import android.os.Build;
import android.util.JsonReader;
import android.util.Log;
import java.io.IOException;
import java.io.StringReader;
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 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";
private static final Map<String, String> map = new HashMap<>();
public static void init() {
spoofProvider();
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() {
final String KEYSTORE = "AndroidKeyStore";
......@@ -52,13 +63,15 @@ public final class EntryPoint {
}
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);
if (map.isEmpty()) return;
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"));
}
private static void setProp(String name, String value) {
......
......@@ -10,8 +10,7 @@ https://t.me/playintegrityfix
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.
Or you can use unstable build, you can download in GitHub repo.
Should work and don't crash nothing.
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.
\ No newline at end of file
id=playintegrityfix
name=Play Integrity Fix
version=v13.7
versionCode=137
version=v1.1-PROPS
versionCode=1
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
description=Fix CTS profile (SafetyNet) and DEVICE verdict (Play Integrity).
\ 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
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