├── .gitignore ├── GlossHook ├── include │ └── Gloss.h └── lib │ ├── ARM │ ├── libGlossHook.a │ └── libGlossHook.so │ └── ARM64 │ ├── libGlossHook.a │ └── libGlossHook.so ├── LICENSE ├── README.md └── examples └── GlossHookExample ├── Android.mk ├── Application.mk └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | .so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | .a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app -------------------------------------------------------------------------------- /GlossHook/include/Gloss.h: -------------------------------------------------------------------------------- 1 | #ifndef GLOSSHOOK_H 2 | #define GLOSSHOOK_H 3 | 4 | #ifndef __ANDROID__ 5 | #error GlossHook only support android 6 | #else 7 | #if !(defined __arm__) && !(defined __aarch64__) 8 | #error GlossHook only support arm and arm64 9 | #endif 10 | #endif 11 | 12 | #if (defined __clang__) || (defined __GNUC__) 13 | #define GLOSS_API __attribute__((visibility("default"))) 14 | #else 15 | #define GLOSS_API 16 | #endif 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | #ifdef __arm__ 27 | #define GET_INST_SET(addr) (addr & 1 ? i_set::I_THUMB : i_set::I_ARM) // check addr is arm or thumb (arm: addr thumb: addr + 1) 28 | #endif 29 | 30 | typedef enum { I_NONE = 0, I_THUMB, I_ARM, I_ARM64 } i_set; // inst mode 31 | 32 | typedef void* GHandle; // library handle 33 | 34 | typedef void* GHook; // hook handle 35 | 36 | typedef struct PermissionFlags // memory permission 37 | { 38 | bool bRead : 1; 39 | bool bWrite : 1; 40 | bool bExecute : 1; 41 | bool bPrivate : 1; 42 | bool bShared : 1; 43 | bool align : 3; 44 | } p_flag; 45 | 46 | // register patch 47 | typedef struct GlossRegister 48 | { 49 | // pc register cannot be changed, only read 50 | // x18 register is occupied by a jump instruction, cannot be changed 51 | #ifdef __arm__ 52 | enum e_reg { R0 = 0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, FP = R11, R12, IP = R12, R13, SP = R13, R14, LR = R14, R15, PC = R15, CPSR, MAX_REG }; 53 | 54 | union { 55 | uint32_t r[MAX_REG]; 56 | struct { uint32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, sp, lr, pc, cpsr; } regs; 57 | }; 58 | #elif __aarch64__ 59 | enum e_reg { 60 | X0 = 0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, FP = X29, 61 | X30, LR = X30, X31, SP = X31, PC, CPSR, MAX_REG, 62 | Q0 = X0, Q1 = X1, Q2 = X2, Q3 = X3, Q4 = X4, Q5 = X5, Q6 = X6, Q7 = X7, Q8 = X8, Q9 = X9, Q10 = X10, Q11 = X11, Q12 = X12, Q13 = X13, Q14 = X14, Q15 = X15, 63 | Q16 = X16, Q17 = X17, Q18 = X18, Q19 = X19, Q20 = X20, Q21 = X21, Q22 = X22, Q23 = X23, Q24 = X24, Q25 = X25, Q26 = X26, Q27 = X27, Q28 = X28, Q29 = X29, Q30 = X30, Q31 = X31, 64 | MAX_Q_REG 65 | }; 66 | 67 | typedef union { 68 | __uint128_t q; 69 | double d[2]; 70 | float f[4]; 71 | } __qreg; 72 | 73 | typedef union { 74 | uint64_t x; 75 | uint32_t w[2]; 76 | } __xreg; 77 | 78 | union { 79 | struct { 80 | __uint128_t q[MAX_Q_REG]; 81 | uint64_t x[MAX_REG]; 82 | } r; 83 | 84 | struct { 85 | __qreg q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12, q13, q14, q15, q16, q17, q18, q19, q20, q21, q22, q23, q24, q25, q26, q27, q28, q29, q30, q31; 86 | __xreg x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29; 87 | __xreg lr, sp; uint64_t pc, cpsr; 88 | } regs; 89 | }; 90 | #endif 91 | } gloss_reg; 92 | 93 | // Enable/Disable GlossHook log 94 | // Default: false (disable) 95 | // Tag: GlossHook 96 | GLOSS_API void GlossEnableLog(bool enable); 97 | 98 | // ******************************************************* Library API ****************************************************************************** 99 | // 100 | // Gloss library module api uses xdl library to implement, 101 | // because the dl library provided by the linker (dl) series functions have some problems. (such as Android 7.0+ linker namespace) 102 | // More see: https://github.com/hexhacking/xDL (MIT License) 103 | // 104 | // About { load_bias }: 105 | // { load_bias } is the starting address of the executable file or dynamic shared library in memory. 106 | // { load_bias } has many names, such as: OffsetAddr, BaseAddr, LoadBase, ImageBase, etc. 107 | // { load_bias } is a naming convention used by Google Android source code, We use this naming convention here. (or abbreviated as bias) 108 | // { load_bias } is not the address of the first loaded program header of the dynamic library. 109 | // According to the Android source code, the initial address at which the dynamic library is first loaded into memory is defined as: { load_start }. 110 | // { load_start } and { load_bias } are different only in Android 8.0 and above. 111 | // For Android 7.0 and below, { load_bias } and { load_start } are the same. 112 | // For Android 8.0 and above, if a dynamic library (elf) has a program header (segment) of type PT_LOAD with a p_paddr field of 0, 113 | // then { load_bias } and { load_start } are the same, 114 | // otherwise, { load_bias } and { load_start } are not equal, for example, the arm64 version of { libart.so } in Android 8.0/9.0. 115 | // Since most methods to obtain { load_bias } do not handle and distinguish { load_bias } and { load_start }, 116 | // so using them to obtain { load_bias } will get the wrong { load_bias }. 117 | // Therefore, it is recommended to use GlossAPI or use xdl library to obtain { load_bias }. 118 | // 119 | 120 | /* 121 | * GlossFindLibMapping - Find the memory mapping info of the library in the process. (proc/{pid}/maps or /proc/self/maps) 122 | * 123 | * @param lib_name - The library name (or path name) to find. (Cannot use NULL) 124 | * @param pid - The process id to search. (-1 for current process, pid_t for other process) 125 | * @param lib_path - The library path to store. (Can be NULL) 126 | * @param lib_mem_len - The library memory length to store. (Can be NULL) 127 | * @return The memory mapping address (load_bias) of the library. (failed: 0) 128 | */ 129 | GLOSS_API uintptr_t GlossFindLibMapping(const char* lib_name, pid_t pid, char* lib_path, size_t* lib_mem_len); 130 | 131 | /* 132 | * GlossOpen - Open the library and get the handle. (use xdl) 133 | * 134 | * @note: It is similar to { dlopen }. But the handle returned by GlossOpen cannot be closed using { dlclose }. 135 | * If the library has not been loaded into memory, GlossOpen will call { dlopen } to load the library, and then call xdl_open to open the library. 136 | * I recommend using GlossOpen in most cases. If the library is first loaded and GlossOpen fails, you can use { dlopen } to load the library. 137 | * 138 | * @param lib_name - The library name (or path name) to open. (Cannot use NULL) 139 | * @return The handle of the library. (failed: NULL) 140 | */ 141 | GLOSS_API GHandle GlossOpen(const char* lib_name); 142 | 143 | /* 144 | * GlossClose - Close the library and release the handle, from GlossOpen. (use xdl) 145 | * 146 | * @note: It is similar to { dlclose }. But the handle returned by { dlopen } cannot be closed using GlossClose. 147 | * If GlossOpen uses { dlopen } to load the library, set is_dlclose to true to call { dlclose } to close the library. 148 | * You can check the logs of GlossOpen to see if it uses { dlopen } to load the library. 149 | * 150 | * @param handle - The handle of the library to close. (Cannot use NULL) 151 | * @param is_dlclose - Whether to use dlclose to close the library. (default: false, use dlclose: true) 152 | * @return 0 if success, -1 if failed. (or return value of dlclose) 153 | */ 154 | GLOSS_API int GlossClose(GHandle handle, bool is_dlclose); 155 | 156 | /* 157 | * GlossGetLibBias - Get the load_bias of the library in the process. (use xdl) 158 | * 159 | * @param lib_name - The library name (or path name) to find. (Cannot use NULL) 160 | * @return The memory mapping address (load_bias) of the library. (failed: 0) 161 | */ 162 | GLOSS_API uintptr_t GlossGetLibBias(const char* lib_name); 163 | 164 | /* 165 | * GlossGetLibBiasEx - Get the load_bias of the library in the process. (use xdl) 166 | * 167 | * @param handle - The handle (GlossOpen) of the library to get the load_bias. (Cannot use NULL) 168 | * @return The memory mapping address (load_bias) of the library. (failed: 0) 169 | */ 170 | GLOSS_API uintptr_t GlossGetLibBiasEx(GHandle handle); 171 | 172 | /* 173 | * GlossGetLibPath - Get the path of the library in the process. (use xdl) 174 | * 175 | * @param handle - The handle (GlossOpen) of the library to get the path. (Cannot use NULL) 176 | * @return The library path of the library. (failed: NULL) 177 | */ 178 | GLOSS_API const char* GlossGetLibPath(GHandle handle); 179 | 180 | /* 181 | * GlossGetLibPathEx - Find the dynamic library in which the address is located and get the library path. (use xdl) 182 | * 183 | * @param lib_addr - The address to get the path. (Cannot use 0) 184 | * @param path - The library path to store. (Cannot use NULL) 185 | * @return True if success, false if failed. 186 | */ 187 | GLOSS_API bool GlossGetLibPathEx(uintptr_t lib_addr, char* path); 188 | 189 | /* 190 | * GlossGetLibFileSize - Get the file size of the library. (use xdl) 191 | * 192 | * @param handle - The handle (GlossOpen) of the library to get the file size. (Cannot use NULL) 193 | * @return The file size of the library. (failed: 0) 194 | */ 195 | GLOSS_API size_t GlossGetLibFileSize(GHandle handle); 196 | 197 | /* 198 | * GlossSymbol - find the symbol address or symbol szie (function code bytes) in the library. (use xdl) 199 | * 200 | * @note: This function is similar to { dlsym }, but it can query "debuging symbols" and obtain the function size (in bytes) at the symbol address. 201 | * GlossSymbol first tries to find "dynamic link symbols" (dlsym), if not found, it will try to find "debuging symbols". 202 | * 203 | * @param handle - The handle (GlossOpen) of the library to find the symbol. (Cannot use NULL) 204 | * @param symbol - The symbol name to find. (Cannot use NULL) 205 | * @param sym_size - The symbol (function) memory size to store. (can be NULL) 206 | * @return The symbol address. (failed: 0) 207 | */ 208 | GLOSS_API uintptr_t GlossSymbol(GHandle handle, const char* symbol, size_t* sym_size); 209 | 210 | /* 211 | * GlossSymbolEx - Find the dynamic library in which the address is located and find the symbol address or symbol size (function code bytes). (use xdl) 212 | * 213 | * @note: see GlossSymbol. 214 | * 215 | * @param lib_addr - The address to find the symbol. (Cannot use 0) 216 | * @param symbol - The symbol name to find. (Cannot use NULL) 217 | * @param sym_size - The symbol (function) memory size to store. (can be NULL) 218 | * @return The symbol address. (failed: 0) 219 | */ 220 | GLOSS_API uintptr_t GlossSymbolEx(uintptr_t lib_addr, const char* symbol, size_t* sym_size); 221 | 222 | /* 223 | * GlossGot - Get the GOT address of the symbol. (use xdl) 224 | * 225 | * @note: This function is used to obtain the GOT address of the symbol. 226 | * 227 | * @param handle - The handle (GlossOpen) of the library to find the GOT address. (Cannot use NULL) 228 | * @param symbol - The symbol name to find. (Cannot use NULL) 229 | * @param addr_list - The GOT address list to store. (Cannot use NULL) (Need to manually free memory, e.g. free(addr_list)) 230 | * @param addr_list_size - The GOT address list size to store. (Cannot use NULL) 231 | * @return True if success, false if failed. 232 | */ 233 | GLOSS_API bool GlossGot(GHandle handle, const char* symbol, uintptr_t** addr_list, size_t* addr_list_size); 234 | 235 | /* 236 | * GlossAddr - Find symbol information of the address, including symbol name, size, and func address. (use xdl) 237 | * 238 | * @note: This function is similar to { dladdr }, Find which function the address is located in, and get the function name and size. 239 | * 240 | * @param lib_addr - The address to find the symbol. (Cannot use 0) 241 | * @param sym_addr - The symbol address to store. (Can be NULL) 242 | * @param sym_size - The symbol size (function code bytes) to store. (Can be NULL) 243 | * @param sym_name - The symbol name to store. (Can be NULL) 244 | * @return True if success, false if failed. 245 | */ 246 | GLOSS_API bool GlossAddr(uintptr_t lib_addr, uintptr_t* sym_addr, size_t* sym_size, char* sym_name); 247 | 248 | /* 249 | * GlossGetLibEntry - Get the entry point (.text section start address) of the library. 250 | * 251 | * @param handle - The handle (GlossOpen) of the library to get the entry point. (Cannot use NULL) 252 | * @return The entry address of the library. (failed: 0) 253 | */ 254 | GLOSS_API uintptr_t GlossGetLibEntry(GHandle handle); 255 | 256 | /* 257 | * GlossGetLibSection - Get the section address and size of the library. 258 | * 259 | * @note: Libraries must be loaded into memory. 260 | * 261 | * @param lib_name - The library name (or path name) to find. (Cannot use NULL) 262 | * @param sec_name - The section name to find. (Can use NULL, default: ".text") (e.g. ".text", ".data", ".bss") 263 | * @param sec_size - The section size to store. (Can be NULL) 264 | * @return The section address. (failed: 0) 265 | */ 266 | GLOSS_API uintptr_t GlossGetLibSection(const char* lib_name, const char* sec_name, size_t* sec_size); 267 | 268 | /* 269 | * GlossGetLibSegment - Get the segment (phdr) address and size of the library. 270 | * 271 | * @note: Libraries must be loaded into memory. 272 | * 273 | * @param lib_name - The library name (or path name) to find. (Cannot use NULL) 274 | * @param seg_id - The segment id to find. (0 for the first segment, 1 for the second segment, etc.) 275 | * @param seg_type - The segment type to store. (Can be NULL) (e.g. PT_LOAD, PT_DYNAMIC, PT_TLS #include ) 276 | * @param seg_size - The segment size to store. (Can be NULL) 277 | * @return The segment address. (failed: 0) 278 | */ 279 | GLOSS_API uintptr_t GlossGetLibSegment(const char* lib_name, uint16_t seg_id, uint32_t* seg_type, size_t* seg_size); 280 | 281 | 282 | // ******************************************************* Memory operation API ************************************************************************** 283 | // 284 | /* 285 | * SetMemoryPermission - Set the memory permission of the address. 286 | * 287 | * @param addr - The address to set the permission. (Cannot use 0) 288 | * @param len - The length of the memory to set the permission. (Cannot use 0) 289 | * @param type - The permission type to set, see p_flag. (Can be NULL, default: { bRead:true, bWrite:true, bExecute:true } ) 290 | * @return True if success, false if failed. 291 | */ 292 | GLOSS_API bool SetMemoryPermission(uintptr_t addr, size_t len, p_flag* type); 293 | /* 294 | * Unprotect - Just set the memory permission to { bRead:true, bWrite:true, bExecute:true } 295 | * see SetMemoryPermission. 296 | */ 297 | inline bool Unprotect(uintptr_t addr, size_t len) 298 | { 299 | return SetMemoryPermission(addr, len, NULL); 300 | } 301 | 302 | /* 303 | * GetMemoryPermission - Get the memory permission of the address. (proc/pid/maps or /proc/self/maps) 304 | * 305 | * @param addr - The address to get the permission. (Cannot use 0) 306 | * @param type - The permission type to store, see p_flag. (Cannot use NULL) 307 | * @param pid - The process id to get the permission. (-1 for current process, pid_t for other process) 308 | * @param lib_name - The library name (path name) to get the permission. (can be NULL) 309 | * @return True if success, false if failed. 310 | */ 311 | GLOSS_API bool GetMemoryPermission(uintptr_t addr, p_flag* type, pid_t pid, const char* lib_name); 312 | /* 313 | * IsAddrExecute - Check if the address is executable. 314 | * see GetMemoryPermission. 315 | */ 316 | inline bool IsAddrExecute(uintptr_t addr) 317 | { 318 | p_flag type = { 0,0,0,0,0,0 }; 319 | GetMemoryPermission(addr, &type, -1, NULL); 320 | return type.bExecute; 321 | } 322 | 323 | /* 324 | * WriteMemory - Write data to the address. (atomic write) 325 | * 326 | * @param addr - The address to write the data. (Cannot use NULL) 327 | * @param data - The data to write. (Cannot use NULL) 328 | * @param size - The size of the data to write. (Cannot use 0) 329 | * @param vp - Whether to use virtual protect to change the memory permission before writing the data. (true: unprotect, false: protect) 330 | */ 331 | GLOSS_API void WriteMemory(void* addr, void* data, size_t size, bool vp); 332 | 333 | /* 334 | * ReadMemory - Read data from the address. (atomic read) 335 | * 336 | * @param addr - The address to read the data. (Cannot use NULL) 337 | * @param data - The data to store. (Can be NULL) 338 | * @param size - The size of the data to read. (Cannot use 0) 339 | * @param vp - Whether to use virtual protect to change the memory permission before reading the data. (true: unprotect, false: protect) 340 | * @return The data read. (if data is NULL, return malloc allocated data, need to free it by yourself) 341 | */ 342 | GLOSS_API void* ReadMemory(void* addr, void* data, size_t size, bool vp); 343 | 344 | /* 345 | * MemoryFill - Fill the memory with the value. 346 | * 347 | * @param addr - The address to fill the memory. (Cannot use NULL) 348 | * @param value - The value to fill. 349 | * @param size - The size of the memory to fill. (Cannot use 0) 350 | * @param vp - Whether to use virtual protect to change the memory permission before filling the memory. (true: unprotect, false: protect) 351 | */ 352 | GLOSS_API void MemoryFill(void* addr, uint8_t value, size_t size, bool vp); 353 | 354 | 355 | // ******************************************************* Hook API ******************************************************************************** 356 | // 357 | /* 358 | * GlossInit - Initialize the GlossHook library, Can be re-initialized multiple times. 359 | * 360 | * @param is_init_linker - Whether to initialize the linker. (AutoEnabled(Default): false) 361 | */ 362 | GLOSS_API void GlossInit(bool is_init_linker); 363 | // 364 | // GlossHook some notes: 365 | // 366 | // 1. About { GlossInit } 367 | // { GlossHook } needs to call the { GlossInit } function once at program startup, which is usually called automatically. 368 | // If the parameter is false, it will allocate some memory. This is necessary; otherwise, GlossHook will not function. 369 | // If the parameter is true, it will additionally initialize the linker functionality, obtain linker symbols, and hook linker functions. 370 | // Can be initialized multiple times, but only the first time is effective. 371 | // In some scenarios, you can manually call it to make your hook effective. 372 | // For example code: 373 | // 374 | // __attribute__((constructor)) void my_entry_func() 375 | // { 376 | // GlossInit(true); // call GlossInit at program startup 377 | // 378 | // // your code here 379 | // } 380 | // 381 | // { GlossHook } automatic initialization occurs in the constructor attribute function, 382 | // If you use { GlossHook } in the constructor attribute function, you need to call GlossInit to pre-initialize. 383 | // (The constructor attribute function is called in a random order.) 384 | // 385 | // 386 | // 2. About { new_func } and { old_func } 387 | // Taking the function { GlossHook } as an example, { new_func } is the new function after being hooked, 388 | // and { old_func } is the old function before being hooked. 389 | // { new_func } is also known as { my_func, hook_func, proxy_func, inject_func }. 390 | // { old_func } is also known as { prev_func, call_func }, but it is not { orig_func }, because it may be a hooked function, not the original function. 391 | // ( Only the first time hooking, { old_func } is { orig_func } ) 392 | // 393 | // Hook { malloc } example code: 394 | // 395 | // void* (*old_malloc)(size_t size) = nullptr; // old_func to store 396 | // void* my_malloc(size_t size) // new_func 397 | // { 398 | // // your code here 399 | // 400 | // return old_malloc(size); // call old_func 401 | // } 402 | // 403 | // GlossHook((void*)malloc, (void*)my_malloc, (void**)&old_malloc); // hook malloc 404 | // 405 | // 406 | // 3. About re-entry problem of hook function 407 | // As an example, let's consider the hook function of malloc, If my_malloc(new_func) calls malloc again, my_malloc will enter a loop and cause a crash. 408 | // In addition, if my_malloc calls other functions that call malloc, it will also cause a re-entry. 409 | // The re-entry problem can be difficult to locate, because the cause of the crash is random, 410 | // and it may be a memory access error or a function call stack overflow. 411 | // When the re-entry occurs in a very large function call chain, it is difficult to locate the specific position. 412 | // Crash code: 413 | // 414 | // void* (*old_malloc)(size_t size); // old_func to store 415 | // void* my_malloc(size_t size) // new_func 416 | // { 417 | // // your code here 418 | // 419 | // void* p = malloc(size); // call malloc, my_malloc will be re-entered, and cause crash 420 | // 421 | // // your code here 422 | // 423 | // strdup("test"); // strdup call malloc, my_malloc will be re-entered, and cause crash 424 | // 425 | // // your code here 426 | // 427 | // return old_malloc(size); // call old_func, It will not re-enter because it is the old function returned by the hook 428 | // } 429 | // 430 | // GlossHook((void*)malloc, (void*)my_malloc, (void**)&old_malloc); // hook malloc 431 | // 432 | // To avoid re-entry, it is recommended to avoid calling functions that may cause re-entry. 433 | // In some scenarios, we may have to use re-entry functions, and to solve this problem, we can add some additional code: 434 | // 435 | // #include 436 | // 437 | // static pthread_key_t in_hook_key; 438 | // 439 | // void* (*old_malloc)(size_t size); // old_func to store 440 | // void* my_malloc(size_t size) // new_func 441 | // { 442 | // void* flag = pthread_getspecific(in_hook_key); // check if in hook 443 | // if (flag == nullptr) 444 | // { 445 | // pthread_setspecific(in_hook_key, (void*)1); // set in hook flag 446 | // 447 | // void* p = malloc(size); // call malloc, it will not re-enter 448 | // 449 | // // your code here 450 | // 451 | // strdup("test"); // strdup call malloc, it will not re-enter 452 | // 453 | // // your code here 454 | // 455 | // pthread_setspecific(in_hook_key, nullptr); // clear in hook flag 456 | // } 457 | // return old_malloc(size); // call old_func, if in the hook, directly callback the old function to avoid re-entry 458 | // } 459 | // 460 | // GlossHook((void*)malloc, (void*)my_malloc, (void**)&old_malloc); // hook malloc 461 | // 462 | // The above code should solve the re-entry problem, 463 | // and there are other methods to solve the re-entry problem, such as using a bool variable to check the hook status, or use atomic variables. 464 | // GlossHook also provides a solution: 465 | // 466 | // GHook hook_handle = nullptr; // hook handle 467 | // void* (*old_malloc)(size_t size); // old_func to store 468 | // void* my_malloc(size_t size) // new_func 469 | // { 470 | // static void* (*orig_malloc)(size_t size) = (void* (*)(size_t))GlossHookGetOriglFunc(hook_handle); // original malloc function 471 | // 472 | // // your code here 473 | // 474 | // void* p = orig_malloc(size); // call orig_malloc, skip hook if in the my_malloc, will not re-enter 475 | // 476 | // // your code here 477 | // 478 | // // strdup("test"); // not support, will cause crash 479 | // 480 | // // your code here 481 | // 482 | // return old_malloc(size); // call old_func, It will not re-enter because it is the old function returned by the hook 483 | // } 484 | // 485 | // hook_handle = GlossHook((void*)malloc, (void*)my_malloc, (void**)&old_malloc); // hook malloc, get hook handle 486 | // 487 | // However, it only applies to the case where the hook function is called directly, 488 | // and the case where other functions are called still causes re-entry. 489 | // 490 | // 491 | 492 | /* 493 | * GlossHookAddTrampolines - Add trampolines memory to the library. 494 | * 495 | * @note: This function is used to add trampolines to the library, it can be used to solve the problem of limited jump range for 4-byte hooks. 496 | * 497 | * B/BL/BLX instructions have jump range limitations. GlossHook will allocate free memory within the range of the shared object (SO) to create a trampoline. 498 | * The nearby memory space of the SO is limited, To avoid reaching the automatic memory allocation limit, 499 | * you can add a memory range to be used as trampolines yourself. The starting address must be 4-byte aligned, within the range of branch instruction jumps. 500 | * and it should be free memory that is not used at runtime. 501 | * GlossHook will prioritize the added trampoline memory. 502 | * 503 | * @param lib_name - The library name (or path name) to add trampolines. (Cannot use NULL) 504 | * @param start_addr - The start address. (Absolute address, Cannot use NULL) 505 | * @param size - The size range. (Cannot use 0, ARM requires at least 8 bytes, ARM64 requires at least 16 bytes.) 506 | */ 507 | GLOSS_API void GlossHookAddTrampolines(const char* lib_name, uintptr_t start_addr, size_t size); 508 | 509 | /* 510 | * GlossHook - Inline hook function head by symbol address. 511 | * 512 | * @note: { sym_addr } must differentiate between thumb and arm. (e.g 0x12345679 or 0x12345678) 513 | * 514 | * If the function size is smaller than the jump instruction size, 515 | * the B instruction will automatically be used for a relative jump (the function must be at least 4 bytes). 516 | * 517 | * B instructions have jump range limitations. GlossHook will allocate free memory within the range of the shared object (SO) to create a trampoline. 518 | * The nearby memory space of the SO is limited, which can also lead to hook failures. (see { GlossHookAddTrampolines }) 519 | * 520 | * @param sym_addr - The symbol address to hook. (Cannot use NULL) 521 | * @param new_func - The new function to hook. (Cannot use NULL) 522 | * @param old_func - The old function to store. (Can be NULL) 523 | * @return The hook handle. (failed: NULL) 524 | */ 525 | GLOSS_API GHook GlossHook(void* sym_addr, void* new_func, void** old_func); 526 | 527 | /* 528 | * GlossHookAddr - Inline hook function head by function address. 529 | * 530 | * @note: The parameter { i_set mode } differentiates between thumb, arm, and arm64 modes for the { func_addr }. 531 | * 532 | * B instructions have jump range limitations. GlossHook will allocate free memory within the range of the shared object (SO) to create a trampoline. 533 | * The nearby memory space of the SO is limited, which can also lead to hook failures. (see { GlossHookAddTrampolines }) 534 | * 535 | * @param func_addr - The function address to hook. (Cannot use NULL) 536 | * @param new_func - The new function to hook. (Cannot use NULL) 537 | * @param old_func - The old function to store. (Can be NULL) 538 | * @param is_4_byte_hook - Whether to use 4-byte hook. (true: Jump with 4-byte B instruction, false: defautl) 539 | * @param mode - The hook mode. (see i_set) 540 | * @return The hook handle. (failed: NULL) 541 | */ 542 | GLOSS_API GHook GlossHookAddr(void* func_addr, void* new_func, void** old_func, bool is_4_byte_hook, i_set mode); 543 | 544 | /* 545 | * GlossHookBranch - Inline hook branch instruction. (BL, BLX) 546 | * 547 | * @note: The parameter { i_set mode } differentiates between thumb, arm, and arm64 modes for the { branch_addr }. 548 | * 549 | * BL and BLX instructions have jump range limitations. GlossHook will allocate free memory within the range of the shared object (SO) to create a trampoline. 550 | * The nearby memory space of the SO is limited, which can also lead to hook failures. (see { GlossHookAddTrampolines }) 551 | * 552 | * @param branch_addr - The branch instruction address to hook. (Cannot use NULL) 553 | * @param new_func - The new function to hook. (Cannot use NULL) 554 | * @param old_func - The old function to store. (Can be NULL) 555 | * @param mode - The hook mode. (see i_set) 556 | * @return The hook handle. (failed: NULL) 557 | */ 558 | GLOSS_API GHook GlossHookBranchBL(void* branch_addr, void* new_func, void** old_func, i_set mode); 559 | #ifdef __arm__ 560 | GLOSS_API GHook GlossHookBranchBLX(void* branch_addr, void* new_func, void** old_func, i_set mode); 561 | #endif 562 | 563 | /* 564 | * GlossHookInternalCallback - Internal hook callback function. 565 | * 566 | * @param regs - The register information, see gloss_reg. 567 | * @param hook - The hook handle. 568 | */ 569 | typedef void (*GlossHookInternalCallback)(gloss_reg* regs, GHook hook); 570 | /* 571 | * GlossHookInternal - Inline hook executable code at any position, accessing register and stack information. 572 | * 573 | * @note: The parameter { i_set mode } differentiates between thumb, arm, and arm64 modes for the { addr }. 574 | * 575 | * B instructions have jump range limitations. GlossHook will allocate free memory within the range of the shared object (SO) to create a trampoline. 576 | * The nearby memory space of the SO is limited, which can also lead to hook failures. (see { GlossHookAddTrampolines }) 577 | * 578 | * If ret_addr is set, it may break the ability to hook the address multiple times. 579 | * 580 | * @param addr - The address to hook. (Cannot use NULL) 581 | * @param new_func - The new function to hook, see GlossHookInternalCallback. (Cannot use NULL) 582 | * @param ret_addr - The return address of the new function. (Can be NULL, if it is NULL, default to jumping to the original instruction for execution) 583 | * @param is_4_byte_hook - Whether to use 4-byte hook. (true: Jump with 4-byte B instruction, false: defautl) 584 | * @param mode - The hook mode. (see i_set) 585 | * @return The hook handle. (failed: NULL) 586 | */ 587 | GLOSS_API GHook GlossHookInternal(void* addr, GlossHookInternalCallback new_func, void* ret_addr, bool is_4_byte_hook, i_set mode); 588 | 589 | /* 590 | * GlossHookRedirect - Redirect executable code at any position to a new address. 591 | * 592 | * @note: The parameter { i_set mode } differentiates between thumb, arm, and arm64 modes for the { redirect_addr }. 593 | * 594 | * B instructions have jump range limitations. GlossHook will allocate free memory within the range of the shared object (SO) to create a trampoline. 595 | * The nearby memory space of the SO is limited, which can also lead to hook failures. 596 | * 597 | * @param addr - The address to redirect. (Cannot use NULL) 598 | * @param new_addr - The new address to redirect. (Cannot use NULL) 599 | * @param is_4_byte_hook - Whether to use 4-byte hook. (true: Jump with 4-byte B instruction, false: defautl) 600 | * @param mode - The hook mode. (see i_set) 601 | * @return The hook handle. (failed: NULL) 602 | */ 603 | GLOSS_API GHook GlossHookRedirect(void* addr, void* new_addr, bool is_4_byte_hook, i_set mode); 604 | 605 | /* 606 | * GlossGotHook - Hook Global Offset Table 607 | * 608 | * @param got_addr - The GOT entry address to hook. (Cannot use NULL) 609 | * @param new_func - The new function to hook. (Cannot use NULL) 610 | * @param old_func - The old function to store. (Can be NULL) 611 | * @return The hook handle. (failed: NULL) 612 | */ 613 | GLOSS_API GHook GlossGotHook(void* got_addr, void* new_func, void** old_func); 614 | 615 | // GlossLinkerFuncProxy - Proxy for linker function. 616 | // Support function: dlopen, dlsym, other linker or libdl.so function. 617 | union GlossLinkerFuncProxy 618 | { 619 | struct GlossDlopenProxy 620 | { 621 | // API Level 19 (Android 4.4) and below - K 622 | void* (*dlopen)(const char* filename, int flags); 623 | void** old_dlopen; 624 | 625 | // API Level 21 - 23 (Android 5.0 - 6.0) - L L_MR1 M 626 | // Starting from Android 5.0, dlopen is divided into { dlopen } and { android_dlopen_ext } two functions. 627 | // dlopen and android_dlopen_ext -> dlopen_ext -> do_dlopen 628 | void* (*do_dlopen)(const char* filename, int flags, const void* extinfo); 629 | void** old_do_dlopen; 630 | 631 | // API Level 24 (Android 7.0) and above - N 632 | // dlopen and android_dlopen_ext -> dlopen_ext -> do_dlopen 633 | void* (*do_dlopen_n)(const char* filename, int flags, const void* extinfo, void* caller_addr); 634 | void** old_do_dlopen_n; 635 | 636 | // API Level 26 (Android 8.0) and above 637 | // dlopen and android_dlopen_ext -> __loader_dlopen and __loader_android_dlopen_ext -> dlopen_ext -> do_dlopen 638 | // Can hook { __loader_dlopen } or { __loader_android_dlopen_ext } 639 | } DlopenProxy; 640 | 641 | struct GlossDlsymProxy 642 | { 643 | // API Level 23 (Android 6.0) and below - M 644 | void* (*dlsym)(void* handle, const char* symbol); 645 | void** old_dlsym; 646 | 647 | // API Level 24 (Android 7.0) and above - N 648 | // dlsym and dlvsym -> dlsym_impl -> do_dlsym 649 | bool (*do_dlsym)(void* handle, const char* sym_name, const char* sym_ver, const void* caller_addr, void** symbol); 650 | void** old_do_dlsym; 651 | 652 | // API Level 26 (Android 8.0) and above 653 | // dlsym -> __loader_dlsym -> dlsym_impl -> do_dlsym 654 | // dlvsym -> __loader_dlvsym -> dlsym_impl -> do_dlsym 655 | // Can hook { __loader_dlsym } or { __loader_dlvsym } 656 | } DlsymProxy; 657 | 658 | // Other Linker Function 659 | struct GlossFuncProxy 660 | { 661 | // libdl.so or linker 662 | void* linker_func; 663 | void** old_linker_func; 664 | } FuncProxy; 665 | }; 666 | /* 667 | * GlossLinkerHook - Hook linker and dl functions. 668 | * 669 | * @note: Starting from Android 7.0, due to the linker namespace limit, it is impossible to directly hook the dl series functions in the linker. 670 | * To implement hooking dl series functions, some special processing is done, and a separate API is provided to hook dl series functions. 671 | * Support hooking all symbols functions in the linker and libdl.so. (libdl.so was introduced in Android 8.0) 672 | * Android emulators may not be supported. 673 | * 674 | * @param dlfunc - The linker function c/c++ symbol name to hook. (Cannot use NULL) 675 | * @param new_dlfunc - The new linker function to hook, see GlossLinkerFuncProxy. (Cannot use NULL) 676 | * @return The hook handle. (failed: NULL) 677 | */ 678 | GLOSS_API GHook GlossLinkerHook(const char* dlfunc, GlossLinkerFuncProxy new_dlfunc); 679 | 680 | /* 681 | * GlossHookCallback_t - The callback function when the Hook becomes effective. 682 | * 683 | * @param hook - The hook handle. 684 | * @param lib_name - The library name (or path name). 685 | * @param addr - The symbol addr or got addr list. 686 | * @param size - The symbol size or got addr list size. 687 | */ 688 | struct GlossHookCallback_t 689 | { 690 | GHook hook; // hook handle 691 | const char* path; // lib_name or lib_path 692 | void* addr; // sym_addr or got_addr_list 693 | size_t size; // sym_size or got_addr_list_size 694 | }; 695 | typedef void (*GlossHookCallback)(const GlossHookCallback_t info); 696 | 697 | /* 698 | * GlossHookByName - Inline hook function head by symbol name. 699 | * 700 | * @note: If the dynamic library has been loaded, the hook is completed immediately, 701 | * otherwise, it will be automatically hooked when the library is loaded in the future, need Enable init linke.(see GlossInit) 702 | * Android emulators may not be supported. 703 | * 704 | * @param lib_name - The library name (or path name) to hook. (Cannot use NULL) 705 | * @param sym_name - The symbol name to hook. (Cannot use NULL) 706 | * @param new_func - The new function to hook. (Cannot use NULL) 707 | * @param old_func - The old function to store. (Can be NULL) 708 | * @param call_back_func - The callback function when the hook is triggered, see GlossHookCallback_t. (Can be NULL) 709 | * @return The hook handle. (failed: NULL) 710 | */ 711 | GLOSS_API GHook GlossHookByName(const char* lib_name, const char* sym_name, void* new_func, void** old_func, GlossHookCallback call_back_func); 712 | 713 | /* 714 | * GlossPltHook - Hook Global Offset Table by symbol name 715 | * 716 | * @note: If the dynamic library has been loaded, the hook is completed immediately, 717 | * otherwise, it will be automatically hooked when the library is loaded in the future, need Enable init linke.(see GlossInit) 718 | * Android emulators may not be supported. 719 | * 720 | * @param lib_name - The library name (or path name) to hook. (Cannot use NULL) 721 | * @param sym_name - The symbol name to hook. (Cannot use NULL) 722 | * @param new_func - The new function to hook. (Cannot use NULL) 723 | * @param old_func - The old function to store. (Can be NULL) 724 | * @param call_back_func - The callback function when the hook is triggered, see GlossHookCallback_t. (Can be NULL) 725 | * @return The hook handle. (failed: NULL) 726 | */ 727 | GLOSS_API GHook GlossPltHook(const char* lib_name, const char* sym_name, void* new_func, void** old_func, GlossHookCallback call_back_func); 728 | 729 | /* 730 | * GlossHookAddrByName - Inline hook function head by offset address. 731 | * 732 | * @note: If the dynamic library has been loaded, the hook is completed immediately, 733 | * otherwise, it will be automatically hooked when the library is loaded in the future, need Enable init linke.(see GlossInit) 734 | * Android emulators may not be supported. 735 | * 736 | * B instructions have jump range limitations. GlossHook will allocate free memory within the range of the shared object (SO) to create a trampoline. 737 | * The nearby memory space of the SO is limited, which can also lead to hook failures. 738 | * 739 | * @param lib_name - The library name (or path name) to hook. (Cannot use NULL) 740 | * @param offset_addr - The offset address of the function. (Cannot use NULL) 741 | * @param new_func - The new function to hook. (Cannot use NULL) 742 | * @param old_func - The old function to store. (Can be NULL) 743 | * @param is_4_byte_hook - Whether to use 4-byte hook. (true: Jump with 4-byte B instruction, false: defautl) 744 | * @param mode - The hook mode. (see i_set) 745 | * @param call_back_func - The callback function when the hook is triggered, see GlossHookCallback_t. (Can be NULL) 746 | * @return The hook handle. (failed: NULL) 747 | */ 748 | GLOSS_API GHook GlossHookAddrByName(const char* lib_name, uintptr_t offset_addr, void* new_func, void** old_func, bool is_4_byte_hook, i_set mode, GlossHookCallback call_back_func); 749 | 750 | /* 751 | * GlossHookDisable/Enable/Delete - Disable/Enable/Delete hook. 752 | * 753 | * @param hook - The hook handle. (Cannot use NULL) 754 | */ 755 | GLOSS_API void GlossHookDisable(GHook hook); 756 | GLOSS_API void GlossHookEnable(GHook hook); 757 | GLOSS_API void GlossHookDelete(GHook hook); 758 | /* 759 | * All - Disable/Enable/Delete all hooks from the specified address. 760 | * 761 | * @param addr - The address to disable/enable/delete hooks. (Cannot use NULL) 762 | * @param mode - The hook mode. (see i_set) 763 | */ 764 | GLOSS_API void GlossHookDisableAll(void* addr, i_set mode); 765 | GLOSS_API void GlossHookEnableAll(void* addr, i_set mode); 766 | GLOSS_API void GlossHookDeleteAll(void* addr, i_set mode); 767 | 768 | /* 769 | * GlossHookGetCount - Get the current hook count id. 770 | * 771 | * @param hook - The hook handle. (Cannot use NULL) 772 | * @return Count id. (0: failed) 773 | */ 774 | GLOSS_API int GlossHookGetCount(GHook hook); 775 | /* 776 | * GlossHookGetTotalCount - Get the hook total count id from the specified address. 777 | * 778 | * @param addr - The address to get hook total count. (Cannot use NULL) 779 | * @param inst_set - The instruction set. (see i_set) 780 | * @return Total count id. (0: failed) 781 | */ 782 | GLOSS_API int GlossHookGetTotalCount(void* addr, i_set inst_set); 783 | 784 | /* 785 | * GlossHookGetLastHook - Get the last hook handle from the specified address. 786 | * 787 | * @param addr - The address to get last hook handle. (Cannot use NULL) 788 | * @param inst_set - The instruction set. (see i_set) 789 | * @return The last hook handle. (NULL: failed) 790 | */ 791 | GLOSS_API GHook GlossHookGetLastHook(void* addr, i_set inst_set); 792 | 793 | /* 794 | * GlossHookGetPrevHook - Get the previous hook handle. 795 | * 796 | * @param hook - The hook handle. (Cannot use NULL) 797 | * @return The previous hook handle. (NULL: failed) 798 | */ 799 | GLOSS_API GHook GlossHookGetPrevHook(GHook hook); 800 | 801 | /* 802 | * GlossHookGetNextHook - Get the next hook handle. 803 | * 804 | * @param hook - The hook handle. (Cannot use NULL) 805 | * @return The next hook handle. (NULL: failed) 806 | */ 807 | GLOSS_API GHook GlossHookGetNextHook(GHook hook); 808 | 809 | /* 810 | * GlossHookReplaceNewFunc - Replace the new function of the hook. 811 | * 812 | * @param hook - The hook handle. (Cannot use NULL) 813 | * @param new_func - The new function to replace. (Cannot use NULL) 814 | */ 815 | GLOSS_API void GlossHookReplaceNewFunc(GHook hook, void* new_func); 816 | 817 | /* 818 | * GlossHookGetOldFunc - Get the old function of the hook. 819 | * 820 | * @param hook - The hook handle. (Cannot use NULL) 821 | * @return The old function. (NULL: failed) 822 | */ 823 | GLOSS_API void* GlossHookGetOldFunc(GHook hook); 824 | 825 | /* 826 | * GlossHookGetOriglFunc - Get the original function of the hook. 827 | * 828 | * @param hook - The hook handle. (Cannot use NULL) 829 | * @return The original function. (NULL: failed) 830 | */ 831 | GLOSS_API void* GlossHookGetOriglFunc(GHook hook); 832 | 833 | /* 834 | * GlossHookGetFixedInst - Get the fixed instruction buffer of the hook. 835 | * 836 | * @param hook - The hook handle. (Cannot use NULL) 837 | * @param len - The fixed instruction len. (Can be NULL) 838 | * @return The fixed instruction buffer. (NULL: failed) 839 | */ 840 | GLOSS_API uint8_t* GlossHookGetFixedInst(GHook hook, size_t* len); 841 | 842 | /* 843 | * GlossHookGetBackupsInst - Get the original instruction buffer of the hook. 844 | * 845 | * @param hook - The hook handle. (Cannot use NULL) 846 | * @param len - The original instruction len. (Can be NULL) 847 | * @return The original instruction buffer. (NULL: failed) 848 | */ 849 | GLOSS_API uint8_t* GlossHookGetBackupsInst(GHook hook, size_t* len); 850 | 851 | #ifdef __cplusplus 852 | } 853 | /* 854 | * Write any type of value to memory. 855 | */ 856 | template 857 | inline static void WriteMemory(uintptr_t addr, T value, bool vp = true) 858 | { 859 | WriteMemory(reinterpret_cast(addr), reinterpret_cast(&value), sizeof(T), vp); 860 | } 861 | 862 | /* 863 | * Read any type of value from memory. 864 | */ 865 | template 866 | inline static T ReadMemory(uintptr_t addr, bool vp = true) 867 | { 868 | T value; 869 | ReadMemory(reinterpret_cast(addr), reinterpret_cast(&value), sizeof(T), vp); 870 | return value; 871 | } 872 | 873 | 874 | // *********************************************************** Inst API ****************************************************************************** 875 | // GlossHook Inst.h 876 | #ifndef GLOSS_HOOK_INST_H 877 | #define GLOSS_HOOK_INST_H 878 | 879 | namespace Gloss { 880 | namespace Inst { 881 | 882 | // conditions type 883 | enum class Conds { EQ, NE, CS, HS = CS, CC, LO = CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV, MAX_COND }; 884 | 885 | // branchs type 886 | enum class Branchs { B_COND16, B_COND, B_16, B, BL, BLX, MAX_BRANCH }; 887 | /* 888 | * GetBranch - Get branch instruction type of addr. 889 | * 890 | * @param addr - Address to get branch type. 891 | * @param mode - The instruction mode. (see i_set) 892 | * @return - Branch type. (see branchs) 893 | */ 894 | GLOSS_API Branchs GetBranch(uintptr_t addr, i_set mode); 895 | 896 | #ifdef __arm__ 897 | 898 | /* 899 | * IsThumb32 - Check if addr is thumb32 instruction. 900 | * 901 | * @param addr - Address to check. 902 | * @return - True if addr is thumb32 instruction, otherwise false. 903 | */ 904 | GLOSS_API bool IsThumb32(uint32_t addr); 905 | 906 | /* 907 | * MakeNOP - Make nop instruction. (thumb16/32) 908 | * 909 | * @param addr - Address to make nop instruction. 910 | * @param size - The byte size of the instruction. 911 | */ 912 | GLOSS_API void MakeThumb16NOP(uint32_t addr, size_t size); 913 | GLOSS_API void MakeThumb32NOP(uint32_t addr, size_t size); 914 | 915 | /* 916 | * MakeRET - Make function return instruction. (thumb16) 917 | * 918 | * @param addr - Address to make return instruction. 919 | * @param type - The instruction type. ( 1: BX LR, 0: MOV PC, LR) 920 | */ 921 | GLOSS_API void MakeThumbRET(uint32_t addr, uint8_t type); 922 | 923 | /* 924 | * MakeBranch - Make branch instruction. (thumb16/32 B BC BL BLX) 925 | * 926 | * @param addr - Address to make branch instruction. 927 | * @param dest - The branch destination. 928 | * @param cond - The branch condition. (see conds) 929 | * @return - The branch instruction. 930 | */ 931 | GLOSS_API uint16_t MakeThumb16B(uint32_t addr, uint32_t dest); 932 | GLOSS_API uint16_t MakeThumb16BCond(uint32_t addr, uint32_t dest, Conds cond); 933 | GLOSS_API uint32_t MakeThumb32B(uint32_t addr, uint32_t dest); 934 | GLOSS_API uint32_t MakeThumb32BCond(uint32_t addr, uint32_t dest, Conds cond); 935 | GLOSS_API uint32_t MakeThumbBL(uint32_t addr, uint32_t func); 936 | GLOSS_API uint32_t MakeThumbBL_W(uint32_t addr, uint32_t func); 937 | GLOSS_API uint32_t MakeThumbBLX(uint32_t addr, uint32_t func); 938 | GLOSS_API uint32_t MakeThumbBLX_W(uint32_t addr, uint32_t func); 939 | 940 | /* 941 | * MakeCB - Make conditional branch instruction. (thumb16) 942 | * 943 | * @param addr - Address to make conditional branch instruction. 944 | * @param dest - The branch destination. 945 | * @param reg - The condition register. (see gloss_reg::e_reg) 946 | * @param is_cbnz - True if the instruction is CBNZ, otherwise CBZ. 947 | * @return - The conditional branch instruction. 948 | */ 949 | GLOSS_API uint16_t MakeThumbCB(uint32_t addr, uint32_t dest, gloss_reg::e_reg reg, bool is_cbnz); 950 | 951 | /* 952 | * MakeAbsoluteJump - Make absolute jump instruction. (thumb32) 953 | * 954 | * Inst; 955 | * addr[0] LDR.W PC, [PC, #0] 956 | * addr[4] dest 957 | * 958 | * @param addr - Address to make absolute jump instruction. 959 | * @param dest - The absolute jump destination. 960 | * @return - The absolute jump instruction byte size. 961 | */ 962 | GLOSS_API int8_t MakeThumbAbsoluteJump(uint32_t addr, uint32_t dest); 963 | 964 | /* 965 | * GetBranchDestination - Get branch destination. (thumb16/32) 966 | * 967 | * @param addr - Address to get branch destination. 968 | * @return - The branch destination address. 969 | */ 970 | GLOSS_API uint32_t GetThumb16BranchDestination(uint32_t addr); 971 | GLOSS_API uint32_t GetThumb32BranchDestination(uint32_t addr); 972 | 973 | /* 974 | * MakeNOP - Make nop instruction. (arm) 975 | * 976 | * @param addr - Address to make nop instruction. 977 | * @param size - The byte size of the instruction. 978 | */ 979 | GLOSS_API void MakeArmNOP(uint32_t addr, size_t size); 980 | 981 | /* 982 | * MakeRET - Make function return instruction. (arm) 983 | * 984 | * @param addr - Address to make return instruction. 985 | * @param type - The instruction type. ( 1: BX LR, 0: MOV PC, LR) 986 | */ 987 | GLOSS_API void MakeArmRET(uint32_t addr, uint8_t type); 988 | 989 | /* 990 | * MakeBranch - Make branch instruction. (arm B BC BL BLX) 991 | * 992 | * @param addr - Address to make branch instruction. 993 | * @param dest - The branch destination. 994 | * @param cond - The branch condition. (see conds) 995 | * @return - The branch instruction. 996 | */ 997 | GLOSS_API uint32_t MakeArmB(uint32_t addr, uint32_t dest, Conds cond = Conds::AL); 998 | GLOSS_API uint32_t MakeArmBL(uint32_t addr, uint32_t func, Conds cond = Conds::AL); 999 | GLOSS_API uint32_t MakeArmBLX(uint32_t addr, uint32_t func); 1000 | 1001 | /* 1002 | * MakeAbsoluteJump - Make absolute jump instruction. (arm) 1003 | * 1004 | * Inst; 1005 | * addr[0] LDR PC, [PC, #-4] 1006 | * addr[4] dest 1007 | * 1008 | * @param addr - Address to make absolute jump instruction. 1009 | * @param dest - The absolute jump destination. 1010 | * @return - The absolute jump instruction byte size. 1011 | */ 1012 | GLOSS_API int8_t MakeArmAbsoluteJump(uint32_t addr, uint32_t dest); 1013 | 1014 | /* 1015 | * GetBranchDestination - Get branch destination. (arm) 1016 | * 1017 | * @param addr - Address to get branch destination. 1018 | * @return - The branch destination address. 1019 | */ 1020 | GLOSS_API uint32_t GetArmBranchDestination(uint32_t addr); 1021 | 1022 | #elif __aarch64__ 1023 | 1024 | /* 1025 | * MakeNOP - Make nop instruction. (aarch64) 1026 | * 1027 | * @param addr - Address to make nop instruction. 1028 | * @param size - The byte size of the instruction. 1029 | */ 1030 | GLOSS_API void MakeArm64NOP(uint64_t addr, size_t size); 1031 | 1032 | /* 1033 | * MakeRET - Make function return instruction. (aarch64) 1034 | * 1035 | * @param addr - Address to make return instruction. 1036 | * @param type - The instruction type. ( 1: BR X30(LR) 0: RET) 1037 | */ 1038 | GLOSS_API void MakeArm64RET(uint64_t addr, uint8_t type); 1039 | 1040 | /* 1041 | * MakeBranch - Make branch instruction. (aarch64 B BC BL) 1042 | * 1043 | * @param addr - Address to make branch instruction. 1044 | * @param dest - The branch destination. 1045 | * @param cond - The branch condition. (see conds) 1046 | * @return - The branch instruction. 1047 | */ 1048 | GLOSS_API uint32_t MakeArm64B(uint64_t addr, uint64_t dest); 1049 | GLOSS_API uint32_t MakeArm64BCond(uint64_t addr, uint64_t dest, Conds cond); 1050 | GLOSS_API uint32_t MakeArm64BL(uint64_t addr, uint64_t func); 1051 | 1052 | /* 1053 | * MakeCB - Make conditional branch instruction. (aarch64) 1054 | * 1055 | * @param addr - Address to make conditional branch instruction. 1056 | * @param dest - The branch destination. 1057 | * @param reg - The condition register. (see gloss_reg::e_reg) 1058 | * @param is_cbnz - True if the instruction is CBNZ, otherwise CBZ. 1059 | * @param is64 - True if the register is 64bit, otherwise 32bit. 1060 | * @return - The conditional branch instruction. 1061 | */ 1062 | GLOSS_API uint32_t MakeArm64CB(uint64_t addr, uint64_t dest, gloss_reg::e_reg reg, bool is_cbnz, bool is64); 1063 | 1064 | /* 1065 | * MakeAbsoluteJump - Make absolute jump instruction. (aarch64) 1066 | * 1067 | * Inst; (Jump) 1068 | * addr[0] LDR X18, #8 1069 | * addr[4] BR X18 1070 | * addr[8] dest 1071 | * 1072 | * Inst; (JumpRet) 1073 | * addr[0] LDR X18, #8 1074 | * addr[4] RET X18 1075 | * addr[8] dest 1076 | * 1077 | * Inst; (Jump32) 1078 | * addr[0] ADRP X18, dest 1079 | * addr[4] BR X18 1080 | * 1081 | * Inst; (Jump128) 1082 | * addr[0] STP X1, X0, [SP, #-0x10] 1083 | * addr[4] LDR X0, 8 1084 | * addr[8] BR X0 1085 | * addr[12] dest 1086 | * addr[20] LDR X0, [SP, -0x8] 1087 | * 1088 | * @param addr - Address to make absolute jump instruction. 1089 | * @param dest - The absolute jump destination. 1090 | * @param reg - The register to store the jump address. (see gloss_reg::e_reg) 1091 | * @return - The absolute jump instruction byte size. 1092 | */ 1093 | GLOSS_API int8_t MakeArm64AbsoluteJump(uint64_t addr, uint64_t dest, gloss_reg::e_reg reg = gloss_reg::e_reg::X18); // unlimited 1094 | GLOSS_API int8_t MakeArm64AbsoluteJumpRet(uint64_t addr, uint64_t dest, gloss_reg::e_reg reg = gloss_reg::e_reg::X18); // unlimited 1095 | GLOSS_API int8_t MakeArm64AbsoluteJump32(uint64_t addr, uint64_t dest, gloss_reg::e_reg reg = gloss_reg::e_reg::X18); // 4g limit 1096 | GLOSS_API int8_t MakeArm64AbsoluteJump128(uint64_t addr, uint64_t dest); // unlimited 1097 | 1098 | /* 1099 | * GetBranchDestination - Get branch destination. (aarch64) 1100 | * 1101 | * @param addr - Address to get branch destination. 1102 | * @return - The branch destination address. 1103 | */ 1104 | GLOSS_API uint64_t GetArm64BranchDestination(uint64_t addr); 1105 | 1106 | #endif 1107 | } 1108 | } 1109 | #endif 1110 | 1111 | #endif 1112 | #endif -------------------------------------------------------------------------------- /GlossHook/lib/ARM/libGlossHook.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XMDS/GlossHook/0647fc80f919ac6a4fcc3c91a99254789ceab29d/GlossHook/lib/ARM/libGlossHook.a -------------------------------------------------------------------------------- /GlossHook/lib/ARM/libGlossHook.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XMDS/GlossHook/0647fc80f919ac6a4fcc3c91a99254789ceab29d/GlossHook/lib/ARM/libGlossHook.so -------------------------------------------------------------------------------- /GlossHook/lib/ARM64/libGlossHook.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XMDS/GlossHook/0647fc80f919ac6a4fcc3c91a99254789ceab29d/GlossHook/lib/ARM64/libGlossHook.a -------------------------------------------------------------------------------- /GlossHook/lib/ARM64/libGlossHook.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XMDS/GlossHook/0647fc80f919ac6a4fcc3c91a99254789ceab29d/GlossHook/lib/ARM64/libGlossHook.so -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 XMDS 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GlossHook 2 | GlossHook is a simple yet feature-rich Android NativeHook library, well-suited for Android game modification and mod development, and it can also be applied in other contexts. 3 | GlossHook is utilized by AndroidModLoader and has enabled the creation of a vast number of mods for Android GTA games, demonstrating its stability! 4 | 5 | GlossHook是一个简单、功能多的安卓NativeHook库,适用于安卓游戏修改和模组制作,它也能用于其它场景。 6 | GlossHook被AndroidModLoader使用,为安卓GTA游戏创建了大量模组,它是稳定的! 7 | 8 | [AML](https://github.com/RusJJ/AndroidModLoader) 9 | 10 | # Features 11 | ## English 12 | - Supports InlineHook and PltHook (GotHook) for thumb/arm/arm64 architectures. 13 | 14 | - Supports Android 5.0~14.0. 15 | 16 | - Supports hooking at a single call site (branch instructions BL/BLX) of a function. Sometimes, you may only need to hook one specific call site of a function rather than all its call sites. 17 | 18 | - Supports hooking at any arbitrary location within a function. Within the proxy function, you can read/write registers and the stack at that location and insert any type of function call. 19 | 20 | - Supports inserting inline assembly functions (asm) at a specific location. 21 | 22 | - Supports hooking functions in the Linker, such as dlopen/dlsym, etc. 23 | 24 | - Supports hooking for loading dynamic libraries (so) in the future. 25 | 26 | - Supports hooking constructor/entry functions (.init and .init_array sections functions). 27 | 28 | - Supports the shortest 4-byte hooking, accommodating short functions. 29 | 30 | - Supports multiple hooking at the same location. 31 | 32 | - Supports calling back the original function within the proxy function or directly replacing the function without calling back. 33 | 34 | - Supports enable/disable/delete any single or multiple hooking. When enable/disable/delete a single hooking, it does not affect other hooking at the same location. 35 | 36 | - Provides commonly used APIs for retrieving dynamic library (so) information, such as obtaining the base address and searching for symbol addresses. 37 | 38 | - Provide APIs for writing to memory, reading from memory, and removing memory protection. 39 | 40 | - Provides APIs for writing assembly instructions, such as commonly used assembly instructions like NOP/RET/B. 41 | 42 | - For more APIs, refer to the header file descriptions. 43 | 44 | ## 中文 45 | * 支持thumb/arm/arm64的InlineHook和PltHook(GotHook). 46 | 47 | * 支持安卓5.0~14.0. 48 | 49 | * 支持对函数单个调用点的hook(分支指令BL/BLX),有时候你可能只需要hook函数其中一处调用点,而不是函数的全部调用点. 50 | 51 | * 支持对函数内任意位置的hook,在代理函数中可读写该位置的寄存器和栈,插入任何类型的函数调用. 52 | 53 | * 支持对一个位置插入内嵌汇编函数(asm). 54 | 55 | * 支持对Linke中函数的hook,例如dlopen/dlsym等. 56 | 57 | * 支持对未来加载动态库(so)的hook. 58 | 59 | * 支持对构造函数/入口函数的hook(.init和.init_array节中的函数). 60 | 61 | * 支持最短4字节hook,适配短函数. 62 | 63 | * 支持对同一个位置的多次hook. 64 | 65 | * 支持代理函数中回调原函数,也可不回调直接替换函数. 66 | 67 | * 支持开启/关闭/删除任意一个或多个hook. 开启/关闭/删除任意1个hook时,对同位置其它hook不影响. 68 | 69 | * 提供常用的获取动态库(so)信息的API,例如获取首地址,查找符号地址等. 70 | 71 | * 提供写入内存/读取内存/解除内存保护/的API. 72 | 73 | * 提供汇编指令写入API,例如NOP/RET/B等常用汇编指令. 74 | 75 | * 更多其它API见头文件说明. 76 | -------------------------------------------------------------------------------- /examples/GlossHookExample/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH:= $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | LOCAL_MODULE := GlossHook 5 | LOCAL_SRC_FILES := $(LOCAL_PATH)/$(TARGET_ARCH)/libGlossHook.a 6 | include $(PREBUILT_STATIC_LIBRARY) 7 | 8 | include $(CLEAR_VARS) 9 | LOCAL_MODULE := GlossHookDemo 10 | LOCAL_CPP_EXTENSION := .cpp 11 | LOCAL_SRC_FILES := main.cpp 12 | LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)/include 13 | LOCAL_C_INCLUDES += $(LOCAL_PATH)/include 14 | LOCAL_CPPFLAGS += -std=c++17 -Wall -Wextra -Werror 15 | LOCAL_LDLIBS += -llog 16 | ifeq ($(TARGET_ARCH_ABI),arm64-v8a) 17 | LOCAL_LDFLAGS += -Wl,-z,max-page-size=16384 18 | else ifeq ($(TARGET_ARCH_ABI), armeabi-v7a) 19 | LOCAL_CPPFLAGS += -mfloat-abi=softfp 20 | endif 21 | LOCAL_STATIC_LIBRARIES := GlossHook 22 | include $(BUILD_EXECUTABLE) -------------------------------------------------------------------------------- /examples/GlossHookExample/Application.mk: -------------------------------------------------------------------------------- 1 | NDK_TOOLCHAIN_VERSION := clang 2 | APP_STL := c++_static 3 | APP_ABI := armeabi-v7a arm64-v8a 4 | ifeq ($(NDK_DEBUG), 1) 5 | APP_OPTIM := debug 6 | else 7 | APP_OPTIM := release 8 | endif 9 | APP_PLATFORM := android-21 -------------------------------------------------------------------------------- /examples/GlossHookExample/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Gloss.h" 3 | 4 | __attribute__((noinline)) void test() 5 | { 6 | std::cout << "Hello World!" << std::endl; 7 | } 8 | 9 | void (*old_test)(); 10 | void my_test() 11 | { 12 | std::cout << "hook 1" << std::endl; 13 | old_test(); 14 | } 15 | 16 | void (*old_test2)(); 17 | void my_test2() 18 | { 19 | std::cout << "hook 2" << std::endl; 20 | old_test2(); 21 | } 22 | 23 | void (*old_test3)(); 24 | void my_test3() 25 | { 26 | std::cout << "hook 3" << std::endl; 27 | old_test3(); 28 | } 29 | 30 | int main() 31 | { 32 | test(); 33 | GHook h1 = GlossHook((void*)test, (void*)my_test, (void**)&old_test); 34 | test(); 35 | GHook h2 = GlossHook((void*)test, (void*)my_test2, (void**)&old_test2); 36 | test(); 37 | GHook h3 = GlossHook((void*)test, (void*)my_test3, (void**)&old_test3); 38 | test(); 39 | 40 | GlossHookDisable(h3); 41 | test(); 42 | GlossHookDisable(h2); 43 | test(); 44 | GlossHookDisable(h1); 45 | test(); 46 | 47 | GlossHookEnable(h1); 48 | test(); 49 | GlossHookEnable(h2); 50 | test(); 51 | GlossHookEnable(h3); 52 | test(); 53 | 54 | GlossHookDelete(h3); 55 | test(); 56 | GlossHookDelete(h2); 57 | test(); 58 | GlossHookDelete(h1); 59 | test(); 60 | return 0; 61 | } --------------------------------------------------------------------------------