Fix errors
Some checks failed
Android CI / build (push) Has been cancelled

This commit is contained in:
chiteroman 2025-04-08 20:06:53 +02:00
parent 44a0ccc850
commit 9a27afefe1
No known key found for this signature in database
GPG Key ID: 49B8638F84128889
22 changed files with 85 additions and 2210 deletions

View File

@ -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")

View File

@ -1,9 +0,0 @@
Telegram channel:
https://t.me/playintegrityfix
Donations:
https://www.paypal.com/paypalme/chiteroman0
# v18.9
- Update fingerprint.

View File

@ -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" }

View File

@ -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, "<init>",
"(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<void **>(&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;
}

Binary file not shown.

View File

@ -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

View File

@ -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"
}

View File

@ -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")
}
}

View File

@ -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)

View File

@ -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 ()

View File

@ -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 <dlfcn.h>
#include <link.h>
#include <stddef.h>
#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

File diff suppressed because it is too large Load Diff

View File

@ -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:
*;
};

View File

@ -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 <android/api-level.h>
#include <ctype.h>
#include <dlfcn.h>
#include <elf.h>
#include <inttypes.h>
#include <link.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/auxv.h>
#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;
}

View File

@ -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 <link.h>
#include <stddef.h>
#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

View File

@ -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 <dlfcn.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdio.h>
#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;
}
}

View File

@ -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

View File

@ -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 <ctype.h>
#include <inttypes.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#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;
}

View File

@ -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 <stddef.h>
#include <stdint.h>
#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

View File

@ -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 <android/api-level.h>
#include <ctype.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
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;
}

View File

@ -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 <errno.h>
#include <stdbool.h>
#include <stddef.h>
#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

View File

@ -6,12 +6,12 @@
#include <cerrno>
#include <filesystem>
#include <sys/stat.h>
#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<char, 256> buffer{};
std::string result;
bool found = false;
std::unique_ptr<FILE, decltype(&pclose)> 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<int>(dir.length());
int size = static_cast<int>(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<InitFuncPtr>(xdl_sym(handle, "init", nullptr));
void *handle = dlopen((gmsDir + "/libinject.so").c_str(), RTLD_NOW);
if (!handle)
return;
auto init_func = reinterpret_cast<InitFuncPtr>(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)