码迷,mamicode.com
首页 > 移动开发 > 详细

android hook 框架 libinject2 如何实现so注入

时间:2015-02-11 20:29:36      阅读:461      评论:0      收藏:0      [点我收藏+]

标签:

上一篇 android hook 框架 libinject 简介、编译、运行 实际运行了so的注入并调用了注入so里的一个函数,这篇开始分析其实现。 

 

与之前分析的 abdi 项目一样,libinject2 也是依赖于linux系统的 ptrace 系统调用。

 

android hook 框架 ADBI 简介、编译、运行

android hook 框架 ADBI 如何实现so注入

android hook 框架 ADBI 如何实现函数挂钩

 

这个库首先对ptrace的调用封装了几个helper函数

int ptrace_readdata(pid_t pid,  uint8_t *src, uint8_t *buf, size_t size)
{
        uint32_t i, j, remain;
        uint8_t *laddr;

        union u {
                long val;
                char chars[sizeof(long)];
        } d;

        j = size / 4;
        remain = size % 4;

        laddr = buf;

        for (i = 0; i < j; i ++) {
                d.val = ptrace(PTRACE_PEEKTEXT, pid, src, 0);
                memcpy(laddr, d.chars, 4);
                src += 4;
                laddr += 4;
        }

        if (remain > 0) {
                d.val = ptrace(PTRACE_PEEKTEXT, pid, src, 0);
                memcpy(laddr, d.chars, remain);
        }

        return 0;
}

int ptrace_writedata(pid_t pid, uint8_t *dest, uint8_t *data, size_t size)
{
        uint32_t i, j, remain;
        uint8_t *laddr;
{
        if (ptrace(PTRACE_CONT, pid, NULL, 0) < 0) {
                perror("ptrace_cont");
                return -1;
        }

        return 0;
}

int ptrace_attach(pid_t pid)
{
        if (ptrace(PTRACE_ATTACH, pid, NULL, 0) < 0) {
                perror("ptrace_attach");
                return -1;
        }

        int status = 0;
        waitpid(pid, &status , WUNTRACED);

        return 0;
}

int ptrace_detach(pid_t pid)
{
        if (ptrace(PTRACE_DETACH, pid, NULL, 0) < 0) {
                perror("ptrace_detach");
                return -1;
        }

        return 0;
}

long ptrace_retval(struct pt_regs * regs)
{
#if defined(__arm__)
        return regs->ARM_r0;
#elif defined(__i386__)
        return regs->eax;
#else
#error "Not supported"
#endif
}

long ptrace_ip(struct pt_regs * regs)
{
#if defined(__arm__)
        return regs->ARM_pc;
#elif defined(__i386__)
        return regs->eip;
#else
#error "Not supported"
#endif
}

int ptrace_call_wrapper(pid_t target_pid, const char * func_name, void * func_addr, long * parameters, int param_num, struct pt_regs * regs)
{
        DEBUG_PRINT("[+] Calling %s in target process.\n", func_name);
        if (ptrace_call(target_pid, (uint32_t)func_addr, parameters, param_num, regs) == -1)
                return -1;

        if (ptrace_getregs(target_pid, regs) == -1)
                return -1;
        DEBUG_PRINT("[+] Target process returned from %s, return value=%x, pc=%x \n",
                        func_name, ptrace_retval(regs), ptrace_ip(regs));
        return 0;
}

 

下面两个函数实现了获取目标进程加载的动态库内部函数的地址,与 adbi 的原理一致,都是利用函数与动态库加载进内存的起始地址的offset一致,来计算的,个人觉得 libinject 在实现同样的功能时代码给 adbi 写得更舒服,这也是研究各种源码的好处,有对比才有高低。

void* get_module_base(pid_t pid, const char* module_name)  // 这个函数获取动态库 module_name 加载在进程 pid 后的起始地址
{
        FILE *fp;
        long addr = 0;
        char *pch;
        char filename[32];
        char line[1024];

        if (pid < 0) {
                /* self process */
                snprintf(filename, sizeof(filename), "/proc/self/maps", pid);  // 同样是通过解析 maps 文件得到的
        } else {
                snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
        }

        fp = fopen(filename, "r");

        if (fp != NULL) {
                while (fgets(line, sizeof(line), fp)) {
                        if (strstr(line, module_name)) {
                                pch = strtok( line, "-" );
                                addr = strtoul( pch, NULL, 16 );

                                if (addr == 0x8000)
                                        addr = 0;

                                break;
                        }
                }

                fclose(fp) ;
        }

        return (void *)addr;
}

void* get_remote_addr(pid_t target_pid, const char* module_name, void* local_addr) // 这个函数获取目标进程内某个动态库函数的地址
{
        void* local_handle, *remote_handle;

        local_handle = get_module_base(-1, module_name);
        remote_handle = get_module_base(target_pid, module_name);

        DEBUG_PRINT("[+] get_remote_addr: local[%x], remote[%x]\n", local_handle, remote_handle);

        void * ret_addr = (void *)((uint32_t)local_addr + (uint32_t)remote_handle - (uint32_t)local_handle);// 算法一致, local_addr - local_handle 得到                                                                                              // offset, 然后再加上 remote_handle, 即得到目标进程的函数地址

        return ret_addr;
}

 

下面这个是 libinject2 的核心函数:

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;
        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;
        extern uint32_t _dlopen_addr_s, _dlopen_param1_s, _dlopen_param2_s, _dlsym_addr_s,                 _dlsym_param2_s, _dlclose_addr_s, _inject_start_s, _inject_end_s, _inject_function_param_s,                 _saved_cpsr_s, _saved_r0_pc_s;

        uint32_t code_length;
        long parameters[10];

        DEBUG_PRINT("[+] Injecting process: %d\n", target_pid);

        if (ptrace_attach(target_pid) == -1)
                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);

        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);

        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);

#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);

#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");
        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);
        ret = 0;

exit:
        return ret;
}

 

最后是main函数,libinject2 只是注入了一个So到目标进程,并执行了so里的一个函数,还没有真正劫持目标进程的函数

int main(int argc, char** argv) {
        pid_t target_pid;
        //target_pid = find_pid_of("/system/bin/surfaceflinger");
        target_pid = atoi(argv[1]);
        if (-1 == target_pid) {
                printf("Can‘t find the process\n");
                return -1;
        }
        //target_pid = find_pid_of("/data/test");
        inject_remote_process(target_pid, "/data/local/tmp/libhello.so", "hook_entry",  "I‘m parameter!", strlen("I‘m parameter!"));
        return 0;
}

 

android hook 框架 libinject2 如何实现so注入

标签:

原文地址:http://www.cnblogs.com/jiayy/p/4286864.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!