ConsoleHook

utils of hook javascript function and value changes for js reverse engineering

目前為 2025-01-09 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name ConsoleHook
  3. // @namespace http://tampermonkey.net/
  4. // @version 2025-01-09-patch1
  5. // @description utils of hook javascript function and value changes for js reverse engineering
  6. // @author @Esonhugh
  7. // @match http://*
  8. // @match https://*
  9. // @include http://*
  10. // @include https://*
  11. // @icon https://blog.eson.ninja/img/reol.png
  12. // @grant none
  13. // @license MIT
  14. // @run-at document-start
  15. // ==/UserScript==
  16.  
  17. (function () {
  18. console.hooks = {
  19. // settings
  20. settings: {
  21. // trigger debugger if hook is caught
  22. autoDebug: false,
  23. // don't let page jump to other place
  24. blockPageJump: false,
  25. // log prefix
  26. prefix: "[EHOOKS] ",
  27. // init with eventListener added
  28. checkEventListnerAdded: false,
  29. // init with cookie change listener
  30. checkCookieChange: false,
  31. // init with localstorage get set
  32. checkLocalStorageGetSet: false,
  33. // anti dead loop debugger in script
  34. antiDeadLoopDebugger: true,
  35.  
  36. // hidden too many logs
  37. hiddenlog: false,
  38. },
  39.  
  40. rawlog: function (...data) {
  41. if (this.settings.hiddenlog) {
  42. return; // don't print
  43. }
  44. return console.debug(...data);
  45. },
  46.  
  47. log: console.warn,
  48.  
  49. debugger: function () {
  50. // traped in debug
  51. if (this.settings.autoDebug) {
  52. debugger;
  53. }
  54. },
  55.  
  56. hooked: {},
  57.  
  58. dumpstack() {
  59. var err = new Error();
  60. this.log(err.stack.split("\n").slice(2) // delete Error and dumpstack self
  61. .reverse().concat(`${this.settings.prefix}Stack Dump -> STACK TOP`).reverse()
  62. // add StackDump message at top
  63. .join("\n"))
  64. },
  65.  
  66. dumpHooked() {
  67. for (var i in this.hooked) {
  68. this.log(`${i}: `, this.hooked[i]);
  69. }
  70. },
  71.  
  72. hookfunc: function (
  73. object,
  74. functionName,
  75. posthook = () => {},
  76. prehook = () => {}
  77. ) {
  78. (function (originalFunction) {
  79. object[functionName] = function () {
  80. // hook logic
  81. // 1. Allow Check
  82. var args = prehook([originalFunction, arguments, this]);
  83. var realargs = arguments;
  84. if (args) {
  85. realargs = args;
  86. } else {
  87. realargs = arguments;
  88. }
  89. // 2. Execute old function
  90. var returnValue = originalFunction.apply(this, realargs);
  91. console.hooks.rawlog(
  92. `${console.hooks.settings.prefix}Hook function trap-> func[${functionName}]`,
  93. "args->",
  94. realargs,
  95. "ret->",
  96. returnValue
  97. );
  98. console.hooks.debugger();
  99. // 3. Post hook change values
  100. var newReturn = posthook([
  101. returnValue,
  102. originalFunction,
  103. realargs,
  104. this,
  105. ]);
  106. if (newReturn) {
  107. return newReturn;
  108. }
  109. return returnValue;
  110. };
  111. object[functionName].toString = function () {
  112. console.hooks.rawlog(
  113. `${console.hooks.settings.prefix}Found hook toString check!`,
  114. originalFunction
  115. );
  116. console.hooks.debugger();
  117. return originalFunction.toString();
  118. };
  119. console.hooks.hooked[functionName] = originalFunction;
  120. })(object[functionName]);
  121. this.rawlog(
  122. `${console.hooks.settings.prefix}Hook function`,
  123. functionName,
  124. "success!"
  125. );
  126. },
  127.  
  128. unhookfunc: function (object, functionName) {
  129. object[functionName] = console.hooks.hooked[functionName];
  130. this.rawlog(
  131. `${console.hooks.settings.prefix}unHook function`,
  132. functionName,
  133. "success!"
  134. );
  135. },
  136.  
  137. hookCookie: function () {
  138. try {
  139. var cookieDesc =
  140. Object.getOwnPropertyDescriptor(Document.prototype, "cookie") ||
  141. Object.getOwnPropertyDescriptor(HTMLDocument.prototype, "cookie");
  142. if (cookieDesc && cookieDesc.configurable) {
  143. this.hooked["Cookie"] = document.cookie;
  144. Object.defineProperty(document, "cookie", {
  145. set: function (val) {
  146. console.hooks.rawlog(
  147. `${console.hooks.settings.prefix}Hook捕获到cookie设置->`,
  148. val
  149. );
  150. console.hooks.debugger();
  151. console.hooks.hooked["Cookie"] = val;
  152. return val;
  153. },
  154. get: function () {
  155. return (console.hooks.hooked["Cookie"] = "");
  156. },
  157. configurable: true,
  158. });
  159. } else {
  160. var org = document.__lookupSetter__("cookie");
  161. document.__defineSetter__("cookie", function (cookie) {
  162. console.hooks.rawlog(
  163. `${console.hooks.settings.prefix}Cookie Set as`,
  164. cookie
  165. );
  166. console.hooks.debugger();
  167. org = cookie;
  168. });
  169. document.__defineGetter__("cookie", function () {
  170. console.hooks.rawlog(
  171. `${console.hooks.settings.prefix}Cookie Got`,
  172. org
  173. );
  174. console.hooks.debugger();
  175. return org;
  176. });
  177. }
  178. } catch (e) {
  179. this.rawlog(`${console.hooks.settings.prefix}Cookie hook failed!`);
  180. }
  181. },
  182.  
  183. hookLocalStorage: function () {
  184. this.hookfunc(localStorage, "getItem");
  185. this.hookfunc(localStorage, "setItem");
  186. this.hookfunc(localStorage, "removeItem");
  187. this.hookfunc(localStorage, "clear");
  188. this.rawlog(`${console.hooks.settings.prefix}LocalStorage hooked!`);
  189. },
  190.  
  191. hookValueViaGetSet: function (name, obj, key) {
  192. if (obj[key]) {
  193. this.hooked[key] = obj[key];
  194. }
  195. var obj_name = `${name}.${key}`;
  196. var org = obj.__lookupSetter__(key);
  197. obj.__defineSetter__(key, function (val) {
  198. org = console.hooks.hooked[key];
  199. console.hooks.rawlog(
  200. `${console.hooks.settings.prefix}Hook value set `,
  201. obj_name,
  202. "value->",
  203. org,
  204. "newvalue->",
  205. val
  206. );
  207. console.hooks.debugger();
  208. console.hooks.hooked[key] = val;
  209. });
  210. obj.__defineGetter__(key, function () {
  211. org = console.hooks.hooked[key];
  212. console.hooks.rawlog(
  213. `${console.hooks.settings.prefix}Hook value get `,
  214. obj_name,
  215. "value->",
  216. org
  217. );
  218. console.hooks.debugger();
  219. return org;
  220. });
  221. },
  222.  
  223. hookValueViaProxy: function (name, obj, key = "default_all") {
  224. var obj_name = "OBJ_" + name;
  225. return new Proxy(obj, {
  226. get: function (target, property, receiver) {
  227. if (!target[property]) {
  228. ret = undefined;
  229. } else {
  230. ret = target[property];
  231. }
  232. if (key === "default_all") {
  233. console.hooks.rawlog(
  234. `${console.hooks.settings.prefix}Hook Proxy value get`,
  235. `${obj_name}.${property}`,
  236. "value->",
  237. ret
  238. );
  239. console.hooks.debugger();
  240. }
  241. if (property == key && key != "default_all") {
  242. console.hooks.rawlog(
  243. `${console.hooks.settings.prefix}Hook Proxy value get`,
  244. `${obj_name}.${property}`,
  245. "value->",
  246. ret
  247. );
  248. console.hooks.debugger();
  249. }
  250. return target[property];
  251. },
  252. set: function (target, property, newValue, receiver) {
  253. if (!target[property]) {
  254. ret = undefined;
  255. } else {
  256. ret = target[property];
  257. }
  258. if (key === "default_all") {
  259. console.hooks.rawlog(
  260. `${console.hooks.settings.prefix}Hook Proxy value set`,
  261. `${obj_name}.${property}`,
  262. "value->",
  263. ret,
  264. "newvalue->",
  265. newValue
  266. );
  267. console.hooks.debugger();
  268. }
  269. if (property == key && key != "default_all") {
  270. console.hooks.rawlog(
  271. `${console.hooks.settings.prefix}Hook Proxy value get`,
  272. `${obj_name}.${property}`,
  273. "value->",
  274. ret,
  275. "newvalue->",
  276. newValue
  277. );
  278. console.hooks.debugger();
  279. }
  280. target[property] = newValue;
  281. return true;
  282. },
  283. });
  284. },
  285.  
  286. hookEvents: function (params) {
  287. var placeToReplace;
  288. if (window.EventTarget && EventTarget.prototype.addEventListener) {
  289. placeToReplace = EventTarget;
  290. } else {
  291. placeToReplace = Element;
  292. }
  293. this.hookfunc(
  294. placeToReplace.prototype,
  295. "addEventListener",
  296. function (res) {
  297. let [ret, originalFunction, arguments] = res;
  298. console.hooks.rawlog(
  299. `${console.hooks.settings.prefix}Hook event listener added!`,
  300. arguments
  301. );
  302. }
  303. );
  304. },
  305.  
  306. antiDebuggerLoops: function () {
  307. processDebugger = (type,res) => {
  308. let [originalFunction, arguments, t] = res;
  309. var handler = arguments[0];
  310. console.hooks.debugger();
  311. if (handler.toString().includes("debugger")) {
  312. console.hooks.log(
  313. `${console.hooks.settings.prefix}found debug loop in ${type}`
  314. );
  315. console.hooks.debugger();
  316. let func = handler.toString().replaceAll("debugger", "");
  317. arguments[0] = new Function("return " + func)();
  318. return arguments;
  319. } else {
  320. return arguments;
  321. }
  322. };
  323.  
  324. this.hookfunc(
  325. window,
  326. "setInterval",
  327. () => {},
  328. (res)=>{return processDebugger("setInterval", res)}
  329. );
  330. this.hookfunc(
  331. window,
  332. "setTimeout",
  333. () => {},
  334. (res) => {return processDebugger("setTimeout", res)}
  335. );
  336. this.hookfunc(Function.prototype, "constructor", (res) => {
  337. let [ret, originalFunction, arguments, env] = res;
  338. if (ret.toString().includes("debugger")) {
  339. console.hooks.log(
  340. `${console.hooks.settings.prefix}found debug loop in Function constructor`
  341. );
  342. console.hooks.debugger();
  343. let func = ret.toString().replaceAll("debugger", "");
  344. return new Function("return " + func)();
  345. }
  346. return ret;
  347. });
  348. },
  349.  
  350. init: function () {
  351. if (this.settings.blockPageJump) {
  352. window.onbeforeunload = function () {
  353. return "ANTI LEAVE";
  354. };
  355. }
  356. if (this.settings.checkEventListnerAdded) {
  357. this.hookEvents();
  358. }
  359. if (this.settings.checkCookieChange) {
  360. this.hookCookie();
  361. }
  362. if (this.settings.checkLocalStorageGetSet) {
  363. this.hookLocalStorage();
  364. }
  365. if (this.settings.antiDeadLoopDebugger) {
  366. this.antiDebuggerLoops();
  367. }
  368. },
  369.  
  370. main: function () {
  371. this.hookfunc(window, "eval");
  372. this.hookfunc(window, "Function");
  373. this.hookfunc(window, "atob");
  374. this.hookfunc(window, "btoa");
  375. this.hookfunc(window, "fetch");
  376. this.hookfunc(window, "encodeURI");
  377. this.hookfunc(window, "encodeURIComponent");
  378.  
  379. this.hookfunc(JSON, "parse");
  380. this.hookfunc(JSON, "stringify");
  381.  
  382. this.hookfunc(console, "log");
  383. // this.hookfunc(console, "warn")
  384. // this.hookfunc(console, "error")
  385. // this.hookfunc(console, "info")
  386. // this.hookfunc(console, "debug")
  387. // this.hookfunc(console, "table")
  388. // this.hookfunc(console, "trace")
  389. this.hookfunc(console, "clear");
  390. },
  391. };
  392.  
  393. // auto run init
  394. console.hooks.init();
  395. })();