FunctionHooker.js

Hook most functions on runtime via the function name

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.gf.qytechs.cn/scripts/469993/1214452/FunctionHookerjs.js

  1. // ==UserScript==
  2. // @name FunctionHooker.js
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.1
  5. // @description Hook most functions on runtime via the function name
  6. // @author You
  7. // @match *://*.*
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. class FunctionHooker {
  12. constructor() {
  13. this.hooks = new Map();
  14. this.originalName = "";
  15. }
  16. getOriginal(functionName) {
  17. return this.hooks.get(functionName);
  18. }
  19.  
  20. hook(targetFunction, hookFunction) {
  21. const isString = typeof targetFunction == "string";
  22. // TODO: isString is used to eventually distinct a target function passed as a direct reference
  23. // to a function from the user passing a function name as a string
  24. // problem is there is no way to go from a function reference to a proper function name string
  25.  
  26. const isFullyQualifiedName = targetFunction.indexOf('.') != -1;
  27. this.originalName = targetFunction;
  28. if (isFullyQualifiedName) { this.hookFullyQualified(targetFunction, hookFunction); return; }
  29.  
  30. const originalFunction = window[targetFunction];
  31.  
  32. if (originalFunction) {
  33. this.hooks.set(targetFunction, originalFunction);
  34. window[targetFunction] = hookFunction;
  35. } else {
  36. throw new Error(`Function '${targetFunction}' does not exist in the 'window' object.`);
  37. }
  38. }
  39.  
  40. unhook(functionName) {
  41. const isFullyQualifiedName = functionName.indexOf('.') != -1;
  42. if (isFullyQualifiedName) { this.unhookFullyQualified(functionName); return; }
  43. const originalFunction = this.hooks.get(functionName);
  44.  
  45. if (originalFunction) {
  46. window[functionName] = originalFunction;
  47. this.hooks.delete(functionName);
  48. } else {
  49. throw new Error(`Function '${functionName}' is not hooked.`);
  50. }
  51. }
  52.  
  53. resolveFullyQualifiedFunctionName(functionName) {
  54. const functionNames = functionName.split('.');
  55. let resolvedFunction = window;
  56.  
  57. for (const name of functionNames) {
  58. resolvedFunction = resolvedFunction[name];
  59.  
  60. if (!resolvedFunction) {
  61. throw new Error(`Function '${functionName}' does not exist.`);
  62. }
  63. }
  64.  
  65. return resolvedFunction;
  66. }
  67.  
  68. hookFullyQualified(functionName, hookFunction) {
  69. const resolvedFunction = this.resolveFullyQualifiedFunctionName(functionName);
  70. const originalFunction = resolvedFunction;
  71.  
  72. this.hooks.set(functionName, originalFunction);
  73.  
  74. const parentObject = functionName
  75. .split('.')
  76. .slice(0, -1)
  77. .reduce((obj, prop) => (obj[prop] ? obj[prop] : obj), window);
  78.  
  79. const functionNameLeaf = functionName.split('.').pop();
  80. if (typeof parentObject[functionNameLeaf] != 'function') { debugger; throw new Error(`Function '${this.originalName}' is not hooked.`); }
  81. parentObject[functionNameLeaf] = hookFunction;
  82. }
  83.  
  84. unhookFullyQualified(functionName) {
  85. const resolvedFunction = this.resolveFullyQualifiedFunctionName(functionName);
  86. const originalFunction = this.hooks.get(functionName);
  87.  
  88. if (originalFunction) {
  89. const parentObject = functionName
  90. .split('.')
  91. .slice(0, -1)
  92. .reduce((obj, prop) => (obj[prop] ? obj[prop] : obj), window);
  93.  
  94. const functionNameLeaf = functionName.split('.').pop();
  95. parentObject[functionNameLeaf] = originalFunction;
  96.  
  97. this.hooks.delete(functionName);
  98. } else {
  99. throw new Error(`Function '${functionName}' is not hooked.`);
  100. }
  101. }
  102. }

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址