雨翔河
首页
列表
关于
破解天眼查 token,_utm,paaptp 的过程
2019-01-24 15:07
#### 记录破解天眼查接口的token,_utm,paaptp三个cookie值的过程 > 当发这篇文章的时候,该网站已经放弃了接口加密,我也终于敢把文章发表出来聊一聊接口加密破解的这一过程。 使用token和_utm可以去请求加密的接口,paaptp暂时不清楚它们后端用来做什么判断,很可能是这篇文章结尾说的那个问题导致的后端没有去做校验,或者这个仅仅是用来做加密接口监控用的。。。 首先在本地搭建好nginx,将它请求的js服务器ip通过修改host映射到本地,然后代理服务器打开将js请求都到本地下载好的js文件里,这样就可以自己在js里调试它的加密代码,下载过来的它的js是压缩后的,随便找个解压的网站解压一下就格式化好了可以正常看了,其实不管怎么加密,只要涉及到前后端这样交互就在js里找到它的加密方法,不外乎各种跳转各种转换各种混淆,只是复杂程度不一样罢了。 token和_utm参数的的破解在网络上可以找到,百度下就能找到有几个热心网友的解决方案,要想拿到token必须得想到转asc码,要想拿到_utm必须得找到正确的字典。 这两个参数非常简单,重点是网络上的破解方式都是有缺陷的,而且是致命的缺陷,原因是:网络上的破解方式得到_utm参数使用的字典是错误的字典,真正的字典是需要在js里一步一步调试出来的,然后自己保留下来用来得到_utm,根本不是写死在js里的那个数组字典,为什么它们能得到那个字典以为是正确的,因为使用那个错误字典的时候所有的请求只要key的首字符是2开头的都不会有问题,因为这个假的字典只有key是2的时候是正确的,所以你会发现当你的key首字符不是2的时候,能返回数据但是得到的数据都是假数据,这个错误对于爬虫来说是致命的。 网络上很多人问paaptp这个参数怎么破解,这个问题暂时在网络上没发现解决方案,下面说下我的这个破解途径。 怎么找到这个开始的呢,那就得一步步在最初的请求那里加打印cookie值, ``` console.log("paaptp1cookie7:"+document.cookie);, ``` 发现在下面的这个地方出现了paaptp,而语句的最开始没有这个cookie值 生成过程: 所有的request请求有这么一段js(js在后面,先看打印的值),打印出来的那些值是如下所示: 可以看出e是$rootScope e:打印出来是7204a5e4d515ccf8f3993,它是来自于$rootScope t:打印出来是cookie字符 a:打印出来是app字符 i:打印出来是path字符 s:undefined uuuuu:打印出来就是98913c3738d4060da6d71b10db2f26e105cfaf198a04ed9a9b15ccf8f39bb,这就是我们要的paaptp,可以看下面的打印就知道了。 n[0][t]打印出来是这样的: ``` TYCID=53ecf2b992f74da7ba44bc45084e4ebe; tnet=61.141.65.59; Qs_lvt_117460=1498117164; ssuid=3231699369; Hm_lvt_e92c8d65d92d534b0fc290df538b4758=1498117165; Hm_lpvt_e92c8d65d92d534b0fc290df538b4758=1498130888; Qs_pv_117460=346691578890329000%2C3751116267975784400%2C3842879489752609300%2C341436929071772100%2C442033311581940200; _pk_id.6835.e431=c3ab1be22fcbc2d3.1498117165.2.1498130888.1498130888.; _pk_ses.6835.e431=*; _pk_id.1.e431=610e1349b353388a.1498117165.2.1498130889.1498130888.; _pk_ses.1.e431=*; bannerStorageV2=%22true%22; paaptp=98913c3738d4060da6d71b10db2f26e105cfaf198a04ed9a9b15ccf8f39bb ``` 它的js代码是这样的: ``` app.run(["$rootScope", "$window", "$document", "appName", "onner", "merge", "ErrorMsg", function($rootScope, t, n, a, i, o, s) { console.log("$rootScope"+$rootScope); var e = $rootScope; console.log("eeee:"+e) angular.$splitNum = function(e, t) { console.log("e:"+e); console.log("t:"+t); console.log("a:"+a); console.log("i:"+i); console.log("s:"+s); console.log("paaptp1cookie7:"+document.cookie); for (var s = "", r = (new Date).getTime(), c = 0; c < a.length; c++) s += a.charCodeAt(c).toString(); var l = Math.round(1e9 * Math.random()) % 1e8; for (s += l, s += r; s.length > 10;) s = (parseInt(s.substring(0, 10)) + parseInt(s.substring(10, s.length))).toString(); for (var d = l; d.length > 3;) d = (parseInt(d.substring(0, 3)) + parseInt(d.substring(3, d.length))).toString(); d /= a.length; for (var p = "", u = "", c = 0; c < e.length; c++) p = parseInt(e.charCodeAt(c) ^ parseInt((s + c * d) % 255)), u += 16 > p ? "0" + p.toString(16) : p.toString(16), d += s % d; for (l = l.toString(16); l.length < 8;) l = "0" + l; u += l, r = parseInt(r).toString(16), u += r, consol.log("uuuuuuuu:"+u); n[0][t] = o.m(a, i, "0", ".") + "=" + u + ";" + i + "=/;"; console.log("n[0][t]:"+n[0][t]); }, e.showErrorMsg = function(e) { s.showErrorMessage(e) } }]) ``` 由此可以看出我们不知道的只有e这个值 我们去寻找谁调用的angular.$splitNum,找到这个e的值 我们看到了这么个东西:e的值是e[0][1] ``` i.prototype.$$safe = function(e, n, a) { a = a ? a: 18; for (var i = "",o = this.e.split(","), s = 0; a > s; s++){ i += o[s].length > n + 1 ? o[s][n] : ""; } console.log("e[0][1]:"+e[0][1]); console.log("e[0][1],i:"+i); console.log("t.$splitNum->e:"+e); return t.$splitNum(e[0][1], i) }; ``` 再去寻找是谁调用的 prototype.$$safe 方法。 看到了这个 ``` function g(e) { var t = new angular.$sanitize("XMLHttpRequest"), console.log("tttt:"+t); var temp = t.$get(",", 1, 6); console.log("t.$get(",", 1, 6):"+temp); n = XMLHttpRequest.responsesType(temp); console.log("XMLHttpRequest.responsesType(t.$get(",", 1, 6)):"+n); t.$$safe(n, 2) } ``` 如上面所述 打印出来那个t.$get(",", 1, 6)的内容是: odtib n打印出来的内容是:sessionStorage,7204a5e4d515ccf8f3993 所以很明显,我们可以知道传入的那个未知的值就是这个n到safe去的,而safe里面那个e取的是e[0][1],可以知道7204a5e4d515ccf8f3993就是嘛,那么这个sessionStorage是什么时候放进去的呢,搜索了下sessionStorage 14个匹配的,其中这段代码吸引了我: ``` angular.module("app").run(["$rootScope", "maxUSize", "$window", function(e, t, n) { console.log("maxUSizetttttttt:"+t); for (var a = "localStorage", i = "", o = (new Date).getTime(), s = 0; s < a.length; s++) i += a.charCodeAt(s).toString(); var r = Math.round(1e9 * Math.random()) % 1e8; for (i += r, i += o; i.length > 10;) i = (parseInt(i.substring(0, 10)) + parseInt(i.substring(10, i.length))).toString(); for (var c = r; c.length > 3;) c = (parseInt(c.substring(0, 3)) + parseInt(c.substring(3, c.length))).toString(); c /= a.length; for (var l = "", d = "", s = 0; s < t.length; s++) l = parseInt(t.charCodeAt(s) ^ parseInt((i + s * c) % 255)), d += 16 > l ? "0" + l.toString(16) : l.toString(16), c += i % c; for (r = r.toString(16); r.length < 8;) r = "0" + r; d += r, o = parseInt(o).toString(16), d += o; var p = new angular.$sanitize("Storage"); n[p.$get(",", 1, 6)] = [], console.log("sessionStorage d:"+d); n[p.$get(",", 1, 6)].push(["sessionStorage", d]) }]) ``` 看到那个push了没,说明是从这里放进去的,打个log试下,果然是这样 这段代码是用来获取odtib的,也就是那个e,那个我们要生成paaptp的钥匙,但是这个钥匙的生成需要用到参数t,参数t是来自于maxUSize,maxUSize在js里搜索了下,是这样的: ``` app.constant("maxUSize", "3") ``` 所以只需要把这些js转换为java代码就ok了,但是目前遇到这些问题: aa:9711211242 bb:2950221498117399587 cc:9711211242 dd:2950221498117399600 s:2950221507828610600 s是由cc和dd相加得到的,很明显这不可能,js里面如果调用这样的代码,如果传入的值越界了,出现的值不可预知,很神奇,不符合加减法了,应该是越界了: ``` var aa=9711211242; var bb=2950221498117399587 var cc = parseInt(aa); var dd = parseInt(bb); console.log("cc:"+cc); console.log("dd:"+dd); s = ( cc+ dd ).toString(); console.log("s:"+s); ``` 这里有一个非常有趣的事情,就是其实这个paaptp字符串的一部分的值生成可能是不可预知的,因为js的超大值加法会得到一个错误的越界值 如上面的这段代码,即使你不用程序,笔算都能知道答案不会是js输出的那个,整个js涉及到加密的那些代码很多命名都是fuxk和wtf,可以想象得出来该网站的程序员心中肯定是一万个草泥马在奔腾,当破解完它的paaptp参数的时候瞬间觉得可能这也是它们自己犯的错误,这个网站的反爬虫工程师和前端也应该在纠结问题出在哪里,前后端得到的值不一致。 巧合的是在一天前,网站撤下了接口加密,替换成了渲染好html返回回来,爬虫的抓取就方便多了,破解也不需要了,模拟浏览器也不需要了,只需要直接发起get请求即可。 爬虫和反爬就是程序员互相伤害的战场,哈。 写下这篇文章纪念下自己花了三天时间搞的东西。。。如有侵犯天眼查网站权利,无条件撤下该文章。
类型:工作
标签:天眼查,破解
Copyright © 雨翔河
我与我周旋久
独孤影
开源实验室