PART1,前言
近年来混合开发APP逐渐成为主流的开发模式,与传统的开发模式相比混合开发极大的提升了开发效率,同时跨平台的特性也降低了开发成本,一直以来混合开发被诟病的性能问题随着技术的发展也得到改善。技术的发展往往是一把双刃剑,混合开发模式的出现导致“一次编码,多端运行”变成了现实,除此之外混合开发的APP相比原生开发的APP逆向成本也有了一定提升,这就给了黑灰产足够的诱惑:低成本、难逆向。混合开发模式的出现和快速发展给了黑灰产、病毒木马可乘之机,为应对未来的威胁我们应该做好技术储备,目前市面主流的混合开发框架有三款:uni-app、React Native和Flutter,三款框架各有优劣,从成本而言uni-app可能是三款框架中最好上手、最快开发、支持最多平台的,同时抓包可以算是最常见的逆向手段,我便对几个用uni-app框架开发的APP进行分析,尝试寻求一种相对通用的抓包方案。
PART2,关于uni-app
概念
uni-app是什么?了解一种技术或者框架最好的渠道就是官网,从uni-app官网可得知“uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个平台”,简单翻译下uni-app就是一款使用Vue开发的一套代码多端运行的混合开发框架。
uni-app的优势
官网也介绍了uni-app的优势,其中大多数的优势React Native、Flutter等其他混合开发框架也具备,这里着重说几点uni-app与其他框架比较的优势:
1、uni-app实现真正意义上的“一套代码多端运行”,支持更多的平台,提升开发效率。
2、与Flutter相比,uni-app使用Vue进行开发无需学习新的语言,开发成本较低。
底层原理浅析
上图取自官网uni-app功能框架图,其实我们只需要关注native.js部分提及“使用JS直接调用IOS API”和“使用JS直接调用Android API”大致就可以了解uni-app的运行原理,uni-app在Android或IOS设备运行时从架构上可以分成视图层和逻辑层,其中视图层负责页面渲染,而逻辑层负责执行业务逻辑,最终业务逻辑的执行会直接调用Android或IOS的原生API实现,除此之外页面渲染最终也会利用原生UI组件。所谓一套源码多端运行,也是因为uni-app可以使用条件编译实现不同平台的特性编码。
如何逆向uni-app
关于如何逆向uni-app,正好赶上最近ChatGPT比较火,我也体验了一把号称ChatGPT同根同源的平替“Claude”,得到的答案如上图所示。从图中可以看出Claude建议从几个方面考虑如何逆向,由于我本人是开发出身所以看到第8条建议的时候内心是非常认同的,“阅读uniapp的开发文档与源码示例,可以得到官方提供的一些框架结构与说明信息”,其实之前通过官网我们已经大致清楚了uni-app的功能框架图,并且确定uni-app的逻辑实现最终是通过native.js直接调用Android或IOS的原生API实现。因此我们只需要对官方提供的源码示例(Demo)进行分析,必定会找到一些较为通用的逆向技巧,接下来便以Android为例开始一步步分析,获取一种针对uni-app较为通用的抓包方案。
PART3,抓包实战
加上官网下载的Demo,我的手里一共有三个apk,直接挂代理用BurpSuite等抓包工具抓包的话,毫无疑问三个都是抓包失败,并且另外两个apk是加固的,为了最快的达成目的,我直接逆向Demo一步步探索相对通用的抓包方案:
第一步,思路分析
简单看了下Demo,我脑海瞬间出现4种抓包方案:
1.暴力破解
还是看官网!从API介绍可以了解到,uni-app是通过uni.request(OBJECT)发起请求,并且从上图参数说明中可以看到一个用于验证ssl证书的参数“sslVerify”,所以理论上只要我们能够把这个参数修改为false,即可管不ssl证书验证,那么如何修改该参数呢?
上图为Demo的文件目录部分截图,我们可以从assets目录下找到uni-app的前端代码,所以我们可以通过修改对应的代码后二次打包关闭ssl证书验证,也可以通过定制系统将整个资源包替换来实现同样的功能,那是相当暴力!但是对加固的应用而言,相关代码是经过混淆保护的,很难定位关键代码,这种思路就不通用了。
2.更改网络安全配置
上图为官方Demo的安全配置文件,可以看出debug模式是同时信任系统证书和用户证书的,那么我们可以通过二次打包或者定制ROM对apk的manifest文件进行修改,将debuggable属性修改为true,当然我们也可以直接对安全配置文件进行修改,设置信任用户证书,但是这种思路可能无法覆盖全部的请求,并且逆向两个加固的apk看了下并没有安全配置文件,因此也是不通用的。
3.Hook bypass ssl pinning
通过Hook来破解证书钢钉,在原生APP逆向时是一个常见的思路,对于uni-app其实也是完全可行的,不过个人感觉既然能够Hook,没必要再借助BurpSuite等工具进行抓包了,于是没有进一步验证,但是理论上是绝对可行的,当然还一个主要的原因是许多应用都会检测代理,看起来这种思路也不是那么通用。
4.报文自吐
该思路也是本文接下来要分享的思路,其实很简单,就是通过逆向分析官方Demo,从而确定网络请求框架,然后对网络请求框架进行分析,确定Hook的关键函数,最后打印请求报文和响应报文。
第二步,顺藤摸瓜
使用Jadx打开官网Demo,待反编译完成后查看文件目录,可看到上图红框中对应的目录,基本可以判断uni-app所开发的APP是通过OkHttp这一框架实现网络请求,只不过对应的包名与OkHttp官方包名有所不同,猜测是为了适配uni-app做了一定的改动,但是万变不离其宗,整体的思路应该是相同的。
第三步,照猫画虎
OkHttp作为目前可以说是安卓开发最主流的网络通信框架,用起来也是比较简单的,其支持同步请求和异步请求两种方式,首先需要实例化一个OkHttpClient对象,OkHttpClient有两个构造方法,可以通过传入一个构建好的Builder来设置相关参数,也可以采取默认的构造方,这时候就可以设置不走代理、证书钢钉等配置。
然后构建一个Request对象,其实就是请求,结合最后获得的Response即可得到完整的网络报文。
接下来就是真正的请求了,无论是异步还是同步请求,都需要调用OkHttpClient对象的newCall(Request)方法,而newCall方法最终会调用RealCall的newRealCall方法获取到一个RealCall对象,异步请求对应RealCall的enqueue方法,而同步请求则对应execute方法,如果继续阅读OkHttp框架源码不难发现enqueue最终还是会回到execute,因此只关注该方法即可。
继续跟进getResponseWithInterceptorChain方法,我们可以看到这个方法会创建一个Interceptor的List,并且会向里添加一系列的元素,Interceptor是一个接口,所有的拦截器都要实现该接口,请记住这一点后面会用到。
最终通过chain.proceed(originalRequest)获取到Response对象,也就是响应对象。
再次回到本文的主题,如何抓包呢?所谓抓包其实就是对应用网络通信过程中的请求和响应报文进行截获,也就是前面提及到的Request和Response对象,只要能获取到这两个对象就可以实现相关报文的打印。
前面提及到所有的拦截器都会实现Interceptor接口,目前网上有很多自定义拦截器实现的抓包方案,frida提供了一个名为“registerClass”的api注册接口类,借助这个api可以方便的创建一个自定义拦截器,然后获取Request和Reponse对象。
如果不喜欢frida,非要用xposed实现呢?Xposed并未听说会支持注册接口,那么我么不妨换一种思路,我们的目的本质上是获取Request和Reponse对象,回顾OkHttpClient是如何使用的?其实完全可以对RealCall这个类的getResponseWithInterceptorChain方法进行Hook,通过反射获取到Request对象originalRequest,然后通过getResult获取到返回值,也就是Reponse对象,后面就是报文的打印了,网上可抄的案例很多。
前面其实已经分享了两种OkHttpClient的通用抓包方案:基于Frida、基于Xposed,那么对于uni-app的抓包来说也是小事一桩了,无非就是找到对应的目标类和目标方法即可,关键代码如下图所示:
第四步,大功告成
最后就是简单的验证了,通过验证官网Demo及手头另外两个加固的apk都是可以正常抓到报文的,所以理论上这算是一种针对uni-app相对通用的抓包方案,大功告成。
PART4,总结与展望
Ok,到此接近文章的尾声了,其实本文分享的内容也是比较简单的,无非就是官网资料对uni-app框架有一个初步的认识和了解,判断其业务逻辑最终还是由原生实现,进一步借助官方Demo确定网络请求框架后照葫芦画瓢根据OkHttpClient的通用抓包方案稍加改造即可实现对uni-app相对通用的抓包。
其实混合开发的APP必定会涉及原生与Web端的交互,因此无论是React Native、uni-app,还是Flutter都可以用类似的思路进行分析,比如RN的模块、Flutter的引擎层等等都可以成为我们开始逆向工作的下手点。