diff --git a/app/src/main/cpp/main.cpp b/app/src/main/cpp/main.cpp index 87dc92b0..b6be2d4d 100644 --- a/app/src/main/cpp/main.cpp +++ b/app/src/main/cpp/main.cpp @@ -43,47 +43,58 @@ static ssize_t xwrite(int fd, const void *buffer, size_t count) { } static bool DEBUG = false; -static std::string DEVICE_INITIAL_SDK_INT, SECURITY_PATCH, BUILD_ID; +static std::map jsonProps; typedef void (*T_Callback)(void *, const char *, const char *, uint32_t); -static T_Callback o_callback = nullptr; +static std::map callbacks; static void modify_callback(void *cookie, const char *name, const char *value, uint32_t serial) { + if (cookie == nullptr || name == nullptr || value == nullptr || + !callbacks.contains(cookie)) + return; - if (!cookie || !name || !value || !o_callback) return; + const char *oldValue = value; - std::string_view prop(name); + std::string prop(name); - if (prop.ends_with("api_level")) { - if (!DEVICE_INITIAL_SDK_INT.empty()) { - value = DEVICE_INITIAL_SDK_INT.c_str(); - } - } else if (prop.ends_with(".security_patch")) { - if (!SECURITY_PATCH.empty()) { - value = SECURITY_PATCH.c_str(); - } - } else if (prop.ends_with(".build.id")) { - if (!BUILD_ID.empty()) { - value = BUILD_ID.c_str(); + // Spoof specific property values + if (prop == "init.svc.adbd") { + value = "stopped"; + } else if (prop == "sys.usb.state") { + value = "mtp"; + } + + if (jsonProps.count(prop)) { + // Exact property match + value = jsonProps[prop].c_str(); + } else { + // Leading * wildcard property match + for (const auto &p: jsonProps) { + if (p.first.starts_with("*") && prop.ends_with(p.first.substr(1))) { + value = p.second.c_str(); + break; + } } } - if (DEBUG) LOGD("[%s]: '%s'", name, value); + if (oldValue == value) { + if (DEBUG) LOGD("[%s]: %s (unchanged)", name, oldValue); + } else { + LOGD("[%s]: %s -> %s", name, oldValue, value); + } - return o_callback(cookie, name, value, serial); + return callbacks[cookie](cookie, name, value, serial); } static void (*o_system_property_read_callback)(prop_info *, T_Callback, void *) = nullptr; static void my_system_property_read_callback(prop_info *pi, T_Callback callback, void *cookie) { - if (pi && callback && cookie) o_callback = callback; + if (pi && callback && cookie) callbacks[cookie] = callback; return o_system_property_read_callback(pi, modify_callback, cookie); } static bool doHook() { - LOGD("loaded Dobby version: %s", DobbyGetVersion()); - void *ptr = DobbySymbolResolver(nullptr, "__system_property_read_callback"); if (ptr && !DobbyHook(ptr, (void *) my_system_property_read_callback, @@ -225,39 +236,48 @@ class PlayIntegrityFix : public zygisk::ModuleBase { void parseJSON() { if (json.empty()) return; - if (json.contains("ID") && json["ID"].is_string()) { - BUILD_ID = json["ID"].get(); - } - - if (json.contains("SECURITY_PATCH") && json["SECURITY_PATCH"].is_string()) { - SECURITY_PATCH = json["SECURITY_PATCH"].get(); - } - - if (json.contains("DEVICE_INITIAL_SDK_INT")) { - if (json["DEVICE_INITIAL_SDK_INT"].is_string()) { - DEVICE_INITIAL_SDK_INT = json["DEVICE_INITIAL_SDK_INT"].get(); - } else if (json["DEVICE_INITIAL_SDK_INT"].is_number_integer()) { - DEVICE_INITIAL_SDK_INT = std::to_string(json["DEVICE_INITIAL_SDK_INT"].get()); - } else { - LOGE("Couldn't parse DEVICE_INITIAL_SDK_INT value!"); - } - json.erase("DEVICE_INITIAL_SDK_INT"); - } - if (json.contains("spoofProvider") && json["spoofProvider"].is_boolean()) { spoofProvider = json["spoofProvider"].get(); + json.erase("spoofProvider"); } if (json.contains("spoofProps") && json["spoofProps"].is_boolean()) { spoofProps = json["spoofProps"].get(); + json.erase("spoofProps"); } if (json.contains("spoofSignature") && json["spoofSignature"].is_boolean()) { spoofSignature = json["spoofSignature"].get(); + json.erase("spoofSignature"); } if (json.contains("DEBUG") && json["DEBUG"].is_boolean()) { DEBUG = json["DEBUG"].get(); + json.erase("DEBUG"); + } + + std::vector eraseKeys; + for (auto &jsonList: json.items()) { + if (DEBUG) LOGD("Parsing %s", jsonList.key().c_str()); + if (jsonList.key().find_first_of("*.") != std::string::npos) { + // Name contains . or * (wildcard) so assume real property name + if (!jsonList.value().is_null() && jsonList.value().is_string()) { + auto value = jsonList.value().get(); + if (value.empty()) { + LOGD("%s is empty, skipping", jsonList.key().c_str()); + } else { + if (DEBUG) LOGD("Adding '%s' to properties list", jsonList.key().c_str()); + jsonProps[jsonList.key()] = value; + } + } else { + LOGD("Error parsing %s!", jsonList.key().c_str()); + } + eraseKeys.push_back(jsonList.key()); + } + } + // Remove properties from parsed JSON + for (const auto &key: eraseKeys) { + if (json.contains(key)) json.erase(key); } } diff --git a/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java b/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java index b48a1c03..33a3a5c8 100644 --- a/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java +++ b/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java @@ -181,7 +181,6 @@ public static void init(String json, boolean spoofProvider, boolean spoofSignatu jsonObject.keys().forEachRemaining(key -> { Field field = getBuildField(key); if (field == null) return; - field.setAccessible(true); String value; try { value = jsonObject.getString(key); @@ -200,10 +199,19 @@ public static void init(String json, boolean spoofProvider, boolean spoofSignatu public static void spoofFields() { map.forEach((field, value) -> { try { - String oldValue = (String) field.get(null); - if (value.equals(oldValue)) return; - field.set(null, value); + field.setAccessible(true); + Object oldValue = field.get(null); + Object object = value; + if (oldValue instanceof Integer) { + object = Integer.parseInt(value); + } + if (object.equals(oldValue)) { + field.setAccessible(false); + return; + } + field.set(null, object); Log.i(TAG, "Set '" + field.getName() + "' to '" + value + "'"); + field.setAccessible(false); } catch (Throwable t) { Log.e(TAG, "spoofFields", t); } diff --git a/module/pif.json b/module/pif.json index 368fe7d3..e1408369 100644 --- a/module/pif.json +++ b/module/pif.json @@ -1,6 +1,4 @@ { - "TYPE": "user", - "TAGS": "release-keys", "ID": "AP41.240823.009", "BRAND": "google", "DEVICE": "tokay", @@ -11,7 +9,10 @@ "INCREMENTAL": "12329489", "RELEASE": "15", "SECURITY_PATCH": "2024-09-05", - "DEVICE_INITIAL_SDK_INT": 25, + "DEVICE_INITIAL_SDK_INT": "21", + "*.build.id": "AP41.240823.009", + "*.security_patch": "2024-09-05", + "*api_level": "21", "spoofProvider": true, "spoofProps": true, "spoofSignature": false,