本文最后更新于 2024-07-06,文章内容可能已经过时。

本篇文章为log生成逻辑(终于算搞到最后了,嘻嘻)
重点来了,本文出现的前端JS代码片段均为解密后的代码,未解密的代码截图也没有办法进行分享

准备工作

首先还是需要找一个需要log校验的活动,这里直接以炸年兽活动为例,所有的电商节活动除了前几天,基本上都会开始上校验。

找一个抓包工具,然后将活动地址抓出来,因为很多活动其实都是网页版的。使用Chrome将UA修改成APP抓出来的UA就可以了。

初识log

其实一直在说log校验、log校验,很多人都不知道log校验到底是啥,我们进一个活动,点开请求仔细查看一下。

image-20230120202741444

文章写的太晚了,不过没啥,起码还能看到一些东西。这里标注出来的log就是我们要拿到的东西。

定位生成代码

在Chrome中可以查看到请求的调用过程,这里只是需要“亿点点”的耐心就好了。

image-20230120204844104

或者使用字符串搜索大法也可以尝试一下,不过京东前端加密后,能不能搜得到还是一个未知数。不行的话还是要老老实实的搞一下,肯花力气一定是能找到入口的。

image-20230120205002376

解密后整理一下,然后直接翻到方法的首页,然后开始进行分析。获取log的方法应该是window.smashUtils.get_risk_result了。

image-20230122221955643

分析JS

提前说一声,这里面有一部分变量已经被我修改了,后来发现没啥必要,但是已经和最初始的不一样了。

生成log —— window.smashUtils.get_risk_result部分

image-20230122222321106

看一下这里面的入参t对象的生成内容,可以看一下iddata里面的random都是随机的。然后random这个随机内容调用的是window.smashUtils.getRandom(8),这个看着应该是生成一个长度为8的随机字符串。

然后下面一部分还会用到初始化的变量initParam

getRandom方法 —— 生成指定位数的随机字符串

image-20230122222704749

这里面看一下,就是获取一个长度最大为15的随机字符串。并且字符串貌似并不会出现0。

初始化变量 —— window.smashUtils.init() 部分

查看一下initParam变量是什么时候进行初始化的。

image-20230122223224612可以看到实际上这个变量就是调用window.smashUtils.init()进行初始化的。搜索一下,或者打印一下调用堆栈信息进行查找一下。

window.smashUtils.init({appid: "50174", sceneid: "ZNShPage_h5", uid: Object(je.getUUID)()})

appidsceneid应该很明显就是用来定位活动的了,然后uid后续没有用到,可以直接无情的抛弃他,不然也可以看一下它的值,好像也就是个空串吧,就不清楚了。

我们会看到会将入参的Object直接传给initParam完成赋值,但是init方法中还有很多其他的的变量也进行了初始化,而且后面会发现直接参与的log生成,所以我们也进行解密一下吧。

getLoadData() —— 载入时完成部分变量初始化

image-20230122224207189

这里就很明显,_t应该就是判断有没有进行一些变量的初始化,然后H就是当前时间戳,encrypt_id给了一个true,这个看着就不太对,这个后续应该还会把值进行改变,然后还调用了setInter()方法。

setInter()里面就是重新设置了定时器,去上报了一下数据,这个应该埋点数据了,可以直接忽略掉。

然后调用getBatteryStatus() Lt变量赋值,可以查看一下变量的使用情况,有且只有在getInterfaceData()方法中用到,根据setInter()的分析,这里面应该是埋点的上报数据,那么可以先不管他,直接注释掉,不对了可以再重新返回来进行查看吗。完全没有必要一步到位。

image-20230122224928825

clearjoyytoken(i.appid, true) —— 清除JoyToken

image-20230122225239245

其他又出现了一个新家伙,R变量,查看一下变量初始化。

image-20230122225849493

这里可以看到R和getTokem()先按下不表吧,因为这里逻辑很明显跟他们俩没啥关系,因为下面的if分支中又一段e && tt === 1,如果为真将进行一些操作。

还记得tt吗,初始值为0,调用window.smashUtils.init()会加1,然后e变量也是init()方法中传递过来的为true,所以会直接走下面的清楚操作。a变量也没用到,下个地方再说getTokem()方法吧

getTouchSession() —— 获取session

image-20230122230407554

这个方法就很简单了,就是根据调用方法的时间和随机数来生成了一个字符串。

getjoyytoken(i.appid, true) —— 获取JoyToken

image-20230122231127217

又遇到熟悉的表达式了,这说明这里肯定要进getSwitch()方法的,入参是appid,也就是50174,这里肯定每一个活动都不一样的。看一下getSwitch()方法的代码。

image-20230122232536860

这里总感觉那个collect_rate变量的判断有一点点多余,算了,继续向后看吧。

$t.decipherJoyToken(y, initParam.appid) —— 解密JoyToken

image-20230122232849910

朴实无华的解密JoyToken,直接拷走就能用了。不过不知道为啥getjoyytoken()方法中为啥要加上appid,后续解密的时候还需要移除,再往后看看吧。

image-20230122234247882

其中A.default.atobFunc()可以看到其实就是普通的window.atob,他只是在没有这个方法时,会重新实现一下。

shshshfpb初始化

可以看到https://rjsb-token-m.jd.com/gettoken请求中的whwswswws变量是从Cookie中拿到的,那么要找一下从哪里初始化的。

其实刷新一个网页可以观察到,每次和gettoken接口一起发送的还有两个接口,一个是https://blackhole.m.jd.com/getinfo,另外一个是https://blackhole.m.jd.com/bypass。其中bypass是在$t.reportInterfaceData中调用的,这个方法暂定为埋点,其中getinfo接口的返回值和whwswswws变量相同。

image-20230123152614250

再去代码中确认一下。

image-20230123152733184

可以确定是getInfo接口中初始化了whwswswws,说明还有一部分变量不是在window.smashUtils.init()中初始化的,还需要看一下从哪里调用的,找出另外一部分变量的初始化。

到这里,window.smashUtils.init应该就算结束了,剩下的参数初始化都是在另外的地方初始化了。

剩余参数初始化

getInfo()追上去,看一下哪里进行了调用。

image-20230123162608573

$t.getLocalData()很明显就是获取这种标志位和初始变量,用于判断活动环境的。这些变量可以直接通过正常环境中直接拷贝出来。

image-20230123162921146

$t.getAppOs()$t.getBlog()就是我们上两篇文章说的,获取用户的设备信息和Blog变量,可以直接翻看其他的文章。

$t.getFpv()方法是初始化shshshfpvCookie变量,但是后续好像没有地方使用到。

image-20230123162957207

$t.getInfo()即为上个段落中,初始化shshshfpb

$t.setjoyyaCookie.init一时间不知道是干嘛的,看着是初始化joyya?但是后面好像没看到用处,解密都懒得解密,后续再说。

$t.getJrInfo()应该就是获取京东金融的环境了,像电商节的活动,有些任务就会区分京东和京东金融的环境,应该就是这个方法了,这个可以暂时不用管,先搞定京东环境再说吧。

那到这里基本上变量的初始化应该就完成了,可以重新看log的生成逻辑了。

重回window.smashUtils.get_risk_result部分

image-20230123175724575

这里比较有意思的地方在这里,还记得gettoken接口拿回来的东西吗。是不是放到joyytokem下面了,这里的getTokem就给取出来了,然后并将其中的xcd属性解密后居然是个JS代码块?高级高级,然后重新执行可以后端自定义的JS,如果后端也可以根据执行结果看出来环境是否异常吧?

然后截一下后面的代码吧。

image-20230123192833934

这里面应该就没什么东西了,根据加密字符串的特征,可以判断出L.default.toString()就是sha256HexS.default.toString()就是sha1HexgetCrcCode()就是获取冗余校验码,utoa()实际上就是window.btoa()

附带一份那个log对象的属性含义。

image-20230123204012683

然后就只剩下最后一个xorEncrypt()方法没有揭秘了,解出来看一看。

image-20230123193312333

到这里log的生成逻辑应该就已经被扒的干干净净的,最终的ie变量就是log变量了,body中的random经过分析,其实也就是调用window.smashUtils.get_risk_result传递进来的random

image-20230123193546638

进行测试

啊,可以直接跟你们说,实际上还是不能用的,请求接口会出现请从正常途径参加活动,原因有两个,一个是上面埋了一个坑,嘻嘻,可能遇到也有可能遇不到,完全看运气。

另外一个坑就是炸年兽活动居然在Cookie里面还有校验,一整个大震惊。

image-20230123195104426