From fd9fe6b4f86144489eb091fe689ee12390e07787 Mon Sep 17 00:00:00 2001 From: ShirosakiMio <852468399@qq.com> Date: Thu, 15 Aug 2024 13:11:09 +0800 Subject: [PATCH] change xhook to bytehook --- FCL/build.gradle | 1 + FCLauncher/build.gradle | 5 +- .../java/com/oracle/dalvik/VMLauncher.java | 7 + .../com/tungsten/fclauncher/FCLauncher.java | 8 +- .../tungsten/fclauncher/bridge/FCLBridge.java | 5 +- FCLauncher/src/main/jni/Android.mk | 26 +- FCLauncher/src/main/jni/fcl/fcl_bridge.c | 1 - FCLauncher/src/main/jni/fcl/fcl_loader.c | 140 ++- FCLauncher/src/main/jni/fcl/jre_launcher.c | 209 ++++ FCLauncher/src/main/jni/xhook/include/queue.h | 554 --------- FCLauncher/src/main/jni/xhook/include/tree.h | 768 ------------ .../src/main/jni/xhook/include/xh_core.h | 48 - .../src/main/jni/xhook/include/xh_elf.h | 85 -- .../src/main/jni/xhook/include/xh_errno.h | 37 - .../src/main/jni/xhook/include/xh_log.h | 45 - .../src/main/jni/xhook/include/xh_util.h | 51 - .../src/main/jni/xhook/include/xh_version.h | 41 - FCLauncher/src/main/jni/xhook/include/xhook.h | 50 - FCLauncher/src/main/jni/xhook/xh_core.c | 656 ----------- FCLauncher/src/main/jni/xhook/xh_elf.c | 1046 ----------------- FCLauncher/src/main/jni/xhook/xh_jni.c | 59 - FCLauncher/src/main/jni/xhook/xh_log.c | 27 - FCLauncher/src/main/jni/xhook/xh_util.c | 121 -- FCLauncher/src/main/jni/xhook/xh_version.c | 66 -- FCLauncher/src/main/jni/xhook/xhook.c | 56 - 25 files changed, 301 insertions(+), 3811 deletions(-) create mode 100644 FCLauncher/src/main/java/com/oracle/dalvik/VMLauncher.java create mode 100644 FCLauncher/src/main/jni/fcl/jre_launcher.c delete mode 100644 FCLauncher/src/main/jni/xhook/include/queue.h delete mode 100644 FCLauncher/src/main/jni/xhook/include/tree.h delete mode 100644 FCLauncher/src/main/jni/xhook/include/xh_core.h delete mode 100644 FCLauncher/src/main/jni/xhook/include/xh_elf.h delete mode 100644 FCLauncher/src/main/jni/xhook/include/xh_errno.h delete mode 100644 FCLauncher/src/main/jni/xhook/include/xh_log.h delete mode 100644 FCLauncher/src/main/jni/xhook/include/xh_util.h delete mode 100644 FCLauncher/src/main/jni/xhook/include/xh_version.h delete mode 100644 FCLauncher/src/main/jni/xhook/include/xhook.h delete mode 100644 FCLauncher/src/main/jni/xhook/xh_core.c delete mode 100644 FCLauncher/src/main/jni/xhook/xh_elf.c delete mode 100644 FCLauncher/src/main/jni/xhook/xh_jni.c delete mode 100644 FCLauncher/src/main/jni/xhook/xh_log.c delete mode 100644 FCLauncher/src/main/jni/xhook/xh_util.c delete mode 100644 FCLauncher/src/main/jni/xhook/xh_version.c delete mode 100644 FCLauncher/src/main/jni/xhook/xhook.c diff --git a/FCL/build.gradle b/FCL/build.gradle index 0acfd87b..c91fe8c0 100644 --- a/FCL/build.gradle +++ b/FCL/build.gradle @@ -100,6 +100,7 @@ android { jniLibs { useLegacyPackaging true } + pickFirst '**/libbytehook.so' } splits { def arch = System.getProperty("arch", "all") diff --git a/FCLauncher/build.gradle b/FCLauncher/build.gradle index 974213a0..82498523 100644 --- a/FCLauncher/build.gradle +++ b/FCLauncher/build.gradle @@ -33,10 +33,13 @@ android { } } ndkVersion '25.1.8937393' + buildFeatures { + prefab true + } } dependencies { - + implementation 'com.bytedance:bytehook:1.0.9' implementation 'com.jaredrummler:android-device-names:2.1.0' implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'com.google.android.material:material:1.11.0' diff --git a/FCLauncher/src/main/java/com/oracle/dalvik/VMLauncher.java b/FCLauncher/src/main/java/com/oracle/dalvik/VMLauncher.java new file mode 100644 index 00000000..4cd1385b --- /dev/null +++ b/FCLauncher/src/main/java/com/oracle/dalvik/VMLauncher.java @@ -0,0 +1,7 @@ +package com.oracle.dalvik; + +public final class VMLauncher { + private VMLauncher() { + } + public static native int launchJVM(String[] args); +} diff --git a/FCLauncher/src/main/java/com/tungsten/fclauncher/FCLauncher.java b/FCLauncher/src/main/java/com/tungsten/fclauncher/FCLauncher.java index 845b9153..5afe21e4 100644 --- a/FCLauncher/src/main/java/com/tungsten/fclauncher/FCLauncher.java +++ b/FCLauncher/src/main/java/com/tungsten/fclauncher/FCLauncher.java @@ -9,6 +9,7 @@ import android.system.Os; import android.util.ArrayMap; import com.jaredrummler.android.device.DeviceName; +import com.oracle.dalvik.VMLauncher; import com.tungsten.fclauncher.bridge.FCLBridge; import com.tungsten.fclauncher.plugins.FFmpegPlugin; import com.tungsten.fclauncher.utils.Architecture; @@ -234,6 +235,7 @@ public class FCLauncher { String nativeDir = config.getContext().getApplicationInfo().nativeLibraryDir; bridge.dlopen(nativeDir + "/libopenal.so"); + bridge.dlopen(nativeDir + "/" + config.getRenderer().getGlLibName()); } private static void launch(FCLConfig config, FCLBridge bridge, String task) throws IOException { @@ -260,10 +262,10 @@ public class FCLauncher { isToken = true; log(bridge, prefix + arg); } - bridge.setupJLI(); bridge.setLdLibraryPath(getLibraryPath(config.getContext(), config.getJavaPath())); - log(bridge, "Hook exit " + (bridge.setupExitTrap(bridge) == 0 ? "success" : "failed")); - int exitCode = bridge.jliLaunch(args); + bridge.setupExitTrap(bridge); + log(bridge, "Hook success"); + int exitCode = VMLauncher.launchJVM(args); bridge.onExit(exitCode); } diff --git a/FCLauncher/src/main/java/com/tungsten/fclauncher/bridge/FCLBridge.java b/FCLauncher/src/main/java/com/tungsten/fclauncher/bridge/FCLBridge.java index 21f83df4..bbdde7b9 100644 --- a/FCLauncher/src/main/java/com/tungsten/fclauncher/bridge/FCLBridge.java +++ b/FCLauncher/src/main/java/com/tungsten/fclauncher/bridge/FCLBridge.java @@ -83,7 +83,6 @@ public class FCLBridge implements Serializable { private SurfaceTexture surfaceTexture; static { - System.loadLibrary("xhook"); System.loadLibrary("fcl"); System.loadLibrary("fcl_awt"); } @@ -101,12 +100,10 @@ public class FCLBridge implements Serializable { public native void setenv(String key, String value); public native int dlopen(String path); public native void setLdLibraryPath(String path); - public native int setupExitTrap(FCLBridge bridge); + public native void setupExitTrap(FCLBridge bridge); public native void setEventPipe(); public native void pushEvent(long time, int type, int keycode, int keyChar); public native void refreshHitResultType(); - public native void setupJLI(); - public native int jliLaunch(String[] args); public native void setFCLBridge(FCLBridge fclBridge); diff --git a/FCLauncher/src/main/jni/Android.mk b/FCLauncher/src/main/jni/Android.mk index c570fbca..0a5c6a07 100644 --- a/FCLauncher/src/main/jni/Android.mk +++ b/FCLauncher/src/main/jni/Android.mk @@ -12,29 +12,14 @@ LOCAL_SRC_FILES := tinywrapper/main.c tinywrapper/string_utils.c LOCAL_C_INCLUDES := $(LOCAL_PATH)/tinywrapper include $(BUILD_SHARED_LIBRARY) -include $(CLEAR_VARS) -LOCAL_MODULE := xhook -LOCAL_SRC_FILES := xhook/xhook.c \ - xhook/xh_core.c \ - xhook/xh_elf.c \ - xhook/xh_jni.c \ - xhook/xh_log.c \ - xhook/xh_util.c \ - xhook/xh_version.c -LOCAL_C_INCLUDES := $(LOCAL_PATH)/xhook/include -LOCAL_CFLAGS := -Wall -Wextra -Werror -fvisibility=hidden -LOCAL_CONLYFLAGS := -std=c11 -LOCAL_LDLIBS := -llog -include $(BUILD_SHARED_LIBRARY) - include $(CLEAR_VARS) LOCAL_MODULE := fcl -LOCAL_SHARED_LIBRARIES := xhook +LOCAL_SHARED_LIBRARIES := bytehook LOCAL_SRC_FILES := fcl/fcl_bridge.c \ fcl/fcl_event.c \ - fcl/fcl_loader.c -LOCAL_C_INCLUDES := $(LOCAL_PATH)/xhook/include \ - $(LOCAL_PATH)/fcl/include + fcl/fcl_loader.c \ + fcl/jre_launcher.c +LOCAL_C_INCLUDES := $(LOCAL_PATH)/fcl/include LOCAL_LDLIBS := -llog -ldl -landroid include $(BUILD_SHARED_LIBRARY) @@ -346,4 +331,5 @@ LOCAL_SRC_FILES := lwjgl/opengl/org_lwjgl_opengl_AMDDebugOutput.c \ lwjgl/opengl/org_lwjgl_opengl_NVXProgressFence.c \ lwjgl/opengl/org_lwjgl_opengl_OVRMultiview.c LOCAL_CFLAGS := -O2 -Wall -c -fPIC -std=c99 -Wunused -DLWJGL_FCL -Wunused-value -include $(BUILD_SHARED_LIBRARY) \ No newline at end of file +include $(BUILD_SHARED_LIBRARY) +$(call import-module,prefab/bytehook) \ No newline at end of file diff --git a/FCLauncher/src/main/jni/fcl/fcl_bridge.c b/FCLauncher/src/main/jni/fcl/fcl_bridge.c index 7fb38a69..4f2ec28d 100644 --- a/FCLauncher/src/main/jni/fcl/fcl_bridge.c +++ b/FCLauncher/src/main/jni/fcl/fcl_bridge.c @@ -65,7 +65,6 @@ JNIEXPORT void JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_setFCLBridg } JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { - env_init(); if (fcl->android_jvm == NULL) { fcl->android_jvm = vm; JNIEnv* env = 0; diff --git a/FCLauncher/src/main/jni/fcl/fcl_loader.c b/FCLauncher/src/main/jni/fcl/fcl_loader.c index 6e167f72..71594c71 100644 --- a/FCLauncher/src/main/jni/fcl/fcl_loader.c +++ b/FCLauncher/src/main/jni/fcl/fcl_loader.c @@ -8,25 +8,12 @@ #include #include #include -#include +#include #include #include #include #include -#define FULL_VERSION "1.8.0-internal" -#define DOT_VERSION "1.8" -#define PROGNAME "java" -#define LAUNCHER_NAME "openjdk" - -static char* const_progname = PROGNAME; -static const char* const_launcher = LAUNCHER_NAME; -static const char** const_jargs = NULL; -static const char** const_appclasspath = NULL; -static const jboolean const_cpwildcard = JNI_TRUE; -static const jboolean const_javaw = JNI_FALSE; -static const jint const_ergo_class = 0; //DEFAULT_POLICY - typedef void (*android_update_LD_LIBRARY_PATH_t)(const char*); static volatile jobject exitTrap_bridge; static volatile jmethodID exitTrap_method; @@ -35,6 +22,7 @@ static volatile jmethodID log_method; static JavaVM *log_pipe_jvm; static int fclFd[2]; static pthread_t logger; +static _Atomic bool exit_tripped = false; void correctUtfBytes(char *bytes) { char three = 0; @@ -204,72 +192,80 @@ JNIEXPORT void JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_setLdLibrar (*env)->ReleaseStringUTFChars(env, ldLibraryPath, ldLibPathUtf); } -void (*old_exit)(int code); -void custom_exit(int code) { - __android_log_print(code == 0 ? ANDROID_LOG_INFO : ANDROID_LOG_ERROR, "FCL", "JVM exit with code %d.", code); +typedef void (*exit_func)(int); + +_Noreturn static void nominal_exit(int code) { JNIEnv *env; - (*exitTrap_jvm)->AttachCurrentThread(exitTrap_jvm, &env, NULL); - (*env)->CallVoidMethod(env, exitTrap_bridge, exitTrap_method, code); + jint errorCode = (*exitTrap_jvm)->GetEnv(exitTrap_jvm, (void**)&env, JNI_VERSION_1_6); + if(errorCode == JNI_EDETACHED) { + errorCode = (*exitTrap_jvm)->AttachCurrentThread(exitTrap_jvm, &env, NULL); + } + if(errorCode != JNI_OK) { + // Step on a landmine and die, since we can't invoke the Dalvik exit without attaching to + // Dalvik. + // I mean, if Zygote can do that, why can't I? + killpg(getpgrp(), SIGTERM); + } + if(code != 0) { + // Exit code 0 is pretty established as "eh it's fine" + // so only open the GUI if the code is != 0 + (*env)->CallVoidMethod(env, exitTrap_bridge, exitTrap_method, code); + } + // Delete the reference, not gonna need 'em later anyway (*env)->DeleteGlobalRef(env, exitTrap_bridge); - (*exitTrap_jvm)->DetachCurrentThread(exitTrap_jvm); - old_exit(code); + + // A hat trick, if you will + // Call the Android System.exit() to perform Android's shutdown hooks and do a + // fully clean exit. + // After doing this, either of these will happen: + // 1. Runtime calls exit() for real and it will be handled by ByteHook's recurse handler + // and redirected back to the OS + // 2. Zygote sends SIGTERM (no handling necessary, the process perishes) + // 3. A different thread calls exit() and the hook will go through the exit_tripped path + jclass systemClass = (*env)->FindClass(env,"java/lang/System"); + jmethodID exitMethod = (*env)->GetStaticMethodID(env, systemClass, "exit", "(I)V"); + (*env)->CallStaticVoidMethod(env, systemClass, exitMethod, 0); + // System.exit() should not ever return, but the compiler doesn't know about that + // so put a while loop here + while(1) {} } -JNIEXPORT jint JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_setupExitTrap(JNIEnv *env, jobject jobject1, jobject bridge) { +static void custom_exit(int code) { + __android_log_print(code == 0 ? ANDROID_LOG_INFO : ANDROID_LOG_ERROR, "FCL", "JVM exit with code %d.", code); + // If the exit was already done (meaning it is recursive or from a different thread), pass the call through + if(exit_tripped) { + BYTEHOOK_CALL_PREV(custom_exit, exit_func, code); + BYTEHOOK_POP_STACK(); + return; + } + exit_tripped = true; + // Perform a nominal exit, as we expect. + nominal_exit(code); + BYTEHOOK_POP_STACK(); +} + +static void custom_atexit() { + // Same as custom_exit, but without the code or the exit passthrough. + if(exit_tripped) { + return; + } + exit_tripped = true; + nominal_exit(0); +} + +JNIEXPORT void JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_setupExitTrap(JNIEnv *env, jobject jobject1, jobject bridge) { exitTrap_bridge = (*env)->NewGlobalRef(env, bridge); (*env)->GetJavaVM(env, &exitTrap_jvm); jclass exitTrap_exitClass = (*env)->NewGlobalRef(env,(*env)->FindClass(env, "com/tungsten/fclauncher/bridge/FCLBridge")); exitTrap_method = (*env)->GetMethodID(env, exitTrap_exitClass, "onExit", "(I)V"); (*env)->DeleteGlobalRef(env, exitTrap_exitClass); - // Enable xhook debug mode here - // xhook_enable_debug(1); - xhook_register(".*\\.so$", "exit", custom_exit, (void **) &old_exit); - return xhook_refresh(1); -} - -int -(*JLI_Launch)(int argc, char ** argv, /* main argc, argc */ - int jargc, const char** jargv, /* java args */ - int appclassc, const char** appclassv, /* app classpath */ - const char* fullversion, /* full version defined */ - const char* dotversion, /* dot version defined */ - const char* pname, /* program name */ - const char* lname, /* launcher name */ - jboolean javaargs, /* JAVA_ARGS */ - jboolean cpwildcard, /* classpath wildcard */ - jboolean javaw, /* windows-only javaw */ - jint ergo_class /* ergnomics policy */ -); - -JNIEXPORT void JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_setupJLI(JNIEnv* env, jobject jobject){ - - void* handle; - handle = dlopen("libjli.so", RTLD_LAZY | RTLD_GLOBAL); - JLI_Launch = (int (*)(int, char **, int, const char**, int, const char**, const char*, const char*, const char*, const char*, jboolean, jboolean, jboolean, jint))dlsym(handle, "JLI_Launch"); - -} - -JNIEXPORT jint JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_jliLaunch(JNIEnv *env, jobject jobject, jobjectArray argsArray){ - int argc = (*env)->GetArrayLength(env, argsArray); - char* argv[argc]; - for (int i = 0; i < argc; i++) { - jstring str = (*env)->GetObjectArrayElement(env, argsArray, i); - int len = (*env)->GetStringUTFLength(env, str); - char* buf = malloc(len + 1); - int characterLen = (*env)->GetStringLength(env, str); - (*env)->GetStringUTFRegion(env, str, 0, characterLen, buf); - buf[len] = 0; - argv[i] = buf; + if(bytehook_init(BYTEHOOK_MODE_AUTOMATIC, false) == BYTEHOOK_STATUS_CODE_OK) { + bytehook_hook_all(NULL, + "exit", + &custom_exit, + NULL, + NULL); + }else { + atexit(custom_atexit); } - - return JLI_Launch(argc, argv, - sizeof(const_jargs) / sizeof(char *), const_jargs, - sizeof(const_appclasspath) / sizeof(char *), const_appclasspath, - FULL_VERSION, - DOT_VERSION, - (const_progname != NULL) ? const_progname : *argv, - (const_launcher != NULL) ? const_launcher : *argv, - (const_jargs != NULL) ? JNI_TRUE : JNI_FALSE, - const_cpwildcard, const_javaw, const_ergo_class); - } \ No newline at end of file diff --git a/FCLauncher/src/main/jni/fcl/jre_launcher.c b/FCLauncher/src/main/jni/fcl/jre_launcher.c new file mode 100644 index 00000000..5fd846ae --- /dev/null +++ b/FCLauncher/src/main/jni/fcl/jre_launcher.c @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include +#include +#include +#include +#include +#include +#include +#include +// Boardwalk: missing include +#include + +#include "include/fcl_internal.h" + + +// Uncomment to try redirect signal handling to JVM +// #define TRY_SIG2JVM + +// PojavLancher: fixme: are these wrong? +#define FULL_VERSION "1.8.0-internal" +#define DOT_VERSION "1.8" + +static const char* const_progname = "java"; +static const char* const_launcher = "openjdk"; +static const char** const_jargs = NULL; +static const char** const_appclasspath = NULL; +static const jboolean const_javaw = JNI_FALSE; +static const jboolean const_cpwildcard = JNI_TRUE; +static const jint const_ergo_class = 0; // DEFAULT_POLICY +static struct sigaction old_sa[NSIG]; + +void (*__old_sa)(int signal, siginfo_t *info, void *reserved); +int (*JVM_handle_linux_signal)(int signo, siginfo_t* siginfo, void* ucontext, int abort_if_unrecognized); + +void android_sigaction(int signal, siginfo_t *info, void *reserved) { + printf("process killed with signal %d code %p addr %p\n", signal,info->si_code,info->si_addr); + if (JVM_handle_linux_signal == NULL) { // should not happen, but still + __old_sa = old_sa[signal].sa_sigaction; + __old_sa(signal,info,reserved); + exit(1); + } else { + // Based on https://github.com/PojavLauncherTeam/openjdk-multiarch-jdk8u/blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/os/linux/vm/os_linux.cpp#L4688-4693 + int orig_errno = errno; // Preserve errno value over signal handler. + JVM_handle_linux_signal(signal, info, reserved, true); + errno = orig_errno; + } +} +typedef jint JNI_CreateJavaVM_func(JavaVM **pvm, void **penv, void *args); + +typedef jint JLI_Launch_func(int argc, char ** argv, /* main argc, argc */ + int jargc, const char** jargv, /* java args */ + int appclassc, const char** appclassv, /* app classpath */ + const char* fullversion, /* full version defined */ + const char* dotversion, /* dot version defined */ + const char* pname, /* program name */ + const char* lname, /* launcher name */ + jboolean javaargs, /* JAVA_ARGS */ + jboolean cpwildcard, /* classpath wildcard*/ + jboolean javaw, /* windows-only javaw */ + jint ergo /* ergonomics class policy */ +); + +static jint launchJVM(int margc, char** margv) { + void* libjli = dlopen("libjli.so", RTLD_LAZY | RTLD_GLOBAL); + + // Boardwalk: silence + // LOGD("JLI lib = %x", (int)libjli); + if (NULL == libjli) { + FCL_INTERNAL_LOG("JLI lib = NULL: %s", dlerror()); + return -1; + } + FCL_INTERNAL_LOG("Found JLI lib"); + + JLI_Launch_func *pJLI_Launch = + (JLI_Launch_func *)dlsym(libjli, "JLI_Launch"); + // Boardwalk: silence + // LOGD("JLI_Launch = 0x%x", *(int*)&pJLI_Launch); + + if (NULL == pJLI_Launch) { + FCL_INTERNAL_LOG("JLI_Launch = NULL"); + return -1; + } + + FCL_INTERNAL_LOG("Calling JLI_Launch"); + + return pJLI_Launch(margc, margv, + 0, NULL, // sizeof(const_jargs) / sizeof(char *), const_jargs, + 0, NULL, // sizeof(const_appclasspath) / sizeof(char *), const_appclasspath, + FULL_VERSION, + DOT_VERSION, + *margv, // (const_progname != NULL) ? const_progname : *margv, + *margv, // (const_launcher != NULL) ? const_launcher : *margv, + (const_jargs != NULL) ? JNI_TRUE : JNI_FALSE, + const_cpwildcard, const_javaw, const_ergo_class); +/* + return pJLI_Launch(argc, argv, + 0, NULL, 0, NULL, FULL_VERSION, + DOT_VERSION, *margv, *margv, // "java", "openjdk", + JNI_FALSE, JNI_TRUE, JNI_FALSE, 0); +*/ +} + +char** convert_to_char_array(JNIEnv *env, jobjectArray jstringArray) { + int num_rows = (*env)->GetArrayLength(env, jstringArray); + char **cArray = (char **) malloc(num_rows * sizeof(char*)); + jstring row; + + for (int i = 0; i < num_rows; i++) { + row = (jstring) (*env)->GetObjectArrayElement(env, jstringArray, i); + cArray[i] = (char*)(*env)->GetStringUTFChars(env, row, 0); + } + + return cArray; +} + + +void free_char_array(JNIEnv *env, jobjectArray jstringArray, const char **charArray) { + int num_rows = (*env)->GetArrayLength(env, jstringArray); + jstring row; + + for (int i = 0; i < num_rows; i++) { + row = (jstring) (*env)->GetObjectArrayElement(env, jstringArray, i); + (*env)->ReleaseStringUTFChars(env, row, charArray[i]); + } +} + +/* + * Class: com_oracle_dalvik_VMLauncher + * Method: launchJVM + * Signature: ([Ljava/lang/String;)I + */ + +jint JNICALL Java_com_oracle_dalvik_VMLauncher_launchJVM(JNIEnv *env, jclass clazz, jobjectArray argsArray) { +#ifdef TRY_SIG2JVM + void* libjvm = dlopen("libjvm.so", RTLD_LAZY | RTLD_GLOBAL); + if (NULL == libjvm) { + LOGE("JVM lib = NULL: %s", dlerror()); + return -1; + } + JVM_handle_linux_signal = dlsym(libjvm, "JVM_handle_linux_signal"); +#endif + + jint res = 0; + // int i; + //Prepare the signal trapper + struct sigaction catcher; + memset(&catcher,0,sizeof(sigaction)); + catcher.sa_sigaction = android_sigaction; + catcher.sa_flags = SA_SIGINFO|SA_RESTART; + // SA_RESETHAND; +#define CATCHSIG(X) sigaction(X, &catcher, &old_sa[X]) + CATCHSIG(SIGILL); + //CATCHSIG(SIGABRT); + CATCHSIG(SIGBUS); + CATCHSIG(SIGFPE); +#ifdef TRY_SIG2JVM + CATCHSIG(SIGSEGV); +#endif + CATCHSIG(SIGSTKFLT); + CATCHSIG(SIGPIPE); + CATCHSIG(SIGXFSZ); + //Signal trapper ready + + // Save dalvik JNIEnv pointer for JVM launch thread +// pojav_environ->dalvikJNIEnvPtr_ANDROID = env; + + if (argsArray == NULL) { + FCL_INTERNAL_LOG("Args array null, returning"); + //handle error + return 0; + } + + int argc = (*env)->GetArrayLength(env, argsArray); + char **argv = convert_to_char_array(env, argsArray); + + FCL_INTERNAL_LOG("Done processing args"); + + res = launchJVM(argc, argv); + + FCL_INTERNAL_LOG("Going to free args"); + free_char_array(env, argsArray, argv); + + FCL_INTERNAL_LOG("Free done"); + + return res; +} diff --git a/FCLauncher/src/main/jni/xhook/include/queue.h b/FCLauncher/src/main/jni/xhook/include/queue.h deleted file mode 100644 index c2443bef..00000000 --- a/FCLauncher/src/main/jni/xhook/include/queue.h +++ /dev/null @@ -1,554 +0,0 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)queue.h 8.5 (Berkeley) 8/20/94 - * $FreeBSD: stable/9/sys/sys/queue.h 252365 2013-06-29 04:25:40Z lstewart $ - */ - -#ifndef QUEUE_H -#define QUEUE_H - -/* #include */ -#define __containerof(ptr, type, field) ((type *)((char *)(ptr) - ((char *)&((type *)0)->field))) - -/* - * This file defines four types of data structures: singly-linked lists, - * singly-linked tail queues, lists and tail queues. - * - * A singly-linked list is headed by a single forward pointer. The elements - * are singly linked for minimum space and pointer manipulation overhead at - * the expense of O(n) removal for arbitrary elements. New elements can be - * added to the list after an existing element or at the head of the list. - * Elements being removed from the head of the list should use the explicit - * macro for this purpose for optimum efficiency. A singly-linked list may - * only be traversed in the forward direction. Singly-linked lists are ideal - * for applications with large datasets and few or no removals or for - * implementing a LIFO queue. - * - * A singly-linked tail queue is headed by a pair of pointers, one to the - * head of the list and the other to the tail of the list. The elements are - * singly linked for minimum space and pointer manipulation overhead at the - * expense of O(n) removal for arbitrary elements. New elements can be added - * to the list after an existing element, at the head of the list, or at the - * end of the list. Elements being removed from the head of the tail queue - * should use the explicit macro for this purpose for optimum efficiency. - * A singly-linked tail queue may only be traversed in the forward direction. - * Singly-linked tail queues are ideal for applications with large datasets - * and few or no removals or for implementing a FIFO queue. - * - * A list is headed by a single forward pointer (or an array of forward - * pointers for a hash table header). The elements are doubly linked - * so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before - * or after an existing element or at the head of the list. A list - * may be traversed in either direction. - * - * A tail queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or - * after an existing element, at the head of the list, or at the end of - * the list. A tail queue may be traversed in either direction. - * - * For details on the use of these macros, see the queue(3) manual page. - * - * SLIST LIST STAILQ TAILQ - * _HEAD + + + + - * _HEAD_INITIALIZER + + + + - * _ENTRY + + + + - * _INIT + + + + - * _EMPTY + + + + - * _FIRST + + + + - * _NEXT + + + + - * _PREV - + - + - * _LAST - - + + - * _FOREACH + + + + - * _FOREACH_FROM + + + + - * _FOREACH_SAFE + + + + - * _FOREACH_FROM_SAFE + + + + - * _FOREACH_REVERSE - - - + - * _FOREACH_REVERSE_FROM - - - + - * _FOREACH_REVERSE_SAFE - - - + - * _FOREACH_REVERSE_FROM_SAFE - - - + - * _INSERT_HEAD + + + + - * _INSERT_BEFORE - + - + - * _INSERT_AFTER + + + + - * _INSERT_TAIL - - + + - * _CONCAT - - + + - * _REMOVE_AFTER + - + - - * _REMOVE_HEAD + - + - - * _REMOVE + + + + - * _SWAP + + + + - * - */ - -/* - * Singly-linked List declarations. - */ -#define SLIST_HEAD(name, type, qual) \ - struct name { \ - struct type *qual slh_first; /* first element */ \ - } - -#define SLIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define SLIST_ENTRY(type, qual) \ - struct { \ - struct type *qual sle_next; /* next element */ \ - } - -/* - * Singly-linked List functions. - */ -#define SLIST_INIT(head) do { \ - SLIST_FIRST((head)) = NULL; \ - } while (0) - -#define SLIST_EMPTY(head) ((head)->slh_first == NULL) - -#define SLIST_FIRST(head) ((head)->slh_first) - -#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) - -#define SLIST_FOREACH(var, head, field) \ - for ((var) = SLIST_FIRST((head)); \ - (var); \ - (var) = SLIST_NEXT((var), field)) - -#define SLIST_FOREACH_FROM(var, head, field) \ - for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \ - (var); \ - (var) = SLIST_NEXT((var), field)) - -#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = SLIST_FIRST((head)); \ - (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define SLIST_FOREACH_FROM_SAFE(var, head, field, tvar) \ - for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \ - (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define SLIST_INSERT_HEAD(head, elm, field) do { \ - SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ - SLIST_FIRST((head)) = (elm); \ - } while (0) - -#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ - SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ - SLIST_NEXT((slistelm), field) = (elm); \ - } while (0) - -#define SLIST_REMOVE_AFTER(elm, field) do { \ - SLIST_NEXT(elm, field) = \ - SLIST_NEXT(SLIST_NEXT(elm, field), field); \ - } while (0) - -#define SLIST_REMOVE_HEAD(head, field) do { \ - SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ - } while (0) - -#define SLIST_REMOVE(head, elm, type, field) do { \ - if (SLIST_FIRST((head)) == (elm)) { \ - SLIST_REMOVE_HEAD((head), field); \ - } \ - else { \ - struct type *curelm = SLIST_FIRST((head)); \ - while (SLIST_NEXT(curelm, field) != (elm)) \ - curelm = SLIST_NEXT(curelm, field); \ - SLIST_REMOVE_AFTER(curelm, field); \ - } \ - } while (0) - -#define SLIST_SWAP(head1, head2, type) do { \ - struct type *swap_first = SLIST_FIRST(head1); \ - SLIST_FIRST(head1) = SLIST_FIRST(head2); \ - SLIST_FIRST(head2) = swap_first; \ - } while (0) - -/* - * List declarations. - */ -#define LIST_HEAD(name, type, qual) \ - struct name { \ - struct type *qual lh_first; /* first element */ \ - } - -#define LIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define LIST_ENTRY(type, qual) \ - struct { \ - struct type *qual le_next; /* next element */ \ - struct type *qual *le_prev; /* address of previous next element */ \ - } - -/* - * List functions. - */ -#define LIST_INIT(head) do { \ - LIST_FIRST((head)) = NULL; \ - } while (0) - -#define LIST_EMPTY(head) ((head)->lh_first == NULL) - -#define LIST_FIRST(head) ((head)->lh_first) - -#define LIST_NEXT(elm, field) ((elm)->field.le_next) - -#define LIST_PREV(elm, head, type, field) \ - ((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \ - __containerof((elm)->field.le_prev, struct type, field.le_next)) - -#define LIST_FOREACH(var, head, field) \ - for ((var) = LIST_FIRST((head)); \ - (var); \ - (var) = LIST_NEXT((var), field)) - -#define LIST_FOREACH_FROM(var, head, field) \ - for ((var) = ((var) ? (var) : LIST_FIRST((head))); \ - (var); \ - (var) = LIST_NEXT((var), field)) - -#define LIST_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = LIST_FIRST((head)); \ - (var) && ((tvar) = LIST_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define LIST_FOREACH_FROM_SAFE(var, head, field, tvar) \ - for ((var) = ((var) ? (var) : LIST_FIRST((head))); \ - (var) && ((tvar) = LIST_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define LIST_INSERT_HEAD(head, elm, field) do { \ - if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ - LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field); \ - LIST_FIRST((head)) = (elm); \ - (elm)->field.le_prev = &LIST_FIRST((head)); \ - } while (0) - -#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ - (elm)->field.le_prev = (listelm)->field.le_prev; \ - LIST_NEXT((elm), field) = (listelm); \ - *(listelm)->field.le_prev = (elm); \ - (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ - } while (0) - -#define LIST_INSERT_AFTER(listelm, elm, field) do { \ - if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL) \ - LIST_NEXT((listelm), field)->field.le_prev = \ - &LIST_NEXT((elm), field); \ - LIST_NEXT((listelm), field) = (elm); \ - (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ - } while (0) - -#define LIST_REMOVE(elm, field) do { \ - if (LIST_NEXT((elm), field) != NULL) \ - LIST_NEXT((elm), field)->field.le_prev = \ - (elm)->field.le_prev; \ - *(elm)->field.le_prev = LIST_NEXT((elm), field); \ - } while (0) - -#define LIST_SWAP(head1, head2, type, field) do { \ - struct type *swap_tmp = LIST_FIRST((head1)); \ - LIST_FIRST((head1)) = LIST_FIRST((head2)); \ - LIST_FIRST((head2)) = swap_tmp; \ - if ((swap_tmp = LIST_FIRST((head1))) != NULL) \ - swap_tmp->field.le_prev = &LIST_FIRST((head1)); \ - if ((swap_tmp = LIST_FIRST((head2))) != NULL) \ - swap_tmp->field.le_prev = &LIST_FIRST((head2)); \ - } while (0) - -/* - * Singly-linked Tail queue declarations. - */ -#define STAILQ_HEAD(name, type, qual) \ - struct name { \ - struct type *qual stqh_first;/* first element */ \ - struct type *qual *stqh_last;/* addr of last next element */ \ - } - -#define STAILQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).stqh_first } - -#define STAILQ_ENTRY(type, qual) \ - struct { \ - struct type *qual stqe_next; /* next element */ \ - } - -/* - * Singly-linked Tail queue functions. - */ -#define STAILQ_INIT(head) do { \ - STAILQ_FIRST((head)) = NULL; \ - (head)->stqh_last = &STAILQ_FIRST((head)); \ - } while (0) - -#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) - -#define STAILQ_FIRST(head) ((head)->stqh_first) - -#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) - -#define STAILQ_LAST(head, type, field) \ - (STAILQ_EMPTY((head)) ? NULL : \ - __containerof((head)->stqh_last, struct type, field.stqe_next)) - -#define STAILQ_FOREACH(var, head, field) \ - for((var) = STAILQ_FIRST((head)); \ - (var); \ - (var) = STAILQ_NEXT((var), field)) - -#define STAILQ_FOREACH_FROM(var, head, field) \ - for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \ - (var); \ - (var) = STAILQ_NEXT((var), field)) - -#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = STAILQ_FIRST((head)); \ - (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define STAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \ - for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \ - (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define STAILQ_INSERT_HEAD(head, elm, field) do { \ - if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ - STAILQ_FIRST((head)) = (elm); \ - } while (0) - -#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ - if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL) \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ - STAILQ_NEXT((tqelm), field) = (elm); \ - } while (0) - -#define STAILQ_INSERT_TAIL(head, elm, field) do { \ - STAILQ_NEXT((elm), field) = NULL; \ - *(head)->stqh_last = (elm); \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ - } while (0) - -#define STAILQ_CONCAT(head1, head2) do { \ - if (!STAILQ_EMPTY((head2))) { \ - *(head1)->stqh_last = (head2)->stqh_first; \ - (head1)->stqh_last = (head2)->stqh_last; \ - STAILQ_INIT((head2)); \ - } \ - } while (0) - -#define STAILQ_REMOVE_AFTER(head, elm, field) do { \ - if ((STAILQ_NEXT(elm, field) = \ - STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ - } while (0) - -#define STAILQ_REMOVE_HEAD(head, field) do { \ - if ((STAILQ_FIRST((head)) = \ - STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ - (head)->stqh_last = &STAILQ_FIRST((head)); \ - } while (0) - -#define STAILQ_REMOVE(head, elm, type, field) do { \ - if (STAILQ_FIRST((head)) == (elm)) { \ - STAILQ_REMOVE_HEAD((head), field); \ - } \ - else { \ - struct type *curelm = STAILQ_FIRST((head)); \ - while (STAILQ_NEXT(curelm, field) != (elm)) \ - curelm = STAILQ_NEXT(curelm, field); \ - STAILQ_REMOVE_AFTER(head, curelm, field); \ - } \ - } while (0) - -#define STAILQ_SWAP(head1, head2, type) do { \ - struct type *swap_first = STAILQ_FIRST(head1); \ - struct type **swap_last = (head1)->stqh_last; \ - STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \ - (head1)->stqh_last = (head2)->stqh_last; \ - STAILQ_FIRST(head2) = swap_first; \ - (head2)->stqh_last = swap_last; \ - if (STAILQ_EMPTY(head1)) \ - (head1)->stqh_last = &STAILQ_FIRST(head1); \ - if (STAILQ_EMPTY(head2)) \ - (head2)->stqh_last = &STAILQ_FIRST(head2); \ - } while (0) - -/* - * Tail queue declarations. - */ -#define TAILQ_HEAD(name, type, qual) \ - struct name { \ - struct type *qual tqh_first; /* first element */ \ - struct type *qual *tqh_last; /* addr of last next element */ \ -} - -#define TAILQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).tqh_first } - -#define TAILQ_ENTRY(type, qual) \ - struct { \ - struct type *qual tqe_next; /* next element */ \ - struct type *qual *tqe_prev; /* address of previous next element */ \ - } - -/* - * Tail queue functions. - */ -#define TAILQ_INIT(head) do { \ - TAILQ_FIRST((head)) = NULL; \ - (head)->tqh_last = &TAILQ_FIRST((head)); \ - } while (0) - -#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) - -#define TAILQ_FIRST(head) ((head)->tqh_first) - -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) - -#define TAILQ_PREV(elm, headname, field) \ - (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) - -#define TAILQ_LAST(head, headname) \ - (*(((struct headname *)((head)->tqh_last))->tqh_last)) - -#define TAILQ_FOREACH(var, head, field) \ - for ((var) = TAILQ_FIRST((head)); \ - (var); \ - (var) = TAILQ_NEXT((var), field)) - -#define TAILQ_FOREACH_FROM(var, head, field) \ - for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \ - (var); \ - (var) = TAILQ_NEXT((var), field)) - -#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = TAILQ_FIRST((head)); \ - (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \ - for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \ - (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ - for ((var) = TAILQ_LAST((head), headname); \ - (var); \ - (var) = TAILQ_PREV((var), headname, field)) - -#define TAILQ_FOREACH_REVERSE_FROM(var, head, headname, field) \ - for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \ - (var); \ - (var) = TAILQ_PREV((var), headname, field)) - -#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ - for ((var) = TAILQ_LAST((head), headname); \ - (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ - (var) = (tvar)) - -#define TAILQ_FOREACH_REVERSE_FROM_SAFE(var, head, headname, field, tvar) \ - for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \ - (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ - (var) = (tvar)) - -#define TAILQ_INSERT_HEAD(head, elm, field) do { \ - if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ - TAILQ_FIRST((head))->field.tqe_prev = \ - &TAILQ_NEXT((elm), field); \ - else \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ - TAILQ_FIRST((head)) = (elm); \ - (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ - } while (0) - -#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ - (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ - TAILQ_NEXT((elm), field) = (listelm); \ - *(listelm)->field.tqe_prev = (elm); \ - (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ - } while (0) - -#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ - if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL) \ - TAILQ_NEXT((elm), field)->field.tqe_prev = \ - &TAILQ_NEXT((elm), field); \ - else \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ - TAILQ_NEXT((listelm), field) = (elm); \ - (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ - } while (0) - -#define TAILQ_INSERT_TAIL(head, elm, field) do { \ - TAILQ_NEXT((elm), field) = NULL; \ - (elm)->field.tqe_prev = (head)->tqh_last; \ - *(head)->tqh_last = (elm); \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ - } while (0) - -#define TAILQ_CONCAT(head1, head2, field) do { \ - if (!TAILQ_EMPTY(head2)) { \ - *(head1)->tqh_last = (head2)->tqh_first; \ - (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ - (head1)->tqh_last = (head2)->tqh_last; \ - TAILQ_INIT((head2)); \ - } \ - } while (0) - -#define TAILQ_REMOVE(head, elm, field) do { \ - if ((TAILQ_NEXT((elm), field)) != NULL) \ - TAILQ_NEXT((elm), field)->field.tqe_prev = \ - (elm)->field.tqe_prev; \ - else \ - (head)->tqh_last = (elm)->field.tqe_prev; \ - *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ - } while (0) - -#define TAILQ_SWAP(head1, head2, type, field) do { \ - struct type *swap_first = (head1)->tqh_first; \ - struct type **swap_last = (head1)->tqh_last; \ - (head1)->tqh_first = (head2)->tqh_first; \ - (head1)->tqh_last = (head2)->tqh_last; \ - (head2)->tqh_first = swap_first; \ - (head2)->tqh_last = swap_last; \ - if ((swap_first = (head1)->tqh_first) != NULL) \ - swap_first->field.tqe_prev = &(head1)->tqh_first; \ - else \ - (head1)->tqh_last = &(head1)->tqh_first; \ - if ((swap_first = (head2)->tqh_first) != NULL) \ - swap_first->field.tqe_prev = &(head2)->tqh_first; \ - else \ - (head2)->tqh_last = &(head2)->tqh_first; \ - } while (0) - -#endif diff --git a/FCLauncher/src/main/jni/xhook/include/tree.h b/FCLauncher/src/main/jni/xhook/include/tree.h deleted file mode 100644 index dc938ae5..00000000 --- a/FCLauncher/src/main/jni/xhook/include/tree.h +++ /dev/null @@ -1,768 +0,0 @@ -/* $NetBSD: tree.h,v 1.8 2004/03/28 19:38:30 provos Exp $ */ -/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */ -/* $FreeBSD: stable/9/sys/sys/tree.h 189204 2009-03-01 04:57:23Z bms $ */ - -/*- - * Copyright 2002 Niels Provos - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TREE_H -#define TREE_H - -/* #include */ -#ifndef __unused -#define __unused __attribute__((__unused__)) -#endif - -/* - * This file defines data structures for different types of trees: - * splay trees and red-black trees. - * - * A splay tree is a self-organizing data structure. Every operation - * on the tree causes a splay to happen. The splay moves the requested - * node to the root of the tree and partly rebalances it. - * - * This has the benefit that request locality causes faster lookups as - * the requested nodes move to the top of the tree. On the other hand, - * every lookup causes memory writes. - * - * The Balance Theorem bounds the total access time for m operations - * and n inserts on an initially empty tree as O((m + n)lg n). The - * amortized cost for a sequence of m accesses to a splay tree is O(lg n); - * - * A red-black tree is a binary search tree with the node color as an - * extra attribute. It fulfills a set of conditions: - * - every search path from the root to a leaf consists of the - * same number of black nodes, - * - each red node (except for the root) has a black parent, - * - each leaf node is black. - * - * Every operation on a red-black tree is bounded as O(lg n). - * The maximum height of a red-black tree is 2lg (n+1). - */ - -#define SPLAY_HEAD(name, type) \ -struct name { \ - struct type *sph_root; /* root of the tree */ \ -} - -#define SPLAY_INITIALIZER(root) \ - { NULL } - -#define SPLAY_INIT(root) do { \ - (root)->sph_root = NULL; \ -} while (/*CONSTCOND*/ 0) - -#define SPLAY_ENTRY(type) \ -struct { \ - struct type *spe_left; /* left element */ \ - struct type *spe_right; /* right element */ \ -} - -#define SPLAY_LEFT(elm, field) (elm)->field.spe_left -#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right -#define SPLAY_ROOT(head) (head)->sph_root -#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) - -/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ -#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ - SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ - SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ - (head)->sph_root = tmp; \ -} while (/*CONSTCOND*/ 0) - -#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ - SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ - SPLAY_LEFT(tmp, field) = (head)->sph_root; \ - (head)->sph_root = tmp; \ -} while (/*CONSTCOND*/ 0) - -#define SPLAY_LINKLEFT(head, tmp, field) do { \ - SPLAY_LEFT(tmp, field) = (head)->sph_root; \ - tmp = (head)->sph_root; \ - (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ -} while (/*CONSTCOND*/ 0) - -#define SPLAY_LINKRIGHT(head, tmp, field) do { \ - SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ - tmp = (head)->sph_root; \ - (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ -} while (/*CONSTCOND*/ 0) - -#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ - SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ - SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ - SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ - SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ -} while (/*CONSTCOND*/ 0) - -/* Generates prototypes and inline functions */ - -#define SPLAY_PROTOTYPE(name, type, field, cmp) \ -void name##_SPLAY(struct name *, struct type *); \ -void name##_SPLAY_MINMAX(struct name *, int); \ -struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ -struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ - \ -/* Finds the node with the same key as elm */ \ -static __inline struct type * \ -name##_SPLAY_FIND(struct name *head, struct type *elm) \ -{ \ - if (SPLAY_EMPTY(head)) \ - return(NULL); \ - name##_SPLAY(head, elm); \ - if ((cmp)(elm, (head)->sph_root) == 0) \ - return (head->sph_root); \ - return (NULL); \ -} \ - \ -static __inline struct type * \ -name##_SPLAY_NEXT(struct name *head, struct type *elm) \ -{ \ - name##_SPLAY(head, elm); \ - if (SPLAY_RIGHT(elm, field) != NULL) { \ - elm = SPLAY_RIGHT(elm, field); \ - while (SPLAY_LEFT(elm, field) != NULL) { \ - elm = SPLAY_LEFT(elm, field); \ - } \ - } else \ - elm = NULL; \ - return (elm); \ -} \ - \ -static __inline struct type * \ -name##_SPLAY_MIN_MAX(struct name *head, int val) \ -{ \ - name##_SPLAY_MINMAX(head, val); \ - return (SPLAY_ROOT(head)); \ -} - -/* Main splay operation. - * Moves node close to the key of elm to top - */ -#define SPLAY_GENERATE(name, type, field, cmp) \ -struct type * \ -name##_SPLAY_INSERT(struct name *head, struct type *elm) \ -{ \ - if (SPLAY_EMPTY(head)) { \ - SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ - } else { \ - int __comp; \ - name##_SPLAY(head, elm); \ - __comp = (cmp)(elm, (head)->sph_root); \ - if(__comp < 0) { \ - SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ - SPLAY_RIGHT(elm, field) = (head)->sph_root; \ - SPLAY_LEFT((head)->sph_root, field) = NULL; \ - } else if (__comp > 0) { \ - SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ - SPLAY_LEFT(elm, field) = (head)->sph_root; \ - SPLAY_RIGHT((head)->sph_root, field) = NULL; \ - } else \ - return ((head)->sph_root); \ - } \ - (head)->sph_root = (elm); \ - return (NULL); \ -} \ - \ -struct type * \ -name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ -{ \ - struct type *__tmp; \ - if (SPLAY_EMPTY(head)) \ - return (NULL); \ - name##_SPLAY(head, elm); \ - if ((cmp)(elm, (head)->sph_root) == 0) { \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ - (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ - } else { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ - name##_SPLAY(head, elm); \ - SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ - } \ - return (elm); \ - } \ - return (NULL); \ -} \ - \ -void \ -name##_SPLAY(struct name *head, struct type *elm) \ -{ \ - struct type __node, *__left, *__right, *__tmp; \ - int __comp; \ -\ - SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ - __left = __right = &__node; \ -\ - while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \ - if (__comp < 0) { \ - __tmp = SPLAY_LEFT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if ((cmp)(elm, __tmp) < 0){ \ - SPLAY_ROTATE_RIGHT(head, __tmp, field); \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKLEFT(head, __right, field); \ - } else if (__comp > 0) { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if ((cmp)(elm, __tmp) > 0){ \ - SPLAY_ROTATE_LEFT(head, __tmp, field); \ - if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKRIGHT(head, __left, field); \ - } \ - } \ - SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ -} \ - \ -/* Splay with either the minimum or the maximum element \ - * Used to find minimum or maximum element in tree. \ - */ \ -void name##_SPLAY_MINMAX(struct name *head, int __comp) \ -{ \ - struct type __node, *__left, *__right, *__tmp; \ -\ - SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ - __left = __right = &__node; \ -\ - while (1) { \ - if (__comp < 0) { \ - __tmp = SPLAY_LEFT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if (__comp < 0){ \ - SPLAY_ROTATE_RIGHT(head, __tmp, field); \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKLEFT(head, __right, field); \ - } else if (__comp > 0) { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if (__comp > 0) { \ - SPLAY_ROTATE_LEFT(head, __tmp, field); \ - if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKRIGHT(head, __left, field); \ - } \ - } \ - SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ -} - -#define SPLAY_NEGINF -1 -#define SPLAY_INF 1 - -#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) -#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) -#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) -#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) -#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ - : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) -#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ - : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) - -#define SPLAY_FOREACH(x, name, head) \ - for ((x) = SPLAY_MIN(name, head); \ - (x) != NULL; \ - (x) = SPLAY_NEXT(name, head, x)) - -/* Macros that define a red-black tree */ -#define RB_HEAD(name, type) \ -struct name { \ - struct type *rbh_root; /* root of the tree */ \ -} - -#define RB_INITIALIZER(root) \ - { NULL } - -#define RB_INIT(root) do { \ - (root)->rbh_root = NULL; \ -} while (/*CONSTCOND*/ 0) - -#define RB_BLACK 0 -#define RB_RED 1 -#define RB_ENTRY(type) \ -struct { \ - struct type *rbe_left; /* left element */ \ - struct type *rbe_right; /* right element */ \ - struct type *rbe_parent; /* parent element */ \ - int rbe_color; /* node color */ \ -} - -#define RB_LEFT(elm, field) (elm)->field.rbe_left -#define RB_RIGHT(elm, field) (elm)->field.rbe_right -#define RB_PARENT(elm, field) (elm)->field.rbe_parent -#define RB_COLOR(elm, field) (elm)->field.rbe_color -#define RB_ROOT(head) (head)->rbh_root -#define RB_EMPTY(head) (RB_ROOT(head) == NULL) - -#define RB_SET(elm, parent, field) do { \ - RB_PARENT(elm, field) = parent; \ - RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ - RB_COLOR(elm, field) = RB_RED; \ -} while (/*CONSTCOND*/ 0) - -#define RB_SET_BLACKRED(black, red, field) do { \ - RB_COLOR(black, field) = RB_BLACK; \ - RB_COLOR(red, field) = RB_RED; \ -} while (/*CONSTCOND*/ 0) - -#ifndef RB_AUGMENT -#define RB_AUGMENT(x) do {} while (0) -#endif - -#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ - (tmp) = RB_RIGHT(elm, field); \ - if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \ - RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ - } \ - RB_AUGMENT(elm); \ - if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ - if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ - RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ - else \ - RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ - } else \ - (head)->rbh_root = (tmp); \ - RB_LEFT(tmp, field) = (elm); \ - RB_PARENT(elm, field) = (tmp); \ - RB_AUGMENT(tmp); \ - if ((RB_PARENT(tmp, field))) \ - RB_AUGMENT(RB_PARENT(tmp, field)); \ -} while (/*CONSTCOND*/ 0) - -#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ - (tmp) = RB_LEFT(elm, field); \ - if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \ - RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ - } \ - RB_AUGMENT(elm); \ - if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ - if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ - RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ - else \ - RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ - } else \ - (head)->rbh_root = (tmp); \ - RB_RIGHT(tmp, field) = (elm); \ - RB_PARENT(elm, field) = (tmp); \ - RB_AUGMENT(tmp); \ - if ((RB_PARENT(tmp, field))) \ - RB_AUGMENT(RB_PARENT(tmp, field)); \ -} while (/*CONSTCOND*/ 0) - -/* Generates prototypes and inline functions */ -#define RB_PROTOTYPE(name, type, field, cmp) \ - RB_PROTOTYPE_INTERNAL(name, type, field, cmp,) -#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ - RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static) -#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ -attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \ -attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ -attr struct type *name##_RB_REMOVE(struct name *, struct type *); \ -attr struct type *name##_RB_INSERT(struct name *, struct type *); \ -attr struct type *name##_RB_FIND(struct name *, struct type *); \ -attr struct type *name##_RB_NFIND(struct name *, struct type *); \ -attr struct type *name##_RB_NEXT(struct type *); \ -attr struct type *name##_RB_PREV(struct type *); \ -attr struct type *name##_RB_MINMAX(struct name *, int); \ - \ - -/* Main rb operation. - * Moves node close to the key of elm to top - */ -#define RB_GENERATE(name, type, field, cmp) \ - RB_GENERATE_INTERNAL(name, type, field, cmp,) -#define RB_GENERATE_STATIC(name, type, field, cmp) \ - RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static) -#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ -attr void \ -name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ -{ \ - struct type *parent, *gparent, *tmp; \ - while ((parent = RB_PARENT(elm, field)) != NULL && \ - RB_COLOR(parent, field) == RB_RED) { \ - gparent = RB_PARENT(parent, field); \ - if (parent == RB_LEFT(gparent, field)) { \ - tmp = RB_RIGHT(gparent, field); \ - if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ - RB_COLOR(tmp, field) = RB_BLACK; \ - RB_SET_BLACKRED(parent, gparent, field);\ - elm = gparent; \ - continue; \ - } \ - if (RB_RIGHT(parent, field) == elm) { \ - RB_ROTATE_LEFT(head, parent, tmp, field);\ - tmp = parent; \ - parent = elm; \ - elm = tmp; \ - } \ - RB_SET_BLACKRED(parent, gparent, field); \ - RB_ROTATE_RIGHT(head, gparent, tmp, field); \ - } else { \ - tmp = RB_LEFT(gparent, field); \ - if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ - RB_COLOR(tmp, field) = RB_BLACK; \ - RB_SET_BLACKRED(parent, gparent, field);\ - elm = gparent; \ - continue; \ - } \ - if (RB_LEFT(parent, field) == elm) { \ - RB_ROTATE_RIGHT(head, parent, tmp, field);\ - tmp = parent; \ - parent = elm; \ - elm = tmp; \ - } \ - RB_SET_BLACKRED(parent, gparent, field); \ - RB_ROTATE_LEFT(head, gparent, tmp, field); \ - } \ - } \ - RB_COLOR(head->rbh_root, field) = RB_BLACK; \ -} \ - \ -attr void \ -name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ -{ \ - struct type *tmp; \ - while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ - elm != RB_ROOT(head)) { \ - if (RB_LEFT(parent, field) == elm) { \ - tmp = RB_RIGHT(parent, field); \ - if (RB_COLOR(tmp, field) == RB_RED) { \ - RB_SET_BLACKRED(tmp, parent, field); \ - RB_ROTATE_LEFT(head, parent, tmp, field);\ - tmp = RB_RIGHT(parent, field); \ - } \ - if ((RB_LEFT(tmp, field) == NULL || \ - RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ - (RB_RIGHT(tmp, field) == NULL || \ - RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ - RB_COLOR(tmp, field) = RB_RED; \ - elm = parent; \ - parent = RB_PARENT(elm, field); \ - } else { \ - if (RB_RIGHT(tmp, field) == NULL || \ - RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ - struct type *oleft; \ - if ((oleft = RB_LEFT(tmp, field)) \ - != NULL) \ - RB_COLOR(oleft, field) = RB_BLACK;\ - RB_COLOR(tmp, field) = RB_RED; \ - RB_ROTATE_RIGHT(head, tmp, oleft, field);\ - tmp = RB_RIGHT(parent, field); \ - } \ - RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ - RB_COLOR(parent, field) = RB_BLACK; \ - if (RB_RIGHT(tmp, field)) \ - RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ - RB_ROTATE_LEFT(head, parent, tmp, field);\ - elm = RB_ROOT(head); \ - break; \ - } \ - } else { \ - tmp = RB_LEFT(parent, field); \ - if (RB_COLOR(tmp, field) == RB_RED) { \ - RB_SET_BLACKRED(tmp, parent, field); \ - RB_ROTATE_RIGHT(head, parent, tmp, field);\ - tmp = RB_LEFT(parent, field); \ - } \ - if ((RB_LEFT(tmp, field) == NULL || \ - RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ - (RB_RIGHT(tmp, field) == NULL || \ - RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ - RB_COLOR(tmp, field) = RB_RED; \ - elm = parent; \ - parent = RB_PARENT(elm, field); \ - } else { \ - if (RB_LEFT(tmp, field) == NULL || \ - RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ - struct type *oright; \ - if ((oright = RB_RIGHT(tmp, field)) \ - != NULL) \ - RB_COLOR(oright, field) = RB_BLACK;\ - RB_COLOR(tmp, field) = RB_RED; \ - RB_ROTATE_LEFT(head, tmp, oright, field);\ - tmp = RB_LEFT(parent, field); \ - } \ - RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ - RB_COLOR(parent, field) = RB_BLACK; \ - if (RB_LEFT(tmp, field)) \ - RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ - RB_ROTATE_RIGHT(head, parent, tmp, field);\ - elm = RB_ROOT(head); \ - break; \ - } \ - } \ - } \ - if (elm) \ - RB_COLOR(elm, field) = RB_BLACK; \ -} \ - \ -attr struct type * \ -name##_RB_REMOVE(struct name *head, struct type *elm) \ -{ \ - struct type *child, *parent, *old = elm; \ - int color; \ - if (RB_LEFT(elm, field) == NULL) \ - child = RB_RIGHT(elm, field); \ - else if (RB_RIGHT(elm, field) == NULL) \ - child = RB_LEFT(elm, field); \ - else { \ - struct type *left; \ - elm = RB_RIGHT(elm, field); \ - while ((left = RB_LEFT(elm, field)) != NULL) \ - elm = left; \ - child = RB_RIGHT(elm, field); \ - parent = RB_PARENT(elm, field); \ - color = RB_COLOR(elm, field); \ - if (child) \ - RB_PARENT(child, field) = parent; \ - if (parent) { \ - if (RB_LEFT(parent, field) == elm) \ - RB_LEFT(parent, field) = child; \ - else \ - RB_RIGHT(parent, field) = child; \ - RB_AUGMENT(parent); \ - } else \ - RB_ROOT(head) = child; \ - if (RB_PARENT(elm, field) == old) \ - parent = elm; \ - (elm)->field = (old)->field; \ - if (RB_PARENT(old, field)) { \ - if (RB_LEFT(RB_PARENT(old, field), field) == old)\ - RB_LEFT(RB_PARENT(old, field), field) = elm;\ - else \ - RB_RIGHT(RB_PARENT(old, field), field) = elm;\ - RB_AUGMENT(RB_PARENT(old, field)); \ - } else \ - RB_ROOT(head) = elm; \ - RB_PARENT(RB_LEFT(old, field), field) = elm; \ - if (RB_RIGHT(old, field)) \ - RB_PARENT(RB_RIGHT(old, field), field) = elm; \ - if (parent) { \ - left = parent; \ - do { \ - RB_AUGMENT(left); \ - } while ((left = RB_PARENT(left, field)) != NULL); \ - } \ - goto color; \ - } \ - parent = RB_PARENT(elm, field); \ - color = RB_COLOR(elm, field); \ - if (child) \ - RB_PARENT(child, field) = parent; \ - if (parent) { \ - if (RB_LEFT(parent, field) == elm) \ - RB_LEFT(parent, field) = child; \ - else \ - RB_RIGHT(parent, field) = child; \ - RB_AUGMENT(parent); \ - } else \ - RB_ROOT(head) = child; \ -color: \ - if (color == RB_BLACK) \ - name##_RB_REMOVE_COLOR(head, parent, child); \ - return (old); \ -} \ - \ -/* Inserts a node into the RB tree */ \ -attr struct type * \ -name##_RB_INSERT(struct name *head, struct type *elm) \ -{ \ - struct type *tmp; \ - struct type *parent = NULL; \ - int comp = 0; \ - tmp = RB_ROOT(head); \ - while (tmp) { \ - parent = tmp; \ - comp = (cmp)(elm, parent); \ - if (comp < 0) \ - tmp = RB_LEFT(tmp, field); \ - else if (comp > 0) \ - tmp = RB_RIGHT(tmp, field); \ - else \ - return (tmp); \ - } \ - RB_SET(elm, parent, field); \ - if (parent != NULL) { \ - if (comp < 0) \ - RB_LEFT(parent, field) = elm; \ - else \ - RB_RIGHT(parent, field) = elm; \ - RB_AUGMENT(parent); \ - } else \ - RB_ROOT(head) = elm; \ - name##_RB_INSERT_COLOR(head, elm); \ - return (NULL); \ -} \ - \ -/* Finds the node with the same key as elm */ \ -attr struct type * \ -name##_RB_FIND(struct name *head, struct type *elm) \ -{ \ - struct type *tmp = RB_ROOT(head); \ - int comp; \ - while (tmp) { \ - comp = cmp(elm, tmp); \ - if (comp < 0) \ - tmp = RB_LEFT(tmp, field); \ - else if (comp > 0) \ - tmp = RB_RIGHT(tmp, field); \ - else \ - return (tmp); \ - } \ - return (NULL); \ -} \ - \ -/* Finds the first node greater than or equal to the search key */ \ -attr struct type * \ -name##_RB_NFIND(struct name *head, struct type *elm) \ -{ \ - struct type *tmp = RB_ROOT(head); \ - struct type *res = NULL; \ - int comp; \ - while (tmp) { \ - comp = cmp(elm, tmp); \ - if (comp < 0) { \ - res = tmp; \ - tmp = RB_LEFT(tmp, field); \ - } \ - else if (comp > 0) \ - tmp = RB_RIGHT(tmp, field); \ - else \ - return (tmp); \ - } \ - return (res); \ -} \ - \ -/* ARGSUSED */ \ -attr struct type * \ -name##_RB_NEXT(struct type *elm) \ -{ \ - if (RB_RIGHT(elm, field)) { \ - elm = RB_RIGHT(elm, field); \ - while (RB_LEFT(elm, field)) \ - elm = RB_LEFT(elm, field); \ - } else { \ - if (RB_PARENT(elm, field) && \ - (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ - elm = RB_PARENT(elm, field); \ - else { \ - while (RB_PARENT(elm, field) && \ - (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ - elm = RB_PARENT(elm, field); \ - elm = RB_PARENT(elm, field); \ - } \ - } \ - return (elm); \ -} \ - \ -/* ARGSUSED */ \ -attr struct type * \ -name##_RB_PREV(struct type *elm) \ -{ \ - if (RB_LEFT(elm, field)) { \ - elm = RB_LEFT(elm, field); \ - while (RB_RIGHT(elm, field)) \ - elm = RB_RIGHT(elm, field); \ - } else { \ - if (RB_PARENT(elm, field) && \ - (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ - elm = RB_PARENT(elm, field); \ - else { \ - while (RB_PARENT(elm, field) && \ - (elm == RB_LEFT(RB_PARENT(elm, field), field)))\ - elm = RB_PARENT(elm, field); \ - elm = RB_PARENT(elm, field); \ - } \ - } \ - return (elm); \ -} \ - \ -attr struct type * \ -name##_RB_MINMAX(struct name *head, int val) \ -{ \ - struct type *tmp = RB_ROOT(head); \ - struct type *parent = NULL; \ - while (tmp) { \ - parent = tmp; \ - if (val < 0) \ - tmp = RB_LEFT(tmp, field); \ - else \ - tmp = RB_RIGHT(tmp, field); \ - } \ - return (parent); \ -} - -#define RB_NEGINF -1 -#define RB_INF 1 - -#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) -#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) -#define RB_FIND(name, x, y) name##_RB_FIND(x, y) -#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) -#define RB_NEXT(name, x, y) name##_RB_NEXT(y) -#define RB_PREV(name, x, y) name##_RB_PREV(y) -#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) -#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) - -#define RB_FOREACH(x, name, head) \ - for ((x) = RB_MIN(name, head); \ - (x) != NULL; \ - (x) = name##_RB_NEXT(x)) - -#define RB_FOREACH_FROM(x, name, y) \ - for ((x) = (y); \ - ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ - (x) = (y)) - -#define RB_FOREACH_SAFE(x, name, head, y) \ - for ((x) = RB_MIN(name, head); \ - ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ - (x) = (y)) - -#define RB_FOREACH_REVERSE(x, name, head) \ - for ((x) = RB_MAX(name, head); \ - (x) != NULL; \ - (x) = name##_RB_PREV(x)) - -#define RB_FOREACH_REVERSE_FROM(x, name, y) \ - for ((x) = (y); \ - ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ - (x) = (y)) - -#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \ - for ((x) = RB_MAX(name, head); \ - ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ - (x) = (y)) - -#endif diff --git a/FCLauncher/src/main/jni/xhook/include/xh_core.h b/FCLauncher/src/main/jni/xhook/include/xh_core.h deleted file mode 100644 index 35087945..00000000 --- a/FCLauncher/src/main/jni/xhook/include/xh_core.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. -// -// 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 2018-04-11. - -#ifndef XH_CORE_H -#define XH_CORE_H 1 - -#ifdef __cplusplus -extern "C" { -#endif - -int xh_core_register(const char *pathname_regex_str, const char *symbol, - void *new_func, void **old_func); - -int xh_core_ignore(const char *pathname_regex_str, const char *symbol); - -int xh_core_refresh(int async); - -void xh_core_clear(); - -void xh_core_enable_debug(int flag); - -void xh_core_enable_sigsegv_protection(int flag); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/FCLauncher/src/main/jni/xhook/include/xh_elf.h b/FCLauncher/src/main/jni/xhook/include/xh_elf.h deleted file mode 100644 index 1697dc48..00000000 --- a/FCLauncher/src/main/jni/xhook/include/xh_elf.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. -// -// 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 2018-04-11. - -#ifndef XH_ELF_H -#define XH_ELF_H 1 - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct -{ - const char *pathname; - - ElfW(Addr) base_addr; - ElfW(Addr) bias_addr; - - ElfW(Ehdr) *ehdr; - ElfW(Phdr) *phdr; - - ElfW(Dyn) *dyn; //.dynamic - ElfW(Word) dyn_sz; - - const char *strtab; //.dynstr (string-table) - ElfW(Sym) *symtab; //.dynsym (symbol-index to string-table's offset) - - ElfW(Addr) relplt; //.rel.plt or .rela.plt - ElfW(Word) relplt_sz; - - ElfW(Addr) reldyn; //.rel.dyn or .rela.dyn - ElfW(Word) reldyn_sz; - - ElfW(Addr) relandroid; //android compressed rel or rela - ElfW(Word) relandroid_sz; - - //for ELF hash - uint32_t *bucket; - uint32_t bucket_cnt; - uint32_t *chain; - uint32_t chain_cnt; //invalid for GNU hash - - //append for GNU hash - uint32_t symoffset; - ElfW(Addr) *bloom; - uint32_t bloom_sz; - uint32_t bloom_shift; - - int is_use_rela; - int is_use_gnu_hash; -} xh_elf_t; - -int xh_elf_init(xh_elf_t *self, uintptr_t base_addr, const char *pathname); -int xh_elf_hook(xh_elf_t *self, const char *symbol, void *new_func, void **old_func); - -int xh_elf_check_elfheader(uintptr_t base_addr); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/FCLauncher/src/main/jni/xhook/include/xh_errno.h b/FCLauncher/src/main/jni/xhook/include/xh_errno.h deleted file mode 100644 index e628cd77..00000000 --- a/FCLauncher/src/main/jni/xhook/include/xh_errno.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. -// -// 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 2018-04-11. - -#ifndef XH_ERRNO_H -#define XH_ERRNO_H 1 - -#define XH_ERRNO_UNKNOWN 1001 -#define XH_ERRNO_INVAL 1002 -#define XH_ERRNO_NOMEM 1003 -#define XH_ERRNO_REPEAT 1004 -#define XH_ERRNO_NOTFND 1005 -#define XH_ERRNO_BADMAPS 1006 -#define XH_ERRNO_FORMAT 1007 -#define XH_ERRNO_ELFINIT 1008 -#define XH_ERRNO_SEGVERR 1009 - -#endif diff --git a/FCLauncher/src/main/jni/xhook/include/xh_log.h b/FCLauncher/src/main/jni/xhook/include/xh_log.h deleted file mode 100644 index e108c4b0..00000000 --- a/FCLauncher/src/main/jni/xhook/include/xh_log.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. -// -// 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 2018-04-11. - -#ifndef XH_LOG_H -#define XH_LOG_H 1 - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -extern android_LogPriority xh_log_priority; - -#define XH_LOG_TAG "xhook" -#define XH_LOG_DEBUG(fmt, ...) do{if(xh_log_priority <= ANDROID_LOG_DEBUG) __android_log_print(ANDROID_LOG_DEBUG, XH_LOG_TAG, fmt, ##__VA_ARGS__);}while(0) -#define XH_LOG_INFO(fmt, ...) do{if(xh_log_priority <= ANDROID_LOG_INFO) __android_log_print(ANDROID_LOG_INFO, XH_LOG_TAG, fmt, ##__VA_ARGS__);}while(0) -#define XH_LOG_WARN(fmt, ...) do{if(xh_log_priority <= ANDROID_LOG_WARN) __android_log_print(ANDROID_LOG_WARN, XH_LOG_TAG, fmt, ##__VA_ARGS__);}while(0) -#define XH_LOG_ERROR(fmt, ...) do{if(xh_log_priority <= ANDROID_LOG_ERROR) __android_log_print(ANDROID_LOG_ERROR, XH_LOG_TAG, fmt, ##__VA_ARGS__);}while(0) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/FCLauncher/src/main/jni/xhook/include/xh_util.h b/FCLauncher/src/main/jni/xhook/include/xh_util.h deleted file mode 100644 index b57f8dc6..00000000 --- a/FCLauncher/src/main/jni/xhook/include/xh_util.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. -// -// 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 2018-04-11. - -#ifndef XH_UTILS_H -#define XH_UTILS_H 1 - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(__LP64__) -#define XH_UTIL_FMT_LEN "16" -#define XH_UTIL_FMT_X "llx" -#else -#define XH_UTIL_FMT_LEN "8" -#define XH_UTIL_FMT_X "x" -#endif - -#define XH_UTIL_FMT_FIXED_X XH_UTIL_FMT_LEN XH_UTIL_FMT_X -#define XH_UTIL_FMT_FIXED_S XH_UTIL_FMT_LEN "s" - -int xh_util_get_mem_protect(uintptr_t addr, size_t len, const char *pathname, unsigned int *prot); -int xh_util_get_addr_protect(uintptr_t addr, const char *pathname, unsigned int *prot); -int xh_util_set_addr_protect(uintptr_t addr, unsigned int prot); -void xh_util_flush_instruction_cache(uintptr_t addr); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/FCLauncher/src/main/jni/xhook/include/xh_version.h b/FCLauncher/src/main/jni/xhook/include/xh_version.h deleted file mode 100644 index b70b4f2f..00000000 --- a/FCLauncher/src/main/jni/xhook/include/xh_version.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. -// -// 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 2018-04-11. - -#ifndef XH_VERSION_H -#define XH_VERSION_H 1 - -#ifdef __cplusplus -extern "C" { -#endif - -unsigned int xh_version(); - -const char *xh_version_str(); - -const char *xh_version_str_full(); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/FCLauncher/src/main/jni/xhook/include/xhook.h b/FCLauncher/src/main/jni/xhook/include/xhook.h deleted file mode 100644 index 93dd5b4c..00000000 --- a/FCLauncher/src/main/jni/xhook/include/xhook.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. -// -// 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 2018-04-11. - -#ifndef XHOOK_H -#define XHOOK_H 1 - -#ifdef __cplusplus -extern "C" { -#endif - -#define XHOOK_EXPORT __attribute__((visibility("default"))) - -int xhook_register(const char *pathname_regex_str, const char *symbol, - void *new_func, void **old_func) XHOOK_EXPORT; - -int xhook_ignore(const char *pathname_regex_str, const char *symbol) XHOOK_EXPORT; - -int xhook_refresh(int async) XHOOK_EXPORT; - -void xhook_clear() XHOOK_EXPORT; - -void xhook_enable_debug(int flag) XHOOK_EXPORT; - -void xhook_enable_sigsegv_protection(int flag) XHOOK_EXPORT; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/FCLauncher/src/main/jni/xhook/xh_core.c b/FCLauncher/src/main/jni/xhook/xh_core.c deleted file mode 100644 index 21d05f5e..00000000 --- a/FCLauncher/src/main/jni/xhook/xh_core.c +++ /dev/null @@ -1,656 +0,0 @@ -// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. -// -// 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 2018-04-11. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define XH_CORE_DEBUG 0 - -//registered hook info collection -typedef struct xh_core_hook_info -{ -#if XH_CORE_DEBUG - char *pathname_regex_str; -#endif - regex_t pathname_regex; - char *symbol; - void *new_func; - void **old_func; - TAILQ_ENTRY(xh_core_hook_info,) link; -} xh_core_hook_info_t; -typedef TAILQ_HEAD(xh_core_hook_info_queue, xh_core_hook_info,) xh_core_hook_info_queue_t; - -//ignored hook info collection -typedef struct xh_core_ignore_info -{ -#if XH_CORE_DEBUG - char *pathname_regex_str; -#endif - regex_t pathname_regex; - char *symbol; //NULL meaning for all symbols - TAILQ_ENTRY(xh_core_ignore_info,) link; -} xh_core_ignore_info_t; -typedef TAILQ_HEAD(xh_core_ignore_info_queue, xh_core_ignore_info,) xh_core_ignore_info_queue_t; - -//required info from /proc/self/maps -typedef struct xh_core_map_info -{ - char *pathname; - uintptr_t base_addr; - xh_elf_t elf; - RB_ENTRY(xh_core_map_info) link; -} xh_core_map_info_t; -static __inline__ int xh_core_map_info_cmp(xh_core_map_info_t *a, xh_core_map_info_t *b) -{ - return strcmp(a->pathname, b->pathname); -} -typedef RB_HEAD(xh_core_map_info_tree, xh_core_map_info) xh_core_map_info_tree_t; -RB_GENERATE_STATIC(xh_core_map_info_tree, xh_core_map_info, link, xh_core_map_info_cmp) - -//signal handler for SIGSEGV -//for xh_elf_init(), xh_elf_hook(), xh_elf_check_elfheader() -static int xh_core_sigsegv_enable = 1; //enable by default -static struct sigaction xh_core_sigsegv_act_old; -static volatile int xh_core_sigsegv_flag = 0; -static sigjmp_buf xh_core_sigsegv_env; -static void xh_core_sigsegv_handler(int sig) -{ - (void)sig; - - if(xh_core_sigsegv_flag) - siglongjmp(xh_core_sigsegv_env, 1); - else - sigaction(SIGSEGV, &xh_core_sigsegv_act_old, NULL); -} -static int xh_core_add_sigsegv_handler() -{ - struct sigaction act; - - if(!xh_core_sigsegv_enable) return 0; - - if(0 != sigemptyset(&act.sa_mask)) return (0 == errno ? XH_ERRNO_UNKNOWN : errno); - act.sa_handler = xh_core_sigsegv_handler; - - if(0 != sigaction(SIGSEGV, &act, &xh_core_sigsegv_act_old)) - return (0 == errno ? XH_ERRNO_UNKNOWN : errno); - - return 0; -} -static void xh_core_del_sigsegv_handler() -{ - if(!xh_core_sigsegv_enable) return; - - sigaction(SIGSEGV, &xh_core_sigsegv_act_old, NULL); -} - - -static xh_core_hook_info_queue_t xh_core_hook_info = TAILQ_HEAD_INITIALIZER(xh_core_hook_info); -static xh_core_ignore_info_queue_t xh_core_ignore_info = TAILQ_HEAD_INITIALIZER(xh_core_ignore_info); -static xh_core_map_info_tree_t xh_core_map_info = RB_INITIALIZER(&xh_core_map_info); -static pthread_mutex_t xh_core_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t xh_core_cond = PTHREAD_COND_INITIALIZER; -static volatile int xh_core_inited = 0; -static volatile int xh_core_init_ok = 0; -static volatile int xh_core_async_inited = 0; -static volatile int xh_core_async_init_ok = 0; -static pthread_mutex_t xh_core_refresh_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_t xh_core_refresh_thread_tid; -static volatile int xh_core_refresh_thread_running = 0; -static volatile int xh_core_refresh_thread_do = 0; - - -int xh_core_register(const char *pathname_regex_str, const char *symbol, - void *new_func, void **old_func) -{ - xh_core_hook_info_t *hi; - regex_t regex; - - if(NULL == pathname_regex_str || NULL == symbol || NULL == new_func) return XH_ERRNO_INVAL; - - if(xh_core_inited) - { - XH_LOG_ERROR("do not register hook after refresh(): %s, %s", pathname_regex_str, symbol); - return XH_ERRNO_INVAL; - } - - if(0 != regcomp(®ex, pathname_regex_str, REG_NOSUB)) return XH_ERRNO_INVAL; - - if(NULL == (hi = malloc(sizeof(xh_core_hook_info_t)))) return XH_ERRNO_NOMEM; - if(NULL == (hi->symbol = strdup(symbol))) - { - free(hi); - return XH_ERRNO_NOMEM; - } -#if XH_CORE_DEBUG - if(NULL == (hi->pathname_regex_str = strdup(pathname_regex_str))) - { - free(hi->symbol); - free(hi); - return XH_ERRNO_NOMEM; - } -#endif - hi->pathname_regex = regex; - hi->new_func = new_func; - hi->old_func = old_func; - - pthread_mutex_lock(&xh_core_mutex); - TAILQ_INSERT_TAIL(&xh_core_hook_info, hi, link); - pthread_mutex_unlock(&xh_core_mutex); - - return 0; -} - -int xh_core_ignore(const char *pathname_regex_str, const char *symbol) -{ - xh_core_ignore_info_t *ii; - regex_t regex; - - if(NULL == pathname_regex_str) return XH_ERRNO_INVAL; - - if(xh_core_inited) - { - XH_LOG_ERROR("do not ignore hook after refresh(): %s, %s", pathname_regex_str, symbol ? symbol : "ALL"); - return XH_ERRNO_INVAL; - } - - if(0 != regcomp(®ex, pathname_regex_str, REG_NOSUB)) return XH_ERRNO_INVAL; - - if(NULL == (ii = malloc(sizeof(xh_core_ignore_info_t)))) return XH_ERRNO_NOMEM; - if(NULL != symbol) - { - if(NULL == (ii->symbol = strdup(symbol))) - { - free(ii); - return XH_ERRNO_NOMEM; - } - } - else - { - ii->symbol = NULL; //ignore all symbols - } -#if XH_CORE_DEBUG - if(NULL == (ii->pathname_regex_str = strdup(pathname_regex_str))) - { - free(ii->symbol); - free(ii); - return XH_ERRNO_NOMEM; - } -#endif - ii->pathname_regex = regex; - - pthread_mutex_lock(&xh_core_mutex); - TAILQ_INSERT_TAIL(&xh_core_ignore_info, ii, link); - pthread_mutex_unlock(&xh_core_mutex); - - return 0; -} - -static int xh_core_check_elf_header(uintptr_t base_addr, const char *pathname) -{ - if(!xh_core_sigsegv_enable) - { - return xh_elf_check_elfheader(base_addr); - } - else - { - int ret = XH_ERRNO_UNKNOWN; - - xh_core_sigsegv_flag = 1; - if(0 == sigsetjmp(xh_core_sigsegv_env, 1)) - { - ret = xh_elf_check_elfheader(base_addr); - } - else - { - ret = XH_ERRNO_SEGVERR; - XH_LOG_WARN("catch SIGSEGV when check_elfheader: %s", pathname); - } - xh_core_sigsegv_flag = 0; - return ret; - } -} - -static void xh_core_hook_impl(xh_core_map_info_t *mi) -{ - //init - if(0 != xh_elf_init(&(mi->elf), mi->base_addr, mi->pathname)) return; - - //hook - xh_core_hook_info_t *hi; - xh_core_ignore_info_t *ii; - int ignore; - TAILQ_FOREACH(hi, &xh_core_hook_info, link) //find hook info - { - if(0 == regexec(&(hi->pathname_regex), mi->pathname, 0, NULL, 0)) - { - ignore = 0; - TAILQ_FOREACH(ii, &xh_core_ignore_info, link) //find ignore info - { - if(0 == regexec(&(ii->pathname_regex), mi->pathname, 0, NULL, 0)) - { - if(NULL == ii->symbol) //ignore all symbols - return; - - if(0 == strcmp(ii->symbol, hi->symbol)) //ignore the current symbol - { - ignore = 1; - break; - } - } - } - - if(0 == ignore) - xh_elf_hook(&(mi->elf), hi->symbol, hi->new_func, hi->old_func); - } - } -} - -static void xh_core_hook(xh_core_map_info_t *mi) -{ - if(!xh_core_sigsegv_enable) - { - xh_core_hook_impl(mi); - } - else - { - xh_core_sigsegv_flag = 1; - if(0 == sigsetjmp(xh_core_sigsegv_env, 1)) - { - xh_core_hook_impl(mi); - } - else - { - XH_LOG_WARN("catch SIGSEGV when init or hook: %s", mi->pathname); - } - xh_core_sigsegv_flag = 0; - } -} - -static void xh_core_refresh_impl() -{ - char line[512]; - FILE *fp; - uintptr_t base_addr; - char perm[5]; - unsigned long offset; - int pathname_pos; - char *pathname; - size_t pathname_len; - xh_core_map_info_t *mi, *mi_tmp; - xh_core_map_info_t mi_key; - xh_core_hook_info_t *hi; - xh_core_ignore_info_t *ii; - int match; - xh_core_map_info_tree_t map_info_refreshed = RB_INITIALIZER(&map_info_refreshed); - - if(NULL == (fp = fopen("/proc/self/maps", "r"))) - { - XH_LOG_ERROR("fopen /proc/self/maps failed"); - return; - } - - while(fgets(line, sizeof(line), fp)) - { - if(sscanf(line, "%"PRIxPTR"-%*lx %4s %lx %*x:%*x %*d%n", &base_addr, perm, &offset, &pathname_pos) != 3) continue; - - //check permission - if(perm[0] != 'r') continue; - if(perm[3] != 'p') continue; //do not touch the shared memory - - //check offset - // - //We are trying to find ELF header in memory. - //It can only be found at the beginning of a mapped memory regions - //whose offset is 0. - if(0 != offset) continue; - - //get pathname - while(isspace(line[pathname_pos]) && pathname_pos < (int)(sizeof(line) - 1)) - pathname_pos += 1; - if(pathname_pos >= (int)(sizeof(line) - 1)) continue; - pathname = line + pathname_pos; - pathname_len = strlen(pathname); - if(0 == pathname_len) continue; - if(pathname[pathname_len - 1] == '\n') - { - pathname[pathname_len - 1] = '\0'; - pathname_len -= 1; - } - if(0 == pathname_len) continue; - if('[' == pathname[0]) continue; - - //check pathname - //if we need to hook this elf? - match = 0; - TAILQ_FOREACH(hi, &xh_core_hook_info, link) //find hook info - { - if(0 == regexec(&(hi->pathname_regex), pathname, 0, NULL, 0)) - { - TAILQ_FOREACH(ii, &xh_core_ignore_info, link) //find ignore info - { - if(0 == regexec(&(ii->pathname_regex), pathname, 0, NULL, 0)) - { - if(NULL == ii->symbol) - goto check_finished; - - if(0 == strcmp(ii->symbol, hi->symbol)) - goto check_continue; - } - } - - match = 1; - check_continue: - break; - } - } - check_finished: - if(0 == match) continue; - - //check elf header format - //We are trying to do ELF header checking as late as possible. - if(0 != xh_core_check_elf_header(base_addr, pathname)) continue; - - //check existed map item - mi_key.pathname = pathname; - if(NULL != (mi = RB_FIND(xh_core_map_info_tree, &xh_core_map_info, &mi_key))) - { - //exist - RB_REMOVE(xh_core_map_info_tree, &xh_core_map_info, mi); - - //repeated? - //We only keep the first one, that is the real base address - if(NULL != RB_INSERT(xh_core_map_info_tree, &map_info_refreshed, mi)) - { -#if XH_CORE_DEBUG - XH_LOG_DEBUG("repeated map info when update: %s", line); -#endif - free(mi->pathname); - free(mi); - continue; - } - - //re-hook if base_addr changed - if(mi->base_addr != base_addr) - { - mi->base_addr = base_addr; - xh_core_hook(mi); - } - } - else - { - //not exist, create a new map info - if(NULL == (mi = (xh_core_map_info_t *)malloc(sizeof(xh_core_map_info_t)))) continue; - if(NULL == (mi->pathname = strdup(pathname))) - { - free(mi); - continue; - } - mi->base_addr = base_addr; - - //repeated? - //We only keep the first one, that is the real base address - if(NULL != RB_INSERT(xh_core_map_info_tree, &map_info_refreshed, mi)) - { -#if XH_CORE_DEBUG - XH_LOG_DEBUG("repeated map info when create: %s", line); -#endif - free(mi->pathname); - free(mi); - continue; - } - - //hook - xh_core_hook(mi); //hook - } - } - fclose(fp); - - //free all missing map item, maybe dlclosed? - RB_FOREACH_SAFE(mi, xh_core_map_info_tree, &xh_core_map_info, mi_tmp) - { -#if XH_CORE_DEBUG - XH_LOG_DEBUG("remove missing map info: %s", mi->pathname); -#endif - RB_REMOVE(xh_core_map_info_tree, &xh_core_map_info, mi); - if(mi->pathname) free(mi->pathname); - free(mi); - } - - //save the new refreshed map info tree - xh_core_map_info = map_info_refreshed; - - XH_LOG_INFO("map refreshed"); - -#if XH_CORE_DEBUG - RB_FOREACH(mi, xh_core_map_info_tree, &xh_core_map_info) - XH_LOG_DEBUG(" %"PRIxPTR" %s\n", mi->base_addr, mi->pathname); -#endif -} - -static void *xh_core_refresh_thread_func(void *arg) -{ - (void)arg; - - pthread_setname_np(pthread_self(), "xh_refresh_loop"); - - while(xh_core_refresh_thread_running) - { - //waiting for a refresh task or exit - pthread_mutex_lock(&xh_core_mutex); - while(!xh_core_refresh_thread_do && xh_core_refresh_thread_running) - { - pthread_cond_wait(&xh_core_cond, &xh_core_mutex); - } - if(!xh_core_refresh_thread_running) - { - pthread_mutex_unlock(&xh_core_mutex); - break; - } - xh_core_refresh_thread_do = 0; - pthread_mutex_unlock(&xh_core_mutex); - - //refresh - pthread_mutex_lock(&xh_core_refresh_mutex); - xh_core_refresh_impl(); - pthread_mutex_unlock(&xh_core_refresh_mutex); - } - - return NULL; -} - -static void xh_core_init_once() -{ - if(xh_core_inited) return; - - pthread_mutex_lock(&xh_core_mutex); - - if(xh_core_inited) goto end; - - xh_core_inited = 1; - - //dump debug info - XH_LOG_INFO("%s\n", xh_version_str_full()); -#if XH_CORE_DEBUG - xh_core_hook_info_t *hi; - TAILQ_FOREACH(hi, &xh_core_hook_info, link) - XH_LOG_INFO(" hook: %s @ %s, (%p, %p)\n", hi->symbol, hi->pathname_regex_str, - hi->new_func, hi->old_func); - xh_core_ignore_info_t *ii; - TAILQ_FOREACH(ii, &xh_core_ignore_info, link) - XH_LOG_INFO(" ignore: %s @ %s\n", ii->symbol ? ii->symbol : "ALL ", - ii->pathname_regex_str); -#endif - - //register signal handler - if(0 != xh_core_add_sigsegv_handler()) goto end; - - //OK - xh_core_init_ok = 1; - - end: - pthread_mutex_unlock(&xh_core_mutex); -} - -static void xh_core_init_async_once() -{ - if(xh_core_async_inited) return; - - pthread_mutex_lock(&xh_core_mutex); - - if(xh_core_async_inited) goto end; - - xh_core_async_inited = 1; - - //create async refresh thread - xh_core_refresh_thread_running = 1; - if(0 != pthread_create(&xh_core_refresh_thread_tid, NULL, &xh_core_refresh_thread_func, NULL)) - { - xh_core_refresh_thread_running = 0; - goto end; - } - - //OK - xh_core_async_init_ok = 1; - - end: - pthread_mutex_unlock(&xh_core_mutex); -} - -int xh_core_refresh(int async) -{ - //init - xh_core_init_once(); - if(!xh_core_init_ok) return XH_ERRNO_UNKNOWN; - - if(async) - { - //init for async - xh_core_init_async_once(); - if(!xh_core_async_init_ok) return XH_ERRNO_UNKNOWN; - - //refresh async - pthread_mutex_lock(&xh_core_mutex); - xh_core_refresh_thread_do = 1; - pthread_cond_signal(&xh_core_cond); - pthread_mutex_unlock(&xh_core_mutex); - } - else - { - //refresh sync - pthread_mutex_lock(&xh_core_refresh_mutex); - xh_core_refresh_impl(); - pthread_mutex_unlock(&xh_core_refresh_mutex); - } - - return 0; -} - -void xh_core_clear() -{ - //stop the async refresh thread - if(xh_core_async_init_ok) - { - pthread_mutex_lock(&xh_core_mutex); - xh_core_refresh_thread_running = 0; - pthread_cond_signal(&xh_core_cond); - pthread_mutex_unlock(&xh_core_mutex); - - pthread_join(xh_core_refresh_thread_tid, NULL); - xh_core_async_init_ok = 0; - } - xh_core_async_inited = 0; - - //unregister the sig handler - if(xh_core_init_ok) - { - xh_core_del_sigsegv_handler(); - xh_core_init_ok = 0; - } - xh_core_inited = 0; - - pthread_mutex_lock(&xh_core_mutex); - pthread_mutex_lock(&xh_core_refresh_mutex); - - //free all map info - xh_core_map_info_t *mi, *mi_tmp; - RB_FOREACH_SAFE(mi, xh_core_map_info_tree, &xh_core_map_info, mi_tmp) - { - RB_REMOVE(xh_core_map_info_tree, &xh_core_map_info, mi); - if(mi->pathname) free(mi->pathname); - free(mi); - } - - //free all hook info - xh_core_hook_info_t *hi, *hi_tmp; - TAILQ_FOREACH_SAFE(hi, &xh_core_hook_info, link, hi_tmp) - { - TAILQ_REMOVE(&xh_core_hook_info, hi, link); -#if XH_CORE_DEBUG - free(hi->pathname_regex_str); -#endif - regfree(&(hi->pathname_regex)); - free(hi->symbol); - free(hi); - } - - //free all ignore info - xh_core_ignore_info_t *ii, *ii_tmp; - TAILQ_FOREACH_SAFE(ii, &xh_core_ignore_info, link, ii_tmp) - { - TAILQ_REMOVE(&xh_core_ignore_info, ii, link); -#if XH_CORE_DEBUG - free(ii->pathname_regex_str); -#endif - regfree(&(ii->pathname_regex)); - free(ii->symbol); - free(ii); - } - - pthread_mutex_unlock(&xh_core_refresh_mutex); - pthread_mutex_unlock(&xh_core_mutex); -} - -void xh_core_enable_debug(int flag) -{ - xh_log_priority = (flag ? ANDROID_LOG_DEBUG : ANDROID_LOG_WARN); -} - -void xh_core_enable_sigsegv_protection(int flag) -{ - xh_core_sigsegv_enable = (flag ? 1 : 0); -} diff --git a/FCLauncher/src/main/jni/xhook/xh_elf.c b/FCLauncher/src/main/jni/xhook/xh_elf.c deleted file mode 100644 index 5e901cca..00000000 --- a/FCLauncher/src/main/jni/xhook/xh_elf.c +++ /dev/null @@ -1,1046 +0,0 @@ -// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. -// -// 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 2018-04-11. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define XH_ELF_DEBUG 0 - -#ifndef EI_ABIVERSION -#define EI_ABIVERSION 8 -#endif - -#if defined(__arm__) -#define XH_ELF_R_GENERIC_JUMP_SLOT R_ARM_JUMP_SLOT //.rel.plt -#define XH_ELF_R_GENERIC_GLOB_DAT R_ARM_GLOB_DAT //.rel.dyn -#define XH_ELF_R_GENERIC_ABS R_ARM_ABS32 //.rel.dyn -#elif defined(__aarch64__) -#define XH_ELF_R_GENERIC_JUMP_SLOT R_AARCH64_JUMP_SLOT -#define XH_ELF_R_GENERIC_GLOB_DAT R_AARCH64_GLOB_DAT -#define XH_ELF_R_GENERIC_ABS R_AARCH64_ABS64 -#elif defined(__i386__) -#define XH_ELF_R_GENERIC_JUMP_SLOT R_386_JMP_SLOT -#define XH_ELF_R_GENERIC_GLOB_DAT R_386_GLOB_DAT -#define XH_ELF_R_GENERIC_ABS R_386_32 -#elif defined(__x86_64__) -#define XH_ELF_R_GENERIC_JUMP_SLOT R_X86_64_JUMP_SLOT -#define XH_ELF_R_GENERIC_GLOB_DAT R_X86_64_GLOB_DAT -#define XH_ELF_R_GENERIC_ABS R_X86_64_64 -#endif - -#if defined(__LP64__) -#define XH_ELF_R_SYM(info) ELF64_R_SYM(info) -#define XH_ELF_R_TYPE(info) ELF64_R_TYPE(info) -#else -#define XH_ELF_R_SYM(info) ELF32_R_SYM(info) -#define XH_ELF_R_TYPE(info) ELF32_R_TYPE(info) -#endif - -//iterator for plain PLT -typedef struct -{ - uint8_t *cur; - uint8_t *end; - int is_use_rela; -} xh_elf_plain_reloc_iterator_t; - -static void xh_elf_plain_reloc_iterator_init(xh_elf_plain_reloc_iterator_t *self, - ElfW(Addr) rel, ElfW(Word) rel_sz, int is_use_rela) -{ - self->cur = (uint8_t *)rel; - self->end = self->cur + rel_sz; - self->is_use_rela = is_use_rela; -} - -static void *xh_elf_plain_reloc_iterator_next(xh_elf_plain_reloc_iterator_t *self) -{ - if(self->cur >= self->end) return NULL; - - void *ret = (void *)(self->cur); - self->cur += (self->is_use_rela ? sizeof(ElfW(Rela)) : sizeof(ElfW(Rel))); - return ret; -} - -//sleb128 decoder -typedef struct -{ - uint8_t *cur; - uint8_t *end; -} xh_elf_sleb128_decoder_t; - -static void xh_elf_sleb128_decoder_init(xh_elf_sleb128_decoder_t *self, - ElfW(Addr) rel, ElfW(Word) rel_sz) -{ - self->cur = (uint8_t *)rel; - self->end = self->cur + rel_sz; -} - -static int xh_elf_sleb128_decoder_next(xh_elf_sleb128_decoder_t *self, size_t *ret) -{ - size_t value = 0; - static const size_t size = 8 * sizeof(value); - size_t shift = 0; - uint8_t byte; - - do - { - if(self->cur >= self->end) - return XH_ERRNO_FORMAT; - - byte = *(self->cur)++; - value |= ((size_t)(byte & 127) << shift); - shift += 7; - } while(byte & 128); - - if(shift < size && (byte & 64)) - { - value |= -((size_t)(1) << shift); - } - - *ret = value; - return 0; -} - -//iterator for sleb128 decoded packed PLT -typedef struct -{ - xh_elf_sleb128_decoder_t decoder; - size_t relocation_count; - size_t group_size; - size_t group_flags; - size_t group_r_offset_delta; - size_t relocation_index; - size_t relocation_group_index; - ElfW(Rela) rela; - ElfW(Rel) rel; - ElfW(Addr) r_offset; - size_t r_info; - ssize_t r_addend; - int is_use_rela; -} xh_elf_packed_reloc_iterator_t; - -const size_t RELOCATION_GROUPED_BY_INFO_FLAG = 1; -const size_t RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG = 2; -const size_t RELOCATION_GROUPED_BY_ADDEND_FLAG = 4; -const size_t RELOCATION_GROUP_HAS_ADDEND_FLAG = 8; - -static int xh_elf_packed_reloc_iterator_init(xh_elf_packed_reloc_iterator_t *self, - ElfW(Addr) rel, ElfW(Word) rel_sz, int is_use_rela) -{ - int r; - - memset(self, 0, sizeof(xh_elf_packed_reloc_iterator_t)); - xh_elf_sleb128_decoder_init(&(self->decoder), rel, rel_sz); - self->is_use_rela = is_use_rela; - - if(0 != (r = xh_elf_sleb128_decoder_next(&(self->decoder), &(self->relocation_count)))) return r; - if(0 != (r = xh_elf_sleb128_decoder_next(&(self->decoder), (size_t *)&(self->r_offset)))) return r; - return 0; -} - -static int xh_elf_packed_reloc_iterator_read_group_fields(xh_elf_packed_reloc_iterator_t *self) -{ - int r; - size_t val; - - if(0 != (r = xh_elf_sleb128_decoder_next(&(self->decoder), &(self->group_size)))) return r; - if(0 != (r = xh_elf_sleb128_decoder_next(&(self->decoder), &(self->group_flags)))) return r; - - if(self->group_flags & RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG) - if(0 != (r = xh_elf_sleb128_decoder_next(&(self->decoder), &(self->group_r_offset_delta)))) return r; - - if(self->group_flags & RELOCATION_GROUPED_BY_INFO_FLAG) - if(0 != (r = xh_elf_sleb128_decoder_next(&(self->decoder), (size_t *)&(self->r_info)))) return r; - - if((self->group_flags & RELOCATION_GROUP_HAS_ADDEND_FLAG) && - (self->group_flags & RELOCATION_GROUPED_BY_ADDEND_FLAG)) - { - if(0 == self->is_use_rela) - { - XH_LOG_ERROR("unexpected r_addend in android.rel section"); - return XH_ERRNO_FORMAT; - } - if(0 != (r = xh_elf_sleb128_decoder_next(&(self->decoder), &val))) return r; - self->r_addend += (ssize_t)val; - } - else if(0 == (self->group_flags & RELOCATION_GROUP_HAS_ADDEND_FLAG)) - { - self->r_addend = 0; - } - - self->relocation_group_index = 0; - return 0; -} - -static void *xh_elf_packed_reloc_iterator_next(xh_elf_packed_reloc_iterator_t *self) -{ - size_t val; - - if(self->relocation_index >= self->relocation_count) return NULL; - - if(self->relocation_group_index == self->group_size) - { - if(0 != xh_elf_packed_reloc_iterator_read_group_fields(self)) return NULL; - } - - if(self->group_flags & RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG) - { - self->r_offset += self->group_r_offset_delta; - } - else - { - if(0 != xh_elf_sleb128_decoder_next(&(self->decoder), &val)) return NULL; - self->r_offset += val; - } - - if(0 == (self->group_flags & RELOCATION_GROUPED_BY_INFO_FLAG)) - if(0 != xh_elf_sleb128_decoder_next(&(self->decoder), &(self->r_info))) return NULL; - - if(self->is_use_rela && - (self->group_flags & RELOCATION_GROUP_HAS_ADDEND_FLAG) && - (0 == (self->group_flags & RELOCATION_GROUPED_BY_ADDEND_FLAG))) - { - if(0 != xh_elf_sleb128_decoder_next(&(self->decoder), &val)) return NULL; - self->r_addend += (ssize_t)val; - } - - self->relocation_index++; - self->relocation_group_index++; - - if(self->is_use_rela) - { - self->rela.r_offset = self->r_offset; - self->rela.r_info = self->r_info; - self->rela.r_addend = self->r_addend; - return (void *)(&(self->rela)); - } - else - { - self->rel.r_offset = self->r_offset; - self->rel.r_info = self->r_info; - return (void *)(&(self->rel)); - } -} - -//ELF header checker -int xh_elf_check_elfheader(uintptr_t base_addr) -{ - ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)base_addr; - - //check magic - if(0 != memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) return XH_ERRNO_FORMAT; - - //check class (64/32) -#if defined(__LP64__) - if(ELFCLASS64 != ehdr->e_ident[EI_CLASS]) return XH_ERRNO_FORMAT; -#else - if(ELFCLASS32 != ehdr->e_ident[EI_CLASS]) return XH_ERRNO_FORMAT; -#endif - - //check endian (little/big) - if(ELFDATA2LSB != ehdr->e_ident[EI_DATA]) return XH_ERRNO_FORMAT; - - //check version - if(EV_CURRENT != ehdr->e_ident[EI_VERSION]) return XH_ERRNO_FORMAT; - - //check type - if(ET_EXEC != ehdr->e_type && ET_DYN != ehdr->e_type) return XH_ERRNO_FORMAT; - - //check machine -#if defined(__arm__) - if(EM_ARM != ehdr->e_machine) return XH_ERRNO_FORMAT; -#elif defined(__aarch64__) - if(EM_AARCH64 != ehdr->e_machine) return XH_ERRNO_FORMAT; -#elif defined(__i386__) - if(EM_386 != ehdr->e_machine) return XH_ERRNO_FORMAT; -#elif defined(__x86_64__) - if(EM_X86_64 != ehdr->e_machine) return XH_ERRNO_FORMAT; -#else - return XH_ERRNO_FORMAT; -#endif - - //check version - if(EV_CURRENT != ehdr->e_version) return XH_ERRNO_FORMAT; - - return 0; -} - -//ELF hash func -static uint32_t xh_elf_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; -} - -//GNU hash func -static uint32_t xh_elf_gnu_hash(const uint8_t *name) -{ - uint32_t h = 5381; - - while(*name != 0) - { - h += (h << 5) + *name++; - } - return h; -} - -static ElfW(Phdr) *xh_elf_get_first_segment_by_type(xh_elf_t *self, ElfW(Word) type) -{ - ElfW(Phdr) *phdr; - - for(phdr = self->phdr; phdr < self->phdr + self->ehdr->e_phnum; phdr++) - { - if(phdr->p_type == type) - { - return phdr; - } - } - return NULL; -} - -static ElfW(Phdr) *xh_elf_get_first_segment_by_type_offset(xh_elf_t *self, ElfW(Word) type, ElfW(Off) offset) -{ - ElfW(Phdr) *phdr; - - for(phdr = self->phdr; phdr < self->phdr + self->ehdr->e_phnum; phdr++) - { - if(phdr->p_type == type && phdr->p_offset == offset) - { - return phdr; - } - } - return NULL; -} - -static int xh_elf_hash_lookup(xh_elf_t *self, const char *symbol, uint32_t *symidx) -{ - uint32_t hash = xh_elf_hash((uint8_t *)symbol); - const char *symbol_cur; - uint32_t i; - - for(i = self->bucket[hash % self->bucket_cnt]; 0 != i; i = self->chain[i]) - { - symbol_cur = self->strtab + self->symtab[i].st_name; - - if(0 == strcmp(symbol, symbol_cur)) - { - *symidx = i; - XH_LOG_INFO("found %s at symidx: %u (ELF_HASH)\n", symbol, *symidx); - return 0; - } - } - - return XH_ERRNO_NOTFND; -} - -static int xh_elf_gnu_hash_lookup_def(xh_elf_t *self, const char *symbol, uint32_t *symidx) -{ - uint32_t hash = xh_elf_gnu_hash((uint8_t *)symbol); - - static uint32_t elfclass_bits = sizeof(ElfW(Addr)) * 8; - size_t word = self->bloom[(hash / elfclass_bits) % self->bloom_sz]; - size_t mask = 0 - | (size_t)1 << (hash % elfclass_bits) - | (size_t)1 << ((hash >> self->bloom_shift) % elfclass_bits); - - //if at least one bit is not set, this symbol is surely missing - if((word & mask) != mask) return XH_ERRNO_NOTFND; - - //ignore STN_UNDEF - uint32_t i = self->bucket[hash % self->bucket_cnt]; - if(i < self->symoffset) return XH_ERRNO_NOTFND; - - //loop through the chain - while(1) - { - const char *symname = self->strtab + self->symtab[i].st_name; - const uint32_t symhash = self->chain[i - self->symoffset]; - - if((hash | (uint32_t)1) == (symhash | (uint32_t)1) && 0 == strcmp(symbol, symname)) - { - *symidx = i; - XH_LOG_INFO("found %s at symidx: %u (GNU_HASH DEF)\n", symbol, *symidx); - return 0; - } - - //chain ends with an element with the lowest bit set to 1 - if(symhash & (uint32_t)1) break; - - i++; - } - - return XH_ERRNO_NOTFND; -} - -static int xh_elf_gnu_hash_lookup_undef(xh_elf_t *self, const char *symbol, uint32_t *symidx) -{ - uint32_t i; - - for(i = 0; i < self->symoffset; i++) - { - const char *symname = self->strtab + self->symtab[i].st_name; - if(0 == strcmp(symname, symbol)) - { - *symidx = i; - XH_LOG_INFO("found %s at symidx: %u (GNU_HASH UNDEF)\n", symbol, *symidx); - return 0; - } - } - return XH_ERRNO_NOTFND; -} - -static int xh_elf_gnu_hash_lookup(xh_elf_t *self, const char *symbol, uint32_t *symidx) -{ - if(0 == xh_elf_gnu_hash_lookup_def(self, symbol, symidx)) return 0; - if(0 == xh_elf_gnu_hash_lookup_undef(self, symbol, symidx)) return 0; - return XH_ERRNO_NOTFND; -} - -static int xh_elf_find_symidx_by_name(xh_elf_t *self, const char *symbol, uint32_t *symidx) -{ - if(self->is_use_gnu_hash) - return xh_elf_gnu_hash_lookup(self, symbol, symidx); - else - return xh_elf_hash_lookup(self, symbol, symidx); -} - -static int xh_elf_replace_function(xh_elf_t *self, const char *symbol, ElfW(Addr) addr, void *new_func, void **old_func) -{ - void *old_addr; - unsigned int old_prot = 0; - unsigned int need_prot = PROT_READ | PROT_WRITE; - int r; - - //already replaced? - //here we assume that we always have read permission, is this a problem? - if(*(void **)addr == new_func) return 0; - - //get old prot - if(0 != (r = xh_util_get_addr_protect(addr, self->pathname, &old_prot))) - { - XH_LOG_ERROR("get addr prot failed. ret: %d", r); - return r; - } - - if(old_prot != need_prot) - { - //set new prot - if(0 != (r = xh_util_set_addr_protect(addr, need_prot))) - { - XH_LOG_ERROR("set addr prot failed. ret: %d", r); - return r; - } - } - - //save old func - old_addr = *(void **)addr; - if(NULL != old_func) *old_func = old_addr; - - //replace func - *(void **)addr = new_func; //segmentation fault sometimes - - if(old_prot != need_prot) - { - //restore the old prot - if(0 != (r = xh_util_set_addr_protect(addr, old_prot))) - { - XH_LOG_WARN("restore addr prot failed. ret: %d", r); - } - } - - //clear cache - xh_util_flush_instruction_cache(addr); - - XH_LOG_INFO("XH_HK_OK %p: %p -> %p %s %s\n", (void *)addr, old_addr, new_func, symbol, self->pathname); - return 0; -} - -static int xh_elf_check(xh_elf_t *self) -{ - if(0 == self->base_addr) - { - XH_LOG_ERROR("base_addr == 0\n"); - return 1; - } - if(0 == self->bias_addr) - { - XH_LOG_ERROR("bias_addr == 0\n"); - return 1; - } - if(NULL == self->ehdr) - { - XH_LOG_ERROR("ehdr == NULL\n"); - return 1; - } - if(NULL == self->phdr) - { - XH_LOG_ERROR("phdr == NULL\n"); - return 1; - } - if(NULL == self->strtab) - { - XH_LOG_ERROR("strtab == NULL\n"); - return 1; - } - if(NULL == self->symtab) - { - XH_LOG_ERROR("symtab == NULL\n"); - return 1; - } - if(NULL == self->bucket) - { - XH_LOG_ERROR("bucket == NULL\n"); - return 1; - } - if(NULL == self->chain) - { - XH_LOG_ERROR("chain == NULL\n"); - return 1; - } - if(1 == self->is_use_gnu_hash && NULL == self->bloom) - { - XH_LOG_ERROR("bloom == NULL\n"); - return 1; - } - - return 0; -} - -#if XH_ELF_DEBUG - -static void xh_elf_dump_elfheader(xh_elf_t *self) -{ - static char alpha_tab[17] = "0123456789ABCDEF"; - int i; - uint8_t ch; - char buff[EI_NIDENT * 3 + 1]; - - for(i = 0; i < EI_NIDENT; i++) - { - ch = self->ehdr->e_ident[i]; - buff[i * 3 + 0] = alpha_tab[(int)((ch >> 4) & 0x0F)]; - buff[i * 3 + 1] = alpha_tab[(int)(ch & 0x0F)]; - buff[i * 3 + 2] = ' '; - } - buff[EI_NIDENT * 3] = '\0'; - - XH_LOG_DEBUG("Elf Header:\n"); - XH_LOG_DEBUG(" Magic: %s\n", buff); - XH_LOG_DEBUG(" Class: %#x\n", self->ehdr->e_ident[EI_CLASS]); - XH_LOG_DEBUG(" Data: %#x\n", self->ehdr->e_ident[EI_DATA]); - XH_LOG_DEBUG(" Version: %#x\n", self->ehdr->e_ident[EI_VERSION]); - XH_LOG_DEBUG(" OS/ABI: %#x\n", self->ehdr->e_ident[EI_OSABI]); - XH_LOG_DEBUG(" ABI Version: %#x\n", self->ehdr->e_ident[EI_ABIVERSION]); - XH_LOG_DEBUG(" Type: %#x\n", self->ehdr->e_type); - XH_LOG_DEBUG(" Machine: %#x\n", self->ehdr->e_machine); - XH_LOG_DEBUG(" Version: %#x\n", self->ehdr->e_version); - XH_LOG_DEBUG(" Entry point address: %"XH_UTIL_FMT_X"\n", self->ehdr->e_entry); - XH_LOG_DEBUG(" Start of program headers: %"XH_UTIL_FMT_X" (bytes into file)\n", self->ehdr->e_phoff); - XH_LOG_DEBUG(" Start of section headers: %"XH_UTIL_FMT_X" (bytes into file)\n", self->ehdr->e_shoff); - XH_LOG_DEBUG(" Flags: %#x\n", self->ehdr->e_flags); - XH_LOG_DEBUG(" Size of this header: %u (bytes)\n", self->ehdr->e_ehsize); - XH_LOG_DEBUG(" Size of program headers: %u (bytes)\n", self->ehdr->e_phentsize); - XH_LOG_DEBUG(" Number of program headers: %u\n", self->ehdr->e_phnum); - XH_LOG_DEBUG(" Size of section headers: %u (bytes)\n", self->ehdr->e_shentsize); - XH_LOG_DEBUG(" Number of section headers: %u\n", self->ehdr->e_shnum); - XH_LOG_DEBUG(" Section header string table index: %u\n", self->ehdr->e_shstrndx); -} - -static void xh_elf_dump_programheader(xh_elf_t *self) -{ - ElfW(Phdr) *phdr = self->phdr; - size_t i; - - XH_LOG_DEBUG("Program Headers:\n"); - XH_LOG_DEBUG(" %-8s " \ - "%-"XH_UTIL_FMT_FIXED_S" " \ - "%-"XH_UTIL_FMT_FIXED_S" " \ - "%-"XH_UTIL_FMT_FIXED_S" " \ - "%-"XH_UTIL_FMT_FIXED_S" " \ - "%-"XH_UTIL_FMT_FIXED_S" " \ - "%-8s " \ - "%-s\n", - "Type", - "Offset", - "VirtAddr", - "PhysAddr", - "FileSiz", - "MemSiz", - "Flg", - "Align"); - for(i = 0; i < self->ehdr->e_phnum; i++, phdr++) - { - XH_LOG_DEBUG(" %-8x " \ - "%."XH_UTIL_FMT_FIXED_X" " \ - "%."XH_UTIL_FMT_FIXED_X" " \ - "%."XH_UTIL_FMT_FIXED_X" " \ - "%."XH_UTIL_FMT_FIXED_X" " \ - "%."XH_UTIL_FMT_FIXED_X" " \ - "%-8x " \ - "%"XH_UTIL_FMT_X"\n", - phdr->p_type, - phdr->p_offset, - phdr->p_vaddr, - phdr->p_paddr, - phdr->p_filesz, - phdr->p_memsz, - phdr->p_flags, - phdr->p_align); - } -} - -static void xh_elf_dump_dynamic(xh_elf_t *self) -{ - ElfW(Dyn) *dyn = self->dyn; - size_t dyn_cnt = (self->dyn_sz / sizeof(ElfW(Dyn))); - size_t i; - - XH_LOG_DEBUG("Dynamic section contains %zu entries:\n", dyn_cnt); - XH_LOG_DEBUG(" %-"XH_UTIL_FMT_FIXED_S" " \ - "%s\n", - "Tag", - "Val"); - for(i = 0; i < dyn_cnt; i++, dyn++) - { - XH_LOG_DEBUG(" %-"XH_UTIL_FMT_FIXED_X" " \ - "%-"XH_UTIL_FMT_X"\n", - dyn->d_tag, - dyn->d_un.d_val); - } -} - -static void xh_elf_dump_rel(xh_elf_t *self, const char *type, ElfW(Addr) rel_addr, ElfW(Word) rel_sz) -{ - ElfW(Rela) *rela; - ElfW(Rel) *rel; - ElfW(Word) cnt; - ElfW(Word) i; - ElfW(Sym) *sym; - - if(self->is_use_rela) - { - rela = (ElfW(Rela) *)(rel_addr); - cnt = rel_sz / sizeof(ElfW(Rela)); - } - else - { - rel = (ElfW(Rel) *)(rel_addr); - cnt = rel_sz / sizeof(ElfW(Rel)); - } - - XH_LOG_DEBUG("Relocation section '.rel%s%s' contains %u entries:\n", - (self->is_use_rela ? "a" : ""), type, cnt); - XH_LOG_DEBUG(" %-"XH_UTIL_FMT_FIXED_S" " \ - "%-"XH_UTIL_FMT_FIXED_S" " \ - "%-8s " \ - "%-8s " \ - "%-8s " \ - "%s\n", - "Offset", - "Info", - "Type", - "Sym.Idx", - "Sym.Val", - "Sym.Name"); - const char *fmt = " %."XH_UTIL_FMT_FIXED_X" " \ - "%."XH_UTIL_FMT_FIXED_X" " \ - "%.8x " \ - "%.8u " \ - "%.8x " \ - "%s\n"; - for(i = 0; i < cnt; i++) - { - if(self->is_use_rela) - { - sym = &(self->symtab[XH_ELF_R_SYM(rela[i].r_info)]); - XH_LOG_DEBUG(fmt, - rela[i].r_offset, - rela[i].r_info, - XH_ELF_R_TYPE(rela[i].r_info), - XH_ELF_R_SYM(rela[i].r_info), - sym->st_value, - self->strtab + sym->st_name); - } - else - { - sym = &(self->symtab[XH_ELF_R_SYM(rel[i].r_info)]); - XH_LOG_DEBUG(fmt, - rel[i].r_offset, - rel[i].r_info, - XH_ELF_R_TYPE(rel[i].r_info), - XH_ELF_R_SYM(rel[i].r_info), - sym->st_value, - self->strtab + sym->st_name); - } - } -} - -static void xh_elf_dump_symtab(xh_elf_t *self) -{ - if(self->is_use_gnu_hash) return; - - ElfW(Word) symtab_cnt = self->chain_cnt; - ElfW(Word) i; - - XH_LOG_DEBUG("Symbol table '.dynsym' contains %u entries:\n", symtab_cnt); - XH_LOG_DEBUG(" %-8s " \ - "%-"XH_UTIL_FMT_FIXED_S" " \ - "%s\n", - "Idx", - "Value", - "Name"); - for(i = 0; i < symtab_cnt; i++) - { - XH_LOG_DEBUG(" %-8u " \ - "%."XH_UTIL_FMT_FIXED_X" " \ - "%s\n", - i, - self->symtab[i].st_value, - self->strtab + self->symtab[i].st_name); - } -} - -static void xh_elf_dump(xh_elf_t *self) -{ - if(xh_log_priority < ANDROID_LOG_DEBUG) return; - - XH_LOG_DEBUG("Elf Pathname: %s\n", self->pathname); - XH_LOG_DEBUG("Elf bias addr: %p\n", (void *)self->bias_addr); - xh_elf_dump_elfheader(self); - xh_elf_dump_programheader(self); - xh_elf_dump_dynamic(self); - xh_elf_dump_rel(self, ".plt", self->relplt, self->relplt_sz); - xh_elf_dump_rel(self, ".dyn", self->reldyn, self->reldyn_sz); - xh_elf_dump_symtab(self); -} - -#endif - -int xh_elf_init(xh_elf_t *self, uintptr_t base_addr, const char *pathname) -{ - if(0 == base_addr || NULL == pathname) return XH_ERRNO_INVAL; - - //always reset - memset(self, 0, sizeof(xh_elf_t)); - - self->pathname = pathname; - self->base_addr = (ElfW(Addr))base_addr; - self->ehdr = (ElfW(Ehdr) *)base_addr; - self->phdr = (ElfW(Phdr) *)(base_addr + self->ehdr->e_phoff); //segmentation fault sometimes - - //find the first load-segment with offset 0 - ElfW(Phdr) *phdr0 = xh_elf_get_first_segment_by_type_offset(self, PT_LOAD, 0); - if(NULL == phdr0) - { - XH_LOG_ERROR("Can NOT found the first load segment. %s", pathname); - return XH_ERRNO_FORMAT; - } - -#if XH_ELF_DEBUG - if(0 != phdr0->p_vaddr) - XH_LOG_DEBUG("first load-segment vaddr NOT 0 (vaddr: %p). %s", - (void *)(phdr0->p_vaddr), pathname); -#endif - - //save load bias addr - if(self->base_addr < phdr0->p_vaddr) return XH_ERRNO_FORMAT; - self->bias_addr = self->base_addr - phdr0->p_vaddr; - - //find dynamic-segment - ElfW(Phdr) *dhdr = xh_elf_get_first_segment_by_type(self, PT_DYNAMIC); - if(NULL == dhdr) - { - XH_LOG_ERROR("Can NOT found dynamic segment. %s", pathname); - return XH_ERRNO_FORMAT; - } - - //parse dynamic-segment - self->dyn = (ElfW(Dyn) *)(self->bias_addr + dhdr->p_vaddr); - self->dyn_sz = dhdr->p_memsz; - ElfW(Dyn) *dyn = self->dyn; - ElfW(Dyn) *dyn_end = self->dyn + (self->dyn_sz / sizeof(ElfW(Dyn))); - uint32_t *raw; - for(; dyn < dyn_end; dyn++) - { - switch(dyn->d_tag) //segmentation fault sometimes - { - case DT_NULL: - //the end of the dynamic-section - dyn = dyn_end; - break; - case DT_STRTAB: - { - self->strtab = (const char *)(self->bias_addr + dyn->d_un.d_ptr); - if((ElfW(Addr))(self->strtab) < self->base_addr) return XH_ERRNO_FORMAT; - break; - } - case DT_SYMTAB: - { - self->symtab = (ElfW(Sym) *)(self->bias_addr + dyn->d_un.d_ptr); - if((ElfW(Addr))(self->symtab) < self->base_addr) return XH_ERRNO_FORMAT; - break; - } - case DT_PLTREL: - //use rel or rela? - self->is_use_rela = (dyn->d_un.d_val == DT_RELA ? 1 : 0); - break; - case DT_JMPREL: - { - self->relplt = (ElfW(Addr))(self->bias_addr + dyn->d_un.d_ptr); - if((ElfW(Addr))(self->relplt) < self->base_addr) return XH_ERRNO_FORMAT; - break; - } - case DT_PLTRELSZ: - self->relplt_sz = dyn->d_un.d_val; - break; - case DT_REL: - case DT_RELA: - { - self->reldyn = (ElfW(Addr))(self->bias_addr + dyn->d_un.d_ptr); - if((ElfW(Addr))(self->reldyn) < self->base_addr) return XH_ERRNO_FORMAT; - break; - } - case DT_RELSZ: - case DT_RELASZ: - self->reldyn_sz = dyn->d_un.d_val; - break; - case DT_ANDROID_REL: - case DT_ANDROID_RELA: - { - self->relandroid = (ElfW(Addr))(self->bias_addr + dyn->d_un.d_ptr); - if((ElfW(Addr))(self->relandroid) < self->base_addr) return XH_ERRNO_FORMAT; - break; - } - case DT_ANDROID_RELSZ: - case DT_ANDROID_RELASZ: - self->relandroid_sz = dyn->d_un.d_val; - break; - case DT_HASH: - { - //ignore DT_HASH when ELF contains DT_GNU_HASH hash table - if(1 == self->is_use_gnu_hash) continue; - - raw = (uint32_t *)(self->bias_addr + dyn->d_un.d_ptr); - if((ElfW(Addr))raw < self->base_addr) return XH_ERRNO_FORMAT; - self->bucket_cnt = raw[0]; - self->chain_cnt = raw[1]; - self->bucket = &raw[2]; - self->chain = &(self->bucket[self->bucket_cnt]); - break; - } - case DT_GNU_HASH: - { - raw = (uint32_t *)(self->bias_addr + dyn->d_un.d_ptr); - if((ElfW(Addr))raw < self->base_addr) return XH_ERRNO_FORMAT; - self->bucket_cnt = raw[0]; - self->symoffset = raw[1]; - self->bloom_sz = raw[2]; - self->bloom_shift = raw[3]; - self->bloom = (ElfW(Addr) *)(&raw[4]); - self->bucket = (uint32_t *)(&(self->bloom[self->bloom_sz])); - self->chain = (uint32_t *)(&(self->bucket[self->bucket_cnt])); - self->is_use_gnu_hash = 1; - break; - } - default: - break; - } - } - - //check android rel/rela - if(0 != self->relandroid) - { - const char *rel = (const char *)self->relandroid; - if(self->relandroid_sz < 4 || - rel[0] != 'A' || - rel[1] != 'P' || - rel[2] != 'S' || - rel[3] != '2') - { - XH_LOG_ERROR("android rel/rela format error\n"); - return XH_ERRNO_FORMAT; - } - - self->relandroid += 4; - self->relandroid_sz -= 4; - } - - //check elf info - if(0 != xh_elf_check(self)) - { - XH_LOG_ERROR("elf init check failed. %s", pathname); - return XH_ERRNO_FORMAT; - } - -#if XH_ELF_DEBUG - xh_elf_dump(self); -#endif - - XH_LOG_INFO("init OK: %s (%s %s PLT:%u DYN:%u ANDROID:%u)\n", self->pathname, - self->is_use_rela ? "RELA" : "REL", - self->is_use_gnu_hash ? "GNU_HASH" : "ELF_HASH", - self->relplt_sz, self->reldyn_sz, self->relandroid_sz); - - return 0; -} - -static int xh_elf_find_and_replace_func(xh_elf_t *self, const char *section, - int is_plt, const char *symbol, - void *new_func, void **old_func, - uint32_t symidx, void *rel_common, - int *found) -{ - ElfW(Rela) *rela; - ElfW(Rel) *rel; - ElfW(Addr) r_offset; - size_t r_info; - size_t r_sym; - size_t r_type; - ElfW(Addr) addr; - int r; - - if(NULL != found) *found = 0; - - if(self->is_use_rela) - { - rela = (ElfW(Rela) *)rel_common; - r_info = rela->r_info; - r_offset = rela->r_offset; - } - else - { - rel = (ElfW(Rel) *)rel_common; - r_info = rel->r_info; - r_offset = rel->r_offset; - } - - //check sym - r_sym = XH_ELF_R_SYM(r_info); - if(r_sym != symidx) return 0; - - //check type - r_type = XH_ELF_R_TYPE(r_info); - if(is_plt && r_type != XH_ELF_R_GENERIC_JUMP_SLOT) return 0; - if(!is_plt && (r_type != XH_ELF_R_GENERIC_GLOB_DAT && r_type != XH_ELF_R_GENERIC_ABS)) return 0; - - //we found it - XH_LOG_INFO("found %s at %s offset: %p\n", symbol, section, (void *)r_offset); - if(NULL != found) *found = 1; - - //do replace - addr = self->bias_addr + r_offset; - if(addr < self->base_addr) return XH_ERRNO_FORMAT; - if(0 != (r = xh_elf_replace_function(self, symbol, addr, new_func, old_func))) - { - XH_LOG_ERROR("replace function failed: %s at %s\n", symbol, section); - return r; - } - - return 0; -} - -int xh_elf_hook(xh_elf_t *self, const char *symbol, void *new_func, void **old_func) -{ - uint32_t symidx; - void *rel_common; - xh_elf_plain_reloc_iterator_t plain_iter; - xh_elf_packed_reloc_iterator_t packed_iter; - int found; - int r; - - if(NULL == self->pathname) - { - XH_LOG_ERROR("not inited\n"); - return XH_ERRNO_ELFINIT; //not inited? - } - - if(NULL == symbol || NULL == new_func) return XH_ERRNO_INVAL; - - XH_LOG_INFO("hooking %s in %s\n", symbol, self->pathname); - - //find symbol index by symbol name - if(0 != (r = xh_elf_find_symidx_by_name(self, symbol, &symidx))) return 0; - - //replace for .rel(a).plt - if(0 != self->relplt) - { - xh_elf_plain_reloc_iterator_init(&plain_iter, self->relplt, self->relplt_sz, self->is_use_rela); - while(NULL != (rel_common = xh_elf_plain_reloc_iterator_next(&plain_iter))) - { - if(0 != (r = xh_elf_find_and_replace_func(self, - (self->is_use_rela ? ".rela.plt" : ".rel.plt"), 1, - symbol, new_func, old_func, - symidx, rel_common, &found))) return r; - if(found) break; - } - } - - //replace for .rel(a).dyn - if(0 != self->reldyn) - { - xh_elf_plain_reloc_iterator_init(&plain_iter, self->reldyn, self->reldyn_sz, self->is_use_rela); - while(NULL != (rel_common = xh_elf_plain_reloc_iterator_next(&plain_iter))) - { - if(0 != (r = xh_elf_find_and_replace_func(self, - (self->is_use_rela ? ".rela.dyn" : ".rel.dyn"), 0, - symbol, new_func, old_func, - symidx, rel_common, NULL))) return r; - } - } - - //replace for .rel(a).android - if(0 != self->relandroid) - { - xh_elf_packed_reloc_iterator_init(&packed_iter, self->relandroid, self->relandroid_sz, self->is_use_rela); - while(NULL != (rel_common = xh_elf_packed_reloc_iterator_next(&packed_iter))) - { - if(0 != (r = xh_elf_find_and_replace_func(self, - (self->is_use_rela ? ".rela.android" : ".rel.android"), 0, - symbol, new_func, old_func, - symidx, rel_common, NULL))) return r; - } - } - - return 0; -} diff --git a/FCLauncher/src/main/jni/xhook/xh_jni.c b/FCLauncher/src/main/jni/xhook/xh_jni.c deleted file mode 100644 index 6acf7e61..00000000 --- a/FCLauncher/src/main/jni/xhook/xh_jni.c +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. -// -// 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 2018-04-11. - -#include -#include - -#define JNI_API_DEF(f) Java_com_qiyi_xhook_NativeHandler_##f - -JNIEXPORT jint JNI_API_DEF(refresh)(JNIEnv *env, jobject obj, jboolean async) -{ - (void)env; - (void)obj; - - return xhook_refresh(async ? 1 : 0); -} - -JNIEXPORT void JNI_API_DEF(clear)(JNIEnv *env, jobject obj) -{ - (void)env; - (void)obj; - - xhook_clear(); -} - -JNIEXPORT void JNI_API_DEF(enableDebug)(JNIEnv *env, jobject obj, jboolean flag) -{ - (void)env; - (void)obj; - - xhook_enable_debug(flag ? 1 : 0); -} - -JNIEXPORT void JNI_API_DEF(enableSigSegvProtection)(JNIEnv *env, jobject obj, jboolean flag) -{ - (void)env; - (void)obj; - - xhook_enable_sigsegv_protection(flag ? 1 : 0); -} diff --git a/FCLauncher/src/main/jni/xhook/xh_log.c b/FCLauncher/src/main/jni/xhook/xh_log.c deleted file mode 100644 index efa5549b..00000000 --- a/FCLauncher/src/main/jni/xhook/xh_log.c +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. -// -// 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 2018-04-11. - -#include -#include - -android_LogPriority xh_log_priority = ANDROID_LOG_WARN; diff --git a/FCLauncher/src/main/jni/xhook/xh_util.c b/FCLauncher/src/main/jni/xhook/xh_util.c deleted file mode 100644 index 919ae8ea..00000000 --- a/FCLauncher/src/main/jni/xhook/xh_util.c +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. -// -// 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 2018-04-11. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PAGE_START(addr) ((addr) & PAGE_MASK) -#define PAGE_END(addr) (PAGE_START(addr + sizeof(uintptr_t) - 1) + PAGE_SIZE) -#define PAGE_COVER(addr) (PAGE_END(addr) - PAGE_START(addr)) - -int xh_util_get_mem_protect(uintptr_t addr, size_t len, const char *pathname, unsigned int *prot) -{ - uintptr_t start_addr = addr; - uintptr_t end_addr = addr + len; - FILE *fp; - char line[512]; - uintptr_t start, end; - char perm[5]; - int load0 = 1; - int found_all = 0; - - *prot = 0; - - if(NULL == (fp = fopen("/proc/self/maps", "r"))) return XH_ERRNO_BADMAPS; - - while(fgets(line, sizeof(line), fp)) - { - if(NULL != pathname) - if(NULL == strstr(line, pathname)) continue; - - if(sscanf(line, "%"PRIxPTR"-%"PRIxPTR" %4s ", &start, &end, perm) != 3) continue; - - if(perm[3] != 'p') continue; - - if(start_addr >= start && start_addr < end) - { - if(load0) - { - //first load segment - if(perm[0] == 'r') *prot |= PROT_READ; - if(perm[1] == 'w') *prot |= PROT_WRITE; - if(perm[2] == 'x') *prot |= PROT_EXEC; - load0 = 0; - } - else - { - //others - if(perm[0] != 'r') *prot &= ~PROT_READ; - if(perm[1] != 'w') *prot &= ~PROT_WRITE; - if(perm[2] != 'x') *prot &= ~PROT_EXEC; - } - - if(end_addr <= end) - { - found_all = 1; - break; //finished - } - else - { - start_addr = end; //try to find the next load segment - } - } - } - - fclose(fp); - - if(!found_all) return XH_ERRNO_SEGVERR; - - return 0; -} - -int xh_util_get_addr_protect(uintptr_t addr, const char *pathname, unsigned int *prot) -{ - return xh_util_get_mem_protect(addr, sizeof(addr), pathname, prot); -} - -int xh_util_set_addr_protect(uintptr_t addr, unsigned int prot) -{ - if(0 != mprotect((void *)PAGE_START(addr), PAGE_COVER(addr), (int)prot)) - return 0 == errno ? XH_ERRNO_UNKNOWN : errno; - - return 0; -} - -void xh_util_flush_instruction_cache(uintptr_t addr) -{ - __builtin___clear_cache((void *)PAGE_START(addr), (void *)PAGE_END(addr)); -} diff --git a/FCLauncher/src/main/jni/xhook/xh_version.c b/FCLauncher/src/main/jni/xhook/xh_version.c deleted file mode 100644 index b2e3222f..00000000 --- a/FCLauncher/src/main/jni/xhook/xh_version.c +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. -// -// 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 2018-04-11. - -#include - -#define XH_VERSION_MAJOR 1 -#define XH_VERSION_MINOR 2 -#define XH_VERSION_EXTRA 0 - -#define XH_VERSION ((XH_VERSION_MAJOR << 16) | (XH_VERSION_MINOR << 8) | (XH_VERSION_EXTRA)) - -#define XH_VERSION_TO_STR_HELPER(x) #x -#define XH_VERSION_TO_STR(x) XH_VERSION_TO_STR_HELPER(x) - -#define XH_VERSION_STR XH_VERSION_TO_STR(XH_VERSION_MAJOR) "." \ - XH_VERSION_TO_STR(XH_VERSION_MINOR) "." \ - XH_VERSION_TO_STR(XH_VERSION_EXTRA) - -#if defined(__arm__) -#define XH_VERSION_ARCH "arm" -#elif defined(__aarch64__) -#define XH_VERSION_ARCH "aarch64" -#elif defined(__i386__) -#define XH_VERSION_ARCH "x86" -#elif defined(__x86_64__) -#define XH_VERSION_ARCH "x86_64" -#else -#define XH_VERSION_ARCH "unknown" -#endif - -#define XH_VERSION_STR_FULL "libxhook "XH_VERSION_STR" ("XH_VERSION_ARCH")" - -unsigned int xh_version() -{ - return XH_VERSION; -} - -const char *xh_version_str() -{ - return XH_VERSION_STR; -} - -const char *xh_version_str_full() -{ - return XH_VERSION_STR_FULL; -} diff --git a/FCLauncher/src/main/jni/xhook/xhook.c b/FCLauncher/src/main/jni/xhook/xhook.c deleted file mode 100644 index 9d4b7765..00000000 --- a/FCLauncher/src/main/jni/xhook/xhook.c +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. -// -// 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 2018-04-11. - -#include -#include - -int xhook_register(const char *pathname_regex_str, const char *symbol, - void *new_func, void **old_func) -{ - return xh_core_register(pathname_regex_str, symbol, new_func, old_func); -} - -int xhook_ignore(const char *pathname_regex_str, const char *symbol) -{ - return xh_core_ignore(pathname_regex_str, symbol); -} - -int xhook_refresh(int async) -{ - return xh_core_refresh(async); -} - -void xhook_clear() -{ - return xh_core_clear(); -} - -void xhook_enable_debug(int flag) -{ - return xh_core_enable_debug(flag); -} - -void xhook_enable_sigsegv_protection(int flag) -{ - return xh_core_enable_sigsegv_protection(flag); -}