mirror of
https://github.com/chiteroman/PlayIntegrityFix.git
synced 2025-01-19 19:05:01 +08:00
Improve code
This commit is contained in:
parent
b145c85df9
commit
78dde206ee
@ -28,8 +28,7 @@ android {
|
|||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
arguments += setOf("-DANDROID_STL=none", "-DCMAKE_BUILD_TYPE=MinSizeRel")
|
arguments += setOf("-DANDROID_STL=none", "-DCMAKE_BUILD_TYPE=MinSizeRel")
|
||||||
cFlags += setOf("-flto=full", "-fvisibility=hidden", "-fvisibility-inlines-hidden", "-ffunction-sections", "-fdata-sections")
|
cppFlags += setOf("-std=c++20", "-fno-exceptions", "-fno-rtti", "-fvisibility=hidden", "-fvisibility-inlines-hidden")
|
||||||
cppFlags += setOf("-std=c++20", "-fno-exceptions", "-fno-rtti", "-flto=full", "-fvisibility=hidden", "-fvisibility-inlines-hidden", "-ffunction-sections", "-fdata-sections")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,6 @@ static std::string SECURITY_PATCH;
|
|||||||
|
|
||||||
#define PROP_FILE_PATH "/data/adb/modules/playintegrityfix/pif.prop"
|
#define PROP_FILE_PATH "/data/adb/modules/playintegrityfix/pif.prop"
|
||||||
|
|
||||||
#define MAX_LINE_LENGTH 256
|
|
||||||
|
|
||||||
typedef void (*T_Callback)(void *, const char *, const char *, uint32_t);
|
typedef void (*T_Callback)(void *, const char *, const char *, uint32_t);
|
||||||
|
|
||||||
static std::map<void *, T_Callback> callbacks;
|
static std::map<void *, T_Callback> callbacks;
|
||||||
@ -33,8 +31,19 @@ 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")) value = API_LEVEL.c_str();
|
if (prop.ends_with("api_level")) {
|
||||||
else if (prop.ends_with("security_patch")) value = SECURITY_PATCH.c_str();
|
if (API_LEVEL.empty()) {
|
||||||
|
value = nullptr;
|
||||||
|
} else {
|
||||||
|
value = API_LEVEL.c_str();
|
||||||
|
}
|
||||||
|
} else if (prop.ends_with("security_patch")) {
|
||||||
|
if (SECURITY_PATCH.empty()) {
|
||||||
|
value = nullptr;
|
||||||
|
} else {
|
||||||
|
value = SECURITY_PATCH.c_str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!prop.starts_with("cache") && !prop.starts_with("debug")) LOGD("[%s] -> %s", name, value);
|
if (!prop.starts_with("cache") && !prop.starts_with("debug")) LOGD("[%s] -> %s", name, value);
|
||||||
|
|
||||||
@ -58,9 +67,9 @@ static void parsePropsFile(const char *filename) {
|
|||||||
|
|
||||||
FILE *file = fopen(filename, "r");
|
FILE *file = fopen(filename, "r");
|
||||||
|
|
||||||
char line[MAX_LINE_LENGTH];
|
char line[256];
|
||||||
|
|
||||||
while (fgets(line, sizeof(line), file) != nullptr) {
|
while (fgets(line, sizeof(line), file)) {
|
||||||
|
|
||||||
std::string key, value;
|
std::string key, value;
|
||||||
|
|
||||||
@ -83,33 +92,21 @@ static void parsePropsFile(const char *filename) {
|
|||||||
if (key == "SECURITY_PATCH") {
|
if (key == "SECURITY_PATCH") {
|
||||||
SECURITY_PATCH = value;
|
SECURITY_PATCH = value;
|
||||||
LOGD("Set SECURITY_PATCH to '%s'", value.c_str());
|
LOGD("Set SECURITY_PATCH to '%s'", value.c_str());
|
||||||
} else if (key == "API_LEVEL") {
|
} else if (key == "FIRST_API_LEVEL") {
|
||||||
API_LEVEL = value;
|
API_LEVEL = value;
|
||||||
LOGD("Set API_LEVEL to '%s'", value.c_str());
|
LOGD("Set API_LEVEL to '%s'", value.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
key.clear();
|
key.clear();
|
||||||
|
key.shrink_to_fit();
|
||||||
|
|
||||||
value.clear();
|
value.clear();
|
||||||
key.shrink_to_fit();
|
value.shrink_to_fit();
|
||||||
key.shrink_to_fit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(file);
|
fclose(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void doHook(const std::string &str) {
|
|
||||||
parsePropsFile(str.c_str());
|
|
||||||
|
|
||||||
void *handle = DobbySymbolResolver("libc.so", "__system_property_read_callback");
|
|
||||||
if (handle == nullptr) {
|
|
||||||
LOGD("Couldn't find '__system_property_read_callback' handle. Report to @chiteroman");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
LOGD("Found '__system_property_read_callback' handle at %p", handle);
|
|
||||||
DobbyHook(handle, (void *) my_system_property_read_callback,
|
|
||||||
(void **) &o_system_property_read_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
class PlayIntegrityFix : public zygisk::ModuleBase {
|
class PlayIntegrityFix : public zygisk::ModuleBase {
|
||||||
public:
|
public:
|
||||||
void onLoad(zygisk::Api *api, JNIEnv *env) override {
|
void onLoad(zygisk::Api *api, JNIEnv *env) override {
|
||||||
@ -129,49 +126,49 @@ public:
|
|||||||
|
|
||||||
if (isGms) api->setOption(zygisk::FORCE_DENYLIST_UNMOUNT);
|
if (isGms) api->setOption(zygisk::FORCE_DENYLIST_UNMOUNT);
|
||||||
|
|
||||||
if (isGmsUnstable) {
|
if (!isGmsUnstable) {
|
||||||
|
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
|
||||||
callbacks.clear();
|
|
||||||
API_LEVEL.clear();
|
|
||||||
SECURITY_PATCH.clear();
|
|
||||||
API_LEVEL.shrink_to_fit();
|
|
||||||
SECURITY_PATCH.shrink_to_fit();
|
|
||||||
|
|
||||||
int fd = api->connectCompanion();
|
|
||||||
|
|
||||||
auto rawDir = env->GetStringUTFChars(args->app_data_dir, nullptr);
|
|
||||||
propsFile = rawDir;
|
|
||||||
env->ReleaseStringUTFChars(args->app_data_dir, rawDir);
|
|
||||||
|
|
||||||
propsFile = propsFile + "/pif.prop";
|
|
||||||
|
|
||||||
int strSize = static_cast<int>(propsFile.size());
|
|
||||||
|
|
||||||
write(fd, &strSize, sizeof(strSize));
|
|
||||||
write(fd, propsFile.data(), strSize);
|
|
||||||
|
|
||||||
long size;
|
|
||||||
read(fd, &size, sizeof(size));
|
|
||||||
|
|
||||||
char buffer[size];
|
|
||||||
read(fd, buffer, size);
|
|
||||||
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
moduleDex.insert(moduleDex.end(), buffer, buffer + size);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
|
callbacks.clear();
|
||||||
|
|
||||||
|
API_LEVEL.clear();
|
||||||
|
API_LEVEL.shrink_to_fit();
|
||||||
|
|
||||||
|
SECURITY_PATCH.clear();
|
||||||
|
SECURITY_PATCH.shrink_to_fit();
|
||||||
|
|
||||||
|
int fd = api->connectCompanion();
|
||||||
|
|
||||||
|
auto rawDir = env->GetStringUTFChars(args->app_data_dir, nullptr);
|
||||||
|
propsFile = rawDir;
|
||||||
|
env->ReleaseStringUTFChars(args->app_data_dir, rawDir);
|
||||||
|
|
||||||
|
propsFile = propsFile + "/cache/pif.prop";
|
||||||
|
|
||||||
|
int strSize = static_cast<int>(propsFile.size());
|
||||||
|
|
||||||
|
write(fd, &strSize, sizeof(strSize));
|
||||||
|
write(fd, propsFile.data(), strSize);
|
||||||
|
|
||||||
|
long size;
|
||||||
|
read(fd, &size, sizeof(size));
|
||||||
|
|
||||||
|
char buffer[size];
|
||||||
|
read(fd, buffer, size);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
moduleDex.insert(moduleDex.end(), buffer, buffer + size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override {
|
void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override {
|
||||||
if (!isGmsUnstable) return;
|
if (!isGmsUnstable) return;
|
||||||
|
|
||||||
doHook(propsFile);
|
doHook();
|
||||||
|
|
||||||
if (!moduleDex.empty()) injectDex();
|
injectDex();
|
||||||
|
|
||||||
LOGD("clean");
|
LOGD("clean");
|
||||||
propsFile.clear();
|
propsFile.clear();
|
||||||
@ -191,7 +188,25 @@ private:
|
|||||||
std::string propsFile;
|
std::string propsFile;
|
||||||
std::vector<char> moduleDex;
|
std::vector<char> moduleDex;
|
||||||
|
|
||||||
|
void doHook() {
|
||||||
|
if (!propsFile.empty()) parsePropsFile(propsFile.c_str());
|
||||||
|
|
||||||
|
void *handle = DobbySymbolResolver("libc.so", "__system_property_read_callback");
|
||||||
|
if (handle == nullptr) {
|
||||||
|
LOGD("Couldn't find '__system_property_read_callback' handle. Report to @chiteroman");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LOGD("Found '__system_property_read_callback' handle at %p", handle);
|
||||||
|
DobbyHook(handle, (void *) my_system_property_read_callback,
|
||||||
|
(void **) &o_system_property_read_callback);
|
||||||
|
}
|
||||||
|
|
||||||
void injectDex() {
|
void injectDex() {
|
||||||
|
if (moduleDex.empty()) {
|
||||||
|
LOGD("Dex not loaded in memory");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LOGD("Preparing to inject %d bytes to the process", static_cast<int>(moduleDex.size()));
|
LOGD("Preparing to inject %d bytes to the process", static_cast<int>(moduleDex.size()));
|
||||||
|
|
||||||
LOGD("get system classloader");
|
LOGD("get system classloader");
|
||||||
@ -232,7 +247,7 @@ static void companion(int fd) {
|
|||||||
|
|
||||||
std::filesystem::copy_file(PROP_FILE_PATH, propsFile,
|
std::filesystem::copy_file(PROP_FILE_PATH, propsFile,
|
||||||
std::filesystem::copy_options::overwrite_existing);
|
std::filesystem::copy_options::overwrite_existing);
|
||||||
std::filesystem::permissions(propsFile, std::filesystem::perms::others_all);
|
std::filesystem::permissions(propsFile, std::filesystem::perms::all);
|
||||||
|
|
||||||
propsFile.clear();
|
propsFile.clear();
|
||||||
propsFile.shrink_to_fit();
|
propsFile.shrink_to_fit();
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
|
|
||||||
#define ZYGISK_API_VERSION 4
|
#define ZYGISK_API_VERSION 2
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
@ -142,7 +142,6 @@ struct AppSpecializeArgs {
|
|||||||
jint &gid;
|
jint &gid;
|
||||||
jintArray &gids;
|
jintArray &gids;
|
||||||
jint &runtime_flags;
|
jint &runtime_flags;
|
||||||
jobjectArray &rlimits;
|
|
||||||
jint &mount_external;
|
jint &mount_external;
|
||||||
jstring &se_info;
|
jstring &se_info;
|
||||||
jstring &nice_name;
|
jstring &nice_name;
|
||||||
@ -150,7 +149,6 @@ struct AppSpecializeArgs {
|
|||||||
jstring &app_data_dir;
|
jstring &app_data_dir;
|
||||||
|
|
||||||
// Optional arguments. Please check whether the pointer is null before de-referencing
|
// Optional arguments. Please check whether the pointer is null before de-referencing
|
||||||
jintArray *const fds_to_ignore;
|
|
||||||
jboolean *const is_child_zygote;
|
jboolean *const is_child_zygote;
|
||||||
jboolean *const is_top_app;
|
jboolean *const is_top_app;
|
||||||
jobjectArray *const pkg_data_info_list;
|
jobjectArray *const pkg_data_info_list;
|
||||||
@ -243,14 +241,6 @@ struct Api {
|
|||||||
// Returns bitwise-or'd zygisk::StateFlag values.
|
// Returns bitwise-or'd zygisk::StateFlag values.
|
||||||
uint32_t getFlags();
|
uint32_t getFlags();
|
||||||
|
|
||||||
// Exempt the provided file descriptor from being automatically closed.
|
|
||||||
//
|
|
||||||
// This API only make sense in preAppSpecialize; calling this method in any other situation
|
|
||||||
// is either a no-op (returns true) or an error (returns false).
|
|
||||||
//
|
|
||||||
// When false is returned, the provided file descriptor will eventually be closed by zygote.
|
|
||||||
bool exemptFd(int fd);
|
|
||||||
|
|
||||||
// Hook JNI native methods for a class
|
// Hook JNI native methods for a class
|
||||||
//
|
//
|
||||||
// Lookup all registered JNI native methods and replace it with your own methods.
|
// Lookup all registered JNI native methods and replace it with your own methods.
|
||||||
@ -267,10 +257,13 @@ struct Api {
|
|||||||
// 56b4346000-56b4347000 r-xp 00002000 fe:00 235 /system/bin/app_process64
|
// 56b4346000-56b4347000 r-xp 00002000 fe:00 235 /system/bin/app_process64
|
||||||
// (More details: https://man7.org/linux/man-pages/man5/proc.5.html)
|
// (More details: https://man7.org/linux/man-pages/man5/proc.5.html)
|
||||||
//
|
//
|
||||||
// The `dev` and `inode` pair uniquely identifies a file being mapped into memory.
|
// For ELFs loaded in memory with pathname matching `regex`, replace function `symbol` with `newFunc`.
|
||||||
// For matching ELFs loaded in memory, replace function `symbol` with `newFunc`.
|
|
||||||
// If `oldFunc` is not nullptr, the original function pointer will be saved to `oldFunc`.
|
// If `oldFunc` is not nullptr, the original function pointer will be saved to `oldFunc`.
|
||||||
void pltHookRegister(dev_t dev, ino_t inode, const char *symbol, void *newFunc, void **oldFunc);
|
void pltHookRegister(const char *regex, const char *symbol, void *newFunc, void **oldFunc);
|
||||||
|
|
||||||
|
// For ELFs loaded in memory with pathname matching `regex`, exclude hooks registered for `symbol`.
|
||||||
|
// If `symbol` is nullptr, then all symbols will be excluded.
|
||||||
|
void pltHookExclude(const char *regex, const char *symbol);
|
||||||
|
|
||||||
// Commit all the hooks that was previously registered.
|
// Commit all the hooks that was previously registered.
|
||||||
// Returns false if an error occurred.
|
// Returns false if an error occurred.
|
||||||
@ -331,8 +324,8 @@ struct api_table {
|
|||||||
bool (*registerModule)(api_table *, module_abi *);
|
bool (*registerModule)(api_table *, module_abi *);
|
||||||
|
|
||||||
void (*hookJniNativeMethods)(JNIEnv *, const char *, JNINativeMethod *, int);
|
void (*hookJniNativeMethods)(JNIEnv *, const char *, JNINativeMethod *, int);
|
||||||
void (*pltHookRegister)(dev_t, ino_t, const char *, void *, void **);
|
void (*pltHookRegister)(const char *, const char *, void *, void **);
|
||||||
bool (*exemptFd)(int);
|
void (*pltHookExclude)(const char *, const char *);
|
||||||
bool (*pltHookCommit)();
|
bool (*pltHookCommit)();
|
||||||
int (*connectCompanion)(void * /* impl */);
|
int (*connectCompanion)(void * /* impl */);
|
||||||
void (*setOption)(void * /* impl */, Option);
|
void (*setOption)(void * /* impl */, Option);
|
||||||
@ -365,14 +358,14 @@ inline void Api::setOption(Option opt) {
|
|||||||
inline uint32_t Api::getFlags() {
|
inline uint32_t Api::getFlags() {
|
||||||
return tbl->getFlags ? tbl->getFlags(tbl->impl) : 0;
|
return tbl->getFlags ? tbl->getFlags(tbl->impl) : 0;
|
||||||
}
|
}
|
||||||
inline bool Api::exemptFd(int fd) {
|
|
||||||
return tbl->exemptFd != nullptr && tbl->exemptFd(fd);
|
|
||||||
}
|
|
||||||
inline void Api::hookJniNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int numMethods) {
|
inline void Api::hookJniNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int numMethods) {
|
||||||
if (tbl->hookJniNativeMethods) tbl->hookJniNativeMethods(env, className, methods, numMethods);
|
if (tbl->hookJniNativeMethods) tbl->hookJniNativeMethods(env, className, methods, numMethods);
|
||||||
}
|
}
|
||||||
inline void Api::pltHookRegister(dev_t dev, ino_t inode, const char *symbol, void *newFunc, void **oldFunc) {
|
inline void Api::pltHookRegister(const char *regex, const char *symbol, void *newFunc, void **oldFunc) {
|
||||||
if (tbl->pltHookRegister) tbl->pltHookRegister(dev, inode, symbol, newFunc, oldFunc);
|
if (tbl->pltHookRegister) tbl->pltHookRegister(regex, symbol, newFunc, oldFunc);
|
||||||
|
}
|
||||||
|
inline void Api::pltHookExclude(const char *regex, const char *symbol) {
|
||||||
|
if (tbl->pltHookExclude) tbl->pltHookExclude(regex, symbol);
|
||||||
}
|
}
|
||||||
inline bool Api::pltHookCommit() {
|
inline bool Api::pltHookCommit() {
|
||||||
return tbl->pltHookCommit != nullptr && tbl->pltHookCommit();
|
return tbl->pltHookCommit != nullptr && tbl->pltHookCommit();
|
||||||
|
@ -17,19 +17,17 @@ import java.util.Properties;
|
|||||||
|
|
||||||
public final class EntryPoint {
|
public final class EntryPoint {
|
||||||
private static final Properties props = new Properties();
|
private static final Properties props = new Properties();
|
||||||
private static final File file = new File("/data/data/com.google.android.gms/pif.prop");
|
private static final File file = new File("/data/data/com.google.android.gms/cache/pif.prop");
|
||||||
|
|
||||||
public static void init() {
|
public static void init() {
|
||||||
|
|
||||||
try (Reader reader = new FileReader(file)) {
|
try (Reader reader = new FileReader(file)) {
|
||||||
props.load(reader);
|
props.load(reader);
|
||||||
|
LOG("Loaded " + props.size() + " fields!");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LOG("Couldn't load pif.prop file!");
|
LOG("Couldn't load pif.prop file: " + e);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("Loaded " + props.size() + " fields!");
|
|
||||||
|
|
||||||
spoofDevice();
|
spoofDevice();
|
||||||
spoofProvider();
|
spoofProvider();
|
||||||
}
|
}
|
||||||
@ -62,13 +60,13 @@ public final class EntryPoint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void spoofDevice() {
|
public static void spoofDevice() {
|
||||||
setProp("PRODUCT", props.getProperty("PRODUCT"));
|
setProp("PRODUCT", props.getProperty("PRODUCT", "bullhead"));
|
||||||
setProp("DEVICE", props.getProperty("DEVICE"));
|
setProp("DEVICE", props.getProperty("DEVICE", "bullhead"));
|
||||||
setProp("MANUFACTURER", props.getProperty("MANUFACTURER"));
|
setProp("MANUFACTURER", props.getProperty("MANUFACTURER", "LGE"));
|
||||||
setProp("BRAND", props.getProperty("BRAND"));
|
setProp("BRAND", props.getProperty("BRAND", "google"));
|
||||||
setProp("MODEL", props.getProperty("MODEL"));
|
setProp("MODEL", props.getProperty("MODEL", "Nexus 5X"));
|
||||||
setProp("FINGERPRINT", props.getProperty("FINGERPRINT"));
|
setProp("FINGERPRINT", props.getProperty("FINGERPRINT", "google/bullhead/bullhead:8.0.0/OPR6.170623.013/4283548:user/release-keys"));
|
||||||
setVersionProp("SECURITY_PATCH", props.getProperty("SECURITY_PATCH"));
|
setVersionProp("SECURITY_PATCH", props.getProperty("SECURITY_PATCH", "2017-08-05"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setProp(String name, String value) {
|
private static void setProp(String name, String value) {
|
||||||
|
Loading…
Reference in New Issue
Block a user