本文最后更新于:2020年9月27日 晚上
Hook原理
假设我们现在有这样一个JS代码
| function test(aa,bb){ cc = aa + bb; return cc; } test(100,200);
|
我们在console中可以修改这个函数,比还有其它的方法
| var _setInterval=setInterval; setInterval=function(a,b){ if(a.toString().indexOf("debugger")!=-1{ return null; } _setInterval(a,b); } ~~~如让它打印各个参数的输出结果,这就是一个JS Hook ~~~javascript var _test=test; test=function(aa,bb){ console.log(aa); console.log(bb); var result=_test(aa,bb); console(result);
|
这个函数的注入时机是在函数调用之后,页面加载完毕才注入。但实际上可以在调用地方下断点,在它运行的时候注入JS Hook,在函数被调用之前就进行修改,这也是可以的。
JS Hook看起来是很简单的,不过我们能够用它来实现很强大的功能,比如修改一些系统函数,如debugger,Function,eval等,这些都是和反调试相关的。
我们日常拿到的许多数据都是JSON,所以也可以HookJSON.stringfy进行一些操作,这样一来我们就可以在Hook后直接从堆栈中找到调用函数了。
读者应该已经发现,无论如何Hook,我们总是要把自己的代码注入到网页的环境里边,这个注入的时机选择很重要。
可以选择下断点的方式注入,但是有一种更为优雅的方法,那就是编写Chrome拓展插件,插件可以在网页运行之前就对系统函数进行Hook,一些网页的反调试就可以直接步过了
Hook简单案例
JS Hook是比较容易实现的,但是对网站的破坏性却比较大
所以有些网站会有JS Hook的检测,最常见的就是比对关键函数前后的JS文本,如果不一致就进入循环debugger
| function test(x,y){z=x+y;return z;} setInterval(function(){test+""=="function test(x,y){z=x+y;return z;}" ? console.log("未修改") :setInterval(function(){eval("debugger")},1000);},1000); test(100,200);
|
将函数与””相加会使得函数调用toString方法,返回函数自身的字符串类型代码,在通过预设的校验代码就能知道函数是否被修改过。
想要过掉这种Hook检测,可以修改函数返回的字符串,就能使得检验通过
| function test(x,y){z=x+y;return z;}
function test(x,y){return "Hello world";}
test.toString=function(){return "function test(x,y){z=x+y;return z;}";}; setInterval(function(){test+""=="function test(x,y){z=x+y;return z;}" ? console.log("未修改") :setInterval(function(){eval("debugger")},1000);},1000); test(100,200);
|
当然,还有其它的方法可以解决
| var _setInterval=setInterval; setInterval=function(a,b){ if(a.toString().indexOf("debugger")!=-1{ return null; } _setInterval(a,b); }
|
这样做相当于在执行setInterval函数前检查了函数是否有debugger;有就不执行setInterval函数
Hook对象属性
我们要想Hook对象属性,需要用到Object.defineProperties
或者Object.defineProperty
方法,它可以直接在一个对象上修改原有属性或者定义新的属性
| var obj = new Object(); Object.defineProperties(obj, { name: { value: 'JS Hook', configurable: false, }, age: { value: 18, } }) Object.defineProperty(obj, 'name', { value: 'hello' })
|
obj对象定义了name属性和age属性,其中name属性定义了不能修改
在下面尝试去修改name属性的时候,会报错
只要对象生成之后,我们就可以Hook
比如下边的Hook,会在每次设置对象参数的时候debugger(虽然这样做完以后,这个值就不会赋成功了)
| var obj = new Object(); Object.defineProperty(obj, 'name', { set:function(x){debugger;return x;} })
|
对于内置对象属性的Hook,需要在文档加载之前Hook,这时候就需要用到Chrome拓展插件了。
比如document.cookie中的各种cookies,
要想知道cookies是从哪里生成的,使用Chrome拓展是很方便的,如果要使用断点调试可能比较麻烦一点,我们可以在JS文件头部下断点,在console里边输入如下代码
| Object.defineProperty(document,"cookie",{set:function(x){console.log(x);return x;}})
|