某壁纸网站js逆向,涉及ob混淆,滑块
本帖最后由 Esword 于 2021-7-21 15:13 编辑首先在此声明,本文章仅仅用于研究学习,不可用于任何商业活动,否则后果自负。
今天的npy
aHR0cHM6Ly9iei56enptaC5jbi9pbmRleA==
npy这三个字自己脑补吧,哈哈哈哈。
解决无限debugger
法一:
右击debugger行数位置,点击add conditional breakpoint..,添加false,然后按回撤, 刷新网页,发现成功跳过无限debugger
法二:
1、在js文件右击, 然后点击save as ..., 把js文件保存到本地。
2、修改保存到本地的js文件,将debugger成false保存js文件
3、在浏览器Soures获取需要替换的js文件url
4、使用fiddler等工具动态拦截替换js,刷新网页即可
法三:
注入代码到js文件
//去除无限debugger
Function.prototype.__constructor_back = Function.prototype.constructor;
Function.prototype.constructor = function() {
if(arguments && typeof arguments==='string'){
//alert("new function: "+ arguments);
if("debugger" === arguments){
//arguments="console.log(\"anti debugger\");";
//arguments=";";
return
}
}
return Function.prototype.__constructor_back.apply(this,arguments);
}
加密分析与定位
其实看到上面这个过无限debugger的大家都可以大致猜出我们今天的网站有这个一项,这里我才用的法三,注入js。其实一开始我用的法一,但是效果不理想,不是不理想,是很不好,卡死人。里面的验证码滑动都特别卡,我后来尝试法三后,特别的丝滑,跟正常一样。 先说说这个网站吧,它开始是一打开网页就有滑动验证码,后来改了,一打开第一页没有了,下面请求就会有。
首先我们看一下它的代码(下图),很明显,被混淆了。这里我们可以用下面这个网站进行混淆还原,让它至少可以看了。http://tool.yuanrenxue.com/decode_obfuscator猿人学ob混淆还原工具
把这些混淆还原一下后,我们看下一页,首先遇到的是滑动验证码,这里滑动验证码的获取就不多赘述,抓包就好了,在 XHR 里面就可以看到请求。我们看一下滑动验证码检验是否成功参数。
可以看到有三个参数,其中 captchaType 是固定不变的,而 token 是跟滑动验证码的 bs64编码 一起返回的,就是下图,jigsawImageBase64 与originalImageBase64 分别对应滑块图片与背景图片。
正如上图看到的,secretKey 与 token 也被一起返回回来,它们两个下面要被用到。那就剩下一个参数 pointJson ,我们搜索一下它,会发现就只有一个js文件,再在文件里面找它,发现有好几个(也就2个,哈哈哈哈哈),这里就是打断点确定是哪个了。
最后确定下来是这个,在这里你会发现,这个根本没有轨迹的验证什么的,就是单纯验证一下缺口的左边到图片左边缘的像素距离。这里我们看一下还原后的代码。
function pointJson(moveBlockLeft,secretKey) {
_0x4b1647 = moveBlockLeft
pointJson =secretKey ? _0x43f1b9(JSON['stringify']({
'x': _0x4b1647,
'y': 0x5
}), secretKey) : JSON['stringify']({
'x': _0x4b1647,
'y': 0x5
});
return pointJson
}
这个是我改的,看里面的,没有什么的大的改变,说明这里没有怎么混淆,看一下上面两个参数 moveBlockLeft 与 secretKey ,secretKey 就不多说,就是上面说的,而 moveBlockLeft 就是像素距离。但是这里还有一个函数_0x43f1b9,我们看一下它的代码。
这里的代码很明显,这里我们改下一下,用 nodejs 的 crypto-js 库,改一下就好了。可以参考我下面这个代码。
var CryptoJS = require("crypto-js");
function _0x43f1b9(_0x393fb6) {
var _0x4d513d = arguments["length"] > 1 && undefined !== arguments ? arguments : "XwKsGlMcdPMEhR1B",
_0x4b1647 =CryptoJS.enc.Utf8.parse(_0x4d513d),
_0x2e1dac =CryptoJS.enc.Utf8.parse(_0x393fb6),
_0x84666d = CryptoJS.AES.encrypt(_0x2e1dac, _0x4b1647, {
"mode": CryptoJS.mode.ECB,
"padding": CryptoJS.pad.Pkcs7
});
return _0x84666d.toString();
}
这样这个参数 pointJson 就解决了。
这样这个网的滑块就过了。
滑块过后你点击的页面才会加载,但是看请求头会发现有一个参数 captcha
这里再次搜索这个 captcha ,会定位到下图这样的代码
这个会发现 _0x4dd66d ,这个参数可以根据调用栈找到加密办法。也就是下面这个。
我们看一下还原后以及被我改的代码。
function captcha(moveBlockLeft,token,secretKey) {
var captcha = secretKey ? _0x43f1b9(token + '---' + JSON['stringify']({
'x': moveBlockLeft,
'y': 0x5
}), secretKey) : token + '---' + JSON["stringify"]({
'x': moveBlockLeft,
'y': 0x5
});
return captcha
}
_0x43f1b9 这个是不是很熟悉,每次,他就是上面用 nodejs 的 crypto-js 库改加密的函数。
好了这个就是 captcha 的加密。
下面是 auth_key 的加密,当我们点击一个图片时,它会发出请求,其实有两个,一个是缩小版,一个是原版,这个 auth_key 的加密其实很好找的也是与上面一样,搜索就好了,这里就不咋赘述,我就放一个网站加密代码。
还原后以及改写代码:
function url(_0x29df17, _0xea945) {
var _0x537ece = "YQTJLVCqattV1T0fhuhJTW1vyH7ZdyE3",
_0x5998d = "https://doge.zzzmh.cn",
_0x5c5042 = _0x50ecce(32),
_0x56d562 = parseInt((_0xea945 || Date["now"]()) / 1000) + 1800,
_0x25aa83 = _0x29df17["substring"](_0x5998d["length"], -1 == _0x29df17["lastIndexOf"]("?") ? _0x29df17["length"] : _0x29df17["lastIndexOf"]("?")),
_0x41d299 = _0x56d562 + "-" + _0x5c5042 + "-0-" + md5(_0x25aa83 + "-" + _0x56d562 + "-" + _0x5c5042 + "-0-" + _0x537ece);
return _0x29df17 + (_0x29df17["indexOf"]("?") < 0 ? "?" : "&") + "auth_key=" + _0x41d299;
}
这样这个网站的加密就算完成了,但是呢,人家返回的数据也是解密的,还得解密,哈哈哈哈哈,靓男无语了,没办法,只能解密了。
我们先看一下它返回的加密数据。
看是看不出什么的,直接动手搞它。这里我看的是调用栈,然后找到它的。是下图这个。
然后我们打开,设置断点,翻页,刚好停在那里。
其实我们就要下面代码就好了。
_0x417d7d['data']['result'] = JSON['parse'](_0x6247d3['a'](_0x417d7d['data']['result']))
这里我们就看下还原后代码。
_0x417d7d["data"]["result"] = JSON["parse"](_0x6247d3["a"]["decipher"](_0x417d7d["data"]["result"]))
我的代码。
function _0x41d299(_0x29df17) {
for (var _0xea945 = [-111, 52, 91, 65, -65, 116, 119, 106, -121, -82, -5, 80, 51, 97, 68, -83, -112, -51, 23, -46, -34, -114, -55, -11, -127, 90, 33, 22, -31, 50, -17, 20, -44, 15, -94, -123, 118, -23, -61, 114, 71, -104, -126, -117, -81, -54, -18, -110, -4, -95, -91, 94, -80, -14, 120, 105, 85, 104, -86, -108, 67, 25, 101, 108, 16, -105, 111, -10, 117, -73, 77, 89, -29, -98, -68, 112, 107, -1, 86, 121, 88, -101, -124, 69, -30, -8, -113, -74, -118, 57, -25, 12, -115, -106, 95, 127, 84, 124, -102, -28, 73, 43, -60, 28, 46, 115, 30, 122, -75, 125, -67, -77, 3, -7, -53, -13, 53, 78, -72, 1, 11, -71, -39, -79, -3, 19, 41, 126, -43, -125, -27, 34, 63, 8, 72, -35, -41, -63, 60, -24, 102, 47, -119, -103, -22, 45, 59, 64, -96, 49, 83, -107, -120, -57, -70, 0, -38, -84, -40, 24, 14, 48, 29, 44, -36, -47, 56, -92, 38, 37, 4, -50, 103, 10, -89, 55, 113, -26, 110, 54, 36, -20, -78, -12, -116, 70, -37, 5, -62, -76, -48, -64, 79, 100, 40, 6, -58, -90, -19, -9, 39, 93, -99, 21, 7, 26, -2, 27, -45, 81, 58, -122, 76, -66, 2, 92, -42, 98, -16, 9, 61, 62, -15, 99, -21, 31, -56, 87, 17, -52, -69, -33, -59, -85, 66, 74, 18, -93, -128, -87, -32, 42, 32, -88, 109, 96, 13, -6, 75, -100, -49, 35, -97, 82, -109, 123], _0x537ece = 0, _0x5c5042 = 0, _0x56d562 = 0, _0x25aa83 = new Array(), _0x5998d = 0; _0x5998d < _0x29df17["length"]; _0x5998d++) {
_0x537ece = _0x537ece + 1 & 255, _0x5c5042 = (255 & _0xea945) + _0x5c5042 & 255;
var _0x41d299 = _0xea945;
_0xea945 = _0xea945, _0xea945 = _0x41d299, _0x56d562 = (255 & _0xea945) + (255 & _0xea945) & 255, _0x25aa83["push"](_0x29df17 ^ _0xea945);
}
return _0x25aa83;
}
function _0x438891(_0x29df17) {
for (var _0xea945, _0x537ece, _0x5c5042 = "", _0x56d562 = 0; _0x56d562 < _0x29df17["length"];) _0xea945 = _0x29df17, _0x537ece = 0, _0xea945 >>> 7 === 0 ? (_0x5c5042 += String["fromCharCode"](_0x29df17), _0x56d562 += 1) : 252 === (252 & _0xea945) ? (_0x537ece = (3 & _0x29df17) << 30, _0x537ece |= (63 & _0x29df17) << 24, _0x537ece |= (63 & _0x29df17) << 18, _0x537ece |= (63 & _0x29df17) << 12, _0x537ece |= (63 & _0x29df17) << 6, _0x537ece |= 63 & _0x29df17, _0x5c5042 += String["fromCharCode"](_0x537ece), _0x56d562 += 6) : 248 === (248 & _0xea945) ? (_0x537ece = (7 & _0x29df17) << 24, _0x537ece |= (63 & _0x29df17) << 18, _0x537ece |= (63 & _0x29df17) << 12, _0x537ece |= (63 & _0x29df17) << 6, _0x537ece |= 63 & _0x29df17, _0x5c5042 += String["fromCharCode"](_0x537ece), _0x56d562 += 5) : 240 === (240 & _0xea945) ? (_0x537ece = (15 & _0x29df17) << 18, _0x537ece |= (63 & _0x29df17) << 12, _0x537ece |= (63 & _0x29df17) << 6, _0x537ece |= 63 & _0x29df17, _0x5c5042 += String["fromCharCode"](_0x537ece), _0x56d562 += 4) : 224 === (224 & _0xea945) ? (_0x537ece = (31 & _0x29df17) << 12, _0x537ece |= (63 & _0x29df17) << 6, _0x537ece |= 63 & _0x29df17, _0x5c5042 += String["fromCharCode"](_0x537ece), _0x56d562 += 3) : 192 === (192 & _0xea945) ? (_0x537ece = (63 & _0x29df17) << 6, _0x537ece |= 63 & _0x29df17, _0x5c5042 += String["fromCharCode"](_0x537ece), _0x56d562 += 2) : (_0x5c5042 += String["fromCharCode"](_0x29df17), _0x56d562 += 1);
return _0x5c5042;
}
function _0x21a6fa(_0x29df17) {
for (var _0xea945 = atob(_0x29df17), _0x537ece = new Int8Array(_0xea945["length"]), _0x5c5042 = 0; _0x5c5042 < _0xea945["length"]; _0x5c5042++) _0x537ece = _0xea945["charCodeAt"](_0x5c5042);
return _0x537ece;
}
function _0xbe7c1c(_0x29df17) {
return _0x438891(_0x41d299(_0x21a6fa(_0x29df17)));
}
function decode(str) {
var info = _0xbe7c1c(str)
info_dict = JSON.parse(info)
// console.log(info_dict)
return info_dict
}
其实本质上就是个解码的过程。decode 就是主函数。
我们试一个看一看。
{
currPage: 1,
list: [
{ t: 2, w: 6500, h: 3300, i: 'c8bfcd9f880411ebb6edd017c2d2eca2' },
{ t: 2, w: 3840, h: 2233, i: 'c6ac1e46880411ebb6edd017c2d2eca2' },
{ t: 2, w: 1920, h: 1080, i: 'c5398839880411ebb6edd017c2d2eca2' },
{ t: 2, w: 4149, h: 2480, i: '01217514880511ebb6edd017c2d2eca2' },
{ t: 1, w: 2560, h: 1440, i: 'cec99a46880411ebb6edd017c2d2eca2' },
{ t: 2, w: 1920, h: 1200, i: '27524ac7880511ebb6edd017c2d2eca2' },
{ t: 1, w: 1920, h: 1080, i: '865885b0881611ebb6edd017c2d2eca2' },
{ t: 2, w: 3840, h: 2160, i: '0bbd039fb5a54de2b240ab0fcd3af8ed' },
{ t: 2, w: 3840, h: 2160, i: '3f30472a880511ebb6edd017c2d2eca2' },
{ t: 2, w: 3840, h: 2160, i: 'a9982f7441bd4e07a3b1a26af43457d9' },
{ t: 2, w: 4500, h: 2800, i: '0c0f3f16880511ebb6edd017c2d2eca2' },
{ t: 2, w: 3840, h: 2400, i: '4921c7d7eae046c7a4d8575b02a6ae2b' },
{ t: 2, w: 1920, h: 1080, i: 'c5340e3e880811ebb6edd017c2d2eca2' },
{ t: 2, w: 7680, h: 4320, i: '21142970880911ebb6edd017c2d2eca2' },
{ t: 2, w: 4000, h: 2433, i: '156a17e6880511ebb6edd017c2d2eca2' },
{ t: 2, w: 3859, h: 2594, i: '070dfddb880511ebb6edd017c2d2eca2' },
{ t: 2, w: 3840, h: 2160, i: 'bbc58c3d998d4f389fdae649334873f7' },
{ t: 2, w: 7680, h: 4320, i: '4dd06e4787714b08a2d56b5528569a67' },
{ t: 2, w: 2560, h: 1440, i: 'ce329083a43b4526ac6129f8c651bae5' },
{ t: 2, w: 2800, h: 1350, i: '1e8d7c5e880511ebb6edd017c2d2eca2' },
{ t: 2, w: 3840, h: 2160, i: 'cae57fea880411ebb6edd017c2d2eca2' },
{ t: 2, w: 4096, h: 2404, i: '56ac935951ab4af78bf31af55b600d95' },
{ t: 2, w: 7680, h: 4320, i: '4678e4f731874d668ec21a2d2608878c' }
],
pageSize: 23,
totalCount: 34339,
totalPage: 1493
}
很好,解决了,只有这些是什么,就自己搞吧,这里提示一下,跟获取原图链接有关,跟上面 auth_key 获取有关。
图片展示
这就是我搞定其中一部分的图片,很不错,高清的。
这里就放一张。
如果jio的我写的不错就点个关注。
现在可以看了,xdm 这个网站目前已经更新了,每个js都加上了debugger,['constructor']('debu' + 'gger')['call']('action')); 还混淆了一下。。。 怎么没了 还以为能下载,怎么没有了。{:1_924:} 怎么没有了?还想学习学习的 咋没了 还想看看的 本帖最后由 三滑稽甲苯 于 2021-7-19 10:14 编辑
刚刚看到,点进来怎么就没了
PS. 到lz个人主页的广播可以看到一部分 怎么了,满心期待点进来来没了~~ 是不是不能发这种的呢,技术文章?点进来就没了 现在这种都直接挂···· 可惜来晚了,感觉应该能进步的