Probably a good place to ask a specific question about debugging here.
A few years ago, I was hacking a web bookreader.
It has a function that is used to decode images (they're encrypted in some way) into canvas, and I want to find it so I can call it directly in my user script to batch download decoded images.
So I monkey patched `CanvasRenderingContext2D` function, added breakpoint, and found where the the function is defined in the 100k lines of obfuscated JS source code, easily.
The problem is.. once the page is rendered, the function would be nested in some objects, something like `window.abd.fdsfsd.r2323.fsdfs.fasf.xyy.myfunc`.
I don't know how exactly I can find the full "path" of the function so I can call it, despite I'm literally pausing inside of it. I eventually got it done, but it was manual and painful.
So I'm wandering: is there a better way to do it? The browser obviously knows it, it just lacks of a way to tell.
The browser does not know the path. Also, if the function (or one of its parents) is in a closure, there may not even be a path to the function from window.
If you're sure the function is reachable from window you can search for it recursively:
(function () {
function search(prefix, obj, fn, seen = null) {
if (!seen) seen = new Set();
// Prevent cycles.
if (seen.has(obj)) return false;
seen.add(obj);
console.log('Looking in ' + prefix);
for (let key of Object.keys(obj)) {
let child = obj[key];
if (child === null || child === undefined) {
} else if (child === fn) {
console.log('Found it! ' + prefix + '.' + key);
return prefix + '.' + key;
} else if (typeof child === 'object') {
// Search this child.
let res = search(prefix + '.' + key, child, fn, seen);
if (res) {
return res;
}
}
}
return false;
}
// For example:
let fn = function() { alert('hi'); }
window.a = {};
window.a.b = {};
window.a.b.c = {};
window.a.b.c.f = fn;
return search('window', window, fn);
})();
The idea is that you use a breakpoint somewhere where you have a reference to the function to see it then paste the search() function in the debugger console and call it to find it in window
A tree overview of all nested functions and objects with a search function that quickly jumps to that place, and maybe even let you call that function with data from state?
Have you tried accessing `arguments.callee`[0]? It is unfortunately deprecated and might throw an error. I've never tried it myself as I rarely use breakpoints in the debugger.
Do you want to have this in Tampermonkey script ONLY or not necessarily? You can use ResourceOverride addon to simply replace the 100k script with your own script that is almost the same but also assigns the function you need to window.myFn or something. There it can just be picked up by TM.
Thanks for the suggestion, but the goal is to just use this function in my own code (which has lots of other things going on).
I guess it technically can be done by modifying the existing JS in-place, but doing so with a very large, minified JS would be a nightmare in term of maintenance.
To parent off of GP, I've run into this recently while working on some webextension code and I'm thinking my solution is going to be to monkey-patch the script, but merely to expose a reference to the object/function in question.
So TLDR don't monkey-patch a giant minified source file with a bunch of your own code. Monkey-patch the function just enough to get it to be exposed globally with its context, and then have your code separately reference it.
This is still fragile (unless you have a stable entry point with regex or something, which is not completely certain to exist, it'll likely break whenever the script changes), and is still not ideal, and I'm still thinking a bit to see if I can do anything better, but I suspect it's more stable than trying to access the function directly by coding the path and should be a great deal simpler as well since it will work even if the function/context is in a closure.
----
Of course, you might be lucky and there might actually be a way to get at the function. For example, I am separately looking into seeing if I can figure out a clean way to reliably look for imports exposed through a webpack bundle, since those are exposed globally and if you can find the paths reliably you should be able to get access to any of the imports (although you still won't have access to the closures). I haven't made much progress on it though, mostly because it's kind of frustrating to work on.
----
There is also the possibility (although I suspect it would get very messy very quickly, and I'm not sure of current browser support) that you could theoretically maybe rig something together with `function.caller` (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...), possibly patching the minified source file merely to remove "use strict".
I have not messed with `caller` in probably close to a decade at this point, so I make no promises at to whether it still works at all :) but... in its heyday before we realized how wildly insecure it was, it did allow reconstructing the stack from a function in-code in some situations.
A few years ago, I was hacking a web bookreader.
It has a function that is used to decode images (they're encrypted in some way) into canvas, and I want to find it so I can call it directly in my user script to batch download decoded images.
So I monkey patched `CanvasRenderingContext2D` function, added breakpoint, and found where the the function is defined in the 100k lines of obfuscated JS source code, easily.
The problem is.. once the page is rendered, the function would be nested in some objects, something like `window.abd.fdsfsd.r2323.fsdfs.fasf.xyy.myfunc`.
I don't know how exactly I can find the full "path" of the function so I can call it, despite I'm literally pausing inside of it. I eventually got it done, but it was manual and painful.
So I'm wandering: is there a better way to do it? The browser obviously knows it, it just lacks of a way to tell.