温馨提示:本文章所提到的相关技术以及代码仅供学习交流,不可用来做违法或违反博客园相关规定的事情哦~而且本文章不许转载哦,请使用超链接。
来博客园已经有些日子了,博客早就申请了下来,在后台偶然看到了可以自定义博客的样式,觉得很有趣,犹记得上小学的时候新浪博客就支持自定义CSS了,那时还很好奇:“CSS是什么?可以爆头和投手雷吗?”如今度过了i个快乐而又痛苦的日子,终于知道CSS是什么了(我有说我是在吐槽吗?)。
好了,言归正传,首先引出一句话:“黑客是一种态度。”
关于“黑客”一词的解释我稍后会发到Hack分类中,现在我们讲博客园的自定义样式。
其他几个就不说了,基本上是限定在HTML和CSS代码上,我们说“自定义博客侧边栏公告”这一栏,我们可以在其中写javascript代码,比如如下一行:
<script type="text/javascript"> document.write("你好!"); </script>
保存后看博客主页效果:
嘿嘿,下面我们来试试常玩的alert方法:
<script type="text/javascript"> alert("你好!"); </script>
并没有在主页看到效果,回来看代码,发现输入框中的代码在提交后变成了:
<script type="text/javascript"> ; </script>
很显然,过滤程序将alert函数过滤掉了,不过这点难不倒我,还记得我们上面用到的document.write方法吗?我们可以这样来写:
<script type="text/javascript"> var hehele2='<scr'+'ipt ty'+'pe="tex'+'t/java'+'script">'+'a'+'l'+'e'+'r'+'t'+'('+'"'+'呵呵了'+'"'+')'+';'+'</sc'+'ript>'; document.write(hehele2); </script>
测试结果如下:
呵呵了吧!其实分析了一下博客园的部分源代码大体情况是这样的:
在输入框中写入代码点击“保存”后,后端程序会将用户所提交的代码进行一遍过滤,一些敏感代码会被使用正则表达式replace掉,就比如alert(*****)这样的代码;过滤后就写进数据库,在用户打开自己的博客首页的时候,会将数据库中的自定义代码读出来运行,这时候会有一个坏坏的jquery.writeCapture-min.js文件来检测当前页面的代码是否合法,一旦遇到非法代码就会抛出异常,让非法代码中断执行,比如:
<script type="text/javascript"> var hehele2='<script type="text/javascript"></script>'; document.write(hehele2); </script>
这段代码,因为其中的“<script type="text/javascript">”被列为 非法代码,所以当保存并打开博客主页的时候会看到浏览器的Console中会出现异常:
我看了jquery.writeCapture-min.js这个文件,整理一下格式把代码贴在这,有兴趣的朋友可以研究一下:
(function(E, a) { var j = a.document; function A(Q) { var Z = j.createElement("div"); j.body.insertBefore(Z, null); E.replaceWith(Z, '<script type="text/javascript">' + Q + "<\/script>") } E = E || (function(Q) { return { ajax: Q.ajax, $: function(Z) { return Q(Z)[0] }, replaceWith: function(Z, ad) { var ac = Q(Z)[0]; var ab = ac.nextSibling, aa = ac.parentNode; Q(ac).remove(); if (ab) { Q(ab).before(ad) } else { Q(aa).append(ad) } }, onLoad: function(Z) { Q(Z) }, copyAttrs: function(af, ab) { var ad = Q(ab), aa = af.attributes; for (var ac = 0, Z = aa.length; ac < Z; ac++) { if (aa[ac] && aa[ac].value) { try { ad.attr(aa[ac].name, aa[ac].value) } catch (ae) {} } } } } })(a.jQuery); E.copyAttrs = E.copyAttrs || function() {}; E.onLoad = E.onLoad || function() { throw "error: autoAsync cannot be used without jQuery or defining writeCaptureSupport.onLoad" }; function P(ab, aa) { for (var Z = 0, Q = ab.length; Z < Q; Z++) { if (aa(ab[Z]) === false) { return } } } function v(Q) { return Object.prototype.toString.call(Q) === "[object Function]" } function p(Q) { return Object.prototype.toString.call(Q) === "[object String]" } function u(aa, Z, Q) { return Array.prototype.slice.call(aa, Z || 0, Q || aa && aa.length) } function D(ab, aa) { var Q = false; P(ab, Z); function Z(ac) { return !(Q = aa(ac)) } return Q } function L(Q) { this._queue = []; this._children = []; this._parent = Q; if (Q) { Q._addChild(this) } } L.prototype = { _addChild: function(Q) { this._children.push(Q) }, push: function(Q) { this._queue.push(Q); this._bubble("_doRun") }, pause: function() { this._bubble("_doPause") }, resume: function() { this._bubble("_doResume") }, _bubble: function(Z) { var Q = this; while (!Q[Z]) { Q = Q._parent } return Q[Z]() }, _next: function() { if (D(this._children, Q)) { return true } function Q(aa) { return aa._next() } var Z = this._queue.shift(); if (Z) { Z() } return !!Z } }; function i(Q) { if (Q) { return new L(Q) } L.call(this); this.paused = 0 } i.prototype = (function() { function Q() {} Q.prototype = L.prototype; return new Q() })(); i.prototype._doRun = function() { if (!this.running) { this.running = true; try { while (this.paused < 1 && this._next()) {} } finally { this.running = false } } }; i.prototype._doPause = function() { this.paused++ }; i.prototype._doResume = function() { this.paused--; this._doRun() }; function M() {} M.prototype = { _html: "", open: function() { this._opened = true; if (this._delegate) { this._delegate.open() } }, write: function(Q) { if (this._closed) { return } this._written = true; if (this._delegate) { this._delegate.write(Q) } else { this._html += Q } }, writeln: function(Q) { this.write(Q + "\n") }, close: function() { this._closed = true; if (this._delegate) { this._delegate.close() } }, copyTo: function(Q) { this._delegate = Q; Q.foobar = true; if (this._opened) { Q.open() } if (this._written) { Q.write(this._html) } if (this._closed) { Q.close() } } }; var e = (function() { var Q = { f: j.getElementById }; try { Q.f.call(j, "abc"); return true } catch (Z) { return false } })(); function I(Q) { P(Q, function(Z) { var aa = j.getElementById(Z.id); if (!aa) { l("<proxyGetElementById - finish>", "no element in writen markup with id " + Z.id); return } P(Z.el.childNodes, function(ab) { aa.appendChild(ab) }); if (aa.contentWindow) { a.setTimeout(function() { Z.el.contentWindow.document.copyTo(aa.contentWindow.document) }, 1) } E.copyAttrs(Z.el, aa) }) } function s(Z, Q) { if (Q && Q[Z] === false) { return false } return Q && Q[Z] || o[Z] } function x(Z, ai) { var ae = [], ad = s("proxyGetElementById", ai), ag = s("writeOnGetElementById", ai), Q = { write: j.write, writeln: j.writeln, finish: function() {}, out: "" }; Z.state = Q; j.write = ah; j.writeln = aa; if (ad || ag) { Q.getEl = j.getElementById; j.getElementById = ab; if (ag) { findEl = af } else { findEl = ac; Q.finish = function() { I(ae) } } } function ah(aj) { Q.out += aj } function aa(aj) { Q.out += aj + "\n" } function ac(ak) { var aj = j.createElement("div"); ae.push({ id: ak, el: aj }); aj.contentWindow = { document: new M() }; return aj } function af(al) { var aj = E.$(Z.target); var ak = j.createElement("div"); aj.parentNode.insertBefore(ak, aj); E.replaceWith(ak, Q.out); Q.out = ""; return e ? Q.getEl.call(j, al) : Q.getEl(al) } function ab(ak) { var aj = e ? Q.getEl.call(j, ak) : Q.getEl(ak); return aj || findEl(ak) } return Q } function V(Q) { j.write = Q.write; j.writeln = Q.writeln; if (Q.getEl) { j.getElementById = Q.getEl } return Q.out } function N(Q) { return Q && Q.replace(/^\s*<!(\[CDATA\[|--)/, "").replace(/(\]\]|--)>\s*$/, "") } function b() {} function d(Z, Q) { console.error("Error", Q, "executing code:", Z) } var l = v(a.console && console.error) ? d : b; function S(aa, Z, Q) { var ab = x(Z, Q); try { A(N(aa)) } catch (ac) { l(aa, ac) } finally { V(ab) } return ab } function O(Z) { var Q = /^(\w+:)?\/\/([^\/?#]+)/.exec(Z); return Q && (Q[1] && Q[1] != location.protocol || Q[2] != location.host) } function T(Q) { return new RegExp(Q + "=(?:([\"'])([\\s\\S]*?)\\1|([^\\s>]+))", "i") } function k(Q) { var Z = T(Q); return function(aa) { var ab = Z.exec(aa) || []; return ab[2] || ab[3] } } var r = /(<script[\s\S]*?>)([\s\S]*?)<\/script>/ig, n = T("src"), X = k("src"), q = k("type"), Y = k("language"), C = "__document_write_ajax_callbacks__", B = "__document_write_ajax_div-", g = "window['" + C + "']['%d']();", m = a[C] = {}, w = '<script type="text/javascript">' + g + "<\/script>", H = 0; function c() { return (++H).toString() } function G(Z, aa) { var Q; if (v(Z)) { Q = Z; Z = null } Z = Z || {}; Q = Q || Z && Z.done; Z.done = aa ? function() { aa(Q) } : Q; return Z } var z = new i(); var y = []; var f = window._debugWriteCapture ? function() {} : function(Q, aa, Z) { y.push({ type: Q, src: aa, data: Z }) }; var K = window._debugWriteCapture ? function() {} : function() { y.push(arguments) }; function W(Q) { var Z = c(); m[Z] = function() { Q(); delete m[Z] }; return Z } function J(Q) { return w.replace(/%d/, W(Q)) } function R(ac, ag, aa, ae) { var ad = aa && new i(aa) || z; ag = G(ag); var ab = s("done", ag); var Q = ""; var Z = s("fixUrls", ag); if (!v(Z)) { Z = function(ah) { return ah } } if (v(ab)) { Q = J(function() { ad.push(ab) }) } return ac.replace(r, af) + Q; function af(aj, av, ai) { var an = X(av), am = q(av) || "", aB = Y(av) || "", aA = (!am && !aB) || am.toLowerCase().indexOf("javascript") !== -1 || aB.toLowerCase().indexOf("javascript") !== -1; f("replace", an, aj); if (!aA) { return aj } var aw = W(ap), ao = B + aw, au, al = { target: "#" + ao, parent: ae }; function ap() { ad.push(au) } if (an) { an = Z(an); av = av.replace(n, ""); if (O(an)) { au = az } else { if (s("asyncAll", ag)) { au = ay() } else { au = at } } } else { au = ax } function ax() { ah(ai) } function at() { E.ajax({ url: an, type: "GET", dataType: "text", async: false, success: function(aC) { ah(aC) } }) } function ak(aE, aC, aD) { l("<XHR for " + an + ">", aD); ad.resume() } function aq() { return J(function() { ad.resume() }) } function ay() { var aE, aD; function aC(aG, aF) { if (!aE) { aD = aG; return } try { ah(aG, aq()) } catch (aH) { l(aG, aH) } } E.ajax({ url: an, type: "GET", dataType: "text", async: true, success: aC, error: ak }); return function() { aE = true; if (aD) { ah(aD) } else { ad.pause() } } } function az(aC) { var aE = x(al, ag); ad.pause(); f("pause", an); E.ajax({ url: an, type: "GET", dataType: "script", success: aD, error: ak }); function aD(aH, aG, aF) { f("out", an, aE.out); ar(V(aE), J(aE.finish) + aq()); f("resume", an) } } function ah(aD, aC) { var aE = S(aD, al, ag); aC = J(aE.finish) + (aC || ""); ar(aE.out, aC) } function ar(aD, aC) { E.replaceWith(al.target, R(aD, null, ad, al) + (aC || "")) } return '<div style="display: none" id="' + ao + '"></div>' + av + g.replace(/%d/, aw) + "<\/script>" } } function F(Z, aa) { var Q = z; P(Z, function(ab) { Q.push(ac); function ac() { ab.action(R(ab.html, ab.options, Q), ab) } }); if (aa) { Q.push(aa) } } function U(Q) { var Z = Q; while (Z && Z.nodeType === 1) { Q = Z; Z = Z.lastChild; while (Z && Z.nodeType !== 1) { Z = Z.previousSibling } } return Q } function h(Q) { var aa = j.write, ad = j.writeln, Z, ab = []; j.writeln = function(ae) { j.write(ae + "\n") }; var ac; j.write = function(af) { var ae = U(j.body); if (ae !== Z) { Z = ae; ab.push(ac = { el: ae, out: [] }) } ac.out.push(af) }; E.onLoad(function() { var ah, ak, af, aj, ai; Q = G(Q); ai = Q.done; Q.done = function() { j.write = aa; j.writeln = ad; if (ai) { ai() } }; for (var ag = 0, ae = ab.length; ag < ae; ag++) { ah = ab[ag].el; ak = j.createElement("div"); ah.parentNode.insertBefore(ak, ah.nextSibling); af = ab[ag].out.join(""); aj = ae - ag === 1 ? R(af, Q) : R(af); E.replaceWith(ak, aj) } }) } var t = "writeCapture"; var o = a[t] = { _original: a[t], fixUrls: function(Q) { return Q.replace(/&/g, "&") }, noConflict: function() { a[t] = this._original; return this }, debug: y, proxyGetElementById: false, _forTest: { Q: i, GLOBAL_Q: z, $: E, matchAttr: k, slice: u, capture: x, uncapture: V, captureWrite: S }, replaceWith: function(Q, aa, Z) { E.replaceWith(Q, R(aa, Z)) }, html: function(Q, ab, Z) { var aa = E.$(Q); aa.innerHTML = "<span/>"; E.replaceWith(aa.firstChild, R(ab, Z)) }, load: function(Q, aa, Z) { E.ajax({ url: aa, dataType: "text", type: "GET", success: function(ab) { o.html(Q, ab, Z) } }) }, autoAsync: h, sanitize: R, sanitizeSerial: F } })(this.writeCaptureSupport, this); (function(g, d, n) { var c = { html: h }; g.each(["append", "prepend", "after", "before", "wrap", "wrapAll", "replaceWith", "wrapInner"], function() { c[this] = i(this) }); function a(q) { return Object.prototype.toString.call(q) == "[object String]" } function p(u, t, s, r) { if (arguments.length == 0) { return o.call(this) } var q = c[u]; if (u == "load") { return l.call(this, t, s, r) } if (!q) { j(u) } return b.call(this, t, s, q) } g.fn.writeCapture = p; var k = "__writeCaptureJsProxied-fghebd__"; function o() { if (this[k]) { return this } var r = this; function q() { var t = this, s = false; this[k] = true; g.each(c, function(v) { var u = r[v]; if (!u) { return } t[v] = function(y, x, w) { if (!s && a(y)) { try { s = true; return p.call(t, v, y, x, w) } finally { s = false } } return u.apply(t, arguments) } }); this.pushStack = function() { return o.call(r.pushStack.apply(t, arguments)) }; this.endCapture = function() { return r } } q.prototype = r; return new q() } function b(t, s, u) { var q, r = this; if (s && s.done) { q = s.done; delete s.done } else { if (g.isFunction(s)) { q = s; s = null } } d.sanitizeSerial(g.map(this, function(v) { return { html: t, options: s, action: function(w) { u.call(v, w) } } }), q && function() { q.call(r) } || q); return this } function h(q) { g(this).html(q) } function i(q) { return function(r) { g(this)[q](r) } } function l(t, s, v) { var r = this, q, u = t.indexOf(" "); if (u >= 0) { q = t.slice(u, t.length); t = t.slice(0, u) } if (g.isFunction(v)) { s = s || {}; s.done = v } return g.ajax({ url: t, type: s && s.type || "GET", dataType: "html", data: s && s.params, complete: f(r, s, q) }) } function f(r, s, q) { return function(u, t) { if (t == "success" || t == "notmodified") { var v = m(u.responseText, q); b.call(r, v, s, h) } } } var e = /jquery-writeCapture-script-placeholder-(\d+)-wc/g; function m(s, r) { if (!r || !s) { return s } var t = 0, q = {}; return g("<div/>").append(s.replace(/<script(.|\s)*?\/script>/g, function(u) { q[t] = u; return "jquery-writeCapture-script-placeholder-" + (t++) + "-wc" })).find(r).html().replace(e, function(u, v) { return q[v] }) } function j(q) { throw "invalid method parameter " + q } g.writeCapture = d })(jQuery, writeCapture.noConflict());
在这个文件中,映入眼帘的是闭包结构,什么?不知道闭包结构?其实我也刚刚知道而已,大体了解了一下,大概是这个意思:
(function(E, a){ var s="aaa"; function f2(){ s+="bbb"; } return f2; } )(f2());//这里相当于f2被浏览器对象当作全局变量进行调用
用括号的格式声明一个匿名函数,在匿名函数中有一些变量和一个子函数f2,匿名函数返回子函数f2,而f2同时又被当作全局变量调用,于是发生了一个很有趣的事情:f2被当作全局变量,所以不会被GC回收,而匿名函数因为被子函数f2访问,所以也不会被GC回收,导致这个匿名函数常驻内存之中,但由于没有名字,所以我们无法再找到并调用这个匿名函数,只能通过预先在f2中所写的语句来对匿名函数中的变量进行操作。基本上效果是:1.匿名函数及其中的局部变量被隐藏。2.匿名函数及其子成员常驻内存,直到页面关闭。(本段抛砖引玉啦~~~)
就是这个可恶的家伙导致我接下来的工作很难开展。
销毁原有的jQuery:
<script type="text/javascript"> //删除旧jQuery $=jQuery; delete $; delete jQuery; </script>
接下来的工作很难开展了,都是因为那个jquery.writeCapture-min.js,怎么样才能销毁这个文件产生的对象呢?有待研究。
本文章系受著作权法保护,未经著作人同意,不得盗用;使用或引用本文章内容请注明作者名、原地址:书中叶http://www.cnblogs.com/libook