美文网首页Android技术进阶Android热修复技术
android hook之注入安卓进程,并hook java世界

android hook之注入安卓进程,并hook java世界

作者: SHUTUP | 来源:发表于2015-07-30 10:57 被阅读2029次

    本文是对看雪上一篇文章的学习笔记。记录自己的一些实践和遇到的问题。
    原文地址:注入安卓进程,并hook java世界的方法.

    hook流程:

    • 通过系统ptrace调用可以控制被traced进程的寄存器和程序映象。
    int inject_remote_process(pid_t target_pid, const char *library_path, const char *function_name, const char *param, size_t param_size)
    {
            int ret = -1;
            void *mmap_addr, *dlopen_addr, *dlsym_addr, *dlclose_addr, *dlerror_addr; // 存放目标进程相应函数的地址
            void *local_handle, *remote_handle, *dlhandle;
            uint8_t *map_base = 0; // 存放目标进程mmap获取的内存块的地址
            uint8_t *dlopen_param1_ptr, *dlsym_param2_ptr, *saved_r0_pc_ptr, *inject_param_ptr, *remote_code_ptr, *local_code_ptr;
    
            struct pt_regs regs;
            struct pt_regs original_regs;
           
            uint32_t code_length;
            long parameters[10];
    
            DEBUG_PRINT("[+] Injecting process: %d\n", target_pid);
    
            if (ptrace_attach(target_pid) == -1) // 第一步: attach 到目标进程
                    goto exit;
    
            if (ptrace_getregs(target_pid, &regs) == -1)
                    goto exit;
    
            /* save original registers */
            memcpy(&original_regs, &regs, sizeof(regs)); // 第二步:保存目标进程被注入前的寄存器内容,方便注入完成后恢复
    
            mmap_addr = get_remote_addr(target_pid, libc_path, (void *)mmap);
            DEBUG_PRINT("[+] Remote mmap address: %x\n", mmap_addr);
    
            /* call mmap */
            parameters[0] = 0;  // addr
            parameters[1] = 0x4000; // size
            parameters[2] = PROT_READ | PROT_WRITE | PROT_EXEC;  // prot
            parameters[3] =  MAP_ANONYMOUS | MAP_PRIVATE; // flags
            parameters[4] = 0; //fd
            parameters[5] = 0; //offset
    
            if (ptrace_call_wrapper(target_pid, "mmap", mmap_addr, parameters, 6, &regs) == -1)
                    goto exit;
    
            map_base = ptrace_retval(&regs);  // 第三步,获取目标进程mmap调用的地址,并执行mmap调用,在目标进程分配一块地址,用于存放后面要注入的库路径和相关函数地址等
    
            dlopen_addr = get_remote_addr( target_pid, linker_path, (void *)dlopen );
            dlsym_addr = get_remote_addr( target_pid, linker_path, (void *)dlsym );
            dlclose_addr = get_remote_addr( target_pid, linker_path, (void *)dlclose );
            dlerror_addr = get_remote_addr( target_pid, linker_path, (void *)dlerror );
    
            DEBUG_PRINT("[+] Get imports: dlopen: %x, dlsym: %x, dlclose: %x, dlerror: %x\n",
                            dlopen_addr, dlsym_addr, dlclose_addr, dlerror_addr);
    
            printf("library path = %s\n", library_path);
            ptrace_writedata(target_pid, map_base, library_path, strlen(library_path) + 1);// 第四步,获取目标进程动态库的几个函数,并将要注入的so的路径写入刚刚申请的内存的初始地址
    
            parameters[0] = map_base;
            parameters[1] = RTLD_NOW| RTLD_GLOBAL;
    
            if (ptrace_call_wrapper(target_pid, "dlopen", dlopen_addr, parameters, 2, &regs) == -1)
                    goto exit;
    
            void * sohandle = ptrace_retval(&regs); // 第五步,在目标进程内调用 dlopen函数加载要注入的 so ,这一步成功后,so已经被注入目标进程的地址空间内了
    
    #define FUNCTION_NAME_ADDR_OFFSET       0x100
            ptrace_writedata(target_pid, map_base + FUNCTION_NAME_ADDR_OFFSET, function_name, strlen(function_name) + 1);
            parameters[0] = sohandle;
            parameters[1] = map_base + FUNCTION_NAME_ADDR_OFFSET;
    
            if (ptrace_call_wrapper(target_pid, "dlsym", dlsym_addr, parameters, 2, &regs) == -1)
                    goto exit;
    
            void * hook_entry_addr = ptrace_retval(&regs);
            DEBUG_PRINT("hook_entry_addr = %p\n", hook_entry_addr); // 第六步,在目标进程内调用 dlsym函数获取刚刚注入的so里的hook函数
    
    #define FUNCTION_PARAM_ADDR_OFFSET      0x200
            ptrace_writedata(target_pid, map_base + FUNCTION_PARAM_ADDR_OFFSET, param, strlen(param) + 1);
            parameters[0] = map_base + FUNCTION_PARAM_ADDR_OFFSET;
    
            if (ptrace_call_wrapper(target_pid, "hook_entry", hook_entry_addr, parameters, 1, &regs) == -1)
                    goto exit;
    
           // printf("Press enter to dlclose and detach\n"); // 第七步,在目标进程内调用hook函数
          //  getchar();
            parameters[0] = sohandle;
    
            if (ptrace_call_wrapper(target_pid, "dlclose", dlclose, parameters, 1, &regs) == -1)
                    goto exit;
    
            /* restore */
            ptrace_setregs(target_pid, &original_regs);
            ptrace_detach(target_pid); // 第八步,恢复目标进程的寄存器,detach 退出对目标进程的 ptrace
            ret = 0;
    
    exit:
            return ret;
    }
    
    • 在将so1注入到目标进程后,会执行so1中的一个方法,在这个方法中,我们加载一个新的so2库到进程。
    • 在so2库中封装了需要hook的函数的一些信息
    • 在so1中进行方法的替换,即修改了目标函数应该调用的函数指针。(具体替换还需要分析)

    目前实现的功能:

    • 按照原作者的意图,实现了替换功能。

    参考链接:

    JNI介绍

    相关文章

      网友评论

        本文标题:android hook之注入安卓进程,并hook java世界

        本文链接:https://www.haomeiwen.com/subject/epomqttx.html