1

I'm trying to override Object() calls in JavaScript, in order to intercept and save all the parameters passed to the object constructor.

I don't have any access to the original code since I am running from an injected code but I do run from the same scope and share the same window of the original code.

I tried this approach:

(function (nativeObject) {
    window.Object = function (value) {
        if (value.magic) {
            window.myMagic = value.magic;
        }
        return nativeObject(value);
    }
})(Object);

as well as saving the original window.Object on window.nativeObject and calling it from within my hook, but in both ways I end up getting:

TypeError: Object.defineProperty is not a function
TypeError: Object.keys is not a function
Uncaught (in promise) TypeError: Object.isExtensible is not a function
Uncaught (in promise) TypeError: Object.create is not a function

Is it because my window.myMagic calls the the Object methods to set the myMagic key in the window object?

Is what I'm trying to do possible?

5
  • 1
    In what code do you need to intercept Object calls? That sounds like a really bad idea. Commented Dec 26, 2021 at 21:40
  • @Bergi I'm trying to get statistics about data being transferred in a certain web client (and don't have the access to the code). I want to set hooks on whatever built in functions I can, like XMLHttpRequest, Object, etc - and do some analytics based on it. Is there a smarter way to do this? Commented Dec 26, 2021 at 21:46
  • Transferred from where to where? But no, intercepting Object calls is unlikely to be effective, since most objects are constructed through other means. Commented Dec 26, 2021 at 22:05
  • @Bergi And is there any way to hook and intercept object assignments like myObject.key = ...? Commented Dec 26, 2021 at 22:19
  • It's possible with getters (and, if you don't know the key name, with proxies), but for both you must have control over myObject and it only works with assignments. Still not sure what your goal (or even concrete problem) is, so I can't give practical advice. Commented Dec 26, 2021 at 22:34

2 Answers 2

1

I'm going to show how to replace the Object constructor with a proxy: we need to implement both the apply and construct traps for invocations of Object without or with new.

(nativeObject => {
    function Object(value) {
        if (value.magic) {
            globalThis.myMagic = value.magic;
        }
        return nativeObject(value);
    }
    globalThis.Object = new Proxy(nativeObject, {
        apply: (target, thisArg, args) => Object(...args),
        construct: (target, args) => Object(...args)
    });
})(Object);

// Test
new Object({ magic: 42 });
console.log(myMagic); // prints 42
Object({ magic: 'foo' });
console.log(myMagic); // prints "foo"
console.log(Object.getOwnPropertyNames(Object)); // prints an array of property names

Just note that this method will not work with any predefined functions, which may require different treatments for apply and construct. The Object function is a special case in that it behaves in the same way with or without new.

Sign up to request clarification or add additional context in comments.

12 Comments

Can I use the same approach to proxy and hook function calls?
@amiregelz Sort of. It would take a couple of changes to make it work. Do you have a particluar example in mind?
Yes :) I want to detect when a specific function is being called by intercepting all function calls and looking at the called function signature and its string representation.
@amiregelz The difficult part is not creating the proxy, but replacing the original function, and this can be done only when the the function to be intercepted is accessible at the time of proxying.
Got it. So it's not possible to proxy the Function built-in method/constructor to intercept all functions simultaneously?
|
1

You are replacing Object with a function that doesn't have any of the expected static methods on it. Calling Object.defineProperties no longer works, it's nativeObject.defineProperties that would be required.

You can however easily copy those properties from the native function onto your replacement function, to avoid breaking code that relies on them:

(function (nativeObject) {
    window.Object = function (value) {
        if (value.magic) {
            window.myMagic = value.magic;
        }
        return nativeObject(value);
    }
    for (const key of Reflect.ownKeys(nativeObject)) { // names and symbols
        const descriptor = nativeObject.getOwnPropertyDescriptor(nativeObject, key);
        nativeObject.defineProperty(Object, key, descriptor);
    }
})(Object);

4 Comments

I'm getting nativeObject.defineOwnProperty is not a function. Also, looking at Reflect and Proxy got me thinking, is there a better or easier to create a proxy like that?
@amiregelz Ooops, now updated with tested code :-) No, a Proxy won't really help here.
How does this solution differ from GOTO 0's?
@amiregelz Apart from the obvious (not using an unnecessary proxy), the approach also works in an ES5 environment (ok, you'll have to use Object.getOwnPropertyNames instead of Reflect.ownKeys of course). Is there something specific you want to know about?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.