首页
社区
课程
招聘
某抢茅台APP的reservationToken算法分析
发表于: 2021-3-2 14:18 19180

某抢茅台APP的reservationToken算法分析

2021-3-2 14:18
19180

在调用下单接口(addorder.html),里面包含一个参数名称为reservationToken,它的值是一串类似md5的十六进制。这里分享下逆向追踪过程,目前已实现。

拖入APK到jadx,直接搜索关键字reservationToken,我们看到图中的代码

其中orderPrepareParameter2.mReservationToken = MD5Util.encode("ANDROID" + W.e() + X.b()); 是根据 3个字符串进行拼接在执行的操作,那么我们接下来就来查找这2个方法的字符串。

目前已知:md5("ANDROID" + ? + ?)

我们追入:W.e() 内进行查看

我们可以看到,它这里是直接把结果存入的f26606b进行返回的,由于该APP它都做了缓存判断,所以如果直接下frida的话,也没办法直接HOOK到它生成的过程,但是我们发现他是调用的static方法UTDevice.getUtdid 获得的,我们可以编写frida代码主动调用,然后看看它输出的结果,以下是frida代码:

编写好代码直接运行,因为是主动调用的,无需等待hook, 那么我们看到是一串字符串,感觉有点像base64编码。

这部操作的意义并不是很大,只是知道了 W.e() 的返回值,但我们需要知道它的生成过程,所以继续 UTDevice.getUtdid 跟进。

我们继续跟进去后,发现它是调用的 b.b(context) 获取的一个class类,然后在调用 f() 返回的结果:

那么我们继续跟如b.b()内的实现部分

这里我们看到,它先判断f13187a是不是null,如果是的话,继续调用a(context)创建,这些都是它的缓存机制判断,我们继续跟进a内

这里就是它创建class类的参数赋值代码了,我们知道,刚刚它是调用 b.b(context) 然后调用 f() 来得到的,我们现在去看看 f() 它返回的是对应哪个属性,这样就知道这里对应的是哪个值了。

我们发现,f是返回的f13186g,而f13186g是由e方法赋值的,那么上一张截图,我们看到,e方法就是传入的 value 这个值。aVar.e(value) 也就是上一张截图的这行代码了,那么我们就继续跟进value的方法,也就是 String value = c.a(context).getValue(); 里面的过程

我们这里可以看到,它调用的h()方法,继续跟进,事情逐渐变得好玩了。

这里代码比较多,我们先来一下,它是调用的 this.h = i(); ,如果不是空的,就直接返回,其实这里也是获取缓存的值,我们跟进 i() 里面,由于这个方法代码反编译失败,都是一片绿色,阅读比较吃力,但是经过详细的阅读得出就是读取的缓存,所以这行忽略,我们往下看:
byte[] c2 = m5c();

this.h = b.encodeToString(c2, 2);

得出2行关键代码,这里它通过调用m5c()获得一个byteArr数组,接着进行base64编码后返回,也就是m5c里面估计就是关键生成了。

这里基本大部分都是Android的SDK代码,我们可以直接新建一个java工程,直接复制他的代码,将报错地方纠正。

我们扣出代码,发现报错的地方就是 d.getBytes 、 e.a(this.mContext) 、 g.a 、b 四处地方,我们逐一进去查看,首先查看 d.getBytes()

它就是进行的一个位移操作,我还以为是什么复杂的类,我们直接复制出来就好了,重新命名下。

直接复制出来,我重新命名成了 DgetBytes,然后把 d.getBytes 改成这个方法名,就解决了,那么我们继续查看下一个方法 e.a(this.mContext) ,跟进

这个方法也很简单,就是获取手机的deviceId,下面的就是判断如果获取不到执行别的获取方案,就不跟进了。 我们直接写死deviceId,也就是IMEI码就行了,到时候在封装成一个传参的方式即可。
最后跟进g.a()里面查看

这也是一个相加操作,很简单,也直接跟刚刚的方式一样扣出来,我重新命名成了ga,然后修改下调用的代码即可。

还剩最后一个 b() 方法,这个也是可以直接扣的

我们重新命名成了be,那么看下完全扣完的代码,一点报错没有了

后面我们在进行BASE64编码就完成了第二个参数的生成过程了!! 如果要转成其它语言代码的话,就看你的代码阅读能力了,因为都是直接扣出来的~

目前已知:md5("ANDROID" + 算法A(IMEI) + ?)

这里我就定义成它叫做算法A,他的调用过程就是 Base64.getEncoder().encodeToString(m5c()); 的返回,接下来我们解析第三个参数

我们继续进行扣代码,继续跟进X.b()内查看

这个方法很简单,看着代码挺多,我们慢慢阅读解析。
首先它调用 String packageName = AppContext.getContext().getPackageName() 获取当前APP的包名,然后获取缓存,看看有没有记录device_id这个值,我们要知道他的生成过程。
如果没有,那么它继续调用Settings.Secure.getString(AppContext.getContext().getContentResolver(), "android_id"),这个就是获取系统参数的android_id
如果获取的值是一个它固定的值9774d56d682e549c它就拿来返回了。
最终我们肯定确定,它就是调用
String deviceId = ((TelephonyManager) AppContext.getContext().getSystemService("phone")).getDeviceId();
f8203a = (deviceId != null ? UUID.nameUUIDFromBytes(deviceId.getBytes("utf8")) : UUID.randomUUID()).toString();

获取手机的IMEI,然后在通过 nameUUIDFromBytes 进行格式化,自此就结束了~

其实我们用frida HOOK发现,它返回的值跟我们抓包看到的APPKEY是一样的值。

目前已知:md5("ANDROID" + 算法A(IMEI) + UUID格式化(IMEI))


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 7
支持
分享
最新回复 (11)
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
很不错,适合小白分析。
2021-3-2 17:16
0
雪    币: 190
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
学习了,非常详细
2021-3-4 10:58
0
雪    币: 2181
活跃值: (528)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
学习了,感谢楼主分享
2021-3-6 09:41
0
雪    币: 116
活跃值: (1012)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
支持一下
2021-3-6 10:53
0
雪    币: 3967
活跃值: (3240)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
大佬 天天手撕茅台
2021-3-26 18:05
1
雪    币: 24
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
7
有茅台作者联系一下
2021-4-29 13:01
0
雪    币: 222
活跃值: (88)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
reservationToken解决了也抢不到,不知道什么原因。有没有谁用程序抢到的?
2022-11-30 16:55
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10
谁有成品哇?连下下呢
2023-3-2 14:11
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
11
茅台1499 有茅台作者联系一下
有人联系你了么?
2023-3-2 14:11
0
雪    币: 200
活跃值: (190)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
现在的更新了
2023-4-6 18:57
0
游客
登录 | 注册 方可回帖
返回
//