ConsoleHook

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

目前为 2025-01-10 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name ConsoleHook
  3. // @namespace http://tampermonkey.net/
  4. // @version 2025-01-10
  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] ", // u can filter all this things with this tag
  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 default debug logs if you don't need it
  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. // dump the real stack for u
  53. this.dumpstack();
  54. debugger;
  55. }
  56. },
  57.  
  58. hooked: {},
  59.  
  60. dumpstack(print = true) {
  61. var err = new Error();
  62. ret = err.stack
  63. .split("\n")
  64. .slice(2) // delete Error and dumpstack self
  65. .reverse()
  66. .concat(`${this.settings.prefix}Stack Dump -> STACK TOP`)
  67. .reverse()
  68. // add StackDump message at top
  69. .join("\n");
  70. if (print) {
  71. this.log(ret);
  72. }
  73. return ret;
  74. },
  75.  
  76. dumpHooked() {
  77. for (var i in this.hooked) {
  78. this.log(`${i}: `, this.hooked[i]);
  79. }
  80. },
  81.  
  82. hookfunc: function (
  83. object,
  84. functionName,
  85. posthook = () => {},
  86. prehook = () => {}
  87. ) {
  88. (function (originalFunction) {
  89. object[functionName] = function () {
  90. // hook logic
  91. // 1. Allow Check
  92. var args = prehook([originalFunction, arguments, this]);
  93. var realargs = arguments;
  94. if (args) {
  95. realargs = args;
  96. } else {
  97. realargs = arguments;
  98. }
  99. // 2. Execute old function
  100. var returnValue = originalFunction.apply(this, realargs);
  101. console.hooks.rawlog(
  102. `${console.hooks.settings.prefix}Hook function trap-> func[${functionName}]`,
  103. "args->",
  104. realargs,
  105. "ret->",
  106. returnValue
  107. );
  108. console.hooks.debugger();
  109. // 3. Post hook change values
  110. var newReturn = posthook([
  111. returnValue,
  112. originalFunction,
  113. realargs,
  114. this,
  115. ]);
  116. if (newReturn) {
  117. return newReturn;
  118. }
  119. return returnValue;
  120. };
  121. object[functionName].toString = function () {
  122. console.hooks.rawlog(
  123. `${console.hooks.settings.prefix}Found hook toString check!`,
  124. originalFunction
  125. );
  126. console.hooks.debugger();
  127. return originalFunction.toString();
  128. };
  129. console.hooks.hooked[functionName] = originalFunction;
  130. })(object[functionName]);
  131. this.rawlog(
  132. `${console.hooks.settings.prefix}Hook function`,
  133. functionName,
  134. "success!"
  135. );
  136. },
  137.  
  138. unhookfunc: function (object, functionName) {
  139. object[functionName] = console.hooks.hooked[functionName];
  140. this.rawlog(
  141. `${console.hooks.settings.prefix}unHook function`,
  142. functionName,
  143. "success!"
  144. );
  145. },
  146.  
  147. hookCookie: function () {
  148. try {
  149. var cookieDesc =
  150. Object.getOwnPropertyDescriptor(Document.prototype, "cookie") ||
  151. Object.getOwnPropertyDescriptor(HTMLDocument.prototype, "cookie");
  152. if (cookieDesc && cookieDesc.configurable) {
  153. this.hooked["Cookie"] = document.cookie;
  154. Object.defineProperty(document, "cookie", {
  155. set: function (val) {
  156. console.hooks.rawlog(
  157. `${console.hooks.settings.prefix}Hook捕获到cookie设置->`,
  158. val
  159. );
  160. console.hooks.debugger();
  161. console.hooks.hooked["Cookie"] = val;
  162. return val;
  163. },
  164. get: function () {
  165. return (console.hooks.hooked["Cookie"] = "");
  166. },
  167. configurable: true,
  168. });
  169. } else {
  170. var org = document.__lookupSetter__("cookie");
  171. document.__defineSetter__("cookie", function (cookie) {
  172. console.hooks.rawlog(
  173. `${console.hooks.settings.prefix}Cookie Set as`,
  174. cookie
  175. );
  176. console.hooks.debugger();
  177. org = cookie;
  178. });
  179. document.__defineGetter__("cookie", function () {
  180. console.hooks.rawlog(
  181. `${console.hooks.settings.prefix}Cookie Got`,
  182. org
  183. );
  184. console.hooks.debugger();
  185. return org;
  186. });
  187. }
  188. } catch (e) {
  189. this.rawlog(`${console.hooks.settings.prefix}Cookie hook failed!`);
  190. }
  191. },
  192.  
  193. hookLocalStorage: function () {
  194. this.hookfunc(localStorage, "getItem");
  195. this.hookfunc(localStorage, "setItem");
  196. this.hookfunc(localStorage, "removeItem");
  197. this.hookfunc(localStorage, "clear");
  198. this.rawlog(`${console.hooks.settings.prefix}LocalStorage hooked!`);
  199. },
  200.  
  201. hookValueViaGetSet: function (name, obj, key) {
  202. if (obj[key]) {
  203. this.hooked[key] = obj[key];
  204. }
  205. var obj_name = `${name}.${key}`;
  206. var org = obj.__lookupSetter__(key);
  207. obj.__defineSetter__(key, function (val) {
  208. org = console.hooks.hooked[key];
  209. console.hooks.rawlog(
  210. `${console.hooks.settings.prefix}Hook value set `,
  211. obj_name,
  212. "value->",
  213. org,
  214. "newvalue->",
  215. val
  216. );
  217. console.hooks.debugger();
  218. console.hooks.hooked[key] = val;
  219. });
  220. obj.__defineGetter__(key, function () {
  221. org = console.hooks.hooked[key];
  222. console.hooks.rawlog(
  223. `${console.hooks.settings.prefix}Hook value get `,
  224. obj_name,
  225. "value->",
  226. org
  227. );
  228. console.hooks.debugger();
  229. return org;
  230. });
  231. },
  232.  
  233. hookValueViaProxy: function (name, obj, key = "default_all") {
  234. var obj_name = "OBJ_" + name;
  235. return new Proxy(obj, {
  236. get: function (target, property, receiver) {
  237. var ret = target[property];
  238. if (key === "default_all") {
  239. console.hooks.rawlog(
  240. `${console.hooks.settings.prefix}Hook Proxy value get`,
  241. `${obj_name}.${property}`,
  242. "value->",
  243. ret
  244. );
  245. console.hooks.debugger();
  246. }
  247. if (property == key && key != "default_all") {
  248. console.hooks.rawlog(
  249. `${console.hooks.settings.prefix}Hook Proxy value get`,
  250. `${obj_name}.${property}`,
  251. "value->",
  252. ret
  253. );
  254. console.hooks.debugger();
  255. }
  256. return target[property];
  257. },
  258. set: function (target, property, newValue, receiver) {
  259. var ret = target[property];
  260. if (key === "default_all") {
  261. console.hooks.rawlog(
  262. `${console.hooks.settings.prefix}Hook Proxy value set`,
  263. `${obj_name}.${property}`,
  264. "value->",
  265. ret,
  266. "newvalue->",
  267. newValue
  268. );
  269. console.hooks.debugger();
  270. }
  271. if (property == key && key != "default_all") {
  272. console.hooks.rawlog(
  273. `${console.hooks.settings.prefix}Hook Proxy value get`,
  274. `${obj_name}.${property}`,
  275. "value->",
  276. ret,
  277. "newvalue->",
  278. newValue
  279. );
  280. console.hooks.debugger();
  281. }
  282. target[property] = newValue;
  283. return true;
  284. },
  285. });
  286. },
  287.  
  288. hookValueViaObject: function (name, obj, key) {
  289. var obj_desc = Object.getOwnPropertyDescriptor(obj, key);
  290. if (!obj_desc || !obj_desc.configurable || obj[key] === undefined) {
  291. return Error("No Priv to set Property or No such keys!");
  292. }
  293. var obj_name = "OBJ_" + name;
  294. this.hooked[obj_name] = obj[key];
  295. Object.defineProperty(obj, key, {
  296. configurable: true,
  297. get() {
  298. console.hooks.rawlog(
  299. `${console.hooks.settings.prefix}Hook Object value get`,
  300. `${obj_name}.${key}`,
  301. "value->",
  302. console.hooks.hooked[obj_name]
  303. );
  304. console.hooks.debugger();
  305. return console.hooks.hooked[obj_name];
  306. },
  307. set(v) {
  308. console.hooks.rawlog(
  309. `${console.hooks.settings.prefix}Hook Proxy value get`,
  310. `${obj_name}.${key}`,
  311. "value->",
  312. console.hooks.hooked[obj_name],
  313. "newvalue->",
  314. v
  315. );
  316. console.hooks.hooked[obj_name] = v;
  317. },
  318. });
  319. },
  320.  
  321. hookEvents: function (params) {
  322. var placeToReplace;
  323. if (window.EventTarget && EventTarget.prototype.addEventListener) {
  324. placeToReplace = EventTarget;
  325. } else {
  326. placeToReplace = Element;
  327. }
  328. this.hookfunc(
  329. placeToReplace.prototype,
  330. "addEventListener",
  331. function (res) {
  332. let [ret, originalFunction, arguments] = res;
  333. console.hooks.rawlog(
  334. `${console.hooks.settings.prefix}Hook event listener added!`,
  335. arguments
  336. );
  337. }
  338. );
  339. },
  340.  
  341. antiDebuggerLoops: function () {
  342. processDebugger = (type, res) => {
  343. let [originalFunction, arguments, t] = res;
  344. var handler = arguments[0];
  345. console.hooks.debugger();
  346. if (handler.toString().includes("debugger")) {
  347. console.hooks.log(
  348. `${console.hooks.settings.prefix}found debug loop in ${type}`
  349. );
  350. console.hooks.debugger();
  351. let func = handler.toString().replaceAll("debugger", "");
  352. arguments[0] = new Function("return " + func)();
  353. return arguments;
  354. } else {
  355. return arguments;
  356. }
  357. };
  358.  
  359. this.hookfunc(
  360. window,
  361. "setInterval",
  362. () => {},
  363. (res) => {
  364. return processDebugger("setInterval", res);
  365. }
  366. );
  367. this.hookfunc(
  368. window,
  369. "setTimeout",
  370. () => {},
  371. (res) => {
  372. return processDebugger("setTimeout", res);
  373. }
  374. );
  375.  
  376. this.hookfunc(Function.prototype, "constructor", (res) => {
  377. let [ret, originalFunction, arguments, env] = res;
  378. if (ret.toString().includes("debugger")) {
  379. console.hooks.log(
  380. `${console.hooks.settings.prefix}found debug loop in Function constructor`
  381. );
  382. console.hooks.debugger();
  383. let func = ret.toString().replaceAll("debugger", "");
  384. return new Function("return " + func)();
  385. }
  386. return ret;
  387. });
  388. },
  389.  
  390. init: function () {
  391. if (this.settings.blockPageJump) {
  392. window.onbeforeunload = function () {
  393. return "ANTI LEAVE";
  394. };
  395. }
  396. if (this.settings.checkEventListnerAdded) {
  397. this.hookEvents();
  398. }
  399. if (this.settings.checkCookieChange) {
  400. this.hookCookie();
  401. }
  402. if (this.settings.checkLocalStorageGetSet) {
  403. this.hookLocalStorage();
  404. }
  405. if (this.settings.antiDeadLoopDebugger) {
  406. this.antiDebuggerLoops();
  407. }
  408. },
  409.  
  410. main: function () {
  411. this.hookfunc(window, "eval");
  412. this.hookfunc(window, "Function");
  413. this.hookfunc(window, "atob");
  414. this.hookfunc(window, "btoa");
  415. this.hookfunc(window, "fetch");
  416. this.hookfunc(window, "encodeURI");
  417. this.hookfunc(window, "encodeURIComponent");
  418.  
  419. this.hookfunc(JSON, "parse");
  420. this.hookfunc(JSON, "stringify");
  421.  
  422. this.hookfunc(console, "log");
  423. // this.hookfunc(console, "warn")
  424. // this.hookfunc(console, "error")
  425. // this.hookfunc(console, "info")
  426. // this.hookfunc(console, "debug")
  427. // this.hookfunc(console, "table")
  428. // this.hookfunc(console, "trace")
  429. this.hookfunc(console, "clear");
  430. },
  431. };
  432.  
  433. // auto run init
  434. console.hooks.init();
  435. })();