目标网站:https://www.baibianip.com/home/free.html
在家公众号看到,拿来练练手。
打开网页源代码发现每个id都变成了
<td> <script>FFcampanology('ZGH4AQt1AQNmZwR2AF4lZwHhZmLhAwxkAGxkAwVkAmt0'); </script></td>
那坑定是被加密了。
在全局搜索FFcampanology,这里有个坑每次刷新FFcampanology会变,可能变成FFmathematical,FFimprecisely等
发现关键处:https://www.baibianip.com/home/indexjs?_t=1588054823.2621:formatted里面的
function FFcampanology(s) {
document.write(ddip(s));
}
应该就是这里,习惯性的打上断点,刷新,咦???没停住,再刷新,还是没停住,算了不纠结了。(关于这个打断点不停住,文末有解决)
然后试着在文内搜索ddip,发现有两个eval如下:
eval(function(p, a, c, k, e, d) {
e = function(c) {
return (c < a ? "" : e(parseInt(c / a))) + ((c = c % a) > 35 ? String.fromCharCode(c + 29) : c.toString(36))
}
;
if (!''.replace(/^/, String)) {
while (c--)
d[e(c)] = k[c] || e(c);
k = [function(e) {
return d[e]
}
];
e = function() {
return '\\w+'
}
;
c = 1;
}
;while (c--)
if (k[c])
p = p.replace(new RegExp('\\b' + e(c) + '\\b','g'), k[c]);
return p;
}('8 D(3){d 6=[];w(d i=0;i<3.j;i++){7(3.1(i)<x||3.1(i)>E){6.h(3.l(i))}4 7(3.1(i)>F){6.h(m.g(3.1(i)-f))}4{6.h(m.g(3.1(i)+f))}}9 6.k("")}8 e(t,u,v){9 m.g(((t-u+v)%(v*2))+u)}8 r(s){d b=[],c,i=s.j,a=\'a\'.1(),z=a+o,A=\'A\'.1(),p=A+o;n(i--){c=s.1(i);7(c>=a&&c<z){b[i]=e(c,a,f)}4 7(c>=A&&c<p){b[i]=e(c,A,f)}4{b[i]=s.l(i)}}9 b.k(\'\')}8 q(s){d b=[],c,i=s.j,a=\'0\'.1(),z=a+C;n(i--){c=s.1(i);7(c>=a&&c<z){b[i]=e(c,a,5)}4{b[i]=s.l(i)}}9 b.k(\'\')}8 B(s){9 y(q(s))}', 42, 42, '|charCodeAt||str|else||newarr|if|function|return||||var|rot|13|fromCharCode|push||length|join|charAt|String|while|26|Z|rot5|r13|||||for|65|rot13|||rot135|10|r3|90|77'.split('|'), 0, {}));
eval(function(p, a, c, k, e, d) {
e = function(c) {
return (c < a ? "" : e(parseInt(c / a))) + ((c = c % a) > 35 ? String.fromCharCode(c + 29) : c.toString(36))
}
;
if (!''.replace(/^/, String)) {
while (c--)
d[e(c)] = k[c] || e(c);
k = [function(e) {
return d[e]
}
];
e = function() {
return '\\w+'
}
;
c = 1;
}
;while (c--)
if (k[c])
p = p.replace(new RegExp('\\b' + e(c) + '\\b','g'), k[c]);
return p;
}('f c(3){4=b(3.2());5=$.a.e(4);1=5.2().6(8);9=1.d;7=1.6(0,9-8);g 7}', 17, 17, '|e3|toString|e0|e1|e2|substr|e4|10|l3|base64|r13|ddip|length|decode|function|return'.split('|'), 0, {}));
这两个eval()只要将它里面的函数复制到console.log()再打印在控制台或者node即可得到未混淆前的函数,如下:
第一个eval:
console.log(function(p, a, c, k, e, d) {
e = function(c) {
return (c < a ? "" : e(parseInt(c / a))) + ((c = c % a) > 35 ? String.fromCharCode(c + 29) : c.toString(36))
}
;
if (!''.replace(/^/, String)) {
while (c--)
d[e(c)] = k[c] || e(c);
k = [function(e) {
return d[e]
}
];
e = function() {
return '\\w+'
}
;
c = 1;
}
;while (c--)
if (k[c])
p = p.replace(new RegExp('\\b' + e(c) + '\\b','g'), k[c]);
return p;
}('f c(3){4=b(3.2());5=$.a.e(4);1=5.2().6(8);9=1.d;7=1.6(0,9-8);g 7}', 17, 17, '|e3|toString|e0|e1|e2|substr|e4|10|l3|base64|r13|ddip|length|decode|function|return'.split('|'), 0, {}))
输出:
function ddip(e0){e1=r13(e0.toString());e2=$.base64.decode(e1);e3=e2.toString().substr(10);l3=e3.length;e4=e3.substr(0,l3-10);return e4}
第二个eval也是如上操作,输出:
function r3(str){var newarr=[];for(var i=0;i<str.length;i++){if(str.charCodeAt(i)<65||str.charCodeAt(i)>90){newarr.push(str.charAt(i))}else if(str.charCodeAt(i)>77){newarr.push(String.fromCharCode(str.charCodeAt(i)-13))}else{newarr.push(String.fromCharCode(str.charCodeAt(i)+13))}}return newarr.join("")}function rot(t,u,v){return String.fromCharCode(((t-u+v)%(v*2))+u)}function r13(s){var b=[],c,i=s.length,a='a'.charCodeAt(),z=a+26,A='A'.charCodeAt(),Z=A+26;while(i--){c=s.charCodeAt(i);if(c>=a&&c<z){b[i]=rot(c,a,13)}else if(c>=A&&c<Z){b[i]=rot(c,A,13)}else{b[i]=s.charAt(i)}}return b.join('')}function rot5(s){var b=[],c,i=s.length,a='0'.charCodeAt(),z=a+10;while(i--){c=s.charCodeAt(i);if(c>=a&&c<z){b[i]=rot(c,a,5)}else{b[i]=s.charAt(i)}}return b.join('')}function rot135(s){return rot13(rot5(s))}
将两个还原后的函数复制到node,并格式化得到:
function r3(str) {var newarr = [];for (var i = 0; i < str.length; i++) {if (str.charCodeAt(i) < 65 || str.charCodeAt(i) > 90) {newarr.push(str.charAt(i))} else if (str.charCodeAt(i) > 77) {newarr.push(String.fromCharCode(str.charCodeAt(i) - 13))} else {newarr.push(String.fromCharCode(str.charCodeAt(i) + 13))}}return newarr.join("")
}function rot(t, u, v) {return String.fromCharCode(((t - u + v) % (v * 2)) + u)
}function r13(s) {var b = [], c, i = s.length, a = 'a'.charCodeAt(), z = a + 26, A = 'A'.charCodeAt(), Z = A + 26;while (i--) {c = s.charCodeAt(i);if (c >= a && c < z) {b[i] = rot(c, a, 13)} else if (c >= A && c < Z) {b[i] = rot(c, A, 13)} else {b[i] = s.charAt(i)}}return b.join('')
}function rot5(s) {var b = [], c, i = s.length, a = '0'.charCodeAt(), z = a + 10;while (i--) {c = s.charCodeAt(i);if (c >= a && c < z) {b[i] = rot(c, a, 5)} else {b[i] = s.charAt(i)}}return b.join('')
}function rot135(s) {return rot13(rot5(s))
}function ddip(e0) {e1 = r13(e0.toString());e2 = $.base64.decode(e1);e3 = e2.toString().substr(10);l3 = e3.length;e4 = e3.substr(0, l3 - 10);return e4
}
当看到$.base64.decode时,因为没法调试,我第一时间就想是不是可以用CryptoJS来,于是改成:
var CryptoJS = require('crypto-js');
function ddip(e0) {e1 = r13(e0.toString());e2 = CryptoJS.enc.Base64.parse(e1)e3 = e2.toString(CryptoJS.enc.Utf8).substr(10);l3 = e3.length;e4 = e3.substr(0, l3 - 10);return e4
}
然后试着运行下,perfect!!!!能用,解决。
然后我去看那家公众号里是如何解决的,原来,是搜索decode,在一段匿名函数里,要做一些修改,如下:
将这段匿名函数整个复制下来,把最后的传参jQuery改成$,并在最开头定义一下 var $ = {};
所以照做:
var $={}
(function ($) {var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", a256 = '', r64 = [256], r256 = [256], i = 0;var UTF8 = {encode: function (strUni) {var strUtf = strUni.replace(/[\u0080-\u07ff]/g, function (c) {var cc = c.charCodeAt(0);return String.fromCharCode(0xc0 | cc >> 6, 0x80 | cc & 0x3f);}).replace(/[\u0800-\uffff]/g, function (c) {var cc = c.charCodeAt(0);return String.fromCharCode(0xe0 | cc >> 12, 0x80 | cc >> 6 & 0x3F, 0x80 | cc & 0x3f);});return strUtf;},decode: function (strUtf) {var strUni = strUtf.replace(/[\u00e0-\u00ef][\u0080-\u00bf][\u0080-\u00bf]/g, function (c) {var cc = ((c.charCodeAt(0) & 0x0f) << 12) | ((c.charCodeAt(1) & 0x3f) << 6) | (c.charCodeAt(2) & 0x3f);return String.fromCharCode(cc);}).replace(/[\u00c0-\u00df][\u0080-\u00bf]/g, function (c) {var cc = (c.charCodeAt(0) & 0x1f) << 6 | c.charCodeAt(1) & 0x3f;return String.fromCharCode(cc);});return strUni;}};while (i < 256) {var c = String.fromCharCode(i);a256 += c;r256[i] = i;r64[i] = b64.indexOf(c);++i;}function code(s, discard, alpha, beta, w1, w2) {s = String(s);var buffer = 0, i = 0, length = s.length, result = '', bitsInBuffer = 0;while (i < length) {var c = s.charCodeAt(i);c = c < 256 ? alpha[c] : -1;buffer = (buffer << w1) + c;bitsInBuffer += w1;while (bitsInBuffer >= w2) {bitsInBuffer -= w2;var tmp = buffer >> bitsInBuffer;result += beta.charAt(tmp);buffer ^= tmp << bitsInBuffer;}++i;}if (!discard && bitsInBuffer > 0)result += beta.charAt(buffer << (w2 - bitsInBuffer));return result;}var Plugin = $.base64 = function (dir, input, encode) {return input ? Plugin[dir](input, encode) : dir ? null : this;};Plugin.btoa = Plugin.encode = function (plain, utf8encode) {plain = Plugin.raw === false || Plugin.utf8encode || utf8encode ? UTF8.encode(plain) : plain;plain = code(plain, false, r256, b64, 8, 6);return plain + '===='.slice((plain.length % 4) || 4);};Plugin.atob = Plugin.decode = function (coded, utf8decode) {coded = String(coded).split('=');var i = coded.length;do {--i;coded[i] = code(coded[i], true, r64, a256, 6, 8);} while (i > 0);coded = coded.join('');return Plugin.raw === false || Plugin.utf8decode || utf8decode ? UTF8.decode(coded) : coded;};
}($));
然后隐掉那个修改的ddip,改用原来的ddip,发现竟然报错:TypeError: Cannot set property 'base64' of undefined,我也是纳闷,卡了住了,然后就是各种搜索答案,各种修改,都不行。。。。。。。
最后骚操作删除两处的 $.base64,报错:TypeError: {} is not a function
搜了下大概说是其原因除了函数本身有错之外,还有一种很奇怪的情况:函数本身没有错,但是运行时就是不能正常运行。这种情况与javascript的特性有关:变量与函数声明前置的优先级。
这时突然想起之前看过的匿名自动执行函数,于是把函数回复原样,在(function ($)的前面加了一个!改成!(function ($),执行。。。。。。我呆了,竟然。。。成功了,真的卧槽。
到这里就已经解决了解码问题。抠好的代码在文末。
下面说下是如何解决的打了断点但是没停住问题。
当时情况发生时,我就想到和之前有个练习过的网页一样是加了时间戳的,所以打了也是白打,于是我刷新发现果然变了,当时使用reres替换成本地文件,于是现在也是同样的操作,把https://www.baibianip.com/home/indexjs?_t=1588061549.0092下所有代码复制到一个文件中,再在源码中搜索indexjs,发现这个文件是带着时间戳请求得来的。
然后刷新,发现ip那一栏是空白的,又多次刷新,还是无果,放弃了一下,就去研究那个报错问题。
期间吃了个午饭,睡了个午觉,继续,重点来了,阴差阳错下发现当时搜索的FFcampanology搜不到了,幸好有个不变的ddip,搜索下,快速定位,居然变成了FFpresentation,又刷新,又变,在开头有提到过。
这时想到用reres替换的文件不管用,原因极有可能是源代码中的函数名也就是FFpresentation,和请求下来的文件我复制到本地文件里的函数名不一样了。
好......骚操作开始了,想到用charles,里面有个 rewrite进行源码替换。
把请求下来的源码中符合正则的函数名都替换成FFunstinting,也就是复制到本地文件里的那个函数名。
开启reres,激动人心时刻到了,刷新,出现了,ip出现了。
看下源码中的函数名,都变成了FFunstinting。
接着全局搜索下FFunstinting,打个断点,刷新,停住了。
然后进入ddip内部,打断点
进入r13查看
进入decode查看
接下来就可以愉快的打断点调试了。
下面是抠好的代码,可直接在node里运行:
var $={}
!(function ($) {var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", a256 = '', r64 = [256], r256 = [256], i = 0;var UTF8 = {encode: function (strUni) {var strUtf = strUni.replace(/[\u0080-\u07ff]/g, function (c) {var cc = c.charCodeAt(0);return String.fromCharCode(0xc0 | cc >> 6, 0x80 | cc & 0x3f);}).replace(/[\u0800-\uffff]/g, function (c) {var cc = c.charCodeAt(0);return String.fromCharCode(0xe0 | cc >> 12, 0x80 | cc >> 6 & 0x3F, 0x80 | cc & 0x3f);});return strUtf;},decode: function (strUtf) {var strUni = strUtf.replace(/[\u00e0-\u00ef][\u0080-\u00bf][\u0080-\u00bf]/g, function (c) {var cc = ((c.charCodeAt(0) & 0x0f) << 12) | ((c.charCodeAt(1) & 0x3f) << 6) | (c.charCodeAt(2) & 0x3f);return String.fromCharCode(cc);}).replace(/[\u00c0-\u00df][\u0080-\u00bf]/g, function (c) {var cc = (c.charCodeAt(0) & 0x1f) << 6 | c.charCodeAt(1) & 0x3f;return String.fromCharCode(cc);});return strUni;}};while (i < 256) {var c = String.fromCharCode(i);a256 += c;r256[i] = i;r64[i] = b64.indexOf(c);++i;}function code(s, discard, alpha, beta, w1, w2) {s = String(s);var buffer = 0, i = 0, length = s.length, result = '', bitsInBuffer = 0;while (i < length) {var c = s.charCodeAt(i);c = c < 256 ? alpha[c] : -1;buffer = (buffer << w1) + c;bitsInBuffer += w1;while (bitsInBuffer >= w2) {bitsInBuffer -= w2;var tmp = buffer >> bitsInBuffer;result += beta.charAt(tmp);buffer ^= tmp << bitsInBuffer;}++i;}if (!discard && bitsInBuffer > 0)result += beta.charAt(buffer << (w2 - bitsInBuffer));return result;}var Plugin = $.base64 = function (dir, input, encode) {return input ? Plugin[dir](input, encode) : dir ? null : this;};Plugin.btoa = Plugin.encode = function (plain, utf8encode) {plain = Plugin.raw === false || Plugin.utf8encode || utf8encode ? UTF8.encode(plain) : plain;plain = code(plain, false, r256, b64, 8, 6);return plain + '===='.slice((plain.length % 4) || 4);};Plugin.atob = Plugin.decode = function (coded, utf8decode) {coded = String(coded).split('=');var i = coded.length;do {--i;coded[i] = code(coded[i], true, r64, a256, 6, 8);} while (i > 0);coded = coded.join('');return Plugin.raw === false || Plugin.utf8decode || utf8decode ? UTF8.decode(coded) : coded;};
}($));function r3(str) {var newarr = [];for (var i = 0; i < str.length; i++) {if (str.charCodeAt(i) < 65 || str.charCodeAt(i) > 90) {newarr.push(str.charAt(i))} else if (str.charCodeAt(i) > 77) {newarr.push(String.fromCharCode(str.charCodeAt(i) - 13))} else {newarr.push(String.fromCharCode(str.charCodeAt(i) + 13))}}return newarr.join("")
}function rot(t, u, v) {return String.fromCharCode(((t - u + v) % (v * 2)) + u)
}function r13(s) {var b = [], c, i = s.length, a = 'a'.charCodeAt(), z = a + 26, A = 'A'.charCodeAt(), Z = A + 26;while (i--) {c = s.charCodeAt(i);if (c >= a && c < z) {b[i] = rot(c, a, 13)} else if (c >= A && c < Z) {b[i] = rot(c, A, 13)} else {b[i] = s.charAt(i)}}return b.join('')
}function rot5(s) {var b = [], c, i = s.length, a = '0'.charCodeAt(), z = a + 10;while (i--) {c = s.charCodeAt(i);if (c >= a && c < z) {b[i] = rot(c, a, 5)} else {b[i] = s.charAt(i)}}return b.join('')
}function rot135(s) {return rot13(rot5(s))
}function ddip(e0) {e1 = r13(e0.toString());e2 = $.base64.decode(e1);e3 = e2.toString().substr(10);l3 = e3.length;e4 = e3.substr(0, l3 - 10);return e4
}var CryptoJS = require('crypto-js');
function ddip11(e0) {e1 = r13(e0.toString());e2 = CryptoJS.enc.Base64.parse(e1)e3 = e2.toString(CryptoJS.enc.Utf8).substr(10);l3 = e3.length;e4 = e3.substr(0, l3 - 10);return e4
}e4 = ddip('ZGH4ZmLjZmL2AGR4Av4lZGxhZwRjYwpjZGH4BGLmAmZ4ZD==')
console.log(e4)写完这篇文章,又要准备晚饭了,时间过的真快。
惊奇的发现请求https://www.baibianip.com/home/indexjs也可以,原来时间戳只是个摆设................