步骤
- 寻找
Hook
点 - 编写
hook
逻辑 - 调试
公式
old_func = func
func = function(){
my task;
return func.apply(argument)
}
// 修改原生的方法,伪装没有被hook,比如toString方法
func.prototype······ = ······
hook
对象中的属性
hook对象中的属性
old_attr = obj.attr
Object.defineProperty(obj, 'attr', {
get:function(){
console.log(cookie_cache);
return old_attr
},
set:function(val){
return ·······
}
})
关于hook
- 如果能修改源码,那么一般来说源码修改比hook方便
- 系统/框架API无法轻松通过源码修改来实现我们的目的
js
由于是解释型语言,代码 == 二进制,一般使用源码修改修改方法js
语言由于是解释型语言,无法通过全局root
定位到js
所有方法定义,现代js
为了避免变量污染大多对js
代码进行多层js
函数包装,故很难通过框架自动化寻找hook
点。
为什么能实现hook
客户端拥有js
的最高解释权,可以决定在任何时候注入js
而服务器无法左右,只能通过检测和混淆手段令hook
难度加大,但是却无法阻止。
hook
的目的
js hook
目的是找到函数入口以及一些参数变化,便于分析js
逻辑,但是hook
的能力远不及此,只能借助其寻找函数入口。
hook
的弊端和缺陷
函数hook
一般不会出现hook
失败的情况,只有可能是__proto__
模拟的不好被检测到了
属性hook
当所有网站逻辑都采用Object.defineProperty
绑定后,属性hook
就会失效
还有一种叫做局部hook
,只不过需要在当进入作用域的那一刻进行hook
hook
插件(油猴脚本注入)
//run-at document-start
(function(){
alert('hook success');
var eval_bk = eval;
eval = function(val){
console.log(val)
return eval_bk(val);
};
eval.toString = function(){
return "function eval(){[native code]}"
};
eval.length = 1;
})();
例子:
// ==UserScript==
// @name 万能hook eval函数
// @namespace http://tampermonkey.net/
// @version 0.1
// @description eval-everything
// @author xiaosheng
// @include *
// @grant none
// @run-at document-start
// ==/UserScript==
(function() {
alert('hook success');
var eval_bk = eval;
eval = function(val){
console.log(val)
return eval_bk(val);
};
eval.toString = function(){
return "function eval() { [native code] }"
};
eval.length = 1;
})();
原型链相关的hook
a = "加密逻辑"
按常规的hook方式,hook a.split
a.split = function(){
debugger;
}
这种方式重写不了
得用原型链 --- :因为a.split方法是通过原型链来的,其实是 String.prototype.split
String.prototype.split = function(){
debugger;
}
/*
改进一下,为了让hook之后的代码也能正常执行,下面这样写是错误的
x下面这样写 会导致 递归 栈溢出
String.prototype.split = function(val){
str = this.toString()
debugger;
return str.split(val)
}
再改进一下,
下面这样不行,因为,return str.split_bk(val) 找的是str里面的split_bk方法,
而不是自己重写的这个方法
split_bk = String.prototype.split
String.prototype.split = function(val){
str = this.toString()
debugger;
return str.split_bk(val)
}
*/
String.prototype.split_bk = String.prototype.split
String.prototype.split = function(val){
str = this.toString()
debugger;
return str.split_bk(val)
}
这样也能被检测到,比如通过toString
String.prototype.split.toString = function(){
return "function split() { [native code] }"
}
XMLHttpRequest.prototype.setRequestHeader = function(){
debugger;
}
hook
对象
思考题:比如ob
混淆的内存泄露,他是通过依靠正则完成的,那么是否能hook
正则,然后让test
的检测逻辑发生变化(恒为true
, 或者取反,由此处理内存泄露的问题)
RegExp.prototype.test_bk = RegExp.prototype.test
RegExp.prototype.test = function(val){
t = this
debugger;
return !t.test_bk(val)
};
RegExp.prototype.test.toString = function(){return "function test() { [native code] }"}
两个常用hook
函数
Object.defineProperty(document, "cookie", {
get:function(){
console.log('getting cookie')
},
set:function(val){
if(val.indexOf('sign')!=-1){
debugger;
return val;
}
}
})
Function.prototype.constructor_bk = Function.prototype.constructor
Function.prototype.constructor = function(){
if (arguments[0]=="debugger"){
}else{
return Function.prototype.constructor_bk.apply(this, arguments)
}
}