作为前端工程师,想必大家都对网络请求的抓包和模拟请求都很熟悉,也有一些人基于这些抓包的信息去做了一些抢票工具之类的应用。

最近看到了一篇很有趣的文章,作者是对某租车小程序的网络请求进行抓包分析,还逆向解析了参数加密方式,很精彩的一篇文章,推荐大家阅读。


以下是正文:

1、前序

最近临近暑期,想去海边玩.

想自驾游,无车呀,咋办,只能上某租车平台租车,打开一看价格不菲啊

7e8e0833443dabc28e62c61a73d4ea80.jpeg
image.png

当我准备租的时候,改了时间,发现价格居然变少了,灵机一变的我突发奇想,会不会改了一个取车网点会不会也很便宜了呢?

ae082e192846d998994bb80e5408399f.jpeg
image.png

果不其然,价格变低了不少,也就是说【时间+地点】可能会决定价格的变动,那怎么样做最优解呢?

最暴力的方式就是循环时间并且循环地点获取最低价格,那么怎么样调用这个查询接口呢?

思路:通过抓包的方式抓取到接口,然后动态的修改参数去获取查询结果的列表即可

2、前置准备

  1. 抓包工具:fildder,以及配置好 https 证书,能抓到电脑小程序的请求,手机的也行配置好证书就行

  2. 微信小程序解密工具:UnpackMiniApp,用于解密微信小程序

  3. 微信小程序逆向工具:wxapkgconvertor,用于逆向微信小程序获取混淆的 JavaScript 代码

  4. 文件搜索工具:everything,用于快速搜索电脑系统文件

3、开始抓包接口

首先先打开某租车小程序,已经打开过的建议先删除小程序避免找不到.wxapkg 文件

bddaee45167c96794c925271d42b3d2a.jpeg
image.png

进入小程序之后随便点击一下,保证.wxapkg 的存储

9a7a2b4f88197c073b851c993685f859.jpeg
image.png

找到选车页面,选择时间和网点之后点击立即选车,点击的同时打开 fildder 进行抓包

df415e2c8ec0d8c0057937c8ac51ccdd.jpeg
image.png

通过抓包软件 fildder 可以看到响应数据找到对应的请求接口

eb5cec992420a81702d4ef4e9283f7f8.jpeg
image.png

4、模拟请求研究参数

4.1 Postman 请求

上一节中通过 fildder 抓到对应的包之后,复制请求的 url 到 postman 进行二次请求测试

236b48f49736a4ca8c00256e97bdffa0.jpeg
image.png

4.2 入参研究

通过 postman 请求是 ge 请求,并且有四个参数,并且无需 header 的任何参数,那看起来应该是不难了

  • cid:猜测是城市 id

  • q:不知道是什么,通过百分号看出来应该是 encodeURIComponent 过的参数

  • sign:一看就是加密的签名密钥,这个估计是重点

  • uid:未知的参数

做过爬虫的都知道有些参数不一定需要的,通过一个一个参数取消来判断哪些参数是不必要的,减少不必要的逆向工作

4.2.1 cid 去除

452cfab20351b24347db4812c435c3c8.jpeg
image.png

发现不太行,cid 为必要参数

4.2.2 q、sign、uid 的分别去除

45f20d5703ed0b29e537f13ff4a16ddf.jpeg
image.png

分别都报错了,说明四个参数都是必要的好了,现在该研究参数是怎么来的了

4.3 参数研究

4.3.1 q 参数

之前发现 q 参数是一个类似 encodeURIComponent 过的参数,这里做一下校验,请求到在线 UrlEncode 的网站解析发现是一个合法是数值

66aa16a35b1425d416348deba8035ffc.jpeg
image.png
{
    "pickupCityId": "14",
    "pickupTime": "2024-08-09 12:30",
    "returnCityId": "14",
    "returnTime": "2024-08-11 12:30",
    "entrance": 1,
    "holidaysWaitingFlag": 0,
    "pickupDoorFlag": false,
    "returnDoorFlag": false,
    "exclusivenearby": true,
    "pickupDeptId": "127248",
    "returnDeptId": "127248",
    "bucketIdList": [319, 991, 1138, 1187, 32, 2621, 137, 256, 270, 508, 522, 585, 1537, 2901, 2565, 2461, 2363, 2293, 3020, 1866, 2999, 1712, 1635, 1558, 1488, 1369, 928, 886, 389, 2663, 2698, 2852, 2915, 2992, 3048, 3069, 3195, 396, 1068, 1607, 1642, 1670, 1698, 1810, 1831, 2496, 2684, 2733, 2873, 2943, 3104, 3188, 2090, 298, 732, 1320]
}

见名知起义,可以大胆的先猜测它的含义,用于后续研究

  • pickupCityId:应该是取车城市

  • returnCityId:还车城市

  • pickupDeptId:取车网点

  • returnDeptId:还车网点

大胆假设一下,如果我修改了还车时间再编码一下发过去请求,会不会成功呢(校验 sign 的参数跟哪些参数有关,一般 sign 都是混合多个参数进行加密的)

修改还车时间为 2024-08-30 12:30,然后再次发送请求看看结果

c8ee11fb6e8a200a49091f3361232db2.jpeg
image.png

果然失败了,意料之中,剩下几个参数不用研究,直接去源码中查看

5、逆向解析

5.1、获取微信小程序加密包

首先先下载一个 everything(快速搜索文件的软件)输入.wxapkg 后缀名,然后点击修改时间倒叙排序(要提前删除小程序,重新进入登录,才能准确找到小程序加密包)

77e05dc1cc8a9e008a08c98cd339214b.jpeg
image.png

进入文件夹,打开 UnpackMiniApp.exe 文件,选择需要破解的微信小程序包

b85574ef57982224bd39b7345f13bdb2.jpeg
image.png

5.2、解析获取混淆源码

破解之后会有一个新的 wxapkg 文件,然后使用 wxapkgconvertor 转换为混淆过后的源码

07efef6978b4aef0a332fb6f0eacb806.jpeg
image.png

在当面文件夹会生成一个解析后的源码

686069b937e12680d148f087384dcd96.jpeg
image.png

6、逆向解析

6.1、代码格式化

获取到的源码是混淆且去掉空格的,打开 app-services.js 进行反混淆,优先使用网上的混淆还原工具去格式化,因为编辑器的格式化不一定正确

6.2、寻找 sign 的加密方式

寻找参数的加密方式一般很简单一般搜索 "sign:"、"sign="、"sign"等关键字就行,毕竟是作为请求参数过来的

f5deb97203411c4d4198624ac62f6ecf.jpeg
image.png

搜索了一下 "sign:"就出现两个结果,并且出现了 cid、q、uid,看起来很像了,把方法拆出来看

function(e) {
   var t = o.R.getState().baseInfo.bucketIdList,
      n = e.data || {},
      i = JSON.stringify((0, r.Z)((0, r.Z)({},
            n), {},
         {
            bucketIdList: null != t ? t: void 0
         })),
      u = (0, c.uP)(),
      l = {
         cid: a.x,
         q: i,
         sign: (0, c.Ur)("cid=".concat(a.x, ";q=").concat(i).concat(u ? ";uid=".concat(u) : "").concat(a.$h))
      };
   return u && (l.uid = u),
      l
}

貌似看不太懂,看不懂我们有 gpt 啊,问 gpt,要善于借助 chatgpt,比如 (0, c.Ur)这种是什么意思等

83ac7c0febc5f565da04600604b40bc2.jpeg
image.png

gpt 的回答是调用了 c.Ur 方法,并且把参数 concat 起来作为参数调用它,得到 sign,现在分开来看

  • cid:取到的是 a.x ,我们暂时用抓包到的 cid,根据观察同一个城市是不变的

  • q:取的是 i,就是我们抓包到的一个参数反解析得到的对象,我们根据它进行修改时间、城市就可以了

  • u:看起来是可以不传的, u ? ";uid=".concat(u) : "" 这句代码可以看出,暂时取抓包抓到的

  • a.$h:这个不知道是什么,继续往下看

点击应用 a.$h,查看引入的地方

8928715f107617deea4df505b37ac13f.jpeg
image.png

返回的是 a,再点击 a,发现是一个常量对象,那就破解了 $h

f44053a0dad7108683980aab9ee833b6.jpeg
image.png

6.3、 加密函数推导

上一节已经把 c.Ur 的入参都搞定了就是用一个字符串 concat 起来就好了,现在就要做到 c.Ur 是什么函数了,同理点击找到定义

3cc4710c2ba79f43bc41fcf92c7f2af3.jpeg
image.png

追踪下去是定义了一个方法

c2b9fae3226751f8fdde5904e357e242.jpeg
image.png

主要函数有 Z、R 函数,不确定是什么,继续点击 Z、并且 R 函数传入了三个参数,e 就是我们的拼接字符串,void 0 和!0 ,不知道是什么意思,但是记住是三个参数

d280c8e1ad4f7ea6310e90bc7074da2a.jpeg
image.png

Z 方法没有引入其他的方法了,直接复制下来,在看 R 方法

c0d257adb0f03b88475ef27bfbf82e63.jpeg
image.png

网上看发现 n 是这个函数的参数,n.n(m)也不知道是什么意思,看不懂,不过肯定是一个函数,那就直接先看 m 函数,传入了一个数字,搜索一下这个数字

b366ad759b3c3c831b34597914ee4393.jpeg
image.png
31c1f9bfbea5ef4af04cceb844615af4.jpeg
image.png

发现它就是定义了一个函数,但是又臭又长,不知道是什么意思,老样子 问 gpt 吧

18e5d0d51f0440dce2276d289090e9ec.jpeg
image.png

gpt 真是厉害,没看到任何关于 md5 的字母,却分析出来了,并且告诉我 c 就是入口函数,而且刚好是三个参数,刚好跟之前调用 R 方法的的三个参数对应上,那我就大胆猜测就是直接调用了这个方法

c92a7c3dc5b23e89bf56adefc9011b19.jpeg
image.png

到此所有的方法以及解析完成了,然后全部复制下来测试一遍看看

7、 本地 js 文件测试加密参数

7.1 本地方法

将拷贝的方法全部复制下来之后,组装一下,原来闭包的方式要改一下

22d4d171f2427c0be97931906b04317c.jpeg
image.png

完整代码

24e8105a9bdfbaf41fd3c69fea0fed8c.jpeg
image.png

7.2 测试校验

结果是这个数字,是不是很眼熟,打开之前 postman 请求的参数看看,发现是一模一样

e5b8bebae618f5c6d6d49f7f88b95c45.jpeg
image.png

8、总结

本文的目的是为了学习抓包知识、js 混淆知识等、以及代码分析,掌握安全开发意识无论是混淆和反混淆技能都是很有必要的,在调研一些市面上的功能的时候可以用到,只有会了反破解,你才懂的如何去防止别人反破解

原文地址:https://juejin.cn/post/7410289323737612315

作者:Archermo

Logo

加入社区!打开量化的大门,首批课程上线啦!

更多推荐