[hook.js]通用Javascript函数钩子
Author:pnig0s_小P
最近看Dom Xss检测相关的Paper,涉及到Hook Javascript函数,网上翻了一下,貌似没有什么通用的函数钩子脚本,自己用就自己写一个吧。最后有代码地址,前面写下mind storm的过程。
最经典且简单的Javascript函数钩子的写法应该是下面这样了:
1 2 3 4 5 |
var _alert = alert; window.alert = function(s) { console.log("Hooked!"); _alert(s); } |
不过这种Hook方式跟闹着玩儿似的,用到实际生产上通用性不好,效率也不高。
国内比较早看到的介绍Javascript函数劫持的文章应该是安全焦点上luoluo写的《浅谈javascript函数劫持》,用Javascript函数钩子实现了一个简单的内联代码调试器。余弦的新书《Web前端黑客技术揭秘》中也设计到了相关内容。后来看到了大风在08年搞了一个anehta的攻击平台,其中有一段能够hook任意Javascript函数的代码,看了下有一些问题,不过毕竟钩子只是anehta其中一个功能。这里贴出部分代码,有兴趣可以到这里看完整版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
hook: function(funcNameHooked, RealFuncAfterHooked, hookFunc){ try { setTimeout(function(){ //alert("hook before: "+window[funcNameHooked]); // 保存原函数 window[RealFuncAfterHooked] = window[funcNameHooked]; //window[funcNameHooked] = window[hookFunc]; // 参数个数可以根据需要进行调整 window[funcNameHooked] = function (param1,param2,param3,param4,param5,param6,param7){ // 劫持参数 var newParam = new Array(); // 先执行注入的函数; 需要返回被劫持后的参数,作为新参数传入原函数 newParam = window[hookFunc](param1,param2, param3, param4, param5, param6, param7) //alert("newParam= "+newParam); // 再执行原函数 window[RealFuncAfterHooked](newParam[0], newParam[1], newParam[2], newParam[3], newParam[4], newParam[5], newParam[6]); // 不注入参数,直接执行原函数; //window[RealFuncAfterHooked](param1,param2,param3,param4,param5,param6,param7); } //alert("hook after: "+window[funcNameHooked]); }, 10); return true; } catch (e){ return false; } }, |
这段代码固定了被Hook的函数所在对象是window,这样对于自定义对象中的函数及原型对象中的函数(String.prototype)就没办法进行Hook了。而且参数param[1-7]是写死在函数里的,通用性不太好,其实可以用arguments对象来实现变参。
因为要做的是函数钩子,函数又都是Function对象的实例,那么直接给Function.prototype添加hook和unhook函数就可以了。
按照这个思路自己写了一个,简单封装了一下,能够对普通的全局函数(eg:alert),自定义类中的函数(eg:cat.Eat()),以及原型对象中的函数(eg:String.prototype.slice)进行hook。可以防止函数被二次hook而导致的callback in callback。代码不长这里就贴出来了,也可以到github上去看,有测试样例和详细的参数说明。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
function Hooks() { return { initEnv:function () { Function.prototype.hook = function (realFunc,hookFunc,context,funcName) { var _context = null; //函数上下文 var _funcName = null; //函数名 _context = context || window; _funcName = funcName || getFuncName(this); _context[realFunc] = this; if(_context[_funcName].prototype && _context[_funcName].prototype.isHooked) { console.log("Already has been hooked,unhook first"); return false; } function getFuncName (fn) { // 获取函数名 var strFunc = fn.toString(); var _regex = /function\s+(\w+)\s*\(/; var patten = strFunc.match(_regex); if (patten) { return patten[1]; }; return ''; } try { eval('_context[_funcName] = function '+_funcName+'(){\n'+ 'var args = Array.prototype.slice.call(arguments,0);\n'+ 'var obj = this;\n'+ 'hookFunc.apply(obj,args)\n'+ 'return _context[realFunc].apply(obj,args);\n'+ '};'); _context[_funcName].prototype.isHooked = true; return true; }catch (e) { console.log("Hook failed,check the params."); return false; } } Function.prototype.unhook = function (realFunc,funcName,context) { var _context = null; var _funcName = null; _context = context || window; _funcName = funcName; if (!_context[_funcName].prototype.isHooked) { console.log("No function is hooked on"); return false; } _context[_funcName] = _context[realFunc]; delete _context[realFunc]; return true; } }, cleanEnv:function () { if(Function.prototype.hasOwnProperty("hook")) { delete Function.prototype.hook; } if(Function.prototype.hasOwnProperty("unhook")) { delete Function.prototype.unhook; } return true; } }; } |
Javascript写的少,各种意见建议欢迎:)
Github:[hookjs]
2条评论
不错啊,有意思。。。
http://www.shuazuanmi.com 网站被拦截,还不说明原因, 你们旗下的scanv为什么这么霸道