Android逆向入门5——Retrofit在App中的具体应用

在前两节中,我们先试图直接分析sign,到处乱撞,没有Android开发的一些经验,逆向之旅很难往下走。所以我们先是补充了Android网络通信库的相关知识,之后又亲手用OKhttp和Retrofit实现了简单的网络请求。
三十年河东,三十年河西,莫欺少年穷。这一篇再战Sign算法,一定会让你对Android和Android逆向有更深的体会。

在这里插入图片描述
在这里插入图片描述
这是一条网络请求的所有内容,之前已经反反复复的用它了。
我们之前说,现在Android应用的主流网络通信框架是Retrofit+OKhttp,那么根据我们之前学习的Retrofit开发知识,怎样才能快速定位到这个请求,或者这个sign呢?

回想一下Retrofit搭建的第一步,如下是上一篇中的截图。
在这里插入图片描述
@GET里的这部分URL,以及@Query括号里的带引号的字段名,这两个是最容易定位的特征。
为什么不搜索@GET呢?因为App中有大量的网络通信,只要是使用Retrofit发出去,那么很可能会有一百一千种@GET和@POST,单品Retrofit代码本身的特征很难定位到我们需要破解的这一条网络请求。

Jadx反编译小红书App,全局搜索“search/notes”,第三篇中我们已经做过这样的尝试了,只不过当时没有开发知识,看不懂具体的逻辑。
在这里插入图片描述
在这里插入图片描述
我们很轻松的找到了这条网络请求接口的配置,除此之外,这儿还有许许多多App中其他的网络请求。
我们从上往下仔细看看,我们自己写过一个叫meituanService的接口,而这儿其实也是一个RetrofitService接口,叫AliothServices,只不过里面配置的网络请求比我们多罢了。
在这里插入图片描述
当你意识到这一步时,很可能会有恍然大悟,豁然开朗的感觉,甚至会有一些小小的自负,“App网络通信不过如此,我马上就可以搞出解密了。”
在这里插入图片描述
我们写的接口和别人写的一样吗?我们来对比一下。为了方便看,我将它的格式稍微调整一下。

@GET("/api/sns/v9/search/notes")
    q<SearchResultNotesBean> searchSnsNoteBeta(@Query("keyword") String str, 
                                               @Query("filters") String str2, 
    										   @Query("sort") String str3, 
    										   @Query("page") int i, 
    										   @Query("page_size") int i2, 
    										   @Query("source") String str4, 
    										   @Query("search_id") String str5, 
    										   @Query("api_extra") String str6, 
    										   @Query("page_pos") int i3, 
    										   @Query("allow_rewrite") int i4);
@GET("getMerchantComment")
Call<ResponseBody> inquireMeiTuan(@Query("platform")String platform,
                               @Query("partner")String partner,
                               @Query("originUrl")String originUrl,
                               @Query("riskLevel")String riskLevel,
                               @Query("optimusCode")String optimusCode,
                               @Query("id")String id,
                               @Query("userId")String userId,
                               @Query("offset") String offset,
                               @Query("pageSize")String pageSize,
                               @Query("sortType") String sortType);

主要有两点差异,我们从左往右看

一、最左边是返回值,我们返回Call<ResponseBody>类型, 它返回q<SearchResultNotesBean>,q是啥?尖括号里为啥和我们不一样??话说,本身的尖括号又是啥??Retrofit的Call后面为什么要跟着尖括号?
二、小红书的Url拼接似乎缺参数
我们分析一下,先看我们自己的url链接:https://www.meituan.com/meishi/api/poi/getMerchantComment?platform=1&partner=126&originUrl=https%3A%2F%2Fwww.meituan.com%2Fmeishi%2F6309410%2F&riskLevel=1&optimusCode=1&id=6309410&userId=&offset=0&pageSize=10&sortType=1它确实也很长,但每一部分哪来的都很清楚。

url 来处
https://www.meituan.com/meishi/api/poi/ 我们在创建Retrofit实例时添加的BaseUrl
getMerchantComment @GET中的内容
后面十个参数 十个@Query

那么小红书中的这条url呢?
假设同样BaseUrl + @GET + @Query*N
因为@GET中为/api/sns/v9/search/notes,所以再怎么拼接,BaseUrl也只是https://www.xiaohongshu.com/,不可能含有什么参数,而@Query中只有十个参数。
在这里插入图片描述
这十一个参数莫名其妙找不到,而且要命的是,不管是deviceId这种设备参数,还是device_fingerprint这种更复杂的设备指纹,又或是我们在寻扎的sign,竟然都在消失的参数中。这十一个参数去哪儿了?从这个AliothServices接口,到发出这条请求被我们的抓包软件抓住为止,中间又发生了什么?
敬请收看今日说法特别篇《大山深处——消失的十一个参数》
——————————————————————————————————————————————
停停停,言归正传。我们分别就上述两个问题进行探索

一、我们返回的是Call<ResponseBody>,它返回q<SearchResultNotesBean>。我们返回ResponseBody,表示将HTTP的响应体转换为ResponseBody,数据返回结果是一个干净的Json,你可以根据返回结果自定义一个实体类,用于装网络请求返回的数据,这样可以更细化的对数据进行操作。网络上有许多自动化将Json结果转化为实体类的工具,或许你可以试试这个网站:http://www.jsonschema2pojo.org/ 。

SearchResultNotesBean就是它的实体类,我们Ctrl加左键进入SearchResultNotesBean的内部。
在这里插入图片描述
再进入<SearchNoteItem>内
在这里插入图片描述
我们对照一下第一节中,小红书抓包返回的结果,内容完全吻合。
在这里插入图片描述
第二个问题是我们返回Call类型,而小红书是q类型,这是为什么呢?其实这是RxJava+Retrofit的结果,好好的Retrofit不好吗?为啥要再用RxJava?事实上,这是为了实现“相同的逻辑,更简洁的代码”,为了更灵活的架构,更好的代码、更优的用户体验,在逆向时,你会发现开发人员的各种骚操作,杂七杂八的工具、各种各样的封装、乱秀一通的骚操作。比如现在的RxJava,或者之后我们破解大众点评时会遇到的热修复技术,这些东西对破解的影响说大不大说小不小。如果你知道并且认识它的代码形式,你就可以在破解时更加有底气,不会钻进一团泥淖。但如果你不了解App中涉及的这些技术,你就会遇上大麻烦,你会发现你掌握的破解知识和你遇到的实际问题如下图——
在这里插入图片描述
所以我们需要更多的了解和学习Android的知识,但我不建议你一头钻进Android开发层。最优解是先懂得多,但不用太深。先聊这些,我们继续回归正题。RxJava+Retrofit这个组合有什么特点呢?最明显一个特点就是用Observable代替Call,如果我们使用RxJava来优化和简化我们的网络请求框架,那么Call<ResponseBody>就会变成Observable<ResponseBody>,而之所以我们看到的小红书呈现效果是q<ResponseBody>,是因为Apk对整体代码做了混淆,不信你可以进入q类,看一下它的类名和注释。

在这里插入图片描述
疑问一就解决了,如果你想对RxJava有更多的了解,可以看一下这篇优秀的博客。
给 Android 开发者的 RxJava 详解 http://gank.io/post/560e15be2dca930e00da1083

我们还有一个问题,十一个参数去哪儿了?实际上,这是使用了OkHttp的拦截器功能。拦截器是Okhttp框架很重要的一个特性,它有许多功能,我们只就当前所需要的功能进行举例。假设你制作了一款App,里面有一百二十种GET和POST,但每条请求都需要DeviceId、timestamp以及cookie用来对请求来源做验证和限制,如果写二百四十个@Query也未免太傻了。这个时候我们就可以使用拦截器,给从App中发出的所有请求统一添加参数。

这个功能更凝练的表述是这样的:
拦截器可以拦截即将发出的请求及对响应结果做相应处理,比如增加一些应用需要和服务端交互的通用信息。
小红书消失的十一个参数,正是这种通用信息,所以小红书采用了拦截器进行了优雅的处理。

这一篇就这么讲完了,下一篇就是根据现在掌握的东西来定位加密Sign的地方了,有兴趣的读者已经可以直接先行教程一步找到SIGN的加密处了。

这一篇的内容,如果只是想听懂,或者说解决问题,并不难,但如果想完全理解,或者说真正搞懂,十分十分不容易。信息量实在比较大,而且对新手很不友好,这和我写教程的初衷完全不符,但一来知识点太多,涉及到Java自身的泛型、设计模式、注解,涉及到RxJava,RxJava的上手难度真是不小,涉及到封装和一些设计模式……所以我实在不知道从哪儿讲最好,二来也是作者能力和笔力也有限,无法清晰的表达出这一节中涉及到的一些技术要点。
我琢磨琢磨,日后这一章会重写。

现在给一些关键点,可以去搜索,也可以直接参考我给的链接,我想这些会给你很大的帮助。
Java泛型 https://blog.csdn.net/tyrroo/article/details/80930938;https://cloud.tencent.com/developer/ask/193019
Retrofit入门基本使用总结 https://www.cnblogs.com/baiqiantao/p/7494850.html
Retrofit完全解析 https://www.jianshu.com/p/7b839b7c5884
Android 教你一步步搭建MVP+Retrofit+RxJava网络请求框架 https://www.jianshu.com/p/7b839b7c5884
给 Android 开发者的 RxJava 详解 http://gank.io/post/560e15be2dca930e00da1083

一生很短,我们终将会失去它 所以不妨大胆一点 爱一个人,攀一座山,追一次梦 不妨大胆一点,有很多事没有答案

7/27补充

小红书并不适合促进你Retrofit的理解,你可以找一个更简单的App进行训练,至少别是RxJava+Retrofit,这对新手很不友好。我推荐对可以试一下伊对这个app,对它的网络请求框架进行分析,相对比较清晰和好理解,下面放一些截图方便大家对应。伊对是单纯的Retrofit,没有使用RxJava(至少我没还没发现)

为了保证我们分析的版本一致,可以使用我提供的百度云
链接:https://pan.baidu.com/s/1frp_g0vyhhJi_uaQsl619Q
提取码:bruh

首先是抓包分析,使用手机号登录,我们抓一下动态页的包。
在这里插入图片描述

直接搜索moments.json
在这里插入图片描述
在这里插入图片描述
查找用例
在这里插入图片描述
MiApi是什么呢,点进去看一下,是一个用于初始化参数的管理类。
点进去,在getInstance方法里,很清楚的看到了拦截器的位置,拦截器里有header里所需要的所有字段,你可能会说这四个没有,可以看一下上一篇的末尾,我们纠正了一个小错误,补充了一些Okhttp的知识,这四个字段是由默认拦截器加上去的,而Retrofit是基于Okhttp的封装,自然也会加这几个参数。

在这里插入图片描述

补充完毕,大家加油。

发布了27 篇原创文章 · 获赞 120 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_38851536/article/details/97489983