How can I mimic Greasemonkey/Firefox's unsafeWindow functionality in Chrome?
Asked Answered
T

6

7

I'm just fiddling around with user scripts in chrome right now, so please bear with my potential ignorance/idiocy.

In the page I'm writing a script for, there is a <script> element that declares a variable x. Does this mean that, in my user script, I can just access x from the global namespace?

For example, if the only line in my userscript is alert(x);, should that work as expected (assuming x is a String)? I understand chrome doesn't support unsafewindow, but for some reason I'm finding it impossible to figure out how to mimic the functionality. Is it even possible?

Trickery answered 25/10, 2009 at 21:32 Comment(0)
C
9

contentWindow was available in Chrome 3, but removed in Chrome 4. Only possible solution for Chrome 4:

location.href="javascript:(function(){ alert('Hello'); })()"
Crier answered 28/10, 2009 at 17:37 Comment(0)
F
13

This will give you a reference to the window object (as p):

var p = unsafeWindow;

if(window.navigator.vendor.match(/Google/)) {
    var div = document.createElement("div");
    div.setAttribute("onclick", "return window;");
    p = div.onclick();
};
Francis answered 20/1, 2011 at 18:34 Comment(2)
There’s no need for “vendor sniffing”, you could just do something like this: gist.github.com/1143845Sesterce
This doesn't seem to work any more in the latest version of Chrome.Adverbial
E
11

Update:
The onclick exploit no longer works in the latest Chrome releases.

To get unsafeWindow functionality in Chrome, your best bet is to install and use Tampermonkey -- which you would be smart to do, regardless. Tampermonkey has full support for the Greasemonkey API and much easier script management.

Greasemonkey scripts and Tampermonkey scripts are almost always fully compatible, something that's not true for plain Chrome userscripts.

Forgoing Tampermonkey, the only alternative that still works is to use some form of script injection.



The following is now obsolete:

Chrome now defines unsafeWindow for userscripts / content-scripts, but Chrome's unsafeWindow still does not allow access to JS objects created by the target page.

Here's how to provide a properly unsafe, unsafeWindow -- in a cross-browser way that uses Feature Detection (good) versus Browser Sniffing (Bad):

/*--- Create a proper unsafeWindow object on browsers where it doesn't exist
    (Chrome, mainly).
    Chrome now defines unsafeWindow, but does not give it the same access to
    a page's javascript that a properly unsafe, unsafeWindow has.
    This code remedies that.
*/
var bGreasemonkeyServiceDefined     = false;

try {
    if (typeof Components.interfaces.gmIGreasemonkeyService === "object") {
        bGreasemonkeyServiceDefined = true;
    }
}
catch (err) {
    //Ignore.
}

if ( typeof unsafeWindow === "undefined"  ||  ! bGreasemonkeyServiceDefined) {
    unsafeWindow    = ( function () {
        var dummyElem   = document.createElement('p');
        dummyElem.setAttribute ('onclick', 'return window;');
        return dummyElem.onclick ();
    } ) ();
}
Europium answered 8/6, 2012 at 8:5 Comment(4)
does this still work? i tried it out in chrome in order to override the XHR send, but it doesn't seem to do anything. i just added: var oldSend = unsafeWindow.XMLHttpRequest.prototype.send; unsafeWindow.XMLHttpRequest.prototype.send = function(){ console.log("notified of XHR update"); oldSend.apply(this, arguments); } but I get no output during the requests. this code does produce output if I inject it into the page.Ringmaster
@Mix, Yes, I just verified that it still works on Chrome version 18 and version 19 (19.0.1084.56 m). Open a new question for your issue.Europium
@user280109, Yeah, Chrome fixed that exploit. You should install and use Tampermonkey anyway. Otherwise you'll have to use script injection.Europium
ViolentMonkey is also an option in chrome, and is open source, so I'd rather recommend that than TamperMonkey. The depth of the answer is much appreciated, though! I'd been trying to figure it out for a long time.Haler
C
9

contentWindow was available in Chrome 3, but removed in Chrome 4. Only possible solution for Chrome 4:

location.href="javascript:(function(){ alert('Hello'); })()"
Crier answered 28/10, 2009 at 17:37 Comment(0)
H
1

If you want to interact with page JavaScript, you will have to insert a script into a page. (Unless you want to use any of the hacks suggested at this page, of course.) I have cooked up a function to do just that for my own scripts, I will post it here in case anyone wants to use it.

/*
    @description    This function will insert the given code as a <script> or <style> block into a page.
    @param The code to insert; supported types are: JavaScript Function, String (JavaScript), String (CSS).
    @param2 Optional: The type of code that is inserted. If omitted, "js" is assumed. Possible values are 'js' or 'css'.
    @return The HTML element that was inserted, or FALSE on failure
*/
function insert(z,t){
    var j,f,x,c,i,n,d
    d=document
    c=d.createElement
    i=d.head.appendChild
    a=d.createTextNode
    if(typeof z==='function') j=!0,f=!0;
    if((t=='js'||!t)&&!f){j=!0,f=!1}
    if(t=='css'&&!j){x=c('style');x.setAttribute('type','text/css')}
    if(j){x=c('script');x.setAttribute('type','text/javascript')}
    if(f) n=a('('+z+')()');else n=a(z)
    x.appendChild(n)

    if(x){return i(x)}else{return !1}
}

A few examples to clarify:

//Inserting a JavaScript function
var func=function(){
    stopAds();
    startFileDownload();
}

insert(func);


//Inserting JavaScript as a string
var strJS="prompt(\"Copy:\",someVariableAtThePage);";

insert(strJS);
//Or with an OPTIONAL 2nd parameter:
insert(strJS,'js');


//Inserting CSS
var strCSS=".ad{display:none !important}    #downloadButton{display:block}";

insert(strCSS,'css');//Specifying 2nd parameter as "css" is required.
Hamlen answered 29/12, 2011 at 14:38 Comment(0)
W
0

ok heres an idea you can inject the script using the address bar...

javascript:var ElEm = document.createElement("script");ElEm.src='[path_to_script]';document.body.appendChild(ElEm);

then you can run whatever you want in the window with your javascript

Waxbill answered 29/10, 2009 at 20:32 Comment(1)
oh and if the variable is global for the page you should be able to read it with your javascriptWaxbill
A
0

The script in @Johan's answer is very cool and useful. But I needed it and wanted to see it deobfuscated.

For those who would like to see it or use it in a readable format, as I did, here it goes. It's the same function, just with a little refactoring for clarity. This may be useful for quicker understanding or even for forking:

function insert(code, tipo) {
    let isJS, isFunc, x, n;
    if (typeof code === "function") {
        isJS = true;
        isFunc = true;
    }
    if ((tipo === "js" || !tipo) && !isFunc) {
        isJS = true;
        isFunc = false;
    }
    if (tipo === "css" && !isJS) {
        x = document.createElement("style");
        x.setAttribute("type", "text/css");
    }
    if (isJS) {
        x = document.createElement("script");
        x.setAttribute("type", "text/javascript");
    }
    if (isFunc) n = document.createTextNode("(" + code + ")()");
    else n = document.createTextNode(code);
    x.appendChild(n);

    if (x) {
        return document.head.appendChild(x);
    } else {
        return false;
    }
}

Arin answered 7/5 at 21:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.