序言
第一集该文主要就如是说VirtualAPP采用的Native Hook控制技术,不是很深入细致,因为牵涉许多C++,ELF和x86有关的习题,许多科学知识还没融会,目前只是逗留在术语的基本概念上。先期认知了在进行补足。
应用领域大背景
VirtualAPP中采用了Native Hook控制技术,主要就用作交互式APP的文档出访链接。这句话怎么认知和为何这么做呢,他们先简述呵呵VirtualAPP的大体基本原理。在VirtualAPP中开启两个交互式APP,大体分成如下表所示两部:
VirtualAPP透过交互式服务项目器端开启APP B(交互式APP) 交互式服务项目器端透过Provider建立APP B有关联的民主化,与此同时代替Intent统计数据对准全权模块 APP B民主化开启,与此同时将控制系统服务项目全权第一类,透过静态全权的形式全数代替,对准交互式服务项目器端 APP B民主化 接到intent统计数据,将intent中统计数据导出,再次代替为最终目标模块。进而同时实现卫子夫皇太子。
在前述关键性步骤他们能窥见,交互式APP是VirtaulAPP的两个子民主化。可见一斑他们在交互式app中展开文档储存或是sp操作形式时,最后的储存方向也是在VirtaulAPP的data产品目录下,这样就会增添两个难题。如果容许数个app就会可能出现文档出访武装冲突,与此同时也没努力做到APP间隔绝的目地。而VirtualAPP就是透过Native Hook控制技术化解了该难题。每一APP都有自己各别的文档储存方向。
源代码预测
上面他们来单纯介绍下他是如何同时实现的,关键性形式是VClientImpl的startIOUniformer形式,能窥见展开了储存方向态射,如在子民主化当他们出访
/data/data/http://com.xxx/产品目录时能间接态射到io.virtualapp/virtual/data/user/0/http://com.xxx
NativeEngine.redirectDirectory(“/sys/class/net/wlan0/address”, wifiMacAddressFile);
NativeEngine.redirectDirectory(“/sys/class/net/eth0/address”, wifiMacAddressFile);
NativeEngine.redirectDirectory(“/sys/class/net/wifi/address”, wifiMacAddressFile);
NativeEngine.redirectDirectory(“/data/data/” + info.packageName, info.dataDir);
NativeEngine.redirectDirectory(“/data/user/0/” + info.packageName, info.dataDir);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
NativeEngine.redirectDirectory(“/data/user_de/0/” + info.packageName, info.dataDir);
}
String libPath = VEnvironment.getAppLibDirectory(info.packageName).getAbsolutePath();
String userLibPath = new File(VEnvironment.getUserSystemDirectory(userId), info.packageName + “/lib”).getAbsolutePath();
NativeEngine.redirectDirectory(userLibPath, libPath);
NativeEngine.redirectDirectory(“/data/data/” + info.packageName + “/lib/”, libPath);
NativeEngine.redirectDirectory(“/data/user/0/” + info.packageName + “/lib/”, libPath);
该形式最后会调用IOUniformer.cpp的startUniformer形式
void IOUniformer::startUniformer(const char *so_path, int api_level, int preview_api_level) {
void *handle = dlopen(“libc.so”, RTLD_NOW);
if (handle) {
HOOK_SYMBOL(handle, faccessat);
HOOK_SYMBOL(handle, __openat);
HOOK_SYMBOL(handle, fchmodat);
HOOK_SYMBOL(handle, fchownat);
HOOK_SYMBOL(handle, renameat);
HOOK_SYMBOL(handle, fstatat64);
HOOK_SYMBOL(handle, __statfs);
HOOK_SYMBOL(handle, __statfs64);
HOOK_SYMBOL(handle, mkdirat);
HOOK_SYMBOL(handle, mknodat);
HOOK_SYMBOL(handle, truncate);
HOOK_SYMBOL(handle, linkat);
HOOK_SYMBOL(handle, readlinkat);
HOOK_SYMBOL(handle, unlinkat);
HOOK_SYMBOL(handle, symlinkat);
HOOK_SYMBOL(handle, utimensat);
HOOK_SYMBOL(handle, __getcwd);
他们知道android控制系统是基于Linux内核,文档读写操作形式也是间接的透过库函数展开控制系统调用,如他们在应用领域开发中采用的inputStream与outputStream进行文档读写最后也是调用libc.so库函数提供的形式。
所以需要努力做到就是将libc库函数的形式展开Hook,将输入参数代替为他们的交互式app方向,该过程即为native Hook。还有两个疑问点是他们怎么知道要hook哪些函数呢,只能透过查看libc的源代码,当然源代码也是公开的,能间接查看如下表所示地址。
https://www.androidos.net.cn/android/9.0.0_r8/xref/bionic/libc/bionic以faccessat形式为例,他们能看到形式参数有个pathname他们需要将改形式参数代替掉,然后再次调用控制系统形式。
extern “C” int ___faccessat(int, const char*, int);
int faccessat(int dirfd, const char* pathname, int mode, int flags)
{
// “The mode specifies the accessibility check(s) to be performed, // and is either the value F_OK, or a mask consisting of the // bitwise OR of one or more of R_OK, W_OK, and X_OK.”
if ((mode != F_OK) && ((mode & ~(R_OK | W_OK | X_OK)) != 0) &&
((mode & (R_OK | W_OK | X_OK)) == 0)) {
errno = EINVAL;
return –1;
}
具体同时实现
经过前述关键性步骤他们知道了,需要对libc链接库的形式展开hook,但是如何努力做到呢,这就不得不提Native Hook的具体同时实现了,Native Hook的同时实现形式有两种两个是PLT Hook 与 Inline Hook,同时实现基本原理牵涉so静态链接过程与ELF文档格式,汇编指令等,这块大家能百度呵呵。而罗迪采用的是两个第三方开源项目Cydia Substrate(http://www.cydiasubstrate.com/
),该项目即是inline Hook的一种具体同时实现。爱奇艺开源的xHook则是PLT Hook方案的具体同时实现。与PLT Hook方案比较,inline Hook实用场景更广泛,能力更强大。而VirualAPP透过灵活的运用宏定义,Hook两个方法只需要两个关键性步骤:
1. Hook调用
HOOK_SYMBOL(handle, faccessat);
2. 定义代替的形式
// int faccessat(int dirfd, const char *pathname, int mode, int flags);HOOK_DEF(int, faccessat, int dirfd, const char *pathname, int mode, int flags) {
int res;
const char *redirect_path = relocate_path(pathname, &res);
int ret = syscall(__NR_faccessat, dirfd, redirect_path, mode, flags);
return ret;
}
上面他们预测呵呵 HOOK_SYMBOL与HOOK_DEF宏展开过程
#define HOOK_SYMBOL(handle, func) hook_function(handle, #func, (void*) new_##func, (void**) &orig_##func)#define HOOK_DEF(ret, func, …) \ static ret (*orig_##func)(__VA_ARGS__); \
static ret new_##func(__VA_ARGS__)
在编译期间会展开宏代替,HOOK_SYMBOL(handle, faccessat)最后代替为如下表所示格式 ;
hook_function(handle,faccessat,(void*) new_faccessat,(void**)&orig_faccessat)
HOOK_DEF最后会代替为如下表所示格式:
static int (*orig_faccessat)(int dirfd, const char *pathname, int mode, int flags);
static int new_faccessat(int, faccessat, int dirfd, const char *pathname, int mode, int flags) {
int res;
const char *redirect_path = relocate_path(pathname, &res);
int ret = syscall(__NR_faccessat, dirfd, redirect_path, mode, flags);
return ret;
}
能窥见透过宏代替,他们定义了两个函数指针,和两个newfaccessat的代替函数,最后调用hook_function形式同时实现Hook,hook_function内部调用MSHookFunction函数,该函数即为Cydia Substrate提供的能力。
static inline void hook_function(void *handle, const char *symbol, void *new_func, void **old_func) {
void *addr = dlsym(handle, symbol);
if (addr == NULL) { return; }
MSHookFunction(addr, new_func, old_func);
}
总结
相信大家对Native Hook在整体上有了初步的认识,学习Native Hook不能一蹴而就而是个缓慢的过程。先期该文为大家分享MSHookFunction的具体同时实现基本原理