├── jni ├── Android.mk ├── Application.mk ├── bridge.c ├── inject.c └── sotool.h └── readme.md /jni/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | LOCAL_MODULE := inject 5 | LOCAL_SRC_FILES := inject.c 6 | 7 | #shellcode.s 8 | 9 | LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog 10 | 11 | #LOCAL_FORCE_STATIC_EXECUTABLE := true 12 | include $(BUILD_EXECUTABLE) 13 | 14 | 15 | 16 | 17 | include $(CLEAR_VARS) 18 | 19 | LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog 20 | LOCAL_MODULE := bridge 21 | 22 | LOCAL_SRC_FILES := bridge.c 23 | LOCAL_CFLAGS := -g 24 | 25 | include $(BUILD_SHARED_LIBRARY) -------------------------------------------------------------------------------- /jni/Application.mk: -------------------------------------------------------------------------------- 1 | APP_ABI := armeabi-v7a -------------------------------------------------------------------------------- /jni/bridge.c: -------------------------------------------------------------------------------- 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 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #define LOG_TAG "bridge" 22 | #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) 23 | #define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) 24 | #define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) 25 | 26 | __attribute__((constructor)) static void _init() { 27 | LOGD("[_init] Bridge so has been loaded!!!!"); 28 | 29 | } 30 | 31 | 32 | int hook_entry(char* cache){ 33 | LOGD("so_entry is now running!\n"); 34 | const char* dexPath; 35 | const char* dexOptDir; 36 | const char* className; 37 | const char* methodName; 38 | 39 | JNIEnv *(*getJNIEnv)(); 40 | void *handle = dlopen( "system/lib/libandroid_runtime.so", RTLD_NOW ); 41 | getJNIEnv = dlsym( handle, "_ZN7android14AndroidRuntime9getJNIEnvEv" ); 42 | if ( !getJNIEnv ) { 43 | LOGE("can not find getJNIEnv!"); 44 | return -1; 45 | } 46 | 47 | JNIEnv *env = getJNIEnv(); 48 | 49 | jint ver; 50 | ver = (*env)->GetVersion( env ); 51 | switch ( ver ) { 52 | 53 | case 0x00010001: 54 | LOGD("JNI version is JNI_VERSION_1_1");break; 55 | 56 | case 0x00010002: 57 | LOGD("JNI version is JNI_VERSION_1_2");break; 58 | 59 | case 0x00010004: 60 | LOGD("JNI version is JNI_VERSION_1_4");break; 61 | 62 | case 0x00010006: 63 | LOGD("JNI version is JNI_VERSION_1_6");break; 64 | 65 | default: 66 | LOGD("Unknown JNI_VERSION:0x%x",ver);break; 67 | } 68 | 69 | jclass stringClass, classLoaderClass, dexClassLoaderClass, targetClass; 70 | jmethodID getSystemClassLoaderMethod, dexClassLoaderContructor, loadClassMethod, targetMethod; 71 | jobject systemClassLoaderObject, dexClassLoaderObject; 72 | jstring dexPathString, dexOptDirString, classNameString, tmpString; 73 | jobjectArray stringArray; 74 | 75 | LOGD("-------------- now begin dex injection --------------"); 76 | 77 | /* set dex dir */ 78 | LOGD("step1: setting dex dir and opt dir..."); 79 | dexPath = "/data/inj/classes.dex"; 80 | dexOptDir = "/data/data/com.wuchao.helloworld/cache"; 81 | className = "com.wuchao.dextobeinjected.wuchao"; 82 | methodName = "methodToBeInvoked"; 83 | LOGD("step1 finished!\n"); 84 | 85 | 86 | /* Get SystemClasLoader */ 87 | LOGD("step2: getting systemClassLoader method and invoke it to get systemClassLoader obeject..."); 88 | stringClass = (*env)->FindClass(env, "java/lang/String");//获取String类 89 | classLoaderClass = (*env)->FindClass(env, "java/lang/ClassLoader");//获取classLoader类 90 | getSystemClassLoaderMethod = (*env)->GetStaticMethodID(env, classLoaderClass, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");//获取classLoader中的getSystemClassLoader静态方法 91 | systemClassLoaderObject = (*env)->CallStaticObjectMethod(env, classLoaderClass, getSystemClassLoaderMethod);//调用getSystemClassLoader静态方法来获取所属对象systemClassLoaderObject 92 | if (! systemClassLoaderObject) { 93 | LOGE("Failed to call systemClassLoaderObject"); 94 | return -1; 95 | } 96 | LOGD("step2 finished!\n"); 97 | 98 | /* Create DexClassLoader */ 99 | LOGD("step3: using dexClassLoader class to create dexClassLoader object..."); 100 | dexClassLoaderClass = (*env)->FindClass(env, "dalvik/system/DexClassLoader");//获取dexClassLoader类 101 | dexClassLoaderContructor = (*env)->GetMethodID(env, dexClassLoaderClass, "", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)V");//获取dexClassLoader的Contructor 102 | dexPathString = (*env)->NewStringUTF(env, dexPath);//将char*转换成jString 103 | dexOptDirString = (*env)->NewStringUTF(env, dexOptDir);//将char*转换成jString 104 | dexClassLoaderObject = (*env)->NewObject(env, dexClassLoaderClass, dexClassLoaderContructor, dexPathString, dexOptDirString, NULL, systemClassLoaderObject);//生成自定义的dexClassLoader对象 105 | LOGD("step3 finished!\n"); 106 | 107 | /* Use DexClassLoader to load target class */ 108 | LOGD("step4: using dexClassLoader class to find [loadClass] method and using dexClassLoader object created above to load target class:[%s]...", className); 109 | loadClassMethod = (*env)->GetMethodID(env, dexClassLoaderClass, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");//获取dexClassLoader类中的“loadClass”方法 110 | classNameString = (*env)->NewStringUTF(env, className);////将char*转换成jString 111 | targetClass = (jclass)(*env)->CallObjectMethod(env, dexClassLoaderObject, loadClassMethod, classNameString); //调用“loadClass”方法来获取目标类:com.wuchao.dextobeinjectd.wuchao 112 | if (!targetClass) { 113 | LOGE("Failed to load target class [%s]", className); 114 | return -1; 115 | } 116 | LOGD("step4 finished!\n"); 117 | 118 | /* Invoke target method */ 119 | LOGD("step5: using [%s] class loaded above to find [%s] method and invoke it...", className, methodName); 120 | targetMethod = (*env)->GetStaticMethodID(env, targetClass, methodName, "()V");//获取目标类中的静态方法:methodToBeInvoked 121 | if (!targetMethod) { 122 | LOGE("Failed to load target method [%s]", methodName); 123 | return -1; 124 | } 125 | (*env)->CallStaticVoidMethod(env, targetClass, targetMethod);//调用目标静态方法 126 | LOGD("step5 finished, invoking [%s] method succeeded!", methodName); 127 | 128 | return 0; 129 | } 130 | -------------------------------------------------------------------------------- /jni/inject.c: -------------------------------------------------------------------------------- 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 | #include 15 | #include 16 | 17 | #include "sotool.h" 18 | 19 | #define AND60_SDK 23 20 | 21 | #if defined(__i386__) 22 | #define pt_regs user_regs_struct 23 | #endif 24 | 25 | 26 | 27 | #if 0 28 | #define LOG_TAG "INJECT" 29 | #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG, fmt, ##args) 30 | #define DEBUG_PRINT(format,args...) LOGD(format, ##args) 31 | #else 32 | #define DEBUG_PRINT(format,args...) printf(format, ##args) 33 | #endif 34 | 35 | #define CPSR_T_MASK ( 1u << 5 ) 36 | 37 | const char *libc_path = "/system/lib/libc.so"; 38 | const char *linker_path = "/system/bin/linker"; 39 | const char *libart_path = "/system/lib/libart.so"; 40 | 41 | static char dl_module_path[512]; 42 | static int sdk_ver = 0; 43 | static unsigned dlopen_ext_offset = 0; 44 | 45 | int ptrace_readdata(pid_t pid, uint8_t *src, uint8_t *buf, size_t size) 46 | { 47 | uint32_t i, j, remain; 48 | uint8_t *laddr; 49 | 50 | union u { 51 | long val; 52 | char chars[sizeof(long)]; 53 | } d; 54 | 55 | j = size / 4; 56 | remain = size % 4; 57 | 58 | laddr = buf; 59 | 60 | for (i = 0; i < j; i ++) { 61 | d.val = ptrace(PTRACE_PEEKTEXT, pid, src, 0); 62 | memcpy(laddr, d.chars, 4); 63 | src += 4; 64 | laddr += 4; 65 | } 66 | 67 | if (remain > 0) { 68 | d.val = ptrace(PTRACE_PEEKTEXT, pid, src, 0); 69 | memcpy(laddr, d.chars, remain); 70 | } 71 | 72 | return 0; 73 | } 74 | 75 | int ptrace_writedata(pid_t pid, uint8_t *dest, const uint8_t *data, size_t size) 76 | { 77 | uint32_t i, j, remain; 78 | uint8_t *laddr; 79 | 80 | union u { 81 | long val; 82 | char chars[sizeof(long)]; 83 | } d; 84 | 85 | j = size / 4; 86 | remain = size % 4; 87 | 88 | laddr = (uint8_t*)data; 89 | 90 | for (i = 0; i < j; i ++) { 91 | memcpy(d.chars, laddr, 4); 92 | int ret = ptrace(PTRACE_POKETEXT, pid, dest, d.val); 93 | if (ret == -1) { 94 | DEBUG_PRINT("[ptrace_writedata] poketext failed: %s\n", strerror(errno)); 95 | } 96 | 97 | dest += 4; 98 | laddr += 4; 99 | } 100 | 101 | if (remain > 0) { 102 | d.val = ptrace(PTRACE_PEEKTEXT, pid, dest, 0); 103 | if (d.val == -1) { 104 | DEBUG_PRINT("[ptrace_writedata] peektext failed: %s\n", strerror(errno)); 105 | } 106 | for (i = 0; i < remain; i ++) { 107 | d.chars[i] = *laddr ++; 108 | } 109 | 110 | int ret = ptrace(PTRACE_POKETEXT, pid, dest, d.val); 111 | if (ret == -1) { 112 | DEBUG_PRINT("[ptrace_writedata] poketext failed: %s\n", strerror(errno)); 113 | } 114 | } 115 | 116 | return 0; 117 | } 118 | 119 | int ptrace_setregs(pid_t pid, struct pt_regs * regs); 120 | int ptrace_getregs(pid_t pid, struct pt_regs * regs); 121 | int ptrace_continue(pid_t pid); 122 | 123 | #if defined(__arm__) 124 | int ptrace_call(pid_t pid, uint32_t addr, long *params, uint32_t num_params, struct pt_regs* regs) 125 | { 126 | uint32_t i; 127 | for (i = 0; i < num_params && i < 4; i ++) { 128 | regs->uregs[i] = params[i]; 129 | } 130 | 131 | // 132 | // push remained params onto stack 133 | // 134 | if (i < num_params) { 135 | regs->ARM_sp -= (num_params - i) * sizeof(long) ; 136 | ptrace_writedata(pid, (void *)regs->ARM_sp, (uint8_t *)¶ms[i], (num_params - i) * sizeof(long)); 137 | } 138 | 139 | regs->ARM_pc = addr; 140 | if (regs->ARM_pc & 1) { 141 | /* thumb */ 142 | regs->ARM_pc &= (~1u); 143 | regs->ARM_cpsr |= CPSR_T_MASK; 144 | } else { 145 | /* arm */ 146 | regs->ARM_cpsr &= ~CPSR_T_MASK; 147 | } 148 | 149 | regs->ARM_lr = 0; 150 | 151 | if (ptrace_setregs(pid, regs) == -1 152 | || ptrace_continue(pid) == -1) { 153 | printf("error\n"); 154 | return -1; 155 | } 156 | 157 | int stat = 0; 158 | waitpid(pid, &stat, WUNTRACED); 159 | while (stat != 0xb7f) { 160 | if (ptrace_continue(pid) == -1) { 161 | printf("error\n"); 162 | return -1; 163 | } 164 | waitpid(pid, &stat, WUNTRACED); 165 | } 166 | 167 | return 0; 168 | } 169 | 170 | #elif defined(__i386__) 171 | long ptrace_call(pid_t pid, uint32_t addr, long *params, uint32_t num_params, struct user_regs_struct * regs) 172 | { 173 | regs->esp -= (num_params) * sizeof(long); 174 | ptrace_writedata(pid, (void *)regs->esp, (uint8_t *)params, (num_params) * sizeof(long)); 175 | 176 | long tmp_addr = 0x00; 177 | regs->esp -= sizeof(long); 178 | ptrace_writedata(pid, regs->esp, (char *)&tmp_addr, sizeof(tmp_addr)); 179 | 180 | regs->eip = addr; 181 | 182 | if (ptrace_setregs(pid, regs) == -1 183 | || ptrace_continue( pid) == -1) { 184 | printf("error\n"); 185 | return -1; 186 | } 187 | 188 | int stat = 0; 189 | waitpid(pid, &stat, WUNTRACED); 190 | while (stat != 0xb7f) { 191 | if (ptrace_continue(pid) == -1) { 192 | printf("error\n"); 193 | return -1; 194 | } 195 | waitpid(pid, &stat, WUNTRACED); 196 | } 197 | 198 | return 0; 199 | } 200 | #else 201 | #error "Not supported" 202 | #endif 203 | 204 | int ptrace_getregs(pid_t pid, struct pt_regs * regs) 205 | { 206 | if (ptrace(PTRACE_GETREGS, pid, NULL, regs) < 0) { 207 | perror("ptrace_getregs: Can not get register values"); 208 | return -1; 209 | } 210 | 211 | return 0; 212 | } 213 | 214 | int ptrace_setregs(pid_t pid, struct pt_regs * regs) 215 | { 216 | if (ptrace(PTRACE_SETREGS, pid, NULL, regs) < 0) { 217 | perror("ptrace_setregs: Can not set register values"); 218 | return -1; 219 | } 220 | 221 | return 0; 222 | } 223 | 224 | int ptrace_continue(pid_t pid) 225 | { 226 | if (ptrace(PTRACE_CONT, pid, NULL, 0) < 0) { 227 | perror("ptrace_cont"); 228 | return -1; 229 | } 230 | 231 | return 0; 232 | } 233 | 234 | int ptrace_attach(pid_t pid) 235 | { 236 | if (ptrace(PTRACE_ATTACH, pid, NULL, 0) < 0) { 237 | perror("ptrace_attach"); 238 | return -1; 239 | } 240 | 241 | int status = 0; 242 | waitpid(pid, &status , WUNTRACED); 243 | 244 | return 0; 245 | } 246 | 247 | int ptrace_detach(pid_t pid) 248 | { 249 | if (ptrace(PTRACE_DETACH, pid, NULL, 0) < 0) { 250 | perror("ptrace_detach"); 251 | return -1; 252 | } 253 | 254 | return 0; 255 | } 256 | 257 | void get_module_path(unsigned long addr, char* module_path) { 258 | char filename[32]; 259 | snprintf(filename, sizeof(filename), "/proc/self/maps"); 260 | FILE *fp = fopen(filename, "r"); 261 | if (fp == NULL) { 262 | DEBUG_PRINT("[get_module_path] open /proc/self/maps failed!\n"); 263 | return; 264 | } 265 | 266 | char line[512]; 267 | memset(line, 0, 512); 268 | while (fgets(line, sizeof(line), fp)) { 269 | #if defined(__aarch64__) || defined(__x86_64__) 270 | char *fmt="%016lx-%016lx %*s %*s %*s %*s %s"; 271 | #else 272 | char *fmt="%x-%x %*s %*s %*s %*s %s"; 273 | #endif 274 | unsigned long b, e; 275 | sscanf(line, fmt,&b, &e, module_path); 276 | if (b < addr && e > addr) { 277 | DEBUG_PRINT("[get_module_path] module_path:%s\n", module_path); 278 | break; 279 | } 280 | } 281 | fclose(fp); 282 | } 283 | 284 | void* get_module_base(pid_t pid, const char* module_name) 285 | { 286 | FILE *fp; 287 | long addr = 0; 288 | char *pch; 289 | char filename[32]; 290 | char line[1024]; 291 | 292 | if (pid < 0) { 293 | /* self process */ 294 | snprintf(filename, sizeof(filename), "/proc/self/maps"); 295 | } else { 296 | snprintf(filename, sizeof(filename), "/proc/%d/maps", pid); 297 | } 298 | 299 | fp = fopen(filename, "r"); 300 | 301 | if (fp != NULL) { 302 | while (fgets(line, sizeof(line), fp)) { 303 | if (strstr(line, module_name)) { 304 | pch = strtok( line, "-" ); 305 | addr = strtoul( pch, NULL, 16 ); 306 | 307 | if (addr == 0x8000) 308 | addr = 0; 309 | 310 | break; 311 | } 312 | } 313 | 314 | fclose(fp) ; 315 | } 316 | 317 | return (void *)addr; 318 | } 319 | 320 | void* get_remote_addr(pid_t target_pid, void* local_addr) 321 | { 322 | void* local_handle, *remote_handle; 323 | 324 | char module_path[256]; 325 | memset(module_path, 0, 256); 326 | get_module_path((unsigned long)local_addr, module_path); 327 | 328 | local_handle = get_module_base(-1, module_path); 329 | remote_handle = get_module_base(target_pid, module_path); 330 | 331 | DEBUG_PRINT("[+] get_remote_addr: local[%p], remote[%p]\n", local_handle, remote_handle); 332 | void * ret_addr = (void *)((uint32_t)local_addr + (uint32_t)remote_handle - (uint32_t)local_handle); 333 | 334 | #if defined(__i386__) 335 | if (!strcmp(module_path, libc_path)) { 336 | ret_addr += 2; 337 | } 338 | #endif 339 | return ret_addr; 340 | } 341 | 342 | int find_pid_of(const char *process_name) 343 | { 344 | int id; 345 | pid_t pid = -1; 346 | DIR* dir; 347 | FILE *fp; 348 | char filename[32]; 349 | char cmdline[256]; 350 | 351 | struct dirent * entry; 352 | 353 | if (process_name == NULL) 354 | return -1; 355 | 356 | dir = opendir("/proc"); 357 | if (dir == NULL) 358 | return -1; 359 | 360 | while((entry = readdir(dir)) != NULL) { 361 | id = atoi(entry->d_name); 362 | if (id != 0) { 363 | sprintf(filename, "/proc/%d/cmdline", id); 364 | fp = fopen(filename, "r"); 365 | if (fp) { 366 | fgets(cmdline, sizeof(cmdline), fp); 367 | fclose(fp); 368 | 369 | if (strcmp(process_name, cmdline) == 0) { 370 | /* process found */ 371 | pid = id; 372 | break; 373 | } 374 | } 375 | } 376 | } 377 | 378 | closedir(dir); 379 | return pid; 380 | } 381 | 382 | long ptrace_retval(struct pt_regs * regs) 383 | { 384 | #if defined(__arm__) 385 | return regs->ARM_r0; 386 | #elif defined(__i386__) 387 | return regs->eax; 388 | #else 389 | #error "Not supported" 390 | #endif 391 | } 392 | 393 | long ptrace_ip(struct pt_regs * regs) 394 | { 395 | #if defined(__arm__) 396 | return regs->ARM_pc; 397 | #elif defined(__i386__) 398 | return regs->eip; 399 | #else 400 | #error "Not supported" 401 | #endif 402 | } 403 | 404 | int ptrace_call_wrapper(pid_t target_pid, const char * func_name, void * func_addr, long * parameters, int param_num, struct pt_regs * regs) 405 | { 406 | struct pt_regs curreg; 407 | if (ptrace_getregs(target_pid, &curreg) == -1) 408 | return -1; 409 | DEBUG_PRINT("[+] Calling %s in target process, current pc=%ld\n", func_name, ptrace_ip(&curreg)); 410 | if (ptrace_call(target_pid, (uint32_t)func_addr, parameters, param_num, regs) == -1) 411 | return -1; 412 | 413 | if (ptrace_getregs(target_pid, regs) == -1) 414 | return -1; 415 | DEBUG_PRINT("[+] Target process returned from %s, return value=%lx, pc=%lx \n", 416 | func_name, ptrace_retval(regs), ptrace_ip(regs)); 417 | return 0; 418 | } 419 | 420 | int inject_remote_process(pid_t target_pid, const char *injected_lib, const char *function_name, const char *param, size_t param_size) 421 | { 422 | int ret = -1; 423 | void *mmap_addr, *dlopen_addr, *dlsym_addr, *dlclose_addr, *dlerror_addr; 424 | void *local_handle, *remote_handle, *dlhandle; 425 | uint8_t *map_base = 0; 426 | uint8_t *dlopen_param1_ptr, *dlsym_param2_ptr, *saved_r0_pc_ptr, *inject_param_ptr, *remote_code_ptr, *local_code_ptr; 427 | 428 | struct pt_regs regs, original_regs; 429 | extern uint32_t _dlopen_addr_s, _dlopen_param1_s, _dlopen_param2_s, _dlsym_addr_s, \ 430 | _dlsym_param2_s, _dlclose_addr_s, _inject_start_s, _inject_end_s, _inject_function_param_s, \ 431 | _saved_cpsr_s, _saved_r0_pc_s; 432 | 433 | uint32_t code_length; 434 | long parameters[10]; 435 | 436 | DEBUG_PRINT("[+] Injecting process: %d\n", target_pid); 437 | 438 | if (ptrace_attach(target_pid) == -1) 439 | goto exit; 440 | 441 | if (ptrace_getregs(target_pid, ®s) == -1) 442 | goto exit; 443 | 444 | /* save original registers */ 445 | memcpy(&original_regs, ®s, sizeof(regs)); 446 | 447 | mmap_addr = get_remote_addr(target_pid, (void *)mmap); 448 | DEBUG_PRINT("[+] Remote mmap address: %p\n", mmap_addr); 449 | 450 | /* call mmap */ 451 | parameters[0] = 0; // addr 452 | parameters[1] = 0x1000; // size 453 | parameters[2] = PROT_READ | PROT_WRITE | PROT_EXEC; // prot 454 | parameters[3] = MAP_ANONYMOUS | MAP_PRIVATE; // flags 455 | parameters[4] = 0; //fd 456 | parameters[5] = 0; //offset 457 | 458 | if (ptrace_call_wrapper(target_pid, "mmap", mmap_addr, parameters, 6, ®s) == -1) 459 | goto exit; 460 | 461 | map_base = (uint8_t *)ptrace_retval(®s); 462 | char* test_str = "111111111111111111111111111111111111"; 463 | ptrace_writedata(target_pid, map_base, (const uint8_t *)test_str, strlen(test_str) + 1); 464 | 465 | uint8_t readbuf[32]; 466 | ptrace_readdata(target_pid, map_base, readbuf, 31); 467 | readbuf[31] = 0; 468 | DEBUG_PRINT("[+] read data: %s\n", readbuf); 469 | 470 | DEBUG_PRINT("[+] local dlopen=%p, dlsym=%p, dlclose=%p, dlerror=%p\n", 471 | dlopen, dlsym, dlclose, dlerror); 472 | 473 | dlopen_addr = get_remote_addr(target_pid, (void *)dlopen); 474 | dlsym_addr = get_remote_addr(target_pid, (void *)dlsym ); 475 | dlclose_addr = get_remote_addr(target_pid, (void *)dlclose); 476 | dlerror_addr = get_remote_addr(target_pid, (void *)dlerror); 477 | 478 | DEBUG_PRINT("[+] Get imports: dlopen: %p, dlsym: %p, dlclose: %p, dlerror: %p\n", 479 | dlopen_addr, dlsym_addr, dlclose_addr, dlerror_addr); 480 | 481 | DEBUG_PRINT("library path = %s, map_base = %p\n", injected_lib, map_base); 482 | ptrace_writedata(target_pid, map_base, (const uint8_t *)injected_lib, strlen(injected_lib) + 1); 483 | 484 | if (sdk_ver > AND60_SDK) { 485 | DEBUG_PRINT("[+] android 7.0+ system, use dlopen_ext\n"); 486 | void* target_linker_base = get_module_base(target_pid, linker_path); 487 | void* target_dlopen_ext_addr = (void*)((unsigned long)target_linker_base + dlopen_ext_offset); 488 | DEBUG_PRINT("[+] target_dlopen_ext_addr addr: %p\n", target_dlopen_ext_addr); 489 | void* target_libart_base = get_module_base(target_pid, libart_path); 490 | unsigned long target_caller_addr = (unsigned long)target_libart_base + 0x2000; 491 | DEBUG_PRINT("[+] target_caller_addr addr: %p\n", (void*)target_caller_addr); 492 | 493 | parameters[0] = (long)map_base; 494 | parameters[1] = RTLD_NOW; 495 | parameters[2] = 0; 496 | parameters[3] = target_caller_addr; 497 | 498 | if (ptrace_call_wrapper(target_pid, "dlopen_ext", target_dlopen_ext_addr, 499 | parameters, 4, ®s) == -1) 500 | goto exit; 501 | } 502 | else { 503 | parameters[0] = (long)map_base; 504 | parameters[1] = RTLD_NOW| RTLD_GLOBAL; 505 | 506 | if (ptrace_call_wrapper(target_pid, "dlopen", dlopen_addr, parameters, 2, ®s) == -1) 507 | goto exit; 508 | } 509 | 510 | void* sohandle = (void*)ptrace_retval(®s); 511 | 512 | #define FUNCTION_NAME_ADDR_OFFSET 0x100 513 | ptrace_writedata(target_pid, map_base + FUNCTION_NAME_ADDR_OFFSET, (const uint8_t *)function_name, strlen(function_name) + 1); 514 | parameters[0] = (long)sohandle; 515 | parameters[1] = (long)(map_base + FUNCTION_NAME_ADDR_OFFSET); 516 | 517 | if (ptrace_call_wrapper(target_pid, "dlsym", dlsym_addr, parameters, 2, ®s) == -1) 518 | goto exit; 519 | 520 | void* hook_entry_addr = (void*)ptrace_retval(®s); 521 | DEBUG_PRINT("hook_entry_addr = %p\n", hook_entry_addr); 522 | 523 | #define FUNCTION_PARAM_ADDR_OFFSET 0x200 524 | ptrace_writedata(target_pid, map_base + FUNCTION_PARAM_ADDR_OFFSET, (uint8_t*)param, strlen(param) + 1); 525 | parameters[0] = (long)(map_base + FUNCTION_PARAM_ADDR_OFFSET); 526 | 527 | 528 | // if (ptrace_call_wrapper(target_pid, "hook_entry", hook_entry_addr, parameters, 1, ®s) == -1) 529 | // goto exit; 530 | 531 | printf("Press enter to dlclose and detach\n"); 532 | //getchar(); 533 | parameters[0] = (long)sohandle; 534 | 535 | if (ptrace_call_wrapper(target_pid, "dlclose", dlclose, parameters, 1, ®s) == -1) 536 | goto exit; 537 | 538 | /* restore */ 539 | ptrace_setregs(target_pid, &original_regs); 540 | ptrace_detach(target_pid); 541 | ret = 0; 542 | 543 | exit: 544 | return ret; 545 | } 546 | 547 | static void init_sdk_ver(){ 548 | char value[32] = {0}; 549 | 550 | int len = __system_property_get("ro.build.version.sdk", value); 551 | if (len <= 0) { 552 | DEBUG_PRINT("[init_sdk_ver] read ro.build.version.sdk error!"); 553 | return; 554 | } 555 | 556 | sdk_ver = atoi(value); 557 | DEBUG_PRINT("[init_sdk_ver] ro.build.version.sdk: %d\n", sdk_ver); 558 | } 559 | 560 | static void init_dlopen_ext_offset() { 561 | FILE *fp = NULL; 562 | if (!(fp = fopen(linker_path, "rb"))) { 563 | DEBUG_PRINT("[init_dlopen_ext_offset]Unable to open %s\n", linker_path); 564 | return; 565 | } 566 | 567 | fseek(fp, 0, SEEK_END); 568 | int size = ftell(fp); 569 | fseek(fp, 0, SEEK_SET); 570 | 571 | char *buffer = (char*)malloc(size); 572 | if (fread(buffer, 1, size, fp) != size) { 573 | DEBUG_PRINT("fread error\n"); 574 | return; 575 | } 576 | fclose(fp); 577 | 578 | unsigned long symstr_off = 0, symtab_off = 0, symtab_size = 0; 579 | unsigned long symtab_entsize = 0, symtab_count = 0; 580 | const elf_header_t* eh = (elf_header_t*)buffer; 581 | const elf_sheader_t* esh = (elf_sheader_t*)(buffer + eh->shoff); 582 | char* section_str = esh[eh->shstrndx].sh_offset + buffer; 583 | 584 | for (int i = 0; i < eh->shnum; i++) { 585 | char* sname = esh[i].sh_name + section_str; 586 | if (strcmp(sname, ".symtab") == 0) { 587 | symtab_off = esh[i].sh_offset; 588 | symtab_size = esh[i].sh_size; 589 | symtab_entsize = esh[i].sh_entsize; 590 | symtab_count = symtab_size / symtab_entsize; 591 | DEBUG_PRINT("[init_dlopen_ext_offset]: symtab offset = %lx, count=%lx, index= %d\n", 592 | symtab_off, symtab_count, i); 593 | } 594 | if (strcmp(sname, ".strtab") == 0) { 595 | symstr_off = esh[i].sh_offset; 596 | DEBUG_PRINT("[init_dlopen_ext_offset] symstr offset = %lx, index = %d\n", symstr_off, i); 597 | } 598 | 599 | } 600 | 601 | if(!symtab_off) { 602 | DEBUG_PRINT("[init_dlopen_ext_offset] can't find symtab from sections\n"); 603 | } 604 | 605 | elf_sym_t* edt = (elf_sym_t*)(buffer + symtab_off); 606 | 607 | const char* name_dlopen_ext_N = "__dl__ZL10dlopen_extPKciPK17android_dlextinfoPv"; 608 | const char* name_dlopen_ext_O = "__dl__ZL10dlopen_extPKciPK17android_dlextinfoPKv"; 609 | const char* name_dlopen_ext_P = "__dl___loader_android_dlopen_ext"; 610 | 611 | for(int i = 0 ; i < symtab_count; i++) { 612 | uint8_t st_type = ELF32_ST_TYPE(edt[i].info); 613 | char* st_name = buffer + symstr_off + edt[i].name; 614 | // DEBUG_PRINT("[init_dlopen_ext_offset] walk sym name:%s, value:%x\n", st_name, edt[i].value); 615 | if (st_type == STT_FUNC && edt[i].size) { 616 | if(strcmp(st_name, name_dlopen_ext_N) == 0) { 617 | dlopen_ext_offset = edt[i].value; 618 | DEBUG_PRINT("[init_dlopen_ext_offset] find dlopen_ext_N: %x\n", dlopen_ext_offset); 619 | break; 620 | } 621 | else if (strcmp(st_name, name_dlopen_ext_O) == 0) { 622 | dlopen_ext_offset = edt[i].value; 623 | DEBUG_PRINT("[init_dlopen_ext_offset] find dlopen_ext_O: %x\n", dlopen_ext_offset); 624 | break; 625 | } 626 | else if (strcmp(st_name, name_dlopen_ext_P) == 0) { 627 | dlopen_ext_offset = edt[i].value; 628 | DEBUG_PRINT("[init_dlopen_ext_offset] find dlopen_ext_P: %x\n", dlopen_ext_offset); 629 | break; 630 | } 631 | } 632 | } 633 | 634 | free(buffer); 635 | } 636 | 637 | int main(int argc, char** argv) { 638 | if (argc < 3) { 639 | DEBUG_PRINT("[main] usage: ./inject {pid} {libpath}"); 640 | } 641 | pid_t target_pid = atoi(argv[1]); 642 | char* injected_lib = argv[2]; 643 | DEBUG_PRINT("[main] target_pid:%d, libpath:%s\n", target_pid, injected_lib); 644 | 645 | init_sdk_ver(); 646 | if (sdk_ver > AND60_SDK) { 647 | init_dlopen_ext_offset(); 648 | if (dlopen_ext_offset == 0) { 649 | DEBUG_PRINT("[main] can't locate dlopen_ext\n"); 650 | return 1; 651 | } 652 | } 653 | 654 | char* param = "I'm parameter!"; 655 | inject_remote_process(target_pid, injected_lib, "hook_entry", param, strlen(param)); 656 | return 0; 657 | } -------------------------------------------------------------------------------- /jni/sotool.h: -------------------------------------------------------------------------------- 1 | #ifndef __sotool_h__ 2 | #define __sotool_h__ 3 | 4 | #include 5 | #include 6 | 7 | #if defined(__arm__) || defined(__i386__) 8 | #define elf_header_t elf32_header_t 9 | #define elf_pheader_t elf32_pheader_t 10 | #define elf_sheader_t elf32_sheader_t 11 | #define elf_sym_t elf32_sym_t 12 | #else 13 | #error "Not supported" 14 | #endif 15 | 16 | typedef struct { 17 | uint8_t ident[16]; /* The first 4 bytes are the ELF magic */ 18 | 19 | uint16_t type; /* == 2, EXEC (executable file) */ 20 | uint16_t machine; /* == 8, MIPS r3000 */ 21 | uint32_t version; /* == 1, default ELF value */ 22 | uint32_t entry; /* program starting point */ 23 | uint32_t phoff; /* program header offset in the file */ 24 | 25 | uint32_t shoff; /* section header offset in the file, unused for us, so == 0 */ 26 | uint32_t flags; /* flags, unused for us. */ 27 | uint16_t ehsize; /* this header size ( == 52 ) */ 28 | uint16_t phentsize; /* size of a program header ( == 32 ) */ 29 | uint16_t phnum; /* number of program headers */ 30 | uint16_t shentsize; /* size of a section header, unused here */ 31 | 32 | uint16_t shnum; /* number of section headers, unused here */ 33 | uint16_t shstrndx; /* section index of the string table */ 34 | } elf32_header_t; 35 | 36 | typedef struct { 37 | uint32_t type; /* == 1, PT_LOAD (that is, this section will get loaded */ 38 | uint32_t offset; /* offset in file, on a 4096 bytes boundary */ 39 | uint32_t vaddr; /* virtual address where this section is loaded */ 40 | uint32_t paddr; /* physical address where this section is loaded */ 41 | uint32_t filesz; /* size of that section in the file */ 42 | uint32_t memsz; /* size of that section in memory (rest is zero filled) */ 43 | uint32_t flags; /* PF_X | PF_W | PF_R, that is executable, writable, readable */ 44 | uint32_t align; /* == 0x1000 that is 4096 bytes */ 45 | } elf32_pheader_t; 46 | 47 | typedef struct { 48 | uint32_t sh_name; 49 | uint32_t sh_type; 50 | uint32_t sh_flags; 51 | uint32_t sh_addr; 52 | uint32_t sh_offset; 53 | uint32_t sh_size; 54 | uint32_t sh_link; 55 | uint32_t sh_info; 56 | uint32_t sh_addralign; 57 | uint32_t sh_entsize; 58 | } elf32_sheader_t; 59 | 60 | typedef struct { 61 | uint32_t name; 62 | uint32_t value; 63 | uint32_t size; 64 | uint8_t info; 65 | uint8_t other; 66 | uint16_t shndx; 67 | } elf32_sym_t; 68 | 69 | #endif /* __sotool_h__ */ -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 参考 https://github.com/longlong2013/android_dex_injection --------------------------------------------------------------------------------