mirror of
https://github.com/chiteroman/PlayIntegrityFix.git
synced 2025-01-18 19:12:38 +02:00
Improvements
- Better logic in prop hook. - Extract common fields from fingerprint. - Other changes.
This commit is contained in:
parent
51350088ae
commit
ac9d4d385c
@ -53,9 +53,15 @@ static void modify_callback(void *cookie, const char *name, const char *value, u
|
|||||||
|
|
||||||
if (!cookie || !name || !value || !o_callback) return;
|
if (!cookie || !name || !value || !o_callback) return;
|
||||||
|
|
||||||
|
const char *oldValue = value;
|
||||||
|
|
||||||
std::string_view prop(name);
|
std::string_view prop(name);
|
||||||
|
|
||||||
if (prop.ends_with("api_level")) {
|
if (prop == "init.svc.adbd") {
|
||||||
|
value = "stopped";
|
||||||
|
} else if (prop == "sys.usb.state") {
|
||||||
|
value = "mtp";
|
||||||
|
} else if (prop.ends_with("api_level")) {
|
||||||
if (!DEVICE_INITIAL_SDK_INT.empty()) {
|
if (!DEVICE_INITIAL_SDK_INT.empty()) {
|
||||||
value = DEVICE_INITIAL_SDK_INT.c_str();
|
value = DEVICE_INITIAL_SDK_INT.c_str();
|
||||||
}
|
}
|
||||||
@ -69,7 +75,11 @@ static void modify_callback(void *cookie, const char *name, const char *value, u
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DEBUG) LOGD("[%s]: '%s'", name, value);
|
if (strcmp(oldValue, value) == 0) {
|
||||||
|
if (DEBUG) LOGD("[%s]: %s (unchanged)", name, oldValue);
|
||||||
|
} else {
|
||||||
|
LOGD("[%s]: %s -> %s", name, oldValue, value);
|
||||||
|
}
|
||||||
|
|
||||||
return o_callback(cookie, name, value, serial);
|
return o_callback(cookie, name, value, serial);
|
||||||
}
|
}
|
||||||
@ -82,12 +92,10 @@ static void my_system_property_read_callback(prop_info *pi, T_Callback callback,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool doHook() {
|
static bool doHook() {
|
||||||
LOGD("loaded Dobby version: %s", DobbyGetVersion());
|
|
||||||
|
|
||||||
void *ptr = DobbySymbolResolver(nullptr, "__system_property_read_callback");
|
void *ptr = DobbySymbolResolver(nullptr, "__system_property_read_callback");
|
||||||
|
|
||||||
if (ptr && !DobbyHook(ptr, (void *) my_system_property_read_callback,
|
if (ptr && DobbyHook(ptr, (void *) my_system_property_read_callback,
|
||||||
(void **) &o_system_property_read_callback)) {
|
(void **) &o_system_property_read_callback) == 0) {
|
||||||
LOGD("hook __system_property_read_callback successful at %p", ptr);
|
LOGD("hook __system_property_read_callback successful at %p", ptr);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -166,6 +174,9 @@ public:
|
|||||||
bool trickyStore = false;
|
bool trickyStore = false;
|
||||||
xread(fd, &trickyStore, sizeof(trickyStore));
|
xread(fd, &trickyStore, sizeof(trickyStore));
|
||||||
|
|
||||||
|
bool testSignedRom = false;
|
||||||
|
xread(fd, &testSignedRom, sizeof(testSignedRom));
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
LOGD("Dex file size: %d", dexSize);
|
LOGD("Dex file size: %d", dexSize);
|
||||||
@ -178,6 +189,11 @@ public:
|
|||||||
spoofProvider = false;
|
spoofProvider = false;
|
||||||
spoofProps = false;
|
spoofProps = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (testSignedRom) {
|
||||||
|
LOGD("--- ROM IS SIGNED WITH TEST KEYS ---");
|
||||||
|
spoofSignature = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override {
|
void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override {
|
||||||
@ -213,8 +229,8 @@ private:
|
|||||||
JNIEnv *env = nullptr;
|
JNIEnv *env = nullptr;
|
||||||
std::vector<uint8_t> dexVector;
|
std::vector<uint8_t> dexVector;
|
||||||
nlohmann::json json;
|
nlohmann::json json;
|
||||||
bool spoofProps = false;
|
bool spoofProps = true;
|
||||||
bool spoofProvider = false;
|
bool spoofProvider = true;
|
||||||
bool spoofSignature = false;
|
bool spoofSignature = false;
|
||||||
|
|
||||||
void dlclose() {
|
void dlclose() {
|
||||||
@ -225,14 +241,6 @@ private:
|
|||||||
void parseJSON() {
|
void parseJSON() {
|
||||||
if (json.empty()) return;
|
if (json.empty()) return;
|
||||||
|
|
||||||
if (json.contains("ID") && json["ID"].is_string()) {
|
|
||||||
BUILD_ID = json["ID"].get<std::string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (json.contains("SECURITY_PATCH") && json["SECURITY_PATCH"].is_string()) {
|
|
||||||
SECURITY_PATCH = json["SECURITY_PATCH"].get<std::string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (json.contains("DEVICE_INITIAL_SDK_INT")) {
|
if (json.contains("DEVICE_INITIAL_SDK_INT")) {
|
||||||
if (json["DEVICE_INITIAL_SDK_INT"].is_string()) {
|
if (json["DEVICE_INITIAL_SDK_INT"].is_string()) {
|
||||||
DEVICE_INITIAL_SDK_INT = json["DEVICE_INITIAL_SDK_INT"].get<std::string>();
|
DEVICE_INITIAL_SDK_INT = json["DEVICE_INITIAL_SDK_INT"].get<std::string>();
|
||||||
@ -246,18 +254,57 @@ private:
|
|||||||
|
|
||||||
if (json.contains("spoofProvider") && json["spoofProvider"].is_boolean()) {
|
if (json.contains("spoofProvider") && json["spoofProvider"].is_boolean()) {
|
||||||
spoofProvider = json["spoofProvider"].get<bool>();
|
spoofProvider = json["spoofProvider"].get<bool>();
|
||||||
|
json.erase("spoofProvider");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (json.contains("spoofProps") && json["spoofProps"].is_boolean()) {
|
if (json.contains("spoofProps") && json["spoofProps"].is_boolean()) {
|
||||||
spoofProps = json["spoofProps"].get<bool>();
|
spoofProps = json["spoofProps"].get<bool>();
|
||||||
|
json.erase("spoofProps");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (json.contains("spoofSignature") && json["spoofSignature"].is_boolean()) {
|
if (json.contains("spoofSignature") && json["spoofSignature"].is_boolean()) {
|
||||||
spoofSignature = json["spoofSignature"].get<bool>();
|
spoofSignature = json["spoofSignature"].get<bool>();
|
||||||
|
json.erase("spoofSignature");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (json.contains("DEBUG") && json["DEBUG"].is_boolean()) {
|
if (json.contains("DEBUG") && json["DEBUG"].is_boolean()) {
|
||||||
DEBUG = json["DEBUG"].get<bool>();
|
DEBUG = json["DEBUG"].get<bool>();
|
||||||
|
json.erase("DEBUG");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.contains("FINGERPRINT") && json["FINGERPRINT"].is_string()) {
|
||||||
|
std::string fingerprint = json["FINGERPRINT"].get<std::string>();
|
||||||
|
|
||||||
|
std::vector<std::string> vector;
|
||||||
|
auto parts = fingerprint | std::views::split('/');
|
||||||
|
|
||||||
|
for (const auto &part: parts) {
|
||||||
|
auto subParts = std::string(part.begin(), part.end()) | std::views::split(':');
|
||||||
|
for (const auto &subPart: subParts) {
|
||||||
|
vector.emplace_back(subPart.begin(), subPart.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vector.size() == 8) {
|
||||||
|
json["BRAND"] = vector[0];
|
||||||
|
json["PRODUCT"] = vector[1];
|
||||||
|
json["DEVICE"] = vector[2];
|
||||||
|
json["RELEASE"] = vector[3];
|
||||||
|
json["ID"] = vector[4];
|
||||||
|
json["INCREMENTAL"] = vector[5];
|
||||||
|
json["TYPE"] = vector[6];
|
||||||
|
json["TAGS"] = vector[7];
|
||||||
|
} else {
|
||||||
|
LOGE("Error parsing fingerprint values!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.contains("SECURITY_PATCH") && json["SECURITY_PATCH"].is_string()) {
|
||||||
|
SECURITY_PATCH = json["SECURITY_PATCH"].get<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.contains("ID") && json["ID"].is_string()) {
|
||||||
|
BUILD_ID = json["ID"].get<std::string>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,6 +425,26 @@ static std::vector<uint8_t> readFile(const char *path) {
|
|||||||
return vector;
|
return vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool checkOtaZip() {
|
||||||
|
std::array<char, 128> buffer{};
|
||||||
|
std::string result;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
std::unique_ptr<FILE, decltype(&pclose)> pipe(
|
||||||
|
popen("unzip -l /system/etc/security/otacerts.zip", "r"), pclose);
|
||||||
|
if (!pipe) return false;
|
||||||
|
|
||||||
|
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
|
||||||
|
result += buffer.data();
|
||||||
|
if (result.find("test") != std::string::npos) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
static void companion(int fd) {
|
static void companion(int fd) {
|
||||||
|
|
||||||
std::vector<uint8_t> dex, json;
|
std::vector<uint8_t> dex, json;
|
||||||
@ -403,6 +470,9 @@ static void companion(int fd) {
|
|||||||
|
|
||||||
bool trickyStore = std::filesystem::exists(TS_PATH);
|
bool trickyStore = std::filesystem::exists(TS_PATH);
|
||||||
xwrite(fd, &trickyStore, sizeof(trickyStore));
|
xwrite(fd, &trickyStore, sizeof(trickyStore));
|
||||||
|
|
||||||
|
bool testSignedRom = checkOtaZip();
|
||||||
|
xwrite(fd, &testSignedRom, sizeof(testSignedRom));
|
||||||
}
|
}
|
||||||
|
|
||||||
REGISTER_ZYGISK_MODULE(PlayIntegrityFix)
|
REGISTER_ZYGISK_MODULE(PlayIntegrityFix)
|
||||||
|
@ -181,15 +181,16 @@ public final class EntryPoint {
|
|||||||
jsonObject.keys().forEachRemaining(key -> {
|
jsonObject.keys().forEachRemaining(key -> {
|
||||||
Field field = getBuildField(key);
|
Field field = getBuildField(key);
|
||||||
if (field == null) return;
|
if (field == null) return;
|
||||||
field.setAccessible(true);
|
|
||||||
String value;
|
|
||||||
try {
|
try {
|
||||||
value = jsonObject.getString(key);
|
String value = jsonObject.getString(key);
|
||||||
|
if (value.isBlank()) {
|
||||||
|
Log.w(TAG, "Field '" + key + "' have an empty value!");
|
||||||
|
} else {
|
||||||
|
map.put(field, value);
|
||||||
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
Log.e(TAG, "init", t);
|
Log.e(TAG, "init", t);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
map.putIfAbsent(field, value);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Log.i(TAG, "Parsed " + map.size() + " fields from JSON");
|
Log.i(TAG, "Parsed " + map.size() + " fields from JSON");
|
||||||
@ -200,9 +201,14 @@ public final class EntryPoint {
|
|||||||
public static void spoofFields() {
|
public static void spoofFields() {
|
||||||
map.forEach((field, value) -> {
|
map.forEach((field, value) -> {
|
||||||
try {
|
try {
|
||||||
|
field.setAccessible(true);
|
||||||
String oldValue = (String) field.get(null);
|
String oldValue = (String) field.get(null);
|
||||||
if (value.equals(oldValue)) return;
|
if (value.equals(oldValue)) {
|
||||||
|
field.setAccessible(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
field.set(null, value);
|
field.set(null, value);
|
||||||
|
field.setAccessible(false);
|
||||||
Log.i(TAG, "Set '" + field.getName() + "' to '" + value + "'");
|
Log.i(TAG, "Set '" + field.getName() + "' to '" + value + "'");
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
Log.e(TAG, "spoofFields", t);
|
Log.e(TAG, "spoofFields", t);
|
||||||
|
@ -1,19 +1,7 @@
|
|||||||
{
|
{
|
||||||
"TYPE": "user",
|
|
||||||
"TAGS": "release-keys",
|
|
||||||
"ID": "AP41.240823.009",
|
|
||||||
"BRAND": "google",
|
|
||||||
"DEVICE": "tokay",
|
|
||||||
"FINGERPRINT": "google/tokay_beta/tokay:15/AP41.240823.009/12329489:user/release-keys",
|
"FINGERPRINT": "google/tokay_beta/tokay:15/AP41.240823.009/12329489:user/release-keys",
|
||||||
"MANUFACTURER": "Google",
|
"MANUFACTURER": "Google",
|
||||||
"MODEL": "Pixel 9",
|
"MODEL": "Pixel 9",
|
||||||
"PRODUCT": "tokay_beta",
|
|
||||||
"INCREMENTAL": "12329489",
|
|
||||||
"RELEASE": "15",
|
|
||||||
"SECURITY_PATCH": "2024-09-05",
|
"SECURITY_PATCH": "2024-09-05",
|
||||||
"DEVICE_INITIAL_SDK_INT": 25,
|
"DEVICE_INITIAL_SDK_INT": 21
|
||||||
"spoofProvider": true,
|
|
||||||
"spoofProps": true,
|
|
||||||
"spoofSignature": false,
|
|
||||||
"DEBUG": false
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user