-
我们搞的是二级评论接口的 ab值,先随便找个视频,打开评论区,抓个包,确定评论的接口。
-
确定好接口地址,ab值的加密生成位置,网上有很多,这里就不展示跟栈流程了,放一张图展示。
-
在这个位置打上断点,除此之外还需要打上 xhr断点,可以避免很多的干扰日志生成。
-
可以看到总共3472条日志,日志数量不多,但是很多位置看的都比较无厘头,这个ab最后是以列表的形式返回,说明 e参数生成的 ab值。我们先浅浅的往上看日志,浅浅的分析分析。
-
处理了几个 jsvmp的案例,我们现在应该也能总结出一点点规律,这个 this的英文字母,是 base64的魔改编码,那么说明ab值最后是上面的乱码字符经过魔改 b64生成的,这是我们的线索一。
-
那我们现在往上看需要找到乱码的初始生成位置是在哪。
-
各位大佬看到这个位置,仔细观察应该可以发现,这俩个乱码字符不是同一个,我们先重新命名一下,距离 ab值生成位置近的为初始一,再重复一下,ab值是乱码一经过魔改的b64编码后生成的。这个乱码一是由乱码二 fromCharCode方法后的值再相加得到的。
-
梳理下我们现在得到的线索:
str1=String.fromCharCode(str2) # str指乱码字符
ab = b64(str1) # b64指魔改的base64,其实也不算魔改,只是把映射表做了替换,原本的映射表是大小写的英文字母、数字、+、/字符。
-
我们继续向上找乱码二是在什么位置开始生成的。
-
日志看到这里,开始变得无厘头,没什么有用的信息,过!
-
又往上滑,到这个位置,这一片211的日志暂时不知道是做什么用处,乱码二的生成方式可以看到,就是这个138位的数组通过了fromCharCode方法,然后把结果相加。138位数组是怎么来的呢?再往上看,是130位数组和一个8位数组拼接起来的,再往上看就是130位数组的生成逻辑。
-
我们网上再看到初始生成位置。
-
初始位置使用到了很多随机数,说明这130位数组的生成逻辑中有使用到随机数。8位数组的逻辑目前我们没看到。目前的日志已经出现逻辑不同的情况,说明我们的断点已经不够了,先梳理下目前的线索:
138位数组是由130位数与8位数组拼接起来的,130位数组是由随机数和其他逻辑生成的,8位数组的逻辑暂时没看到。
- 乱码二的生成逻辑是将
138位数组经过fromCharCode方法生成的。
str1=String.fromCharCode(str2) # str指乱码字符
ab = b64(str1) # b64指魔改的base64。
-
可以看到上面又是一个concat方法,也就是数组拼接。一个50位数组与3个数组拼接,组成98位数组。这98位数组用到什么地方,我们暂且也不知道。
-
这个时候可以先不管逻辑不通的地方,接着向上看日志,也可以补充完整其他断点位置,重头再看日志。
-
那我这里就补充断点了,重新打印下完整的日志。
-
简单看代码,m赋值给 v了,说明 v是堆栈,++p是在操作指令集。
-
我们需要把堆栈取值、赋值、方法调用、运算符的位置都打上日志断点,然后从头部往下看下日志。
-
从将载荷请求加密这里开始看,上面的内容都是轨迹相关的内容,可以看到将载荷内容尾部拼接了 dgzx4个字符,然后经过了一个加密算法得到了32位的数组。
-
这个加密算法可以点击方法,会自动跳转到代码位置,扣下来即可直接用。
SM3是中国国家密码管理局发布的256位密码杂凑(哈希)算法,对标 SHA-256,遵循 Merkle-Damgård结构,核心用于数据完整性校验、数字签名与消息认证,已成为国标 (GB/T 32905-2016)与国际标准,广泛应用于政务、金融等领域。
-
这里是这么一个逻辑:
encrypt1 = SM3(载荷内容+字符串 dhzx) // SM3指加密算法,载荷内容就是网站载荷中的内容
encrypt2 = SM3(encrypt1)
encrypt3 = SM3("dhzx")
encrypt4 = SM3(encrypt3)
-
然后下面取出了userAgent,暂时还没用到。
-
这个位置比较简单,看下日志就懂了,我就不多赘述。接着往下。
-
这里开始打乱数组的顺序。
-
这里数组的顺序已经打乱完成,取出了 ua开始操作。
-
这里再插几嘴个人见解,大佬们可以直接略过这堆废话:
- 对字符操作一般就是俩个方法,
String.fromCharCode()和"aaa".CharCodeAt()方法,比如
- 拿上图中的
UA举例来说,想操作,肯定就是用String.fromCharCode方法,拿UA的长度,循环遍历对应码表或者是万国表,得到的一般就是乱码,换个高档叫法:不可见字符。
- 同样得到乱码之后,再取其长度,使用
CharAt方法,就可以把乱码换成我们常见的数字或者字母、字符,把 aaa换成 b64的码表就是魔改的b64了。
- 我只是简单举个例子,其中肯定还会参杂其他的算法,修改值,改变结果,但是这俩个函数方法本质就是这么使用。
-
接着向下看。
javascript:;
-
这里已经和上面的内容对上了,我们接着向下看。
-
到这里我们再重新整理下线索:
- 头部位置我们进行了多次的国密加密算法,分别对载荷内容,固定字符串进行了多次加密,这里又对处理后的
ua值进行了加密。
- 先把上面的线索
copy下来(我太懒了555)。
encrypt1 = SM3(载荷内容+字符串 dhzx) // SM3指加密算法,载荷内容就是网站载荷中的内容
encrypt2 = SM3(encrypt1)
encrypt3 = SM3("dhzx")
encrypt4 = SM3(encrypt3)
- 然后对
UA进行了fromChaCode,又进行了CharCodeAt,得到了处理后的UA值。
encrypt4 = SM3(UA_) // 这里的UA_指的是处理后的UA值
-
再往下看,用到了时间戳,下面的部分就算得上是 ab值的重头戏了,最难的部分。
-
这部分日志对上文国密加密后的值、时间戳、浏览器的指纹进行了操作。
-
这里可以看到,浏览器指纹通过 CharCodeAt方法后也得到一个 44位数组。
-
50位数组,最难的部分。这之中还有 4位数组和 8位数组,相对来说比较简单。
-
到这里已经和刚刚的部分接上了,98位数组是由50位数组与44位数组、4位数组4、1位数组拼接起来的。
-
50位数组最后再说。
-
44位数组是浏览器指纹生成的,小数组看日志就可以分析出来。
-
从头到尾整理下现在的线索:
- 对载荷内容拼接上定值字符串、定值字符串,进行
2次国密算法。
- 拿到
UA,经过String.fromCharCode()和CharCodeAt()方法后,再对其进行国密算法加密。
- 拿到国密算法加密的结果,加上时间戳,随机数经过其他算法得到
50位数组。
- 通过浏览器指纹得到
44位数组。
- 拼接到
98位数组后,与随机数生成130位数组和8位数组。
130位数组拼接上8位数组,经过fromCharCode()生成了乱码二(str2)
str1=String.fromCharCode(str2) # str指乱码字符
ab = b64(str1)# b64指魔改的base64。
-
这就是简单的生成逻辑。日志中不止一处生成了256位数组,然后修改数组位移,我只截图了一处,另外一处各位大佬们看看日志就可以解决掉。
-
最麻烦,最难的应该是50位数组,下面会着重讲下50位数组的生成逻辑,其他位置难度不大,大佬们多多动手。
50位数组
-
我们先定位到50位数组的生成位置。
-
日志不完整没办法了,我们直接再看这个 d()方法的代码。
-
最后我问了 AI,搜索了很多文章,看到有一篇里的大佬是这么讲的,给指令集的位置打上断点,看下出现最多的指令集数字,查看该分支内有没有日志断点,二者取余,即可。(站在巨人的肩膀很爽)
-
最终断点位置贴图如下。
-
打好日志断点后,再看生成位置。
-
这个时候就有 50位数组的来历了。
思路一:
-
这 88位数组也就是E,可以称之为是个全局数组,里面包含了所有的内容,比如载荷请求内容,定值字符串,还有些固定的数字、数组,国密加密返回的数组,浏览器指纹返回的数组、短数组、时间戳、版本号等等。其中也有我们需要的 50位数组。
-
这个是大数组的索引值,是固定的,也就是说,如果把这个全局数组复原了,利用这个定值索引,从全局数组中取值,最后 push进数组,就能得到我们的 50位数组。
-
这个方法极其麻烦,需要再重头走一遍日志,从全局数组生成位置,就开始跟,生成值后 push进全局数组,这样写整体的代码也可以修改,后续需要值的时候可以直接从全局数组取。
-
日志可以多打几遍,50位数组中也有固定的参数。
思路二:
-
依旧是这张图。
-
我们从途中可以看到 50位数组的索引值,可以向上追,全局数组索引值是什么时候添加进去的,是通过什么方式得到的,通过日志得到当前索引值是如何生成的,直接 push进数组得到 50位数组即可。
-
这种方式无需复原全局数组。
贴图
总结
-
讲一下我遇到的坑吧
- 没遇到随机数、时间戳的代码还原时要确认,保证还原的与网站一样。
- 时间戳的差值
- 轨迹可以是定值
-
希望各位大佬能指出不足,多多指教!