某验滑块加密分析(上)
目标网站:aHR0cHM6Ly93d3cuZ2VldGVzdC5jb20vZGVtby9zbGlkZS1mbG9hdC5odG1s这个滑块没有涉及到补环境这些,比较容易上手,由于流程复杂,我就把它分为上下两篇.上 主要讲如何拿到缺口图片 下篇讲如何加密轨迹生成w值!
直接上手分析(最好边扣边写下流程,不然扣到后面会被搞懵逼):
一.打开f12抓包分析.从最开始发包到拿到缺口图片主要有这几步:
(1)请求接口拿到challenge(这个会改变)和gt值
(2)请求get.php拿到一个json,这里请求带了一个w值 需要破解的地方
(3)请求ajax.php,拿到验证码类型.这里也有一个w值加密,而且可以明显看出跟上一个get.phpw值加密方式不一样
(4)再请求get.php获取缺口图片以及后面加密会用到的参数.
流程分析完毕,大概就是先拿到gt和challge 然后经过两次请求后端验证,成功通过,第四次请求返回图片json.
二.定位第二步加密位置,
有一点经验的应该知道极验的w值unicode编码后可以直接搜到加密位置,如果新手的话推荐在发包位置,点开js,然后一步一步堆栈上去,这样可以加深映像.
这里由于主要是讨论如何加密,所以定位就自己摸索下,我直接全局搜\u0077 然后进入fullpage这个js里面
接下来继续搜"\u0077" 可以看到有三个位置,分别在三个位置打上断点,然后刷新网页,可以看到断点断住了
而"\u0077"这个值也就是w是由a+n拼接起来的,接下来就要找a和n生成的地方.这里可以明显看到n生成的地方var n = t();
我们要跟进这个t方法看看到底怎么生成的,所以在这一行打上断点,然后刷新网页(如果没断住的话 有可能是浏览器卡了 重新打开一个网页下断点就行).
断住后我们可以鼠标左键选中t这个方法,会出来他的方法,然后点进去.或者在控制台输入t也会出来,点进去
好的,开始分析.这个方法最后只返回了一个r,所以我们直接找r生成的地方,有两个地方生成,第一个是直接生成new Q()(t(e))第二个是判断上面生成的r长度不为256时再生成一次,其实看第一个生成就行了,因为这个r是rsa加密。
在第一个r生成打上断点,new Q()(t(e))可以拆解成 t(e) 生成了一个参数然后传到new Q()这个方法里面。
接下来找t加密方法,我们在控制台输入t 然后点进去,
看到只返回了t而t又是ce()生成的.直接在ce()处断点跟进去,
又可以看到是四个S4()拼接起来的,继续断点跟进S4(),可以看到
在他的return下断点,然后选中DUQR(246) 可以看到是random ,toString是toString,substring是substring
接下来替换下((1 + Math()) * 65536 | 0)(16)(1) 就变成了((1 + Math["random"]()) * 65536 | 0)["toString"](16)["substring"](1)+((1 + Math["random"]()) * 65536 | 0)["toString"](16)["substring"](1)
所以可以得到t(e)就是四个((1 + Math["random"]()) * 65536 | 0)["toString"](16)["substring"](1)+((1 + Math["random"]()) * 65536 | 0)["toString"](16)["substring"](1)拼接起来
我们写个function方便后面调用
function get_ue(){
//这里是四个随机数的加密
return ((1 + Math["random"]()) * 65536 | 0)["toString"](16)["substring"](1)+((1 + Math["random"]()) * 65536 | 0)["toString"](16)["substring"](1)+((1 + Math["random"]()) * 65536 | 0)["toString"](16)["substring"](1)+((1 + Math["random"]()) * 65536 | 0)["toString"](16)["substring"](1)
}
接下来分析new Q() 操作还是一样断点,控制台输入跟进这个方法
在这里,要说一点,扣js是能不改代码就最好别改,因为你不知道这成千上万行的代码到底哪些代码被你这个加密用到了,能用原生的js就用原生的js.对于new Q()这个加密可以直接把这个加密函数扣下来,然后缺啥补啥,但是这样扣起来比较耗时.所以我推荐第二种方法,
在fullpage这个js里面我们可以看到整体就是一个大的function而且把这个function 放进浏览器运行不报错,说明所有的js都在这里面,我们可以直接导出他的方法来用,有点像python实例化一个class,然后直接调用这个class里面的方法.
直接把fullpage所有的js复制下来放进notepad++里面然后折叠所有层次,接下来全局搜索function QtWm(e) {就可以定位到他,我们可以看见它在一个function里面并被赋值给Q,
由于这个大function是一个闭包,得定义一个全局变量来接收这个function直接在js开头定义 vartestRSA;然后在这个Q后面接收他
接下来 ,在这个大function后面写上自己的调用方法,大致如下:
function get_ue(){
//这里是四个随机数的加密
return ((1 + Math["random"]()) * 65536 | 0)["toString"](16)["substring"](1)+((1 + Math["random"]()) * 65536 | 0)["toString"](16)["substring"](1)+((1 + Math["random"]()) * 65536 | 0)["toString"](16)["substring"](1)+((1 + Math["random"]()) * 65536 | 0)["toString"](16)["substring"](1)
}
functionget_w(){
//第一个w值
//首先拿到四个随机数
varue=get_ue()
//加密这四个随机数 var r = new Q()(t(e));
varr=new testRSA()['encrypt'](ue)
return r
}
encrypt就是SBvg(352)反混淆的结果.接下来直接把代码丢进浏览器运行,可以得出结果(这样扣出来的代码只能在浏览器运行,在node运行会报错,因为代码里面有一些操作html和获取windows的 这些都是node环境没有的,如需在node运行,需要删除一些代码,这里只是做交流分析用,就不提供删除方法了,感兴趣可以自己慢慢调试删除)
这样 我们就把n值得到了,接下来扣a值var a = u(i); 发现里面用到了i,所以我们需要先扣i的生成,方法同上 var i = it()(ve(t), t());
分析一下他是先生成ve(t) 和 t 生成i.所以我们先找 t[NMLl(1257) 的加密生成,断点跟进去发现就是四个随机数拼接的,跟上面的ue()一样,这里就不多说了.
接下来看ve(t)这个也可以拆分成两个往ve传入t 得到结果,所以我们先找t是什么,控制台输入t可以得到结果
对于这种是个json的数据 我们最好多刷新几次多次输入看看结果有何不同,如果结果不变就说明是固定的,那就少很多事,如果值变了,就去找那个值的生成方法.通过多次刷新调用,发现这个json变化的是key为challenge和i的值.
challenge是官方返回的到时传进去就行,找i生成的地方.先看同一个function里面的参数,如果找不到就往上一级堆栈继续找,极验这个就在同一个function
可以很明显看出 t() 生成一个值(也就是json里面i的值)赋值给e最终e赋值给t 而MXFq(269)反混淆就是i.
所以我们要找t() 加密方法.控制台输入,然后进去断点.
从头到尾看,首先我们得找到n值,控制台输入r 可以得到一个json,多刷新几次后,发现结果不变.我们直接把它写死.
n就是个时间戳,接下来四个赋值都是-1,一步一步跟下去就可以看到,接下来就是一个for循环.r() 就是他的循环顺序 ,这个是固定不变的.
简单分析下这个算法 for循环r()的长度次数,每次循环取出r()对应的值,然后根据这个key再从r 拿到对应的值 在根据一个三元运算往i这个空数组里面push运算出来的值,最后一步相当于python的"!!".join(i)拼接起来返回
算法大概就是这样,可以一步一步运行起来看运算过程,我这边就不细跟下去了.然后开始自己写一个算法,这个思路比较简单,直接上手写
function getiii(){
//拿到json里面变化的i值n是固定的
varn={"STYLE":1,"SCRIPT":6,"A":1,"DIV":12,"LABEL":3,"INPUT":2,"textLength":14438,"HTMLLength":15743,"documentMode":"CSS1Compat","browserLanguage":"zh-CN","browserLanguages":"zh-CN","devicePixelRatio":1,"colorDepth":24,"userAgent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36","cookieEnabled":1,"netEnabled":1,"innerWidth":376,"innerHeight":950,"outerWidth":1920,"outerHeight":1040,"screenWidth":1920,"screenHeight":1080,"screenAvailWidth":1920,"screenAvailHeight":1040,"screenLeft":0,"screenTop":0,"screenAvailLeft":0,"screenAvailTop":0,"localStorageEnabled":1,"sessionStorageEnabled":1,"indexedDBEnabled":1,"platform":"Win32","doNotTrack":0,"timezone":-8,"canvas2DFP":"584f4432fe6ebea605c1f943c0a39f15","canvas3DFP":"0b03cc6df4e2fc61df0144cad52b685f","plugins":"nppdf32.dll,npalissologin.dll,npAliSecCtrl.dll,npaliedit.dll,npYunWebDetect.dll,internal-pdf-viewer,mhjfbmdgcfjbbpaeojofohoefgiehjai,np-mswmp.dll,internal-nacl-plugin,npQQMailWebKit.dll,npQMExtensionsMozilla.dll,npQzoneMusic.dll,npactivex.dll,npxluser2.0.2.3.dll,npcombrg.dll,npQQPhotoDrawEx.dll","maxTouchPoints":0,"flashEnabled":-1,"javaEnabled":0,"hardwareConcurrency":6,"jsFonts":"Arial,ArialBlack,ArialNarrow,Calibri,Cambria,CambriaMath,ComicSansMS,Consolas,Courier,CourierNew,Georgia,Helvetica,Impact,LucidaConsole,LucidaSansUnicode,MicrosoftSansSerif,MSGothic,MSPGothic,MSSansSerif,MSSerif,PalatinoLinotype,SegoePrint,SegoeScript,SegoeUI,SegoeUILight,SegoeUISemibold,SegoeUISymbol,Tahoma,Times,TimesNewRoman,TrebuchetMS,Verdana,Wingdings","mediaDevices":-1,"timestamp":1626511113995,"deviceorientation":-1,"touchEvent":-1,"performanceTiming":-1,"internalip":-1}
n['timestamp']=new Date()["getTime"]();
// n['timestamp']=1626521179265;
// n['timestamp']=1626519692398;
n['deviceorientation']=-1;
n['touchEvent']=-1;
n['performanceTiming']=-1;
n['internalip']=-1;
var i = [];
var thx=["textLength", "HTMLLength", "documentMode", "A", "ARTICLE", "ASIDE", "AUDIO", "BASE", "BUTTON", "CANVAS", "CODE", "IFRAME", "IMG", "INPUT", "LABEL", "LINK", "NAV", "OBJECT", "OL", "PICTURE", "PRE", "SECTION", "SELECT", "SOURCE", "SPAN", "STYLE", "TABLE", "TEXTAREA", "VIDEO", "screenLeft", "screenTop", "screenAvailLeft", "screenAvailTop", "innerWidth", "innerHeight", "outerWidth", "outerHeight", "browserLanguage", "browserLanguages", "systemLanguage", "devicePixelRatio", "colorDepth", "userAgent", "cookieEnabled", "netEnabled", "screenWidth", "screenHeight", "screenAvailWidth", "screenAvailHeight", "localStorageEnabled", "sessionStorageEnabled", "indexedDBEnabled", "CPUClass", "platform", "doNotTrack", "timezone", "canvas2DFP", "canvas3DFP", "plugins", "maxTouchPoints", "flashEnabled", "javaEnabled", "hardwareConcurrency", "jsFonts", "timestamp", "performanceTiming", "internalip", "mediaDevices", "DIV", "P", "UL", "LI", "SCRIPT", "deviceorientation", "touchEvent"]
for(var j = 0; j < thx.length; j++) {
var t = n]
// check_type(t)
i["push"](check_type(t) ? -1 : t)
}
return i["join"]("!!")
}
到此,json里面的i值就生成了,i值生成,那t 这个参数就组成了,接下来就是看it()这个方法是什么
同上操作,现在控制台输入MXFq(1250),得到一个encrypt1 看到这个单词,其实就大概可以猜出他是什么加密.js扣多了,加密其实就那几个.控制台输入it()跟进去看.
这种加密,如果单独只扣出他的加密的话,就得一个一个补,很麻烦,最好的还是直接导出加密函数让自己调用.所以直接全局搜\u0065\u006e\u0063\u0072\u0079\u0070\u0074\u0031,可以看到他在 function it() 里面
还是老样子,定义一个全局变量testenc接收这个方法,然后调用就行,大致代码就是
varn={"STYLE":1,"SCRIPT":6,"A":1,"DIV":12,"LABEL":3,"INPUT":2,"textLength":14438,"HTMLLength":15743,"documentMode":"CSS1Compat","browserLanguage":"zh-CN","browserLanguages":"zh-CN","devicePixelRatio":1,"colorDepth":24,"userAgent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36","cookieEnabled":1,"netEnabled":1,"innerWidth":376,"innerHeight":950,"outerWidth":1920,"outerHeight":1040,"screenWidth":1920,"screenHeight":1080,"screenAvailWidth":1920,"screenAvailHeight":1040,"screenLeft":0,"screenTop":0,"screenAvailLeft":0,"screenAvailTop":0,"localStorageEnabled":1,"sessionStorageEnabled":1,"indexedDBEnabled":1,"platform":"Win32","doNotTrack":0,"timezone":-8,"canvas2DFP":"584f4432fe6ebea605c1f943c0a39f15","canvas3DFP":"0b03cc6df4e2fc61df0144cad52b685f","plugins":"nppdf32.dll,npalissologin.dll,npAliSecCtrl.dll,npaliedit.dll,npYunWebDetect.dll,internal-pdf-viewer,mhjfbmdgcfjbbpaeojofohoefgiehjai,np-mswmp.dll,internal-nacl-plugin,npQQMailWebKit.dll,npQMExtensionsMozilla.dll,npQzoneMusic.dll,npactivex.dll,npxluser2.0.2.3.dll,npcombrg.dll,npQQPhotoDrawEx.dll","maxTouchPoints":0,"flashEnabled":-1,"javaEnabled":0,"hardwareConcurrency":6,"jsFonts":"Arial,ArialBlack,ArialNarrow,Calibri,Cambria,CambriaMath,ComicSansMS,Consolas,Courier,CourierNew,Georgia,Helvetica,Impact,LucidaConsole,LucidaSansUnicode,MicrosoftSansSerif,MSGothic,MSPGothic,MSSansSerif,MSSerif,PalatinoLinotype,SegoePrint,SegoeScript,SegoeUI,SegoeUILight,SegoeUISemibold,SegoeUISymbol,Tahoma,Times,TimesNewRoman,TrebuchetMS,Verdana,Wingdings","mediaDevices":-1,"timestamp":1626511113995,"deviceorientation":-1,"touchEvent":-1,"performanceTiming":-1,"internalip":-1}
var bx=getiii(n)
//组装自己的json
varo={"gt":gt,"challenge":challenge,"offline":false,"new_captcha":true,"product":"float","width":"300px","https":true,"api_server":"apiv6.geetest.com","protocol":"https://","aspect_radio":{"beeline":50,"pencil":128,"click":128,"slide":103,"voice":128},"beeline":"/static/js/beeline.1.0.1.js","static_servers":["static.geetest.com/","dn-staticdown.qbox.me/"],"click":"/static/js/click.3.0.1.js","slide":"/static/js/slide.7.8.3.js","pencil":"/static/js/pencil.1.0.3.js","fullpage":"/static/js/fullpage.9.0.7.js","type":"fullpage","voice":"/static/js/voice.1.2.0.js","geetest":"/static/js/geetest.6.0.9.js","cc":6,"ww":true,"i":bx}
console.log(JSON.stringify(o))
//encrypt1是MXFq(1250)的反混淆
var bbb=testenc()["encrypt1"](JSON.stringify(o),ue)
这里就把var i = it()(ve(t), t());i值求到了,接下来就是 var a = u(i);这一步拿到a值,方法跟上面一样,控制台输入u 跟进去
发现他把上一步得出的i值传进来后,又经过t加密得到一个数组r,再把r的两个值拼接起来返回.如果我们自己改写又要去扣t这个方法 很麻烦,所以直接导出调用最简单.全局搜\u0053\u0042\u006f\u0058,发现在u这个方法里面,定义一个全局变量testaes接收.大致代码如下
var a = testaes["SBoX"](bbb);
到此三个方法都能自己生成了,我们写一个调用方法组装下这三个参数.
放进浏览器运行下
运行没问题,接下来就是验证这个w是否正确,写个简单的python脚本带上w值取请求接口就行,返回成功说明扣得没问题
三.分析ajax里面的w值生成.
这个ajax的w值生成,我是从发包地方一步一步堆栈跟上去的,他的加密位置大概就在这里(如果不想跟可以直接搜new Date() 进入fullpage最后一个)
直接控制台输入 esZZ(532) + r + esZZ(1367) + vrju(addHash() + vrju(vrju()) + vrju(e())) + esZZ(515) + fATm(554); 看得到什么
是一个字符串,最后return u(_(uHyn, r()));可以大致看懂就是加密了这个字符串(js里面有个JSON.stringify,可以把字典转成这种字符串的格式)然后返回.经过多次刷新发现r字符串里面会改变的key有tt,h,hh,hi,passtime,rp.
其中passtime就是耗时,这个可以随机.
接下来就找这几个值生成的地方.你可以全局搜r 或者从当前断点处往上看r在哪里生成的,大概位置就在同一个function里面
这一步就是往r里面添加东西,直接下断点,看看有些什么参数
控制台输出下s,发现是一个数组,里面的参数就是我们需要加密字符串的前身.看看s怎么来的[ || VLOJ(188)], , , a) || -1], , (t))], (n))], , )], || -1], || -1], () || -1], , + a + o)]];
找到变动的那几个key所对应的方法 tt , a) || -1];h(n))]; hh ;hi)] ;rp + a + o)];
一个一个看,先找tt的加密方法me(e, a, a) || -1. 可以看出就是往me里面穿了三个参数加密后得出的,其中e是r(); 得到的(上面有定义),a是一个数组,是上一步请求成功,服务器返回的,a也是.
分析完了,开始找r方法,控制台输入,跟进去,
分析下算法,把e里面的TRdL(返混淆后的)取出来赋值给t,然后e(e(t)并返回,先看看t是个什么东西,
是一个轨迹的数组,这种我们先写死,先扣算法,轨迹的生成可以后面慢慢研究.先直接进入e 看一下
直接全局变量导出,定义一个testtraj1接收,
后面如果不跟unicode码就代表导出那个大的hUUu方法,有unicode编码则导出里面unicode那个小方法,我这里是为了后面调试.再自写一个方法调用
function get_traeck(){
//轨迹信息
var t=[["move",378,344,1626838592485,"pointermove"],["move",377,344,1626838592527,"pointermove"],["move",376,345,1626838592542,"pointermove"],["move",376,346,1626838592614,"pointermove"],["move",376,347,1626838592655,"pointermove"],["move",376,349,1626838592662,"pointermove"],["move",376,350,1626838593046,"pointermove"],["move",376,351,1626838593054,"pointermove"],["move",376,352,1626838593062,"pointermove"],["move",376,353,1626838593071,"pointermove"],["move",376,354,1626838593078,"pointermove"],["move",376,357,1626838593088,"pointermove"],["move",376,358,1626838593103,"pointermove"],["move",376,359,1626838593110,"pointermove"],["move",376,361,1626838593118,"pointermove"],["move",375,361,1626838593230,"pointermove"],["move",373,360,1626838593238,"pointermove"],["move",373,359,1626838593246,"pointermove"],["move",371,359,1626838593254,"pointermove"],["move",370,358,1626838593262,"pointermove"],["move",368,357,1626838593271,"pointermove"],["move",366,356,1626838593278,"pointermove"],["move",364,355,1626838593287,"pointermove"],["move",362,354,1626838593294,"pointermove"],["move",359,352,1626838593302,"pointermove"],["move",357,351,1626838593310,"pointermove"],["move",354,350,1626838593318,"pointermove"],["move",351,350,1626838593326,"pointermove"],["move",348,350,1626838593334,"pointermove"],["move",346,350,1626838593342,"pointermove"],["move",345,349,1626838593350,"pointermove"],["move",342,349,1626838593358,"pointermove"],["move",338,349,1626838593366,"pointermove"],["move",333,349,1626838593374,"pointermove"],["move",329,348,1626838593382,"pointermove"],["move",321,346,1626838593390,"pointermove"],["move",317,344,1626838593398,"pointermove"],["move",313,344,1626838593407,"pointermove"],["move",309,341,1626838593414,"pointermove"],["move",303,337,1626838593422,"pointermove"],["move",299,335,1626838593430,"pointermove"],["move",296,332,1626838593439,"pointermove"],["move",294,330,1626838593447,"pointermove"],["move",293,329,1626838593473,"pointermove"],["move",292,329,1626838593478,"pointermove"],["move",290,329,1626838593487,"pointermove"],["move",290,327,1626838593526,"pointermove"],["move",290,326,1626838593534,"pointermove"],["move",289,325,1626838593542,"pointermove"],["move",290,325,1626838593662,"pointermove"],["move",291,325,1626838593671,"pointermove"],["move",294,324,1626838593678,"pointermove"],["move",294,322,1626838593688,"pointermove"],["move",296,322,1626838593694,"pointermove"],["move",296,321,1626838593710,"pointermove"],["move",297,320,1626838593726,"pointermove"],["move",298,319,1626838593734,"pointermove"],["move",298,318,1626838593742,"pointermove"],["move",299,317,1626838593751,"pointermove"],["move",301,317,1626838593758,"pointermove"],["move",302,316,1626838593767,"pointermove"],["move",303,314,1626838593774,"pointermove"],["down",303,314,1626838593849,"pointerdown"],["focus",1626838593850],["up",303,314,1626838593926,"pointerup"]]
var et=testtraj1(t)
return et
}
//console.log(get_ww("019924a82c70bb123aae90d483087f94","ea6698b3074ebb51c091ceaab07fe4f5"))
console.log(get_traeck())
丢进浏览器运行发现报错,这时候就需要手动debugger分析报错了啥,debugger过程我就不细说了,最后发现var l = o(e); 这一行报错,提示没有找到这个方法.跟进这个方法,
老规矩,全局变量接收testtraj2,并自写一个方法调用var l=testtraj2(t)
接下来这个l值生成了 ,我们传进去 所以还得对\u0067\u0052\u0045\u0056这个方法改写下,
"\u0067\u0052\u0045\u0056": function(e,thx) { var UGut = AXzPo.DVn
, TNZEZo = ['XtKnl'.concat(UGut)
, Vjlo = TNZEZo[1;
TNZEZo.shift();
var WvQs = TNZEZo[0;
var t = 0
, r = 0
, n = 0
, i = 0;
var a = [];
var o = this;
var s = o[Vjlo(735;
if (e[Vjlo(67)] <= 0) {
return [];
}
var c = null;
var _ = null;
// var l = o(e);
varl =thx;
var u = l[Vjlo(67;
// var f = u < this ? 0 : u - this;
var f = 0;
for (; f < u; f = f + 1) {
var p = l[f;
var h = p[0;
if (new hfAt([UGut(706), UGut(737), Vjlo(773), Vjlo(423)])[UGut(413)](h) > -1) {
if (!c) {
c = p;
}
_ = p;
a[UGut(31)]([h, [p[1] - t, p[2] - r, ck_e(s ? p[3] - s : s)]);
t = p[1;
r = p[2;
s = p[3;
} else if (new hfAt([Vjlo(410), UGut(434), UGut(482)])[Vjlo(413)](h) > -1) {
a[Vjlo(31)]([h, ck_e(s ? p[1] - s : s)]);
s = p[1;
}
}
o[UGut(748)] = c;
o[Vjlo(702)] = _;
return a;
},
大概说下改了哪些地方,我断点调试的时候 var l = o(e); 用 varl =thx;替代 thx就是testtraj2生成的值,var f = u < this ? 0 : u - this; 经过多次运算这里是0直接写死,o[Vjlo(745)]提示找不到,跟进去看发现算法很简单,直接改写
function ck_e(e){
var t = (1 << 15) - 1;
if (typeof e !=="number") {
return e;
} else if (e > t) {
e = t;
} else if (e < -t) {
e = -t;
}
return Math["round"](e);
}改动了这三个地方,接下来就放进浏览器运行,运行正常,所以e(t) 扣完了,接下来e,跟进去看是个encode 直接导出他,然后把这三个方法组一下,运行出最终的轨迹加密,代码如下:function get_traeck(){
//轨迹信息
var t=[["move",378,344,1626838592485,"pointermove"],["move",377,344,1626838592527,"pointermove"],["move",376,345,1626838592542,"pointermove"],["move",376,346,1626838592614,"pointermove"],["move",376,347,1626838592655,"pointermove"],["move",376,349,1626838592662,"pointermove"],["move",376,350,1626838593046,"pointermove"],["move",376,351,1626838593054,"pointermove"],["move",376,352,1626838593062,"pointermove"],["move",376,353,1626838593071,"pointermove"],["move",376,354,1626838593078,"pointermove"],["move",376,357,1626838593088,"pointermove"],["move",376,358,1626838593103,"pointermove"],["move",376,359,1626838593110,"pointermove"],["move",376,361,1626838593118,"pointermove"],["move",375,361,1626838593230,"pointermove"],["move",373,360,1626838593238,"pointermove"],["move",373,359,1626838593246,"pointermove"],["move",371,359,1626838593254,"pointermove"],["move",370,358,1626838593262,"pointermove"],["move",368,357,1626838593271,"pointermove"],["move",366,356,1626838593278,"pointermove"],["move",364,355,1626838593287,"pointermove"],["move",362,354,1626838593294,"pointermove"],["move",359,352,1626838593302,"pointermove"],["move",357,351,1626838593310,"pointermove"],["move",354,350,1626838593318,"pointermove"],["move",351,350,1626838593326,"pointermove"],["move",348,350,1626838593334,"pointermove"],["move",346,350,1626838593342,"pointermove"],["move",345,349,1626838593350,"pointermove"],["move",342,349,1626838593358,"pointermove"],["move",338,349,1626838593366,"pointermove"],["move",333,349,1626838593374,"pointermove"],["move",329,348,1626838593382,"pointermove"],["move",321,346,1626838593390,"pointermove"],["move",317,344,1626838593398,"pointermove"],["move",313,344,1626838593407,"pointermove"],["move",309,341,1626838593414,"pointermove"],["move",303,337,1626838593422,"pointermove"],["move",299,335,1626838593430,"pointermove"],["move",296,332,1626838593439,"pointermove"],["move",294,330,1626838593447,"pointermove"],["move",293,329,1626838593473,"pointermove"],["move",292,329,1626838593478,"pointermove"],["move",290,329,1626838593487,"pointermove"],["move",290,327,1626838593526,"pointermove"],["move",290,326,1626838593534,"pointermove"],["move",289,325,1626838593542,"pointermove"],["move",290,325,1626838593662,"pointermove"],["move",291,325,1626838593671,"pointermove"],["move",294,324,1626838593678,"pointermove"],["move",294,322,1626838593688,"pointermove"],["move",296,322,1626838593694,"pointermove"],["move",296,321,1626838593710,"pointermove"],["move",297,320,1626838593726,"pointermove"],["move",298,319,1626838593734,"pointermove"],["move",298,318,1626838593742,"pointermove"],["move",299,317,1626838593751,"pointermove"],["move",301,317,1626838593758,"pointermove"],["move",302,316,1626838593767,"pointermove"],["move",303,314,1626838593774,"pointermove"],["down",303,314,1626838593849,"pointerdown"],["focus",1626838593850],["up",303,314,1626838593926,"pointerup"]]
//轨迹加密报错 找不到var l = o(e);解决办法
var l=testtraj2(t)
//console.log(l)
var et=testtraj1(t,l)
//console.log(et)
var i=testencode(et)
return i
}
//console.log(get_ww("019924a82c70bb123aae90d483087f94","ea6698b3074ebb51c091ceaab07fe4f5"))
console.log(get_traeck())浏览器运行下结果对的,ok搞定.me(e, a, a)现在这me里面的三个参数都知晓了 ,直接跟进me方法里面,导出它直接调用 最终代码如下:
function get_traeck(){
//轨迹信息
var t=[["move",378,344,1626838592485,"pointermove"],["move",377,344,1626838592527,"pointermove"],["move",376,345,1626838592542,"pointermove"],["move",376,346,1626838592614,"pointermove"],["move",376,347,1626838592655,"pointermove"],["move",376,349,1626838592662,"pointermove"],["move",376,350,1626838593046,"pointermove"],["move",376,351,1626838593054,"pointermove"],["move",376,352,1626838593062,"pointermove"],["move",376,353,1626838593071,"pointermove"],["move",376,354,1626838593078,"pointermove"],["move",376,357,1626838593088,"pointermove"],["move",376,358,1626838593103,"pointermove"],["move",376,359,1626838593110,"pointermove"],["move",376,361,1626838593118,"pointermove"],["move",375,361,1626838593230,"pointermove"],["move",373,360,1626838593238,"pointermove"],["move",373,359,1626838593246,"pointermove"],["move",371,359,1626838593254,"pointermove"],["move",370,358,1626838593262,"pointermove"],["move",368,357,1626838593271,"pointermove"],["move",366,356,1626838593278,"pointermove"],["move",364,355,1626838593287,"pointermove"],["move",362,354,1626838593294,"pointermove"],["move",359,352,1626838593302,"pointermove"],["move",357,351,1626838593310,"pointermove"],["move",354,350,1626838593318,"pointermove"],["move",351,350,1626838593326,"pointermove"],["move",348,350,1626838593334,"pointermove"],["move",346,350,1626838593342,"pointermove"],["move",345,349,1626838593350,"pointermove"],["move",342,349,1626838593358,"pointermove"],["move",338,349,1626838593366,"pointermove"],["move",333,349,1626838593374,"pointermove"],["move",329,348,1626838593382,"pointermove"],["move",321,346,1626838593390,"pointermove"],["move",317,344,1626838593398,"pointermove"],["move",313,344,1626838593407,"pointermove"],["move",309,341,1626838593414,"pointermove"],["move",303,337,1626838593422,"pointermove"],["move",299,335,1626838593430,"pointermove"],["move",296,332,1626838593439,"pointermove"],["move",294,330,1626838593447,"pointermove"],["move",293,329,1626838593473,"pointermove"],["move",292,329,1626838593478,"pointermove"],["move",290,329,1626838593487,"pointermove"],["move",290,327,1626838593526,"pointermove"],["move",290,326,1626838593534,"pointermove"],["move",289,325,1626838593542,"pointermove"],["move",290,325,1626838593662,"pointermove"],["move",291,325,1626838593671,"pointermove"],["move",294,324,1626838593678,"pointermove"],["move",294,322,1626838593688,"pointermove"],["move",296,322,1626838593694,"pointermove"],["move",296,321,1626838593710,"pointermove"],["move",297,320,1626838593726,"pointermove"],["move",298,319,1626838593734,"pointermove"],["move",298,318,1626838593742,"pointermove"],["move",299,317,1626838593751,"pointermove"],["move",301,317,1626838593758,"pointermove"],["move",302,316,1626838593767,"pointermove"],["move",303,314,1626838593774,"pointermove"],["down",303,314,1626838593849,"pointerdown"],["focus",1626838593850],["up",303,314,1626838593926,"pointerup"]]
//轨迹加密报错 找不到var l = o(e);解决办法
var l=testtraj2(t)
//console.log(l)
var et=testtraj1(t,l)
//console.log(et)
var i=testencode(et)
//服务器返回的
var q=
var w="76706e2e"//服务器返回的s
var y= testme(i,q,w)
return y
}
//console.log(get_ww("019924a82c70bb123aae90d483087f94","ea6698b3074ebb51c091ceaab07fe4f5"))
console.log(get_traeck())放进浏览器运行,结果正确,轨迹加密到此扣完了接下来开始扣json里面h的值生成(n))]分析下 把n放进u加密然后把结果md5一下(Z就是md5).先找n生成地方, var n = r(); 这里生成的,跟进去看算法
解读下这个算法,大概就是循环长度为75的r()数组(这个数组顺序是固定),每次取出数组下标对应的值,这个值就是r这个json里面的key,根据key去json里面拿到值,然后经过a(r(t) ? r : t)这一步对值的三元运算,并把运算结果往a空数组里面push,
return a(n) 最后这一步类似于python的"magic data".join(a)到此分析完毕,如果正向写稍微麻烦了点,不过最后一步既然是jion那么我们可以反推用spilt("")来拿到a,因为数组和json都是固定不变的,所致a也是固定的,经过转化,
a应该是['14438', '15743', 'CSS1Compat', '1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '2', '3', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '1', '-1', '-1', '-1', '0', '0', '0', '0', '558', '950', '1920', '1040', 'zh-CN', 'zh-CN', '-1', '1', '24', 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36', '1', '1', '1920', '1080', '1920', '1040', '1', '1', '1', '-1', 'Win32', '0', '-8', '584f4432fe6ebea605c1f943c0a39f15', '0b03cc6df4e2fc61df0144cad52b685f', 'nppdf32.dll,npalissologin.dll,npAliSecCtrl.dll,npaliedit.dll,npYunWebDetect.dll,internal-pdf-viewer,mhjfbmdgcfjbbpaeojofohoefgiehjai,np-mswmp.dll,internal-nacl-plugin,npQQMailWebKit.dll,npQMExtensionsMozilla.dll,npQzoneMusic.dll,npactivex.dll,npxluser2.0.2.3.dll,npcombrg.dll,npQQPhotoDrawEx.dll', '0', '-1', '0', '6', 'Arial,ArialBlack,ArialNarrow,Calibri,Cambria,CambriaMath,ComicSansMS,Consolas,Courier,CourierNew,Georgia,Helvetica,Impact,LucidaConsole,LucidaSansUnicode,MicrosoftSansSerif,MSGothic,MSPGothic,MSSansSerif,MSSerif,PalatinoLinotype,SegoePrint,SegoeScript,SegoeUI,SegoeUILight,SegoeUISemibold,SegoeUISymbol,Tahoma,Times,TimesNewRoman,TrebuchetMS,Verdana,Wingdings',1626846127770 , '-1', '-1', '-1', '12', '-1', '-1', '-1', '6', '-1', '-1'] 这里面有个时间戳1626846127770自己写的时候替换下就行
所以n="magic data".join(a)n值求到 直接跟进u看方法,然后导出 ,因为前面定义过testaes来接收u,直接用就行了,写一个方法调用,如下:
function get_ajaxw(){
var data=['14438', '15743', 'CSS1Compat', '1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '2', '3', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '1', '-1', '-1', '-1', '0', '0', '0', '0', '558', '950', '1920', '1040', 'zh-CN', 'zh-CN', '-1', '1', '24', 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36', '1', '1', '1920', '1080', '1920', '1040', '1', '1', '1', '-1', 'Win32', '0', '-8', '584f4432fe6ebea605c1f943c0a39f15', '0b03cc6df4e2fc61df0144cad52b685f', 'nppdf32.dll,npalissologin.dll,npAliSecCtrl.dll,npaliedit.dll,npYunWebDetect.dll,internal-pdf-viewer,mhjfbmdgcfjbbpaeojofohoefgiehjai,np-mswmp.dll,internal-nacl-plugin,npQQMailWebKit.dll,npQMExtensionsMozilla.dll,npQzoneMusic.dll,npactivex.dll,npxluser2.0.2.3.dll,npcombrg.dll,npQQPhotoDrawEx.dll', '0', '-1', '0', '6', 'Arial,ArialBlack,ArialNarrow,Calibri,Cambria,CambriaMath,ComicSansMS,Consolas,Courier,CourierNew,Georgia,Helvetica,Impact,LucidaConsole,LucidaSansUnicode,MicrosoftSansSerif,MSGothic,MSPGothic,MSSansSerif,MSSerif,PalatinoLinotype,SegoePrint,SegoeScript,SegoeUI,SegoeUILight,SegoeUISemibold,SegoeUISymbol,Tahoma,Times,TimesNewRoman,TrebuchetMS,Verdana,Wingdings', 1626846127770, '-1', '-1', '-1', '12', '-1', '-1', '-1', '6', '-1', '-1']
varn=data.join("magic data")
var t=testaes['RrSY'](n)
return t
}
//console.log(get_ww("019924a82c70bb123aae90d483087f94","ea6698b3074ebb51c091ceaab07fe4f5"))
//console.log(get_traeck())
console.log(get_ajaxw())
放进浏览器运行
运行正确,u(n)扣完了,开始扣最外面那个Z()方法,直接跟进去导出来用就行,步骤同上,该写完丢到浏览器运行下
运行正确,h值完毕,hh和hi如果想跟进去看方法步骤跟h一样的,我这里就不细跟了 就说一下怎么来的,hh是吧那个data.join("magic data") 然后直接md5 相比h少了一步加密,hi是data.join("!!")然后直接md5,好了我们直接改写,然后运行就行
运行正常,接下来就是扣rp的值 Z(a + a + o) 里面三个参数分别是gt+challge+passtime 然后md5一下,
所有变动的参数全部弄出来了,接下来就组装json就行
接下来就是r = u(_(uHyn, r())); 两个参数全部整明白了 接下来就把_和u扣出来就完事了,
_在function it() {里面直接导出用 ,u导出来过,直接用就行了,最后代码如下:
function get_ajaxw(gt,challge){
var ue="85163855977acca6"
var data=['14438', '15743', 'CSS1Compat', '1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '2', '3', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '1', '-1', '-1', '-1', '0', '0', '0', '0', '558', '950', '1920', '1040', 'zh-CN', 'zh-CN', '-1', '1', '24', 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36', '1', '1', '1920', '1080', '1920', '1040', '1', '1', '1', '-1', 'Win32', '0', '-8', '584f4432fe6ebea605c1f943c0a39f15', '0b03cc6df4e2fc61df0144cad52b685f', 'nppdf32.dll,npalissologin.dll,npAliSecCtrl.dll,npaliedit.dll,npYunWebDetect.dll,internal-pdf-viewer,mhjfbmdgcfjbbpaeojofohoefgiehjai,np-mswmp.dll,internal-nacl-plugin,npQQMailWebKit.dll,npQMExtensionsMozilla.dll,npQzoneMusic.dll,npactivex.dll,npxluser2.0.2.3.dll,npcombrg.dll,npQQPhotoDrawEx.dll', '0', '-1', '0', '6', 'Arial,ArialBlack,ArialNarrow,Calibri,Cambria,CambriaMath,ComicSansMS,Consolas,Courier,CourierNew,Georgia,Helvetica,Impact,LucidaConsole,LucidaSansUnicode,MicrosoftSansSerif,MSGothic,MSPGothic,MSSansSerif,MSSerif,PalatinoLinotype,SegoePrint,SegoeScript,SegoeUI,SegoeUILight,SegoeUISemibold,SegoeUISymbol,Tahoma,Times,TimesNewRoman,TrebuchetMS,Verdana,Wingdings', 1626846127770, '-1', '-1', '-1', '12', '-1', '-1', '-1', '6', '-1', '-1']
varn=data.join("magic data")
var passtimes = randomNum(10000, 20000)
var t=testaes['RrSY'](n)
var h= testmd5(t)
//获取h值
var hh=testmd5(data.join("magic data"))
console.log(hh)
//获取hi值
varhi=testmd5(data.join("!!"))
console.log(hi)
var rp = testmd5(gt+challge+passtimes)
var data1={
"lang":"zh-cn",
"type":"fullpage",
"tt":t,
"light":"SPAN_0",
"s":"c7c3e21112fe4f741921cb3e4ff9f7cb",
"h":h,
"hh":hh,
"hi":hi,
"vip_order":-1,"ct":-1,
"ep":{"v":"9.0.7","de":false,"te":false,"me":true,"ven":"Google Inc.","ren":"ANGLE (Intel(R) UHD Graphics 630 Direct3D11 vs_5_0 ps_5_0)","fp":["move",545,232,1626750892274,"pointermove"],"lp":["up",373,314,1626750896424,"pointerup"],"em":{"ph":0,"cp":0,"ek":"11","wd":0,"nt":0,"si":0,"sc":0},"tm":{"a":1626750891079,"b":1626750891417,"c":1626750891417,"d":0,"e":0,"f":1626750891082,"g":1626750891084,"h":1626750891112,"i":1626750891112,"j":1626750891172,"k":1626750891130,"l":1626750891172,"m":1626750891413,"n":1626750891413,"o":1626750891418,"p":1626750891660,"q":1626750891660,"r":1626750891663,"s":1626750891664,"t":1626750891664,"u":1626750891664},"by":0},
"passtime":passtimes,"rp":rp,"captcha_token":"1645706478"}
return testaes['SBoX'](testenc()["encrypt"](JSON.stringify(data1),ue))
}
//console.log(get_ww("019924a82c70bb123aae90d483087f94","ea6698b3074ebb51c091ceaab07fe4f5"))
//console.log(get_traeck())
console.log(get_ajaxw("019924a82c70bb123aae90d483087f94","ea6809a6067a797a8cf4f905ddb19fa9"))
丢进去运行,结果正常完美.
到此请求图片拿到的所有加密扣完了,写个测试脚本看看能拿到图片不
能拿到,扣得没错!!!里面有个坑 就是第一次get.php的w值里面那个用到了ue(四个随机数组成) ,第二次w也用到了 要保持两个值相同. 极验检测不算严格,第二次w轨迹可以复用,以后如果严格起来,这里轨迹得自己生成,极验小改版一般会改动captcha_token的值 而这个值是经过服务器返回的js算的,会改动,
如果不想手动取改代码,就把加密扣出来就行,这次逆向仅供交流学习,给的代码也只能在浏览器运行,node和python调用报错,需要自己把一些代码删掉!!!
排版估计有点乱,将就看看,没怎么发过 帖子. 滑块过验证的轨迹加密跟前面的w加密大同小异.耐心点就能扣出来,极验的滑块比较简单,适合新手扣下.
代码改写那里不知道为啥是乱码,在这里补上,排版乱了点 凑合着看看
"\u0067\u0052\u0045\u0056": function(e,thx) {
var UGut = AXzPo.DVn
, TNZEZo = ['XtKnl'].concat(UGut)
, Vjlo = TNZEZo;
TNZEZo.shift();
var WvQs = TNZEZo;
var t = 0
, r = 0
, n = 0
, i = 0;
var a = [];
var o = this;
var s = o;
if (e <= 0) {
return [];
}
var c = null;
var _ = null;
// var l = o(e);
varl =thx;
var u = l;
// var f = u < this ? 0 : u - this;
var f = 0;
for (; f < u; f = f + 1) {
var p = l;
var h = p;
if (new hfAt()(h) > -1) {
if (!c) {
c = p;
}
_ = p;
a( - t, p - r], ck_e(s ? p - s : s)]);
t = p;
r = p;
s = p;
} else if (new hfAt()(h) > -1) {
a( - s : s)]);
s = p;
}
}
o = c;
o = _;
return a;
}, 666 太强了 楼主v5霸气帅炸天!哈哈~ 留下两个字牛逼 看的6666 楼主是在太强了,亲收下我的摩拜 厉害啊,这要是我估计得搞好几天 谢谢大佬,可以按照思路走一遍了 嗯嗯,,谢谢大神 楼主牛啊,膜拜