javascript钩子; 劫持方法/伪造参数/篡改结果/还原劫持
当前为
// ==UserScript==
// @name [ js.hook.js ]
// @description javascript钩子; 劫持方法/伪造参数/篡改结果/还原劫持
// @namespace js.hook.js
// @version 0.0.3
// @author vc1
// ==/UserScript==
/*
*
* [ js.hook.js ]
*
* javascript钩子
*
* * 劫持方法
* * 伪造参数
* * 篡改结果
* * 还原劫持
*
* * 2016-04-02
* * vc1
*
*/
(function(name, factory) {
if (typeof define === "function" && define.amd) {
define(name, factory);
} else if (typeof module === "object" && module.exports) {
module.exports = factory();
} else {
this[name] = factory();
}
})('hook', function() {
/*
* 入口方法
*
* hook(alert)
* hook('window.alert')
* hook(window, 'alert')
* hook('MyOjbect.User.info.edit')
*/
function hook() {
'use stric'
if (this instanceof hook) return this;
var fn_real, // 原始方法正身
fn_name, // 被劫持的方法名
fn_object_name,
fn_object; // 被劫持的方法所在对象
// 'window.alert'
// 'alert'
// alert
// window, 'alert'
var args = Array.prototype.slice.call(arguments),
arg = args.pop();
fn_object = args.pop() || root;
fn_name = arg.name;
if (typeof arg === 'string') {
arg = arg.split('.');
fn_name = arg.pop();
fn_object_name = arg.join('.');
fn_object = eval(fn_object_name || fn_object);
}
fn_real = fn_object[fn_name];
if (!(fn_object && fn_name && fn_real)) {
console.error(arguments);
throw new Error('hook fail');
}
var storage;
if (fn_object_name) {
storage = hook.prototype.storage[fn_object_name] = hook.prototype
.storage[fn_object_name] || {};
} else {
Object.defineProperties(fn_object, {
'__hook__': {
value: {},
enumerable: false,
configurable: true
}
});
storage = fn_object.__hook__;
}
// 已经劫持过了,返回已有的钩子
if (storage[fn_name]) {
return storage[fn_name].exports;
}
var h = new hook();
// 原始方法正身
h.fn_real = fn_real;
// 被劫持的方法名
h.fn_name = fn_name;
// 被劫持的方法所在对象,默认 window
h.fn_object = fn_object;
// 所在对象名称
h.fn_object_name = fn_object_name;
// 伪造传入参数
h.fakeArgFn = null;
// 伪造返回结果
h.fakeRstFn = null;
// 对外暴露的功能
h.exports = {
fake: h.fake.bind(h),
fakeArg: h.fakeArg.bind(h),
fakeRst: h.fakeRst.bind(h),
off: h.off.bind(h),
offArg: h.offArg.bind(h),
offRst: h.offRst.bind(h),
data: {
fn_real: fn_real,
fn_name: fn_name,
fn_object_name: fn_object_name,
fn_object: fn_object,
get fn_puppet() {
return h.fn_puppet;
},
get fakeArgFn() {
return h.fakeArgFn;
},
get fakeRstFn() {
return h.fakeRstFn;
}
}
};
// 保存当前钩子
storage[fn_name] = h;
return h.exports;
}
hook.prototype.storage = {};
var root = window || global,
eval = root.eval;
/*
* 替换原始方法
*
* 作用等于 temp=alert; alert=function(){// your function}
*
* fakeFn(arguments, data)
* 接收到的参数列表, 原始方法信息, 对象实例或原对象, 执行时的作用域
* flag为false,等于x=fn
*/
hook.prototype.fake = function(fakeFn, flag) {
var data = this.exports.data;
var puppet = eval("(function " + this.fn_real.name + "() {" +
"data.scope = this;" +
(flag === false ?
"return fakeFn.apply(this, arguments)" :
"return fakeFn.call(this, arguments, data)"
) +
"})");
for (var prop in Object.getOwnPropertyNames(this.fn_real)) {
puppet[prop] = this.fn_real[prop];
}
puppet.toLocaleString = puppet.toString = function() {
return 'function () { [native code] }';
};
this.fn_puppet = puppet;
this.fn_object[this.fn_name] = puppet;
return this.exports;
};
/*
* 在原方法前,劫持传入的参数
*
* fakeArg('直接替换为要传入的参数', ...)
* fakeArg(function(原参数,){
* //
* return [修改后的参数1,2,3]
* })
*
* 无返回则采用原始参数
*/
hook.prototype.fakeArg = function(arg) {
'use stric'
this.__fakeArgRst__();
this.fakeArgFn = this.__getFun__(arguments);
return this.exports;
};
/*
* 在原方法后,劫持返回的数据
*
* fakeRst('直接替换为要传入的参数')
* fakeRst(function(原返回值){
* //
* return 修改后的返回值
* })
*/
hook.prototype.fakeRst = function(arg) {
'use stric'
this.__fakeArgRst__();
this.fakeRstFn = this.__getFun__(arg);
return this.exports;
};
/*
* 开启劫持arg/rst
*/
hook.prototype.__fakeArgRst__ = function() {
'use stric'
if (typeof this.fn_puppet === 'function') return;
var t = this;
var fakeArgRstFn = function(args, data) {
var faked_arg = data.fakeArgFn ? data.fakeArgFn.apply(
this, args) || args : args;
typeof faked_arg !== 'string' && Array.prototype.slice.call(
faked_arg).length === 0 && (faked_arg = [
faked_arg]);
var real_rst = data.fn_real.apply(this, faked_arg);
var faked_rst = data.fakeRstFn ? data.fakeRstFn.call(
this, real_rst) : real_rst;
return faked_rst;
};
this.fake(fakeArgRstFn);
};
/*
* 关闭劫持
*
* 传入参数为空:关闭前后所有劫持 hook(alert).off()
* 传入字符串 "arg" 或 "rst":关闭对应劫持 hook(alert).off('arg')
* 传入方法:关闭对应劫持
*
* 前后劫持全部关闭后,还原被 hook 的方法
*/
hook.prototype.off = function(filter) {
'use stric'
if (!filter) {
delete this.fakeArgFn;
delete this.fakeRstFn;
} else {
(this.fakeArgFn === fn || filter === 'arg') && delete this.fakeArgFn;
(this.fakeRstFn === fn || filter === 'rst') && delete this.fakeRstFn;
}
if (!this.fakeArgFn && !this.fakeRstFn) {
this.fn_object[this.fn_name] = this.fn_real;
this.fn_puppet = undefined;
//delete this.storage[this.fn_object_name][this.fn_name];
}
return this.exports;
};
/*
* 关闭前面的参数劫持
*
*/
hook.prototype.offArg = function(filter) {
'use stric'
filter = filter || 'arg';
this.off(filter);
return this.exports;
};
/*
* 关闭后面的结果劫持
*
*/
hook.prototype.offRst = function(filter) {
'use stric'
filter || 'rst';
this.off(filter);
return this.exports;
};
/*
* 直接修改参数或返回结果
*/
hook.prototype.__getcloser__ = function(args) {
'use stric'
return function() {
return args;
};
};
hook.prototype.__getFun__ = function(arg) {
'use stric'
return typeof arg[0] == 'function' ? arg[0] : this.__getcloser__(
arg);
};
return hook;
});