0
\$\begingroup\$

I want to override the console.log function in order to save the data other scripts log. My script executes before any other script, so I have full control over the environment. This is my current function for overwriting console.log:

+function(){
    var a = Function.prototype, b = 'toString', c = a[b], d = c.apply(c).split(c.name), e = [], f = [], g = function(a, b){
        e.push(a);
        f.push(b);
        return a;
    }, _ = [];

    a[b] = function(h){
        return g(function toString(){
            var i = e.indexOf(this);
            return i != -1 ? f[i] || d.join(this.name) : h.apply(this);
        });
    }(c);

    console.log = function(a){
        return g(function log(){
            var b = [], i;
            for(i in arguments) b.push(arguments[i]);
                _.push(b.slice());
            return a.apply(this, arguments);
        });
    }(console.log);
}();

My question is simple: is it possible that some script executed after this can reveal that I have an overwritten console.log function?

I will use it for debugging scripts sent from users to my Node.js server application. I am using vm module, so I need to overwrite sandbox the object's console.log function in order to trace what users log to console in received scripts.

If this code looks obfuscated, here is a better version.

\$\endgroup\$
17
  • \$\begingroup\$ I don't like where you're going with this; you seem to be hacking around something that could be easily done via a decorator and I can't help but wonder just what you're using this for. \$\endgroup\$
    – Pimgd
    Aug 11, 2016 at 22:46
  • \$\begingroup\$ Also, yes, the debugger is able to get at the scopes \$\endgroup\$
    – Pimgd
    Aug 11, 2016 at 22:55
  • \$\begingroup\$ @Pimgd. The biggest problem of Stack Exchange sites is, I think, that users mostly vote questions by their assumption where OP will use answer. This is totaly, wrong, you cannot vote question because you assume I will use it for hacking. The real purpose I am looking for answer is because I want to execute scripts sent from users in my Node.js server application, but I want to find what they log to console in each script, nothing more than that. \$\endgroup\$
    – user114831
    Aug 11, 2016 at 22:58
  • \$\begingroup\$ @Pimgd. Also, debugger is not the problem, because other scripts cannot use debugger, it is available manually. \$\endgroup\$
    – user114831
    Aug 11, 2016 at 23:00
  • \$\begingroup\$ @Pimgd. Why it is so important where I will use it? Is it illegal to overwrite local browser function using available methods provided by Javascript? Oh, sorry, if it is illegal, I think someone should put me in a jail. You car report me to FBI saying "Hey, he has overwriten console.log function, arrest him immediately". \$\endgroup\$
    – user114831
    Aug 11, 2016 at 23:08

3 Answers 3

2
\$\begingroup\$

At first sight, this is really clever, because inspecting console.log will still show log() { [native code] }

But then, what is this property prototype that is not present in the original console.log?

Even more interesting, in Chrome Canary, console.log.prototype.constructor will show the location of the implementation, which is clearly in user space:

Object
  constructor:log()
    arguments:null
    caller:null
    length:0
    name:"log"
    prototype:Object
    __proto__:()
    [[FunctionLocation]]:VM1191:16
    [[Scopes]]:Scopes[3]
  __proto__:Object

In node.js, the constructor just behaves weirdly and is indicative of weird things going on.

Furthermore, since this is codereview, the commonly accepted practice for immediately self executing is

(function functionName(arguments){ 
})();

That + is super hokey, and will be used in future codegolfing entries ;)

\$\endgroup\$
1
  • \$\begingroup\$ Very nicely spotted. \$\endgroup\$
    – Pimgd
    Aug 12, 2016 at 15:15
2
\$\begingroup\$

I tried hacking around this in various ways and practically the only way I could detect it was wrapped was by having an old reference to console.log and using ===. Since you state your code will run before any other scripts will run, this shouldn't be a problem.

That said, there's also console.info, warn, trace, so maybe you'd want to wrap those too?

From a code quality perspective, your variable naming needs work. You can haul it through a minifier later; what you have right now is unmaintainable. I don't even know what half of it does thanks to the variable naming.

\$\endgroup\$
1
\$\begingroup\$

Because my original code looks very obfuscated and this article says that OP is not allowed to edit code after accepting an answer, I am writing here beautified and easy-to-understand code:

+function(){
    var FunctionPrototype = Function.prototype;
    var toStr = 'toString';
    var originalFunc = FunctionPrototype[toStr];
    var namePattern = originalFunc.apply(originalFunc).split(originalFunc.name);
    var overwritenFuncs = [];
    var overwritenFuncsNames = [];
    var overwrite = function(originalFunction, overridenToStr){
        overwritenFuncs.push(originalFunction);
        overwritenFuncsNames.push(overridenToStr);
        return originalFunction;
    };
    var tracedLogs = [];

    FunctionPrototype[toStr] = function(h){
        return overwrite(function toString(){
            var i = overwritenFuncs.indexOf(this);
            return i != -1 ? overwritenFuncsNames[i] || namePattern.join(this.name) : h.apply(this);
        });
    }(originalFunc);

    console.log = function(originalConsoleLog){
        return overwrite(function log(){
            var b = [], i;
            for(i in arguments) b.push(arguments[i]);
            tracedLogs.push(b.slice());
            return originalConsoleLog.apply(this, arguments);
        });
    }(console.log);
}();
\$\endgroup\$
1
  • \$\begingroup\$ It's great that you added a non-minified version, but as an answer, it won't get reviewed. Are you okay with that? \$\endgroup\$
    – Pimgd
    Aug 12, 2016 at 7:49

Your Answer

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