├── .gitignore ├── README.md ├── build.gradle ├── build.sh ├── jni ├── .gitattributes ├── Android.mk ├── Application.mk ├── external │ ├── Android.mk │ ├── include │ │ └── xhook │ │ │ └── xhook.h │ └── xhook │ │ ├── queue.h │ │ ├── tree.h │ │ ├── xh_core.c │ │ ├── xh_core.h │ │ ├── xh_elf.c │ │ ├── xh_elf.h │ │ ├── xh_errno.h │ │ ├── xh_jni.c │ │ ├── xh_log.c │ │ ├── xh_log.h │ │ ├── xh_util.c │ │ ├── xh_util.h │ │ ├── xh_version.c │ │ ├── xh_version.h │ │ ├── xhook.c │ │ └── xhook.h └── main │ ├── Android.mk │ ├── hook.cpp │ ├── hook.h │ ├── logging.h │ ├── main.cpp │ ├── misc.cpp │ ├── misc.h │ ├── riru.c │ └── riru.h ├── src └── main │ └── AndroidManifest.xml └── template_override ├── common ├── service.sh └── system.prop ├── config.sh ├── module.prop └── riru_module.prop /.gitignore: -------------------------------------------------------------------------------- 1 | /.externalNativeBuild 2 | /build 3 | /libs 4 | /obj 5 | /release 6 | /magisk-module/system 7 | /magisk-module/*.zip 8 | *.iml -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # THIS REPO has been DESPERATED 2 | # [MOVE TO HERE](https://github.com/MiPushFramework/MiPushFakeForRiru) 3 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion rootProject.ext.targetSdkVersion 5 | defaultConfig { 6 | minSdkVersion rootProject.ext.minSdkVersion 7 | targetSdkVersion rootProject.ext.targetSdkVersion 8 | 9 | externalNativeBuild { 10 | ndkBuild { 11 | abiFilters 'arm64-v8a', 'armeabi-v7a' 12 | arguments "NDK_PROJECT_PATH=jni/" 13 | } 14 | } 15 | } 16 | externalNativeBuild { 17 | ndkBuild { 18 | path 'jni/Android.mk' 19 | } 20 | } 21 | } 22 | 23 | task zip(type: Exec) { 24 | workingDir '..' 25 | commandLine 'sh', 'build.sh', project.name, 'v10' 26 | } 27 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | function copy_files { 2 | # /data/misc/riru/modules/template exists -> libriru_template.so will be loaded 3 | # Change "template" to your module name 4 | # You can also use this folder as your config folder 5 | NAME="mipush_fake" 6 | mkdir -p $TMP_DIR_MAGISK/data/misc/riru/modules/$NAME 7 | cp $MODULE_NAME/template_override/riru_module.prop $TMP_DIR_MAGISK/data/misc/riru/modules/$NAME/module.prop 8 | 9 | cp $MODULE_NAME/template_override/config.sh $TMP_DIR_MAGISK 10 | cp $MODULE_NAME/template_override/module.prop $TMP_DIR_MAGISK 11 | cp -r $MODULE_NAME/template_override/common $TMP_DIR_MAGISK 12 | } -------------------------------------------------------------------------------- /jni/.gitattributes: -------------------------------------------------------------------------------- 1 | libs/** binary 2 | -------------------------------------------------------------------------------- /jni/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(call all-makefiles-under, $(LOCAL_PATH)) -------------------------------------------------------------------------------- /jni/Application.mk: -------------------------------------------------------------------------------- 1 | APP_ABI := arm64-v8a armeabi-v7a# x86 x86_64 2 | APP_PLATFORM := android-23 3 | APP_CFLAGS := -std=gnu99 4 | APP_CPPFLAGS := -std=c++11 5 | APP_STL := c++_static 6 | APP_SHORT_COMMANDS := true -------------------------------------------------------------------------------- /jni/external/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | LOCAL_MODULE := xhook 5 | LOCAL_SRC_FILES := xhook/xhook.c \ 6 | xhook/xh_core.c \ 7 | xhook/xh_elf.c \ 8 | xhook/xh_jni.c \ 9 | xhook/xh_log.c \ 10 | xhook/xh_util.c \ 11 | xhook/xh_version.c 12 | LOCAL_C_INCLUDES := $(LOCAL_PATH) 13 | LOCAL_CFLAGS := -Wall -Wextra -Werror -fvisibility=hidden 14 | LOCAL_CONLYFLAGS := -std=c11 15 | LOCAL_LDLIBS := -llog 16 | include $(BUILD_STATIC_LIBRARY) -------------------------------------------------------------------------------- /jni/external/include/xhook/xhook.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #ifndef XHOOK_H 25 | #define XHOOK_H 1 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | #define XHOOK_EXPORT __attribute__((visibility("default"))) 32 | 33 | int xhook_register(const char *pathname_regex_str, const char *symbol, 34 | void *new_func, void **old_func) XHOOK_EXPORT; 35 | 36 | int xhook_ignore(const char *pathname_regex_str, const char *symbol) XHOOK_EXPORT; 37 | 38 | int xhook_refresh(int async) XHOOK_EXPORT; 39 | 40 | void xhook_clear() XHOOK_EXPORT; 41 | 42 | void xhook_enable_debug(int flag) XHOOK_EXPORT; 43 | 44 | void xhook_enable_sigsegv_protection(int flag) XHOOK_EXPORT; 45 | 46 | #ifdef __cplusplus 47 | } 48 | #endif 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /jni/external/xhook/queue.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 1991, 1993 3 | * The Regents of the University of California. All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. Neither the name of the University nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | * 29 | * @(#)queue.h 8.5 (Berkeley) 8/20/94 30 | * $FreeBSD: stable/9/sys/sys/queue.h 252365 2013-06-29 04:25:40Z lstewart $ 31 | */ 32 | 33 | #ifndef QUEUE_H 34 | #define QUEUE_H 35 | 36 | /* #include */ 37 | #define __containerof(ptr, type, field) ((type *)((char *)(ptr) - ((char *)&((type *)0)->field))) 38 | 39 | /* 40 | * This file defines four types of data structures: singly-linked lists, 41 | * singly-linked tail queues, lists and tail queues. 42 | * 43 | * A singly-linked list is headed by a single forward pointer. The elements 44 | * are singly linked for minimum space and pointer manipulation overhead at 45 | * the expense of O(n) removal for arbitrary elements. New elements can be 46 | * added to the list after an existing element or at the head of the list. 47 | * Elements being removed from the head of the list should use the explicit 48 | * macro for this purpose for optimum efficiency. A singly-linked list may 49 | * only be traversed in the forward direction. Singly-linked lists are ideal 50 | * for applications with large datasets and few or no removals or for 51 | * implementing a LIFO queue. 52 | * 53 | * A singly-linked tail queue is headed by a pair of pointers, one to the 54 | * head of the list and the other to the tail of the list. The elements are 55 | * singly linked for minimum space and pointer manipulation overhead at the 56 | * expense of O(n) removal for arbitrary elements. New elements can be added 57 | * to the list after an existing element, at the head of the list, or at the 58 | * end of the list. Elements being removed from the head of the tail queue 59 | * should use the explicit macro for this purpose for optimum efficiency. 60 | * A singly-linked tail queue may only be traversed in the forward direction. 61 | * Singly-linked tail queues are ideal for applications with large datasets 62 | * and few or no removals or for implementing a FIFO queue. 63 | * 64 | * A list is headed by a single forward pointer (or an array of forward 65 | * pointers for a hash table header). The elements are doubly linked 66 | * so that an arbitrary element can be removed without a need to 67 | * traverse the list. New elements can be added to the list before 68 | * or after an existing element or at the head of the list. A list 69 | * may be traversed in either direction. 70 | * 71 | * A tail queue is headed by a pair of pointers, one to the head of the 72 | * list and the other to the tail of the list. The elements are doubly 73 | * linked so that an arbitrary element can be removed without a need to 74 | * traverse the list. New elements can be added to the list before or 75 | * after an existing element, at the head of the list, or at the end of 76 | * the list. A tail queue may be traversed in either direction. 77 | * 78 | * For details on the use of these macros, see the queue(3) manual page. 79 | * 80 | * SLIST LIST STAILQ TAILQ 81 | * _HEAD + + + + 82 | * _HEAD_INITIALIZER + + + + 83 | * _ENTRY + + + + 84 | * _INIT + + + + 85 | * _EMPTY + + + + 86 | * _FIRST + + + + 87 | * _NEXT + + + + 88 | * _PREV - + - + 89 | * _LAST - - + + 90 | * _FOREACH + + + + 91 | * _FOREACH_FROM + + + + 92 | * _FOREACH_SAFE + + + + 93 | * _FOREACH_FROM_SAFE + + + + 94 | * _FOREACH_REVERSE - - - + 95 | * _FOREACH_REVERSE_FROM - - - + 96 | * _FOREACH_REVERSE_SAFE - - - + 97 | * _FOREACH_REVERSE_FROM_SAFE - - - + 98 | * _INSERT_HEAD + + + + 99 | * _INSERT_BEFORE - + - + 100 | * _INSERT_AFTER + + + + 101 | * _INSERT_TAIL - - + + 102 | * _CONCAT - - + + 103 | * _REMOVE_AFTER + - + - 104 | * _REMOVE_HEAD + - + - 105 | * _REMOVE + + + + 106 | * _SWAP + + + + 107 | * 108 | */ 109 | 110 | /* 111 | * Singly-linked List declarations. 112 | */ 113 | #define SLIST_HEAD(name, type, qual) \ 114 | struct name { \ 115 | struct type *qual slh_first; /* first element */ \ 116 | } 117 | 118 | #define SLIST_HEAD_INITIALIZER(head) \ 119 | { NULL } 120 | 121 | #define SLIST_ENTRY(type, qual) \ 122 | struct { \ 123 | struct type *qual sle_next; /* next element */ \ 124 | } 125 | 126 | /* 127 | * Singly-linked List functions. 128 | */ 129 | #define SLIST_INIT(head) do { \ 130 | SLIST_FIRST((head)) = NULL; \ 131 | } while (0) 132 | 133 | #define SLIST_EMPTY(head) ((head)->slh_first == NULL) 134 | 135 | #define SLIST_FIRST(head) ((head)->slh_first) 136 | 137 | #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) 138 | 139 | #define SLIST_FOREACH(var, head, field) \ 140 | for ((var) = SLIST_FIRST((head)); \ 141 | (var); \ 142 | (var) = SLIST_NEXT((var), field)) 143 | 144 | #define SLIST_FOREACH_FROM(var, head, field) \ 145 | for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \ 146 | (var); \ 147 | (var) = SLIST_NEXT((var), field)) 148 | 149 | #define SLIST_FOREACH_SAFE(var, head, field, tvar) \ 150 | for ((var) = SLIST_FIRST((head)); \ 151 | (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ 152 | (var) = (tvar)) 153 | 154 | #define SLIST_FOREACH_FROM_SAFE(var, head, field, tvar) \ 155 | for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \ 156 | (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ 157 | (var) = (tvar)) 158 | 159 | #define SLIST_INSERT_HEAD(head, elm, field) do { \ 160 | SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ 161 | SLIST_FIRST((head)) = (elm); \ 162 | } while (0) 163 | 164 | #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ 165 | SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ 166 | SLIST_NEXT((slistelm), field) = (elm); \ 167 | } while (0) 168 | 169 | #define SLIST_REMOVE_AFTER(elm, field) do { \ 170 | SLIST_NEXT(elm, field) = \ 171 | SLIST_NEXT(SLIST_NEXT(elm, field), field); \ 172 | } while (0) 173 | 174 | #define SLIST_REMOVE_HEAD(head, field) do { \ 175 | SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ 176 | } while (0) 177 | 178 | #define SLIST_REMOVE(head, elm, type, field) do { \ 179 | if (SLIST_FIRST((head)) == (elm)) { \ 180 | SLIST_REMOVE_HEAD((head), field); \ 181 | } \ 182 | else { \ 183 | struct type *curelm = SLIST_FIRST((head)); \ 184 | while (SLIST_NEXT(curelm, field) != (elm)) \ 185 | curelm = SLIST_NEXT(curelm, field); \ 186 | SLIST_REMOVE_AFTER(curelm, field); \ 187 | } \ 188 | } while (0) 189 | 190 | #define SLIST_SWAP(head1, head2, type) do { \ 191 | struct type *swap_first = SLIST_FIRST(head1); \ 192 | SLIST_FIRST(head1) = SLIST_FIRST(head2); \ 193 | SLIST_FIRST(head2) = swap_first; \ 194 | } while (0) 195 | 196 | /* 197 | * List declarations. 198 | */ 199 | #define LIST_HEAD(name, type, qual) \ 200 | struct name { \ 201 | struct type *qual lh_first; /* first element */ \ 202 | } 203 | 204 | #define LIST_HEAD_INITIALIZER(head) \ 205 | { NULL } 206 | 207 | #define LIST_ENTRY(type, qual) \ 208 | struct { \ 209 | struct type *qual le_next; /* next element */ \ 210 | struct type *qual *le_prev; /* address of previous next element */ \ 211 | } 212 | 213 | /* 214 | * List functions. 215 | */ 216 | #define LIST_INIT(head) do { \ 217 | LIST_FIRST((head)) = NULL; \ 218 | } while (0) 219 | 220 | #define LIST_EMPTY(head) ((head)->lh_first == NULL) 221 | 222 | #define LIST_FIRST(head) ((head)->lh_first) 223 | 224 | #define LIST_NEXT(elm, field) ((elm)->field.le_next) 225 | 226 | #define LIST_PREV(elm, head, type, field) \ 227 | ((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \ 228 | __containerof((elm)->field.le_prev, struct type, field.le_next)) 229 | 230 | #define LIST_FOREACH(var, head, field) \ 231 | for ((var) = LIST_FIRST((head)); \ 232 | (var); \ 233 | (var) = LIST_NEXT((var), field)) 234 | 235 | #define LIST_FOREACH_FROM(var, head, field) \ 236 | for ((var) = ((var) ? (var) : LIST_FIRST((head))); \ 237 | (var); \ 238 | (var) = LIST_NEXT((var), field)) 239 | 240 | #define LIST_FOREACH_SAFE(var, head, field, tvar) \ 241 | for ((var) = LIST_FIRST((head)); \ 242 | (var) && ((tvar) = LIST_NEXT((var), field), 1); \ 243 | (var) = (tvar)) 244 | 245 | #define LIST_FOREACH_FROM_SAFE(var, head, field, tvar) \ 246 | for ((var) = ((var) ? (var) : LIST_FIRST((head))); \ 247 | (var) && ((tvar) = LIST_NEXT((var), field), 1); \ 248 | (var) = (tvar)) 249 | 250 | #define LIST_INSERT_HEAD(head, elm, field) do { \ 251 | if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ 252 | LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field); \ 253 | LIST_FIRST((head)) = (elm); \ 254 | (elm)->field.le_prev = &LIST_FIRST((head)); \ 255 | } while (0) 256 | 257 | #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ 258 | (elm)->field.le_prev = (listelm)->field.le_prev; \ 259 | LIST_NEXT((elm), field) = (listelm); \ 260 | *(listelm)->field.le_prev = (elm); \ 261 | (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ 262 | } while (0) 263 | 264 | #define LIST_INSERT_AFTER(listelm, elm, field) do { \ 265 | if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL) \ 266 | LIST_NEXT((listelm), field)->field.le_prev = \ 267 | &LIST_NEXT((elm), field); \ 268 | LIST_NEXT((listelm), field) = (elm); \ 269 | (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ 270 | } while (0) 271 | 272 | #define LIST_REMOVE(elm, field) do { \ 273 | if (LIST_NEXT((elm), field) != NULL) \ 274 | LIST_NEXT((elm), field)->field.le_prev = \ 275 | (elm)->field.le_prev; \ 276 | *(elm)->field.le_prev = LIST_NEXT((elm), field); \ 277 | } while (0) 278 | 279 | #define LIST_SWAP(head1, head2, type, field) do { \ 280 | struct type *swap_tmp = LIST_FIRST((head1)); \ 281 | LIST_FIRST((head1)) = LIST_FIRST((head2)); \ 282 | LIST_FIRST((head2)) = swap_tmp; \ 283 | if ((swap_tmp = LIST_FIRST((head1))) != NULL) \ 284 | swap_tmp->field.le_prev = &LIST_FIRST((head1)); \ 285 | if ((swap_tmp = LIST_FIRST((head2))) != NULL) \ 286 | swap_tmp->field.le_prev = &LIST_FIRST((head2)); \ 287 | } while (0) 288 | 289 | /* 290 | * Singly-linked Tail queue declarations. 291 | */ 292 | #define STAILQ_HEAD(name, type, qual) \ 293 | struct name { \ 294 | struct type *qual stqh_first;/* first element */ \ 295 | struct type *qual *stqh_last;/* addr of last next element */ \ 296 | } 297 | 298 | #define STAILQ_HEAD_INITIALIZER(head) \ 299 | { NULL, &(head).stqh_first } 300 | 301 | #define STAILQ_ENTRY(type, qual) \ 302 | struct { \ 303 | struct type *qual stqe_next; /* next element */ \ 304 | } 305 | 306 | /* 307 | * Singly-linked Tail queue functions. 308 | */ 309 | #define STAILQ_INIT(head) do { \ 310 | STAILQ_FIRST((head)) = NULL; \ 311 | (head)->stqh_last = &STAILQ_FIRST((head)); \ 312 | } while (0) 313 | 314 | #define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) 315 | 316 | #define STAILQ_FIRST(head) ((head)->stqh_first) 317 | 318 | #define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) 319 | 320 | #define STAILQ_LAST(head, type, field) \ 321 | (STAILQ_EMPTY((head)) ? NULL : \ 322 | __containerof((head)->stqh_last, struct type, field.stqe_next)) 323 | 324 | #define STAILQ_FOREACH(var, head, field) \ 325 | for((var) = STAILQ_FIRST((head)); \ 326 | (var); \ 327 | (var) = STAILQ_NEXT((var), field)) 328 | 329 | #define STAILQ_FOREACH_FROM(var, head, field) \ 330 | for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \ 331 | (var); \ 332 | (var) = STAILQ_NEXT((var), field)) 333 | 334 | #define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ 335 | for ((var) = STAILQ_FIRST((head)); \ 336 | (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ 337 | (var) = (tvar)) 338 | 339 | #define STAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \ 340 | for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \ 341 | (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ 342 | (var) = (tvar)) 343 | 344 | #define STAILQ_INSERT_HEAD(head, elm, field) do { \ 345 | if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ 346 | (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 347 | STAILQ_FIRST((head)) = (elm); \ 348 | } while (0) 349 | 350 | #define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ 351 | if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL) \ 352 | (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 353 | STAILQ_NEXT((tqelm), field) = (elm); \ 354 | } while (0) 355 | 356 | #define STAILQ_INSERT_TAIL(head, elm, field) do { \ 357 | STAILQ_NEXT((elm), field) = NULL; \ 358 | *(head)->stqh_last = (elm); \ 359 | (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 360 | } while (0) 361 | 362 | #define STAILQ_CONCAT(head1, head2) do { \ 363 | if (!STAILQ_EMPTY((head2))) { \ 364 | *(head1)->stqh_last = (head2)->stqh_first; \ 365 | (head1)->stqh_last = (head2)->stqh_last; \ 366 | STAILQ_INIT((head2)); \ 367 | } \ 368 | } while (0) 369 | 370 | #define STAILQ_REMOVE_AFTER(head, elm, field) do { \ 371 | if ((STAILQ_NEXT(elm, field) = \ 372 | STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ 373 | (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 374 | } while (0) 375 | 376 | #define STAILQ_REMOVE_HEAD(head, field) do { \ 377 | if ((STAILQ_FIRST((head)) = \ 378 | STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ 379 | (head)->stqh_last = &STAILQ_FIRST((head)); \ 380 | } while (0) 381 | 382 | #define STAILQ_REMOVE(head, elm, type, field) do { \ 383 | if (STAILQ_FIRST((head)) == (elm)) { \ 384 | STAILQ_REMOVE_HEAD((head), field); \ 385 | } \ 386 | else { \ 387 | struct type *curelm = STAILQ_FIRST((head)); \ 388 | while (STAILQ_NEXT(curelm, field) != (elm)) \ 389 | curelm = STAILQ_NEXT(curelm, field); \ 390 | STAILQ_REMOVE_AFTER(head, curelm, field); \ 391 | } \ 392 | } while (0) 393 | 394 | #define STAILQ_SWAP(head1, head2, type) do { \ 395 | struct type *swap_first = STAILQ_FIRST(head1); \ 396 | struct type **swap_last = (head1)->stqh_last; \ 397 | STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \ 398 | (head1)->stqh_last = (head2)->stqh_last; \ 399 | STAILQ_FIRST(head2) = swap_first; \ 400 | (head2)->stqh_last = swap_last; \ 401 | if (STAILQ_EMPTY(head1)) \ 402 | (head1)->stqh_last = &STAILQ_FIRST(head1); \ 403 | if (STAILQ_EMPTY(head2)) \ 404 | (head2)->stqh_last = &STAILQ_FIRST(head2); \ 405 | } while (0) 406 | 407 | /* 408 | * Tail queue declarations. 409 | */ 410 | #define TAILQ_HEAD(name, type, qual) \ 411 | struct name { \ 412 | struct type *qual tqh_first; /* first element */ \ 413 | struct type *qual *tqh_last; /* addr of last next element */ \ 414 | } 415 | 416 | #define TAILQ_HEAD_INITIALIZER(head) \ 417 | { NULL, &(head).tqh_first } 418 | 419 | #define TAILQ_ENTRY(type, qual) \ 420 | struct { \ 421 | struct type *qual tqe_next; /* next element */ \ 422 | struct type *qual *tqe_prev; /* address of previous next element */ \ 423 | } 424 | 425 | /* 426 | * Tail queue functions. 427 | */ 428 | #define TAILQ_INIT(head) do { \ 429 | TAILQ_FIRST((head)) = NULL; \ 430 | (head)->tqh_last = &TAILQ_FIRST((head)); \ 431 | } while (0) 432 | 433 | #define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) 434 | 435 | #define TAILQ_FIRST(head) ((head)->tqh_first) 436 | 437 | #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) 438 | 439 | #define TAILQ_PREV(elm, headname, field) \ 440 | (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) 441 | 442 | #define TAILQ_LAST(head, headname) \ 443 | (*(((struct headname *)((head)->tqh_last))->tqh_last)) 444 | 445 | #define TAILQ_FOREACH(var, head, field) \ 446 | for ((var) = TAILQ_FIRST((head)); \ 447 | (var); \ 448 | (var) = TAILQ_NEXT((var), field)) 449 | 450 | #define TAILQ_FOREACH_FROM(var, head, field) \ 451 | for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \ 452 | (var); \ 453 | (var) = TAILQ_NEXT((var), field)) 454 | 455 | #define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ 456 | for ((var) = TAILQ_FIRST((head)); \ 457 | (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ 458 | (var) = (tvar)) 459 | 460 | #define TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \ 461 | for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \ 462 | (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ 463 | (var) = (tvar)) 464 | 465 | #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ 466 | for ((var) = TAILQ_LAST((head), headname); \ 467 | (var); \ 468 | (var) = TAILQ_PREV((var), headname, field)) 469 | 470 | #define TAILQ_FOREACH_REVERSE_FROM(var, head, headname, field) \ 471 | for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \ 472 | (var); \ 473 | (var) = TAILQ_PREV((var), headname, field)) 474 | 475 | #define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ 476 | for ((var) = TAILQ_LAST((head), headname); \ 477 | (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ 478 | (var) = (tvar)) 479 | 480 | #define TAILQ_FOREACH_REVERSE_FROM_SAFE(var, head, headname, field, tvar) \ 481 | for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \ 482 | (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ 483 | (var) = (tvar)) 484 | 485 | #define TAILQ_INSERT_HEAD(head, elm, field) do { \ 486 | if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ 487 | TAILQ_FIRST((head))->field.tqe_prev = \ 488 | &TAILQ_NEXT((elm), field); \ 489 | else \ 490 | (head)->tqh_last = &TAILQ_NEXT((elm), field); \ 491 | TAILQ_FIRST((head)) = (elm); \ 492 | (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ 493 | } while (0) 494 | 495 | #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ 496 | (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ 497 | TAILQ_NEXT((elm), field) = (listelm); \ 498 | *(listelm)->field.tqe_prev = (elm); \ 499 | (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ 500 | } while (0) 501 | 502 | #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ 503 | if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL) \ 504 | TAILQ_NEXT((elm), field)->field.tqe_prev = \ 505 | &TAILQ_NEXT((elm), field); \ 506 | else \ 507 | (head)->tqh_last = &TAILQ_NEXT((elm), field); \ 508 | TAILQ_NEXT((listelm), field) = (elm); \ 509 | (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ 510 | } while (0) 511 | 512 | #define TAILQ_INSERT_TAIL(head, elm, field) do { \ 513 | TAILQ_NEXT((elm), field) = NULL; \ 514 | (elm)->field.tqe_prev = (head)->tqh_last; \ 515 | *(head)->tqh_last = (elm); \ 516 | (head)->tqh_last = &TAILQ_NEXT((elm), field); \ 517 | } while (0) 518 | 519 | #define TAILQ_CONCAT(head1, head2, field) do { \ 520 | if (!TAILQ_EMPTY(head2)) { \ 521 | *(head1)->tqh_last = (head2)->tqh_first; \ 522 | (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ 523 | (head1)->tqh_last = (head2)->tqh_last; \ 524 | TAILQ_INIT((head2)); \ 525 | } \ 526 | } while (0) 527 | 528 | #define TAILQ_REMOVE(head, elm, field) do { \ 529 | if ((TAILQ_NEXT((elm), field)) != NULL) \ 530 | TAILQ_NEXT((elm), field)->field.tqe_prev = \ 531 | (elm)->field.tqe_prev; \ 532 | else \ 533 | (head)->tqh_last = (elm)->field.tqe_prev; \ 534 | *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ 535 | } while (0) 536 | 537 | #define TAILQ_SWAP(head1, head2, type, field) do { \ 538 | struct type *swap_first = (head1)->tqh_first; \ 539 | struct type **swap_last = (head1)->tqh_last; \ 540 | (head1)->tqh_first = (head2)->tqh_first; \ 541 | (head1)->tqh_last = (head2)->tqh_last; \ 542 | (head2)->tqh_first = swap_first; \ 543 | (head2)->tqh_last = swap_last; \ 544 | if ((swap_first = (head1)->tqh_first) != NULL) \ 545 | swap_first->field.tqe_prev = &(head1)->tqh_first; \ 546 | else \ 547 | (head1)->tqh_last = &(head1)->tqh_first; \ 548 | if ((swap_first = (head2)->tqh_first) != NULL) \ 549 | swap_first->field.tqe_prev = &(head2)->tqh_first; \ 550 | else \ 551 | (head2)->tqh_last = &(head2)->tqh_first; \ 552 | } while (0) 553 | 554 | #endif 555 | -------------------------------------------------------------------------------- /jni/external/xhook/tree.h: -------------------------------------------------------------------------------- 1 | /* $NetBSD: tree.h,v 1.8 2004/03/28 19:38:30 provos Exp $ */ 2 | /* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */ 3 | /* $FreeBSD: stable/9/sys/sys/tree.h 189204 2009-03-01 04:57:23Z bms $ */ 4 | 5 | /*- 6 | * Copyright 2002 Niels Provos 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #ifndef TREE_H 31 | #define TREE_H 32 | 33 | /* #include */ 34 | #ifndef __unused 35 | #define __unused __attribute__((__unused__)) 36 | #endif 37 | 38 | /* 39 | * This file defines data structures for different types of trees: 40 | * splay trees and red-black trees. 41 | * 42 | * A splay tree is a self-organizing data structure. Every operation 43 | * on the tree causes a splay to happen. The splay moves the requested 44 | * node to the root of the tree and partly rebalances it. 45 | * 46 | * This has the benefit that request locality causes faster lookups as 47 | * the requested nodes move to the top of the tree. On the other hand, 48 | * every lookup causes memory writes. 49 | * 50 | * The Balance Theorem bounds the total access time for m operations 51 | * and n inserts on an initially empty tree as O((m + n)lg n). The 52 | * amortized cost for a sequence of m accesses to a splay tree is O(lg n); 53 | * 54 | * A red-black tree is a binary search tree with the node color as an 55 | * extra attribute. It fulfills a set of conditions: 56 | * - every search path from the root to a leaf consists of the 57 | * same number of black nodes, 58 | * - each red node (except for the root) has a black parent, 59 | * - each leaf node is black. 60 | * 61 | * Every operation on a red-black tree is bounded as O(lg n). 62 | * The maximum height of a red-black tree is 2lg (n+1). 63 | */ 64 | 65 | #define SPLAY_HEAD(name, type) \ 66 | struct name { \ 67 | struct type *sph_root; /* root of the tree */ \ 68 | } 69 | 70 | #define SPLAY_INITIALIZER(root) \ 71 | { NULL } 72 | 73 | #define SPLAY_INIT(root) do { \ 74 | (root)->sph_root = NULL; \ 75 | } while (/*CONSTCOND*/ 0) 76 | 77 | #define SPLAY_ENTRY(type) \ 78 | struct { \ 79 | struct type *spe_left; /* left element */ \ 80 | struct type *spe_right; /* right element */ \ 81 | } 82 | 83 | #define SPLAY_LEFT(elm, field) (elm)->field.spe_left 84 | #define SPLAY_RIGHT(elm, field) (elm)->field.spe_right 85 | #define SPLAY_ROOT(head) (head)->sph_root 86 | #define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) 87 | 88 | /* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ 89 | #define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ 90 | SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ 91 | SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ 92 | (head)->sph_root = tmp; \ 93 | } while (/*CONSTCOND*/ 0) 94 | 95 | #define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ 96 | SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ 97 | SPLAY_LEFT(tmp, field) = (head)->sph_root; \ 98 | (head)->sph_root = tmp; \ 99 | } while (/*CONSTCOND*/ 0) 100 | 101 | #define SPLAY_LINKLEFT(head, tmp, field) do { \ 102 | SPLAY_LEFT(tmp, field) = (head)->sph_root; \ 103 | tmp = (head)->sph_root; \ 104 | (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ 105 | } while (/*CONSTCOND*/ 0) 106 | 107 | #define SPLAY_LINKRIGHT(head, tmp, field) do { \ 108 | SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ 109 | tmp = (head)->sph_root; \ 110 | (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ 111 | } while (/*CONSTCOND*/ 0) 112 | 113 | #define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ 114 | SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ 115 | SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ 116 | SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ 117 | SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ 118 | } while (/*CONSTCOND*/ 0) 119 | 120 | /* Generates prototypes and inline functions */ 121 | 122 | #define SPLAY_PROTOTYPE(name, type, field, cmp) \ 123 | void name##_SPLAY(struct name *, struct type *); \ 124 | void name##_SPLAY_MINMAX(struct name *, int); \ 125 | struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ 126 | struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ 127 | \ 128 | /* Finds the node with the same key as elm */ \ 129 | static __inline struct type * \ 130 | name##_SPLAY_FIND(struct name *head, struct type *elm) \ 131 | { \ 132 | if (SPLAY_EMPTY(head)) \ 133 | return(NULL); \ 134 | name##_SPLAY(head, elm); \ 135 | if ((cmp)(elm, (head)->sph_root) == 0) \ 136 | return (head->sph_root); \ 137 | return (NULL); \ 138 | } \ 139 | \ 140 | static __inline struct type * \ 141 | name##_SPLAY_NEXT(struct name *head, struct type *elm) \ 142 | { \ 143 | name##_SPLAY(head, elm); \ 144 | if (SPLAY_RIGHT(elm, field) != NULL) { \ 145 | elm = SPLAY_RIGHT(elm, field); \ 146 | while (SPLAY_LEFT(elm, field) != NULL) { \ 147 | elm = SPLAY_LEFT(elm, field); \ 148 | } \ 149 | } else \ 150 | elm = NULL; \ 151 | return (elm); \ 152 | } \ 153 | \ 154 | static __inline struct type * \ 155 | name##_SPLAY_MIN_MAX(struct name *head, int val) \ 156 | { \ 157 | name##_SPLAY_MINMAX(head, val); \ 158 | return (SPLAY_ROOT(head)); \ 159 | } 160 | 161 | /* Main splay operation. 162 | * Moves node close to the key of elm to top 163 | */ 164 | #define SPLAY_GENERATE(name, type, field, cmp) \ 165 | struct type * \ 166 | name##_SPLAY_INSERT(struct name *head, struct type *elm) \ 167 | { \ 168 | if (SPLAY_EMPTY(head)) { \ 169 | SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ 170 | } else { \ 171 | int __comp; \ 172 | name##_SPLAY(head, elm); \ 173 | __comp = (cmp)(elm, (head)->sph_root); \ 174 | if(__comp < 0) { \ 175 | SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ 176 | SPLAY_RIGHT(elm, field) = (head)->sph_root; \ 177 | SPLAY_LEFT((head)->sph_root, field) = NULL; \ 178 | } else if (__comp > 0) { \ 179 | SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ 180 | SPLAY_LEFT(elm, field) = (head)->sph_root; \ 181 | SPLAY_RIGHT((head)->sph_root, field) = NULL; \ 182 | } else \ 183 | return ((head)->sph_root); \ 184 | } \ 185 | (head)->sph_root = (elm); \ 186 | return (NULL); \ 187 | } \ 188 | \ 189 | struct type * \ 190 | name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ 191 | { \ 192 | struct type *__tmp; \ 193 | if (SPLAY_EMPTY(head)) \ 194 | return (NULL); \ 195 | name##_SPLAY(head, elm); \ 196 | if ((cmp)(elm, (head)->sph_root) == 0) { \ 197 | if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ 198 | (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ 199 | } else { \ 200 | __tmp = SPLAY_RIGHT((head)->sph_root, field); \ 201 | (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ 202 | name##_SPLAY(head, elm); \ 203 | SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ 204 | } \ 205 | return (elm); \ 206 | } \ 207 | return (NULL); \ 208 | } \ 209 | \ 210 | void \ 211 | name##_SPLAY(struct name *head, struct type *elm) \ 212 | { \ 213 | struct type __node, *__left, *__right, *__tmp; \ 214 | int __comp; \ 215 | \ 216 | SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ 217 | __left = __right = &__node; \ 218 | \ 219 | while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \ 220 | if (__comp < 0) { \ 221 | __tmp = SPLAY_LEFT((head)->sph_root, field); \ 222 | if (__tmp == NULL) \ 223 | break; \ 224 | if ((cmp)(elm, __tmp) < 0){ \ 225 | SPLAY_ROTATE_RIGHT(head, __tmp, field); \ 226 | if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ 227 | break; \ 228 | } \ 229 | SPLAY_LINKLEFT(head, __right, field); \ 230 | } else if (__comp > 0) { \ 231 | __tmp = SPLAY_RIGHT((head)->sph_root, field); \ 232 | if (__tmp == NULL) \ 233 | break; \ 234 | if ((cmp)(elm, __tmp) > 0){ \ 235 | SPLAY_ROTATE_LEFT(head, __tmp, field); \ 236 | if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ 237 | break; \ 238 | } \ 239 | SPLAY_LINKRIGHT(head, __left, field); \ 240 | } \ 241 | } \ 242 | SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ 243 | } \ 244 | \ 245 | /* Splay with either the minimum or the maximum element \ 246 | * Used to find minimum or maximum element in tree. \ 247 | */ \ 248 | void name##_SPLAY_MINMAX(struct name *head, int __comp) \ 249 | { \ 250 | struct type __node, *__left, *__right, *__tmp; \ 251 | \ 252 | SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ 253 | __left = __right = &__node; \ 254 | \ 255 | while (1) { \ 256 | if (__comp < 0) { \ 257 | __tmp = SPLAY_LEFT((head)->sph_root, field); \ 258 | if (__tmp == NULL) \ 259 | break; \ 260 | if (__comp < 0){ \ 261 | SPLAY_ROTATE_RIGHT(head, __tmp, field); \ 262 | if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ 263 | break; \ 264 | } \ 265 | SPLAY_LINKLEFT(head, __right, field); \ 266 | } else if (__comp > 0) { \ 267 | __tmp = SPLAY_RIGHT((head)->sph_root, field); \ 268 | if (__tmp == NULL) \ 269 | break; \ 270 | if (__comp > 0) { \ 271 | SPLAY_ROTATE_LEFT(head, __tmp, field); \ 272 | if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ 273 | break; \ 274 | } \ 275 | SPLAY_LINKRIGHT(head, __left, field); \ 276 | } \ 277 | } \ 278 | SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ 279 | } 280 | 281 | #define SPLAY_NEGINF -1 282 | #define SPLAY_INF 1 283 | 284 | #define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) 285 | #define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) 286 | #define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) 287 | #define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) 288 | #define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ 289 | : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) 290 | #define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ 291 | : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) 292 | 293 | #define SPLAY_FOREACH(x, name, head) \ 294 | for ((x) = SPLAY_MIN(name, head); \ 295 | (x) != NULL; \ 296 | (x) = SPLAY_NEXT(name, head, x)) 297 | 298 | /* Macros that define a red-black tree */ 299 | #define RB_HEAD(name, type) \ 300 | struct name { \ 301 | struct type *rbh_root; /* root of the tree */ \ 302 | } 303 | 304 | #define RB_INITIALIZER(root) \ 305 | { NULL } 306 | 307 | #define RB_INIT(root) do { \ 308 | (root)->rbh_root = NULL; \ 309 | } while (/*CONSTCOND*/ 0) 310 | 311 | #define RB_BLACK 0 312 | #define RB_RED 1 313 | #define RB_ENTRY(type) \ 314 | struct { \ 315 | struct type *rbe_left; /* left element */ \ 316 | struct type *rbe_right; /* right element */ \ 317 | struct type *rbe_parent; /* parent element */ \ 318 | int rbe_color; /* node color */ \ 319 | } 320 | 321 | #define RB_LEFT(elm, field) (elm)->field.rbe_left 322 | #define RB_RIGHT(elm, field) (elm)->field.rbe_right 323 | #define RB_PARENT(elm, field) (elm)->field.rbe_parent 324 | #define RB_COLOR(elm, field) (elm)->field.rbe_color 325 | #define RB_ROOT(head) (head)->rbh_root 326 | #define RB_EMPTY(head) (RB_ROOT(head) == NULL) 327 | 328 | #define RB_SET(elm, parent, field) do { \ 329 | RB_PARENT(elm, field) = parent; \ 330 | RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ 331 | RB_COLOR(elm, field) = RB_RED; \ 332 | } while (/*CONSTCOND*/ 0) 333 | 334 | #define RB_SET_BLACKRED(black, red, field) do { \ 335 | RB_COLOR(black, field) = RB_BLACK; \ 336 | RB_COLOR(red, field) = RB_RED; \ 337 | } while (/*CONSTCOND*/ 0) 338 | 339 | #ifndef RB_AUGMENT 340 | #define RB_AUGMENT(x) do {} while (0) 341 | #endif 342 | 343 | #define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ 344 | (tmp) = RB_RIGHT(elm, field); \ 345 | if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \ 346 | RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ 347 | } \ 348 | RB_AUGMENT(elm); \ 349 | if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ 350 | if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ 351 | RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ 352 | else \ 353 | RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ 354 | } else \ 355 | (head)->rbh_root = (tmp); \ 356 | RB_LEFT(tmp, field) = (elm); \ 357 | RB_PARENT(elm, field) = (tmp); \ 358 | RB_AUGMENT(tmp); \ 359 | if ((RB_PARENT(tmp, field))) \ 360 | RB_AUGMENT(RB_PARENT(tmp, field)); \ 361 | } while (/*CONSTCOND*/ 0) 362 | 363 | #define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ 364 | (tmp) = RB_LEFT(elm, field); \ 365 | if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \ 366 | RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ 367 | } \ 368 | RB_AUGMENT(elm); \ 369 | if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ 370 | if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ 371 | RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ 372 | else \ 373 | RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ 374 | } else \ 375 | (head)->rbh_root = (tmp); \ 376 | RB_RIGHT(tmp, field) = (elm); \ 377 | RB_PARENT(elm, field) = (tmp); \ 378 | RB_AUGMENT(tmp); \ 379 | if ((RB_PARENT(tmp, field))) \ 380 | RB_AUGMENT(RB_PARENT(tmp, field)); \ 381 | } while (/*CONSTCOND*/ 0) 382 | 383 | /* Generates prototypes and inline functions */ 384 | #define RB_PROTOTYPE(name, type, field, cmp) \ 385 | RB_PROTOTYPE_INTERNAL(name, type, field, cmp,) 386 | #define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ 387 | RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static) 388 | #define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ 389 | attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \ 390 | attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ 391 | attr struct type *name##_RB_REMOVE(struct name *, struct type *); \ 392 | attr struct type *name##_RB_INSERT(struct name *, struct type *); \ 393 | attr struct type *name##_RB_FIND(struct name *, struct type *); \ 394 | attr struct type *name##_RB_NFIND(struct name *, struct type *); \ 395 | attr struct type *name##_RB_NEXT(struct type *); \ 396 | attr struct type *name##_RB_PREV(struct type *); \ 397 | attr struct type *name##_RB_MINMAX(struct name *, int); \ 398 | \ 399 | 400 | /* Main rb operation. 401 | * Moves node close to the key of elm to top 402 | */ 403 | #define RB_GENERATE(name, type, field, cmp) \ 404 | RB_GENERATE_INTERNAL(name, type, field, cmp,) 405 | #define RB_GENERATE_STATIC(name, type, field, cmp) \ 406 | RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static) 407 | #define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ 408 | attr void \ 409 | name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ 410 | { \ 411 | struct type *parent, *gparent, *tmp; \ 412 | while ((parent = RB_PARENT(elm, field)) != NULL && \ 413 | RB_COLOR(parent, field) == RB_RED) { \ 414 | gparent = RB_PARENT(parent, field); \ 415 | if (parent == RB_LEFT(gparent, field)) { \ 416 | tmp = RB_RIGHT(gparent, field); \ 417 | if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ 418 | RB_COLOR(tmp, field) = RB_BLACK; \ 419 | RB_SET_BLACKRED(parent, gparent, field);\ 420 | elm = gparent; \ 421 | continue; \ 422 | } \ 423 | if (RB_RIGHT(parent, field) == elm) { \ 424 | RB_ROTATE_LEFT(head, parent, tmp, field);\ 425 | tmp = parent; \ 426 | parent = elm; \ 427 | elm = tmp; \ 428 | } \ 429 | RB_SET_BLACKRED(parent, gparent, field); \ 430 | RB_ROTATE_RIGHT(head, gparent, tmp, field); \ 431 | } else { \ 432 | tmp = RB_LEFT(gparent, field); \ 433 | if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ 434 | RB_COLOR(tmp, field) = RB_BLACK; \ 435 | RB_SET_BLACKRED(parent, gparent, field);\ 436 | elm = gparent; \ 437 | continue; \ 438 | } \ 439 | if (RB_LEFT(parent, field) == elm) { \ 440 | RB_ROTATE_RIGHT(head, parent, tmp, field);\ 441 | tmp = parent; \ 442 | parent = elm; \ 443 | elm = tmp; \ 444 | } \ 445 | RB_SET_BLACKRED(parent, gparent, field); \ 446 | RB_ROTATE_LEFT(head, gparent, tmp, field); \ 447 | } \ 448 | } \ 449 | RB_COLOR(head->rbh_root, field) = RB_BLACK; \ 450 | } \ 451 | \ 452 | attr void \ 453 | name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ 454 | { \ 455 | struct type *tmp; \ 456 | while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ 457 | elm != RB_ROOT(head)) { \ 458 | if (RB_LEFT(parent, field) == elm) { \ 459 | tmp = RB_RIGHT(parent, field); \ 460 | if (RB_COLOR(tmp, field) == RB_RED) { \ 461 | RB_SET_BLACKRED(tmp, parent, field); \ 462 | RB_ROTATE_LEFT(head, parent, tmp, field);\ 463 | tmp = RB_RIGHT(parent, field); \ 464 | } \ 465 | if ((RB_LEFT(tmp, field) == NULL || \ 466 | RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ 467 | (RB_RIGHT(tmp, field) == NULL || \ 468 | RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ 469 | RB_COLOR(tmp, field) = RB_RED; \ 470 | elm = parent; \ 471 | parent = RB_PARENT(elm, field); \ 472 | } else { \ 473 | if (RB_RIGHT(tmp, field) == NULL || \ 474 | RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ 475 | struct type *oleft; \ 476 | if ((oleft = RB_LEFT(tmp, field)) \ 477 | != NULL) \ 478 | RB_COLOR(oleft, field) = RB_BLACK;\ 479 | RB_COLOR(tmp, field) = RB_RED; \ 480 | RB_ROTATE_RIGHT(head, tmp, oleft, field);\ 481 | tmp = RB_RIGHT(parent, field); \ 482 | } \ 483 | RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ 484 | RB_COLOR(parent, field) = RB_BLACK; \ 485 | if (RB_RIGHT(tmp, field)) \ 486 | RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ 487 | RB_ROTATE_LEFT(head, parent, tmp, field);\ 488 | elm = RB_ROOT(head); \ 489 | break; \ 490 | } \ 491 | } else { \ 492 | tmp = RB_LEFT(parent, field); \ 493 | if (RB_COLOR(tmp, field) == RB_RED) { \ 494 | RB_SET_BLACKRED(tmp, parent, field); \ 495 | RB_ROTATE_RIGHT(head, parent, tmp, field);\ 496 | tmp = RB_LEFT(parent, field); \ 497 | } \ 498 | if ((RB_LEFT(tmp, field) == NULL || \ 499 | RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ 500 | (RB_RIGHT(tmp, field) == NULL || \ 501 | RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ 502 | RB_COLOR(tmp, field) = RB_RED; \ 503 | elm = parent; \ 504 | parent = RB_PARENT(elm, field); \ 505 | } else { \ 506 | if (RB_LEFT(tmp, field) == NULL || \ 507 | RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ 508 | struct type *oright; \ 509 | if ((oright = RB_RIGHT(tmp, field)) \ 510 | != NULL) \ 511 | RB_COLOR(oright, field) = RB_BLACK;\ 512 | RB_COLOR(tmp, field) = RB_RED; \ 513 | RB_ROTATE_LEFT(head, tmp, oright, field);\ 514 | tmp = RB_LEFT(parent, field); \ 515 | } \ 516 | RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ 517 | RB_COLOR(parent, field) = RB_BLACK; \ 518 | if (RB_LEFT(tmp, field)) \ 519 | RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ 520 | RB_ROTATE_RIGHT(head, parent, tmp, field);\ 521 | elm = RB_ROOT(head); \ 522 | break; \ 523 | } \ 524 | } \ 525 | } \ 526 | if (elm) \ 527 | RB_COLOR(elm, field) = RB_BLACK; \ 528 | } \ 529 | \ 530 | attr struct type * \ 531 | name##_RB_REMOVE(struct name *head, struct type *elm) \ 532 | { \ 533 | struct type *child, *parent, *old = elm; \ 534 | int color; \ 535 | if (RB_LEFT(elm, field) == NULL) \ 536 | child = RB_RIGHT(elm, field); \ 537 | else if (RB_RIGHT(elm, field) == NULL) \ 538 | child = RB_LEFT(elm, field); \ 539 | else { \ 540 | struct type *left; \ 541 | elm = RB_RIGHT(elm, field); \ 542 | while ((left = RB_LEFT(elm, field)) != NULL) \ 543 | elm = left; \ 544 | child = RB_RIGHT(elm, field); \ 545 | parent = RB_PARENT(elm, field); \ 546 | color = RB_COLOR(elm, field); \ 547 | if (child) \ 548 | RB_PARENT(child, field) = parent; \ 549 | if (parent) { \ 550 | if (RB_LEFT(parent, field) == elm) \ 551 | RB_LEFT(parent, field) = child; \ 552 | else \ 553 | RB_RIGHT(parent, field) = child; \ 554 | RB_AUGMENT(parent); \ 555 | } else \ 556 | RB_ROOT(head) = child; \ 557 | if (RB_PARENT(elm, field) == old) \ 558 | parent = elm; \ 559 | (elm)->field = (old)->field; \ 560 | if (RB_PARENT(old, field)) { \ 561 | if (RB_LEFT(RB_PARENT(old, field), field) == old)\ 562 | RB_LEFT(RB_PARENT(old, field), field) = elm;\ 563 | else \ 564 | RB_RIGHT(RB_PARENT(old, field), field) = elm;\ 565 | RB_AUGMENT(RB_PARENT(old, field)); \ 566 | } else \ 567 | RB_ROOT(head) = elm; \ 568 | RB_PARENT(RB_LEFT(old, field), field) = elm; \ 569 | if (RB_RIGHT(old, field)) \ 570 | RB_PARENT(RB_RIGHT(old, field), field) = elm; \ 571 | if (parent) { \ 572 | left = parent; \ 573 | do { \ 574 | RB_AUGMENT(left); \ 575 | } while ((left = RB_PARENT(left, field)) != NULL); \ 576 | } \ 577 | goto color; \ 578 | } \ 579 | parent = RB_PARENT(elm, field); \ 580 | color = RB_COLOR(elm, field); \ 581 | if (child) \ 582 | RB_PARENT(child, field) = parent; \ 583 | if (parent) { \ 584 | if (RB_LEFT(parent, field) == elm) \ 585 | RB_LEFT(parent, field) = child; \ 586 | else \ 587 | RB_RIGHT(parent, field) = child; \ 588 | RB_AUGMENT(parent); \ 589 | } else \ 590 | RB_ROOT(head) = child; \ 591 | color: \ 592 | if (color == RB_BLACK) \ 593 | name##_RB_REMOVE_COLOR(head, parent, child); \ 594 | return (old); \ 595 | } \ 596 | \ 597 | /* Inserts a node into the RB tree */ \ 598 | attr struct type * \ 599 | name##_RB_INSERT(struct name *head, struct type *elm) \ 600 | { \ 601 | struct type *tmp; \ 602 | struct type *parent = NULL; \ 603 | int comp = 0; \ 604 | tmp = RB_ROOT(head); \ 605 | while (tmp) { \ 606 | parent = tmp; \ 607 | comp = (cmp)(elm, parent); \ 608 | if (comp < 0) \ 609 | tmp = RB_LEFT(tmp, field); \ 610 | else if (comp > 0) \ 611 | tmp = RB_RIGHT(tmp, field); \ 612 | else \ 613 | return (tmp); \ 614 | } \ 615 | RB_SET(elm, parent, field); \ 616 | if (parent != NULL) { \ 617 | if (comp < 0) \ 618 | RB_LEFT(parent, field) = elm; \ 619 | else \ 620 | RB_RIGHT(parent, field) = elm; \ 621 | RB_AUGMENT(parent); \ 622 | } else \ 623 | RB_ROOT(head) = elm; \ 624 | name##_RB_INSERT_COLOR(head, elm); \ 625 | return (NULL); \ 626 | } \ 627 | \ 628 | /* Finds the node with the same key as elm */ \ 629 | attr struct type * \ 630 | name##_RB_FIND(struct name *head, struct type *elm) \ 631 | { \ 632 | struct type *tmp = RB_ROOT(head); \ 633 | int comp; \ 634 | while (tmp) { \ 635 | comp = cmp(elm, tmp); \ 636 | if (comp < 0) \ 637 | tmp = RB_LEFT(tmp, field); \ 638 | else if (comp > 0) \ 639 | tmp = RB_RIGHT(tmp, field); \ 640 | else \ 641 | return (tmp); \ 642 | } \ 643 | return (NULL); \ 644 | } \ 645 | \ 646 | /* Finds the first node greater than or equal to the search key */ \ 647 | attr struct type * \ 648 | name##_RB_NFIND(struct name *head, struct type *elm) \ 649 | { \ 650 | struct type *tmp = RB_ROOT(head); \ 651 | struct type *res = NULL; \ 652 | int comp; \ 653 | while (tmp) { \ 654 | comp = cmp(elm, tmp); \ 655 | if (comp < 0) { \ 656 | res = tmp; \ 657 | tmp = RB_LEFT(tmp, field); \ 658 | } \ 659 | else if (comp > 0) \ 660 | tmp = RB_RIGHT(tmp, field); \ 661 | else \ 662 | return (tmp); \ 663 | } \ 664 | return (res); \ 665 | } \ 666 | \ 667 | /* ARGSUSED */ \ 668 | attr struct type * \ 669 | name##_RB_NEXT(struct type *elm) \ 670 | { \ 671 | if (RB_RIGHT(elm, field)) { \ 672 | elm = RB_RIGHT(elm, field); \ 673 | while (RB_LEFT(elm, field)) \ 674 | elm = RB_LEFT(elm, field); \ 675 | } else { \ 676 | if (RB_PARENT(elm, field) && \ 677 | (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ 678 | elm = RB_PARENT(elm, field); \ 679 | else { \ 680 | while (RB_PARENT(elm, field) && \ 681 | (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ 682 | elm = RB_PARENT(elm, field); \ 683 | elm = RB_PARENT(elm, field); \ 684 | } \ 685 | } \ 686 | return (elm); \ 687 | } \ 688 | \ 689 | /* ARGSUSED */ \ 690 | attr struct type * \ 691 | name##_RB_PREV(struct type *elm) \ 692 | { \ 693 | if (RB_LEFT(elm, field)) { \ 694 | elm = RB_LEFT(elm, field); \ 695 | while (RB_RIGHT(elm, field)) \ 696 | elm = RB_RIGHT(elm, field); \ 697 | } else { \ 698 | if (RB_PARENT(elm, field) && \ 699 | (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ 700 | elm = RB_PARENT(elm, field); \ 701 | else { \ 702 | while (RB_PARENT(elm, field) && \ 703 | (elm == RB_LEFT(RB_PARENT(elm, field), field)))\ 704 | elm = RB_PARENT(elm, field); \ 705 | elm = RB_PARENT(elm, field); \ 706 | } \ 707 | } \ 708 | return (elm); \ 709 | } \ 710 | \ 711 | attr struct type * \ 712 | name##_RB_MINMAX(struct name *head, int val) \ 713 | { \ 714 | struct type *tmp = RB_ROOT(head); \ 715 | struct type *parent = NULL; \ 716 | while (tmp) { \ 717 | parent = tmp; \ 718 | if (val < 0) \ 719 | tmp = RB_LEFT(tmp, field); \ 720 | else \ 721 | tmp = RB_RIGHT(tmp, field); \ 722 | } \ 723 | return (parent); \ 724 | } 725 | 726 | #define RB_NEGINF -1 727 | #define RB_INF 1 728 | 729 | #define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) 730 | #define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) 731 | #define RB_FIND(name, x, y) name##_RB_FIND(x, y) 732 | #define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) 733 | #define RB_NEXT(name, x, y) name##_RB_NEXT(y) 734 | #define RB_PREV(name, x, y) name##_RB_PREV(y) 735 | #define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) 736 | #define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) 737 | 738 | #define RB_FOREACH(x, name, head) \ 739 | for ((x) = RB_MIN(name, head); \ 740 | (x) != NULL; \ 741 | (x) = name##_RB_NEXT(x)) 742 | 743 | #define RB_FOREACH_FROM(x, name, y) \ 744 | for ((x) = (y); \ 745 | ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ 746 | (x) = (y)) 747 | 748 | #define RB_FOREACH_SAFE(x, name, head, y) \ 749 | for ((x) = RB_MIN(name, head); \ 750 | ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ 751 | (x) = (y)) 752 | 753 | #define RB_FOREACH_REVERSE(x, name, head) \ 754 | for ((x) = RB_MAX(name, head); \ 755 | (x) != NULL; \ 756 | (x) = name##_RB_PREV(x)) 757 | 758 | #define RB_FOREACH_REVERSE_FROM(x, name, y) \ 759 | for ((x) = (y); \ 760 | ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ 761 | (x) = (y)) 762 | 763 | #define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \ 764 | for ((x) = RB_MAX(name, head); \ 765 | ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ 766 | (x) = (y)) 767 | 768 | #endif 769 | -------------------------------------------------------------------------------- /jni/external/xhook/xh_core.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include "queue.h" 35 | #include "tree.h" 36 | #include "xh_errno.h" 37 | #include "xh_log.h" 38 | #include "xh_elf.h" 39 | #include "xh_version.h" 40 | #include "xh_core.h" 41 | 42 | #define XH_CORE_DEBUG 0 43 | 44 | //registered hook info collection 45 | typedef struct xh_core_hook_info 46 | { 47 | #if XH_CORE_DEBUG 48 | char *pathname_regex_str; 49 | #endif 50 | regex_t pathname_regex; 51 | char *symbol; 52 | void *new_func; 53 | void **old_func; 54 | TAILQ_ENTRY(xh_core_hook_info,) link; 55 | } xh_core_hook_info_t; 56 | typedef TAILQ_HEAD(xh_core_hook_info_queue, xh_core_hook_info,) xh_core_hook_info_queue_t; 57 | 58 | //ignored hook info collection 59 | typedef struct xh_core_ignore_info 60 | { 61 | #if XH_CORE_DEBUG 62 | char *pathname_regex_str; 63 | #endif 64 | regex_t pathname_regex; 65 | char *symbol; //NULL meaning for all symbols 66 | TAILQ_ENTRY(xh_core_ignore_info,) link; 67 | } xh_core_ignore_info_t; 68 | typedef TAILQ_HEAD(xh_core_ignore_info_queue, xh_core_ignore_info,) xh_core_ignore_info_queue_t; 69 | 70 | //required info from /proc/self/maps 71 | typedef struct xh_core_map_info 72 | { 73 | char *pathname; 74 | uintptr_t base_addr; 75 | xh_elf_t elf; 76 | RB_ENTRY(xh_core_map_info) link; 77 | } xh_core_map_info_t; 78 | static __inline__ int xh_core_map_info_cmp(xh_core_map_info_t *a, xh_core_map_info_t *b) 79 | { 80 | return strcmp(a->pathname, b->pathname); 81 | } 82 | typedef RB_HEAD(xh_core_map_info_tree, xh_core_map_info) xh_core_map_info_tree_t; 83 | RB_GENERATE_STATIC(xh_core_map_info_tree, xh_core_map_info, link, xh_core_map_info_cmp) 84 | 85 | //signal handler for SIGSEGV 86 | //for xh_elf_init(), xh_elf_hook(), xh_elf_check_elfheader() 87 | static int xh_core_sigsegv_enable = 1; //enable by default 88 | static struct sigaction xh_core_sigsegv_act_old; 89 | static volatile int xh_core_sigsegv_flag = 0; 90 | static sigjmp_buf xh_core_sigsegv_env; 91 | static void xh_core_sigsegv_handler(int sig) 92 | { 93 | (void)sig; 94 | 95 | if(xh_core_sigsegv_flag) 96 | siglongjmp(xh_core_sigsegv_env, 1); 97 | else 98 | sigaction(SIGSEGV, &xh_core_sigsegv_act_old, NULL); 99 | } 100 | static int xh_core_add_sigsegv_handler() 101 | { 102 | struct sigaction act; 103 | 104 | if(!xh_core_sigsegv_enable) return 0; 105 | 106 | if(0 != sigemptyset(&act.sa_mask)) return (0 == errno ? XH_ERRNO_UNKNOWN : errno); 107 | act.sa_handler = xh_core_sigsegv_handler; 108 | 109 | if(0 != sigaction(SIGSEGV, &act, &xh_core_sigsegv_act_old)) 110 | return (0 == errno ? XH_ERRNO_UNKNOWN : errno); 111 | 112 | return 0; 113 | } 114 | static void xh_core_del_sigsegv_handler() 115 | { 116 | if(!xh_core_sigsegv_enable) return; 117 | 118 | sigaction(SIGSEGV, &xh_core_sigsegv_act_old, NULL); 119 | } 120 | 121 | 122 | static xh_core_hook_info_queue_t xh_core_hook_info = TAILQ_HEAD_INITIALIZER(xh_core_hook_info); 123 | static xh_core_ignore_info_queue_t xh_core_ignore_info = TAILQ_HEAD_INITIALIZER(xh_core_ignore_info); 124 | static xh_core_map_info_tree_t xh_core_map_info = RB_INITIALIZER(&xh_core_map_info); 125 | static pthread_mutex_t xh_core_mutex = PTHREAD_MUTEX_INITIALIZER; 126 | static pthread_cond_t xh_core_cond = PTHREAD_COND_INITIALIZER; 127 | static volatile int xh_core_inited = 0; 128 | static volatile int xh_core_init_ok = 0; 129 | static volatile int xh_core_async_inited = 0; 130 | static volatile int xh_core_async_init_ok = 0; 131 | static pthread_mutex_t xh_core_refresh_mutex = PTHREAD_MUTEX_INITIALIZER; 132 | static pthread_t xh_core_refresh_thread_tid; 133 | static volatile int xh_core_refresh_thread_running = 0; 134 | static volatile int xh_core_refresh_thread_do = 0; 135 | 136 | 137 | int xh_core_register(const char *pathname_regex_str, const char *symbol, 138 | void *new_func, void **old_func) 139 | { 140 | xh_core_hook_info_t *hi; 141 | regex_t regex; 142 | 143 | if(NULL == pathname_regex_str || NULL == symbol || NULL == new_func) return XH_ERRNO_INVAL; 144 | 145 | if(xh_core_inited) 146 | { 147 | XH_LOG_ERROR("do not register hook after refresh(): %s, %s", pathname_regex_str, symbol); 148 | return XH_ERRNO_INVAL; 149 | } 150 | 151 | if(0 != regcomp(®ex, pathname_regex_str, REG_NOSUB)) return XH_ERRNO_INVAL; 152 | 153 | if(NULL == (hi = malloc(sizeof(xh_core_hook_info_t)))) return XH_ERRNO_NOMEM; 154 | if(NULL == (hi->symbol = strdup(symbol))) 155 | { 156 | free(hi); 157 | return XH_ERRNO_NOMEM; 158 | } 159 | #if XH_CORE_DEBUG 160 | if(NULL == (hi->pathname_regex_str = strdup(pathname_regex_str))) 161 | { 162 | free(hi->symbol); 163 | free(hi); 164 | return XH_ERRNO_NOMEM; 165 | } 166 | #endif 167 | hi->pathname_regex = regex; 168 | hi->new_func = new_func; 169 | hi->old_func = old_func; 170 | 171 | pthread_mutex_lock(&xh_core_mutex); 172 | TAILQ_INSERT_TAIL(&xh_core_hook_info, hi, link); 173 | pthread_mutex_unlock(&xh_core_mutex); 174 | 175 | return 0; 176 | } 177 | 178 | int xh_core_ignore(const char *pathname_regex_str, const char *symbol) 179 | { 180 | xh_core_ignore_info_t *ii; 181 | regex_t regex; 182 | 183 | if(NULL == pathname_regex_str) return XH_ERRNO_INVAL; 184 | 185 | if(xh_core_inited) 186 | { 187 | XH_LOG_ERROR("do not ignore hook after refresh(): %s, %s", pathname_regex_str, symbol ? symbol : "ALL"); 188 | return XH_ERRNO_INVAL; 189 | } 190 | 191 | if(0 != regcomp(®ex, pathname_regex_str, REG_NOSUB)) return XH_ERRNO_INVAL; 192 | 193 | if(NULL == (ii = malloc(sizeof(xh_core_ignore_info_t)))) return XH_ERRNO_NOMEM; 194 | if(NULL != symbol) 195 | { 196 | if(NULL == (ii->symbol = strdup(symbol))) 197 | { 198 | free(ii); 199 | return XH_ERRNO_NOMEM; 200 | } 201 | } 202 | else 203 | { 204 | ii->symbol = NULL; //ignore all symbols 205 | } 206 | #if XH_CORE_DEBUG 207 | if(NULL == (ii->pathname_regex_str = strdup(pathname_regex_str))) 208 | { 209 | free(ii->symbol); 210 | free(ii); 211 | return XH_ERRNO_NOMEM; 212 | } 213 | #endif 214 | ii->pathname_regex = regex; 215 | 216 | pthread_mutex_lock(&xh_core_mutex); 217 | TAILQ_INSERT_TAIL(&xh_core_ignore_info, ii, link); 218 | pthread_mutex_unlock(&xh_core_mutex); 219 | 220 | return 0; 221 | } 222 | 223 | static int xh_core_check_elf_header(uintptr_t base_addr, const char *pathname) 224 | { 225 | if(!xh_core_sigsegv_enable) 226 | { 227 | return xh_elf_check_elfheader(base_addr); 228 | } 229 | else 230 | { 231 | int ret = XH_ERRNO_UNKNOWN; 232 | 233 | xh_core_sigsegv_flag = 1; 234 | if(0 == sigsetjmp(xh_core_sigsegv_env, 1)) 235 | { 236 | ret = xh_elf_check_elfheader(base_addr); 237 | } 238 | else 239 | { 240 | ret = XH_ERRNO_SEGVERR; 241 | XH_LOG_WARN("catch SIGSEGV when check_elfheader: %s", pathname); 242 | } 243 | xh_core_sigsegv_flag = 0; 244 | return ret; 245 | } 246 | } 247 | 248 | static void xh_core_hook_impl(xh_core_map_info_t *mi) 249 | { 250 | //init 251 | if(0 != xh_elf_init(&(mi->elf), mi->base_addr, mi->pathname)) return; 252 | 253 | //hook 254 | xh_core_hook_info_t *hi; 255 | xh_core_ignore_info_t *ii; 256 | int ignore; 257 | TAILQ_FOREACH(hi, &xh_core_hook_info, link) //find hook info 258 | { 259 | if(0 == regexec(&(hi->pathname_regex), mi->pathname, 0, NULL, 0)) 260 | { 261 | ignore = 0; 262 | TAILQ_FOREACH(ii, &xh_core_ignore_info, link) //find ignore info 263 | { 264 | if(0 == regexec(&(ii->pathname_regex), mi->pathname, 0, NULL, 0)) 265 | { 266 | if(NULL == ii->symbol) //ignore all symbols 267 | return; 268 | 269 | if(0 == strcmp(ii->symbol, hi->symbol)) //ignore the current symbol 270 | { 271 | ignore = 1; 272 | break; 273 | } 274 | } 275 | } 276 | 277 | if(0 == ignore) 278 | xh_elf_hook(&(mi->elf), hi->symbol, hi->new_func, hi->old_func); 279 | } 280 | } 281 | } 282 | 283 | static void xh_core_hook(xh_core_map_info_t *mi) 284 | { 285 | if(!xh_core_sigsegv_enable) 286 | { 287 | xh_core_hook_impl(mi); 288 | } 289 | else 290 | { 291 | xh_core_sigsegv_flag = 1; 292 | if(0 == sigsetjmp(xh_core_sigsegv_env, 1)) 293 | { 294 | xh_core_hook_impl(mi); 295 | } 296 | else 297 | { 298 | XH_LOG_WARN("catch SIGSEGV when init or hook: %s", mi->pathname); 299 | } 300 | xh_core_sigsegv_flag = 0; 301 | } 302 | } 303 | 304 | static void xh_core_refresh_impl() 305 | { 306 | char line[512]; 307 | FILE *fp; 308 | uintptr_t base_addr; 309 | char perm[5]; 310 | unsigned long offset; 311 | int pathname_pos; 312 | char *pathname; 313 | size_t pathname_len; 314 | xh_core_map_info_t *mi, *mi_tmp; 315 | xh_core_map_info_t mi_key; 316 | xh_core_hook_info_t *hi; 317 | xh_core_ignore_info_t *ii; 318 | int match; 319 | xh_core_map_info_tree_t map_info_refreshed = RB_INITIALIZER(&map_info_refreshed); 320 | 321 | if(NULL == (fp = fopen("/proc/self/maps", "r"))) 322 | { 323 | XH_LOG_ERROR("fopen /proc/self/maps failed"); 324 | return; 325 | } 326 | 327 | while(fgets(line, sizeof(line), fp)) 328 | { 329 | if(sscanf(line, "%"PRIxPTR"-%*lx %4s %lx %*x:%*x %*d%n", &base_addr, perm, &offset, &pathname_pos) != 3) continue; 330 | 331 | //check permission 332 | if(perm[0] != 'r') continue; 333 | if(perm[3] != 'p') continue; //do not touch the shared memory 334 | 335 | //check offset 336 | // 337 | //We are trying to find ELF header in memory. 338 | //It can only be found at the beginning of a mapped memory regions 339 | //whose offset is 0. 340 | if(0 != offset) continue; 341 | 342 | //get pathname 343 | while(isspace(line[pathname_pos]) && pathname_pos < (int)(sizeof(line) - 1)) 344 | pathname_pos += 1; 345 | if(pathname_pos >= (int)(sizeof(line) - 1)) continue; 346 | pathname = line + pathname_pos; 347 | pathname_len = strlen(pathname); 348 | if(0 == pathname_len) continue; 349 | if(pathname[pathname_len - 1] == '\n') 350 | { 351 | pathname[pathname_len - 1] = '\0'; 352 | pathname_len -= 1; 353 | } 354 | if(0 == pathname_len) continue; 355 | if('[' == pathname[0]) continue; 356 | 357 | //check pathname 358 | //if we need to hook this elf? 359 | match = 0; 360 | TAILQ_FOREACH(hi, &xh_core_hook_info, link) //find hook info 361 | { 362 | if(0 == regexec(&(hi->pathname_regex), pathname, 0, NULL, 0)) 363 | { 364 | TAILQ_FOREACH(ii, &xh_core_ignore_info, link) //find ignore info 365 | { 366 | if(0 == regexec(&(ii->pathname_regex), pathname, 0, NULL, 0)) 367 | { 368 | if(NULL == ii->symbol) 369 | goto check_finished; 370 | 371 | if(0 == strcmp(ii->symbol, hi->symbol)) 372 | goto check_continue; 373 | } 374 | } 375 | 376 | match = 1; 377 | check_continue: 378 | break; 379 | } 380 | } 381 | check_finished: 382 | if(0 == match) continue; 383 | 384 | //check elf header format 385 | //We are trying to do ELF header checking as late as possible. 386 | if(0 != xh_core_check_elf_header(base_addr, pathname)) continue; 387 | 388 | //check existed map item 389 | mi_key.pathname = pathname; 390 | if(NULL != (mi = RB_FIND(xh_core_map_info_tree, &xh_core_map_info, &mi_key))) 391 | { 392 | //exist 393 | RB_REMOVE(xh_core_map_info_tree, &xh_core_map_info, mi); 394 | 395 | //repeated? 396 | //We only keep the first one, that is the real base address 397 | if(NULL != RB_INSERT(xh_core_map_info_tree, &map_info_refreshed, mi)) 398 | { 399 | #if XH_CORE_DEBUG 400 | XH_LOG_DEBUG("repeated map info when update: %s", line); 401 | #endif 402 | free(mi->pathname); 403 | free(mi); 404 | continue; 405 | } 406 | 407 | //re-hook if base_addr changed 408 | if(mi->base_addr != base_addr) 409 | { 410 | mi->base_addr = base_addr; 411 | xh_core_hook(mi); 412 | } 413 | } 414 | else 415 | { 416 | //not exist, create a new map info 417 | if(NULL == (mi = (xh_core_map_info_t *)malloc(sizeof(xh_core_map_info_t)))) continue; 418 | if(NULL == (mi->pathname = strdup(pathname))) 419 | { 420 | free(mi); 421 | continue; 422 | } 423 | mi->base_addr = base_addr; 424 | 425 | //repeated? 426 | //We only keep the first one, that is the real base address 427 | if(NULL != RB_INSERT(xh_core_map_info_tree, &map_info_refreshed, mi)) 428 | { 429 | #if XH_CORE_DEBUG 430 | XH_LOG_DEBUG("repeated map info when create: %s", line); 431 | #endif 432 | free(mi->pathname); 433 | free(mi); 434 | continue; 435 | } 436 | 437 | //hook 438 | xh_core_hook(mi); //hook 439 | } 440 | } 441 | fclose(fp); 442 | 443 | //free all missing map item, maybe dlclosed? 444 | RB_FOREACH_SAFE(mi, xh_core_map_info_tree, &xh_core_map_info, mi_tmp) 445 | { 446 | #if XH_CORE_DEBUG 447 | XH_LOG_DEBUG("remove missing map info: %s", mi->pathname); 448 | #endif 449 | RB_REMOVE(xh_core_map_info_tree, &xh_core_map_info, mi); 450 | if(mi->pathname) free(mi->pathname); 451 | free(mi); 452 | } 453 | 454 | //save the new refreshed map info tree 455 | xh_core_map_info = map_info_refreshed; 456 | 457 | XH_LOG_INFO("map refreshed"); 458 | 459 | #if XH_CORE_DEBUG 460 | RB_FOREACH(mi, xh_core_map_info_tree, &xh_core_map_info) 461 | XH_LOG_DEBUG(" %"PRIxPTR" %s\n", mi->base_addr, mi->pathname); 462 | #endif 463 | } 464 | 465 | static void *xh_core_refresh_thread_func(void *arg) 466 | { 467 | (void)arg; 468 | 469 | pthread_setname_np(pthread_self(), "xh_refresh_loop"); 470 | 471 | while(xh_core_refresh_thread_running) 472 | { 473 | //waiting for a refresh task or exit 474 | pthread_mutex_lock(&xh_core_mutex); 475 | while(!xh_core_refresh_thread_do && xh_core_refresh_thread_running) 476 | { 477 | pthread_cond_wait(&xh_core_cond, &xh_core_mutex); 478 | } 479 | if(!xh_core_refresh_thread_running) 480 | { 481 | pthread_mutex_unlock(&xh_core_mutex); 482 | break; 483 | } 484 | xh_core_refresh_thread_do = 0; 485 | pthread_mutex_unlock(&xh_core_mutex); 486 | 487 | //refresh 488 | pthread_mutex_lock(&xh_core_refresh_mutex); 489 | xh_core_refresh_impl(); 490 | pthread_mutex_unlock(&xh_core_refresh_mutex); 491 | } 492 | 493 | return NULL; 494 | } 495 | 496 | static void xh_core_init_once() 497 | { 498 | if(xh_core_inited) return; 499 | 500 | pthread_mutex_lock(&xh_core_mutex); 501 | 502 | if(xh_core_inited) goto end; 503 | 504 | xh_core_inited = 1; 505 | 506 | //dump debug info 507 | XH_LOG_INFO("%s\n", xh_version_str_full()); 508 | #if XH_CORE_DEBUG 509 | xh_core_hook_info_t *hi; 510 | TAILQ_FOREACH(hi, &xh_core_hook_info, link) 511 | XH_LOG_INFO(" hook: %s @ %s, (%p, %p)\n", hi->symbol, hi->pathname_regex_str, 512 | hi->new_func, hi->old_func); 513 | xh_core_ignore_info_t *ii; 514 | TAILQ_FOREACH(ii, &xh_core_ignore_info, link) 515 | XH_LOG_INFO(" ignore: %s @ %s\n", ii->symbol ? ii->symbol : "ALL ", 516 | ii->pathname_regex_str); 517 | #endif 518 | 519 | //register signal handler 520 | if(0 != xh_core_add_sigsegv_handler()) goto end; 521 | 522 | //OK 523 | xh_core_init_ok = 1; 524 | 525 | end: 526 | pthread_mutex_unlock(&xh_core_mutex); 527 | } 528 | 529 | static void xh_core_init_async_once() 530 | { 531 | if(xh_core_async_inited) return; 532 | 533 | pthread_mutex_lock(&xh_core_mutex); 534 | 535 | if(xh_core_async_inited) goto end; 536 | 537 | xh_core_async_inited = 1; 538 | 539 | //create async refresh thread 540 | xh_core_refresh_thread_running = 1; 541 | if(0 != pthread_create(&xh_core_refresh_thread_tid, NULL, &xh_core_refresh_thread_func, NULL)) 542 | { 543 | xh_core_refresh_thread_running = 0; 544 | goto end; 545 | } 546 | 547 | //OK 548 | xh_core_async_init_ok = 1; 549 | 550 | end: 551 | pthread_mutex_unlock(&xh_core_mutex); 552 | } 553 | 554 | int xh_core_refresh(int async) 555 | { 556 | //init 557 | xh_core_init_once(); 558 | if(!xh_core_init_ok) return XH_ERRNO_UNKNOWN; 559 | 560 | if(async) 561 | { 562 | //init for async 563 | xh_core_init_async_once(); 564 | if(!xh_core_async_init_ok) return XH_ERRNO_UNKNOWN; 565 | 566 | //refresh async 567 | pthread_mutex_lock(&xh_core_mutex); 568 | xh_core_refresh_thread_do = 1; 569 | pthread_cond_signal(&xh_core_cond); 570 | pthread_mutex_unlock(&xh_core_mutex); 571 | } 572 | else 573 | { 574 | //refresh sync 575 | pthread_mutex_lock(&xh_core_refresh_mutex); 576 | xh_core_refresh_impl(); 577 | pthread_mutex_unlock(&xh_core_refresh_mutex); 578 | } 579 | 580 | return 0; 581 | } 582 | 583 | void xh_core_clear() 584 | { 585 | //stop the async refresh thread 586 | if(xh_core_async_init_ok) 587 | { 588 | pthread_mutex_lock(&xh_core_mutex); 589 | xh_core_refresh_thread_running = 0; 590 | pthread_cond_signal(&xh_core_cond); 591 | pthread_mutex_unlock(&xh_core_mutex); 592 | 593 | pthread_join(xh_core_refresh_thread_tid, NULL); 594 | xh_core_async_init_ok = 0; 595 | } 596 | xh_core_async_inited = 0; 597 | 598 | //unregister the sig handler 599 | if(xh_core_init_ok) 600 | { 601 | xh_core_del_sigsegv_handler(); 602 | xh_core_init_ok = 0; 603 | } 604 | xh_core_inited = 0; 605 | 606 | pthread_mutex_lock(&xh_core_mutex); 607 | pthread_mutex_lock(&xh_core_refresh_mutex); 608 | 609 | //free all map info 610 | xh_core_map_info_t *mi, *mi_tmp; 611 | RB_FOREACH_SAFE(mi, xh_core_map_info_tree, &xh_core_map_info, mi_tmp) 612 | { 613 | RB_REMOVE(xh_core_map_info_tree, &xh_core_map_info, mi); 614 | if(mi->pathname) free(mi->pathname); 615 | free(mi); 616 | } 617 | 618 | //free all hook info 619 | xh_core_hook_info_t *hi, *hi_tmp; 620 | TAILQ_FOREACH_SAFE(hi, &xh_core_hook_info, link, hi_tmp) 621 | { 622 | TAILQ_REMOVE(&xh_core_hook_info, hi, link); 623 | #if XH_CORE_DEBUG 624 | free(hi->pathname_regex_str); 625 | #endif 626 | regfree(&(hi->pathname_regex)); 627 | free(hi->symbol); 628 | free(hi); 629 | } 630 | 631 | //free all ignore info 632 | xh_core_ignore_info_t *ii, *ii_tmp; 633 | TAILQ_FOREACH_SAFE(ii, &xh_core_ignore_info, link, ii_tmp) 634 | { 635 | TAILQ_REMOVE(&xh_core_ignore_info, ii, link); 636 | #if XH_CORE_DEBUG 637 | free(ii->pathname_regex_str); 638 | #endif 639 | regfree(&(ii->pathname_regex)); 640 | free(ii->symbol); 641 | free(ii); 642 | } 643 | 644 | pthread_mutex_unlock(&xh_core_refresh_mutex); 645 | pthread_mutex_unlock(&xh_core_mutex); 646 | } 647 | 648 | void xh_core_enable_debug(int flag) 649 | { 650 | xh_log_priority = (flag ? ANDROID_LOG_DEBUG : ANDROID_LOG_WARN); 651 | } 652 | 653 | void xh_core_enable_sigsegv_protection(int flag) 654 | { 655 | xh_core_sigsegv_enable = (flag ? 1 : 0); 656 | } 657 | -------------------------------------------------------------------------------- /jni/external/xhook/xh_core.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #ifndef XH_CORE_H 25 | #define XH_CORE_H 1 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | int xh_core_register(const char *pathname_regex_str, const char *symbol, 32 | void *new_func, void **old_func); 33 | 34 | int xh_core_ignore(const char *pathname_regex_str, const char *symbol); 35 | 36 | int xh_core_refresh(int async); 37 | 38 | void xh_core_clear(); 39 | 40 | void xh_core_enable_debug(int flag); 41 | 42 | void xh_core_enable_sigsegv_protection(int flag); 43 | 44 | #ifdef __cplusplus 45 | } 46 | #endif 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /jni/external/xhook/xh_elf.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include "xh_errno.h" 36 | #include "xh_log.h" 37 | #include "xh_util.h" 38 | #include "xh_elf.h" 39 | 40 | #define XH_ELF_DEBUG 0 41 | 42 | #ifndef EI_ABIVERSION 43 | #define EI_ABIVERSION 8 44 | #endif 45 | 46 | #if defined(__arm__) 47 | #define XH_ELF_R_GENERIC_JUMP_SLOT R_ARM_JUMP_SLOT //.rel.plt 48 | #define XH_ELF_R_GENERIC_GLOB_DAT R_ARM_GLOB_DAT //.rel.dyn 49 | #define XH_ELF_R_GENERIC_ABS R_ARM_ABS32 //.rel.dyn 50 | #elif defined(__aarch64__) 51 | #define XH_ELF_R_GENERIC_JUMP_SLOT R_AARCH64_JUMP_SLOT 52 | #define XH_ELF_R_GENERIC_GLOB_DAT R_AARCH64_GLOB_DAT 53 | #define XH_ELF_R_GENERIC_ABS R_AARCH64_ABS64 54 | #elif defined(__i386__) 55 | #define XH_ELF_R_GENERIC_JUMP_SLOT R_386_JMP_SLOT 56 | #define XH_ELF_R_GENERIC_GLOB_DAT R_386_GLOB_DAT 57 | #define XH_ELF_R_GENERIC_ABS R_386_32 58 | #elif defined(__x86_64__) 59 | #define XH_ELF_R_GENERIC_JUMP_SLOT R_X86_64_JUMP_SLOT 60 | #define XH_ELF_R_GENERIC_GLOB_DAT R_X86_64_GLOB_DAT 61 | #define XH_ELF_R_GENERIC_ABS R_X86_64_64 62 | #endif 63 | 64 | #if defined(__LP64__) 65 | #define XH_ELF_R_SYM(info) ELF64_R_SYM(info) 66 | #define XH_ELF_R_TYPE(info) ELF64_R_TYPE(info) 67 | #else 68 | #define XH_ELF_R_SYM(info) ELF32_R_SYM(info) 69 | #define XH_ELF_R_TYPE(info) ELF32_R_TYPE(info) 70 | #endif 71 | 72 | //iterator for plain PLT 73 | typedef struct 74 | { 75 | uint8_t *cur; 76 | uint8_t *end; 77 | int is_use_rela; 78 | } xh_elf_plain_reloc_iterator_t; 79 | 80 | static void xh_elf_plain_reloc_iterator_init(xh_elf_plain_reloc_iterator_t *self, 81 | ElfW(Addr) rel, ElfW(Word) rel_sz, int is_use_rela) 82 | { 83 | self->cur = (uint8_t *)rel; 84 | self->end = self->cur + rel_sz; 85 | self->is_use_rela = is_use_rela; 86 | } 87 | 88 | static void *xh_elf_plain_reloc_iterator_next(xh_elf_plain_reloc_iterator_t *self) 89 | { 90 | if(self->cur >= self->end) return NULL; 91 | 92 | self->cur += (self->is_use_rela ? sizeof(ElfW(Rela)) : sizeof(ElfW(Rel))); 93 | return (void *)(self->cur); 94 | } 95 | 96 | //sleb128 decoder 97 | typedef struct 98 | { 99 | uint8_t *cur; 100 | uint8_t *end; 101 | } xh_elf_sleb128_decoder_t; 102 | 103 | static void xh_elf_sleb128_decoder_init(xh_elf_sleb128_decoder_t *self, 104 | ElfW(Addr) rel, ElfW(Word) rel_sz) 105 | { 106 | self->cur = (uint8_t *)rel; 107 | self->end = self->cur + rel_sz; 108 | } 109 | 110 | static int xh_elf_sleb128_decoder_next(xh_elf_sleb128_decoder_t *self, size_t *ret) 111 | { 112 | size_t value = 0; 113 | static const size_t size = 8 * sizeof(value); 114 | size_t shift = 0; 115 | uint8_t byte; 116 | 117 | do 118 | { 119 | if(self->cur >= self->end) 120 | return XH_ERRNO_FORMAT; 121 | 122 | byte = *(self->cur)++; 123 | value |= ((size_t)(byte & 127) << shift); 124 | shift += 7; 125 | } while(byte & 128); 126 | 127 | if(shift < size && (byte & 64)) 128 | { 129 | value |= -((size_t)(1) << shift); 130 | } 131 | 132 | *ret = value; 133 | return 0; 134 | } 135 | 136 | //iterator for sleb128 decoded packed PLT 137 | typedef struct 138 | { 139 | xh_elf_sleb128_decoder_t decoder; 140 | size_t relocation_count; 141 | size_t group_size; 142 | size_t group_flags; 143 | size_t group_r_offset_delta; 144 | size_t relocation_index; 145 | size_t relocation_group_index; 146 | ElfW(Rela) rela; 147 | ElfW(Rel) rel; 148 | ElfW(Addr) r_offset; 149 | size_t r_info; 150 | ssize_t r_addend; 151 | int is_use_rela; 152 | } xh_elf_packed_reloc_iterator_t; 153 | 154 | const size_t RELOCATION_GROUPED_BY_INFO_FLAG = 1; 155 | const size_t RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG = 2; 156 | const size_t RELOCATION_GROUPED_BY_ADDEND_FLAG = 4; 157 | const size_t RELOCATION_GROUP_HAS_ADDEND_FLAG = 8; 158 | 159 | static int xh_elf_packed_reloc_iterator_init(xh_elf_packed_reloc_iterator_t *self, 160 | ElfW(Addr) rel, ElfW(Word) rel_sz, int is_use_rela) 161 | { 162 | int r; 163 | 164 | memset(self, 0, sizeof(xh_elf_packed_reloc_iterator_t)); 165 | xh_elf_sleb128_decoder_init(&(self->decoder), rel, rel_sz); 166 | self->is_use_rela = is_use_rela; 167 | 168 | if(0 != (r = xh_elf_sleb128_decoder_next(&(self->decoder), &(self->relocation_count)))) return r; 169 | if(0 != (r = xh_elf_sleb128_decoder_next(&(self->decoder), (size_t *)&(self->r_offset)))) return r; 170 | return 0; 171 | } 172 | 173 | static int xh_elf_packed_reloc_iterator_read_group_fields(xh_elf_packed_reloc_iterator_t *self) 174 | { 175 | int r; 176 | size_t val; 177 | 178 | if(0 != (r = xh_elf_sleb128_decoder_next(&(self->decoder), &(self->group_size)))) return r; 179 | if(0 != (r = xh_elf_sleb128_decoder_next(&(self->decoder), &(self->group_flags)))) return r; 180 | 181 | if(self->group_flags & RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG) 182 | if(0 != (r = xh_elf_sleb128_decoder_next(&(self->decoder), &(self->group_r_offset_delta)))) return r; 183 | 184 | if(self->group_flags & RELOCATION_GROUPED_BY_INFO_FLAG) 185 | if(0 != (r = xh_elf_sleb128_decoder_next(&(self->decoder), (size_t *)&(self->r_info)))) return r; 186 | 187 | if((self->group_flags & RELOCATION_GROUP_HAS_ADDEND_FLAG) && 188 | (self->group_flags & RELOCATION_GROUPED_BY_ADDEND_FLAG)) 189 | { 190 | if(0 == self->is_use_rela) 191 | { 192 | XH_LOG_ERROR("unexpected r_addend in android.rel section"); 193 | return XH_ERRNO_FORMAT; 194 | } 195 | if(0 != (r = xh_elf_sleb128_decoder_next(&(self->decoder), &val))) return r; 196 | self->r_addend += (ssize_t)val; 197 | } 198 | else if(0 == (self->group_flags & RELOCATION_GROUP_HAS_ADDEND_FLAG)) 199 | { 200 | self->r_addend = 0; 201 | } 202 | 203 | self->relocation_group_index = 0; 204 | return 0; 205 | } 206 | 207 | static void *xh_elf_packed_reloc_iterator_next(xh_elf_packed_reloc_iterator_t *self) 208 | { 209 | size_t val; 210 | 211 | if(self->relocation_index >= self->relocation_count) return NULL; 212 | 213 | if(self->relocation_group_index == self->group_size) 214 | { 215 | if(0 != xh_elf_packed_reloc_iterator_read_group_fields(self)) return NULL; 216 | } 217 | 218 | if(self->group_flags & RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG) 219 | { 220 | self->r_offset += self->group_r_offset_delta; 221 | } 222 | else 223 | { 224 | if(0 != xh_elf_sleb128_decoder_next(&(self->decoder), &val)) return NULL; 225 | self->r_offset += val; 226 | } 227 | 228 | if(0 == (self->group_flags & RELOCATION_GROUPED_BY_INFO_FLAG)) 229 | if(0 != xh_elf_sleb128_decoder_next(&(self->decoder), &(self->r_info))) return NULL; 230 | 231 | if(self->is_use_rela && 232 | (self->group_flags & RELOCATION_GROUP_HAS_ADDEND_FLAG) && 233 | (0 == (self->group_flags & RELOCATION_GROUPED_BY_ADDEND_FLAG))) 234 | { 235 | if(0 != xh_elf_sleb128_decoder_next(&(self->decoder), &val)) return NULL; 236 | self->r_addend += (ssize_t)val; 237 | } 238 | 239 | self->relocation_index++; 240 | self->relocation_group_index++; 241 | 242 | if(self->is_use_rela) 243 | { 244 | self->rela.r_offset = self->r_offset; 245 | self->rela.r_info = self->r_info; 246 | self->rela.r_addend = self->r_addend; 247 | return (void *)(&(self->rela)); 248 | } 249 | else 250 | { 251 | self->rel.r_offset = self->r_offset; 252 | self->rel.r_info = self->r_info; 253 | return (void *)(&(self->rel)); 254 | } 255 | } 256 | 257 | //ELF header checker 258 | int xh_elf_check_elfheader(uintptr_t base_addr) 259 | { 260 | ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)base_addr; 261 | 262 | //check magic 263 | if(0 != memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) return XH_ERRNO_FORMAT; 264 | 265 | //check class (64/32) 266 | #if defined(__LP64__) 267 | if(ELFCLASS64 != ehdr->e_ident[EI_CLASS]) return XH_ERRNO_FORMAT; 268 | #else 269 | if(ELFCLASS32 != ehdr->e_ident[EI_CLASS]) return XH_ERRNO_FORMAT; 270 | #endif 271 | 272 | //check endian (little/big) 273 | if(ELFDATA2LSB != ehdr->e_ident[EI_DATA]) return XH_ERRNO_FORMAT; 274 | 275 | //check version 276 | if(EV_CURRENT != ehdr->e_ident[EI_VERSION]) return XH_ERRNO_FORMAT; 277 | 278 | //check type 279 | if(ET_EXEC != ehdr->e_type && ET_DYN != ehdr->e_type) return XH_ERRNO_FORMAT; 280 | 281 | //check machine 282 | #if defined(__arm__) 283 | if(EM_ARM != ehdr->e_machine) return XH_ERRNO_FORMAT; 284 | #elif defined(__aarch64__) 285 | if(EM_AARCH64 != ehdr->e_machine) return XH_ERRNO_FORMAT; 286 | #elif defined(__i386__) 287 | if(EM_386 != ehdr->e_machine) return XH_ERRNO_FORMAT; 288 | #elif defined(__x86_64__) 289 | if(EM_X86_64 != ehdr->e_machine) return XH_ERRNO_FORMAT; 290 | #else 291 | return XH_ERRNO_FORMAT; 292 | #endif 293 | 294 | //check version 295 | if(EV_CURRENT != ehdr->e_version) return XH_ERRNO_FORMAT; 296 | 297 | return 0; 298 | } 299 | 300 | //ELF hash func 301 | static uint32_t xh_elf_hash(const uint8_t *name) 302 | { 303 | uint32_t h = 0, g; 304 | 305 | while (*name) { 306 | h = (h << 4) + *name++; 307 | g = h & 0xf0000000; 308 | h ^= g; 309 | h ^= g >> 24; 310 | } 311 | 312 | return h; 313 | } 314 | 315 | //GNU hash func 316 | static uint32_t xh_elf_gnu_hash(const uint8_t *name) 317 | { 318 | uint32_t h = 5381; 319 | 320 | while(*name != 0) 321 | { 322 | h += (h << 5) + *name++; 323 | } 324 | return h; 325 | } 326 | 327 | static ElfW(Phdr) *xh_elf_get_first_segment_by_type(xh_elf_t *self, ElfW(Word) type) 328 | { 329 | ElfW(Phdr) *phdr; 330 | 331 | for(phdr = self->phdr; phdr < self->phdr + self->ehdr->e_phnum; phdr++) 332 | { 333 | if(phdr->p_type == type) 334 | { 335 | return phdr; 336 | } 337 | } 338 | return NULL; 339 | } 340 | 341 | static ElfW(Phdr) *xh_elf_get_first_segment_by_type_offset(xh_elf_t *self, ElfW(Word) type, ElfW(Off) offset) 342 | { 343 | ElfW(Phdr) *phdr; 344 | 345 | for(phdr = self->phdr; phdr < self->phdr + self->ehdr->e_phnum; phdr++) 346 | { 347 | if(phdr->p_type == type && phdr->p_offset == offset) 348 | { 349 | return phdr; 350 | } 351 | } 352 | return NULL; 353 | } 354 | 355 | static int xh_elf_hash_lookup(xh_elf_t *self, const char *symbol, uint32_t *symidx) 356 | { 357 | uint32_t hash = xh_elf_hash((uint8_t *)symbol); 358 | const char *symbol_cur; 359 | uint32_t i; 360 | 361 | for(i = self->bucket[hash % self->bucket_cnt]; 0 != i; i = self->chain[i]) 362 | { 363 | symbol_cur = self->strtab + self->symtab[i].st_name; 364 | 365 | if(0 == strcmp(symbol, symbol_cur)) 366 | { 367 | *symidx = i; 368 | XH_LOG_INFO("found %s at symidx: %u (ELF_HASH)\n", symbol, *symidx); 369 | return 0; 370 | } 371 | } 372 | 373 | return XH_ERRNO_NOTFND; 374 | } 375 | 376 | static int xh_elf_gnu_hash_lookup_def(xh_elf_t *self, const char *symbol, uint32_t *symidx) 377 | { 378 | uint32_t hash = xh_elf_gnu_hash((uint8_t *)symbol); 379 | 380 | static uint32_t elfclass_bits = sizeof(ElfW(Addr)) * 8; 381 | size_t word = self->bloom[(hash / elfclass_bits) % self->bloom_sz]; 382 | size_t mask = 0 383 | | (size_t)1 << (hash % elfclass_bits) 384 | | (size_t)1 << ((hash >> self->bloom_shift) % elfclass_bits); 385 | 386 | //if at least one bit is not set, this symbol is surely missing 387 | if((word & mask) != mask) return XH_ERRNO_NOTFND; 388 | 389 | //ignore STN_UNDEF 390 | uint32_t i = self->bucket[hash % self->bucket_cnt]; 391 | if(i < self->symoffset) return XH_ERRNO_NOTFND; 392 | 393 | //loop through the chain 394 | while(1) 395 | { 396 | const char *symname = self->strtab + self->symtab[i].st_name; 397 | const uint32_t symhash = self->chain[i - self->symoffset]; 398 | 399 | if((hash | (uint32_t)1) == (symhash | (uint32_t)1) && 0 == strcmp(symbol, symname)) 400 | { 401 | *symidx = i; 402 | XH_LOG_INFO("found %s at symidx: %u (GNU_HASH DEF)\n", symbol, *symidx); 403 | return 0; 404 | } 405 | 406 | //chain ends with an element with the lowest bit set to 1 407 | if(symhash & (uint32_t)1) break; 408 | 409 | i++; 410 | } 411 | 412 | return XH_ERRNO_NOTFND; 413 | } 414 | 415 | static int xh_elf_gnu_hash_lookup_undef(xh_elf_t *self, const char *symbol, uint32_t *symidx) 416 | { 417 | uint32_t i; 418 | 419 | for(i = 0; i < self->symoffset; i++) 420 | { 421 | const char *symname = self->strtab + self->symtab[i].st_name; 422 | if(0 == strcmp(symname, symbol)) 423 | { 424 | *symidx = i; 425 | XH_LOG_INFO("found %s at symidx: %u (GNU_HASH UNDEF)\n", symbol, *symidx); 426 | return 0; 427 | } 428 | } 429 | return XH_ERRNO_NOTFND; 430 | } 431 | 432 | static int xh_elf_gnu_hash_lookup(xh_elf_t *self, const char *symbol, uint32_t *symidx) 433 | { 434 | if(0 == xh_elf_gnu_hash_lookup_def(self, symbol, symidx)) return 0; 435 | if(0 == xh_elf_gnu_hash_lookup_undef(self, symbol, symidx)) return 0; 436 | return XH_ERRNO_NOTFND; 437 | } 438 | 439 | static int xh_elf_find_symidx_by_name(xh_elf_t *self, const char *symbol, uint32_t *symidx) 440 | { 441 | if(self->is_use_gnu_hash) 442 | return xh_elf_gnu_hash_lookup(self, symbol, symidx); 443 | else 444 | return xh_elf_hash_lookup(self, symbol, symidx); 445 | } 446 | 447 | static int xh_elf_replace_function(xh_elf_t *self, const char *symbol, ElfW(Addr) addr, void *new_func, void **old_func) 448 | { 449 | void *old_addr; 450 | unsigned int old_prot = 0; 451 | unsigned int need_prot = PROT_READ | PROT_WRITE; 452 | int r; 453 | 454 | //already replaced? 455 | //here we assume that we always have read permission, is this a problem? 456 | if(*(void **)addr == new_func) return 0; 457 | 458 | //get old prot 459 | if(0 != (r = xh_util_get_addr_protect(addr, self->pathname, &old_prot))) 460 | { 461 | XH_LOG_ERROR("get addr prot failed. ret: %d", r); 462 | return r; 463 | } 464 | 465 | if(old_prot != need_prot) 466 | { 467 | //set new prot 468 | if(0 != (r = xh_util_set_addr_protect(addr, need_prot))) 469 | { 470 | XH_LOG_ERROR("set addr prot failed. ret: %d", r); 471 | return r; 472 | } 473 | } 474 | 475 | //save old func 476 | old_addr = *(void **)addr; 477 | if(NULL != old_func) *old_func = old_addr; 478 | 479 | //replace func 480 | *(void **)addr = new_func; //segmentation fault sometimes 481 | 482 | if(old_prot != need_prot) 483 | { 484 | //restore the old prot 485 | if(0 != (r = xh_util_set_addr_protect(addr, old_prot))) 486 | { 487 | XH_LOG_WARN("restore addr prot failed. ret: %d", r); 488 | } 489 | } 490 | 491 | //clear cache 492 | xh_util_flush_instruction_cache(addr); 493 | 494 | XH_LOG_INFO("XH_HK_OK %p: %p -> %p %s %s\n", (void *)addr, old_addr, new_func, symbol, self->pathname); 495 | return 0; 496 | } 497 | 498 | static int xh_elf_check(xh_elf_t *self) 499 | { 500 | if(0 == self->base_addr) 501 | { 502 | XH_LOG_ERROR("base_addr == 0\n"); 503 | return 1; 504 | } 505 | if(0 == self->bias_addr) 506 | { 507 | XH_LOG_ERROR("bias_addr == 0\n"); 508 | return 1; 509 | } 510 | if(NULL == self->ehdr) 511 | { 512 | XH_LOG_ERROR("ehdr == NULL\n"); 513 | return 1; 514 | } 515 | if(NULL == self->phdr) 516 | { 517 | XH_LOG_ERROR("phdr == NULL\n"); 518 | return 1; 519 | } 520 | if(NULL == self->strtab) 521 | { 522 | XH_LOG_ERROR("strtab == NULL\n"); 523 | return 1; 524 | } 525 | if(NULL == self->symtab) 526 | { 527 | XH_LOG_ERROR("symtab == NULL\n"); 528 | return 1; 529 | } 530 | if(NULL == self->bucket) 531 | { 532 | XH_LOG_ERROR("bucket == NULL\n"); 533 | return 1; 534 | } 535 | if(NULL == self->chain) 536 | { 537 | XH_LOG_ERROR("chain == NULL\n"); 538 | return 1; 539 | } 540 | if(1 == self->is_use_gnu_hash && NULL == self->bloom) 541 | { 542 | XH_LOG_ERROR("bloom == NULL\n"); 543 | return 1; 544 | } 545 | 546 | return 0; 547 | } 548 | 549 | #if XH_ELF_DEBUG 550 | 551 | static void xh_elf_dump_elfheader(xh_elf_t *self) 552 | { 553 | static char alpha_tab[17] = "0123456789ABCDEF"; 554 | int i; 555 | uint8_t ch; 556 | char buff[EI_NIDENT * 3 + 1]; 557 | 558 | for(i = 0; i < EI_NIDENT; i++) 559 | { 560 | ch = self->ehdr->e_ident[i]; 561 | buff[i * 3 + 0] = alpha_tab[(int)((ch >> 4) & 0x0F)]; 562 | buff[i * 3 + 1] = alpha_tab[(int)(ch & 0x0F)]; 563 | buff[i * 3 + 2] = ' '; 564 | } 565 | buff[EI_NIDENT * 3] = '\0'; 566 | 567 | XH_LOG_DEBUG("Elf Header:\n"); 568 | XH_LOG_DEBUG(" Magic: %s\n", buff); 569 | XH_LOG_DEBUG(" Class: %#x\n", self->ehdr->e_ident[EI_CLASS]); 570 | XH_LOG_DEBUG(" Data: %#x\n", self->ehdr->e_ident[EI_DATA]); 571 | XH_LOG_DEBUG(" Version: %#x\n", self->ehdr->e_ident[EI_VERSION]); 572 | XH_LOG_DEBUG(" OS/ABI: %#x\n", self->ehdr->e_ident[EI_OSABI]); 573 | XH_LOG_DEBUG(" ABI Version: %#x\n", self->ehdr->e_ident[EI_ABIVERSION]); 574 | XH_LOG_DEBUG(" Type: %#x\n", self->ehdr->e_type); 575 | XH_LOG_DEBUG(" Machine: %#x\n", self->ehdr->e_machine); 576 | XH_LOG_DEBUG(" Version: %#x\n", self->ehdr->e_version); 577 | XH_LOG_DEBUG(" Entry point address: %"XH_UTIL_FMT_X"\n", self->ehdr->e_entry); 578 | XH_LOG_DEBUG(" Start of program headers: %"XH_UTIL_FMT_X" (bytes into file)\n", self->ehdr->e_phoff); 579 | XH_LOG_DEBUG(" Start of section headers: %"XH_UTIL_FMT_X" (bytes into file)\n", self->ehdr->e_shoff); 580 | XH_LOG_DEBUG(" Flags: %#x\n", self->ehdr->e_flags); 581 | XH_LOG_DEBUG(" Size of this header: %u (bytes)\n", self->ehdr->e_ehsize); 582 | XH_LOG_DEBUG(" Size of program headers: %u (bytes)\n", self->ehdr->e_phentsize); 583 | XH_LOG_DEBUG(" Number of program headers: %u\n", self->ehdr->e_phnum); 584 | XH_LOG_DEBUG(" Size of section headers: %u (bytes)\n", self->ehdr->e_shentsize); 585 | XH_LOG_DEBUG(" Number of section headers: %u\n", self->ehdr->e_shnum); 586 | XH_LOG_DEBUG(" Section header string table index: %u\n", self->ehdr->e_shstrndx); 587 | } 588 | 589 | static void xh_elf_dump_programheader(xh_elf_t *self) 590 | { 591 | ElfW(Phdr) *phdr = self->phdr; 592 | size_t i; 593 | 594 | XH_LOG_DEBUG("Program Headers:\n"); 595 | XH_LOG_DEBUG(" %-8s " \ 596 | "%-"XH_UTIL_FMT_FIXED_S" " \ 597 | "%-"XH_UTIL_FMT_FIXED_S" " \ 598 | "%-"XH_UTIL_FMT_FIXED_S" " \ 599 | "%-"XH_UTIL_FMT_FIXED_S" " \ 600 | "%-"XH_UTIL_FMT_FIXED_S" " \ 601 | "%-8s " \ 602 | "%-s\n", 603 | "Type", 604 | "Offset", 605 | "VirtAddr", 606 | "PhysAddr", 607 | "FileSiz", 608 | "MemSiz", 609 | "Flg", 610 | "Align"); 611 | for(i = 0; i < self->ehdr->e_phnum; i++, phdr++) 612 | { 613 | XH_LOG_DEBUG(" %-8x " \ 614 | "%."XH_UTIL_FMT_FIXED_X" " \ 615 | "%."XH_UTIL_FMT_FIXED_X" " \ 616 | "%."XH_UTIL_FMT_FIXED_X" " \ 617 | "%."XH_UTIL_FMT_FIXED_X" " \ 618 | "%."XH_UTIL_FMT_FIXED_X" " \ 619 | "%-8x " \ 620 | "%"XH_UTIL_FMT_X"\n", 621 | phdr->p_type, 622 | phdr->p_offset, 623 | phdr->p_vaddr, 624 | phdr->p_paddr, 625 | phdr->p_filesz, 626 | phdr->p_memsz, 627 | phdr->p_flags, 628 | phdr->p_align); 629 | } 630 | } 631 | 632 | static void xh_elf_dump_dynamic(xh_elf_t *self) 633 | { 634 | ElfW(Dyn) *dyn = self->dyn; 635 | size_t dyn_cnt = (self->dyn_sz / sizeof(ElfW(Dyn))); 636 | size_t i; 637 | 638 | XH_LOG_DEBUG("Dynamic section contains %zu entries:\n", dyn_cnt); 639 | XH_LOG_DEBUG(" %-"XH_UTIL_FMT_FIXED_S" " \ 640 | "%s\n", 641 | "Tag", 642 | "Val"); 643 | for(i = 0; i < dyn_cnt; i++, dyn++) 644 | { 645 | XH_LOG_DEBUG(" %-"XH_UTIL_FMT_FIXED_X" " \ 646 | "%-"XH_UTIL_FMT_X"\n", 647 | dyn->d_tag, 648 | dyn->d_un.d_val); 649 | } 650 | } 651 | 652 | static void xh_elf_dump_rel(xh_elf_t *self, const char *type, ElfW(Addr) rel_addr, ElfW(Word) rel_sz) 653 | { 654 | ElfW(Rela) *rela; 655 | ElfW(Rel) *rel; 656 | ElfW(Word) cnt; 657 | ElfW(Word) i; 658 | ElfW(Sym) *sym; 659 | 660 | if(self->is_use_rela) 661 | { 662 | rela = (ElfW(Rela) *)(rel_addr); 663 | cnt = rel_sz / sizeof(ElfW(Rela)); 664 | } 665 | else 666 | { 667 | rel = (ElfW(Rel) *)(rel_addr); 668 | cnt = rel_sz / sizeof(ElfW(Rel)); 669 | } 670 | 671 | XH_LOG_DEBUG("Relocation section '.rel%s%s' contains %u entries:\n", 672 | (self->is_use_rela ? "a" : ""), type, cnt); 673 | XH_LOG_DEBUG(" %-"XH_UTIL_FMT_FIXED_S" " \ 674 | "%-"XH_UTIL_FMT_FIXED_S" " \ 675 | "%-8s " \ 676 | "%-8s " \ 677 | "%-8s " \ 678 | "%s\n", 679 | "Offset", 680 | "Info", 681 | "Type", 682 | "Sym.Idx", 683 | "Sym.Val", 684 | "Sym.Name"); 685 | const char *fmt = " %."XH_UTIL_FMT_FIXED_X" " \ 686 | "%."XH_UTIL_FMT_FIXED_X" " \ 687 | "%.8x " \ 688 | "%.8u " \ 689 | "%.8x " \ 690 | "%s\n"; 691 | for(i = 0; i < cnt; i++) 692 | { 693 | if(self->is_use_rela) 694 | { 695 | sym = &(self->symtab[XH_ELF_R_SYM(rela[i].r_info)]); 696 | XH_LOG_DEBUG(fmt, 697 | rela[i].r_offset, 698 | rela[i].r_info, 699 | XH_ELF_R_TYPE(rela[i].r_info), 700 | XH_ELF_R_SYM(rela[i].r_info), 701 | sym->st_value, 702 | self->strtab + sym->st_name); 703 | } 704 | else 705 | { 706 | sym = &(self->symtab[XH_ELF_R_SYM(rel[i].r_info)]); 707 | XH_LOG_DEBUG(fmt, 708 | rel[i].r_offset, 709 | rel[i].r_info, 710 | XH_ELF_R_TYPE(rel[i].r_info), 711 | XH_ELF_R_SYM(rel[i].r_info), 712 | sym->st_value, 713 | self->strtab + sym->st_name); 714 | } 715 | } 716 | } 717 | 718 | static void xh_elf_dump_symtab(xh_elf_t *self) 719 | { 720 | if(self->is_use_gnu_hash) return; 721 | 722 | ElfW(Word) symtab_cnt = self->chain_cnt; 723 | ElfW(Word) i; 724 | 725 | XH_LOG_DEBUG("Symbol table '.dynsym' contains %u entries:\n", symtab_cnt); 726 | XH_LOG_DEBUG(" %-8s " \ 727 | "%-"XH_UTIL_FMT_FIXED_S" " \ 728 | "%s\n", 729 | "Idx", 730 | "Value", 731 | "Name"); 732 | for(i = 0; i < symtab_cnt; i++) 733 | { 734 | XH_LOG_DEBUG(" %-8u " \ 735 | "%."XH_UTIL_FMT_FIXED_X" " \ 736 | "%s\n", 737 | i, 738 | self->symtab[i].st_value, 739 | self->strtab + self->symtab[i].st_name); 740 | } 741 | } 742 | 743 | static void xh_elf_dump(xh_elf_t *self) 744 | { 745 | if(xh_log_priority < ANDROID_LOG_DEBUG) return; 746 | 747 | XH_LOG_DEBUG("Elf Pathname: %s\n", self->pathname); 748 | XH_LOG_DEBUG("Elf bias addr: %p\n", (void *)self->bias_addr); 749 | xh_elf_dump_elfheader(self); 750 | xh_elf_dump_programheader(self); 751 | xh_elf_dump_dynamic(self); 752 | xh_elf_dump_rel(self, ".plt", self->relplt, self->relplt_sz); 753 | xh_elf_dump_rel(self, ".dyn", self->reldyn, self->reldyn_sz); 754 | xh_elf_dump_symtab(self); 755 | } 756 | 757 | #endif 758 | 759 | int xh_elf_init(xh_elf_t *self, uintptr_t base_addr, const char *pathname) 760 | { 761 | if(0 == base_addr || NULL == pathname) return XH_ERRNO_INVAL; 762 | 763 | //always reset 764 | memset(self, 0, sizeof(xh_elf_t)); 765 | 766 | self->pathname = pathname; 767 | self->base_addr = (ElfW(Addr))base_addr; 768 | self->ehdr = (ElfW(Ehdr) *)base_addr; 769 | self->phdr = (ElfW(Phdr) *)(base_addr + self->ehdr->e_phoff); //segmentation fault sometimes 770 | 771 | //find the first load-segment with offset 0 772 | ElfW(Phdr) *phdr0 = xh_elf_get_first_segment_by_type_offset(self, PT_LOAD, 0); 773 | if(NULL == phdr0) 774 | { 775 | XH_LOG_ERROR("Can NOT found the first load segment. %s", pathname); 776 | return XH_ERRNO_FORMAT; 777 | } 778 | 779 | #if XH_ELF_DEBUG 780 | if(0 != phdr0->p_vaddr) 781 | XH_LOG_DEBUG("first load-segment vaddr NOT 0 (vaddr: %p). %s", 782 | (void *)(phdr0->p_vaddr), pathname); 783 | #endif 784 | 785 | //save load bias addr 786 | if(self->base_addr < phdr0->p_vaddr) return XH_ERRNO_FORMAT; 787 | self->bias_addr = self->base_addr - phdr0->p_vaddr; 788 | 789 | //find dynamic-segment 790 | ElfW(Phdr) *dhdr = xh_elf_get_first_segment_by_type(self, PT_DYNAMIC); 791 | if(NULL == dhdr) 792 | { 793 | XH_LOG_ERROR("Can NOT found dynamic segment. %s", pathname); 794 | return XH_ERRNO_FORMAT; 795 | } 796 | 797 | //parse dynamic-segment 798 | self->dyn = (ElfW(Dyn) *)(self->bias_addr + dhdr->p_vaddr); 799 | self->dyn_sz = dhdr->p_memsz; 800 | ElfW(Dyn) *dyn = self->dyn; 801 | ElfW(Dyn) *dyn_end = self->dyn + (self->dyn_sz / sizeof(ElfW(Dyn))); 802 | uint32_t *raw; 803 | for(; dyn < dyn_end; dyn++) 804 | { 805 | switch(dyn->d_tag) //segmentation fault sometimes 806 | { 807 | case DT_NULL: 808 | //the end of the dynamic-section 809 | dyn = dyn_end; 810 | break; 811 | case DT_STRTAB: 812 | { 813 | self->strtab = (const char *)(self->bias_addr + dyn->d_un.d_ptr); 814 | if((ElfW(Addr))(self->strtab) < self->base_addr) return XH_ERRNO_FORMAT; 815 | break; 816 | } 817 | case DT_SYMTAB: 818 | { 819 | self->symtab = (ElfW(Sym) *)(self->bias_addr + dyn->d_un.d_ptr); 820 | if((ElfW(Addr))(self->symtab) < self->base_addr) return XH_ERRNO_FORMAT; 821 | break; 822 | } 823 | case DT_PLTREL: 824 | //use rel or rela? 825 | self->is_use_rela = (dyn->d_un.d_val == DT_RELA ? 1 : 0); 826 | break; 827 | case DT_JMPREL: 828 | { 829 | self->relplt = (ElfW(Addr))(self->bias_addr + dyn->d_un.d_ptr); 830 | if((ElfW(Addr))(self->relplt) < self->base_addr) return XH_ERRNO_FORMAT; 831 | break; 832 | } 833 | case DT_PLTRELSZ: 834 | self->relplt_sz = dyn->d_un.d_val; 835 | break; 836 | case DT_REL: 837 | case DT_RELA: 838 | { 839 | self->reldyn = (ElfW(Addr))(self->bias_addr + dyn->d_un.d_ptr); 840 | if((ElfW(Addr))(self->reldyn) < self->base_addr) return XH_ERRNO_FORMAT; 841 | break; 842 | } 843 | case DT_RELSZ: 844 | case DT_RELASZ: 845 | self->reldyn_sz = dyn->d_un.d_val; 846 | break; 847 | case DT_ANDROID_REL: 848 | case DT_ANDROID_RELA: 849 | { 850 | self->relandroid = (ElfW(Addr))(self->bias_addr + dyn->d_un.d_ptr); 851 | if((ElfW(Addr))(self->relandroid) < self->base_addr) return XH_ERRNO_FORMAT; 852 | break; 853 | } 854 | case DT_ANDROID_RELSZ: 855 | case DT_ANDROID_RELASZ: 856 | self->relandroid_sz = dyn->d_un.d_val; 857 | break; 858 | case DT_HASH: 859 | { 860 | raw = (uint32_t *)(self->bias_addr + dyn->d_un.d_ptr); 861 | if((ElfW(Addr))raw < self->base_addr) return XH_ERRNO_FORMAT; 862 | self->bucket_cnt = raw[0]; 863 | self->chain_cnt = raw[1]; 864 | self->bucket = &raw[2]; 865 | self->chain = &(self->bucket[self->bucket_cnt]); 866 | break; 867 | } 868 | case DT_GNU_HASH: 869 | { 870 | raw = (uint32_t *)(self->bias_addr + dyn->d_un.d_ptr); 871 | if((ElfW(Addr))raw < self->base_addr) return XH_ERRNO_FORMAT; 872 | self->bucket_cnt = raw[0]; 873 | self->symoffset = raw[1]; 874 | self->bloom_sz = raw[2]; 875 | self->bloom_shift = raw[3]; 876 | self->bloom = (ElfW(Addr) *)(&raw[4]); 877 | self->bucket = (uint32_t *)(&(self->bloom[self->bloom_sz])); 878 | self->chain = (uint32_t *)(&(self->bucket[self->bucket_cnt])); 879 | self->is_use_gnu_hash = 1; 880 | break; 881 | } 882 | default: 883 | break; 884 | } 885 | } 886 | 887 | //check android rel/rela 888 | if(0 != self->relandroid) 889 | { 890 | const char *rel = (const char *)self->relandroid; 891 | if(self->relandroid_sz < 4 || 892 | rel[0] != 'A' || 893 | rel[1] != 'P' || 894 | rel[2] != 'S' || 895 | rel[3] != '2') 896 | { 897 | XH_LOG_ERROR("android rel/rela format error\n"); 898 | return XH_ERRNO_FORMAT; 899 | } 900 | 901 | self->relandroid += 4; 902 | self->relandroid_sz -= 4; 903 | } 904 | 905 | //check elf info 906 | if(0 != xh_elf_check(self)) 907 | { 908 | XH_LOG_ERROR("elf init check failed. %s", pathname); 909 | return XH_ERRNO_FORMAT; 910 | } 911 | 912 | #if XH_ELF_DEBUG 913 | xh_elf_dump(self); 914 | #endif 915 | 916 | XH_LOG_INFO("init OK: %s (%s %s PLT:%u DYN:%u ANDROID:%u)\n", self->pathname, 917 | self->is_use_rela ? "RELA" : "REL", 918 | self->is_use_gnu_hash ? "GNU_HASH" : "ELF_HASH", 919 | self->relplt_sz, self->reldyn_sz, self->relandroid_sz); 920 | 921 | return 0; 922 | } 923 | 924 | static int xh_elf_find_and_replace_func(xh_elf_t *self, const char *section, 925 | int is_plt, const char *symbol, 926 | void *new_func, void **old_func, 927 | uint32_t symidx, void *rel_common, 928 | int *found) 929 | { 930 | ElfW(Rela) *rela; 931 | ElfW(Rel) *rel; 932 | ElfW(Addr) r_offset; 933 | size_t r_info; 934 | size_t r_sym; 935 | size_t r_type; 936 | ElfW(Addr) addr; 937 | int r; 938 | 939 | if(NULL != found) *found = 0; 940 | 941 | if(self->is_use_rela) 942 | { 943 | rela = (ElfW(Rela) *)rel_common; 944 | r_info = rela->r_info; 945 | r_offset = rela->r_offset; 946 | } 947 | else 948 | { 949 | rel = (ElfW(Rel) *)rel_common; 950 | r_info = rel->r_info; 951 | r_offset = rel->r_offset; 952 | } 953 | 954 | //check sym 955 | r_sym = XH_ELF_R_SYM(r_info); 956 | if(r_sym != symidx) return 0; 957 | 958 | //check type 959 | r_type = XH_ELF_R_TYPE(r_info); 960 | if(is_plt && r_type != XH_ELF_R_GENERIC_JUMP_SLOT) return 0; 961 | if(!is_plt && (r_type != XH_ELF_R_GENERIC_GLOB_DAT && r_type != XH_ELF_R_GENERIC_ABS)) return 0; 962 | 963 | //we found it 964 | XH_LOG_INFO("found %s at %s offset: %p\n", symbol, section, (void *)r_offset); 965 | if(NULL != found) *found = 1; 966 | 967 | //do replace 968 | addr = self->bias_addr + r_offset; 969 | if(addr < self->base_addr) return XH_ERRNO_FORMAT; 970 | if(0 != (r = xh_elf_replace_function(self, symbol, addr, new_func, old_func))) 971 | { 972 | XH_LOG_ERROR("replace function failed: %s at %s\n", symbol, section); 973 | return r; 974 | } 975 | 976 | return 0; 977 | } 978 | 979 | int xh_elf_hook(xh_elf_t *self, const char *symbol, void *new_func, void **old_func) 980 | { 981 | uint32_t symidx; 982 | void *rel_common; 983 | xh_elf_plain_reloc_iterator_t plain_iter; 984 | xh_elf_packed_reloc_iterator_t packed_iter; 985 | int found; 986 | int r; 987 | 988 | if(NULL == self->pathname) 989 | { 990 | XH_LOG_ERROR("not inited\n"); 991 | return XH_ERRNO_ELFINIT; //not inited? 992 | } 993 | 994 | if(NULL == symbol || NULL == new_func) return XH_ERRNO_INVAL; 995 | 996 | XH_LOG_INFO("hooking %s in %s\n", symbol, self->pathname); 997 | 998 | //find symbol index by symbol name 999 | if(0 != (r = xh_elf_find_symidx_by_name(self, symbol, &symidx))) return 0; 1000 | 1001 | //replace for .rel(a).plt 1002 | if(0 != self->relplt) 1003 | { 1004 | xh_elf_plain_reloc_iterator_init(&plain_iter, self->relplt, self->relplt_sz, self->is_use_rela); 1005 | while(NULL != (rel_common = xh_elf_plain_reloc_iterator_next(&plain_iter))) 1006 | { 1007 | if(0 != (r = xh_elf_find_and_replace_func(self, 1008 | (self->is_use_rela ? ".rela.plt" : ".rel.plt"), 1, 1009 | symbol, new_func, old_func, 1010 | symidx, rel_common, &found))) return r; 1011 | if(found) break; 1012 | } 1013 | } 1014 | 1015 | //replace for .rel(a).dyn 1016 | if(0 != self->reldyn) 1017 | { 1018 | xh_elf_plain_reloc_iterator_init(&plain_iter, self->reldyn, self->reldyn_sz, self->is_use_rela); 1019 | while(NULL != (rel_common = xh_elf_plain_reloc_iterator_next(&plain_iter))) 1020 | { 1021 | if(0 != (r = xh_elf_find_and_replace_func(self, 1022 | (self->is_use_rela ? ".rela.dyn" : ".rel.dyn"), 0, 1023 | symbol, new_func, old_func, 1024 | symidx, rel_common, NULL))) return r; 1025 | } 1026 | } 1027 | 1028 | //replace for .rel(a).android 1029 | if(0 != self->relandroid) 1030 | { 1031 | xh_elf_packed_reloc_iterator_init(&packed_iter, self->relandroid, self->relandroid_sz, self->is_use_rela); 1032 | while(NULL != (rel_common = xh_elf_packed_reloc_iterator_next(&packed_iter))) 1033 | { 1034 | if(0 != (r = xh_elf_find_and_replace_func(self, 1035 | (self->is_use_rela ? ".rela.android" : ".rel.android"), 0, 1036 | symbol, new_func, old_func, 1037 | symidx, rel_common, NULL))) return r; 1038 | } 1039 | } 1040 | 1041 | return 0; 1042 | } 1043 | -------------------------------------------------------------------------------- /jni/external/xhook/xh_elf.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #ifndef XH_ELF_H 25 | #define XH_ELF_H 1 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | typedef struct 36 | { 37 | const char *pathname; 38 | 39 | ElfW(Addr) base_addr; 40 | ElfW(Addr) bias_addr; 41 | 42 | ElfW(Ehdr) *ehdr; 43 | ElfW(Phdr) *phdr; 44 | 45 | ElfW(Dyn) *dyn; //.dynamic 46 | ElfW(Word) dyn_sz; 47 | 48 | const char *strtab; //.dynstr (string-table) 49 | ElfW(Sym) *symtab; //.dynsym (symbol-index to string-table's offset) 50 | 51 | ElfW(Addr) relplt; //.rel.plt or .rela.plt 52 | ElfW(Word) relplt_sz; 53 | 54 | ElfW(Addr) reldyn; //.rel.dyn or .rela.dyn 55 | ElfW(Word) reldyn_sz; 56 | 57 | ElfW(Addr) relandroid; //android compressed rel or rela 58 | ElfW(Word) relandroid_sz; 59 | 60 | //for ELF hash 61 | uint32_t *bucket; 62 | uint32_t bucket_cnt; 63 | uint32_t *chain; 64 | uint32_t chain_cnt; //invalid for GNU hash 65 | 66 | //append for GNU hash 67 | uint32_t symoffset; 68 | ElfW(Addr) *bloom; 69 | uint32_t bloom_sz; 70 | uint32_t bloom_shift; 71 | 72 | int is_use_rela; 73 | int is_use_gnu_hash; 74 | } xh_elf_t; 75 | 76 | int xh_elf_init(xh_elf_t *self, uintptr_t base_addr, const char *pathname); 77 | int xh_elf_hook(xh_elf_t *self, const char *symbol, void *new_func, void **old_func); 78 | 79 | int xh_elf_check_elfheader(uintptr_t base_addr); 80 | 81 | #ifdef __cplusplus 82 | } 83 | #endif 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /jni/external/xhook/xh_errno.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #ifndef XH_ERRNO_H 25 | #define XH_ERRNO_H 1 26 | 27 | #define XH_ERRNO_UNKNOWN 1001 28 | #define XH_ERRNO_INVAL 1002 29 | #define XH_ERRNO_NOMEM 1003 30 | #define XH_ERRNO_REPEAT 1004 31 | #define XH_ERRNO_NOTFND 1005 32 | #define XH_ERRNO_BADMAPS 1006 33 | #define XH_ERRNO_FORMAT 1007 34 | #define XH_ERRNO_ELFINIT 1008 35 | #define XH_ERRNO_SEGVERR 1009 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /jni/external/xhook/xh_jni.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #include 25 | #include "xhook.h" 26 | 27 | #define JNI_API_DEF(f) Java_com_qiyi_xhook_NativeHandler_##f 28 | 29 | JNIEXPORT jint JNI_API_DEF(refresh)(JNIEnv *env, jobject obj, jboolean async) 30 | { 31 | (void)env; 32 | (void)obj; 33 | 34 | return xhook_refresh(async ? 1 : 0); 35 | } 36 | 37 | JNIEXPORT void JNI_API_DEF(clear)(JNIEnv *env, jobject obj) 38 | { 39 | (void)env; 40 | (void)obj; 41 | 42 | xhook_clear(); 43 | } 44 | 45 | JNIEXPORT void JNI_API_DEF(enableDebug)(JNIEnv *env, jobject obj, jboolean flag) 46 | { 47 | (void)env; 48 | (void)obj; 49 | 50 | xhook_enable_debug(flag ? 1 : 0); 51 | } 52 | 53 | JNIEXPORT void JNI_API_DEF(enableSigSegvProtection)(JNIEnv *env, jobject obj, jboolean flag) 54 | { 55 | (void)env; 56 | (void)obj; 57 | 58 | xhook_enable_sigsegv_protection(flag ? 1 : 0); 59 | } 60 | -------------------------------------------------------------------------------- /jni/external/xhook/xh_log.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #include 25 | #include "xh_log.h" 26 | 27 | android_LogPriority xh_log_priority = ANDROID_LOG_WARN; 28 | -------------------------------------------------------------------------------- /jni/external/xhook/xh_log.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #ifndef XH_LOG_H 25 | #define XH_LOG_H 1 26 | 27 | #include 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | extern android_LogPriority xh_log_priority; 34 | 35 | #define XH_LOG_TAG "xhook" 36 | #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) 37 | #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) 38 | #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) 39 | #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) 40 | 41 | #ifdef __cplusplus 42 | } 43 | #endif 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /jni/external/xhook/xh_util.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include "xh_util.h" 37 | #include "xh_errno.h" 38 | #include "xh_log.h" 39 | 40 | #define PAGE_START(addr) ((addr) & PAGE_MASK) 41 | #define PAGE_END(addr) (PAGE_START(addr + sizeof(uintptr_t) - 1) + PAGE_SIZE) 42 | #define PAGE_COVER(addr) (PAGE_END(addr) - PAGE_START(addr)) 43 | 44 | int xh_util_get_mem_protect(uintptr_t addr, size_t len, const char *pathname, unsigned int *prot) 45 | { 46 | uintptr_t start_addr = addr; 47 | uintptr_t end_addr = addr + len; 48 | FILE *fp; 49 | char line[512]; 50 | uintptr_t start, end; 51 | char perm[5]; 52 | int load0 = 1; 53 | int found_all = 0; 54 | 55 | *prot = 0; 56 | 57 | if(NULL == (fp = fopen("/proc/self/maps", "r"))) return XH_ERRNO_BADMAPS; 58 | 59 | while(fgets(line, sizeof(line), fp)) 60 | { 61 | if(NULL != pathname) 62 | if(NULL == strstr(line, pathname)) continue; 63 | 64 | if(sscanf(line, "%"PRIxPTR"-%"PRIxPTR" %4s ", &start, &end, perm) != 3) continue; 65 | 66 | if(perm[3] != 'p') continue; 67 | 68 | if(start_addr >= start && start_addr < end) 69 | { 70 | if(load0) 71 | { 72 | //first load segment 73 | if(perm[0] == 'r') *prot |= PROT_READ; 74 | if(perm[1] == 'w') *prot |= PROT_WRITE; 75 | if(perm[2] == 'x') *prot |= PROT_EXEC; 76 | load0 = 0; 77 | } 78 | else 79 | { 80 | //others 81 | if(perm[0] != 'r') *prot &= ~PROT_READ; 82 | if(perm[1] != 'w') *prot &= ~PROT_WRITE; 83 | if(perm[2] != 'x') *prot &= ~PROT_EXEC; 84 | } 85 | 86 | if(end_addr <= end) 87 | { 88 | found_all = 1; 89 | break; //finished 90 | } 91 | else 92 | { 93 | start_addr = end; //try to find the next load segment 94 | } 95 | } 96 | } 97 | 98 | fclose(fp); 99 | 100 | if(!found_all) return XH_ERRNO_SEGVERR; 101 | 102 | return 0; 103 | } 104 | 105 | int xh_util_get_addr_protect(uintptr_t addr, const char *pathname, unsigned int *prot) 106 | { 107 | return xh_util_get_mem_protect(addr, sizeof(addr), pathname, prot); 108 | } 109 | 110 | int xh_util_set_addr_protect(uintptr_t addr, unsigned int prot) 111 | { 112 | if(0 != mprotect((void *)PAGE_START(addr), PAGE_COVER(addr), (int)prot)) 113 | return 0 == errno ? XH_ERRNO_UNKNOWN : errno; 114 | 115 | return 0; 116 | } 117 | 118 | void xh_util_flush_instruction_cache(uintptr_t addr) 119 | { 120 | __builtin___clear_cache((void *)PAGE_START(addr), (void *)PAGE_END(addr)); 121 | } 122 | -------------------------------------------------------------------------------- /jni/external/xhook/xh_util.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #ifndef XH_UTILS_H 25 | #define XH_UTILS_H 1 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | #if defined(__LP64__) 32 | #define XH_UTIL_FMT_LEN "16" 33 | #define XH_UTIL_FMT_X "llx" 34 | #else 35 | #define XH_UTIL_FMT_LEN "8" 36 | #define XH_UTIL_FMT_X "x" 37 | #endif 38 | 39 | #define XH_UTIL_FMT_FIXED_X XH_UTIL_FMT_LEN XH_UTIL_FMT_X 40 | #define XH_UTIL_FMT_FIXED_S XH_UTIL_FMT_LEN "s" 41 | 42 | int xh_util_get_mem_protect(uintptr_t addr, size_t len, const char *pathname, unsigned int *prot); 43 | int xh_util_get_addr_protect(uintptr_t addr, const char *pathname, unsigned int *prot); 44 | int xh_util_set_addr_protect(uintptr_t addr, unsigned int prot); 45 | void xh_util_flush_instruction_cache(uintptr_t addr); 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /jni/external/xhook/xh_version.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #include "xh_version.h" 25 | 26 | #define XH_VERSION_MAJOR 1 27 | #define XH_VERSION_MINOR 1 28 | #define XH_VERSION_EXTRA 9 29 | 30 | #define XH_VERSION ((XH_VERSION_MAJOR << 16) | (XH_VERSION_MINOR << 8) | (XH_VERSION_EXTRA)) 31 | 32 | #define XH_VERSION_TO_STR_HELPER(x) #x 33 | #define XH_VERSION_TO_STR(x) XH_VERSION_TO_STR_HELPER(x) 34 | 35 | #define XH_VERSION_STR XH_VERSION_TO_STR(XH_VERSION_MAJOR) "." \ 36 | XH_VERSION_TO_STR(XH_VERSION_MINOR) "." \ 37 | XH_VERSION_TO_STR(XH_VERSION_EXTRA) 38 | 39 | #if defined(__arm__) 40 | #define XH_VERSION_ARCH "arm" 41 | #elif defined(__aarch64__) 42 | #define XH_VERSION_ARCH "aarch64" 43 | #elif defined(__i386__) 44 | #define XH_VERSION_ARCH "x86" 45 | #elif defined(__x86_64__) 46 | #define XH_VERSION_ARCH "x86_64" 47 | #else 48 | #define XH_VERSION_ARCH "unknown" 49 | #endif 50 | 51 | #define XH_VERSION_STR_FULL "libxhook "XH_VERSION_STR" ("XH_VERSION_ARCH")" 52 | 53 | unsigned int xh_version() 54 | { 55 | return XH_VERSION; 56 | } 57 | 58 | const char *xh_version_str() 59 | { 60 | return XH_VERSION_STR; 61 | } 62 | 63 | const char *xh_version_str_full() 64 | { 65 | return XH_VERSION_STR_FULL; 66 | } 67 | -------------------------------------------------------------------------------- /jni/external/xhook/xh_version.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #ifndef XH_VERSION_H 25 | #define XH_VERSION_H 1 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | unsigned int xh_version(); 32 | 33 | const char *xh_version_str(); 34 | 35 | const char *xh_version_str_full(); 36 | 37 | #ifdef __cplusplus 38 | } 39 | #endif 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /jni/external/xhook/xhook.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #include "xh_core.h" 25 | #include "xhook.h" 26 | 27 | int xhook_register(const char *pathname_regex_str, const char *symbol, 28 | void *new_func, void **old_func) 29 | { 30 | return xh_core_register(pathname_regex_str, symbol, new_func, old_func); 31 | } 32 | 33 | int xhook_ignore(const char *pathname_regex_str, const char *symbol) 34 | { 35 | return xh_core_ignore(pathname_regex_str, symbol); 36 | } 37 | 38 | int xhook_refresh(int async) 39 | { 40 | return xh_core_refresh(async); 41 | } 42 | 43 | void xhook_clear() 44 | { 45 | return xh_core_clear(); 46 | } 47 | 48 | void xhook_enable_debug(int flag) 49 | { 50 | return xh_core_enable_debug(flag); 51 | } 52 | 53 | void xhook_enable_sigsegv_protection(int flag) 54 | { 55 | return xh_core_enable_sigsegv_protection(flag); 56 | } 57 | -------------------------------------------------------------------------------- /jni/external/xhook/xhook.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #ifndef XHOOK_H 25 | #define XHOOK_H 1 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | #define XHOOK_EXPORT __attribute__((visibility("default"))) 32 | 33 | int xhook_register(const char *pathname_regex_str, const char *symbol, 34 | void *new_func, void **old_func) XHOOK_EXPORT; 35 | 36 | int xhook_ignore(const char *pathname_regex_str, const char *symbol) XHOOK_EXPORT; 37 | 38 | int xhook_refresh(int async) XHOOK_EXPORT; 39 | 40 | void xhook_clear() XHOOK_EXPORT; 41 | 42 | void xhook_enable_debug(int flag) XHOOK_EXPORT; 43 | 44 | void xhook_enable_sigsegv_protection(int flag) XHOOK_EXPORT; 45 | 46 | #ifdef __cplusplus 47 | } 48 | #endif 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /jni/main/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | include $(CLEAR_VARS) 3 | 4 | LOCAL_MODULE := libriru_mipush_fake 5 | LOCAL_C_INCLUDES := \ 6 | $(LOCAL_PATH) \ 7 | jni/external/include 8 | LOCAL_CPPFLAGS += $(CPPFLAGS) 9 | LOCAL_STATIC_LIBRARIES := xhook 10 | LOCAL_LDLIBS += -ldl -llog 11 | LOCAL_LDFLAGS := -Wl 12 | 13 | LOCAL_SRC_FILES:= main.cpp hook.cpp misc.cpp riru.c 14 | 15 | include $(BUILD_SHARED_LIBRARY) -------------------------------------------------------------------------------- /jni/main/hook.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "riru.h" 16 | #include "logging.h" 17 | 18 | #define XHOOK_REGISTER(NAME) \ 19 | if (xhook_register(".*", #NAME, (void*) new_##NAME, (void **) &old_##NAME) != 0) \ 20 | LOGE("failed to register hook " #NAME "."); \ 21 | 22 | #define NEW_FUNC_DEF(ret, func, ...) \ 23 | static ret (*old_##func)(__VA_ARGS__); \ 24 | static ret new_##func(__VA_ARGS__) 25 | 26 | NEW_FUNC_DEF(int, __system_property_get, const char *key, char *value) { 27 | int res = old___system_property_get(key, value); 28 | if (key) { 29 | if (strcmp("ro.miui.ui.version.name", key) == 0) { 30 | strcpy(value, "V9"); 31 | //LOGI("system_property_get: %s -> %s", key, value); 32 | } else if (strcmp("ro.miui.ui.version.code", key) == 0) { 33 | strcpy(value, "7"); 34 | //LOGI("system_property_get: %s -> %s", key, value); 35 | } else if (strcmp("ro.miui.version.code_time", key) == 0) { 36 | strcpy(value, "1527550858"); 37 | //LOGI("system_property_get: %s -> %s", key, value); 38 | } else if (strcmp("ro.miui.internal.storage", key) == 0) { 39 | strcpy(value, "/sdcard/"); 40 | //LOGI("system_property_get: %s -> %s", key, value); 41 | } else if (strcmp("ro.product.manufacturer", key) == 0) { 42 | strcpy(value, "Xiaomi"); 43 | //LOGI("system_property_get: %s -> %s", key, value); 44 | } else if (strcmp("ro.product.brand", key) == 0) { 45 | strcpy(value, "Xiaomi"); 46 | //LOGI("system_property_get: %s -> %s", key, value); 47 | } else if (strcmp("ro.product.name", key) == 0) { 48 | strcpy(value, "Xiaomi"); 49 | //LOGI("system_property_get: %s -> %s", key, value); 50 | } 51 | 52 | } 53 | return res; 54 | } 55 | 56 | NEW_FUNC_DEF(std::string, _ZN7android4base11GetPropertyERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_, const std::string &key, const std::string &default_value) { 57 | std::string res = old__ZN7android4base11GetPropertyERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_(key, default_value); 58 | 59 | if (strcmp("ro.miui.ui.version.name", key.c_str()) == 0) { 60 | res = "V9"; 61 | //LOGI("android::base::GetProperty: %s -> %s", key.c_str(), res.c_str()); 62 | } else if (strcmp("ro.miui.ui.version.code", key.c_str()) == 0) { 63 | res = "7"; 64 | //LOGI("android::base::GetProperty: %s -> %s", key.c_str(), res.c_str()); 65 | } else if (strcmp("ro.miui.version.code_time", key.c_str()) == 0) { 66 | res = "1527550858"; 67 | //LOGI("android::base::GetProperty: %s -> %s", key.c_str(), res.c_str()); 68 | } else if (strcmp("ro.miui.internal.storage", key.c_str()) == 0) { 69 | res = "/sdcard/"; 70 | //LOGI("android::base::GetProperty: %s -> %s", key.c_str(), res.c_str()); 71 | } else if (strcmp("ro.product.manufacturer", key.c_str()) == 0) { 72 | res = "Xiaomi"; 73 | //LOGI("android::base::GetProperty: %s -> %s", key.c_str(), res.c_str()); 74 | } else if (strcmp("ro.product.brand", key.c_str()) == 0) { 75 | res = "Xiaomi"; 76 | //LOGI("android::base::GetProperty: %s -> %s", key.c_str(), res.c_str()); 77 | } else if (strcmp("ro.product.name", key.c_str()) == 0) { 78 | res = "Xiaomi"; 79 | //LOGI("android::base::GetProperty: %s -> %s", key.c_str(), res.c_str()); 80 | } 81 | return res; 82 | } 83 | 84 | void install_hook(const char *package_name, int user) { 85 | LOGI("install hook for %s (%d)", package_name, user); 86 | 87 | XHOOK_REGISTER(__system_property_get); 88 | 89 | char sdk[PROP_VALUE_MAX + 1]; 90 | int sdkLevel = 0; 91 | if (__system_property_get("ro.build.version.sdk", sdk) > 0 && (sdkLevel = atoi(sdk)) >= 28) 92 | XHOOK_REGISTER(_ZN7android4base11GetPropertyERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_); 93 | 94 | if (xhook_refresh(0) == 0) 95 | xhook_clear(); 96 | else 97 | LOGE("failed to refresh hook"); 98 | 99 | 100 | if (riru_get_version() >= 8) { 101 | void *f = riru_get_func("__system_property_get"); 102 | if (f != nullptr) old___system_property_get = (int (*)(const char *, char *)) f; 103 | riru_set_func("__system_property_get", (void *) new___system_property_get); 104 | if (sdkLevel >= 28) { 105 | f = riru_get_func("_ZN7android4base11GetPropertyERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_"); 106 | if (f != nullptr) old__ZN7android4base11GetPropertyERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_ = (std::string (*)(const std::string &, const std::string &)) f; 107 | riru_set_func("_ZN7android4base11GetPropertyERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_", 108 | (void *) new__ZN7android4base11GetPropertyERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_); 109 | } 110 | } 111 | 112 | } -------------------------------------------------------------------------------- /jni/main/hook.h: -------------------------------------------------------------------------------- 1 | #ifndef HOOK_H 2 | #define HOOK_H 3 | 4 | void install_hook(const char* package_name, int user); 5 | 6 | 7 | #endif // HOOK_H 8 | -------------------------------------------------------------------------------- /jni/main/logging.h: -------------------------------------------------------------------------------- 1 | #ifndef _LOGGING_H 2 | #define _LOGGING_H 3 | 4 | #include 5 | #include "android/log.h" 6 | 7 | #ifndef LOG_TAG 8 | #define LOG_TAG "MiPushFakeForRiru" 9 | #endif 10 | 11 | #ifdef DEBUG 12 | #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) 13 | #else 14 | #define LOGD(...) 15 | #endif 16 | #define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__) 17 | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) 18 | #define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__) 19 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) 20 | #define PLOGE(fmt, args...) LOGE(fmt " failed with %d: %s", ##args, errno, strerror(errno)) 21 | 22 | #endif // _LOGGING_H 23 | -------------------------------------------------------------------------------- /jni/main/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "logging.h" 16 | #include "hook.h" 17 | #include "misc.h" 18 | #include 19 | 20 | 21 | #define CONFIG_PATH "/data/misc/riru/modules/mipush_fake" 22 | 23 | #define FAKE_CONFIGURATION_GLOBAL "/data/misc/riru/modules/mipush_fake/packages/ALL" 24 | 25 | 26 | static char package_name[256]; 27 | static int uid; 28 | static int enable_hook; 29 | static std::vector blackList = {"com.google.android", 30 | "de.robv.android.xposed.installer", 31 | "com.xiaomi.xmsf", 32 | "com.tencent.mm", 33 | "top.trumeet.mipush"}; 34 | 35 | int is_app_need_hook(JNIEnv *env, jstring appDataDir) { 36 | if (!appDataDir) 37 | return 0; 38 | 39 | const char *app_data_dir = env->GetStringUTFChars(appDataDir, NULL); 40 | 41 | int user = 0; 42 | if (sscanf(app_data_dir, "/data/%*[^/]/%d/%s", &user, package_name) != 2) { 43 | if (sscanf(app_data_dir, "/data/%*[^/]/%s", package_name) != 1) { 44 | package_name[0] = '\0'; 45 | LOGW("can't parse %s", app_data_dir); 46 | return 0; 47 | } 48 | } 49 | 50 | env->ReleaseStringUTFChars(appDataDir, app_data_dir); 51 | 52 | std::string pkgName = package_name; 53 | for (auto &s : blackList) { 54 | if (pkgName.find(s) != std::string::npos) { 55 | return 0; 56 | } 57 | } 58 | 59 | 60 | if (access(FAKE_CONFIGURATION_GLOBAL, F_OK) == 0) { 61 | return 1; 62 | } 63 | 64 | if (access(CONFIG_PATH "/packages", R_OK) == 0) { 65 | char path[PATH_MAX]; 66 | snprintf(path, PATH_MAX, CONFIG_PATH "/packages/%d.%s", user, package_name); 67 | return access(path, F_OK) == 0; 68 | } 69 | return 0; 70 | } 71 | 72 | void load_config() { 73 | //empty 74 | } 75 | 76 | 77 | 78 | void injectBuild(JNIEnv *env) { 79 | if (env == 0) { 80 | LOGW("failed to inject android.os.Build for %s due to env is null", package_name); 81 | return; 82 | } 83 | LOGI("inject android.os.Build for %s ", package_name); 84 | 85 | jclass build_class = env->FindClass("android/os/Build"); 86 | if (build_class == 0) { 87 | LOGW("failed to inject android.os.Build for %s due to build is null", package_name); 88 | return; 89 | } 90 | 91 | jstring new_str = env->NewStringUTF("Xiaomi"); 92 | 93 | jfieldID brand_id = env->GetStaticFieldID(build_class, "BRAND", "Ljava/lang/String;"); 94 | if (brand_id != 0) { 95 | env->SetStaticObjectField(build_class, brand_id, new_str); 96 | } 97 | 98 | jfieldID manufacturer_id = env->GetStaticFieldID(build_class, "MANUFACTURER", "Ljava/lang/String;"); 99 | if (manufacturer_id != 0) { 100 | env->SetStaticObjectField(build_class, manufacturer_id, new_str); 101 | } 102 | 103 | jfieldID product_id = env->GetStaticFieldID(build_class, "PRODUCT", "Ljava/lang/String;"); 104 | if (product_id != 0) { 105 | env->SetStaticObjectField(build_class, product_id, new_str); 106 | } 107 | 108 | if(env->ExceptionCheck()) 109 | { 110 | env->ExceptionClear(); 111 | } 112 | 113 | env->DeleteLocalRef(new_str); 114 | 115 | } 116 | 117 | 118 | void nativeForkAndSpecialize(int res, int enable_hook, const char *package_name, jint uid) { 119 | if (res == 0 && enable_hook) { 120 | install_hook(package_name, uid / 100000); 121 | } 122 | } 123 | 124 | extern "C" { 125 | __attribute__((visibility("default"))) void nativeForkAndSpecializePre(JNIEnv *env, jclass clazz, 126 | jint _uid, jint gid, 127 | jintArray gids, 128 | jint runtime_flags, 129 | jobjectArray rlimits, 130 | jint _mount_external, 131 | jstring se_info, 132 | jstring se_name, 133 | jintArray fdsToClose, 134 | jintArray fdsToIgnore, 135 | jboolean is_child_zygote, 136 | jstring instructionSet, 137 | jstring appDataDir) { 138 | uid = _uid; 139 | enable_hook = is_app_need_hook(env, appDataDir); 140 | 141 | if (enable_hook) 142 | load_config(); 143 | } 144 | 145 | __attribute__((visibility("default"))) int nativeForkAndSpecializePost(JNIEnv *env, jclass clazz, 146 | jint res) { 147 | 148 | if (res == 0 && enable_hook) { 149 | injectBuild(env); 150 | } 151 | 152 | nativeForkAndSpecialize(res, enable_hook, package_name, uid); 153 | return !enable_hook; 154 | } 155 | 156 | 157 | } 158 | -------------------------------------------------------------------------------- /jni/main/misc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | ssize_t fdgets(char *buf, const size_t size, int fd) { 5 | ssize_t len = 0; 6 | buf[0] = '\0'; 7 | while (len < size - 1) { 8 | ssize_t ret = read(fd, buf + len, 1); 9 | if (ret < 0) 10 | return -1; 11 | if (ret == 0) 12 | break; 13 | if (buf[len] == '\0' || buf[len++] == '\n') { 14 | break; 15 | } 16 | } 17 | buf[len] = '\0'; 18 | buf[size - 1] = '\0'; 19 | return len; 20 | } 21 | -------------------------------------------------------------------------------- /jni/main/misc.h: -------------------------------------------------------------------------------- 1 | #ifndef MISC_H 2 | #define MISC_H 3 | 4 | #include 5 | 6 | ssize_t fdgets(char *buf, const size_t size, int fd); 7 | 8 | #endif // MISC_H 9 | -------------------------------------------------------------------------------- /jni/main/riru.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #ifdef __LP64__ 6 | #define LIB "/system/lib64/libmemtrack.so" 7 | #else 8 | #define LIB "/system/lib/libmemtrack.so" 9 | #endif 10 | 11 | static void *riru_handle; 12 | static char *riru_module_name; 13 | 14 | static void *get_handle() { 15 | if (riru_handle == NULL) 16 | riru_handle = dlopen(LIB, RTLD_NOW | RTLD_GLOBAL); 17 | 18 | return riru_handle; 19 | } 20 | 21 | const char *riru_get_module_name() { 22 | return riru_module_name; 23 | } 24 | 25 | void riru_set_module_name(const char *name) { 26 | riru_module_name = strdup(name); 27 | } 28 | 29 | int riru_get_version() { 30 | static void **sym; 31 | void *handle; 32 | if ((handle = get_handle()) == NULL) return -1; 33 | if (sym == NULL) sym = dlsym(handle, "riru_get_version"); 34 | if (sym) return ((int (*)()) sym)(); 35 | return -1; 36 | } 37 | 38 | void *riru_get_func(const char *name) { 39 | static void **sym; 40 | void *handle; 41 | if ((handle = get_handle()) == NULL) return NULL; 42 | if (sym == NULL) sym = dlsym(handle, "riru_get_func"); 43 | if (sym) return ((void *(*)(const char *, const char *)) sym)(riru_get_module_name(), name); 44 | return NULL; 45 | } 46 | 47 | void *riru_get_native_method_func(const char *className, const char *name, const char *signature) { 48 | static void **sym; 49 | void *handle; 50 | if ((handle = get_handle()) == NULL) return NULL; 51 | if (sym == NULL) sym = dlsym(handle, "riru_get_native_method_func"); 52 | if (sym) 53 | return ((void *(*)(const char *, const char *, const char *, const char *)) sym)( 54 | riru_get_module_name(), className, name, signature); 55 | return NULL; 56 | } 57 | 58 | void riru_set_func(const char *name, void *func) { 59 | static void **sym; 60 | void *handle; 61 | if ((handle = get_handle()) == NULL) return; 62 | if (sym == NULL) sym = dlsym(handle, "riru_set_func"); 63 | if (sym) 64 | ((void *(*)(const char *, const char *, void *)) sym)(riru_get_module_name(), name, func); 65 | } 66 | 67 | void riru_set_native_method_func(const char *className, const char *name, const char *signature, 68 | void *func) { 69 | static void **sym; 70 | void *handle; 71 | if ((handle = get_handle()) == NULL) return; 72 | if (sym == NULL) sym = dlsym(handle, "riru_set_native_method_func"); 73 | if (sym) 74 | ((void *(*)(const char *, const char *, const char *, const char *, void *)) sym)( 75 | riru_get_module_name(), className, name, signature, func); 76 | } -------------------------------------------------------------------------------- /jni/main/riru.h: -------------------------------------------------------------------------------- 1 | #ifndef RIRU_H 2 | #define RIRU_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | __attribute__((visibility("default"))) void riru_set_module_name(const char *name); 8 | 9 | /** 10 | * Get Riru version. 11 | * 12 | * @return Riru version 13 | */ 14 | int riru_get_version(); 15 | 16 | /* 17 | * Get new_func address from last module which hook func. 18 | * Use this as your old_func if you want to hook func. 19 | * 20 | * @param name a unique name 21 | * @return new_func from last module or null 22 | */ 23 | void *riru_get_func(const char *name); 24 | 25 | /* 26 | * Java native version of riru_get_func. 27 | * 28 | * @param className class name 29 | * @param name method name 30 | * @param signature method signature 31 | * @return new_func address from last module or original address 32 | */ 33 | void *riru_get_native_method_func(const char *className, const char *name, const char *signature); 34 | 35 | /* 36 | * Set new_func address for next module which wants to hook func. 37 | * 38 | * @param name a unique name 39 | * @param func your new_func address 40 | */ 41 | void riru_set_func(const char *name, void *func); 42 | 43 | /* 44 | * Java native method version of riru_set_func. 45 | * 46 | * @param className class name 47 | * @param name method name 48 | * @param signature method signature 49 | * @param func your new_func address 50 | */ 51 | void riru_set_native_method_func(const char *className, const char *name, const char *signature, 52 | void *func); 53 | #ifdef __cplusplus 54 | } 55 | #endif 56 | 57 | #endif -------------------------------------------------------------------------------- /src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /template_override/common/service.sh: -------------------------------------------------------------------------------- 1 | #!/system/bin/sh 2 | # Please don't hardcode /magisk/modname/... ; instead, please use $MODDIR/... 3 | # This will make your scripts compatible even if Magisk change its mount point in the future 4 | MODDIR=${0%/*} 5 | 6 | # This script will be executed in late_start service mode 7 | # More info in the main Magisk thread 8 | -------------------------------------------------------------------------------- /template_override/common/system.prop: -------------------------------------------------------------------------------- 1 | # This file will be read by resetprop 2 | # Example: Change dpi 3 | # ro.sf.lcd_density=320 4 | -------------------------------------------------------------------------------- /template_override/config.sh: -------------------------------------------------------------------------------- 1 | ########################################################################################## 2 | # 3 | # Magisk Module Template Config Script 4 | # by topjohnwu 5 | # 6 | ########################################################################################## 7 | ########################################################################################## 8 | # 9 | # Instructions: 10 | # 11 | # 1. Place your files into system folder (delete the placeholder file) 12 | # 2. Fill in your module's info into module.prop 13 | # 3. Configure the settings in this file (config.sh) 14 | # 4. If you need boot scripts, add them into common/post-fs-data.sh or common/service.sh 15 | # 5. Add your additional or modified system properties into common/system.prop 16 | # 17 | ########################################################################################## 18 | 19 | ########################################################################################## 20 | # Configs 21 | ########################################################################################## 22 | 23 | # Set to true if you need to enable Magic Mount 24 | # Most mods would like it to be enabled 25 | AUTOMOUNT=true 26 | 27 | # Set to true if you need to load system.prop 28 | PROPFILE=true 29 | 30 | # Set to true if you need post-fs-data script 31 | POSTFSDATA=false 32 | 33 | # Set to true if you need late_start service script 34 | LATESTARTSERVICE=false 35 | 36 | ########################################################################################## 37 | # Installation Message 38 | ########################################################################################## 39 | 40 | # Set what you want to show when installing your mod 41 | 42 | print_modname() { 43 | ui_print "********************************" 44 | ui_print "Riru - MiPush Fake " 45 | ui_print "********************************" 46 | } 47 | 48 | ########################################################################################## 49 | # Replace list 50 | ########################################################################################## 51 | 52 | # List all directories you want to directly replace in the system 53 | # Check the documentations for more info about how Magic Mount works, and why you need this 54 | 55 | # This is an example 56 | REPLACE=" 57 | /system/app/Youtube 58 | /system/priv-app/SystemUI 59 | /system/priv-app/Settings 60 | /system/framework 61 | " 62 | 63 | # Construct your own list here, it will override the example above 64 | # !DO NOT! remove this if you don't need to replace anything, leave it empty as it is now 65 | REPLACE=" 66 | " 67 | 68 | ########################################################################################## 69 | # Permissions 70 | ########################################################################################## 71 | 72 | set_permissions() { 73 | # Only some special files require specific permissions 74 | # The default permissions should be good enough for most cases 75 | 76 | # Here are some examples for the set_perm functions: 77 | 78 | # set_perm_recursive (default: u:object_r:system_file:s0) 79 | # set_perm_recursive $MODPATH/system/lib 0 0 0755 0644 80 | 81 | # set_perm (default: u:object_r:system_file:s0) 82 | # set_perm $MODPATH/system/bin/app_process32 0 2000 0755 u:object_r:zygote_exec:s0 83 | # set_perm $MODPATH/system/bin/dex2oat 0 2000 0755 u:object_r:dex2oat_exec:s0 84 | # set_perm $MODPATH/system/lib/libart.so 0 0 0644 85 | 86 | # The following is default permissions, DO NOT remove 87 | set_perm_recursive $MODPATH 0 0 0755 0644 88 | } 89 | 90 | ########################################################################################## 91 | # Custom Functions 92 | ########################################################################################## 93 | 94 | # This file (config.sh) will be sourced by the main flash script after util_functions.sh 95 | # If you need custom logic, please add them here as functions, and call these functions in 96 | # update-binary. Refrain from adding code directly into update-binary, as it will make it 97 | # difficult for you to migrate your modules to newer template versions. 98 | # Make update-binary as clean as possible, try to only do function calls in it. 99 | fail() { 100 | echo "$1" 101 | exit 1 102 | } 103 | 104 | check_architecture() { 105 | if [[ "$ARCH" != "arm" && "$ARCH" != "arm64" ]]; then 106 | ui_print "- Unsupported platform: $ARCH" 107 | exit 1 108 | else 109 | ui_print "- Device platform: $ARCH" 110 | fi 111 | } 112 | 113 | copy_files() { 114 | if [ $IS64BIT = false ]; then 115 | ui_print "- Removing unnecessary files" 116 | rm -rf "$MODPATH/system/lib64" 117 | fi 118 | 119 | 120 | ui_print "- Extracting extra files" 121 | unzip -o "$ZIP" 'data/*' -d $MODPATH >&2 122 | 123 | TARGET="/data/misc/riru/modules" 124 | 125 | [ -d $TARGET ] || mkdir -p $TARGET || fail "- Can't mkdir -p $TARGET" 126 | cp -af "$MODPATH$TARGET/." "$TARGET" || fail "- Can't cp -af $MODPATH$TARGET/. $TARGET" 127 | 128 | rm -rf $MODPATH/data 2>/dev/null 129 | 130 | ui_print "- Files copied" 131 | } -------------------------------------------------------------------------------- /template_override/module.prop: -------------------------------------------------------------------------------- 1 | id=mipush_fake 2 | name=Riru - MiPushFakeModule 3 | version=v10 4 | versionCode=10 5 | author=Timothy 6 | description=Fake as XiaoMI device by hook system_property_get. Require Riru - Core installed. 7 | minMagisk=17000 8 | -------------------------------------------------------------------------------- /template_override/riru_module.prop: -------------------------------------------------------------------------------- 1 | name=Riru - MiPushFakeModule 2 | version=v10 3 | versionCode=10 4 | author=Timothy 5 | description=Fake as XiaoMI device by hook system_property_get. Require Riru-Core v9+ installed. 6 | --------------------------------------------------------------------------------