android系统调用封装so,android hook 框架 libinject2 如何实现so注入

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

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

这个库首先对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 {longval;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;

}intptrace_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;

}intptrace_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, 即得到目标进程的函数地址

returnret_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;structpt_regs regs;structpt_regs original_regs;externuint32_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)gotoexit;if (ptrace_getregs(target_pid, &regs) == -1)gotoexit;/*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)gotoexit;

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)gotoexit;void * sohandle = ptrace_retval(&regs);#define FUNCTION_NAME_ADDR_OFFSET 0x100ptrace_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)gotoexit;void * hook_entry_addr = ptrace_retval(&regs);

DEBUG_PRINT("hook_entry_addr = %p\n", hook_entry_addr);#define FUNCTION_PARAM_ADDR_OFFSET 0x200ptrace_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)gotoexit;

printf("Press enter to dlclose and detach\n");

getchar();

parameters[0] =sohandle;if (ptrace_call_wrapper(target_pid, "dlclose", dlclose, parameters, 1, &regs) == -1)gotoexit;/*restore*/ptrace_setregs(target_pid,&original_regs);

ptrace_detach(target_pid);

ret= 0;

exit:returnret;

}

最后是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;

}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值