极验反爬虫防护分析之接口交互的解密方法补遗
本文要分享的内容是去年为了抢鞋而分析 极验(GeeTest)反爬虫防护的笔记,由于篇幅较长(为了多混点CB)我会按照我的分析顺序,分成如下四个主题与大家分享:
本文是第三篇《接口交互的解密方法补遗》,书接上文,上一篇中,我们遗留了两个问题:
- AES的密钥如何生成。
- e的值是什么内容,如何计算得到。
不过在后来的调试过程中发现,geetest并不是简单的使用了base64加密,所以需要进一步分析一下,下面进入正文~
AES加密结果的BASE64编码
在调试的过程中发现AES加密的结果并不是简单的BASE64编码,如下图:
看代码像是BASE64编码后提交给服务器的,但是我将o的值
导出后,自己进行base64编码的结果与这里不一样,因此跟进$_BABW
方法继续分析,如下图:
由此可知,最终的加密结果是由["res"]
+["end"]
拼凑起来的,具体的跟进 $_JJM
方法继续分析, 将混淆的代码还原之后,JS代码如下:
var Base64 = { "$_JGH": function(e){ var t = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789()"; return e < 0 || e >= t["length"] ? "." : t.charAt(e); }, "$_JIY": function(e, t) { return e >> t & 1; }, "$_JJM": function(e, o) { var $this = this; function t(e, t) { for (var n = 0, r = 24 - 1; 0 <= r; r -= 1) { 1 === $this["$_JIY"](t, r) && (n = (n << 1) + $this["$_JIY"](e, r)); } return n; } for (var n = "", r = "", a = e["length"], s = 0; s < a; s += 3) { var c; if (s + 2 < a) { c = (e[s] << 16) + (e[s + 1] << 8) + e[s + 2]; n += this["$_JGH"](t(c, 7274496)) + this["$_JGH"](t(c, 9483264)) + this["$_JGH"](t(c, 19220)) + this["$_JGH"](t(c, 235)); } else { var u = a % 3; 2 == u ? (c = (e[s] << 16) + (e[s + 1] << 8), n += this["$_JGH"](t(c, 7274496)) + this["$_JGH"](t(c, 9483264)) + this["$_JGH"](t(c, 19220)), r = ".") : 1 == u && (c = e[s] << 16, n += this["$_JGH"](t(c, 7274496)) + this["$_JGH"](t(c, 9483264)), r = "." + "."); } } return {'res': n, 'end': r} }, "encode": function (e) { var t = this["$_JJM"](e); return t["res"] + t["end"]; } } // 使用方法,直接将要加密的字节数组传入方法即可 var result = Base64["encode"]([92,25,128,...]) console.log(result);
导出官网要加密的数组,加密结果如下图:
AES密钥的生成方法
继续向上追溯AES密钥的生成方法,来到如下位置:
跟进wr方法,得到如下代码:
由此,整理出来AES密码的生成方法为:
/** * AES密钥的获取方法 */ function create_key() { return (65536 * (1 + Math.random()) | 0).toString(16).substring(1); }; function get_aes_key() { return wr() + wr() + wr() + wr(); }
e值的来历
跟进分析之后,发现e的值是从浏览器的window对象中依次获取,如下内容的信息:
0: "textLength" 1: "HTMLLength" 2: "documentMode" 3: "A" 4: "ARTICLE" 5: "ASIDE" 6: "AUDIO" 7: "BASE" 8: "BUTTON" 9: "CANVAS" 10: "CODE" 11: "IFRAME" 12: "IMG" 13: "INPUT" 14: "LABEL" 15: "LINK" 16: "NAV" 17: "OBJECT" 18: "OL" 19: "PICTURE" 20: "PRE" 21: "SECTION" 22: "SELECT" 23: "SOURCE" 24: "SPAN" 25: "STYLE" 26: "TABLE" 27: "TEXTAREA" 28: "VIDEO" 29: "screenLeft" 30: "screenTop" 31: "screenAvailLeft" 32: "screenAvailTop" 33: "innerWidth" 34: "innerHeight" 35: "outerWidth" 36: "outerHeight" 37: "browserLanguage" 38: "browserLanguages" 39: "systemLanguage" 40: "devicePixelRatio" 41: "colorDepth" 42: "userAgent" 43: "cookieEnabled" 44: "netEnabled" 45: "screenWidth" 46: "screenHeight" 47: "screenAvailWidth" 48: "screenAvailHeight" 49: "localStorageEnabled" 50: "sessionStorageEnabled" 51: "indexedDBEnabled" 52: "CPUClass" 53: "platform" 54: "doNotTrack" 55: "timezone" 56: "canvas2DFP" 57: "canvas3DFP" 58: "plugins" 59: "maxTouchPoints" 60: "flashEnabled" 61: "javaEnabled" 62: "hardwareConcurrency" 63: "jsFonts" 64: "timestamp" 65: "performanceTiming" 66: "internalip" 67: "mediaDevices" 68: "DIV" 69: "P" 70: "UL" 71: "LI" 72: "SCRIPT" 73: "deviceorientation" 74: "touchEvent"
这些key对应的内容为:
A: 337 BUTTON: 1 CPUClass: undefined DIV: 648 HTMLLength: 185450 IFRAME: 7 IMG: 60 INPUT: 48 LABEL: 9 LI: 222 LINK: 17 P: 75 SCRIPT: 69 SECTION: 1 SPAN: 239 STYLE: 2 UL: 49 browserLanguage: "zh-CN" browserLanguages: "zh-CN,zh,zh-TW,zh-HK,en-US,en" canvas2DFP: "805a6cdeadd4f48ade985597f74928cb" canvas3DFP: "cc03697d39800df1ef0d2229132a62e8" colorDepth: 24 cookieEnabled: 1 devicePixelRatio: 1 deviceorientation: false doNotTrack: 1 documentMode: "CSS1Compat" flashEnabled: -1 hardwareConcurrency: 4 indexedDBEnabled: 1 innerHeight: 443 innerWidth: 1634 internalip: undefined javaEnabled: 0 jsFonts: "AndaleMono,Arial,ArialBlack,ArialNarrow,ArialRoundedMTBold,ArialUnicodeMS,ComicSansMS,Courier,CourierNew,Geneva,Georgia,Helvetica,HelveticaNeue,Impact,LUCIDAGRANDE,MicrosoftSansSerif,Monaco,Palatino,Tahoma,Times,TimesNewRoman,TrebuchetMS,Verdana" localStorageEnabled: 1 maxTouchPoints: 0 mediaDevices: -1 netEnabled: 1 outerHeight: 1027 outerWidth: 1634 performanceTiming: "-1,-1,0,0,0,0,0,123,208,1,99154,10,8,403,418,1005,-1,-1,-1,-1" platform: "MacIntel" plugins: "" screenAvailHeight: 1027 screenAvailLeft: 44 screenAvailTop: 23 screenAvailWidth: 1636 screenHeight: 1050 screenLeft: 46 screenTop: 23 screenWidth: 1680 sessionStorageEnabled: 1 systemLanguage: undefined textLength: 46216 timestamp: 1568186269219 timezone: -8 touchEvent: false userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:69.0) Gecko/20100101 Firefox/69.0"
将这些值取为数组并用 !!
进行分隔生成字符串,就得到了e的值。因页面内容相对固定,也取固定字符来用,省的每次单独生成了。
至此,接口交互中参数加密解密的部分就都分析完毕了。下一篇也是最后一篇,我们一起来看如何绕过号称基于大数据的智能行为验证组件Slide的内容: 《极验反爬虫防护分析之slide验证方式下图片的处理及滑动轨迹的生成思路》