นอกจากการกำหนดใหม่console._commandLineAPI
แล้วยังมีวิธีอื่นที่จะเจาะเข้าไปใน InjectedScriptHost บนเบราว์เซอร์ WebKit เพื่อป้องกันหรือปรับเปลี่ยนการประเมินผลของนิพจน์ที่ใส่เข้าไปในคอนโซลของนักพัฒนาซอฟต์แวร์
แก้ไข:
Chrome ได้แก้ไขสิ่งนี้ในรุ่นที่ผ่านมา - ซึ่งต้องเป็นก่อนเดือนกุมภาพันธ์ 2558 เนื่องจากฉันสร้างส่วนสำคัญในเวลานั้น
ดังนั้นนี่คือความเป็นไปได้อีกอย่าง ในครั้งนี้เราขอยกระดับระดับดังกล่าวเป็นโดยตรงInjectedScript
แทนที่จะInjectedScriptHost
เป็นเวอร์ชั่นก่อนหน้า
ซึ่งเป็นสิ่งที่ดีเพราะคุณสามารถนำแผ่นแปะลิงโดยตรงInjectedScript._evaluateAndWrap
แทนที่จะต้องพึ่งพาInjectedScriptHost.evaluate
เพราะมันจะช่วยให้คุณควบคุมสิ่งที่ควรเกิดขึ้นได้อย่างละเอียดยิ่งขึ้น
สิ่งที่น่าสนใจอีกอย่างคือเราสามารถดักจับผลลัพธ์ภายในเมื่อมีการประเมินนิพจน์และคืนค่านั้นให้กับผู้ใช้แทนที่จะเป็นพฤติกรรมปกติ
นี่คือรหัสที่ทำอย่างนั้นคืนผลลัพธ์ภายในเมื่อผู้ใช้ประเมินบางสิ่งในคอนโซล
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);
มันค่อนข้าง verbose แต่ฉันคิดว่าฉันใส่ความคิดเห็นลงไป
ตัวอย่างเช่นโดยปกติหากผู้ใช้ประเมิน[1,2,3,4]
คุณจะคาดหวังผลลัพธ์ต่อไปนี้:
หลังจาก monkeypatching InjectedScript._evaluateAndWrap
ประเมินนิพจน์เดียวกันให้ผลลัพธ์ต่อไปนี้:
ตามที่คุณเห็นลูกศรซ้ายเล็ก ๆ ที่แสดงเอาท์พุทยังคงอยู่ที่นั่น แต่คราวนี้เราได้รับวัตถุ โดยที่ผลลัพธ์ของนิพจน์นั้นอาร์เรย์[1,2,3,4]
จะถูกแทนด้วยวัตถุที่มีคุณสมบัติทั้งหมดที่อธิบายไว้
ฉันขอแนะนำให้พยายามประเมินสิ่งนี้และนิพจน์นั้นรวมถึงสิ่งที่สร้างข้อผิดพลาด มันค่อนข้างน่าสนใจ
นอกจากนี้ให้ดูที่is
- InjectedScriptHost
-วัตถุ มันมีวิธีการบางอย่างในการเล่นและทำความเข้าใจภายในของผู้ตรวจสอบ
แน่นอนคุณสามารถดักจับข้อมูลนั้นทั้งหมดและยังคงส่งคืนผลลัพธ์ดั้งเดิมให้กับผู้ใช้
เพียงแค่เปลี่ยนคำสั่งกลับในเส้นทางอื่นโดยต่อไปนี้console.log (res)
return res
จากนั้นคุณจะจบลงด้วยการดังต่อไปนี้
สิ้นสุดการแก้ไข
นี่เป็นรุ่นก่อนหน้าซึ่งได้รับการแก้ไขโดย Google ดังนั้นจึงไม่ใช่วิธีที่เป็นไปได้อีกต่อไป
หนึ่งในนั้นคือตะขอเข้า Function.prototype.call
Chrome จะประเมินค่านิพจน์ที่ป้อนโดยcall
ใช้ฟังก์ชัน eval ด้วยInjectedScriptHost
เช่นthisArg
var result = evalFunction.call(object, expression);
ให้นี้คุณสามารถฟังสำหรับthisArg
การcall
เป็นอยู่evaluate
และได้รับการอ้างอิงถึงอาร์กิวเมนต์แรก ( 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);
}
};
}
คุณสามารถส่งข้อผิดพลาดเช่นว่าการประเมินถูกปฏิเสธ
นี่คือตัวอย่างที่นิพจน์ที่ป้อนได้รับการส่งผ่านไปยังคอมไพเลอร์ CoffeeScript ก่อนส่งผ่านไปยังevaluate
ฟังก์ชัน