原文首发:看雪论坛 http://bbs.pediy.com/thread-216786.htm
对于Android 应用安全研究人员来说,Xposed 想必一定不陌生。作为一款流行的应用 hook 框架,Xposed 允许对应用进行无感知的hook。许多实用工具,例如早期的脱壳工具 Zjdroid,关闭证书强校验的 JustTrustMe,Android 恶意应用分析沙盒Cuckoo-Droid 等,均是通过 Xposed 完成。
然而,从 Android 5.0 时代起,DVM 模式被 ART 模式取代,代码执行的机制进行了大量的变动。在 ART 模式下安装 Xposed,不仅要求 root 权限,而且需要替换大量的系统库,因此其使用门槛大幅提高。
为此,我们研究并实现了一套 ART 模式下的 hook 工具:VirtualHook。通过这套工具,我们无需 root 权限,便可对应用进行无感知的 hook。本文便对这套工具进行基本的介绍。
基本原理
———————
VirtualHook 是基于以下两个框架实现的:
1. VirtualApp,这是一套插件框架,允许应用以插件的方式运行在其构造的虚拟空间中,而无需实际安装应用
2. YAHFA,这是一套 hook 框架,实现了 ART 环境下的 Java 方法 hook
下面将对其分别进行介绍。
VirtualApp
————————
首先,hook 是什么?hook 就是在应用运行过程中,注入外部的代码,从而改变原有的执行流程。因此,应用中必须存在注入代码的窗口。
例如,使用了热修复技术的应用,就是在启动时加载并应用外部的补丁代码,这类应用便是本身自带了注入代码的窗口。但是,对于逆向分析或安全研究而言,所面对的通常是一个黑盒
App,我们并不知道其是否存在注入代码的窗口,或者存在但无法被利用。为此,我们必须要额外地为应用添加注入代码的窗口。Xposed
便是这样做的:它修改了系统库,对所有应用在启动时添加了注入窗口。但是,这就需要具有 root 权限。
那么,如何在不具有 root权限的情况下实现呢?这就需要用到 VirtualApp 了。 VirtualApp的工作原理介绍可见这篇文章,简而言之,它通过代理常用系统服务的方式,在系统服务层与应用层之间添加了一层虚拟空间,从而允许在不安装应用的情况下运行应用。特别地,VirtualApp本身并不需要 root 权限。
利用VirtualApp 提供的虚拟空间,我们就可以实现很多事情了。应用启动时,会初始化 Application,此时会在应用所在的进程中调用bindApplication()。而 VirtualApp重写了相关代码,那么我们就可以在把注入代码的窗口放在这里,从而实现应用启动时,加载外部的 hook 代码。
其具体实现也非常简单,在类 VClientImpl 的方法 bindApplicationNoCheck() 中,完成了对应用 Application 的创建:
...
try {
mInstrumentation.callApplicationOnCreate(mInitialApplication);
PatchManager.getInstance().checkEnv(HCallbackHook.class);
if (conflict) {
PatchManager.getInstance().checkEnv(AppInstrumentation.class);
}
Application createdApp = ActivityThread.mInitialApplication.get(mainThread);
if (createdApp != null) {
mInitialApplication = createdApp;
}
} catch (Exception e) {
if (!mInstrumentation.onException(mInitialApplication, e)) {
throw new RuntimeException(
"Unable to create application " + mInitialApplication.getClass().getName()
+ ": " + e.toString(), e);
}
}
VActivityManager.get().appDoneExecuting();
}
我们只需要在这个方法的末尾处,添加注入窗口即可。从而,所有在 VirtualApp 中运行的应用,都会被附加上注入窗口。所以,本文所说的非 root 权限 hook 应用,更准确来说,hook 的是在 VirtualApp 中运行的应用。
YAHFA
————————
通过上述介绍,我们大致明白了如何通过 VirtualApp 实现非 root 环境下注入窗口的添加。那么接下来就需要考虑注入窗口的实现,以及如何完成目标方法的替换了,而这便是 hook 框架的工作。
我们调研了几款 hook 框架,包括 Xposed、AndFix 和 Legend,但发现如果在这里使用的话,多少都存在一定的问题:
1. Xposed 需要进行大量的代码变更,过于复杂,而且方法执行的额外开销会增多
2. AndFix 的代码量相对较小,但其进行了方法的全部替换,不支持原方法的调用;对于热修复来说也许影响不大,但对于逆向分析来说,很多时候我们是通过hook来插桩,所以原方法必须要备份以执行
3. Legend 与 AndFix 的实现方式基本一致,但试用后发现存在某些方法解析失败的问题。于是,我们重新设计实现了一套hook框架,即 YAHFA(Yet Another Hook Framework for ART),专门用于这里的代码hook。
至此,我们有了插件框架和 hook 框架,将其简单地集成,便得到了最终的 hook 工具,VirtualHook。其具有如下优点:
1. 支持 ART 模式,事实上也只支持 ART,因为这就是其设计的出发点,DVM模式下用 Xposed 就 OK 了。
2. 无需 root 权限。由于我们是通过 VirtualApp 为应用添加代码注入窗口,所以不需要修改系统本身的库,因此不需要 root 权限,安装难度降低。
3. 轻量。YAHFA 的工作目标,就是高效地运行 hook。hook方法执行所带来的额外开销仅有2、3条机器指令,执行原方法时甚至没有额外的开销。
4. 方便。由于是在 VirtualApp 中完成 hook,因此添加或删除 hook 插件后,不需要像 Xposed 那样重启设备,只需要退出目标应用再重新进入即可。
5. 精细。理论上来说,可以加载多个 hook 插件,甚至对不同应用使用不同 hook 插件。配合 VirtualApp 应用多开,能够更精细地控制 hook 的行为。
示 例
——————
在 VirtualHook 的 repo中,已经包含了一个示例用的 hook 插件demoHookPlugin,这个插件对以下方法进行了插桩:
AssetManager.open()
File()
URL.openConnection()
编译这个 hook 插件,会得到一个 apk,将其保存到设备 SD 卡的指定位置以待加载。随后启动 VirutalHook,添加并运行应用。在应用的日志中,便能看到插桩打印的日志,将上述方法调用时传入的参数打印出来。
由于 VirtualHook 使用的是 YAHFA 作为 hook 框架,因此 hook 插件的编写需要参考 YAHFA 的规则,具体可见 YAHFA 的 demoPlugin。
其他说明
————————
由于 VirtualHook 是 VirtualApp 与 YAHFA 的集成,因此其适用范围就是两者的交集:目前支持的系统是 Android5.1 和 6.0,支持的架构是 armeabi 和 x86。由于 VirtualHook 的出发点是便于安全研究,因此适配度不是其考虑的主要问题。
特别地,对于加固应用的hook,目前使用上述的 demoHookPlugin 试验了360,腾讯,梆梆和爱加密。除了梆梆之外,其他加固的应用均可被hook(爱加密把非错误的日志打印全部重定向了,所以必须通过 Log.e()打印日志)。梆梆加固的应用,在 VirtualApp上无法运行,因此作为其下游的 VirtualHook,目前对梆梆加固的应用也无法使用。希望能够有人研究解决这一问题。
另一方面,目前 VirtualHook 只是对 Java 方法进行 hook。实际上,VirtualApp中自带了对 native 方法进行 hook 的功能,看雪上已经有利用该功能进行应用脱壳的实践了。后续可以将 native
hook 一并整合起来,使 VirtualHook 的功能更强大。
最后放上代码地址。目前主要是作为思路验证和 PoC 的形式,所以其易用性和稳定度还有待提高。希望大家在试用中能够发现问题共同解决,以期将 VirtualHook 打造成为更加实用的工具。
本文由看雪论坛 nabla 原创
❤ 往期热门内容推荐
看雪众测及其渗透测试服务介绍
PHP 7 漏洞挖掘系列之一:Stack-based integer overlow
HG533路由器分析教程之三:数据流跟踪
WEB渗透测试中回显的一些技巧
报名 |《走近企业看安全》第10站 知道创宇
......
更多优秀文章,“关注看雪学院公众号”查看!
看雪论坛:http://bbs.pediy.com
微信公众号 ID:ikanxue
微博:看雪安全
投稿、合作:http://www.kanxue.com