[ js.hook.js ]

javascript钩子; 劫持方法/伪造参数/篡改结果/还原劫持

当前为 2016-10-26 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name [ js.hook.js ]
  3. // @description javascript钩子; 劫持方法/伪造参数/篡改结果/还原劫持
  4. // @namespace js.hook.js
  5. // @version 0.0.4
  6. // @author vc1
  7. // ==/UserScript==
  8. /*
  9. *
  10. * [ js.hook.js ]
  11. *
  12. * javascript钩子
  13. *
  14. * * 劫持方法
  15. * * 伪造参数
  16. * * 篡改结果
  17. * * 还原劫持
  18. *
  19. * * 2016-10-25
  20. * * vc1
  21. *
  22. */
  23. (function(name, factory) {
  24. if (typeof define === "function" && define.amd) {
  25. define(name, factory);
  26. } else if (typeof module === "object" && module.exports) {
  27. module.exports = factory();
  28. } else {
  29. this[name] = factory();
  30. }
  31. })('hook', function() {
  32. /*
  33. * 入口方法
  34. *
  35. * hook(alert)
  36. * hook('window.alert')
  37. * hook(window, 'alert')
  38. * hook('MyOjbect.User.info.edit')
  39. */
  40.  
  41. function hook() {
  42. 'use stric'
  43. if (this instanceof hook) return this;
  44.  
  45. var fn_real, // 原始方法正身
  46. fn_name, // 被劫持的方法名
  47. fn_object_name,
  48. fn_object; // 被劫持的方法所在对象
  49. // 'window.alert'
  50. // 'alert'
  51. // alert
  52. // window, 'alert'
  53. var args = Array.prototype.slice.call(arguments),
  54. arg = args.pop();
  55. fn_object = args.pop() || root;
  56. fn_name = arg.name;
  57. if (typeof arg === 'string') {
  58. arg = arg.split('.');
  59. fn_name = arg.pop();
  60. fn_object_name = arg.join('.');
  61. fn_object = eval(fn_object_name || fn_object);
  62. }
  63. fn_real = fn_object[fn_name];
  64.  
  65. if (!(fn_object && fn_name && fn_real)) {
  66. console.error(arguments);
  67. throw new Error('hook fail');
  68. }
  69.  
  70. var storage;
  71. if (fn_object_name) {
  72. storage = hook.prototype.storage[fn_object_name] =
  73. hook.prototype
  74. .storage[fn_object_name] || {};
  75. } else {
  76. /*Object.defineProperties(fn_object, {
  77. '__hook__': {
  78. value: {},
  79. enumerable: false,
  80. configurable: true
  81. }
  82. });*/
  83. storage = fn_object.__hook__ = {};
  84. }
  85.  
  86. // 已经劫持过了,返回已有的钩子
  87. if (storage[fn_name]) {
  88. return storage[fn_name].exports;
  89. }
  90.  
  91. var h = new hook();
  92. // 原始方法正身
  93. h.fn_real = fn_real;
  94. // 被劫持的方法名
  95. h.fn_name = fn_name;
  96. // 被劫持的方法所在对象,默认 window
  97. h.fn_object = fn_object;
  98. // 所在对象名称
  99. h.fn_object_name = fn_object_name;
  100. // 伪造传入参数
  101. h.fake_arg_fn = null;
  102. // 伪造返回结果
  103. h.fake_rst_fn = null;
  104. // 对外暴露的功能
  105. /*h.exports = {
  106. fake: h.fake.bind(h),
  107. fakeArg: h.fakeArg.bind(h),
  108. fakeRst: h.fakeRst.bind(h),
  109. off: h.off.bind(h),
  110. offArg: h.offArg.bind(h),
  111. offRst: h.offRst.bind(h),
  112. data: {
  113. fn_real: fn_real,
  114. fn_name: fn_name,
  115. fn_object_name: fn_object_name,
  116. fn_object: fn_object,
  117. get fn_puppet() {
  118. return h.fn_puppet;
  119. },
  120. get fakeArgFn() {
  121. return h.fakeArgFn;
  122. },
  123. get fakeRstFn() {
  124. return h.fakeRstFn;
  125. }
  126. }
  127. };*/
  128. h.exports = {
  129. fake: bind(h.fake, h),
  130. fakeArg: bind(h.fakeArg, h),
  131. fakeRst: bind(h.fakeRst, h),
  132. off: bind(h.off, h),
  133. offArg: bind(h.offArg, h),
  134. offRst: bind(h.offRst, h),
  135. data: {
  136. fn_real: fn_real,
  137. fn_name: fn_name,
  138. fn_object_name: fn_object_name,
  139. fn_object: fn_object,
  140. fn_puppet: h.fn_puppet,
  141. fakeArgFn: h.fake_arg_fn,
  142. fakeRstFn: h.fake_rst_fn
  143. }
  144. };
  145.  
  146. // 保存当前钩子
  147. storage[fn_name] = h;
  148.  
  149. return h.exports;
  150. }
  151.  
  152. hook.prototype.storage = {};
  153. var root = window || global,
  154. eval = root.eval;
  155. var bind = function(fun, scope) {
  156. return function() {
  157. return fun.apply(scope, arguments)
  158. }
  159. }
  160.  
  161. /*
  162. * 替换原始方法
  163. *
  164. * 作用等于 temp=alert; alert=function(){// your function}
  165. *
  166. * fakeFn(arguments, data)
  167. * 接收到的参数列表, 原始方法信息, 对象实例或原对象, 执行时的作用域
  168. * flag为false,等于x=fn
  169. */
  170. hook.prototype.fake = function(fakeFn, flag) {
  171. var data = this.exports.data;
  172. var puppet = eval("(function " + this.fn_real.name +
  173. "() {debugger;" +
  174. "data.scope = this;" +
  175. (flag === false ?
  176. "return fakeFn.apply(this, arguments)" :
  177. "return fakeFn.call(this, arguments, data)"
  178. ) +
  179. "})");
  180. for (var prop in Object.getOwnPropertyNames(this.fn_real)) {
  181. puppet[prop] = this.fn_real[prop];
  182. }
  183. puppet.toLocaleString = puppet.toString = function() {
  184. return 'function () { [native code] }';
  185. };
  186.  
  187. this.fn_puppet = this.exports.fn_puppet = puppet;
  188. this.fn_object[this.fn_name] = puppet;
  189. return this.exports;
  190. };
  191.  
  192. /*
  193. * 在原方法前,劫持传入的参数
  194. *
  195. * fakeArg('直接替换为要传入的参数', ...)
  196. * fakeArg(function(原参数,){
  197. * //
  198. * return [修改后的参数1,2,3]
  199. * })
  200. *
  201. * 无返回则采用原始参数
  202. */
  203. hook.prototype.fakeArg = function() {
  204. 'use stric'
  205. this.__fakeArgRst__();
  206. this.fake_arg_fn = this.exports.data.fakeArgFn =
  207. __getFun__(
  208. arguments);
  209. return this.exports;
  210. };
  211.  
  212. hook.prototype.fakeArgFn = function(fn) {
  213. 'use stric'
  214. this.__fakeArgRst__();
  215. this.fake_arg_fn = this.exports.data.fakeArgFn = fn;
  216. return this.exports;
  217. };
  218.  
  219. /*
  220. * 在原方法后,劫持返回的数据
  221. *
  222. * fakeRst('直接替换为要传入的参数')
  223. * fakeRst(function(原返回值){
  224. * //
  225. * return 修改后的返回值
  226. * })
  227. */
  228. hook.prototype.fakeRst = function(arg) {
  229. 'use stric'
  230. this.__fakeArgRst__();
  231. this.fake_rst_fn = this.exports.data.fakeRstFn =
  232. __getFun__(
  233. arg);
  234. return this.exports;
  235. };
  236.  
  237. hook.prototype.fakeRstFn = function(fn) {
  238. 'use stric'
  239. this.__fakeArgRst__();
  240. this.fake_rst_fn = this.exports.data.fakeRstFn = fn;
  241. return this.exports;
  242. };
  243.  
  244.  
  245. /*
  246. * 开启劫持arg/rst
  247. */
  248. hook.prototype.__fakeArgRst__ = function() {
  249. 'use stric'
  250. if (typeof this.fn_puppet === 'function') return;
  251. var t = this;
  252. var fakeArgRstFn = function(args, data) {
  253. var faked_arg = data.fakeArgFn ? data.fakeArgFn
  254. .apply(
  255. this, args) || args : args;
  256. typeof faked_arg !== 'string' && Array.prototype
  257. .slice.call(
  258. faked_arg).length === 0 && (faked_arg = [
  259. faked_arg
  260. ]);
  261. var real_rst = data.fn_real.apply(this,
  262. faked_arg);
  263. var faked_rst = data.fakeRstFn ? data.fakeRstFn
  264. .call(
  265. this, real_rst) : real_rst;
  266. return faked_rst;
  267. };
  268. this.fake(fakeArgRstFn, true);
  269. };
  270.  
  271. /*
  272. * 关闭劫持
  273. *
  274. * 传入参数为空:关闭前后所有劫持 hook(alert).off()
  275. * 传入字符串 "arg" 或 "rst":关闭对应劫持 hook(alert).off('arg')
  276. * 传入方法:关闭对应劫持
  277. *
  278. * 前后劫持全部关闭后,还原被 hook 的方法
  279. */
  280. hook.prototype.off = function(filter) {
  281. 'use stric'
  282. if (!filter) {
  283. this.fake_arg_fn = this.exports.data.fakeArgFn =
  284. null;
  285. this.fake_rst_fn = this.exports.data.fakeRstFn =
  286. null;
  287. } else {
  288. filter === 'arg' && (this.fake_arg_fn = this.exports
  289. .data.fakeArgFn =
  290. null);
  291. filter === 'rst' && (this.fake_rst_fn = this.exports
  292. .data.fakeRstFn =
  293. null);
  294. }
  295.  
  296. if (!this.fake_arg_fn && !this.fake_rst_fn) {
  297. this.fn_object[this.fn_name] = this.fn_real;
  298. this.fn_puppet = undefined;
  299. //delete this.storage[this.fn_object_name][this.fn_name];
  300. }
  301.  
  302. return this.exports;
  303. };
  304.  
  305. /*
  306. * 关闭前面的参数劫持
  307. *
  308. */
  309. hook.prototype.offArg = function(filter) {
  310. 'use stric'
  311. filter = filter || 'arg';
  312. this.off(filter);
  313. return this.exports;
  314. };
  315.  
  316. /*
  317. * 关闭后面的结果劫持
  318. *
  319. */
  320. hook.prototype.offRst = function(filter) {
  321. 'use stric'
  322. filter || 'rst';
  323. this.off(filter);
  324. return this.exports;
  325. };
  326.  
  327.  
  328. /*
  329. * 直接修改参数或返回结果
  330. */
  331. var __getFun__ = function(args) {
  332. 'use stric'
  333. return /*typeof args[0] == 'function' ? args[0] :*/ function() {
  334. return args;
  335. };
  336. };
  337.  
  338. return hook;
  339. });
  340.  
  341.  
  342.  
  343.  
  344. // 效果测试
  345.  
  346.  
  347. /*
  348.  
  349.  
  350.  
  351. window.tool = {
  352. calc: function(msg, n) {
  353. console.warn('calc收到参数:' + msg + ', ' + n);
  354. var r = n * n;
  355. console.warn('calc结果:' + r);
  356. return r;
  357. }
  358. }
  359.  
  360.  
  361.  
  362. console.clear();
  363. console.info('一个计算器:');
  364.  
  365. console.group('原始方法:\ntool.calc');
  366. console.log(tool.calc);
  367. console.info('设置参数:' + '专注于计算平方的计算器' + ', ' + 42);
  368. console.info('接收到的结果:' + tool.calc('专注于计算平方的计算器', 42));
  369. console.groupEnd();
  370. console.log('\n');
  371.  
  372.  
  373. console.group("劫持后:\nhook('window.tool.calc').fakeArg('这个计算器坏了', -1).fakeRst('<(ˉ^ˉ)> 告诉你坏了');");
  374. hook('window.tool.calc').fakeArg('这个计算器坏了', -1).fakeRst('<(ˉ^ˉ)> 告诉你坏了');
  375. console.log(tool.calc);
  376. console.info('设置参数:' + '专注于计算平方的计算器' + ', ' + 42);
  377. console.info('接收到的结果:' + tool.calc('专注于计算平方的计算器', 42));
  378. console.groupEnd();
  379. console.log('\n');
  380.  
  381.  
  382. console.group("还原后:\nhook('window.tool.calc').off();");
  383. hook('window.tool.calc').off();
  384. console.log(tool.calc);
  385. console.info('设置参数:' + '专注于计算平方的计算器' + ', ' + 42);
  386. console.info('接收到的结果:' + tool.calc('专注于计算平方的计算器', 42));
  387. console.groupEnd();
  388.  
  389.  
  390.  
  391. */
  392.  
  393.  
  394.  
  395. /*
  396.  
  397.  
  398.  
  399. function print(msg){
  400. document.write((msg||'<br>') + '<br>');
  401. }
  402.  
  403. window.tool = {
  404. calc: function(msg, n) {
  405. print('calc收到参数:' + msg + ', ' + n);
  406. var r = n * n;
  407. print('calc结果:' + r);
  408. return r;
  409. }
  410. }
  411.  
  412.  
  413. print('一个计算器:');
  414.  
  415. print('原始方法:\ntool.calc');
  416. print(tool.calc);
  417. print('设置参数:' + '专注于计算平方的计算器' + ', ' + 42);
  418. print('接收到的结果:' + tool.calc('专注于计算平方的计算器', 42));
  419. print();
  420. print('\n');
  421.  
  422.  
  423. print("劫持后:\nhook('window.tool.calc').fakeArg('这个计算器坏了', -1).fakeRst('<(ˉ^ˉ)> 告诉你坏了');");
  424. hook('window.tool.calc').fakeArg('这个计算器坏了', -1).fakeRst('<(ˉ^ˉ)> 告诉你坏了');
  425. print(tool.calc);
  426. print('设置参数:' + '专注于计算平方的计算器' + ', ' + 42);
  427. print('接收到的结果:' + tool.calc('专注于计算平方的计算器', 42));
  428. print();
  429. print('\n');
  430.  
  431.  
  432. print("还原后:\nhook('window.tool.calc').off();");
  433. hook('window.tool.calc').off();
  434. print(tool.calc);
  435. print('设置参数:' + '专注于计算平方的计算器' + ', ' + 42);
  436. print('接收到的结果:' + tool.calc('专注于计算平方的计算器', 42));
  437. print();
  438.  
  439.  
  440.  
  441. */