本文要分享的内容是去年为了抢鞋而分析 极验(GeeTest)反爬虫防护的笔记,由于篇幅较长(为了多混点CB)我会按照我的分析顺序,分成如下四个主题与大家分享:
本文是第四篇, 也是最后一篇,网上大部分针对极验的绕过方法大都是模拟手工滑动滑块的方式,但是通过上面几篇文章的分析,我们是能知道Geetest已经对目前市面上大多自动化测试的工具进行了监测,包括 Selenium甚至electron等。所以基于这些工具的破解不是不行,只是人家官方没有严查,不长久的,稳妥之计还是要直接从封包入手。下面进入正文~
背景图片乱序的还原
如《极验反爬虫防护分析之交互流程分析》第五步的分析,得到的 bg和fullbg图片都是乱序处理后的图片,要判断滑动的距离及轨迹需要将图片进行还原。如下图:
还原后的代码为:
functionSEQUENCE() {var e = "6_11_7_10_4_12_3_1_0_5_2_9_8".split("_");for (var t, n = [], r = 0; r < 52; r++) {
t= 2 * parseInt(e[parseInt(r % 26 / 2)]) + r % 2;
parseInt(r/ 2) % 2 || (t += r % 2 ? -1 : 1);
t+= r < 26 ? 26 : 0;
n["push"](t);
}returnn;
}var result =SEQUENCE();
console.log(result.join(", "));
至此,我们知道它是通过两次折叠构建出来52个元素的散列表。通过固定的公式将图片上下、左右互换并根据散列表的值进行乱序。通过分析代码中的字符串常亮6_11_7_10_4_12_3_1_0_5_2_9_8是在slide.7.6.0.js文件中,一开始的方法中定义的:$_DAEAF = decodeURI('N-%60%13)nN-%60%1C%1...,decodeURI解码后的数组第911位就是此字符串常量, 如下图:
继续跟进绘图的代码:
将混淆的代码还原之后,如下:
function$_GEN(t, e) {var $_CJDIX = $_AB.$_Ei()[4][26];for (; $_CJDIX !== $_AB.$_Ei()[8][24];) {switch($_CJDIX) {case $_AB.$_Ei()[16][26]:
t= t[$_DEAo(65)], e = e[$_DDJm(65)];var n = t["width"], r = t["height"], i = document[$_DDJm(27)]($_DEAo(91));
i["width"] = n, i["height"] =r;var CanvasRenderingContext2D = i["getContext"]("2d");
$_CJDIX= $_AB.$_Ei()[8][25];break;case $_AB.$_Ei()[8][25]:
CanvasRenderingContext2D["drawImage"](t, 0, 0);var CanvasRenderingContext2D = e["getContext"]("2d");
e["height"] = r, e["width"] =WIDTH;for (var a = r / 2, u = 0; u < 52; u += 1) {var c = SEQUENCE % 26 * 12 + 1, _ = 25 < SEQUENCE ? a : 0,
l= CanvasRenderingContext2D["getImageData"](c, _, 10, a);
CanvasRenderingContext2D["putImageData"](l, u % 26 * 10, 25 < u ? a : 0);
}
$_CJDIX= $_AB.$_Ei()[0][24];break;
}
}
}
将以上JS编写为还原图片的Python代码如下:
importnumpy as npfrom PIL importImageimportmatplotlib.pyplot as pltdefsequence():
t=0
n=[]
e= "6_11_7_10_4_12_3_1_0_5_2_9_8".split("_")for r in range(0, 52):
t= 2 * int(e[int(r%26/2)]) + r % 2
if 0 == int(r/2)%2:
t+= -1 if (r%2) else 1t+= 26 if (r<26) else0
n.append(t)returnndefgen(_seq, _img):"""用于将图片还原
@param _seq: 图片的序列号,也就是 Sequence 方法生成的结果
@param _img: 图片
@return new img"""r= 160a= int(r / 2)
np_image=np.array(img)
new_np_img= np.zeros((160, 312, 3), dtype=np.uint8)for u in range(0, 52):
c= _seq % 26 * 12 + 1_= int(a if (25 < _seq) else0)
xpos= u % 26 * 10ypos= a if (25 < u) else0#var l = getImageData(c, _, 10, a);
#putImageData(l, u % 26 * 10, 25 < u ? a : 0);
slice_img = np_image[_:(_+a), c:(c+10)]
n=len(slice_img[0])
new_np_img[ypos:(ypos+a), xpos:(xpos+n)] =slice_imgreturnnew_np_imgif __name__ == "__main__":
seq=sequence()
img= Image.open('/Users/datochan/WorkSpace/VSCProjects/nike-bot/Test/src/images/fullbg.jpg')
newimg=gen(seq, img)
plt.imshow(newimg)
plt.show()
找一个待处理的图片:https://static.geetest.com/pictures/gt/6edec3cc1/6edec3cc1.jpg,测试结果如下图:
至此,图片乱序还原的问题搞定。
滑动轨迹的加密方法
同样的方法跟踪滑块失败后的请求,分析回溯来到如下代码:
"$_CHBV": function(t, e, n) {var $_CABJD = $_AB.$_Ds, $_CABIQ = ['$_CACCE'].concat($_CABJD), $_CACAM = $_CABIQ[1];
$_CABIQ.shift();var $_CACBm = $_CABIQ[0];var r = this, i = r[$_CABJD(78)];var o ={"lang": i[$_CABJD(172)] || $_CACAM(161), //语言固定为 zh-hk || zh-cn
"userresponse": $_CEI(t, i[$_CABJD(139)]), //t=滑动的距离,用户响应的内容, $_CABJD(139) = "challenge" 的值