您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
用于快速定位使用jQuery绑定到DOM元素上的事件的代码的真实位置,辅助逆向分析。
当前为
// ==UserScript== // @name jQuery Hook // @namespace https://github.com/CC11001100/jQuery-hook // @version 0.3 // @description 用于快速定位使用jQuery绑定到DOM元素上的事件的代码的真实位置,辅助逆向分析。 // @document https://github.com/CC11001100/jQuery-hook // @author CC11001100 // @match *://*/* // @run-at document-start // @grant none // ==/UserScript== (() => { // 尽量唯一有区分度即可 const globalUniqPrefix = "cc11001100"; // 在第一次设置jquery的时候添加Hook,jQuery初始化的时候会添加一个名为$的全局变量 Object.defineProperty(window, "$", { set: $ => { // 为jquery的各种方法添加Hook try { addHook($); } catch (e) { console.error("为jQuery添加Hook时报错: " + e) } // 删除set描述符拦截,恢复正常赋值 delete window["$"]; window["$"] = $; }, configurable: true }); /** * 为jquery添加一些hook,等会儿使用jquery为dom元素绑定事件的话就会被捕获到 * @param $ */ function addHook($) { if (!$["fn"]) { console.log("当前页面虽然声明了$变量,但并不是jQuery,因此忽略。"); return; } // 一些比较通用的事件的拦截 const eventNameList = [ "click", "dblclick", "blur", "change", "contextmenu", "error", "focus", "focusin", "focusout", "hover", "holdReady", "proxy", "ready", "keydown", "keypress", "keyup", "live", "load", "mousedown", "mouseenter", "mouseleave", "mousemove", "mouseout", "mouseover", "mouseup" ]; for (let eventName of eventNameList) { const old = $.fn[eventName]; $.fn[eventName] = function () { try { setEventFunctionNameToDomObjectAttribute(this, eventName, arguments[0]); } catch (e) { console.error(`为jQuery添加${eventName}类型的事件的Hook时发生错误: ${e}`); } return old.apply(this, arguments); } } // on,不仅是内置事件类型,还有可能有一些自定义的事件类型 // https://api.jquery.com/on/ const fnOnHolder = $.fn.on; $.fn.on = function () { try { const eventName = arguments[0]; let eventFunction = undefined; for (let x of arguments) { if (x instanceof Function) { eventFunction = x; break; } } if (eventFunction instanceof Function) { setEventFunctionNameToDomObjectAttribute(this, eventName, eventFunction); } } catch (e) { console.error(`为jQuery添加on方法的Hook时发生错误: ${e}`); } return fnOnHolder.apply(this, arguments); } // TODO 还有delegate之类的比较隐晦的绑定事件的方式 console.log(`当前页面使用了jQuery,jQuery Hook已初始化完毕。`); } const addressIdGeneratorMap = {}; /** * 生成一个全局唯一的标识 * @param eventName */ function globalUnique(eventName) { const id = (addressIdGeneratorMap[eventName] || 0) + 1; addressIdGeneratorMap[eventName] = id; return `${globalUniqPrefix}_${eventName}_${id}`; } /** * 为绑定了jquery事件的dom元素添加元素,提示所绑定的事件与对应的函数代码的全局变量的名称,只需要复制粘贴跟进去即可 * 注意,有可能会为同一个元素重复绑定相同的事件 * * @param domObject * @param eventName * @param eventFunction */ function setEventFunctionNameToDomObjectAttribute(domObject, eventName, eventFunction) { // TODO bug fix 注意,事件名可能会包含一些非法的字符 // cc11001100-jquery-$destroy-event-function eventName = safeSymbol(eventName); const eventFunctionGlobalName = globalUnique(eventName); window[eventFunctionGlobalName] = eventFunction; const attrName = `${globalUniqPrefix}-jQuery-${eventName}-event-function`; if (domObject.attr(attrName)) { domObject.attr(attrName + "-" + new Date().getTime(), eventFunctionGlobalName); } else { domObject.attr(attrName, eventFunctionGlobalName); } } /*** * * @param name */ function safeSymbol(name) { const replaceMap = { ".": "_dot_", "$": "_dollar_", "-": "_dash_" }; for (let key of Object.getOwnPropertyNames(replaceMap)) { name = name.replace(key, replaceMap[key]); } return name; } })();