diff --git a/build.gradle.kts b/build.gradle.kts index 39ab1e5..b1dc85e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,6 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { + alias(libs.plugins.android.application) apply false alias(libs.plugins.android.library) apply false } @@ -11,8 +12,8 @@ tasks.register("copyZygiskFiles") { val zygiskBuildDir = zygiskModule.layout.buildDirectory.get().asFile val classesJar = zygiskBuildDir - .resolve("intermediates/aar_main_jar/release/syncReleaseLibJars/classes.jar") - classesJar.copyTo(moduleFolder.resolve("classes.jar"), overwrite = true) + .resolve("intermediates/dex/release/minifyReleaseWithR8/classes.dex") + classesJar.copyTo(moduleFolder.resolve("classes.dex"), overwrite = true) val zygiskSoDir = zygiskBuildDir .resolve("intermediates/stripped_native_libs/release/stripReleaseDebugSymbols/out/lib") diff --git a/changelog.md b/changelog.md deleted file mode 100644 index 857932a..0000000 --- a/changelog.md +++ /dev/null @@ -1,9 +0,0 @@ -Telegram channel: -https://t.me/playintegrityfix - -Donations: -https://www.paypal.com/paypalme/chiteroman0 - -# v18.9 - -- Update fingerprint. diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 686d1ea..7466774 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,3 +9,4 @@ hiddenapibypass = { group = "org.lsposed.hiddenapibypass", name = "hiddenapibypa [plugins] android-library = { id = "com.android.library", version.ref = "agp" } +android-application = { id = "com.android.application", version.ref = "agp" } diff --git a/inject/src/main/cpp/inject.cpp b/inject/src/main/cpp/inject.cpp index 365c821..ead9c6b 100644 --- a/inject/src/main/cpp/inject.cpp +++ b/inject/src/main/cpp/inject.cpp @@ -15,7 +15,7 @@ static nlohmann::json json; static bool spoofProps = true, spoofProvider = true, spoofSignature = false; static bool DEBUG = false; -static std::string DEVICE_INITIAL_SDK_INT, SECURITY_PATCH, BUILD_ID; +static std::string DEVICE_INITIAL_SDK_INT = "21", SECURITY_PATCH, BUILD_ID; typedef void (*T_Callback)(void *, const char *, const char *, uint32_t); @@ -215,11 +215,10 @@ static void injectDex() { auto dexClClass = env->FindClass("dalvik/system/PathClassLoader"); auto dexClInit = env->GetMethodID( dexClClass, "", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)V"); - auto str1 = env->NewStringUTF((dir + "/classes.dex").c_str()); - auto str2 = env->NewStringUTF(dir.c_str()); + "(Ljava/lang/String;Ljava/lang/ClassLoader;)V"); + auto classesJar = env->NewStringUTF((dir + "/classes.dex").c_str()); auto dexCl = - env->NewObject(dexClClass, dexClInit, str1, str2, systemClassLoader); + env->NewObject(dexClClass, dexClInit, classesJar, systemClassLoader); if (env->ExceptionCheck()) { env->ExceptionDescribe(); @@ -257,8 +256,7 @@ static void injectDex() { env->DeleteLocalRef(entryClassObj); env->DeleteLocalRef(jsonStr); env->DeleteLocalRef(dexCl); - env->DeleteLocalRef(str1); - env->DeleteLocalRef(str2); + env->DeleteLocalRef(classesJar); env->DeleteLocalRef(dexClClass); env->DeleteLocalRef(clClass); @@ -266,8 +264,7 @@ static void injectDex() { } extern "C" [[gnu::visibility("default"), maybe_unused]] bool -init(JavaVM *vm, const std::string &gmsDir) { - bool close = true; +init(JavaVM *vm, const std::string &gmsDir, bool trickyStore, bool testSignedRom) { if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { LOGE("[INJECT] JNI_ERR!"); @@ -283,20 +280,28 @@ init(JavaVM *vm, const std::string &gmsDir) { parseJSON(); + if (trickyStore) { + spoofProvider = false; + spoofSignature = false; + spoofProps = false; + } + + if (testSignedRom) { + spoofProvider = true; + spoofSignature = true; + } + UpdateBuildFields(); if (spoofProvider || spoofSignature) { injectDex(); } else { - LOGD("[INJECT] Dex file won't be injected due spoofProvider and " - "spoofSignature are false"); + LOGD("[INJECT] Dex file won't be injected due spoofProvider and spoofSignature are false"); } if (spoofProps) { - close = !doHook(); + return !doHook(); } - LOGD("[INJECT] Done!"); - - return close; + return true; } \ No newline at end of file diff --git a/module/classes.jar b/module/classes.jar deleted file mode 100644 index c1bd6c7..0000000 Binary files a/module/classes.jar and /dev/null differ diff --git a/module/module.prop b/module/module.prop index eb7900e..517f17b 100644 --- a/module/module.prop +++ b/module/module.prop @@ -1,7 +1,6 @@ id=playintegrityfix -name=Play Integrity Fix -version=v18.9 -versionCode=18900 +name=Play Integrity Fix [INJECT] +version=v3-inject +versionCode=3 author=chiteroman description=Universal modular fix for Play Integrity (and SafetyNet) on devices running Android 8-15 -updateJson=https://raw.githubusercontent.com/chiteroman/PlayIntegrityFix/main/update.json diff --git a/update.json b/update.json deleted file mode 100644 index d6a9060..0000000 --- a/update.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "version": "v18.9", - "versionCode": 18900, - "zipUrl": "https://github.com/chiteroman/PlayIntegrityFix/releases/download/v18.9/PlayIntegrityFix_v18.9.zip", - "changelog": "https://raw.githubusercontent.com/chiteroman/PlayIntegrityFix/main/changelog.md" -} \ No newline at end of file diff --git a/zygisk/build.gradle.kts b/zygisk/build.gradle.kts index e539e56..d7dc0c1 100644 --- a/zygisk/build.gradle.kts +++ b/zygisk/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - alias(libs.plugins.android.library) + alias(libs.plugins.android.application) } android { @@ -53,9 +53,7 @@ android { release { isMinifyEnabled = true multiDexEnabled = false - proguardFiles( - getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" - ) + proguardFiles += file("proguard-rules.pro") } } diff --git a/zygisk/src/main/cpp/CMakeLists.txt b/zygisk/src/main/cpp/CMakeLists.txt index 70acfc1..d86e658 100644 --- a/zygisk/src/main/cpp/CMakeLists.txt +++ b/zygisk/src/main/cpp/CMakeLists.txt @@ -9,7 +9,3 @@ find_package(cxx REQUIRED CONFIG) link_libraries(cxx::cxx) add_library(zygisk SHARED zygisk.cpp) - -add_subdirectory(xdl) - -target_link_libraries(zygisk PRIVATE xdl) diff --git a/zygisk/src/main/cpp/xdl/CMakeLists.txt b/zygisk/src/main/cpp/xdl/CMakeLists.txt deleted file mode 100644 index da2f351..0000000 --- a/zygisk/src/main/cpp/xdl/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -cmake_minimum_required(VERSION 3.22.1) -project(xdl) - -file(GLOB XDL_SRC *.c) -add_library(xdl STATIC ${XDL_SRC}) -target_compile_features(xdl PRIVATE c_std_17) -target_compile_options(xdl PRIVATE -std=c17) -target_include_directories(xdl PUBLIC include .) -#target_link_libraries(xdl log) - -if (USEASAN) - target_compile_options(xdl PRIVATE -fsanitize=address -fno-omit-frame-pointer) - target_link_options(xdl PRIVATE -fsanitize=address) -else () - target_compile_options(xdl PRIVATE -Oz -ffunction-sections -fdata-sections) - target_link_options(xdl PRIVATE -Oz -Wl,--exclude-libs,ALL -Wl,--gc-sections -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/xdl.map.txt) -endif () - -if ((${ANDROID_ABI} STREQUAL "arm64-v8a") OR (${ANDROID_ABI} STREQUAL "x86_64")) - target_link_options(xdl PRIVATE "-Wl,-z,max-page-size=16384") -endif () diff --git a/zygisk/src/main/cpp/xdl/include/xdl.h b/zygisk/src/main/cpp/xdl/include/xdl.h deleted file mode 100644 index 80d77a2..0000000 --- a/zygisk/src/main/cpp/xdl/include/xdl.h +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) 2020-2024 HexHacking Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -// Created by caikelun on 2020-10-04. - -// -// xDL version: 2.2.0 -// -// xDL is an enhanced implementation of the Android DL series functions. -// For more information, documentation, and the latest version please check: -// https://github.com/hexhacking/xDL -// - -#ifndef IO_GITHUB_HEXHACKING_XDL -#define IO_GITHUB_HEXHACKING_XDL - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - // same as Dl_info: - const char *dli_fname; // Pathname of shared object that contains address. - void *dli_fbase; // Address at which shared object is loaded. - const char *dli_sname; // Name of nearest symbol with address lower than addr. - void *dli_saddr; // Exact address of symbol named in dli_sname. - // added by xDL: - size_t dli_ssize; // Symbol size of nearest symbol with address lower than addr. - const ElfW(Phdr) *dlpi_phdr; // Pointer to array of ELF program headers for this object. - size_t dlpi_phnum; // Number of items in dlpi_phdr. -} xdl_info_t; - -// -// Default value for flags in xdl_open(), xdl_addr4(), and xdl_iterate_phdr(). -// -#define XDL_DEFAULT 0x00 - -// -// Enhanced dlopen() / dlclose() / dlsym(). -// -#define XDL_TRY_FORCE_LOAD 0x01 -#define XDL_ALWAYS_FORCE_LOAD 0x02 -void *xdl_open(const char *filename, int flags); -void *xdl_open2(struct dl_phdr_info *info); -void *xdl_close(void *handle); -void *xdl_sym(void *handle, const char *symbol, size_t *symbol_size); -void *xdl_dsym(void *handle, const char *symbol, size_t *symbol_size); - -// -// Enhanced dladdr(). -// -#define XDL_NON_SYM 0x01 -int xdl_addr(void *addr, xdl_info_t *info, void **cache); -int xdl_addr4(void *addr, xdl_info_t *info, void **cache, int flags); -void xdl_addr_clean(void **cache); - -// -// Enhanced dl_iterate_phdr(). -// -#define XDL_FULL_PATHNAME 0x01 -int xdl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *), void *data, int flags); - -// -// Custom dlinfo(). -// -#define XDL_DI_DLINFO 1 // type of info: xdl_info_t -int xdl_info(void *handle, int request, void *info); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/zygisk/src/main/cpp/xdl/xdl.c b/zygisk/src/main/cpp/xdl/xdl.c deleted file mode 100644 index 14031c2..0000000 --- a/zygisk/src/main/cpp/xdl/xdl.c +++ /dev/null @@ -1,1014 +0,0 @@ -// Copyright (c) 2020-2024 HexHacking Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -// Created by caikelun on 2020-10-04. - -#include "xdl.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "xdl_iterate.h" -#include "xdl_linker.h" -#include "xdl_lzma.h" -#include "xdl_util.h" - -#ifndef STT_GNU_IFUNC -#define STT_GNU_IFUNC 10 -#endif - -#ifndef __LP64__ -#define XDL_LIB_PATH "/system/lib" -#else -#define XDL_LIB_PATH "/system/lib64" -#endif - -#define XDL_DYNSYM_IS_EXPORT_SYM(shndx) (SHN_UNDEF != (shndx)) -#define XDL_SYMTAB_IS_EXPORT_SYM(shndx) \ - (SHN_UNDEF != (shndx) && !((shndx) >= SHN_LORESERVE && (shndx) <= SHN_HIRESERVE)) - -extern __attribute((weak)) unsigned long int getauxval(unsigned long int); - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" - -typedef struct xdl { - char *pathname; - uintptr_t load_bias; - const ElfW(Phdr) *dlpi_phdr; - ElfW(Half) dlpi_phnum; - - struct xdl *next; // to next xdl obj for cache in xdl_addr() - void *linker_handle; // hold handle returned by xdl_linker_force_dlopen() - - // - // (1) for searching symbols from .dynsym - // - - bool dynsym_try_load; - ElfW(Sym) *dynsym; // .dynsym - const char *dynstr; // .dynstr - - // .hash (SYSV hash for .dynstr) - struct { - const uint32_t *buckets; - uint32_t buckets_cnt; - const uint32_t *chains; - uint32_t chains_cnt; - } sysv_hash; - - // .gnu.hash (GNU hash for .dynstr) - struct { - const uint32_t *buckets; - uint32_t buckets_cnt; - const uint32_t *chains; - uint32_t symoffset; - const ElfW(Addr) *bloom; - uint32_t bloom_cnt; - uint32_t bloom_shift; - } gnu_hash; - - // - // (2) for searching symbols from .symtab - // - - bool symtab_try_load; - uintptr_t base; - - ElfW(Sym) *symtab; // .symtab - size_t symtab_cnt; - char *strtab; // .strtab - size_t strtab_sz; -} xdl_t; - -#pragma clang diagnostic pop - -static ElfW(Sym) *xdl_sym_by_addr(void *handle, void *addr); -static ElfW(Sym) *xdl_dsym_by_addr(void *handle, void *addr); - -// load from memory -static int xdl_dynsym_load(xdl_t *self) { - // find the dynamic segment - ElfW(Dyn) *dynamic = NULL; - for (size_t i = 0; i < self->dlpi_phnum; i++) { - const ElfW(Phdr) *phdr = &(self->dlpi_phdr[i]); - if (PT_DYNAMIC == phdr->p_type) { - dynamic = (ElfW(Dyn) *)(self->load_bias + phdr->p_vaddr); - break; - } - } - if (NULL == dynamic) return -1; - - // iterate the dynamic segment - for (ElfW(Dyn) *entry = dynamic; entry && entry->d_tag != DT_NULL; entry++) { - switch (entry->d_tag) { - case DT_SYMTAB: //.dynsym - self->dynsym = (ElfW(Sym) *)(self->load_bias + entry->d_un.d_ptr); - break; - case DT_STRTAB: //.dynstr - self->dynstr = (const char *)(self->load_bias + entry->d_un.d_ptr); - break; - case DT_HASH: //.hash - self->sysv_hash.buckets_cnt = ((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[0]; - self->sysv_hash.chains_cnt = ((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[1]; - self->sysv_hash.buckets = &(((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[2]); - self->sysv_hash.chains = &(self->sysv_hash.buckets[self->sysv_hash.buckets_cnt]); - break; - case DT_GNU_HASH: //.gnu.hash - self->gnu_hash.buckets_cnt = ((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[0]; - self->gnu_hash.symoffset = ((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[1]; - self->gnu_hash.bloom_cnt = ((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[2]; - self->gnu_hash.bloom_shift = ((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[3]; - self->gnu_hash.bloom = (const ElfW(Addr) *)(self->load_bias + entry->d_un.d_ptr + 16); - self->gnu_hash.buckets = (const uint32_t *)(&(self->gnu_hash.bloom[self->gnu_hash.bloom_cnt])); - self->gnu_hash.chains = (const uint32_t *)(&(self->gnu_hash.buckets[self->gnu_hash.buckets_cnt])); - break; - default: - break; - } - } - - if (NULL == self->dynsym || NULL == self->dynstr || - (0 == self->sysv_hash.buckets_cnt && 0 == self->gnu_hash.buckets_cnt)) { - self->dynsym = NULL; - self->dynstr = NULL; - self->sysv_hash.buckets_cnt = 0; - self->gnu_hash.buckets_cnt = 0; - return -1; - } - - return 0; -} - -static void *xdl_read_file_to_heap(int file_fd, size_t file_sz, size_t data_offset, size_t data_len) { - if (0 == data_len) return NULL; - if (data_offset >= file_sz) return NULL; - if (data_offset + data_len > file_sz) return NULL; - - if (data_offset != (size_t)lseek(file_fd, (off_t)data_offset, SEEK_SET)) return NULL; - - void *data = malloc(data_len); - if (NULL == data) return NULL; - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wgnu-statement-expression" - if ((ssize_t)data_len != XDL_UTIL_TEMP_FAILURE_RETRY(read(file_fd, data, data_len))) -#pragma clang diagnostic pop - { - free(data); - return NULL; - } - - return data; -} - -static void *xdl_read_file_to_heap_by_section(int file_fd, size_t file_sz, ElfW(Shdr) *shdr) { - return xdl_read_file_to_heap(file_fd, file_sz, (size_t)shdr->sh_offset, shdr->sh_size); -} - -static void *xdl_read_memory_to_heap(void *mem, size_t mem_sz, size_t data_offset, size_t data_len) { - if (0 == data_len) return NULL; - if (data_offset >= mem_sz) return NULL; - if (data_offset + data_len > mem_sz) return NULL; - - void *data = malloc(data_len); - if (NULL == data) return NULL; - - memcpy(data, (void *)((uintptr_t)mem + data_offset), data_len); - return data; -} - -static void *xdl_read_memory_to_heap_by_section(void *mem, size_t mem_sz, ElfW(Shdr) *shdr) { - return xdl_read_memory_to_heap(mem, mem_sz, (size_t)shdr->sh_offset, shdr->sh_size); -} - -static void *xdl_get_memory(void *mem, size_t mem_sz, size_t data_offset, size_t data_len) { - if (0 == data_len) return NULL; - if (data_offset >= mem_sz) return NULL; - if (data_offset + data_len > mem_sz) return NULL; - - return (void *)((uintptr_t)mem + data_offset); -} - -static void *xdl_get_memory_by_section(void *mem, size_t mem_sz, ElfW(Shdr) *shdr) { - return xdl_get_memory(mem, mem_sz, (size_t)shdr->sh_offset, shdr->sh_size); -} - -// load from disk and memory -static int xdl_symtab_load_from_debugdata(xdl_t *self, int file_fd, size_t file_sz, - ElfW(Shdr) *shdr_debugdata) { - void *debugdata = NULL; - ElfW(Shdr) *shdrs = NULL; - int r = -1; - - // get zipped .gnu_debugdata - uint8_t *debugdata_zip = (uint8_t *)xdl_read_file_to_heap_by_section(file_fd, file_sz, shdr_debugdata); - if (NULL == debugdata_zip) return -1; - - // get unzipped .gnu_debugdata - size_t debugdata_sz; - if (0 != xdl_lzma_decompress(debugdata_zip, shdr_debugdata->sh_size, (uint8_t **)&debugdata, &debugdata_sz)) - goto end; - - // get ELF header - ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)debugdata; - if (0 == ehdr->e_shnum || ehdr->e_shentsize != sizeof(ElfW(Shdr))) goto end; - - // get section headers - shdrs = (ElfW(Shdr) *)xdl_read_memory_to_heap(debugdata, debugdata_sz, (size_t)ehdr->e_shoff, - ehdr->e_shentsize * ehdr->e_shnum); - if (NULL == shdrs) goto end; - - // get .shstrtab - if (SHN_UNDEF == ehdr->e_shstrndx || ehdr->e_shstrndx >= ehdr->e_shnum) goto end; - char *shstrtab = (char *)xdl_get_memory_by_section(debugdata, debugdata_sz, shdrs + ehdr->e_shstrndx); - if (NULL == shstrtab) goto end; - - // find .symtab & .strtab - for (ElfW(Shdr) *shdr = shdrs; shdr < shdrs + ehdr->e_shnum; shdr++) { - char *shdr_name = shstrtab + shdr->sh_name; - - if (SHT_SYMTAB == shdr->sh_type && 0 == strcmp(".symtab", shdr_name)) { - // get & check associated .strtab section - if (shdr->sh_link >= ehdr->e_shnum) continue; - ElfW(Shdr) *shdr_strtab = shdrs + shdr->sh_link; - if (SHT_STRTAB != shdr_strtab->sh_type) continue; - - // get .symtab & .strtab - ElfW(Sym) *symtab = (ElfW(Sym) *)xdl_read_memory_to_heap_by_section(debugdata, debugdata_sz, shdr); - if (NULL == symtab) continue; - char *strtab = (char *)xdl_read_memory_to_heap_by_section(debugdata, debugdata_sz, shdr_strtab); - if (NULL == strtab) { - free(symtab); - continue; - } - - // OK - self->symtab = symtab; - self->symtab_cnt = shdr->sh_size / shdr->sh_entsize; - self->strtab = strtab; - self->strtab_sz = shdr_strtab->sh_size; - r = 0; - break; - } - } - -end: - free(debugdata_zip); - if (NULL != debugdata) free(debugdata); - if (NULL != shdrs) free(shdrs); - return r; -} - -// load from disk and memory -static int xdl_symtab_load(xdl_t *self) { - if ('[' == self->pathname[0]) return -1; - - int r = -1; - ElfW(Shdr) *shdrs = NULL; - char *shstrtab = NULL; - - // get base address - uintptr_t vaddr_min = UINTPTR_MAX; - for (size_t i = 0; i < self->dlpi_phnum; i++) { - const ElfW(Phdr) *phdr = &(self->dlpi_phdr[i]); - if (PT_LOAD == phdr->p_type) { - if (vaddr_min > phdr->p_vaddr) vaddr_min = phdr->p_vaddr; - } - } - if (UINTPTR_MAX == vaddr_min) return -1; - self->base = self->load_bias + vaddr_min; - - // open file - int flags = O_RDONLY | O_CLOEXEC; - int file_fd; - if ('/' == self->pathname[0]) { - file_fd = open(self->pathname, flags); - } else { - char full_pathname[1024]; - // try the fast method - snprintf(full_pathname, sizeof(full_pathname), "%s/%s", XDL_LIB_PATH, self->pathname); - file_fd = open(full_pathname, flags); - if (file_fd < 0) { - // try the slow method - if (0 != xdl_iterate_get_full_pathname(self->base, full_pathname, sizeof(full_pathname))) return -1; - file_fd = open(full_pathname, flags); - } - } - if (file_fd < 0) return -1; - struct stat st; - if (0 != fstat(file_fd, &st)) goto end; - size_t file_sz = (size_t)st.st_size; - - // get ELF header - ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)self->base; - if (0 == ehdr->e_shnum || ehdr->e_shentsize != sizeof(ElfW(Shdr))) goto end; - - // get section headers - shdrs = (ElfW(Shdr) *)xdl_read_file_to_heap(file_fd, file_sz, (size_t)ehdr->e_shoff, - ehdr->e_shentsize * ehdr->e_shnum); - if (NULL == shdrs) goto end; - - // get .shstrtab - if (SHN_UNDEF == ehdr->e_shstrndx || ehdr->e_shstrndx >= ehdr->e_shnum) goto end; - shstrtab = (char *)xdl_read_file_to_heap_by_section(file_fd, file_sz, shdrs + ehdr->e_shstrndx); - if (NULL == shstrtab) goto end; - - // find .symtab & .strtab - for (ElfW(Shdr) *shdr = shdrs; shdr < shdrs + ehdr->e_shnum; shdr++) { - char *shdr_name = shstrtab + shdr->sh_name; - - if (SHT_SYMTAB == shdr->sh_type && 0 == strcmp(".symtab", shdr_name)) { - // get & check associated .strtab section - if (shdr->sh_link >= ehdr->e_shnum) continue; - ElfW(Shdr) *shdr_strtab = shdrs + shdr->sh_link; - if (SHT_STRTAB != shdr_strtab->sh_type) continue; - - // get .symtab & .strtab - ElfW(Sym) *symtab = (ElfW(Sym) *)xdl_read_file_to_heap_by_section(file_fd, file_sz, shdr); - if (NULL == symtab) continue; - char *strtab = (char *)xdl_read_file_to_heap_by_section(file_fd, file_sz, shdr_strtab); - if (NULL == strtab) { - free(symtab); - continue; - } - - // OK - self->symtab = symtab; - self->symtab_cnt = shdr->sh_size / shdr->sh_entsize; - self->strtab = strtab; - self->strtab_sz = shdr_strtab->sh_size; - r = 0; - break; - } else if (SHT_PROGBITS == shdr->sh_type && 0 == strcmp(".gnu_debugdata", shdr_name)) { - if (0 == xdl_symtab_load_from_debugdata(self, file_fd, file_sz, shdr)) { - // OK - r = 0; - break; - } - } - } - -end: - close(file_fd); - if (NULL != shdrs) free(shdrs); - if (NULL != shstrtab) free(shstrtab); - return r; -} - -static xdl_t *xdl_find_from_auxv(unsigned long type, const char *pathname) { - if (NULL == getauxval) return NULL; // API level < 18 - - uintptr_t val = (uintptr_t)getauxval(type); - if (0 == val) return NULL; - - // get base - uintptr_t base = (AT_PHDR == type ? (val & (~0xffful)) : val); - if (0 != memcmp((void *)base, ELFMAG, SELFMAG)) return NULL; - - // ELF info - ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)base; - const ElfW(Phdr) *dlpi_phdr = (const ElfW(Phdr) *)(base + ehdr->e_phoff); - ElfW(Half) dlpi_phnum = ehdr->e_phnum; - - // get bias - uintptr_t min_vaddr = UINTPTR_MAX; - for (size_t i = 0; i < dlpi_phnum; i++) { - const ElfW(Phdr) *phdr = &(dlpi_phdr[i]); - if (PT_LOAD == phdr->p_type) { - if (min_vaddr > phdr->p_vaddr) min_vaddr = phdr->p_vaddr; - } - } - if (UINTPTR_MAX == min_vaddr || base < min_vaddr) return NULL; - uintptr_t load_bias = base - min_vaddr; - - // create xDL object - xdl_t *self; - if (NULL == (self = calloc(1, sizeof(xdl_t)))) return NULL; - if (NULL == (self->pathname = strdup(pathname))) { - free(self); - return NULL; - } - self->load_bias = load_bias; - self->dlpi_phdr = dlpi_phdr; - self->dlpi_phnum = dlpi_phnum; - self->dynsym_try_load = false; - self->symtab_try_load = false; - return self; -} - -static int xdl_find_iterate_cb(struct dl_phdr_info *info, size_t size, void *arg) { - (void)size; - - uintptr_t *pkg = (uintptr_t *)arg; - xdl_t **self = (xdl_t **)*pkg++; - const char *filename = (const char *)*pkg; - - // check load_bias - if (0 == info->dlpi_addr || NULL == info->dlpi_name) return 0; - - // check pathname - if ('[' == filename[0]) { - if (0 != strcmp(info->dlpi_name, filename)) return 0; - } else if ('/' == filename[0]) { - if ('/' == info->dlpi_name[0]) { - if (0 != strcmp(info->dlpi_name, filename)) return 0; - } else { - if (!xdl_util_ends_with(filename, info->dlpi_name)) return 0; - } - } else { - if ('/' == info->dlpi_name[0]) { - if (!xdl_util_ends_with(info->dlpi_name, filename)) return 0; - } else { - if (0 != strcmp(info->dlpi_name, filename)) return 0; - } - } - - // found the target ELF - if (NULL == ((*self) = calloc(1, sizeof(xdl_t)))) return 1; // return failed - if (NULL == ((*self)->pathname = strdup((const char *)info->dlpi_name))) { - free(*self); - *self = NULL; - return 1; // return failed - } - (*self)->load_bias = info->dlpi_addr; - (*self)->dlpi_phdr = info->dlpi_phdr; - (*self)->dlpi_phnum = info->dlpi_phnum; - (*self)->dynsym_try_load = false; - (*self)->symtab_try_load = false; - return 1; // return OK -} - -static xdl_t *xdl_find(const char *filename) { - // from auxv (linker, vDSO) - xdl_t *self = NULL; - if (xdl_util_ends_with(filename, XDL_UTIL_LINKER_BASENAME)) - self = xdl_find_from_auxv(AT_BASE, XDL_UTIL_LINKER_PATHNAME); - else if (xdl_util_ends_with(filename, XDL_UTIL_VDSO_BASENAME)) - self = xdl_find_from_auxv(AT_SYSINFO_EHDR, XDL_UTIL_VDSO_BASENAME); - - // from auxv (app_process) - const char *basename, *pathname; -#if (defined(__arm__) || defined(__i386__)) && __ANDROID_API__ < __ANDROID_API_L__ - if (xdl_util_get_api_level() < __ANDROID_API_L__) { - basename = XDL_UTIL_APP_PROCESS_BASENAME_K; - pathname = XDL_UTIL_APP_PROCESS_PATHNAME_K; - } else -#endif - { - basename = XDL_UTIL_APP_PROCESS_BASENAME; - pathname = XDL_UTIL_APP_PROCESS_PATHNAME; - } - if (xdl_util_ends_with(filename, basename)) self = xdl_find_from_auxv(AT_PHDR, pathname); - - if (NULL != self) return self; - - // from dl_iterate_phdr - uintptr_t pkg[2] = {(uintptr_t)&self, (uintptr_t)filename}; - xdl_iterate_phdr(xdl_find_iterate_cb, pkg, XDL_DEFAULT); - return self; -} - -static void *xdl_open_always_force(const char *filename) { - // always force dlopen() - void *linker_handle = xdl_linker_force_dlopen(filename); - if (NULL == linker_handle) return NULL; - - // find - xdl_t *self = xdl_find(filename); - if (NULL == self) - dlclose(linker_handle); - else - self->linker_handle = linker_handle; - - return (void *)self; -} - -static void *xdl_open_try_force(const char *filename) { - // find - xdl_t *self = xdl_find(filename); - if (NULL != self) return (void *)self; - - // try force dlopen() - void *linker_handle = xdl_linker_force_dlopen(filename); - if (NULL == linker_handle) return NULL; - - // find again - self = xdl_find(filename); - if (NULL == self) - dlclose(linker_handle); - else - self->linker_handle = linker_handle; - - return (void *)self; -} - -void *xdl_open(const char *filename, int flags) { - if (NULL == filename) return NULL; - - if (flags & XDL_ALWAYS_FORCE_LOAD) - return xdl_open_always_force(filename); - else if (flags & XDL_TRY_FORCE_LOAD) - return xdl_open_try_force(filename); - else - return xdl_find(filename); -} - -void *xdl_open2(struct dl_phdr_info *info) { - xdl_t *self = calloc(1, sizeof(xdl_t)); - if (NULL == self) return NULL; - if (NULL == (self->pathname = strdup((const char *)info->dlpi_name))) { - free(self); - return NULL; - } - self->load_bias = info->dlpi_addr; - self->dlpi_phdr = info->dlpi_phdr; - self->dlpi_phnum = info->dlpi_phnum; - self->dynsym_try_load = false; - self->symtab_try_load = false; - return self; -} - -void *xdl_close(void *handle) { - if (NULL == handle) return NULL; - - xdl_t *self = (xdl_t *)handle; - if (NULL != self->pathname) free(self->pathname); - if (NULL != self->symtab) free(self->symtab); - if (NULL != self->strtab) free(self->strtab); - - void *linker_handle = self->linker_handle; - free(self); - return linker_handle; -} - -static uint32_t xdl_sysv_hash(const uint8_t *name) { - uint32_t h = 0, g; - - while (*name) { - h = (h << 4) + *name++; - g = h & 0xf0000000; - h ^= g; - h ^= g >> 24; - } - return h; -} - -static uint32_t xdl_gnu_hash(const uint8_t *name) { - uint32_t h = 5381; - - while (*name) { - h += (h << 5) + *name++; - } - return h; -} - -static ElfW(Sym) *xdl_dynsym_find_symbol_use_sysv_hash(xdl_t *self, const char *sym_name) { - uint32_t hash = xdl_sysv_hash((const uint8_t *)sym_name); - - for (uint32_t i = self->sysv_hash.buckets[hash % self->sysv_hash.buckets_cnt]; 0 != i; - i = self->sysv_hash.chains[i]) { - ElfW(Sym) *sym = self->dynsym + i; - if (0 != strcmp(self->dynstr + sym->st_name, sym_name)) continue; - return sym; - } - - return NULL; -} - -static ElfW(Sym) *xdl_dynsym_find_symbol_use_gnu_hash(xdl_t *self, const char *sym_name) { - uint32_t hash = xdl_gnu_hash((const uint8_t *)sym_name); - - static uint32_t elfclass_bits = sizeof(ElfW(Addr)) * 8; - size_t word = self->gnu_hash.bloom[(hash / elfclass_bits) % self->gnu_hash.bloom_cnt]; - size_t mask = 0 | (size_t)1 << (hash % elfclass_bits) | - (size_t)1 << ((hash >> self->gnu_hash.bloom_shift) % elfclass_bits); - - // if at least one bit is not set, this symbol is surely missing - if ((word & mask) != mask) return NULL; - - // ignore STN_UNDEF - uint32_t i = self->gnu_hash.buckets[hash % self->gnu_hash.buckets_cnt]; - if (i < self->gnu_hash.symoffset) return NULL; - - // loop through the chain - while (1) { - ElfW(Sym) *sym = self->dynsym + i; - uint32_t sym_hash = self->gnu_hash.chains[i - self->gnu_hash.symoffset]; - - if ((hash | (uint32_t)1) == (sym_hash | (uint32_t)1)) { - if (0 == strcmp(self->dynstr + sym->st_name, sym_name)) { - return sym; - } - } - - // chain ends with an element with the lowest bit set to 1 - if (sym_hash & (uint32_t)1) break; - - i++; - } - - return NULL; -} - -typedef struct { - unsigned long size; /** Set to sizeof(__ifunc_arg_t). */ - unsigned long hwcap; /** Set to getauxval(AT_HWCAP). */ - unsigned long hwcap2; /** Set to getauxval(AT_HWCAP2). */ -} xdl_ifunc_arg_t; - -#if defined(__aarch64__) -#define XDL_IFUNC_ARG_HWCAP (1ULL << 62) -#endif - -static void *xdl_resolve_symbol_address(xdl_t *self, ElfW(Sym) *sym, size_t *symbol_size) { - if (ELF_ST_TYPE(sym->st_info) == STT_TLS) { - return NULL; - } else if (ELF_ST_TYPE(sym->st_info) == STT_GNU_IFUNC) { - void *sym_addr = (void *)(self->load_bias + sym->st_value); - void *real_sym_addr = NULL; - if (xdl_util_get_api_level() < __ANDROID_API_R__) { - // Android [4.x, 10] - typedef void *(*ifunc_resolver_t)(void); - real_sym_addr = ((ifunc_resolver_t)sym_addr)(); - } else { - // Android [11, ...) -#if defined(__aarch64__) - if (NULL == getauxval) return NULL; - typedef void *(*ifunc_resolver_t)(uint64_t, xdl_ifunc_arg_t *); - static xdl_ifunc_arg_t arg; - static bool initialized = false; - if (!initialized) { - arg.size = sizeof(xdl_ifunc_arg_t); - arg.hwcap = getauxval(AT_HWCAP); - arg.hwcap2 = getauxval(AT_HWCAP2); - initialized = true; - } - real_sym_addr = ((ifunc_resolver_t)sym_addr)(arg.hwcap | XDL_IFUNC_ARG_HWCAP, &arg); -#elif defined(__arm__) - if (NULL == getauxval) return NULL; - typedef void *(*ifunc_resolver_t)(unsigned long); - static unsigned long hwcap; - static bool initialized = false; - if (!initialized) { - hwcap = getauxval(AT_HWCAP); - initialized = true; - } - real_sym_addr = ((ifunc_resolver_t)sym_addr)(hwcap); -#else - typedef void *(*ifunc_resolver_t)(void); - real_sym_addr = ((ifunc_resolver_t)sym_addr)(); -#endif - } - if (NULL != symbol_size && NULL != real_sym_addr) { - ElfW(Sym) *real_sym = xdl_sym_by_addr(self, real_sym_addr); - if (NULL == real_sym) real_sym = xdl_dsym_by_addr(self, real_sym_addr); - if (NULL != real_sym) *symbol_size = real_sym->st_size; - } - return real_sym_addr; - } else { - if (NULL != symbol_size) *symbol_size = sym->st_size; - return (void *)(self->load_bias + sym->st_value); - } -} - -void *xdl_sym(void *handle, const char *symbol, size_t *symbol_size) { - if (NULL == handle || NULL == symbol) return NULL; - if (NULL != symbol_size) *symbol_size = 0; - - xdl_t *self = (xdl_t *)handle; - - // load .dynsym only once - if (!self->dynsym_try_load) { - self->dynsym_try_load = true; - if (0 != xdl_dynsym_load(self)) return NULL; - } - - // find symbol - if (NULL == self->dynsym) return NULL; - ElfW(Sym) *sym = NULL; - if (self->gnu_hash.buckets_cnt > 0) { - // use GNU hash (.gnu.hash -> .dynsym -> .dynstr), O(x) + O(1) + O(1) - sym = xdl_dynsym_find_symbol_use_gnu_hash(self, symbol); - } - if (NULL == sym && self->sysv_hash.buckets_cnt > 0) { - // use SYSV hash (.hash -> .dynsym -> .dynstr), O(x) + O(1) + O(1) - sym = xdl_dynsym_find_symbol_use_sysv_hash(self, symbol); - } - if (NULL == sym || !XDL_DYNSYM_IS_EXPORT_SYM(sym->st_shndx)) return NULL; - - return xdl_resolve_symbol_address(self, sym, symbol_size); -} - -// clang-format off -/* - * For internal symbols in .symtab, LLVM may add some suffixes (for example for thinLTO). - * The format of the suffix is: ".xxxx.[hash]". LLVM may add multiple suffixes at once. - * The symbol name after removing these all suffixes is called canonical name. - * - * Because the hash part in the suffix may change when recompiled, so here we only match - * the canonical name. - * - * IN ADDITION: According to C/C++ syntax, it is illegal for a function name to contain - * dot character('.'), either in the middle or at the end. - * - * samples: - * - * symbol name in .symtab lookup is match - * ---------------------- ---------------- -------- - * abcd abc N - * abcd abcde N - * abcd abcd Y - * abcd.llvm.10190306339727611508 abc N - * abcd.llvm.10190306339727611508 abcd Y - * abcd.llvm.10190306339727611508 abcd. N - * abcd.llvm.10190306339727611508 abcd.llvm Y - * abcd.llvm.10190306339727611508 abcd.llvm. N - * abcd.__uniq.513291356003753 abcd.__uniq.51329 N - * abcd.__uniq.513291356003753 abcd.__uniq.513291356003753 Y - */ -// clang-format on -static inline bool xdl_dsym_is_match(const char *str, const char *sym, size_t sym_len) { - size_t str_len = strlen(str); - if (0 == str_len) return false; - - if (str_len < sym_len) { - return false; - } else { - bool sym_len_match = (0 == memcmp(str, sym, sym_len)); - if (str_len == sym_len) - return sym_len_match; - else // str_len > sym_len - return sym_len_match && (str[sym_len] == '.' || str[sym_len] == '$'); - } -} - -void *xdl_dsym(void *handle, const char *symbol, size_t *symbol_size) { - if (NULL == handle || NULL == symbol) return NULL; - if (NULL != symbol_size) *symbol_size = 0; - - xdl_t *self = (xdl_t *)handle; - - // load .symtab only once - if (!self->symtab_try_load) { - self->symtab_try_load = true; - if (0 != xdl_symtab_load(self)) return NULL; - } - - // find symbol - if (NULL == self->symtab) return NULL; - size_t symbol_len = strlen(symbol); - for (size_t i = 0; i < self->symtab_cnt; i++) { - ElfW(Sym) *sym = self->symtab + i; - - if (!XDL_SYMTAB_IS_EXPORT_SYM(sym->st_shndx)) continue; - // if (0 != strncmp(self->strtab + sym->st_name, symbol, self->strtab_sz - sym->st_name)) continue; - if (!xdl_dsym_is_match(self->strtab + sym->st_name, symbol, symbol_len)) continue; - - if (NULL != symbol_size) *symbol_size = sym->st_size; - return (void *)(self->load_bias + sym->st_value); - } - - return NULL; -} - -static bool xdl_elf_is_match(uintptr_t load_bias, const ElfW(Phdr) *dlpi_phdr, ElfW(Half) dlpi_phnum, - uintptr_t addr) { - if (addr < load_bias) return false; - - uintptr_t vaddr = addr - load_bias; - for (size_t i = 0; i < dlpi_phnum; i++) { - const ElfW(Phdr) *phdr = &(dlpi_phdr[i]); - if (PT_LOAD != phdr->p_type) continue; - - if (phdr->p_vaddr <= vaddr && vaddr < phdr->p_vaddr + phdr->p_memsz) return true; - } - - return false; -} - -static int xdl_open_by_addr_iterate_cb(struct dl_phdr_info *info, size_t size, void *arg) { - (void)size; - - uintptr_t *pkg = (uintptr_t *)arg; - xdl_t **self = (xdl_t **)*pkg++; - uintptr_t addr = *pkg; - - if (0 == info->dlpi_addr || NULL == info->dlpi_name) return 0; // continue - - if (xdl_elf_is_match(info->dlpi_addr, info->dlpi_phdr, info->dlpi_phnum, addr)) { - // found the target ELF - if (NULL == ((*self) = calloc(1, sizeof(xdl_t)))) return 1; // failed - if (NULL == ((*self)->pathname = strdup((const char *)info->dlpi_name))) { - free(*self); - *self = NULL; - return 1; // failed - } - (*self)->load_bias = info->dlpi_addr; - (*self)->dlpi_phdr = info->dlpi_phdr; - (*self)->dlpi_phnum = info->dlpi_phnum; - (*self)->dynsym_try_load = false; - (*self)->symtab_try_load = false; - return 1; // OK - } - - return 0; // continue -} - -static void *xdl_open_by_addr(void *addr) { - if (NULL == addr) return NULL; - - xdl_t *self = NULL; - uintptr_t pkg[2] = {(uintptr_t)&self, (uintptr_t)addr}; - xdl_iterate_phdr(xdl_open_by_addr_iterate_cb, pkg, XDL_DEFAULT); - - return (void *)self; -} - -static bool xdl_sym_is_match(ElfW(Sym) *sym, uintptr_t offset, bool is_symtab) { - if (is_symtab) { - if (!XDL_SYMTAB_IS_EXPORT_SYM(sym->st_shndx)) return false; - } else { - if (!XDL_DYNSYM_IS_EXPORT_SYM(sym->st_shndx)) return false; - } - if (ELF_ST_TYPE(sym->st_info) == STT_TLS) return false; - - // For thumb instructions, "st_value" is an odd number, and the instructions are stored - // in the range: [st_value - 1, st_value - 1 + st_size). - // NOTE: The dladdr() implementation in the Android bionic linker does NOT fix this for - // thumb and is therefore incorrect. - uintptr_t sym_st_value_fixed = sym->st_value; -#if defined(__arm__) && defined(__thumb__) -#define CLEAR_BIT0(addr) ((addr)&0xFFFFFFFE) - sym_st_value_fixed = CLEAR_BIT0(sym->st_value); -#endif - - return offset >= sym_st_value_fixed && offset < sym_st_value_fixed + sym->st_size; -} - -static ElfW(Sym) *xdl_sym_by_addr(void *handle, void *addr) { - xdl_t *self = (xdl_t *)handle; - - // load .dynsym only once - if (!self->dynsym_try_load) { - self->dynsym_try_load = true; - if (0 != xdl_dynsym_load(self)) return NULL; - } - - // find symbol - if (NULL == self->dynsym) return NULL; - uintptr_t offset = (uintptr_t)addr - self->load_bias; - if (self->gnu_hash.buckets_cnt > 0) { - const uint32_t *chains_all = self->gnu_hash.chains - self->gnu_hash.symoffset; - for (size_t i = 0; i < self->gnu_hash.buckets_cnt; i++) { - uint32_t n = self->gnu_hash.buckets[i]; - if (n < self->gnu_hash.symoffset) continue; - do { - ElfW(Sym) *sym = self->dynsym + n; - if (xdl_sym_is_match(sym, offset, false)) return sym; - } while ((chains_all[n++] & 1) == 0); - } - } else if (self->sysv_hash.chains_cnt > 0) { - for (size_t i = 0; i < self->sysv_hash.chains_cnt; i++) { - ElfW(Sym) *sym = self->dynsym + i; - if (xdl_sym_is_match(sym, offset, false)) return sym; - } - } - - return NULL; -} - -static ElfW(Sym) *xdl_dsym_by_addr(void *handle, void *addr) { - xdl_t *self = (xdl_t *)handle; - - // load .symtab only once - if (!self->symtab_try_load) { - self->symtab_try_load = true; - if (0 != xdl_symtab_load(self)) return NULL; - } - - // find symbol - if (NULL == self->symtab) return NULL; - uintptr_t offset = (uintptr_t)addr - self->load_bias; - for (size_t i = 0; i < self->symtab_cnt; i++) { - ElfW(Sym) *sym = self->symtab + i; - if (xdl_sym_is_match(sym, offset, true)) return sym; - } - - return NULL; -} - -int xdl_addr(void *addr, xdl_info_t *info, void **cache) { - return xdl_addr4(addr, info, cache, XDL_DEFAULT); -} - -int xdl_addr4(void *addr, xdl_info_t *info, void **cache, int flags) { - if (NULL == addr || NULL == info || NULL == cache) return 0; - - memset(info, 0, sizeof(Dl_info)); - - // find handle from cache - xdl_t *handle = NULL; - for (handle = *((xdl_t **)cache); NULL != handle; handle = handle->next) - if (xdl_elf_is_match(handle->load_bias, handle->dlpi_phdr, handle->dlpi_phnum, (uintptr_t)addr)) break; - - // create new handle, save handle to cache - if (NULL == handle) { - handle = (xdl_t *)xdl_open_by_addr(addr); - if (NULL == handle) return 0; - handle->next = *(xdl_t **)cache; - *(xdl_t **)cache = handle; - } - - // we have at least: load_bias, pathname, dlpi_phdr, dlpi_phnum - info->dli_fbase = (void *)handle->load_bias; - info->dli_fname = handle->pathname; - info->dli_sname = NULL; - info->dli_saddr = 0; - info->dli_ssize = 0; - info->dlpi_phdr = handle->dlpi_phdr; - info->dlpi_phnum = (size_t)handle->dlpi_phnum; - - // keep looking for: symbol name, symbol offset, symbol size - if (!(flags & XDL_NON_SYM)) { - ElfW(Sym) *sym; - if (NULL != (sym = xdl_sym_by_addr((void *)handle, addr))) { - info->dli_sname = handle->dynstr + sym->st_name; - info->dli_saddr = (void *)(handle->load_bias + sym->st_value); - info->dli_ssize = sym->st_size; - } else if (NULL != (sym = xdl_dsym_by_addr((void *)handle, addr))) { - info->dli_sname = handle->strtab + sym->st_name; - info->dli_saddr = (void *)(handle->load_bias + sym->st_value); - info->dli_ssize = sym->st_size; - } - } - - return 1; -} - -void xdl_addr_clean(void **cache) { - if (NULL == cache) return; - - xdl_t *handle = *((xdl_t **)cache); - while (NULL != handle) { - xdl_t *tmp = handle; - handle = handle->next; - xdl_close(tmp); - } - *cache = NULL; -} - -int xdl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *), void *data, int flags) { - if (NULL == callback) return 0; - - return xdl_iterate_phdr_impl(callback, data, flags); -} - -int xdl_info(void *handle, int request, void *info) { - if (NULL == handle || XDL_DI_DLINFO != request || NULL == info) return -1; - - xdl_t *self = (xdl_t *)handle; - xdl_info_t *dlinfo = (xdl_info_t *)info; - - dlinfo->dli_fbase = (void *)self->load_bias; - dlinfo->dli_fname = self->pathname; - dlinfo->dli_sname = NULL; - dlinfo->dli_saddr = 0; - dlinfo->dli_ssize = 0; - dlinfo->dlpi_phdr = self->dlpi_phdr; - dlinfo->dlpi_phnum = (size_t)self->dlpi_phnum; - return 0; -} diff --git a/zygisk/src/main/cpp/xdl/xdl.map.txt b/zygisk/src/main/cpp/xdl/xdl.map.txt deleted file mode 100644 index 02558da..0000000 --- a/zygisk/src/main/cpp/xdl/xdl.map.txt +++ /dev/null @@ -1,16 +0,0 @@ -{ - global: - xdl_open; - xdl_open2; - xdl_close; - xdl_sym; - xdl_dsym; - xdl_addr; - xdl_addr4; - xdl_addr_clean; - xdl_iterate_phdr; - xdl_info; - - local: - *; -}; diff --git a/zygisk/src/main/cpp/xdl/xdl_iterate.c b/zygisk/src/main/cpp/xdl/xdl_iterate.c deleted file mode 100644 index 1bcc3f6..0000000 --- a/zygisk/src/main/cpp/xdl/xdl_iterate.c +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright (c) 2020-2024 HexHacking Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -// Created by caikelun on 2020-10-04. - -#include "xdl_iterate.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "xdl.h" -#include "xdl_linker.h" -#include "xdl_util.h" - -/* - * ========================================================================================================= - * API-LEVEL ANDROID-VERSION SOLUTION - * ========================================================================================================= - * 16 4.1 /proc/self/maps - * 17 4.2 /proc/self/maps - * 18 4.3 /proc/self/maps - * 19 4.4 /proc/self/maps - * 20 4.4W /proc/self/maps - * --------------------------------------------------------------------------------------------------------- - * 21 5.0 dl_iterate_phdr() + __dl__ZL10g_dl_mutex + linker/linker64 from getauxval(3) - * 22 5.1 dl_iterate_phdr() + __dl__ZL10g_dl_mutex + linker/linker64 from getauxval(3) - * --------------------------------------------------------------------------------------------------------- - * 23 >= 6.0 dl_iterate_phdr() + linker/linker64 from getauxval(3) - * ========================================================================================================= - */ - -extern __attribute((weak)) int dl_iterate_phdr(int (*)(struct dl_phdr_info *, size_t, void *), void *); -extern __attribute((weak)) unsigned long int getauxval(unsigned long int); - -static uintptr_t xdl_iterate_get_min_vaddr(struct dl_phdr_info *info) { - uintptr_t min_vaddr = UINTPTR_MAX; - for (size_t i = 0; i < info->dlpi_phnum; i++) { - const ElfW(Phdr) *phdr = &(info->dlpi_phdr[i]); - if (PT_LOAD == phdr->p_type) { - if (min_vaddr > phdr->p_vaddr) min_vaddr = phdr->p_vaddr; - } - } - return min_vaddr; -} - -static int xdl_iterate_open_or_rewind_maps(FILE **maps) { - if (NULL == *maps) { - *maps = fopen("/proc/self/maps", "r"); - if (NULL == *maps) return -1; - } else - rewind(*maps); - - return 0; -} - -static int xdl_iterate_get_pathname_from_maps(uintptr_t base, char *buf, size_t buf_len, FILE **maps) { - // open or rewind maps-file - if (0 != xdl_iterate_open_or_rewind_maps(maps)) return -1; // failed - - char line[1024]; - while (fgets(line, sizeof(line), *maps)) { - // check base address - uintptr_t start, end; - if (2 != sscanf(line, "%" SCNxPTR "-%" SCNxPTR " r", &start, &end)) continue; - if (base < start) break; // failed - if (base >= end) continue; - - // get pathname - char *pathname = strchr(line, '/'); - if (NULL == pathname) break; // failed - xdl_util_trim_ending(pathname); - - // found it - strlcpy(buf, pathname, buf_len); - return 0; // OK - } - - return -1; // failed -} - -static int xdl_iterate_by_linker_cb(struct dl_phdr_info *info, size_t size, void *arg) { - uintptr_t *pkg = (uintptr_t *)arg; - xdl_iterate_phdr_cb_t cb = (xdl_iterate_phdr_cb_t)*pkg++; - void *cb_arg = (void *)*pkg++; - FILE **maps = (FILE **)*pkg++; - uintptr_t linker_load_bias = *pkg++; - int flags = (int)*pkg; - - // ignore invalid ELF - if (0 == info->dlpi_addr || NULL == info->dlpi_name || '\0' == info->dlpi_name[0]) return 0; - - // ignore linker if we have returned it already - if (linker_load_bias == info->dlpi_addr) return 0; - - struct dl_phdr_info info_fixed; - info_fixed.dlpi_addr = info->dlpi_addr; - info_fixed.dlpi_name = info->dlpi_name; - info_fixed.dlpi_phdr = info->dlpi_phdr; - info_fixed.dlpi_phnum = info->dlpi_phnum; - info = &info_fixed; - - // fix dlpi_phdr & dlpi_phnum (from memory) - if (NULL == info->dlpi_phdr || 0 == info->dlpi_phnum) { - ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)info->dlpi_addr; - info->dlpi_phdr = (ElfW(Phdr) *)(info->dlpi_addr + ehdr->e_phoff); - info->dlpi_phnum = ehdr->e_phnum; - } - - // fix dlpi_name (from /proc/self/maps) - if ('/' != info->dlpi_name[0] && '[' != info->dlpi_name[0] && (0 != (flags & XDL_FULL_PATHNAME))) { - // get base address - uintptr_t min_vaddr = xdl_iterate_get_min_vaddr(info); - if (UINTPTR_MAX == min_vaddr) return 0; // ignore this ELF - uintptr_t base = (uintptr_t)(info->dlpi_addr + min_vaddr); - - char buf[1024]; - if (0 != xdl_iterate_get_pathname_from_maps(base, buf, sizeof(buf), maps)) return 0; // ignore this ELF - - info->dlpi_name = (const char *)buf; - } - - // callback - return cb(info, size, cb_arg); -} - -static uintptr_t xdl_iterate_get_linker_base(void) { - if (NULL == getauxval) return 0; - - uintptr_t base = (uintptr_t)getauxval(AT_BASE); - if (0 == base) return 0; - if (0 != memcmp((void *)base, ELFMAG, SELFMAG)) return 0; - - return base; -} - -static int xdl_iterate_do_callback(xdl_iterate_phdr_cb_t cb, void *cb_arg, uintptr_t base, - const char *pathname, uintptr_t *load_bias) { - ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)base; - - struct dl_phdr_info info; - info.dlpi_name = pathname; - info.dlpi_phdr = (const ElfW(Phdr) *)(base + ehdr->e_phoff); - info.dlpi_phnum = ehdr->e_phnum; - - // get load bias - uintptr_t min_vaddr = xdl_iterate_get_min_vaddr(&info); - if (UINTPTR_MAX == min_vaddr) return 0; // ignore invalid ELF - info.dlpi_addr = (ElfW(Addr))(base - min_vaddr); - if (NULL != load_bias) *load_bias = info.dlpi_addr; - - return cb(&info, sizeof(struct dl_phdr_info), cb_arg); -} - -static int xdl_iterate_by_linker(xdl_iterate_phdr_cb_t cb, void *cb_arg, int flags) { - if (NULL == dl_iterate_phdr) return 0; - - int api_level = xdl_util_get_api_level(); - FILE *maps = NULL; - int r; - - // dl_iterate_phdr(3) does NOT contain linker/linker64 when Android version < 8.1 (API level 27). - // Here we always try to get linker base address from auxv. - uintptr_t linker_load_bias = 0; - uintptr_t linker_base = xdl_iterate_get_linker_base(); - if (0 != linker_base) { - if (0 != - (r = xdl_iterate_do_callback(cb, cb_arg, linker_base, XDL_UTIL_LINKER_PATHNAME, &linker_load_bias))) - return r; - } - - // for other ELF - uintptr_t pkg[5] = {(uintptr_t)cb, (uintptr_t)cb_arg, (uintptr_t)&maps, linker_load_bias, (uintptr_t)flags}; - if (__ANDROID_API_L__ == api_level || __ANDROID_API_L_MR1__ == api_level) xdl_linker_lock(); - r = dl_iterate_phdr(xdl_iterate_by_linker_cb, pkg); - if (__ANDROID_API_L__ == api_level || __ANDROID_API_L_MR1__ == api_level) xdl_linker_unlock(); - - if (NULL != maps) fclose(maps); - return r; -} - -#if (defined(__arm__) || defined(__i386__)) && __ANDROID_API__ < __ANDROID_API_L__ -static int xdl_iterate_by_maps(xdl_iterate_phdr_cb_t cb, void *cb_arg) { - FILE *maps = fopen("/proc/self/maps", "r"); - if (NULL == maps) return 0; - - int r = 0; - char buf1[1024], buf2[1024]; - char *line = buf1; - uintptr_t prev_base = 0; - bool try_next_line = false; - - while (fgets(line, sizeof(buf1), maps)) { - // Try to find an ELF which loaded by linker. - uintptr_t base, offset; - char exec; - if (3 != sscanf(line, "%" SCNxPTR "-%*" SCNxPTR " r%*c%cp %" SCNxPTR " ", &base, &exec, &offset)) - goto clean; - - if ('-' == exec && 0 == offset) { - // r--p - prev_base = base; - line = (line == buf1 ? buf2 : buf1); - try_next_line = true; - continue; - } else if (exec == 'x') { - // r-xp - char *pathname = NULL; - if (try_next_line && 0 != offset) { - char *prev = (line == buf1 ? buf2 : buf1); - char *prev_pathname = strchr(prev, '/'); - if (NULL == prev_pathname) goto clean; - - pathname = strchr(line, '/'); - if (NULL == pathname) goto clean; - - xdl_util_trim_ending(prev_pathname); - xdl_util_trim_ending(pathname); - if (0 != strcmp(prev_pathname, pathname)) goto clean; - - // we found the line with r-xp in the next line - base = prev_base; - offset = 0; - } - - if (0 != offset) goto clean; - - // get pathname - if (NULL == pathname) { - pathname = strchr(line, '/'); - if (NULL == pathname) goto clean; - xdl_util_trim_ending(pathname); - } - - if (0 != memcmp((void *)base, ELFMAG, SELFMAG)) goto clean; - ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)base; - struct dl_phdr_info info; - info.dlpi_name = pathname; - info.dlpi_phdr = (const ElfW(Phdr) *)(base + ehdr->e_phoff); - info.dlpi_phnum = ehdr->e_phnum; - - // callback - if (0 != (r = xdl_iterate_do_callback(cb, cb_arg, base, pathname, NULL))) break; - } - - clean: - try_next_line = false; - } - - fclose(maps); - return r; -} -#endif - -int xdl_iterate_phdr_impl(xdl_iterate_phdr_cb_t cb, void *cb_arg, int flags) { - // iterate by /proc/self/maps in Android 4.x (Android 4.x only supports arm32 and x86) -#if (defined(__arm__) || defined(__i386__)) && __ANDROID_API__ < __ANDROID_API_L__ - if (xdl_util_get_api_level() < __ANDROID_API_L__) return xdl_iterate_by_maps(cb, cb_arg); -#endif - - // iterate by dl_iterate_phdr() - return xdl_iterate_by_linker(cb, cb_arg, flags); -} - -int xdl_iterate_get_full_pathname(uintptr_t base, char *buf, size_t buf_len) { - FILE *maps = NULL; - int r = xdl_iterate_get_pathname_from_maps(base, buf, buf_len, &maps); - if (NULL != maps) fclose(maps); - return r; -} diff --git a/zygisk/src/main/cpp/xdl/xdl_iterate.h b/zygisk/src/main/cpp/xdl/xdl_iterate.h deleted file mode 100644 index b0bfa94..0000000 --- a/zygisk/src/main/cpp/xdl/xdl_iterate.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2020-2024 HexHacking Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -// Created by caikelun on 2020-10-04. - -#ifndef IO_GITHUB_HEXHACKING_XDL_ITERATE -#define IO_GITHUB_HEXHACKING_XDL_ITERATE - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef int (*xdl_iterate_phdr_cb_t)(struct dl_phdr_info *info, size_t size, void *arg); -int xdl_iterate_phdr_impl(xdl_iterate_phdr_cb_t cb, void *cb_arg, int flags); - -int xdl_iterate_get_full_pathname(uintptr_t base, char *buf, size_t buf_len); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/zygisk/src/main/cpp/xdl/xdl_linker.c b/zygisk/src/main/cpp/xdl/xdl_linker.c deleted file mode 100644 index 687b3db..0000000 --- a/zygisk/src/main/cpp/xdl/xdl_linker.c +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright (c) 2020-2024 HexHacking Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -// Created by caikelun on 2021-02-21. - -#include "xdl_linker.h" - -#include -#include -#include -#include - -#include "xdl.h" -#include "xdl_iterate.h" -#include "xdl_util.h" - -#define XDL_LINKER_SYM_MUTEX "__dl__ZL10g_dl_mutex" -#define XDL_LINKER_SYM_DLOPEN_EXT_N "__dl__ZL10dlopen_extPKciPK17android_dlextinfoPv" -#define XDL_LINKER_SYM_DO_DLOPEN_N "__dl__Z9do_dlopenPKciPK17android_dlextinfoPv" -#define XDL_LINKER_SYM_DLOPEN_O "__dl__Z8__dlopenPKciPKv" -#define XDL_LINKER_SYM_LOADER_DLOPEN_P "__loader_dlopen" - -#ifndef __LP64__ -#define LIB "lib" -#else -#define LIB "lib64" -#endif - -typedef void *(*xdl_linker_dlopen_n_t)(const char *, int, const void *, void *); -typedef void *(*xdl_linker_dlopen_o_t)(const char *, int, const void *); - -static pthread_mutex_t *xdl_linker_mutex = NULL; -static void *xdl_linker_dlopen = NULL; - -typedef enum { MATCH_PREFIX, MATCH_SUFFIX } xdl_linker_match_type_t; - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -typedef struct { - xdl_linker_match_type_t type; - const char *value; -} xdl_linker_match_t; -#pragma clang diagnostic pop - -typedef struct { - void *addr; - xdl_linker_match_t *matches; - size_t matches_cursor; -} xdl_linker_caller_t; - -// https://source.android.com/docs/core/architecture/vndk/linker-namespace -// The following rules are loose and incomplete, you can add more according to your needs. -static xdl_linker_match_t xdl_linker_match_default[] = {{MATCH_SUFFIX, "/libc.so"}}; -static xdl_linker_match_t xdl_linker_match_art[] = {{MATCH_SUFFIX, "/libart.so"}}; -static xdl_linker_match_t xdl_linker_match_sphal[] = {{MATCH_PREFIX, "/vendor/" LIB "/egl/"}, - {MATCH_PREFIX, "/vendor/" LIB "/hw/"}, - {MATCH_PREFIX, "/vendor/" LIB "/"}, - {MATCH_PREFIX, "/odm/" LIB "/"}}; -static xdl_linker_match_t xdl_linker_match_vndk[] = {{MATCH_PREFIX, "/apex/com.android.vndk.v"}, - {MATCH_PREFIX, "/vendor/" LIB "/vndk-sp/"}, - {MATCH_PREFIX, "/odm/" LIB "/vndk-sp/"}}; -static xdl_linker_caller_t xdl_linker_callers[] = { - {NULL, xdl_linker_match_default, sizeof(xdl_linker_match_default) / sizeof(xdl_linker_match_t)}, - {NULL, xdl_linker_match_art, sizeof(xdl_linker_match_art) / sizeof(xdl_linker_match_t)}, - {NULL, xdl_linker_match_sphal, sizeof(xdl_linker_match_sphal) / sizeof(xdl_linker_match_t)}, - {NULL, xdl_linker_match_vndk, sizeof(xdl_linker_match_vndk) / sizeof(xdl_linker_match_t)}}; - -static void xdl_linker_init_symbols_impl(void) { - // find linker from: /proc/self/maps (API level < 18) or getauxval (API level >= 18) - void *handle = xdl_open(XDL_UTIL_LINKER_BASENAME, XDL_DEFAULT); - if (NULL == handle) return; - - int api_level = xdl_util_get_api_level(); - if (__ANDROID_API_L__ == api_level || __ANDROID_API_L_MR1__ == api_level) { - // == Android 5.x - xdl_linker_mutex = (pthread_mutex_t *)xdl_dsym(handle, XDL_LINKER_SYM_MUTEX, NULL); - } else if (__ANDROID_API_N__ == api_level || __ANDROID_API_N_MR1__ == api_level) { - // == Android 7.x - xdl_linker_dlopen = xdl_dsym(handle, XDL_LINKER_SYM_DLOPEN_EXT_N, NULL); - if (NULL == xdl_linker_dlopen) { - xdl_linker_dlopen = xdl_dsym(handle, XDL_LINKER_SYM_DO_DLOPEN_N, NULL); - xdl_linker_mutex = (pthread_mutex_t *)xdl_dsym(handle, XDL_LINKER_SYM_MUTEX, NULL); - } - } else if (__ANDROID_API_O__ == api_level || __ANDROID_API_O_MR1__ == api_level) { - // == Android 8.x - xdl_linker_dlopen = xdl_dsym(handle, XDL_LINKER_SYM_DLOPEN_O, NULL); - } else if (api_level >= __ANDROID_API_P__) { - // >= Android 9.0 - xdl_linker_dlopen = xdl_sym(handle, XDL_LINKER_SYM_LOADER_DLOPEN_P, NULL); - } - - xdl_close(handle); -} - -static void xdl_linker_init_symbols(void) { - static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; - static bool inited = false; - if (!inited) { - pthread_mutex_lock(&lock); - if (!inited) { - xdl_linker_init_symbols_impl(); - inited = true; - } - pthread_mutex_unlock(&lock); - } -} - -void xdl_linker_lock(void) { - xdl_linker_init_symbols(); - - if (NULL != xdl_linker_mutex) pthread_mutex_lock(xdl_linker_mutex); -} - -void xdl_linker_unlock(void) { - if (NULL != xdl_linker_mutex) pthread_mutex_unlock(xdl_linker_mutex); -} - -static void *xdl_linker_get_caller_addr(struct dl_phdr_info *info) { - for (size_t i = 0; i < info->dlpi_phnum; i++) { - const ElfW(Phdr) *phdr = &(info->dlpi_phdr[i]); - if (PT_LOAD == phdr->p_type) { - return (void *)(info->dlpi_addr + phdr->p_vaddr); - } - } - return NULL; -} - -static void xdl_linker_save_caller_addr(struct dl_phdr_info *info, xdl_linker_caller_t *caller, - size_t cursor) { - void *addr = xdl_linker_get_caller_addr(info); - if (NULL != addr) { - caller->addr = addr; - caller->matches_cursor = cursor; - } -} - -static int xdl_linker_get_caller_addr_cb(struct dl_phdr_info *info, size_t size, void *arg) { - (void)size, (void)arg; - if (0 == info->dlpi_addr || NULL == info->dlpi_name) return 0; // continue - - int ret = 1; // OK - for (size_t i = 0; i < sizeof(xdl_linker_callers) / sizeof(xdl_linker_callers[0]); i++) { - xdl_linker_caller_t *caller = &xdl_linker_callers[i]; - for (size_t j = 0; j < caller->matches_cursor; j++) { - xdl_linker_match_t *match = &caller->matches[j]; - if (MATCH_PREFIX == match->type) { - if (xdl_util_starts_with(info->dlpi_name, match->value)) { - xdl_linker_save_caller_addr(info, caller, j); - } - } else if (MATCH_SUFFIX == match->type) { - if (xdl_util_ends_with(info->dlpi_name, match->value)) { - xdl_linker_save_caller_addr(info, caller, j); - } - } - } - if (NULL == caller->addr || 0 != caller->matches_cursor) ret = 0; // continue - } - return ret; -} - -static void xdl_linker_init_caller_addr_impl(void) { - xdl_iterate_phdr_impl(xdl_linker_get_caller_addr_cb, NULL, XDL_DEFAULT); -} - -static void xdl_linker_init_caller_addr(void) { - static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; - static bool inited = false; - if (!inited) { - pthread_mutex_lock(&lock); - if (!inited) { - xdl_linker_init_caller_addr_impl(); - inited = true; - } - pthread_mutex_unlock(&lock); - } -} - -void *xdl_linker_force_dlopen(const char *filename) { - int api_level = xdl_util_get_api_level(); - - if (api_level <= __ANDROID_API_M__) { - // <= Android 6.0 - return dlopen(filename, RTLD_NOW); - } else { - xdl_linker_init_symbols(); - if (NULL == xdl_linker_dlopen) return NULL; - xdl_linker_init_caller_addr(); - - void *handle = NULL; - if (__ANDROID_API_N__ == api_level || __ANDROID_API_N_MR1__ == api_level) { - // == Android 7.x - xdl_linker_lock(); - for (size_t i = 0; i < sizeof(xdl_linker_callers) / sizeof(xdl_linker_callers[0]); i++) { - xdl_linker_caller_t *caller = &xdl_linker_callers[i]; - if (NULL != caller->addr) { - handle = ((xdl_linker_dlopen_n_t)xdl_linker_dlopen)(filename, RTLD_NOW, NULL, caller->addr); - if (NULL != handle) break; - } - } - xdl_linker_unlock(); - } else { - // >= Android 8.0 - for (size_t i = 0; i < sizeof(xdl_linker_callers) / sizeof(xdl_linker_callers[0]); i++) { - xdl_linker_caller_t *caller = &xdl_linker_callers[i]; - if (NULL != caller->addr) { - handle = ((xdl_linker_dlopen_o_t)xdl_linker_dlopen)(filename, RTLD_NOW, caller->addr); - if (NULL != handle) break; - } - } - } - return handle; - } -} diff --git a/zygisk/src/main/cpp/xdl/xdl_linker.h b/zygisk/src/main/cpp/xdl/xdl_linker.h deleted file mode 100644 index 2d40cf4..0000000 --- a/zygisk/src/main/cpp/xdl/xdl_linker.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2020-2024 HexHacking Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -// Created by caikelun on 2021-02-21. - -#ifndef IO_GITHUB_HEXHACKING_XDL_LINKER -#define IO_GITHUB_HEXHACKING_XDL_LINKER - -#ifdef __cplusplus -extern "C" { -#endif - -void xdl_linker_lock(void); -void xdl_linker_unlock(void); - -void *xdl_linker_force_dlopen(const char *filename); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/zygisk/src/main/cpp/xdl/xdl_lzma.c b/zygisk/src/main/cpp/xdl/xdl_lzma.c deleted file mode 100644 index aff6d48..0000000 --- a/zygisk/src/main/cpp/xdl/xdl_lzma.c +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright (c) 2020-2024 HexHacking Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -// Created by caikelun on 2020-11-08. - -#include "xdl_lzma.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "xdl.h" -#include "xdl_util.h" - -// LZMA library pathname & symbol names -#ifndef __LP64__ -#define XDL_LZMA_PATHNAME "/system/lib/liblzma.so" -#else -#define XDL_LZMA_PATHNAME "/system/lib64/liblzma.so" -#endif -#define XDL_LZMA_SYM_CRCGEN "CrcGenerateTable" -#define XDL_LZMA_SYM_CRC64GEN "Crc64GenerateTable" -#define XDL_LZMA_SYM_CONSTRUCT "XzUnpacker_Construct" -#define XDL_LZMA_SYM_ISFINISHED "XzUnpacker_IsStreamWasFinished" -#define XDL_LZMA_SYM_FREE "XzUnpacker_Free" -#define XDL_LZMA_SYM_CODE "XzUnpacker_Code" - -// LZMA data type definition -#define SZ_OK 0 -typedef struct ISzAlloc ISzAlloc; -typedef const ISzAlloc *ISzAllocPtr; -struct ISzAlloc { - void *(*Alloc)(ISzAllocPtr p, size_t size); - void (*Free)(ISzAllocPtr p, void *address); /* address can be 0 */ -}; -typedef enum { - CODER_STATUS_NOT_SPECIFIED, /* use main error code instead */ - CODER_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ - CODER_STATUS_NOT_FINISHED, /* stream was not finished */ - CODER_STATUS_NEEDS_MORE_INPUT /* you must provide more input bytes */ -} ECoderStatus; -typedef enum { - CODER_FINISH_ANY, /* finish at any point */ - CODER_FINISH_END /* block must be finished at the end */ -} ECoderFinishMode; - -// LZMA function type definition -typedef void (*xdl_lzma_crcgen_t)(void); -typedef void (*xdl_lzma_crc64gen_t)(void); -typedef void (*xdl_lzma_construct_t)(void *, ISzAllocPtr); -typedef int (*xdl_lzma_isfinished_t)(const void *); -typedef void (*xdl_lzma_free_t)(void *); -typedef int (*xdl_lzma_code_t)(void *, uint8_t *, size_t *, const uint8_t *, size_t *, ECoderFinishMode, - ECoderStatus *); -typedef int (*xdl_lzma_code_q_t)(void *, uint8_t *, size_t *, const uint8_t *, size_t *, int, - ECoderFinishMode, ECoderStatus *); - -// LZMA function pointor -static xdl_lzma_construct_t xdl_lzma_construct = NULL; -static xdl_lzma_isfinished_t xdl_lzma_isfinished = NULL; -static xdl_lzma_free_t xdl_lzma_free = NULL; -static void *xdl_lzma_code = NULL; - -// LZMA init -static void xdl_lzma_init(void) { - void *lzma = xdl_open(XDL_LZMA_PATHNAME, XDL_TRY_FORCE_LOAD); - if (NULL == lzma) return; - - xdl_lzma_crcgen_t crcgen = NULL; - xdl_lzma_crc64gen_t crc64gen = NULL; - if (NULL == (crcgen = (xdl_lzma_crcgen_t)xdl_sym(lzma, XDL_LZMA_SYM_CRCGEN, NULL))) goto end; - if (NULL == (crc64gen = (xdl_lzma_crc64gen_t)xdl_sym(lzma, XDL_LZMA_SYM_CRC64GEN, NULL))) goto end; - if (NULL == (xdl_lzma_construct = (xdl_lzma_construct_t)xdl_sym(lzma, XDL_LZMA_SYM_CONSTRUCT, NULL))) - goto end; - if (NULL == (xdl_lzma_isfinished = (xdl_lzma_isfinished_t)xdl_sym(lzma, XDL_LZMA_SYM_ISFINISHED, NULL))) - goto end; - if (NULL == (xdl_lzma_free = (xdl_lzma_free_t)xdl_sym(lzma, XDL_LZMA_SYM_FREE, NULL))) goto end; - if (NULL == (xdl_lzma_code = xdl_sym(lzma, XDL_LZMA_SYM_CODE, NULL))) goto end; - crcgen(); - crc64gen(); - -end: - xdl_close(lzma); -} - -// LZMA internal alloc / free -static void *xdl_lzma_internal_alloc(ISzAllocPtr p, size_t size) { - (void)p; - return malloc(size); -} -static void xdl_lzma_internal_free(ISzAllocPtr p, void *address) { - (void)p; - free(address); -} - -int xdl_lzma_decompress(uint8_t *src, size_t src_size, uint8_t **dst, size_t *dst_size) { - size_t src_offset = 0; - size_t dst_offset = 0; - size_t src_remaining; - size_t dst_remaining; - ISzAlloc alloc = {.Alloc = xdl_lzma_internal_alloc, .Free = xdl_lzma_internal_free}; - long long state[4096 / sizeof(long long)]; // must be enough, 8-bit aligned - ECoderStatus status; - int api_level = xdl_util_get_api_level(); - - // init and check - static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; - static bool inited = false; - if (!inited) { - pthread_mutex_lock(&lock); - if (!inited) { - xdl_lzma_init(); - inited = true; - } - pthread_mutex_unlock(&lock); - } - if (NULL == xdl_lzma_code) return -1; - - xdl_lzma_construct(&state, &alloc); - - *dst_size = 2 * src_size; - *dst = NULL; - do { - *dst_size *= 2; - if (NULL == (*dst = realloc(*dst, *dst_size))) { - xdl_lzma_free(&state); - return -1; - } - - src_remaining = src_size - src_offset; - dst_remaining = *dst_size - dst_offset; - - int result; - if (api_level >= __ANDROID_API_Q__) { - xdl_lzma_code_q_t lzma_code_q = (xdl_lzma_code_q_t)xdl_lzma_code; - result = lzma_code_q(&state, *dst + dst_offset, &dst_remaining, src + src_offset, &src_remaining, 1, - CODER_FINISH_ANY, &status); - } else { - xdl_lzma_code_t lzma_code = (xdl_lzma_code_t)xdl_lzma_code; - result = lzma_code(&state, *dst + dst_offset, &dst_remaining, src + src_offset, &src_remaining, - CODER_FINISH_ANY, &status); - } - if (SZ_OK != result) { - free(*dst); - xdl_lzma_free(&state); - return -1; - } - - src_offset += src_remaining; - dst_offset += dst_remaining; - } while (status == CODER_STATUS_NOT_FINISHED); - - xdl_lzma_free(&state); - - if (!xdl_lzma_isfinished(&state)) { - free(*dst); - return -1; - } - - *dst_size = dst_offset; - *dst = realloc(*dst, *dst_size); - return 0; -} diff --git a/zygisk/src/main/cpp/xdl/xdl_lzma.h b/zygisk/src/main/cpp/xdl/xdl_lzma.h deleted file mode 100644 index b1eef1d..0000000 --- a/zygisk/src/main/cpp/xdl/xdl_lzma.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2020-2024 HexHacking Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -// Created by caikelun on 2020-11-08. - -#ifndef IO_GITHUB_HEXHACKING_XDL_LZMA -#define IO_GITHUB_HEXHACKING_XDL_LZMA - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -int xdl_lzma_decompress(uint8_t *src, size_t src_size, uint8_t **dst, size_t *dst_size); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/zygisk/src/main/cpp/xdl/xdl_util.c b/zygisk/src/main/cpp/xdl/xdl_util.c deleted file mode 100644 index 96f15dd..0000000 --- a/zygisk/src/main/cpp/xdl/xdl_util.c +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) 2020-2024 HexHacking Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -// Created by caikelun on 2020-10-04. - -#include "xdl_util.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -bool xdl_util_starts_with(const char *str, const char *start) { - while (*str && *str == *start) { - str++; - start++; - } - - return '\0' == *start; -} - -bool xdl_util_ends_with(const char *str, const char *ending) { - size_t str_len = strlen(str); - size_t ending_len = strlen(ending); - - if (ending_len > str_len) return false; - - return 0 == strcmp(str + (str_len - ending_len), ending); -} - -size_t xdl_util_trim_ending(char *start) { - char *end = start + strlen(start); - while (start < end && isspace((int)(*(end - 1)))) { - end--; - *end = '\0'; - } - return (size_t)(end - start); -} - -static int xdl_util_get_api_level_from_build_prop(void) { - char buf[128]; - int api_level = -1; - - FILE *fp = fopen("/system/build.prop", "r"); - if (NULL == fp) goto end; - - while (fgets(buf, sizeof(buf), fp)) { - if (xdl_util_starts_with(buf, "ro.build.version.sdk=")) { - api_level = atoi(buf + 21); - break; - } - } - fclose(fp); - -end: - return (api_level > 0) ? api_level : -1; -} - -int xdl_util_get_api_level(void) { - static int xdl_util_api_level = -1; - - if (xdl_util_api_level < 0) { - int api_level = android_get_device_api_level(); - if (api_level < 0) - api_level = xdl_util_get_api_level_from_build_prop(); // compatible with unusual models - if (api_level < __ANDROID_API_J__) api_level = __ANDROID_API_J__; - - __atomic_store_n(&xdl_util_api_level, api_level, __ATOMIC_SEQ_CST); - } - - return xdl_util_api_level; -} diff --git a/zygisk/src/main/cpp/xdl/xdl_util.h b/zygisk/src/main/cpp/xdl/xdl_util.h deleted file mode 100644 index 8641d1a..0000000 --- a/zygisk/src/main/cpp/xdl/xdl_util.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2020-2024 HexHacking Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -// Created by caikelun on 2020-10-04. - -#ifndef IO_GITHUB_HEXHACKING_XDL_UTIL -#define IO_GITHUB_HEXHACKING_XDL_UTIL - -#include -#include -#include - -#ifndef __LP64__ -#define XDL_UTIL_LINKER_BASENAME "linker" -#define XDL_UTIL_LINKER_PATHNAME "/system/bin/linker" -#define XDL_UTIL_APP_PROCESS_BASENAME "app_process32" -#define XDL_UTIL_APP_PROCESS_PATHNAME "/system/bin/app_process32" -#define XDL_UTIL_APP_PROCESS_BASENAME_K "app_process" -#define XDL_UTIL_APP_PROCESS_PATHNAME_K "/system/bin/app_process" -#else -#define XDL_UTIL_LINKER_BASENAME "linker64" -#define XDL_UTIL_LINKER_PATHNAME "/system/bin/linker64" -#define XDL_UTIL_APP_PROCESS_BASENAME "app_process64" -#define XDL_UTIL_APP_PROCESS_PATHNAME "/system/bin/app_process64" -#endif -#define XDL_UTIL_VDSO_BASENAME "[vdso]" - -#define XDL_UTIL_TEMP_FAILURE_RETRY(exp) \ - ({ \ - __typeof__(exp) _rc; \ - do { \ - errno = 0; \ - _rc = (exp); \ - } while (_rc == -1 && errno == EINTR); \ - _rc; \ - }) - -#ifdef __cplusplus -extern "C" { -#endif - -bool xdl_util_starts_with(const char *str, const char *start); -bool xdl_util_ends_with(const char *str, const char *ending); - -size_t xdl_util_trim_ending(char *start); - -int xdl_util_get_api_level(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/zygisk/src/main/cpp/zygisk.cpp b/zygisk/src/main/cpp/zygisk.cpp index 6e4f171..2990c65 100644 --- a/zygisk/src/main/cpp/zygisk.cpp +++ b/zygisk/src/main/cpp/zygisk.cpp @@ -6,12 +6,12 @@ #include #include #include -#include "xdl.h" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "PIF", __VA_ARGS__) -#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "PIF", __VA_ARGS__) -#define DEX_PATH "/data/adb/modules/playintegrityfix/classes.jar" +#define TS_PATH "/data/adb/modules/tricky_store" + +#define DEX_PATH "/data/adb/modules/playintegrityfix/classes.dex" #define LIB_64 "/data/adb/modules/playintegrityfix/inject/arm64-v8a.so" #define LIB_32 "/data/adb/modules/playintegrityfix/inject/armeabi-v7a.so" @@ -61,17 +61,37 @@ static bool copyFile(const std::string &from, const std::string &to, mode_t perm ); } +static bool checkOtaZip() { + std::array buffer{}; + std::string result; + bool found = false; + + std::unique_ptr pipe( + popen("unzip -l /system/etc/security/otacerts.zip", "r"), pclose); + if (!pipe) return false; + + while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { + result += buffer.data(); + if (result.find("testkey") != std::string::npos) { + found = true; + break; + } + } + + return found; +} + static void companion(int fd) { bool ok = true; - int length = 0; - xread(fd, &length, sizeof(int)); + int size = 0; + xread(fd, &size, sizeof(int)); std::string dir; - dir.resize(length + 1); - auto bytes = xread(fd, dir.data(), length); + dir.resize(size); + auto bytes = xread(fd, dir.data(), size); dir.resize(bytes); - dir[bytes - 1] = '\0'; + dir.shrink_to_fit(); LOGD("[COMPANION] GMS dir: %s", dir.c_str()); @@ -84,7 +104,7 @@ static void companion(int fd) { LOGD("[COMPANION] copied inject lib"); - auto dexFile = dir + "/classes.jar"; + auto dexFile = dir + "/classes.dex"; ok &= copyFile(DEX_PATH, dexFile, 0644); LOGD("[COMPANION] copied dex"); @@ -100,6 +120,15 @@ static void companion(int fd) { LOGD("[COMPANION] copied json"); + std::string ts(TS_PATH); + bool trickyStore = std::filesystem::exists(ts) && + !std::filesystem::exists(ts + "/disable") && + !std::filesystem::exists(ts + "/remove"); + xwrite(fd, &trickyStore, sizeof(bool)); + + bool testSignedRom = checkOtaZip(); + xwrite(fd, &testSignedRom, sizeof(bool)); + xwrite(fd, &ok, sizeof(bool)); } @@ -146,11 +175,15 @@ public: auto fd = api->connectCompanion(); - int size = static_cast(dir.length()); + int size = static_cast(dir.size()); xwrite(fd, &size, sizeof(int)); xwrite(fd, dir.data(), size); + xread(fd, &trickyStore, sizeof(bool)); + + xread(fd, &testSignedRom, sizeof(bool)); + bool ok = false; xread(fd, &ok, sizeof(bool)); @@ -164,17 +197,22 @@ public: if (gmsDir.empty()) return; - typedef bool (*InitFuncPtr)(JavaVM *, const std::string &); + typedef bool (*InitFuncPtr)(JavaVM *, const std::string &, bool, bool); - auto handle = xdl_open((gmsDir + "/libinject.so").c_str(), XDL_DEFAULT); - auto init_func = reinterpret_cast(xdl_sym(handle, "init", nullptr)); + void *handle = dlopen((gmsDir + "/libinject.so").c_str(), RTLD_NOW); + + if (!handle) + return; + + auto init_func = reinterpret_cast(dlsym(handle, "init")); JavaVM *vm = nullptr; env->GetJavaVM(&vm); - init_func(vm, gmsDir); - - xdl_close(handle); + if (init_func(vm, gmsDir, trickyStore, testSignedRom)) { + LOGD("dlclose injected lib"); + dlclose(handle); + } } void preServerSpecialize(ServerSpecializeArgs *args) override { @@ -185,6 +223,8 @@ private: Api *api = nullptr; JNIEnv *env = nullptr; std::string gmsDir; + bool trickyStore = false; + bool testSignedRom = false; }; REGISTER_ZYGISK_MODULE(PlayIntegrityFix)