在调用下单接口(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))
[注意]APP应用上架合规检测服务,协助应用顺利上架!