AssetHook:Android应用资源数据运行时编辑工具

简介: 本文讲的是AssetHook:Android应用资源数据运行时编辑工具,AssetHook是一个工具,它可以让Android安全研究人员和普通用户能够在无需修改APK本身的情况下随时修改Android应用程序的部分Asset。
本文讲的是 AssetHook:Android应用资源数据运行时编辑工具AssetHook是一个工具,它可以让Android安全研究人员和普通用户能够在无需修改APK本身的情况下随时修改Android应用程序的部分Asset。这样的修改使研究人员可以改变嵌入式数据,以更好地评估和测试移动应用程序。目前来看AssetHook比现有方法更容易使用,且比传统方法更有效。

背景

去年年底,我开始关注Android启用React Native 后 Facebook的新框架,它将跨平台移动开发统一到JavaScript,显然JavaScript是一种不需要介绍的语言。在React Native之前,在JavaScript中构建跨平台移动应用程序的主要方法是使用PhoneGap(…或者现在是Cordova吗?甚至不让我从Ionic开始)。这些都是基于将JavaScript加载到Webview中(UIWebView在iOS上,WebView在Android上)的主要应用程序逻辑。然后,开发人员可以在平台的“本机”语言中编写一些平台特定的代码,并将它们与幽灵一般的webview魔术FFI连接在一起。

React Native将这种设计(也可能是理由)一脚踢开,然后颠覆了传统。它不是使用webview和HTML / CSS进行渲染,它将JavaScript声明的UI映射到平台的本地UI工具包,并嵌入WebKit的JavaScriptCore(JSC)库来运行该JavaScript,完全避免了平台的Webview实现。JSC支持在没有JIT的情况下解释JavaScript,这在iOS上是必需的,因为它的安全模型是基于不允许任何人生成可执行内存的(而且人们说OpenBSD的人是Luddites for W ^ X …); 最后我检查过,V8只是JIT(新的ignition interpreter似乎并没有改变,因为“ JIT代码生成仍然是IC和代码存根 ”)。

作为我最初在Android上进行React Native的一部分,我试图在应用程序中注入额外的JavaScript代码,以将开发控制台REPL加载(并执行janky函数hook)。所以,我在这种情况下做了一个通常的工作,并为Android的android.content.res.AssetManager类写了一个Xposed函数hook。..之后我再没有做什么。

Android使用AssetManager该类作为应用程序的界面来访问嵌入在其APK中的特定类型的文件资源(特别是APK中的assets/目录中)。鉴于我知道(从开放一个发布版本的React Native应用程序)主要的后处理JavaScript软件包作为资产存储,所以hook不起作用是非常奇怪的。然后,我通过React Native的Android代码库开始测试,很快就发现使用C API为Android的资产管理器加载了C ++代码,这解释了为什么Java函数挂起不起作用。

因为我想要修改这些软件包的内容,而不需要创建和签名修改的APK(然后需要更多的hook来欺骗他们的签名),我设置了构建一个工具来hook这些资源负载。我在C ++中写了最初的POC,然后在Rust中重写。

(A)AssetHook

AssetHook是一款LD_PRELOAD用于Android应用程序的函数hook库。它hook了Android的内部资产管理代码,并将资产文件加载从合法(即签名的)APK重定向到设备本地文件系统上的单独位置。(A)AssetHook的初始版本“AAssetHook”(两个“A”)拦截了Android 公共 AAssetManager C API的调用,其实际上是用extern "C"C ++编写的。然而,由于这个API只是一个直接由Java 类使用的Android 内部类的封装,所以我把它重写为“AssetHook”(一个'A')来代替底层的C ++ API。 AssetManagerandroid.content.res.AssetManager

如果没有像AssetHook这样的东西的话,替换Android资产将需要解压APK,替换资产文件,重新打包APK,可能会重新对齐,签署新的APK文件,然后安装它。这不但是一个繁琐和缓慢的过程(特别是APK复制到设备并为更大的应用程序安装过程),还必须处理新的签名打破跨应用程序签名检查的后果。对于使用自定义权限,共享用户ID或自定义IPC访问控制的应用程序组,此新签名将阻止修改的应用程序与其他应用程序进行交互或完全不起作用。然后需要额外的hook来欺骗修改后的APK的签名证书以匹配原来的APK。此外,如果没有更多根深蒂固和灵活的功能hook基础架构(例如修改系统分区二进制文件的Xposed),这种hook在Android上可能是不可能的。使用这种框架的一个关键问题是由于需要移植工作,因此必然会延迟支持新的Android版本。

C API Hooking 使用了 LD_PRELOAD

C API hooking变体(“AAssetHook”)是由vanilla的 LD_PRELOADhook来实现的,它声明了一些重复的函数符号,尽管动态链接的魔力 – 在从其二进制文件外部访问时重写对这些函数的调用。然后在dlopen(3)/ dlsym(3)(在Unix上)使用一个Rust包装库来根据需要代理对原始函数的调用。之后,它会检查一个APK中的给定文件路径是否与设备文件系统上的现有路径匹配,并欺骗C API返回磁盘文件的文件内容,而不是in-

C++ API Hooking 使用了 LD_PRELOAD

由于资产管理器的C ++实现不是公共API,C ++ APIhook变体(“AssetHook”)稍微复杂一点,这在很大程度上依赖于多态性,并且在较小的Android版本中可能会发生变化。当在C ++中使用多态时,通常将通过动态调度处理虚拟方法调用。在大多数“平稳”平台上,通过将虚拟表(vtable)指针作为类的内存结构的第一个元素之一来实现。该指针在构造期间设置,并指向一个填充有该类使用的特定虚拟方法的函数指针的表。LD_PRELOAD在这种情况下,函数hook非常有限,因为它只能挂接导出符号的二进制函数调用,而动态调度调用则使用直接函数指针。这样可以避免基于vtable的呼叫被LD_PRELOAD符号覆盖直接挂起。此外,这些函数指针的顺序很可能会在次级类定义更改时发生更改。在不同的编译器之间也是不一致的,通常可能难以推断出多个版本的二进制文件。

注意:这完全取决于编译器,但是这一点在Unix上的Clang和GCC(至少对于x86 / amd64和ARM / AArch64来说都是一致的)。

例如,下面的代码片段的对象可以被布置,如下图所示:

#include <stdio.h>struct Base {
  virtual void foo() {
    puts("base!");
  }
  size_t a = (size_t)-};struct Derived : public Base {
  virtual void foo() {
    puts("derived!");
  }
  size_t b = (size_t)-};struct DDerived : public Derived {
  void foo() final override {
    puts("dderived!");
  }
  size_t c = (size_t)-};void call_foo(Base& br.foo();}int main() {
  Base b;
  Derived d;
  DDerived dd;
  call_foo(b);
  call_foo(d);
  call_foo(dd);
  return 0;}

 AssetHook:Android应用资源数据运行时编辑工具

功能搜索和vtable插槽映射

处理vtable排序的波动的一种方法是将给定的类“vtable”与其二进制文件的符号表进行交叉引用(用binutils的GPL bfd.h或libelfin解析)。使用手中的函数地址,可以对vtable进行交叉引用以找到其偏移量。然而,这可能不起作用,因为一些虚拟方法函数可能没有符号,就像Android资产管理器的C ++实现一样。另一种方法是扫描这种不符号的函数的原始字节,但这不太可能跨越多个二进制版本。 

事实上,这是完全可能的(使用类似Capstone的东西)去解析调用目标类的虚拟方法并提取这些方法的vtable偏移量的符号符号函数的汇编。

vtable Slot Knocking

AssetHook的C ++ APIhook实现使用了最后一种方法的一个变体,依靠这样一个事实,即将虚拟方法调用的C API本身就是具有ABI稳定性保证的公共API。AssetHook不是分析C API函数的指令来剔除vtable偏移量,而是创建一个假的C ++对象,并使用它来配置vtable。该对象vtable指针指向一个虚构的vtable,其中包含一系列报告调用顺序的函数指针。AssetHook将该对象作为嵌入到void*掩码包装结构体中的指针传递给C API,然后C API通过编译器提供的偏移量调用关联的虚拟方法。执行此调用时,将触发嵌入式函数指针,暴露给定操作的vtable偏移量。这允许通过调用这个假的对象上已知的C API函数来逐个获取实际的vtable顺序,以获得它们包装的C ++方法的vtable偏移量。

注意:对于特殊的涉及 thunk的 “复杂”类,需要更加动态地分析vtable,因为类别的vtable段中的“正常”成员函数指针实际上是由编译器生成的包装函数。该函数相应地移动this指针,并从实际类的更大的vtable中的其他地方调用“真实”成员函数指针。

hook虚拟方法

之后,在返回对象指针LD_PRELOAD的AssetManager类的“公共”非虚拟方法的变形符号名称上创建一个类型的hookAsset。这个hook确定文件是否应该被hooking,如果是这样,返回一个指向一个修改后的Asset对象的指针,其中一个vtable包含了函数hook。

例子:

在这个例子中,我们将使用AssetHook将我们自己的JavaScript文件交换到Tic-tac-toe示例应用程序中(参考React Native文档,我必须传递–dev false给react-native build它来使其大部分应用程序成为最小化的)。我们假设您按照文件中的描述安装了它。

1、安装一个“release”版本的应用程序(为了尽可能的缩小,AssetHook可以同时发布和调试Android APK版本)在一个根深蒂固的测试设备上(AssetHook已知可以与Android 5.x,6.x和7.x一起用32位和64位ARM,以及32位x86上的Android O Developer Preview)。

2、从APK文件中提取assets/index.android.bundle(从嵌入的Android来源app/build目录或使用该设置adb shell pm list packages -f | grep <pkg>和adb pull)。

3、修改文件并注入JavaScript alert(…)。

4、运行以下命令:

$ adb push path/to/index.android.bundle /data/local/tmp/assethook/<pkg>/assets/
$ adb shell su -c 'setprop wrap.<pkg> LD_PRELOAD=/data/local/tmp/lib/libassethook_cppapi.so'

注意: React Native使用32位二进制文件,甚至在64位Android上。因此,32位模式下进程加载,我们需要使用32位版本的AssetHook。

5、启动应用程序(如果已经打开,请先关闭它)。

AssetHook:Android应用资源数据运行时编辑工具

未来的工作

主要优先事项是在执行模式下完全启用SEAndroid时支持Android。现在,AssetHook要求将SELinux置于允许模式,因为替换文件存在于Google试图通过SELinux限制访问现代Android版本的共享临时目录中。我正在寻求支持从应用程序自己的内部目录加载替换资产文件,但这可能需要额外的工具来将文件上传到设备上。




原文发布时间为:2017年6月3日
本文作者:Change
本文来自云栖社区合作伙伴嘶吼,了解相关信息可以关注嘶吼网站。
目录
相关文章
|
5天前
|
缓存 移动开发 Android开发
构建高效Android应用:从优化用户体验到提升性能表现
【4月更文挑战第18天】 在移动开发的世界中,打造一个既快速又流畅的Android应用并非易事。本文深入探讨了如何通过一系列创新的技术策略来提升应用性能和用户体验。我们将从用户界面(UI)设计的简约性原则出发,探索响应式布局和Material Design的实践,再深入剖析后台任务处理、内存管理和电池寿命优化的技巧。此外,文中还将讨论最新的Android Jetpack组件如何帮助开发者更高效地构建高质量的应用。此内容不仅适合经验丰富的开发者深化理解,也适合初学者构建起对Android高效开发的基础认识。
2 0
|
5天前
|
移动开发 Android开发 开发者
构建高效Android应用:采用Kotlin进行内存优化的策略
【4月更文挑战第18天】 在移动开发领域,性能优化一直是开发者关注的焦点。特别是对于Android应用而言,由于设备和版本的多样性,确保应用流畅运行且占用资源少是一大挑战。本文将探讨使用Kotlin语言开发Android应用时,如何通过内存优化来提升应用性能。我们将从减少不必要的对象创建、合理使用数据结构、避免内存泄漏等方面入手,提供实用的代码示例和最佳实践,帮助开发者构建更加高效的Android应用。
5 0
|
7天前
|
缓存 移动开发 Java
构建高效的Android应用:内存优化策略
【4月更文挑战第16天】 在移动开发领域,尤其是针对资源有限的Android设备,内存优化是提升应用性能和用户体验的关键因素。本文将深入探讨Android应用的内存管理机制,分析常见的内存泄漏问题,并提出一系列实用的内存优化技巧。通过这些策略的实施,开发者可以显著减少应用的内存占用,避免不必要的后台服务,以及提高垃圾回收效率,从而延长设备的电池寿命并确保应用的流畅运行。
|
7天前
|
Android开发 开发者
Android网络和数据交互: 请解释Android中的AsyncTask的作用。
Android&#39;s AsyncTask simplifies asynchronous tasks for brief background work, bridging UI and worker threads. It involves execute() for starting tasks, doInBackground() for background execution, publishProgress() for progress updates, and onPostExecute() for returning results to the main thread.
9 0
|
7天前
|
网络协议 安全 API
Android网络和数据交互: 什么是HTTP和HTTPS?在Android中如何进行网络请求?
HTTP和HTTPS是网络数据传输协议,HTTP基于TCP/IP,简单快速,HTTPS则是加密的HTTP,确保数据安全。在Android中,过去常用HttpURLConnection和HttpClient,但HttpClient自Android 6.0起被移除。现在推荐使用支持TLS、流式上传下载、超时配置等特性的HttpsURLConnection进行网络请求。
8 0
|
9天前
|
搜索推荐 开发工具 Android开发
安卓即时应用(Instant Apps)开发指南
【4月更文挑战第14天】Android Instant Apps让用户体验部分应用功能而无需完整下载。开发者需将应用拆分成模块,基于已上线的基础应用构建。使用Android Studio的Instant Apps Feature Library定义模块特性,优化代码与资源以减小模块大小,同步管理即时应用和基础应用的版本。经过测试,可发布至Google Play Console,提升用户便利性,创造新获客机会。
|
10天前
|
Java API 调度
安卓多线程和并发处理:提高应用效率
【4月更文挑战第13天】本文探讨了安卓应用中多线程和并发处理的优化方法,包括使用Thread、AsyncTask、Loader、IntentService、JobScheduler、WorkManager以及线程池。此外,还介绍了RxJava和Kotlin协程作为异步编程工具。理解并恰当运用这些技术能提升应用效率,避免UI卡顿,确保良好用户体验。随着安卓技术发展,更高级的异步处理工具将助力开发者构建高性能应用。
|
10天前
|
编解码 人工智能 测试技术
安卓适配性策略:确保应用在不同设备上的兼容性
【4月更文挑战第13天】本文探讨了提升安卓应用兼容性的策略,包括理解平台碎片化、设计响应式UI(使用dp单位,考虑横竖屏)、利用Android SDK的兼容工具(支持库、资源限定符)、编写兼容性代码(运行时权限、设备特性检查)以及优化性能以适应低端设备。适配性是安卓开发的关键,通过这些方法可确保应用在多样化设备上提供一致体验。未来,自动化测试和AI将助力应对设备碎片化挑战。
|
Java 开发工具 Android开发
Android Studio运行报错:无法访问XXX......请删除该文件或确保该文件位于正确的类路径子目录中
今天运行一个项目发现运行不起来了,报错 错误: 无法访问XXX 错误的类文件: C:\Users\xxx\.gradle\caches\transforms-2\files-2.1\xxx\xxx(xxx/xxx/xxx.class) 错误的 RuntimeInvisibleParameterAnnotations 属性: xxxx 请删除该文件或确保该文件位于正确的类路径子目录中。
1032 0
|
Android开发 Kotlin
【错误记录】Android Studio 运行报错 ( There is not enough memory to perform the requested operation. )
【错误记录】Android Studio 运行报错 ( There is not enough memory to perform the requested operation. )
568 0
【错误记录】Android Studio 运行报错 ( There is not enough memory to perform the requested operation. )