当前位置: 代码迷 >> Android >> 4. 参考文档
  详细解决方案

4. 参考文档

热度:92   发布时间:2016-04-28 05:12:42.0
Android native层动态库注射

1.简介

本文讲解在Android native层,root权限下,注射动态库到目标进程,从而hook目标进程中动态库的函数的实现方式。文中的源码全部来源于网络,我只是稍微加以整理。

环境:Android4.2 源码下编译,模拟器中运行。

2.代码构成

包含三个模块的代码:

1.inject程序:把动态库libhookhelper注射到目标进程

2.libhookhelper:动态库代码。此部分代码用于修改目标进程中目标函数所在的got表的信息,从而替换掉目标函数。理解这部分需要一点点elf格式的知识。文章最后会给出链接文档以作参考。

3.libtest:这部分含有用于测试的目标进程的代码。目标进程调用一个动态库实现打印字符串的功能。无实际意义,仅作测试。

3.代码

3.1 inject程序与Android.mk文件:

inject.c代码如下:

#include <stdio.h>    #include <stdlib.h>    #include <asm/user.h>    #include <asm/ptrace.h>    #include <sys/ptrace.h>    #include <sys/wait.h>    #include <sys/mman.h>    #include <dlfcn.h>    #include <dirent.h>    #include <unistd.h>    #include <string.h>    #include <elf.h>    #include <android/log.h>    #if defined(__i386__)    #define pt_regs         user_regs_struct    #endif    #define ENABLE_DEBUG 1    #if ENABLE_DEBUG    #define  LOG_TAG "inject"    #define  LOGD(fmt, args...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG, fmt, ##args)    #define DEBUG_PRINT(format,args...) \    LOGD(format, ##args)    #else    #define DEBUG_PRINT(format,args...)    #endif    #define CPSR_T_MASK     ( 1u << 5 )    const char *libc_path = "/system/lib/libc.so";    const char *linker_path = "/system/bin/linker";    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;    	union u {    		long val;    		char chars[sizeof(long)];    	} d;    	j = size / 4;    	remain = size % 4;    	laddr = data;    	for (i = 0; i < j; i ++) {    		memcpy(d.chars, laddr, 4);    		ptrace(PTRACE_POKETEXT, pid, dest, d.val);    		dest  += 4;    		laddr += 4;    	}    	if (remain > 0) {    		d.val = ptrace(PTRACE_PEEKTEXT, pid, dest, 0);    		for (i = 0; i < remain; i ++) {    			d.chars[i] = *laddr ++;    		}    		ptrace(PTRACE_POKETEXT, pid, dest, d.val);    	}    	return 0;    }    #if defined(__arm__)    int ptrace_call(pid_t pid, uint32_t addr, long *params, uint32_t num_params, struct pt_regs* regs)    {    	uint32_t i;    	for (i = 0; i < num_params && i < 4; i ++) {    		regs->uregs[i] = params[i];    	}    	//    	// push remained params onto stack    	//    	if (i < num_params) {    		regs->ARM_sp -= (num_params - i) * sizeof(long) ;    		ptrace_writedata(pid, (void *)regs->ARM_sp, (uint8_t *)¶ms[i], (num_params - i) * sizeof(long));    	}    	regs->ARM_pc = addr;    	if (regs->ARM_pc & 1) {    		/* thumb */    		regs->ARM_pc &= (~1u);    		regs->ARM_cpsr |= CPSR_T_MASK;    	} else {    		/* arm */    		regs->ARM_cpsr &= ~CPSR_T_MASK;    	}    	regs->ARM_lr = 0;        	if (ptrace_setregs(pid, regs) == -1     		|| ptrace_continue(pid) == -1) {    		printf("error\n");    		return -1;    	}    	int stat = 0;  	waitpid(pid, &stat, WUNTRACED);  	while (stat != 0xb7f) {  		if (ptrace_continue(pid) == -1) {  			printf("error\n");  			return -1;  		}  		waitpid(pid, &stat, WUNTRACED);  	}  	return 0;    }    #elif defined(__i386__)    long ptrace_call(pid_t pid, uint32_t addr, long *params, uint32_t num_params, struct user_regs_struct * regs)    {    	regs->esp -= (num_params) * sizeof(long) ;    	ptrace_writedata(pid, (void *)regs->esp, (uint8_t *)params, (num_params) * sizeof(long));    	long tmp_addr = 0x00;    	regs->esp -= sizeof(long);    	ptrace_writedata(pid, regs->esp, (char *)&tmp_addr, sizeof(tmp_addr));     	regs->eip = addr;    	if (ptrace_setregs(pid, regs) == -1     		|| ptrace_continue( pid) == -1) {    		printf("error\n");    		return -1;    	}    	int stat = 0;  	waitpid(pid, &stat, WUNTRACED);  	while (stat != 0xb7f) {  		if (ptrace_continue(pid) == -1) {  			printf("error\n");  			return -1;  		}  		waitpid(pid, &stat, WUNTRACED);  	}  	return 0;    }    #else     #error "Not supported"    #endif    int ptrace_getregs(pid_t pid, struct pt_regs * regs)    {    	if (ptrace(PTRACE_GETREGS, pid, NULL, regs) < 0) {    		perror("ptrace_getregs: Can not get register values");    		return -1;    	}    	return 0;    }    int ptrace_setregs(pid_t pid, struct pt_regs * regs)    {    	if (ptrace(PTRACE_SETREGS, pid, NULL, regs) < 0) {    		perror("ptrace_setregs: Can not set register values");    		return -1;    	}    	return 0;    }    int ptrace_continue(pid_t pid)    {    	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;    }    void* get_module_base(pid_t pid, const char* module_name)    {    	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);    	} 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);    #if defined(__i386__)    	if (!strcmp(module_name, libc_path)) {    		ret_addr += 2;    	}    #endif    	return ret_addr;    }    int find_pid_of(const char *process_name)    {    	int id;    	pid_t pid = -1;    	DIR* dir;    	FILE *fp;    	char filename[32];    	char cmdline[256];    	struct dirent * entry;    	if (process_name == NULL)    		return -1;    	dir = opendir("/proc");    	if (dir == NULL)    		return -1;    	while((entry = readdir(dir)) != NULL) {    		id = atoi(entry->d_name);    		if (id != 0) {    			sprintf(filename, "/proc/%d/cmdline", id);    			fp = fopen(filename, "r");    			if (fp) {    				fgets(cmdline, sizeof(cmdline), fp);    				fclose(fp);    				if (strcmp(process_name, cmdline) == 0) {    				    /* process found */    				    pid = id;    				    break;    				}    			}    		}    	}    	closedir(dir);    	return pid;    }    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;    }    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, 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;    }    int main(int argc, char** argv) {    	pid_t target_pid;	if(argc!=2) {		printf("invalid prarams");	}	target_pid = find_pid_of(argv[1]);    	if (-1 == target_pid) {  		printf("Can't find the process\n");  		return -1;  	}     	inject_remote_process(target_pid, "/system/lib/libhookhelper.so", "hook_entry",  "I'm parameter!", strlen("I'm parameter!"));    	return 0;  }  

Android.mk文件

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES := inject.cLOCAL_SHARED_LIBRARIES := libcutils libutils libdlLOCAL_MODULE := injectinclude $(BUILD_EXECUTABLE)

3.2 libhookhelper代码

hookhelper代码如下:

#include <unistd.h>  #include <stdio.h>  #include <stdlib.h>  #include <android/log.h>  #include <elf.h>  #include <fcntl.h>  #include <sys/mman.h>#include <linker.h>#include <dlfcn.h>#define LOG_TAG "hookhelper"  #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)    extern "C" {//external function declarationextern void print();void newPrint()  {      LOGD("new Print\n");    print();}  #define LIBSF_PATH      "/system/bin/cqlmain"#define FUNCTIONNAME    "print"void *g_OriginalFunc = (void*)print;void *g_NewFunc = (void*)newPrint;void* get_module_base(pid_t pid, const char* module_name)  {      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);      } 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 replaceFunc(void *handle,const char *name, void* pNewFun, void** pOldFun)  {      if(!handle)          return;      soinfo *si = (soinfo*)handle;         Elf32_Sym *symtab = si->symtab;        const char *strtab = si->strtab;        Elf32_Rel *rel = si->plt_rel;      unsigned count = si->plt_rel_count;       unsigned idx;       bool fit = 0;    for(idx=0; idx<count; idx++)       {            unsigned int type = ELF32_R_TYPE(rel->r_info);            unsigned int sym = ELF32_R_SYM(rel->r_info);            unsigned int reloc = (unsigned)(rel->r_offset + si->base);            char *sym_name = (char *)(strtab + symtab[sym].st_name);           if(strcmp(sym_name, name)==0)           {               uint32_t page_size = getpagesize();              uint32_t entry_page_start = reloc& (~(page_size - 1));              mprotect((uint32_t *)entry_page_start, page_size, PROT_READ | PROT_WRITE);            *pOldFun = (void *)*((unsigned int*)reloc);            *((unsigned int*)reloc)= (unsigned int)pNewFun;            LOGD("find %s function at address: %p\n",name,(void*)*pOldFun);            fit = 1;            break;        }           rel++;        }      if(fit) {        LOGD("not find :%s in plt_rel\n",FUNCTIONNAME);    }} void replaceFun2() {       void * base_addr = get_module_base(getpid(), LIBSF_PATH);        LOGD("%s address = %p\n", LIBSF_PATH,base_addr);          int fd;        fd = open(LIBSF_PATH, O_RDONLY);        if (-1 == fd) {            LOGD("error\n");            return;        }          Elf32_Ehdr ehdr;        read(fd, &ehdr, sizeof(Elf32_Ehdr));          unsigned long shdr_addr = ehdr.e_shoff;          int shnum = ehdr.e_shnum;          int shent_size = ehdr.e_shentsize;          unsigned long stridx = ehdr.e_shstrndx;            Elf32_Shdr shdr;        lseek(fd, shdr_addr + stridx * shent_size, SEEK_SET);          read(fd, &shdr, shent_size);            char * string_table = (char *)malloc(shdr.sh_size);          lseek(fd, shdr.sh_offset, SEEK_SET);          read(fd, string_table, shdr.sh_size);        lseek(fd, shdr_addr, SEEK_SET);            int i;          uint32_t out_addr = 0;        uint32_t out_size = 0;        uint32_t got_item = 0;      int32_t got_found = 0;        for (i = 0; i < shnum; i++) {              read(fd, &shdr, shent_size);              if (shdr.sh_type == SHT_PROGBITS) {                int name_idx = shdr.sh_name;                        if (strcmp(&(string_table[name_idx]), ".got.plt") == 0                || strcmp(&(string_table[name_idx]), ".got") == 0) {                                out_addr = (uint32_t)(base_addr + shdr.sh_addr);                      out_size = shdr.sh_size;                                      for (i = 0; i < out_size; i += 4) {                          got_item = *(uint32_t *)(out_addr + i);                    if (got_item  == (uint32_t)g_OriginalFunc) {                              LOGD("found %s in got\n",FUNCTIONNAME);                                                 got_found = 1;                            uint32_t page_size = getpagesize();                          uint32_t entry_page_start = (out_addr + i) & (~(page_size - 1));                          mprotect((uint32_t *)entry_page_start, page_size, PROT_READ | PROT_WRITE);                                                *(uint32_t *)(out_addr + i) = (uint32_t)g_NewFunc;                        //break;                          } else if (got_item == (uint32_t)g_NewFunc) {                              LOGD("Already hooked\n");                        got_found = 1;                        break;                          }                 }                                if (got_found)                    break;               }             }          }          free(string_table);          close(fd);}int hook()                                                  {                                                                   #if 1                                                  replaceFunc( dlopen( LIBSF_PATH, RTLD_GLOBAL ),                         FUNCTIONNAME, g_NewFunc, (void**)&g_OriginalFunc);      #else                                                           replaceFun2();                                                  #endif                                                          return 0;                                                   }                                                               int hook_entry(char * a) {      hook();    return 0;  }}

Android.mk文件如下:

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES := hookhelper.cppLOCAL_C_INCLUDES += bionic/linker \LOCAL_SHARED_LIBRARIES := libcutils libutils libprint libdlLOCAL_MODULE    := libhookhelperinclude $(BUILD_SHARED_LIBRARY)

3.3 libtest文件如下:

main.c:

#include <stdio.h>//#include "print.h"int main() {	extern void print();	while(1) {		print();		sleep(2);	}	return 0;}

print.c文件如下:

#include<cutils/log.h>#undef LOG_TAG#define LOG_TAG "test"  #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)    void print() {	LOGD("my print :%p\n",(void*)print);}

Android.mk文件如下:

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES := print.cLOCAL_SHARED_LIBRARIES := libcutils libutils liblogLOCAL_MODULE    := libprintinclude $(BUILD_SHARED_LIBRARY)include $(CLEAR_VARS)LOCAL_SRC_FILES := main.cLOCAL_SHARED_LIBRARIES := libprintLOCAL_MODULE := cqlmaininclude $(BUILD_EXECUTABLE)

4. 参考文档

http://blog.csdn.net/jinzhuojun/article/details/9900105

http://www.xfocus.net/articles/200208/438.html

http://blog.csdn.net/myarrow/article/details/9630377


  相关解决方案