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

Improve code

parent b145c85d
No related branches found
No related tags found
No related merge requests found
...@@ -28,8 +28,7 @@ android { ...@@ -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; ...@@ -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 ...@@ -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) { ...@@ -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) { ...@@ -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();
value.clear();
key.shrink_to_fit();
key.shrink_to_fit(); key.shrink_to_fit();
value.clear();
value.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: ...@@ -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);
return;
}
callbacks.clear(); callbacks.clear();
API_LEVEL.clear();
SECURITY_PATCH.clear();
API_LEVEL.shrink_to_fit();
SECURITY_PATCH.shrink_to_fit();
int fd = api->connectCompanion(); API_LEVEL.clear();
API_LEVEL.shrink_to_fit();
auto rawDir = env->GetStringUTFChars(args->app_data_dir, nullptr); SECURITY_PATCH.clear();
propsFile = rawDir; SECURITY_PATCH.shrink_to_fit();
env->ReleaseStringUTFChars(args->app_data_dir, rawDir);
propsFile = propsFile + "/pif.prop"; int fd = api->connectCompanion();
int strSize = static_cast<int>(propsFile.size()); auto rawDir = env->GetStringUTFChars(args->app_data_dir, nullptr);
propsFile = rawDir;
env->ReleaseStringUTFChars(args->app_data_dir, rawDir);
write(fd, &strSize, sizeof(strSize)); propsFile = propsFile + "/cache/pif.prop";
write(fd, propsFile.data(), strSize);
long size; int strSize = static_cast<int>(propsFile.size());
read(fd, &size, sizeof(size));
char buffer[size]; write(fd, &strSize, sizeof(strSize));
read(fd, buffer, size); write(fd, propsFile.data(), strSize);
close(fd); long size;
read(fd, &size, sizeof(size));
moduleDex.insert(moduleDex.end(), buffer, buffer + size); char buffer[size];
read(fd, buffer, size);
return; close(fd);
}
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY); 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: ...@@ -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) { ...@@ -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 @@ ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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) { ...@@ -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; ...@@ -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 { ...@@ -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) {
......
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