3

I'm trying to modify a function:

console.error = function() {
  return "fake";
}

However, it is possible to detect the function was changed by just running toString() on it:

> console.error.toString()
'function() {\nreturn "fake";\n}'

If the function hadn't been modified, 'function () { [native code] }' would be returned instead.

A solution can be to override toString(), however, it is possible to see that toString has been overriden by running toString on it:

> console.error.toString = () => 'function () { [native code] }';
> console.error.toString()
'function () { [native code] }'
> console.error.toString.toString()
"() => 'function () { [ native code ] }'"

Is there anyway to recursively override toString() or any other method such that it is not possible to detect the function was overriden?

The use case would be for a WebExtension to modify some functions while making it as hard as possible for a website to detect it.

2
  • 3
    I think your only bet here is to override the default Function proptotype function (Function.prototype.toString). But why are you trying to do this at all?
    – M0nst3R
    Commented May 4, 2021 at 22:11
  • 3
    Sounds like an XY problem. What are you trying to do?
    – VLAZ
    Commented May 4, 2021 at 22:12

2 Answers 2

5

You can overwrite Function.prototype.toString itself. However, it might still be possible for other code to circumvent this - easiest by taking a reference to the method before you've overwritten it, rather intricate by restoring a version from a different realm.

{
    const Console = console.constructor;
    const origToString = Function.prototype.toString;
    const origError = Console.prototype.error;
    const {error} = {error() { return "fake"; }};
    const {toString} = {toString() {
        let target = this;
        if (this == toString) target = origToString;
        if (this == error) target = origError;
        return origToString.call(target);
    }};
    Function.prototype.toString = toString;
    Console.prototype.error = error;
}
5
  • Even if you override Function.prototype.toString you would realize this was a fake if you'd run it on something like (() => {}).toString() as there's no native code involved there.
    – MinusFour
    Commented May 4, 2021 at 22:15
  • 2
    @MinusFour Of course I wouldn't override it with something that simply constantly returns function () { [native code] } :-) See also the code I added to the answer
    – Bergi
    Commented May 4, 2021 at 22:20
  • Got me thinking real hard on that one but it's still possible to detect if it's a fake. You could do new Function.prototype.toString() and it would give you a different error. But I think it's safe to assume that's something really far-fetched to try out.
    – MinusFour
    Commented May 4, 2021 at 23:01
  • 1
    @MinusFour Good call. One could detect that using new.target, or better just properly create a (non-constructible) method - see edit
    – Bergi
    Commented May 4, 2021 at 23:09
  • Well that covers all of it. Ultimately, if I really feel code had been supplanted, I would have used the debugger. But no further checks through javascript that I could think of.
    – MinusFour
    Commented May 4, 2021 at 23:22
2

Is there any way override a function such that it is not possible to detect the function was overriden?

I think the answer here is "no". Your best bet is to use a Proxy, but there will always be some way to detect that the code was monkey-patched.

The real "solution" would be to change the runtime to prevent the program from knowing it had been patched.

It really depends what you're doing and to what lengths the other party will go to in order to detect whether the code was modified. There's probably a term for this (does anyone know?), but I'll call this adversarial programming until someone proposes a more correct term.

Not the answer you're looking for? Browse other questions tagged or ask your own question.