Oprócz redefiniowania console._commandLineAPI
, istnieją inne sposoby włamania się do InjectedScriptHost w przeglądarkach WebKit, aby zapobiec lub zmienić ocenę wyrażeń wprowadzonych do konsoli programisty.
Edytować:
Chrome naprawił to w poprzedniej wersji. - które musiały być przed lutym 2015 r., ponieważ wtedy stworzyłem sedno
Oto kolejna możliwość. Tym razem w hak, poziom wyżej, bezpośrednio InjectedScript
zamiast InjectedScriptHost
w przeciwieństwie do wcześniejszej wersji.
Co jest całkiem miłe, ponieważ możesz bezpośrednio małpować łatkę InjectedScript._evaluateAndWrap
zamiast polegać na niej, InjectedScriptHost.evaluate
ponieważ daje to bardziej szczegółową kontrolę nad tym, co powinno się stać.
Inną dość interesującą rzeczą jest to, że możemy przechwycić wynik wewnętrzny podczas oceny wyrażenia i zwrócić go użytkownikowi zamiast normalnego zachowania.
Oto kod, który właśnie to robi, zwraca wynik wewnętrzny, gdy użytkownik ocenia coś w konsoli.
var is;
Object.defineProperty(Object.prototype,"_lastResult",{
get:function(){
return this._lR;
},
set:function(v){
if (typeof this._commandLineAPIImpl=="object") is=this;
this._lR=v;
}
});
setTimeout(function(){
var ev=is._evaluateAndWrap;
is._evaluateAndWrap=function(){
var res=ev.apply(is,arguments);
console.log();
if (arguments[2]==="completion") {
//This is the path you end up when a user types in the console and autocompletion get's evaluated
//Chrome expects a wrapped result to be returned from evaluateAndWrap.
//You can use `ev` to generate an object yourself.
//In case of the autocompletion chrome exptects an wrapped object with the properties that can be autocompleted. e.g.;
//{iGetAutoCompleted: true}
//You would then go and return that object wrapped, like
//return ev.call (is, '', '({test:true})', 'completion', true, false, true);
//Would make `test` pop up for every autocompletion.
//Note that syntax as well as every Object.prototype property get's added to that list later,
//so you won't be able to exclude things like `while` from the autocompletion list,
//unless you wou'd find a way to rewrite the getCompletions function.
//
return res; //Return the autocompletion result. If you want to break that, return nothing or an empty object
} else {
//This is the path where you end up when a user actually presses enter to evaluate an expression.
//In order to return anything as normal evaluation output, you have to return a wrapped object.
//In this case, we want to return the generated remote object.
//Since this is already a wrapped object it would be converted if we directly return it. Hence,
//`return result` would actually replicate the very normal behaviour as the result is converted.
//to output what's actually in the remote object, we have to stringify it and `evaluateAndWrap` that object again.`
//This is quite interesting;
return ev.call (is, null, '(' + JSON.stringify (res) + ')', "console", true, false, true)
}
};
},0);
To trochę gadatliwe, ale pomyślałem, że dodałem do niego kilka komentarzy
Więc normalnie, jeśli użytkownik, na przykład, ocenia, [1,2,3,4]
można oczekiwać następujących danych wyjściowych:
Po monkeypatchingu InjectedScript._evaluateAndWrap
oceniającym to samo wyrażenie, daje następujące dane wyjściowe:
Jak widzisz mała strzałka w lewo wskazująca wyjście, nadal tam jest, ale tym razem otrzymujemy obiekt. W przypadku wyniku wyrażenia tablica [1,2,3,4]
jest reprezentowana jako obiekt ze wszystkimi opisanymi właściwościami.
Polecam spróbować ocenić to i to wyrażenie, w tym te, które generują błędy. To dość interesujące.
Dodatkowo spójrz na obiekt is
- InjectedScriptHost
- . Zapewnia kilka metod zabawy i pozwala uzyskać wgląd w wewnętrzne elementy kontrolera.
Oczywiście możesz przechwycić wszystkie te informacje i nadal zwrócić oryginalny wynik użytkownikowi.
Wystarczy zastąpić instrukcję return w ścieżce else console.log (res)
następującą literą a return res
. Wtedy skończysz z następującymi.
Koniec edycji
To jest poprzednia wersja, która została naprawiona przez Google. Dlatego nie jest już możliwy sposób.
Jeden z nich się zaczepia Function.prototype.call
Chrome ocenia wprowadzone wyrażenie, wprowadzając call
funkcję eval przy pomocy InjectedScriptHost
asthisArg
var result = evalFunction.call(object, expression);
Biorąc to pod uwagę, można nasłuchiwać thisArg
od call
istoty evaluate
i uzyskać odniesienie do pierwszego argumentu ( InjectedScriptHost
)
if (window.URL) {
var ish, _call = Function.prototype.call;
Function.prototype.call = function () { //Could be wrapped in a setter for _commandLineAPI, to redefine only when the user started typing.
if (arguments.length > 0 && this.name === "evaluate" && arguments [0].constructor.name === "InjectedScriptHost") { //If thisArg is the evaluate function and the arg0 is the ISH
ish = arguments[0];
ish.evaluate = function (e) { //Redefine the evaluation behaviour
throw new Error ('Rejected evaluation of: \n\'' + e.split ('\n').slice(1,-1).join ("\n") + '\'');
};
Function.prototype.call = _call; //Reset the Function.prototype.call
return _call.apply(this, arguments);
}
};
}
Możesz np. Zgłosić błąd, że ocena została odrzucona.
Oto przykład, w którym wprowadzone wyrażenie jest przekazywane do kompilatora CoffeeScript przed przekazaniem go do evaluate
funkcji.