Android React Native应用逆向分析初探

Android React Native应用逆向分析初探

前言

随着移动互联网时代的到来,用户在移动设备上花费的时间越来越多,不仅是因为移动设备方便携带,而且还因为层出不穷的大量应用提供为用户使用,以往在电脑上才能做的事情,现在仅靠一部手机就可以解决了。

当前的移动设备厂商很多,但是被广泛使用的主流系统却只有两个,Android和iOS,因此现在大多数应用都会有两个版本,Android版本和iOS版本。然而这两种应用的开发方式却完全不同,移动客户端开发人员不得不分成两个队伍,分别开发Android应用和iOS应用,尽管这两个应用的功能、界面、逻辑都是完全相同的,隐形中就带来了重复造轮子的问题。

Facebook在2015年开源了React Native技术,使用这项技术进行开发时主要使用JavaScript语言和React库,只要掌握了这项技术,那么同时开发Android和iOS应用将变得可能。

尽管这项开发技术的应用已经如此的广泛,但是本人通过搜索发现没有任何一个博客或者帖子是对这类Android应用的逆向分析,不论此种类型的Android应用在逆向工程上的难易程度如何,总该有一些博客对此进行阐述,因此也就产生了本篇文章。

原理

React Native原理简介

React Native框架如下图所示:Alt pic

从上图中可以看出编写一次JS代码就可以在三种不同的前端显示,分别为Android、iOS、Browser,不过针对不同的前端需要做出相应的调整与适配。

当页面真正渲染出来以后,它实际上还是Native代码,React Native的作用就是把JavaScript代码映射成Native代码以及实现两端的通信。可以这么理解,对于开发者编写的JS代码,如果是用于显示UI界面的代码则转化为Android或者iOS界面组件代码并显示,如果是非UI界面的代码则转化为Android或者iOS平台上支持的响应逻辑处理操作。

Android React Native原理简介

Android React Native框架大致分为三层,如下图所示: Alt pic

  • Java层:该层主要提供了Android的UI渲染器UIManager(将JavaScript映射成Android Widget组件)以及一些其他的常用的工具组件(例如:Fresco用于图片加载、Okhttp用于网络请求)等。
  • C++层:该层主要完成了Java与JavaScript的通信以及执行JavaScript代码两件工作,其中JavaScriptCore为解析JS的核心部分,iOS使用的是内置的JavaScriptCore,Android使用的是WebKit的jsc.so。
  • JS层:该层提供了各种供开发者使用的组件以及一些工具库,也是开发者编写的主JS执行入口。

使用Android React Native技术在对Android应用打包时需要先对所有的JS文件打包,打包JS文件的命令有两个:

  • react-native bundle:该命令会整合、优化、混淆所有的JS文件,最后保存到Apk文件中assets目录中的index.android.bundle文件,该文件就是个JS格式的文件。
  • react-native unbundle:该命令除了生成上面提到的index.android.bundle文件之外,还会生成各个单独的未整合JS文件(但会被优化),全部放在Apk文件中assets目录中的js-modules目录下。

react-native bundle命令较为常见,react-native unbundle命令较为少见。

逆向

样本

随着React Native技术的广泛使用,现在也有越来越多的应用开始尝试使用这项技术进行开发,本文使用图曰Android版本进行逆向分析,可以下载并解压出tuyue.apk安装包。

静态分析

  1. 使用解压缩软件(WinRAR等)打开tuyue.apk,在assets目录中发现了index.android.bundle文件,可判断出该应用使用了Android React Native框架。可在工作目录创建新文件夹tuyue_files用于存放分析过程中产生的文件等,进而把index.android.bundle解压到tuyue_files文件夹中。
  2. 使用Notepad++打开index.android.bundle可以发现该JS文件被压缩和混淆过,难以阅读,因此需要去混淆和格式化,可以使用JStillery进行在线转换,使用Beautify和Deobfuscate功能并复制到本地Notepad++中并保存为文件index.android.bundle.jstillery.js,可阅读性大大改善,如下图所示: Alt pic Source Panel中上部的编辑框中是转换之前的JS代码,下部的编辑框是转换之后的JS代码,可以看出JStillery的效果还是不错的。
  3. 接下来就是阅读庞大的JS代码了,对于之前几乎没有使用JS写过代码的小白的我来说这无疑是一项挑战。不过对于这种广泛使用的技术,肯定有人分析过index.android.bundle文件格式的。
  4. 通过搜索还是发现了一篇博客,react-native bundle 解释与拆解,可知整个文件可以分为三个部分,如下图所示: Alt pic
    • polyfills : 最早执行的一些function,定义一些JS函数,包括模块声明方法__d等。
    • module difinitations : 模块声明,以__d开头,每一行代表一个JS的定义,该函数的定义为:__d(factory: FactoryFn, moduleId: number, dependencyMap?: DependencyMap) 1.FactoryFn:其可以被当做函数,如有理解错误,望评论!该函数定义为:
      function(global: Object,
                      _require: RequireFn,
                      module: {exports: {}},
                      exports: {},
                      _dependencyMap: ?DependencyMap)
      
      1. global:global全局对象。
      2. _require:require方法。
      3. module:本模块对象。
      4. exports:模块暴露。
      5. _dependencyMap:模块依赖列表。
      
      每一个模块的参数含义都是相同的,只是有些被混淆了。如下图所示: Alt pic 2.number:本模块ID。 3.DependencyMap:本模块依赖的模块ID列表。 模块示例:
      __d(function(global,_require,module,exports,_dependencyMap){...},
          908,
          [12,600,354,875,909,346]);
      
      文件中的模块按照模块ID从小到大顺序排列。
    • require calls : 执行InitializeCore和Entry File,多行形如require(模块ID);的代码,代码示例:require(41);这里的模块ID即为模块声明部分的模块ID,执行该行代码时会按照深度优先的方法遍历所有依赖模块。
  5. 有了以上文件格式的参考,进而继续进行静态分析将容易一些,不过依然需要人工分析,那么人工分析时就需要从庞大的代码中寻找重要的代码,比较常用的手段是字符串搜索或者代码搜索,都可以定位到想要分析的代码段,静态分析可做的事情不多,下面结合动态分析进行说明。

动态分析

网络请求分析

现在的移动应用越来越离不开网络,应用中展示的内容大多都是通过网络请求得到数据之后展示的内容,那么分析应用的网络请求则是很有必要的。本文使用Charles开启代理服务,在移动设备中设置代理,指向Charles设置的代理端口。打开图曰应用,可在Charles界面中看到该应用产生的网络请求,如下图所示: Alt pic 从中可以得出图曰应用主要访问了三个域名,主要的逻辑业务接口都在api.app.aituyue.cn域名中,另外两个域名的访问都是获取各种图片的请求。然而从上图中的接口访问详情可以看出,接口访问格式为JSON格式,但是数据请求数据字段和响应数据字段都被加密了,无法得知其中含义,api目录下的接口全部都被加密处理了。 尽管api接口的数据被加密了,但是也不算毫无所获,至少获得了比较关键的api域名和接口地址等信息,那么就可以去JS文件中查找有没有相应的关键代码段了,通过搜索JS文件,可以找到如图所示关键代码段: Alt pic Alt pic 从上图中可以看出该JS模块应该属于配置文件模块,其中记录了全局可访问的配置信息,与网络请求相关的配置在api结构中。

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理

滚动至顶部