一文带你掌握android的zygote注入

2,193 阅读4分钟

1.zygote注入的原理

zygote注入是属于全局注入的方式,它主要是依赖于fork()子进程方式进行注入的。 目前市面上比较成熟的注入工具xposed就是基于zygote的全局注入。

它有两大优点:主要在于zygote是系统进程,通过系统进程fork出来后它就具备隐蔽性,强大性。

2.注入实现前准备

zygote进行注入目的:主要是将指定的模块注入到目标进程。 注入器作用:将指定的模块注入到zygote进程

注入事项: 目标进程需要在zygote注入成功后再启动 控制权交还

so模块: so特定功能、控制权交还 libdvm.so dvmLoadNativeCode、判断当前启动的进程是否是 目标进程,获取App进程信息,匹配目标App进程字符串

3.注入实现流程:

从注入的整体来看,zygote注入流程和ptrace注入很相似,由于zygote注入使用了shellcode 方式远程调用函数,zygote属于系统级进程,实现更复杂。

4.注入器实现步骤:

1.关闭selinux 
	/sys/fs/selinux、/proc/mounts  
2.附加到zygote进程,保存进程现场  
	ptrace_attach、waitpid、ptrace_getregs、ptrace_setregs 、memcpy
3.获取zygote进程中关键函数的地址(dlopen/dlsym/mmap/munmap/mprotect都属于系统函数)
	该函数在so模块中的偏移地址=本地函数地址-本地so模块基址
	远程函数地址=远程so模块基址+该函数在so模块中的偏移地址
	注意:本地进程和远程进程都加载的so模块
4.远程调用mmap函数(r0-r3)
	设置推栈布局
5.配置shellcode
	调用dlopen函数加载指定的模块
	调用dlsym函数获取模块中关键函数地址
	调用已获取的关键函数
6.远程调用shellcode
7.调用munmap函数释放内存
8.恢复进程、恢复寄存器现场、释放附加
    
    

5.zygote注入代码实现

//zygote注入进程模块
//参数1:要注入的pid,参数2:要注入的so模块,参数3:要注入的函数,参数4:注入的函数参数
int injectProcess(pid_t pid, char *libraryPath, char *entryFunctionName, char *functionArg) {
  //变量定义
      int ret=0, waitStatus=0, shellcodeDataIndex=0;
  char shellcodeDataBuffer[0x400]={0};
  struct pt_regs orignalRegisters={0}, usingRegisters={0};
  void *libcHandler=NULL, *linkerHandler=NULL;
  void *mmap_self_addr=NULL, *munmap_self_addr=NULL, *mprotect_self_addr=NULL, 
  	*dlopen_self_addr=NULL, *dlsym_self_addr=NULL, *dlclose_self_addr=NULL, *dlerror_self_addr=NULL;
  void *mmap_remote_addr=NULL, *munmap_remote_addr=NULL, *mprotect_remote_addr=NULL,
  	*dlopen_remote_addr=NULL, *dlsym_remote_addr=NULL, *dlclose_remote_addr=NULL, *dlerror_remote_addr=NULL;
  void *mmap_return=NULL;

  extern uint32_t _inject_code_start, _inject_code_end,  _dlopen_param2, _saved_cpsr_value, _dlopen_addr, _dlsym_addr, 
  	_dlclose_addr, _dlerror_addr, _so_path_addr, _so_init_func_addr, _so_func_arg_addr, _saved_r0_pc_addr,
  	_so_path_value, _so_init_func_value, _so_func_arg_value, _saved_r0_pc_value;

  if (libraryPath == NULL || entryFunctionName == NULL || functionArg == NULL)
  	return -1;
  //获取模块基地址
  if (getModuleBase(pid, libraryPath) != (void *)-1) {
  	
  	return 0;
  }
  

  ret = GetRegs(pid, &orignalRegisters);
  if (!ret) {
  	do {

  		// 拷贝数据
  		memcpy(&usingRegisters, &orignalRegisters, sizeof(orignalRegisters));

  		// 获取 remote mmap,munmap,mprotect 函数地址
  		libcHandler = dlopen(LIBC_PATH, RTLD_NOW);
  		mmap_self_addr = dlsym(libcHandler, MMAP_NAME);
  		munmap_self_addr = dlsym(libcHandler, MUNMAP_NAME);
  		mprotect_self_addr = dlsym(libcHandler, MPROTECT_NAME);
  		mmap_remote_addr = getRemoteSymbolAddress(pid, LIBC_PATH, mmap_self_addr);
  		munmap_remote_addr = getRemoteSymbolAddress(pid, LIBC_PATH, munmap_self_addr);
  		mprotect_remote_addr = getRemoteSymbolAddress(pid, LIBC_PATH, mprotect_self_addr);

  		// 远程调用前对mmap的准备
  		usingRegisters.uregs[0] = 0;
  		usingRegisters.uregs[1] = 0x4000;
  		usingRegisters.uregs[2] = PROT_EXEC | PROT_READ | PROT_WRITE;
  		usingRegisters.uregs[3] = MAP_ANONYMOUS | MAP_PRIVATE;
  		usingRegisters.uregs[13] -= sizeof(long);
  		ptrace(PTRACE_POKEDATA, pid, (void *)(usingRegisters.uregs[13]), 0);
  		usingRegisters.uregs[13] -= sizeof(long);
  		ptrace(PTRACE_POKEDATA, pid, (void *)(usingRegisters.uregs[13]), (void *)0xffffffff);

  		usingRegisters.uregs[15] = (long)mmap_remote_addr;
  		if (usingRegisters.uregs[15] & 1u) {
  			usingRegisters.uregs[15] &= (~1u);
  			usingRegisters.uregs[16] |= CPSR_T_MASK;
  		} else {
  			usingRegisters.uregs[16] &= ~CPSR_T_MASK;
  		}

  		// 远程进程中调用mmap
  		ret = invokeRemoteSyscall(pid, &usingRegisters);
  		if (ret < 0) break;

  		// check mmap result.
  		ret = GetRegs(pid, &usingRegisters);
  		if (ret < 0)  break;

  		// 保存mmap的返回值数据
  		mmap_return = (void *)(usingRegisters.uregs[0]);

  		linkerHandler = dlopen(LIBDL_NAME, RTLD_NOW);
  		dlopen_self_addr = dlsym(linkerHandler, "dlopen");
  		dlsym_self_addr = dlsym(linkerHandler, "dlsym");
  		dlclose_self_addr = dlsym(linkerHandler, "dlclose");
  		dlerror_self_addr = dlsym(linkerHandler, "dlerror");
  		dlopen_remote_addr = getRemoteSymbolAddress(pid, LINKER_PATH, dlopen_self_addr);
  		dlsym_remote_addr = getRemoteSymbolAddress(pid, LINKER_PATH, dlsym_self_addr);
  		dlclose_remote_addr = getRemoteSymbolAddress(pid, LINKER_PATH, dlclose_self_addr);
  		dlerror_remote_addr = getRemoteSymbolAddress(pid, LINKER_PATH, dlerror_self_addr);

  		if (dlopen_remote_addr == NULL || dlsym_remote_addr == NULL || dlclose_remote_addr == NULL 
  			|| dlerror_remote_addr == NULL) {

  			break;
  		}

  		memcpy(&usingRegisters, &orignalRegisters, sizeof(orignalRegisters));
  		memset(shellcodeDataBuffer, 0, 0x400);
  		memcpy(shellcodeDataBuffer, &_inject_code_start, (&_inject_code_end - &_inject_code_start) * sizeof(uint32_t));
  		*(uint32_t*) (shellcodeDataBuffer+(&_dlopen_addr - &_inject_code_start)*sizeof(uint32_t)) = (uint32_t)dlopen_remote_addr;
  		*(uint32_t*) (shellcodeDataBuffer+(&_dlsym_addr - &_inject_code_start)*sizeof(uint32_t)) = (uint32_t)dlsym_remote_addr;
  		*(uint32_t*) (shellcodeDataBuffer+(&_dlclose_addr - &_inject_code_start)*sizeof(uint32_t)) = (uint32_t)dlclose_remote_addr;
  		*(uint32_t*) (shellcodeDataBuffer+(&_dlerror_addr - &_inject_code_start)*sizeof(uint32_t)) = (uint32_t)dlerror_remote_addr;

  		strncpy(shellcodeDataBuffer+(&_so_path_value - &_inject_code_start)*sizeof(uint32_t), libraryPath, 255);
  		strncpy(shellcodeDataBuffer+(&_so_init_func_value - &_inject_code_start)*sizeof(uint32_t), entryFunctionName, 255);
  		if (functionArg != NULL) {
  			memcpy(shellcodeDataBuffer+(&_so_func_arg_value - &_inject_code_start)*sizeof(uint32_t), functionArg, 255);
  		}

  		*(uint32_t*)(shellcodeDataBuffer+(&_saved_cpsr_value - &_inject_code_start)*sizeof(uint32_t)) = orignalRegisters.uregs[16];
  		memcpy(shellcodeDataBuffer+(&_saved_r0_pc_value - &_inject_code_start)*sizeof(uint32_t), &(orignalRegisters.uregs[0]), 16 * sizeof(long));

  		usingRegisters.uregs[13] = (uint32_t)(mmap_return + 0x3c00);
  		
  		*(uint32_t*)(shellcodeDataBuffer+(&_so_path_addr - &_inject_code_start)*sizeof(uint32_t))
  			= (uint32_t)((char *)usingRegisters.uregs[13] + (&_so_path_value - &_inject_code_start) * sizeof(uint32_t));
  		*(uint32_t*)(shellcodeDataBuffer+(&_so_init_func_addr - &_inject_code_start)*sizeof(uint32_t))
  			= (uint32_t)((char *)usingRegisters.uregs[13] + (&_so_init_func_value - &_inject_code_start) * sizeof(uint32_t));
  		*(uint32_t*)(shellcodeDataBuffer+(&_so_func_arg_addr - &_inject_code_start)*sizeof(uint32_t))
  			= (uint32_t)((char *)usingRegisters.uregs[13] + (&_so_func_arg_value - &_inject_code_start) * sizeof(uint32_t));
  		*(uint32_t*)(shellcodeDataBuffer+(&_saved_r0_pc_addr - &_inject_code_start)*sizeof(uint32_t))
  			= (uint32_t)((char *)usingRegisters.uregs[13] + (&_saved_r0_pc_value - &_inject_code_start) * sizeof(uint32_t));

  		PTRACE_POKEDATA
  		shellcodeDataIndex = 0;
  		while (shellcodeDataIndex < 0x400 / sizeof(uint32_t)) {
  			ptrace(PTRACE_POKEDATA, pid, (void *)(usingRegisters.uregs[13]+shellcodeDataIndex * sizeof(uint32_t))
  				, (void *)*(uint32_t *)((uint32_t *)shellcodeDataBuffer+shellcodeDataIndex));
  			shellcodeDataIndex++;
  		}

  		usingRegisters.uregs[15] = usingRegisters.uregs[13];
  		usingRegisters.uregs[16] &= ~CPSR_T_MASK;

  		// 在远程进程中调用shellcodeDataBuffer
  		ret = invokeRemoteShellcode(pid, &usingRegisters);
  		if (ret < 0) break;

  		// 检查shellcode代码执行返回效果
  		ret = GetRegs(pid, &usingRegisters);
  		if (ret < 0) break;

  		if ((int)(usingRegisters.uregs[1]) == 1) {
  			// dlopen failed in shellcodeDataBuffer
  			int msg_index = 0;
  			uint32_t *err_msg = (uint32_t *) calloc(0x101, 1);
  			*(char *)err_msg = 0;

  			while (msg_index < 0x40) {
  				err_msg[msg_index] = ptrace(PTRACE_PEEKDATA, pid, (void *)(usingRegisters.uregs[2] + msg_index * sizeof(uint32_t)), 0);
  				msg_index++;
  			}
  			
  			LOGE("dlerror failed:%s\n", (char *)err_msg);

  			free(err_msg);
  		} 

  		// prepare call munmap in the remote process
  		memcpy(&usingRegisters, &orignalRegisters, sizeof(orignalRegisters));
  		
  		usingRegisters.uregs[0] = (long)mmap_return;
  		usingRegisters.uregs[1] = 0x4000;

  		usingRegisters.uregs[15] = (long)munmap_remote_addr;
  		if (usingRegisters.uregs[15] & 1u) {
  			usingRegisters.uregs[15] &= (~1u);
  			usingRegisters.uregs[16] |= CPSR_T_MASK;
  		} else {
  			usingRegisters.uregs[16] &= ~CPSR_T_MASK;
  		}

  		// call munmap in the remote process, don't need check result
  			//because we will restore remote process to the original status right after now.
  		ret = invokeRemoteSyscall(pid, &usingRegisters);
  		if (ret < 0) break;

  		ret = GetRegs(pid, &usingRegisters);
  		if (ret < 0) break;

  		// 检测状态
  		do {
  			LOGE("%s:%d r0:%ld, orig_r0:%ld, r7:%ld, pc:%ld, cpsr:%ld\n", __FUNCTION__, __LINE__
  				, orignalRegisters.ARM_r0, orignalRegisters.ARM_ORIG_r0, orignalRegisters.ARM_r7, orignalRegisters.ARM_pc, orignalRegisters.ARM_cpsr);
  			if (orignalRegisters.ARM_r0 == -0x204) {
  				LOGE("%s:%d r0 == -0x204\n", __FUNCTION__, __LINE__);
  				orignalRegisters.ARM_r0 = -11;
  				if (orignalRegisters.ARM_cpsr & 0x20) {
  					LOGE("%s:%d thumb\n", __FUNCTION__, __LINE__);
  					orignalRegisters.ARM_pc -= 2;
  					orignalRegisters.ARM_r7 = 0;
  				} else {
  					LOGE("%s:%d arm\n", __FUNCTION__, __LINE__);
  					orignalRegisters.ARM_pc -= 4;
  					orignalRegisters.ARM_r7 = 0;
  				}

  				break;
  			}

  			if (orignalRegisters.ARM_r0 != -0x200 && orignalRegisters.ARM_r0 != -514) {
  				LOGE("%s:%d r0 not -0x200 and -514\n", __FUNCTION__, __LINE__);
  				if (orignalRegisters.ARM_r0 != -513)
                                      {
                                          break;
  				}

  				LOGE("%s;%d r0 == -513\n", __FUNCTION__, __LINE__);
  			}

  			if (orignalRegisters.ARM_ORIG_r0 != -0x200) {
  				if (orignalRegisters.ARM_ORIG_r0 == -514) {
  					LOGE("%s:%d orig_r0 == -514\n", __FUNCTION__, __LINE__);
  					orignalRegisters.ARM_r0 = -4;
  					break;
  				}

  				LOGE("%s:%d orig_r0 not -514\n", __FUNCTION__, __LINE__);
  			}

  			if (orignalRegisters.ARM_ORIG_r0 == -513) {
  				LOGE("%s:%d orig_r0 == -513\n", __FUNCTION__, __LINE__);
  				orignalRegisters.ARM_r0 = -4;
  				break;
  			}

  			if (orignalRegisters.ARM_ORIG_r0 == -0x204) {
  				LOGE("%s;%d orig_r0 == -0x204\n", __FUNCTION__, __LINE__);
  				orignalRegisters.ARM_r0 = -4;
  				break;
  			}

  			orignalRegisters.ARM_r0 = orignalRegisters.ARM_ORIG_r0;
  			if (orignalRegisters.ARM_cpsr & 0x20) {
  				orignalRegisters.ARM_pc -= 2;
  			} else {
  				orignalRegisters.ARM_pc -= 4;
  			}
  		} while (0);
  	} while (0);

  	// 远程进程刚刚连接时,将其恢复到原始状态。
  	if (ptrace(PTRACE_SETREGS, pid, NULL, &orignalRegisters) < 0) {
                     //ptrace失败 
  		LOGE("restore original registers failed:%s\n", strerror(errno));
  	}
  }

  return Detach(pid);
}