Refactor code v15.2

This commit is contained in:
chiteroman 2024-01-12 13:32:32 +01:00
parent 0a6f936074
commit a246eb8cf9
20 changed files with 296 additions and 156 deletions

6
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "app/src/main/cpp/Dobby"] [submodule "app/src/main/cpp/libcxx"]
path = app/src/main/cpp/Dobby path = app/src/main/cpp/libcxx
url = https://github.com/jmpews/Dobby.git url = https://github.com/topjohnwu/libcxx.git

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@ -8,10 +8,6 @@ android {
ndkVersion = "26.1.10909125" ndkVersion = "26.1.10909125"
buildToolsVersion = "34.0.0" buildToolsVersion = "34.0.0"
buildFeatures {
prefab = true
}
packaging { packaging {
jniLibs { jniLibs {
excludes += "**/liblog.so" excludes += "**/liblog.so"
@ -27,18 +23,8 @@ android {
versionName = "v15.2" versionName = "v15.2"
externalNativeBuild { externalNativeBuild {
cmake { ndk {
arguments += "-DANDROID_STL=none" jobs = Runtime.getRuntime().availableProcessors()
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 += "-fno-exceptions"
cppFlags += "-fno-rtti"
} }
} }
} }
@ -57,17 +43,12 @@ android {
} }
externalNativeBuild { externalNativeBuild {
cmake { ndkBuild {
path = file("src/main/cpp/CMakeLists.txt") path = file("src/main/cpp/Android.mk")
version = "3.22.1"
} }
} }
} }
dependencies {
implementation("dev.rikka.ndk.thirdparty:cxx:1.2.0")
}
tasks.register("updateModuleProp") { tasks.register("updateModuleProp") {
doLast { doLast {
val versionName = project.android.defaultConfig.versionName val versionName = project.android.defaultConfig.versionName

View File

@ -0,0 +1,16 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := dobby
LOCAL_SRC_FILES := $(LOCAL_PATH)/dobby/$(TARGET_ARCH_ABI)/libdobby.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/dobby
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := zygisk
LOCAL_SRC_FILES := main.cpp
LOCAL_STATIC_LIBRARIES := libcxx dobby
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
include $(LOCAL_PATH)/libcxx/Android.mk

View File

@ -0,0 +1,6 @@
APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
APP_CFLAGS := -fvisibility=hidden -fvisibility-inlines-hidden -ffunction-sections -fdata-sections -Oz -flto
APP_CPPFLAGS := -std=c++20 -fno-exceptions -fno-rtti
APP_LDFLAGS := -Oz -flto -Wl,--exclude-libs,ALL -Wl,--gc-sections
APP_STL := none
APP_PLATFORM := android-26

View File

@ -1,13 +0,0 @@
cmake_minimum_required(VERSION 3.22.1)
project(playintegrityfix)
find_package(cxx REQUIRED CONFIG)
link_libraries(cxx::cxx)
add_library(${CMAKE_PROJECT_NAME} SHARED module.cpp)
add_subdirectory(Dobby)
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE log dobby_static)

@ -1 +0,0 @@
Subproject commit b0176de574104726bb68dff3b77ee666300fc338

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,152 @@
#ifndef dobby_h
#define dobby_h
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdint.h>
typedef uintptr_t addr_t;
typedef uint32_t addr32_t;
typedef uint64_t addr64_t;
typedef void *dobby_dummy_func_t;
typedef void *asm_func_t;
#if defined(__arm__)
typedef struct {
uint32_t dummy_0;
uint32_t dummy_1;
uint32_t dummy_2;
uint32_t sp;
union {
uint32_t r[13];
struct {
uint32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12;
} regs;
} general;
uint32_t lr;
} DobbyRegisterContext;
#elif defined(__arm64__) || defined(__aarch64__)
#define ARM64_TMP_REG_NDX_0 17
typedef union _FPReg {
__int128_t q;
struct {
double d1;
double d2;
} d;
struct {
float f1;
float f2;
float f3;
float f4;
} f;
} FPReg;
// register context
typedef struct {
uint64_t dmmpy_0; // dummy placeholder
uint64_t sp;
uint64_t dmmpy_1; // dummy placeholder
union {
uint64_t x[29];
struct {
uint64_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22,
x23, x24, x25, x26, x27, x28;
} regs;
} general;
uint64_t fp;
uint64_t lr;
union {
FPReg q[32];
struct {
FPReg q0, q1, q2, q3, q4, q5, q6, q7;
// [!!! READ ME !!!]
// for Arm64, can't access q8 - q31, unless you enable full floating-point register pack
FPReg q8, q9, q10, q11, q12, q13, q14, q15, q16, q17, q18, q19, q20, q21, q22, q23, q24, q25, q26, q27, q28, q29,
q30, q31;
} regs;
} floating;
} DobbyRegisterContext;
#elif defined(_M_IX86) || defined(__i386__)
typedef struct _RegisterContext {
uint32_t dummy_0;
uint32_t esp;
uint32_t dummy_1;
uint32_t flags;
union {
struct {
uint32_t eax, ebx, ecx, edx, ebp, esp, edi, esi;
} regs;
} general;
} DobbyRegisterContext;
#elif defined(_M_X64) || defined(__x86_64__)
typedef struct {
uint64_t dummy_0;
uint64_t rsp;
union {
struct {
uint64_t rax, rbx, rcx, rdx, rbp, rsp, rdi, rsi, r8, r9, r10, r11, r12, r13, r14, r15;
} regs;
} general;
uint64_t dummy_1;
uint64_t flags;
} DobbyRegisterContext;
#endif
#define install_hook_name(name, fn_ret_t, fn_args_t...) \
static fn_ret_t fake_##name(fn_args_t); \
static fn_ret_t (*orig_##name)(fn_args_t); \
/* __attribute__((constructor)) */ static void install_hook_##name(void *sym_addr) { \
DobbyHook(sym_addr, (dobby_dummy_func_t)fake_##name, (dobby_dummy_func_t *)&orig_##name); \
return; \
} \
fn_ret_t fake_##name(fn_args_t)
// memory code patch
int DobbyCodePatch(void *address, uint8_t *buffer, uint32_t buffer_size);
// function inline hook
int DobbyHook(void *address, dobby_dummy_func_t replace_func, dobby_dummy_func_t *origin_func);
// dynamic binary instruction instrument
// for Arm64, can't access q8 - q31, unless enable full floating-point register pack
typedef void (*dobby_instrument_callback_t)(void *address, DobbyRegisterContext *ctx);
int DobbyInstrument(void *address, dobby_instrument_callback_t pre_handler);
// destroy and restore code patch
int DobbyDestroy(void *address);
const char *DobbyGetVersion();
// symbol resolver
void *DobbySymbolResolver(const char *image_name, const char *symbol_name);
// import table replace
int DobbyImportTableReplace(char *image_name, char *symbol_name, dobby_dummy_func_t fake_func,
dobby_dummy_func_t *orig_func);
// for arm, Arm64, try use b xxx instead of ldr absolute indirect branch
// for x86, x64, always use absolute indirect jump
void dobby_enable_near_branch_trampoline();
void dobby_disable_near_branch_trampoline();
#ifdef __cplusplus
}
#endif
#endif

Binary file not shown.

Binary file not shown.

@ -0,0 +1 @@
Subproject commit 12c8f4e93f196a700137e983dcceeac43cf807f2

View File

@ -1,8 +1,6 @@
#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"
@ -53,6 +51,7 @@ static void modify_callback(void *cookie, const char *name, const char *value, u
} else if (prop == "sys.usb.state") { } else if (prop == "sys.usb.state") {
value = "none"; value = "none";
} }
if (!prop.starts_with("debug") && !prop.starts_with("cache") && !prop.starts_with("persist")) { if (!prop.starts_with("debug") && !prop.starts_with("cache") && !prop.starts_with("persist")) {
@ -104,25 +103,22 @@ public:
return; return;
} }
std::string_view process(name); if (strncmp(name, "com.google.android.gms", 22) != 0) {
env->ReleaseStringUTFChars(args->nice_name, name);
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); api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
return; return;
} }
api->setOption(zygisk::FORCE_DENYLIST_UNMOUNT); api->setOption(zygisk::FORCE_DENYLIST_UNMOUNT);
if (!isGmsUnstable) { if (strcmp(name, "com.google.android.gms.unstable") != 0) {
env->ReleaseStringUTFChars(args->nice_name, name);
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY); api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
return; return;
} }
env->ReleaseStringUTFChars(args->nice_name, name);
long dexSize = 0, jsonSize = 0; long dexSize = 0, jsonSize = 0;
int fd = api->connectCompanion(); int fd = api->connectCompanion();
@ -130,15 +126,18 @@ public:
read(fd, &dexSize, sizeof(long)); read(fd, &dexSize, sizeof(long));
read(fd, &jsonSize, sizeof(long)); read(fd, &jsonSize, sizeof(long));
LOGD("Dex file size: %ld", dexSize);
LOGD("Json file size: %ld", jsonSize);
vector.resize(dexSize); vector.resize(dexSize);
read(fd, vector.data(), dexSize); read(fd, vector.data(), dexSize);
char jsonBufer[jsonSize]; std::vector<char> jsonVector(jsonSize);
read(fd, jsonBufer, jsonSize); read(fd, jsonVector.data(), jsonSize);
close(fd); close(fd);
std::string_view jsonStr(jsonBufer, jsonSize); std::string_view jsonStr(jsonVector.cbegin(), jsonVector.cend());
json = nlohmann::json::parse(jsonStr, nullptr, false, true); json = nlohmann::json::parse(jsonStr, nullptr, false, true);
if (json.contains("FIRST_API_LEVEL")) { if (json.contains("FIRST_API_LEVEL")) {
@ -238,34 +237,38 @@ private:
}; };
static void companion(int fd) { static void companion(int fd) {
std::ifstream dexFile(CLASSES_DEX, std::ios::in | std::ios::binary); long dexSize = 0, jsonSize = 0;
std::vector<char> dexVector, jsonVector;
if (!dexFile) { FILE *dexFile = fopen(CLASSES_DEX, "rb");
long i = 0;
write(fd, &i, sizeof(i)); if (dexFile) {
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)), FILE *jsonFile = fopen(PIF_JSON, "rb");
std::istreambuf_iterator<char>()); if (jsonFile == nullptr) jsonFile = fopen(PIF_JSON_2, "rb");
long dexSize = dexVector.size();
std::ifstream jsonFile; if (jsonFile) {
if (std::filesystem::exists(PIF_JSON)) { fseek(jsonFile, 0, SEEK_END);
jsonFile = std::ifstream(PIF_JSON, std::ios::in); jsonSize = ftell(jsonFile);
} else if (std::filesystem::exists(PIF_JSON_2)) { fseek(jsonFile, 0, SEEK_SET);
jsonFile = std::ifstream(PIF_JSON_2, std::ios::in);
} else { jsonVector.resize(jsonSize);
long i = 0; fread(jsonVector.data(), 1, jsonSize, jsonFile);
write(fd, &i, sizeof(i));
return; fclose(jsonFile);
} }
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, &jsonSize, sizeof(long)); write(fd, &jsonSize, sizeof(long));

View File

@ -15,45 +15,7 @@ import java.security.Security;
public final class EntryPoint { public final class EntryPoint {
private static JSONObject jsonObject = new JSONObject(); private static JSONObject jsonObject = new JSONObject();
public static void init(String json) { static {
try {
jsonObject = new JSONObject(json);
} catch (JSONException e) {
LOG("Couldn't parse JSON from Zygisk");
}
boolean FORCE_BASIC_ATTESTATION = true;
if (jsonObject.has("FORCE_BASIC_ATTESTATION")) {
try {
FORCE_BASIC_ATTESTATION = jsonObject.getBoolean("FORCE_BASIC_ATTESTATION");
} catch (JSONException e) {
LOG("Couldn't parse FORCE_BASIC_ATTESTATION from JSON");
}
jsonObject.remove("FORCE_BASIC_ATTESTATION");
}
spoofDevice();
if (FORCE_BASIC_ATTESTATION) spoofProvider();
}
static void LOG(String msg) {
Log.d("PIF/Java", msg);
}
static void spoofDevice() {
jsonObject.keys().forEachRemaining(s -> {
try {
Object value = jsonObject.get(s);
setFieldValue(s, value);
} catch (JSONException ignored) {
}
});
}
private static void spoofProvider() {
try { try {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null); keyStore.load(null);
@ -77,6 +39,31 @@ public final class EntryPoint {
} }
} }
public static void init(String json) {
try {
jsonObject = new JSONObject(json);
} catch (JSONException e) {
LOG("Couldn't parse JSON from Zygisk");
}
spoofDevice();
}
static void LOG(String msg) {
Log.d("PIF/Java", msg);
}
static void spoofDevice() {
jsonObject.keys().forEachRemaining(s -> {
try {
Object value = jsonObject.get(s);
setFieldValue(s, value);
} catch (JSONException ignored) {
}
});
}
private static void setFieldValue(String name, Object value) { private static void setFieldValue(String name, Object value) {
if (name == null || value == null || name.isEmpty()) return; if (name == null || value == null || name.isEmpty()) return;

View File

@ -1,3 +1,3 @@
plugins { plugins {
id("com.android.application") version "8.2.0" apply false id("com.android.application") version "8.2.1" apply false
} }

View File

@ -5,8 +5,8 @@ fi
# safetynet-fix module is obsolete and it's incompatible with PIF. # safetynet-fix module is obsolete and it's incompatible with PIF.
if [ -d /data/adb/modules/safetynet-fix ]; then if [ -d /data/adb/modules/safetynet-fix ]; then
rm -rf /data/adb/modules/safetynet-fix rm -rf /data/adb/modules/safetynet-fix
rm -f /data/adb/SNFix.dex rm -f /data/adb/SNFix.dex
ui_print "! safetynet-fix module will be removed. Do NOT install it again along PIF." ui_print "! safetynet-fix module will be removed. Do NOT install it again along PIF."
fi fi
@ -18,41 +18,41 @@ fi
# Remove xiaomi.eu apps # Remove xiaomi.eu apps
if [ -d "/product/app/XiaomiEUInject" ]; then if [ -d "/product/app/XiaomiEUInject" ]; then
directory="$MODPATH/product/app/XiaomiEUInject" directory="$MODPATH/product/app/XiaomiEUInject"
[ -d "$directory" ] || mkdir -p "$directory" [ -d "$directory" ] || mkdir -p "$directory"
touch "$directory/.replace" touch "$directory/.replace"
ui_print "- XiaomiEUInject app removed." ui_print "- XiaomiEUInject app removed."
fi fi
# Remove EliteRoms app # Remove EliteRoms app
if [ -d "/system/app/XInjectModule" ]; then if [ -d "/system/app/XInjectModule" ]; then
directory="$MODPATH/system/app/XInjectModule" directory="$MODPATH/system/app/XInjectModule"
[ -d "$directory" ] || mkdir -p "$directory" [ -d "$directory" ] || mkdir -p "$directory"
touch "$directory/.replace" touch "$directory/.replace"
ui_print "- XInjectModule app removed." ui_print "- XInjectModule app removed."
fi fi
if [ -d "/system/app/EliteDevelopmentModule" ]; then if [ -d "/system/app/EliteDevelopmentModule" ]; then
directory="$MODPATH/system/app/EliteDevelopmentModule" directory="$MODPATH/system/app/EliteDevelopmentModule"
[ -d "$directory" ] || mkdir -p "$directory" [ -d "$directory" ] || mkdir -p "$directory"
touch "$directory/.replace" touch "$directory/.replace"
ui_print "- EliteDevelopmentModule app removed." ui_print "- EliteDevelopmentModule app removed."
fi fi
if [ -f "/data/adb/pif.json" ]; then if [ -f "/data/adb/pif.json" ]; then
mv -f "/data/adb/pif.json" "/data/adb/pif.json.old" mv -f "/data/adb/pif.json" "/data/adb/pif.json.old"
ui_print "- Backup pif.json" ui_print "- Backup pif.json"
fi fi

View File

@ -7,6 +7,5 @@
"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", "ID": "NMF26F"
"FORCE_BASIC_ATTESTATION": true }
}

View File

@ -9,16 +9,16 @@ resetprop_if_diff() {
local NAME=$1 local NAME=$1
local EXPECTED=$2 local EXPECTED=$2
local CURRENT=$(resetprop $NAME) local CURRENT=$(resetprop $NAME)
[ -z "$CURRENT" ] || [ "$CURRENT" == "$EXPECTED" ] || resetprop $NAME $EXPECTED [ -z "$CURRENT" ] || [ "$CURRENT" == "$EXPECTED" ] || resetprop -n $NAME $EXPECTED
} }
resetprop_if_match() { resetprop_if_match() {
local NAME=$1 local NAME=$1
local CONTAINS=$2 local CONTAINS=$2
local VALUE=$3 local VALUE=$3
[[ "$(resetprop $NAME)" == *"$CONTAINS"* ]] && resetprop $NAME $VALUE [[ "$(resetprop $NAME)" == *"$CONTAINS"* ]] && resetprop -n $NAME $VALUE
} }
# RootBeer, Microsoft # RootBeer, Microsoft

View File

@ -4,16 +4,16 @@ resetprop_if_diff() {
local NAME=$1 local NAME=$1
local EXPECTED=$2 local EXPECTED=$2
local CURRENT=$(resetprop $NAME) local CURRENT=$(resetprop $NAME)
[ -z "$CURRENT" ] || [ "$CURRENT" == "$EXPECTED" ] || resetprop $NAME $EXPECTED [ -z "$CURRENT" ] || [ "$CURRENT" == "$EXPECTED" ] || resetprop -n $NAME $EXPECTED
} }
resetprop_if_match() { resetprop_if_match() {
local NAME=$1 local NAME=$1
local CONTAINS=$2 local CONTAINS=$2
local VALUE=$3 local VALUE=$3
[[ "$(resetprop $NAME)" == *"$CONTAINS"* ]] && resetprop $NAME $VALUE [[ "$(resetprop $NAME)" == *"$CONTAINS"* ]] && resetprop -n $NAME $VALUE
} }
# Magisk recovery mode # Magisk recovery mode
@ -34,15 +34,18 @@ fi
# late props which must be set after boot_completed for various OEMs # late props which must be set after boot_completed for various OEMs
until [ "$(resetprop sys.boot_completed)" == "1" ]; do until [ "$(resetprop sys.boot_completed)" == "1" ]; do
sleep 1 sleep 1
done done
# Avoid breaking Realme fingerprint scanners # Avoid breaking Realme fingerprint scanners
resetprop_if_diff ro.boot.flash.locked 1 resetprop_if_diff ro.boot.flash.locked 1
# Avoid breaking Oppo fingerprint scanners # Avoid breaking Oppo fingerprint scanners
resetprop_if_diff ro.boot.vbmeta.device_state locked resetprop_if_diff ro.boot.vbmeta.device_state locked
# Avoid breaking OnePlus display modes/fingerprint scanners # Avoid breaking OnePlus display modes/fingerprint scanners
resetprop_if_diff vendor.boot.verifiedbootstate green resetprop_if_diff vendor.boot.verifiedbootstate green
# Avoid breaking OnePlus/Oppo display fingerprint scanners on OOS/ColorOS 12+ # Avoid breaking OnePlus/Oppo display fingerprint scanners on OOS/ColorOS 12+
resetprop_if_diff ro.boot.verifiedbootstate green resetprop_if_diff ro.boot.verifiedbootstate green
resetprop_if_diff ro.boot.veritymode enforcing resetprop_if_diff ro.boot.veritymode enforcing