mirror of
https://github.com/chiteroman/PlayIntegrityFix.git
synced 2025-01-19 03:22:39 +02:00
Prepare v15.2
This commit is contained in:
parent
0b21f031de
commit
0a6f936074
@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="" vcs="Git" />
|
|
||||||
<mapping directory="$PROJECT_DIR$/app/src/main/cpp/Dobby" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
@ -14,6 +14,7 @@ android {
|
|||||||
|
|
||||||
packaging {
|
packaging {
|
||||||
jniLibs {
|
jniLibs {
|
||||||
|
excludes += "**/liblog.so"
|
||||||
excludes += "**/libdobby.so"
|
excludes += "**/libdobby.so"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -22,19 +23,22 @@ android {
|
|||||||
applicationId = "es.chiteroman.playintegrityfix"
|
applicationId = "es.chiteroman.playintegrityfix"
|
||||||
minSdk = 26
|
minSdk = 26
|
||||||
targetSdk = 34
|
targetSdk = 34
|
||||||
versionCode = 1
|
versionCode = 15200
|
||||||
versionName = "1.0"
|
versionName = "v15.2"
|
||||||
|
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
arguments += "-DANDROID_STL=none"
|
arguments += "-DANDROID_STL=none"
|
||||||
arguments += "-DCMAKE_BUILD_TYPE=Release"
|
arguments += "-DCMAKE_BUILD_TYPE=Release"
|
||||||
|
arguments += "-DCMAKE_CXX_STANDARD=20"
|
||||||
|
arguments += "-DCMAKE_CXX_STANDARD_REQUIRED=True"
|
||||||
|
arguments += "-DCMAKE_CXX_EXTENSIONS=False"
|
||||||
|
arguments += "-DCMAKE_CXX_VISIBILITY_PRESET=hidden"
|
||||||
|
arguments += "-DCMAKE_VISIBILITY_INLINES_HIDDEN=True"
|
||||||
|
arguments += "-DPlugin.Android.BionicLinkerUtil=ON"
|
||||||
|
|
||||||
cppFlags += "-std=c++20"
|
|
||||||
cppFlags += "-fno-exceptions"
|
cppFlags += "-fno-exceptions"
|
||||||
cppFlags += "-fno-rtti"
|
cppFlags += "-fno-rtti"
|
||||||
cppFlags += "-fvisibility=hidden"
|
|
||||||
cppFlags += "-fvisibility-inlines-hidden"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,7 +68,26 @@ dependencies {
|
|||||||
implementation("dev.rikka.ndk.thirdparty:cxx:1.2.0")
|
implementation("dev.rikka.ndk.thirdparty:cxx:1.2.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.register("updateModuleProp") {
|
||||||
|
doLast {
|
||||||
|
val versionName = project.android.defaultConfig.versionName
|
||||||
|
val versionCode = project.android.defaultConfig.versionCode
|
||||||
|
|
||||||
|
val modulePropFile = project.rootDir.resolve("module/module.prop")
|
||||||
|
|
||||||
|
var content = modulePropFile.readText()
|
||||||
|
|
||||||
|
content = content.replace(Regex("version=.*"), "version=$versionName")
|
||||||
|
content = content.replace(Regex("versionCode=.*"), "versionCode=$versionCode")
|
||||||
|
|
||||||
|
modulePropFile.writeText(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
tasks.register("copyFiles") {
|
tasks.register("copyFiles") {
|
||||||
|
dependsOn("updateModuleProp")
|
||||||
|
|
||||||
doLast {
|
doLast {
|
||||||
val moduleFolder = project.rootDir.resolve("module")
|
val moduleFolder = project.rootDir.resolve("module")
|
||||||
val dexFile = project.layout.buildDirectory.get().asFile.resolve("intermediates/dex/release/minifyReleaseWithR8/classes.dex")
|
val dexFile = project.layout.buildDirectory.get().asFile.resolve("intermediates/dex/release/minifyReleaseWithR8/classes.dex")
|
||||||
@ -83,12 +106,12 @@ tasks.register("copyFiles") {
|
|||||||
tasks.register<Zip>("zip") {
|
tasks.register<Zip>("zip") {
|
||||||
dependsOn("copyFiles")
|
dependsOn("copyFiles")
|
||||||
|
|
||||||
archiveFileName.set("PlayIntegrityFix.zip")
|
archiveFileName.set("PlayIntegrityFix_${project.android.defaultConfig.versionName}.zip")
|
||||||
destinationDirectory.set(project.rootDir.resolve("out"))
|
destinationDirectory.set(project.rootDir.resolve("out"))
|
||||||
|
|
||||||
from(project.rootDir.resolve("module"))
|
from(project.rootDir.resolve("module"))
|
||||||
}
|
}
|
||||||
|
|
||||||
afterEvaluate {
|
afterEvaluate {
|
||||||
tasks["assembleRelease"].finalizedBy("copyFiles", "zip")
|
tasks["assembleRelease"].finalizedBy("updateModuleProp", "copyFiles", "zip")
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.22.1)
|
cmake_minimum_required(VERSION 3.22.1)
|
||||||
|
|
||||||
project("playintegrityfix")
|
project(playintegrityfix)
|
||||||
|
|
||||||
find_package(cxx REQUIRED CONFIG)
|
find_package(cxx REQUIRED CONFIG)
|
||||||
|
|
||||||
@ -10,6 +10,4 @@ add_library(${CMAKE_PROJECT_NAME} SHARED module.cpp)
|
|||||||
|
|
||||||
add_subdirectory(Dobby)
|
add_subdirectory(Dobby)
|
||||||
|
|
||||||
SET_OPTION(Plugin.Android.BionicLinkerUtil ON)
|
|
||||||
|
|
||||||
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE log dobby_static)
|
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE log dobby_static)
|
@ -1,7 +1,8 @@
|
|||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
#include <sys/system_properties.h>
|
#include <sys/system_properties.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <fstream>
|
||||||
|
#include <filesystem>
|
||||||
#include "zygisk.hpp"
|
#include "zygisk.hpp"
|
||||||
#include "dobby.h"
|
#include "dobby.h"
|
||||||
#include "json.hpp"
|
#include "json.hpp"
|
||||||
@ -14,15 +15,17 @@
|
|||||||
|
|
||||||
#define PIF_JSON_2 "/data/adb/modules/playintegrityfix/pif.json"
|
#define PIF_JSON_2 "/data/adb/modules/playintegrityfix/pif.json"
|
||||||
|
|
||||||
static std::string FIRST_API_LEVEL, SECURITY_PATCH;
|
static std::string FIRST_API_LEVEL, SECURITY_PATCH, BUILD_ID;
|
||||||
|
|
||||||
typedef void (*T_Callback)(void *, const char *, const char *, uint32_t);
|
typedef void (*T_Callback)(void *, const char *, const char *, uint32_t);
|
||||||
|
|
||||||
static T_Callback o_callback = nullptr;
|
static std::map<void *, T_Callback> callbacks;
|
||||||
|
|
||||||
static void modify_callback(void *cookie, const char *name, const char *value, uint32_t serial) {
|
static void modify_callback(void *cookie, const char *name, const char *value, uint32_t serial) {
|
||||||
|
|
||||||
if (cookie == nullptr || name == nullptr || o_callback == nullptr) return;
|
if (cookie == nullptr || name == nullptr || value == nullptr ||
|
||||||
|
!callbacks.contains(cookie))
|
||||||
|
return;
|
||||||
|
|
||||||
std::string_view prop(name);
|
std::string_view prop(name);
|
||||||
|
|
||||||
@ -40,6 +43,13 @@ static void modify_callback(void *cookie, const char *name, const char *value, u
|
|||||||
value = FIRST_API_LEVEL.c_str();
|
value = FIRST_API_LEVEL.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (prop.ends_with("build.id")) {
|
||||||
|
|
||||||
|
if (!BUILD_ID.empty()) {
|
||||||
|
|
||||||
|
value = BUILD_ID.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
} else if (prop == "sys.usb.state") {
|
} else if (prop == "sys.usb.state") {
|
||||||
|
|
||||||
value = "none";
|
value = "none";
|
||||||
@ -50,7 +60,7 @@ static void modify_callback(void *cookie, const char *name, const char *value, u
|
|||||||
LOGD("[%s] -> %s", name, value);
|
LOGD("[%s] -> %s", name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return o_callback(cookie, name, value, serial);
|
return callbacks[cookie](cookie, name, value, serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void (*o_system_property_read_callback)(const prop_info *, T_Callback, void *);
|
static void (*o_system_property_read_callback)(const prop_info *, T_Callback, void *);
|
||||||
@ -60,12 +70,12 @@ my_system_property_read_callback(const prop_info *pi, T_Callback callback, void
|
|||||||
if (pi == nullptr || callback == nullptr || cookie == nullptr) {
|
if (pi == nullptr || callback == nullptr || cookie == nullptr) {
|
||||||
return o_system_property_read_callback(pi, callback, cookie);
|
return o_system_property_read_callback(pi, callback, cookie);
|
||||||
}
|
}
|
||||||
o_callback = callback;
|
callbacks[cookie] = callback;
|
||||||
return o_system_property_read_callback(pi, modify_callback, cookie);
|
return o_system_property_read_callback(pi, modify_callback, cookie);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void doHook() {
|
static void doHook() {
|
||||||
void *handle = DobbySymbolResolver(nullptr, "__system_property_read_callback");
|
void *handle = DobbySymbolResolver("libc.so", "__system_property_read_callback");
|
||||||
if (handle == nullptr) {
|
if (handle == nullptr) {
|
||||||
LOGD("Couldn't find '__system_property_read_callback' handle. Report to @chiteroman");
|
LOGD("Couldn't find '__system_property_read_callback' handle. Report to @chiteroman");
|
||||||
return;
|
return;
|
||||||
@ -87,68 +97,49 @@ public:
|
|||||||
|
|
||||||
void preAppSpecialize(zygisk::AppSpecializeArgs *args) override {
|
void preAppSpecialize(zygisk::AppSpecializeArgs *args) override {
|
||||||
|
|
||||||
if (args->is_child_zygote && *args->is_child_zygote) {
|
auto name = env->GetStringUTFChars(args->nice_name, nullptr);
|
||||||
|
|
||||||
|
if (name == nullptr) {
|
||||||
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
|
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto name = env->GetStringUTFChars(args->nice_name, nullptr);
|
std::string_view process(name);
|
||||||
|
|
||||||
if (name && strncmp(name, "com.google.android.gms", 22) == 0) {
|
bool isGms = process.starts_with("com.google.android.gms");
|
||||||
|
bool isGmsUnstable = process == "com.google.android.gms.unstable";
|
||||||
|
|
||||||
|
env->ReleaseStringUTFChars(args->nice_name, name);
|
||||||
|
|
||||||
|
if (!isGms) {
|
||||||
|
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
api->setOption(zygisk::FORCE_DENYLIST_UNMOUNT);
|
api->setOption(zygisk::FORCE_DENYLIST_UNMOUNT);
|
||||||
|
|
||||||
if (strcmp(name, "com.google.android.gms.unstable") == 0) {
|
if (!isGmsUnstable) {
|
||||||
|
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
long dexSize = 0, jsonSize = 0;
|
long dexSize = 0, jsonSize = 0;
|
||||||
|
|
||||||
int fd = api->connectCompanion();
|
int fd = api->connectCompanion();
|
||||||
|
|
||||||
read(fd, &dexSize, sizeof(long));
|
read(fd, &dexSize, sizeof(long));
|
||||||
|
|
||||||
if (dexSize > 0) {
|
|
||||||
|
|
||||||
dexVector.resize(dexSize);
|
|
||||||
read(fd, dexVector.data(), dexSize);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
LOGD("Couldn't load classes.dex file in memory!");
|
|
||||||
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
read(fd, &jsonSize, sizeof(long));
|
read(fd, &jsonSize, sizeof(long));
|
||||||
|
|
||||||
if (jsonSize > 0) {
|
vector.resize(dexSize);
|
||||||
|
read(fd, vector.data(), dexSize);
|
||||||
|
|
||||||
jsonVector.resize(jsonSize);
|
char jsonBufer[jsonSize];
|
||||||
read(fd, jsonVector.data(), jsonSize);
|
read(fd, jsonBufer, jsonSize);
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
LOGD("Couldn't load pif.json file in memory!");
|
|
||||||
dexVector.clear();
|
|
||||||
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
end:
|
|
||||||
close(fd);
|
close(fd);
|
||||||
goto clear;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
|
std::string_view jsonStr(jsonBufer, jsonSize);
|
||||||
|
json = nlohmann::json::parse(jsonStr, nullptr, false, true);
|
||||||
clear:
|
|
||||||
env->ReleaseStringUTFChars(args->nice_name, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override {
|
|
||||||
if (dexVector.empty() || jsonVector.empty()) return;
|
|
||||||
|
|
||||||
std::string jsonStr(jsonVector.cbegin(), jsonVector.cend());
|
|
||||||
nlohmann::json json = nlohmann::json::parse(jsonStr, nullptr, false, true);
|
|
||||||
|
|
||||||
if (json.contains("FIRST_API_LEVEL")) {
|
if (json.contains("FIRST_API_LEVEL")) {
|
||||||
|
|
||||||
@ -180,6 +171,29 @@ public:
|
|||||||
LOGD("JSON file doesn't contain SECURITY_PATCH key :(");
|
LOGD("JSON file doesn't contain SECURITY_PATCH key :(");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (json.contains("ID")) {
|
||||||
|
|
||||||
|
if (json["ID"].is_string()) {
|
||||||
|
|
||||||
|
BUILD_ID = json["ID"].get<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (json.contains("BUILD_ID")) {
|
||||||
|
|
||||||
|
if (json["BUILD_ID"].is_string()) {
|
||||||
|
|
||||||
|
BUILD_ID = json["BUILD_ID"].get<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
LOGD("JSON file doesn't contain ID/BUILD_ID keys :(");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override {
|
||||||
|
if (vector.empty() || json.empty()) return;
|
||||||
|
|
||||||
doHook();
|
doHook();
|
||||||
|
|
||||||
LOGD("get system classloader");
|
LOGD("get system classloader");
|
||||||
@ -192,7 +206,7 @@ public:
|
|||||||
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(), dexVector.size());
|
auto buffer = env->NewDirectByteBuffer(vector.data(), vector.size());
|
||||||
auto dexCl = env->NewObject(dexClClass, dexClInit, buffer, systemClassLoader);
|
auto dexCl = env->NewObject(dexClClass, dexClInit, buffer, systemClassLoader);
|
||||||
|
|
||||||
LOGD("load class");
|
LOGD("load class");
|
||||||
@ -208,8 +222,8 @@ public:
|
|||||||
auto str = env->NewStringUTF(json.dump().c_str());
|
auto str = env->NewStringUTF(json.dump().c_str());
|
||||||
env->CallStaticVoidMethod(entryClass, entryInit, str);
|
env->CallStaticVoidMethod(entryClass, entryInit, str);
|
||||||
|
|
||||||
dexVector.clear();
|
vector.clear();
|
||||||
jsonVector.clear();
|
json.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void preServerSpecialize(zygisk::ServerSpecializeArgs *args) override {
|
void preServerSpecialize(zygisk::ServerSpecializeArgs *args) override {
|
||||||
@ -219,50 +233,43 @@ public:
|
|||||||
private:
|
private:
|
||||||
zygisk::Api *api = nullptr;
|
zygisk::Api *api = nullptr;
|
||||||
JNIEnv *env = nullptr;
|
JNIEnv *env = nullptr;
|
||||||
std::vector<char> dexVector, jsonVector;
|
std::vector<char> vector;
|
||||||
|
nlohmann::json json;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void companion(int fd) {
|
static void companion(int fd) {
|
||||||
long dexSize = 0, jsonSize = 0;
|
std::ifstream dexFile(CLASSES_DEX, std::ios::in | std::ios::binary);
|
||||||
std::vector<char> dexVector, jsonVector;
|
|
||||||
|
|
||||||
FILE *dexFile = fopen(CLASSES_DEX, "rb");
|
if (!dexFile) {
|
||||||
|
long i = 0;
|
||||||
if (dexFile) {
|
write(fd, &i, sizeof(i));
|
||||||
|
return;
|
||||||
fseek(dexFile, 0, SEEK_END);
|
|
||||||
dexSize = ftell(dexFile);
|
|
||||||
fseek(dexFile, 0, SEEK_SET);
|
|
||||||
|
|
||||||
dexVector.resize(dexSize);
|
|
||||||
fread(dexVector.data(), 1, dexSize, dexFile);
|
|
||||||
|
|
||||||
fclose(dexFile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<char> dexVector((std::istreambuf_iterator<char>(dexFile)),
|
||||||
|
std::istreambuf_iterator<char>());
|
||||||
|
long dexSize = dexVector.size();
|
||||||
|
|
||||||
|
std::ifstream jsonFile;
|
||||||
|
|
||||||
|
if (std::filesystem::exists(PIF_JSON)) {
|
||||||
|
jsonFile = std::ifstream(PIF_JSON, std::ios::in);
|
||||||
|
} else if (std::filesystem::exists(PIF_JSON_2)) {
|
||||||
|
jsonFile = std::ifstream(PIF_JSON_2, std::ios::in);
|
||||||
|
} else {
|
||||||
|
long i = 0;
|
||||||
|
write(fd, &i, sizeof(i));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<char> jsonVector((std::istreambuf_iterator<char>(jsonFile)),
|
||||||
|
std::istreambuf_iterator<char>());
|
||||||
|
long jsonSize = jsonVector.size();
|
||||||
|
|
||||||
write(fd, &dexSize, sizeof(long));
|
write(fd, &dexSize, sizeof(long));
|
||||||
write(fd, dexVector.data(), dexSize);
|
|
||||||
|
|
||||||
FILE *jsonFile = fopen(PIF_JSON, "r");
|
|
||||||
|
|
||||||
if (jsonFile == nullptr) {
|
|
||||||
|
|
||||||
jsonFile = fopen(PIF_JSON_2, "r");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (jsonFile) {
|
|
||||||
|
|
||||||
fseek(jsonFile, 0, SEEK_END);
|
|
||||||
jsonSize = ftell(jsonFile);
|
|
||||||
fseek(jsonFile, 0, SEEK_SET);
|
|
||||||
|
|
||||||
jsonVector.resize(jsonSize);
|
|
||||||
fread(jsonVector.data(), 1, jsonSize, jsonFile);
|
|
||||||
|
|
||||||
fclose(jsonFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
write(fd, &jsonSize, sizeof(long));
|
write(fd, &jsonSize, sizeof(long));
|
||||||
|
|
||||||
|
write(fd, dexVector.data(), dexSize);
|
||||||
write(fd, jsonVector.data(), jsonSize);
|
write(fd, jsonVector.data(), jsonSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,8 +14,9 @@ public final class CustomProvider extends Provider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized Service getService(String type, String algorithm) {
|
public synchronized Service getService(String type, String algorithm) {
|
||||||
|
EntryPoint.LOG(String.format("[Service] Type: '%s' | Algorithm: '%s'", type, algorithm));
|
||||||
|
|
||||||
EntryPoint.spoofDevice();
|
if ("KeyStore".equals(type)) EntryPoint.spoofDevice();
|
||||||
|
|
||||||
return super.getService(type, algorithm);
|
return super.getService(type, algorithm);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
id=playintegrityfix
|
id=playintegrityfix
|
||||||
name=Play Integrity Fix
|
name=Play Integrity Fix
|
||||||
version=v15.1
|
version=v15.2
|
||||||
versionCode=15100
|
versionCode=15200
|
||||||
author=chiteroman
|
author=chiteroman
|
||||||
description=Universal modular fix for Play Integrity (and SafetyNet) on devices running Android 8+.
|
description=Universal modular fix for Play Integrity (and SafetyNet) on devices running Android 8+.
|
||||||
updateJson=https://raw.githubusercontent.com/chiteroman/PlayIntegrityFix/main/update.json
|
updateJson=https://raw.githubusercontent.com/chiteroman/PlayIntegrityFix/main/update.json
|
||||||
|
@ -7,5 +7,6 @@
|
|||||||
"FINGERPRINT": "acer/c01_ww/acer_c01:7.1.1/NMF26F/1521514970:user/release-keys",
|
"FINGERPRINT": "acer/c01_ww/acer_c01:7.1.1/NMF26F/1521514970:user/release-keys",
|
||||||
"SECURITY_PATCH": "2018-04-01",
|
"SECURITY_PATCH": "2018-04-01",
|
||||||
"FIRST_API_LEVEL": 24,
|
"FIRST_API_LEVEL": 24,
|
||||||
|
"ID": "NMF26F",
|
||||||
"FORCE_BASIC_ATTESTATION": true
|
"FORCE_BASIC_ATTESTATION": true
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user