Skip to content

Instantly share code, notes, and snippets.

@fuzmish
Last active February 5, 2024 04:26
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fuzmish/bd444b1aadc2d22aada7c9b1a6de56ba to your computer and use it in GitHub Desktop.
Save fuzmish/bd444b1aadc2d22aada7c9b1a6de56ba to your computer and use it in GitHub Desktop.

Inject addEventListener hook

With (Tamper|Violent|Grease)monkey, you can run any JavaScript code on any web pages. This allows you to rewrite the content and style of web pages and override their behaviors. However, manipulating the event listeners is a bit more difficult. In particular, to disable or delete a registered event listener, you must have a reference to the event listener function object, which is usually not available. Chrome DevTools (or similar browser developer functionalities) can do this, but in any case it is not available from Tampermonkey.

This code snippet will help you to remove event listeners by inserting a hook into EventTarget.proptotype.addEventListener, the standard method for registering event listeners, and logging all calls to it. For example, to remove all click events, you can use the following code:

//...
(function() {
    'use strict';
    window.addEventListener('load', () => {
      // remove all click event listeners
      for (const eventTarget in eventListeners) {
        if ('click' in eventListeners[eventTarget]) {
          for (const args of eventListeners[eventTarget]['click']) {
            eventTarget.removeEventListener('click', ...args)
          }
        }
      }
    })
    injectAddEventListenerHook(/^click$/)
})()

The key of the eventListeners object is EventTarget; i.e. such as Element. You can remove the event listeners for specific HTML elements as follows:

const eventTarget = document.querySelector('a.special-button')
if (eventTarget in eventListeners && 'click' in eventListeners[eventTarget]) {
  for (const args of eventListeners[eventTarget]['click']) {
    eventTarget.removeEventListener('click', ...args)
  }
}

This hack can easily be defeated by caching the original EventTarget.prototype.addEventListener function in the web page's own script. However, I have never found a web page that does so.

// ==UserScript==
// @name Inject addEventListener hook (example)
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author You
// @match *://*/*
// @icon https://www.google.com/s2/favicons?domain=gist.github.com
// @grant none
// ==/UserScript==
const eventListeners = {}
const rawAddEventListener = EventTarget.prototype.addEventListener
function injectAddEventListenerHook(eventFilter = /.*/) {
EventTarget.prototype.addEventListener = function (...args) {
//console.log('hook addEventListener', ...args)
const eventTarget = this
const eventName = args[0]
if (!eventFilter || eventFilter.test(eventName)) {
if (!(eventTarget in eventListeners)) {
eventListeners[eventTarget] = {}
}
if (!(eventName in eventListeners[eventTarget])) {
eventListeners[eventTarget][eventName] = []
}
eventListeners[eventTarget][eventName].push(args.slice(1))
}
return rawAddEventListener.apply(this, args)
}
}
(function() {
'use strict';
// for example
window.addEventListener('load', () => {
console.log('stored event listeners', eventListeners)
})
injectAddEventListenerHook()
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment