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