本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除!
目标
解决JD常用的验证码
前言
这里常用的就三种接口
[ol]
[/ol]
还有两个验证码
三种验证
登录的滑块接口
接口链接
aHR0cHM6Ly9wYXNzcG9ydC5qZC5jb20vdWMvbG9naW4/bHR5cGU9bG9nb3V0
如上图所示。
这里就不多说废话了。直接刷新看接口
这里可以看到 有两个接口请求发出。分别为
g请求
这里看g请求。直接进第二个栈。
这里看到 很多值已经给了我们值了。这里我们重点观察两个值。分别是e 和 j
这里打断点进栈
好了 然后再进去。然后发现到一个虚拟机里了 这里包含了 e的生成。
然后就是j
j的生成不必多说。看下图就知道了。
其他的值。
然后看返回值
上述请求有几个值需要提出来。方便后续s调用
S请求
这里继续看s请求。
这里和上图结果图作为比较。可以发现。
c好像就是challenge。
这里话不多说了。其他的值都不重要 。
最主要是这个d参数。
我们重点来看这个d
如下图所示。很多值的生成都能直接看到。
这里d 值的生成 则是由一个方法传参加密了一堆数组。
那这个数组是啥东西。其实我们不难发现这就是个轨迹。通过getCoordinate这个方法 才变成了请求接口中的d这个样子。
d方法如下:
'getCoordinate': function(a) {
var b = this;
var c = new Array();
for (var d = 0x0; d
这个方法很简单。缺什么扣什么。
然后传值轨迹。
至于轨迹的生成。可以通过某些算法去实现这个列表数组的生成。
这里是通过举例然后偏移出数组变量
这里贴个方法用于生成数组。
def offer(distance):
index = 0
slide = []
indexTime = str(int(time.time()))[:9]
for item in self.base_slide:
index += 1
item[2] = int(indexTime + str(item[2])[-4:])
if int(item[0]) >= (distance + int(self.base_slide[0][0])):
slide = self.base_slide[:index]
slide.append(
[str(distance + int(self.base_slide[0][0])), item[1], item[2] + 700 + int(random.random() * 1000)])
break
last = int(slide[-1][0].split('.')[0])
pIndex = 0
for item in self.push_slide:
if pIndex == 0 or pIndex == len(self.push_slide) - 1:
times = slide[-1][2]
else:
times = slide[-1][2] + (self.push_slide[pIndex + 1][2] - self.push_slide[pIndex][2])
slide.append([str(item[0] + last), '369', times])
pIndex += 1
# print(json.dumps(slide))
return slide
最后通过getCoordinate 生成加密值。
最后伪装成功参数 然后请求就行了 返回下图代表成功。
cfe接口滑块
下面接口网站如下
aHR0cHM6Ly9jZmUubS5qZC5jb20vcHJpdmF0ZWRvbWFpbi9yaXNrX2hhbmRsZXIvMDMxMDE5MDAvP3JldHVybnVybD1odHRwcyUzQSUyRiUyRml0ZW0uamQuY29tJTJGMTAwMDQ4MjcyNzYyLmh0bWwmcnFob3N0PWh0dHBzJTNBJTJGJTJGYXBpLm0uamQuY29tJnJwaWQ9cnAtMTg2NTQ5NDkwLTEwMDU2LTE3MDk3MTMyMDgzNzEmZXZ0eXBlPTImZXZhcGk9Y29sb3JfcGNfZGV0YWlscGFnZV93YXJlQnVzaW5lc3Mmc291cmNlPTEmZm9yY2VDdXJyZW50Vmlldz0x
如下图页面。这就到了另一个滑块的接口。
这里我们点击快速验证。然后完整的走一遍流程看看。具体的走向是如何的
如下图所示。
这里首先筛选xhr请求。请求太多
如下图所示。图中经过了这么多的请求。
我们一个一个看。
第一个m?std 请求 返回值是0 目测只是判断状态的请求。
第二个api请求。如下图 返回了一个值。请求参数中enbody加密了
第三个api请求也是加密了 enbody。返回值没东西。应该也是个请求判定。
第四个fp请求。请求需要伪装si 和 ct。 而这个si 刚好和第二个api请求的si相同。 返回了 fp 和 st。
第五个请求: web_jcap_report 返回了 code为0 无用请求。
第六个请求:请求传参中带有上图fp参数的加密 还多了个tk加密。返回值 返回了 缺口图和背景图。
第七个请求:无用请求
第八个请求:即是第二个check请求。同第六个请求相似。但是返回值不一样。
那这样我们大概就能明白个具体流程了。
[ol]
[/ol]
api请求
这里我们首先去看一下api请求。
如上图。所示 只有这个enbody值是通过加密获得的。那我们去搜索一下 或者走栈。
如下图所示 直接获取到了 enbody加密的地方。
这里简化一下代码
result = encrypt(JSON.stringify(param), 'rhiasnkdhandrisk', 'r-s-h-n_r_isnkdk')
然后过一下断点。这里可以看到 加密的值分别为
eid: 可以为空
evType: 应该是验证码类型 2
requestId: 由另一个接口605返回的requestID
shshshfpx: 是一个随机值的算法。包含随机生成以及时间戳的拼接。
第二次api请求。这里第二次请求加密的值是 第一次的返回值 已经第一次的那个请求参数。其实可以不需要。这里也展示一下
fp请求
这里fp请求。不太好搜索。我们直接进栈
进栈然后搜索 .si 这里可以发现。ct的算法 已经出来了。
这里可以看到 。这个值应该就是加密的值。
然后把几个函数互相扣一下就行。
这个x函数的算法如下
function s(t, e, n) {
var r = t
, a = o;
e && (i = e);
return c(r, a)
}
这里层层扣即可。
然后把第一次api返回的那个data和这个新生成的ct
去请求 得到fp和 st
两次check
第一次
断点继续走 走到下图所在位置
如上图所示。
这里需要注意的是 这里的t 暂时是不传值的。这里t是什么先留个悬念。
然后进行加密就得到了tk和ct。
然后请求。得到两张以base64为编码的图片。
第二次check请求
这里其他值加密都是一样的。
唯一不同就是这个 JSON.stringify(t) 如下图所示
这里传值是轨迹。通过两张图片识别出来的距离 最终通过算法生成轨迹。
这里轨迹简单看看 第一个是移动的距离值。
第二个和第三个 如下图js所示的位置
这里可以通过算法去实现 也可以通过自建库来实现。
最后通过这些值加密 得到请求参数即可完成滑块。整体流程如下
cfe 点选验证
下面接口网站如下
aHR0cHM6Ly9jZmUubS5qZC5jb20vcHJpdmF0ZWRvbWFpbi9yaXNrX2hhbmRsZXIvMDMxMDE5MDAvP3JldHVybnVybD1odHRwcyUzQSUyRiUyRml0ZW0uamQuY29tJTJGMTAwMDQ4MjcyNzYyLmh0bWwmcnFob3N0PWh0dHBzJTNBJTJGJTJGYXBpLm0uamQuY29tJnJwaWQ9cnAtMTg2NTQ5NDkwLTEwMDU2LTE3MDk3MTMyMDgzNzEmZXZ0eXBlPTImZXZhcGk9Y29sb3JfcGNfZGV0YWlscGFnZV93YXJlQnVzaW5lc3Mmc291cmNlPTEmZm9yY2VDdXJyZW50Vmlldz0x
和滑块一个连接 不同的是 验证码不一样。
触发方式应该是与爬取的等级而定。
如上图所示。
其实上图大体流程都是一样的。这里唯一有一点区别。
如下图所示。这里JSON.stringify(t) 里面传值的不是轨迹。而是 点选的坐标。
这里可以通过两种方式去解决
[ol]
[/ol]
这里还有一点需要注意。
这里点选的 验证码
第一次check返回的tp值是22 。
而滑块是30
可以通过这个去区分验证码。