詳解JavaScript常用的Hook腳本
本文Hook腳本 來(lái)自 包子
頁(yè)面最早加載代碼Hook時(shí)機(jī)
- 在source里 用dom事件斷點(diǎn)的script斷點(diǎn)
- 然后刷新網(wǎng)頁(yè),就會(huì)斷在第一個(gè)js標(biāo)簽,這時(shí)候就可以注入代碼進(jìn)行hook
監(jiān)聽(tīng) 鍵盤(pán) 與 鼠標(biāo) 事件
// 判斷是否按下F12 onkeydown事件 /* 提示:?與 onkeydown 事件相關(guān)聯(lián)的事件觸發(fā)次序: onkeydown onkeypress onkeyup */ // F12的鍵碼為 123,可以直接全局搜索 keyCode == 123, == 123 ,keyCode document.onkeydown = function() { if (window.event && window.event.keyCode == 123) { // 改變鍵碼 event.keyCode = 0; event.returnValue = false; // 監(jiān)聽(tīng)到F12被按下直接關(guān)閉窗口 window.close(); window.location = "about:blank"; } } ; // 監(jiān)聽(tīng)鼠標(biāo)右鍵是否被按下方法 1, oncontextmenu事件 document.oncontextmenu = function () { return false; }; // 監(jiān)聽(tīng)鼠標(biāo)右鍵是否被按下方法 2,onmousedown事件 document.onmousedown = function(evt){ // button屬性是2 就代表是鼠標(biāo)右鍵 if(evt.button == 2){ alert('監(jiān)聽(tīng)到鼠標(biāo)右鍵被按下') evt.preventDefault() // 該方法將通知 Web 瀏覽器不要執(zhí)行與事件關(guān)聯(lián)的默認(rèn)動(dòng)作 return false; // 監(jiān)聽(tīng)用戶工具欄調(diào)起開(kāi)發(fā)者工具,判斷瀏覽器的可視高度和寬度是否有改變,有改變則處理, // 判斷是否開(kāi)了開(kāi)發(fā)者工具不太合理。 var h = window.innerHeight, w = window.innerWidth; window.onresize = function(){ alert('改變了窗口高度') // hook代碼 (function() { //嚴(yán)謹(jǐn)模式 檢查所有錯(cuò)誤 'use strict'; // hook 鼠標(biāo)選擇 Object.defineProperty(document, 'onselectstart', { set: function(val) { console.log('Hook捕獲到選中設(shè)置->', val); return val; } }); // hook 鼠標(biāo)右鍵 Object.defineProperty(document,'oncontextmenu',{ set:function(evt){ console.log("檢測(cè)到右鍵點(diǎn)擊"); return evt }); })();
webpack hook 半自動(dòng)扣
//在加載器后面下斷點(diǎn) 執(zhí)行下面代碼 // 這里的f 替換成需要導(dǎo)出的函數(shù)名 window.zhiyuan = f; window.wbpk_ = ""; window.isz = false; f = function(r){ if(window.isz) { // e[r]里的e 是加載器里的call那里 window.wbpk_ = window.wbpk_ + r.toString()+":"+(e[r]+"")+ ","; } return window.zhiyuan(r); } //在你要的方法加載前下斷點(diǎn) 執(zhí)行 window.isz=true //在你要的方法運(yùn)行后代碼處下斷點(diǎn) 執(zhí)行 window.wbpk_ 拿到所有代碼 注意后面有個(gè)逗號(hào) function o(t) { if (n[t]) return n[t].exports; var i = n[t] = { i: t, l: !1, exports: {} }; console.log("被調(diào)用的 >>> ", e[t].toString()); // 這里進(jìn)行拼接,bb變量需要在全局定義一下 // t 是模塊名, e[t] 是模塊對(duì)應(yīng)的函數(shù), 也就是key:value形式 bb += `"${t}":${e[t].toString()},` return e[t].call(i.exports, i, i.exports, o), i.l = !0, i.exports bz = o;
如果只是調(diào)用模塊,不用模塊里面的方法, 那么直接獲取調(diào)用模塊的時(shí)候所有加載過(guò)的模塊,進(jìn)行拼接
document下的createElement()方法的hook,查看創(chuàng)建了什么元素
(function() { 'use strict' var _createElement = document.createElement.bind(document); document.createElement = function(elm){ // 這里做判斷 是否創(chuàng)建了script這個(gè)元素 if(elm == 'body'){ debugger; } return _createElement(elm); } })();
之前我不知道我用的是 var _createElement = document.createElement
導(dǎo)致一直報(bào)錯(cuò) Uncaught TypeError: Illegal invocation
原來(lái)是需要綁定一下對(duì)象 var _createElement = document.createElement.bind(document);
headers hook 當(dāng)header中包含Authorization時(shí),則插入斷點(diǎn)
var code = function(){ var org = window.XMLHttpRequest.prototype.setRequestHeader; window.XMLHttpRequest.prototype.setRequestHeader = function(key,value){ if(key=='Authorization'){ debugger; } return org.apply(this,arguments); } } var script = document.createElement('script'); script.textContent = '(' + code + ')()'; (document.head||document.documentElement).appendChild(script); script.parentNode.removeChild(script);
請(qǐng)求hook 當(dāng)請(qǐng)求的url里包含MmEwMD時(shí),則插入斷點(diǎn)
var code = function(){ var open = window.XMLHttpRequest.prototype.open; window.XMLHttpRequest.prototype.open = function (method, url, async){ if (url.indexOf("MmEwMD")>-1){ debugger; } return open.apply(this, arguments); }; } var script = document.createElement('script'); script.textContent = '(' + code + ')()'; (document.head||document.documentElement).appendChild(script); script.parentNode.removeChild(script);
docuemnt.getElementById以及value屬性的hook
//?docuemnt.getElementById?以及value屬性的hook,可以參考完成innerHTML的hook document.getElementById?=?function(id)?{ ????var?value?=?document.querySelector('#'?+?id).value; ????console.log('DOM操作?id:?',?id) ????try?{ ????????Object.defineProperty(document.querySelector('#'+?id),?'value',?{ ????????????get:?function()?{ ????????????????console.log('getting?-',?id,?'value?-',?value); ????????????????return?value; ????????????}, ????????????set:?function(val)?{ ????????????????console.log('setting?-',?id,?'value?-',?val) ????????????????value?=?val; ????????????} ????????}) ????}?catch?(e)?{ ????????console.log('---------華麗的分割線--------') ????} ????return?document.querySelector('#'?+?id); }
過(guò)debugger 阿布牛逼
function Closure(injectFunction) { return function() { if (!arguments.length) return injectFunction.apply(this, arguments) arguments[arguments.length - 1] = arguments[arguments.length - 1].replace(/debugger/g, ""); return injectFunction.apply(this, arguments) } } var oldFunctionConstructor = window.Function.prototype.constructor; window.Function.prototype.constructor = Closure(oldFunctionConstructor) //fix native function window.Function.prototype.constructor.toString = oldFunctionConstructor.toString.bind(oldFunctionConstructor); var oldFunction = Function; window.Function = Closure(oldFunction) window.Function.toString = oldFunction.toString.bind(oldFunction); var oldEval = eval; window.eval = Closure(oldEval) window.eval.toString = oldEval.toString.bind(oldEval); // hook GeneratorFunction var oldGeneratorFunctionConstructor = Object.getPrototypeOf(function*() {}).constructor var newGeneratorFunctionConstructor = Closure(oldGeneratorFunctionConstructor) newGeneratorFunctionConstructor.toString = oldGeneratorFunctionConstructor.toString.bind(oldGeneratorFunctionConstructor); Object.defineProperty(oldGeneratorFunctionConstructor.prototype, "constructor", { value: newGeneratorFunctionConstructor, writable: false, configurable: true }) // hook Async Function var oldAsyncFunctionConstructor = Object.getPrototypeOf(async function() {}).constructor var newAsyncFunctionConstructor = Closure(oldAsyncFunctionConstructor) newAsyncFunctionConstructor.toString = oldAsyncFunctionConstructor.toString.bind(oldAsyncFunctionConstructor); Object.defineProperty(oldAsyncFunctionConstructor.prototype, "constructor", { value: newAsyncFunctionConstructor, // hook dom var oldSetAttribute = window.Element.prototype.setAttribute; window.Element.prototype.setAttribute = function(name, value) { if (typeof value == "string") value = value.replace(/debugger/g, "") // 向上調(diào)用 oldSetAttribute.call(this, name, value) ; var oldContentWindow = Object.getOwnPropertyDescriptor(HTMLIFrameElement.prototype, "contentWindow").get Object.defineProperty(window.HTMLIFrameElement.prototype, "contentWindow", { get() { var newV = oldContentWindow.call(this) if (!newV.inject) { newV.inject = true; core.call(newV, globalConfig, newV); } return newV
過(guò)debugger—1 constructor 構(gòu)造器構(gòu)造出來(lái)的
var _constructor = constructor; Function.prototype.constructor = function(s) { if (s == "debugger") { console.log(s); return null; } return _constructor(s); }
過(guò)debugger—2 eval的
(function() { 'use strict'; var eval_ = window.eval; window.eval = function(x) { eval_(x.replace("debugger;", " ; ")); } ; window.eval.toString = eval_.toString; } )();
JSON HOOK
var my_stringify = JSON.stringify; JSON.stringify = function (params) { //這里可以添加其他邏輯比如 debugger console.log("json_stringify params:",params); return my_stringify(params); }; var my_parse = JSON.parse; JSON.parse = function (params) { //這里可以添加其他邏輯比如 debugger console.log("json_parse params:",params); return my_parse(params); };
對(duì)象屬性hook 屬性自定義
(function(){ // 嚴(yán)格模式,檢查所有錯(cuò)誤 'use strict' // document 為要hook的對(duì)象 ,屬性是cookie Object.defineProperty(document,'cookie',{ // hook set方法也就是賦值的方法,get就是獲取的方法 set: function(val){ // 這樣就可以快速給下面這個(gè)代碼行下斷點(diǎn),從而快速定位設(shè)置cookie的代碼 debugger; // 在此處自動(dòng)斷下 console.log('Hook捕獲到set-cookie ->',val); return val; } }) })();
cookies - 1 (不是萬(wàn)能的 有些時(shí)候hook不到 自己插入debugger)
var cookie_cache = document.cookie; Object.defineProperty(document, 'cookie', { get: function() { console.log('Getting cookie'); return cookie_cache; }, set: function(val) { console.log("Seting cookie",val); var cookie = val.split(";")[0]; var ncookie = cookie.split("="); var flag = false; var cache = cookie_cache.split("; "); cache = cache.map(function(a){ if (a.split("=")[0] === ncookie[0]){ flag = true; return cookie; } return a; }) } })
cookies - 2
var code = function(){ var org = document.cookie.__lookupSetter__('cookie'); document.__defineSetter__("cookie",function(cookie){ if(cookie.indexOf('TSdc75a61a')>-1){ debugger; } org = cookie; }); document.__defineGetter__("cookie",function(){return org;}); } var script = document.createElement('script'); script.textContent = '(' + code + ')()'; (document.head||document.documentElement).appendChild(script); script.parentNode.removeChild(script); // 當(dāng)cookie中匹配到了?TSdc75a61a, 則插入斷點(diǎn)。
window attr
// 定義hook屬性 var window_flag_1 = "_t"; var window_flag_2 = "ccc"; var key_value_map = {}; var window_value = window[window_flag_1]; // hook Object.defineProperty(window, window_flag_1, { get: function(){ console.log("Getting",window,window_flag_1,"=",window_value); //debugger return window_value }, set: function(val) { console.log("Setting",window, window_flag_1, "=",val); window_value = val; key_value_map[window[window_flag_1]] = window_flag_1; set_obj_attr(window[window_flag_1],window_flag_2); }); function set_obj_attr(obj,attr){ var obj_attr_value = obj[attr]; Object.defineProperty(obj,attr, { get: function() { console.log("Getting", key_value_map[obj],attr, "=", obj_attr_value); //debugger return obj_attr_value; }, set: function(val){ console.log("Setting", key_value_map[obj], attr, "=", val); obj_attr_value = val; }); }
eval/Function
window.__cr_eval = window.eval; var myeval = function(src) { // src就是eval運(yùn)行后 最終返回的值 console.log(src); console.log("========= eval end ==========="); return window.__cr_eval; } var _myeval = myeval.bind(null); _myeval.toString = window.__cr_eval.toString; Object.defineProperty(window, 'eval',{value: _myeval}); window._cr_fun = window.Function var myfun = function(){ var args = Array.prototype.slice.call(arguments, 0, -1).join(","), src = arguments[arguments.lenght -1]; console.log("======== Function end ============="); return window._cr_fun.apply(this, arguments) myfun.toString = function() {return window._cr_fun + ""} //小花招,這里防止代碼里檢測(cè)原生函數(shù) Object.defineProperty(window, "Function",{value: myfun})
eval 取返回值
_eval = eval; eval = (res)=>{ res1 = res // 返回值 return _eval(res) } eval(xxxxxxxxx)
eval proxy代理 https://segmentfault.com/a/1190000025154230
// 代理eval eval = new Proxy(eval,{ // 如果代理的是函數(shù) 查看調(diào)用 就用apply屬性 // 第二個(gè)參數(shù)是prop 這里用不上 因?yàn)槭菍傩?,eval只是個(gè)函數(shù) 所以prop為undefind 這里設(shè)置了下劃線 —— apply: (target,_,arg)=>{ // target 是被代理的函數(shù)或?qū)ο竺Q(chēng),當(dāng)前是[Function: eval] // arg是傳進(jìn)來(lái)的參數(shù),返回的是個(gè)列表 console.log(arg[0]) } }) // eval執(zhí)行的時(shí)候就會(huì)被代理攔截 // 傳入的如果是字符串 那么只會(huì)返回字符串,這里是匿名函數(shù) 直接執(zhí)行 return了內(nèi)容 eval( (function(){return "我是包子 自己執(zhí)行了"})() ) // 結(jié)果 : 我是包子 自己執(zhí)行了
websocket hook
// 1、webcoket 一般都是json數(shù)據(jù)格式傳輸,那么發(fā)生之前需要JSON.stringify var my_stringify = JSON.stringify; JSON.stringify = function (params) { //這里可以添加其他邏輯比如 debugger console.log("json_stringify params:",params); return my_stringify(params); }; var my_parse = JSON.parse; JSON.parse = function (params) { console.log("json_parse params:",params); return my_parse(params); // 2 webScoket 綁定在windows對(duì)象,上,根據(jù)瀏覽器的不同,websokcet名字可能不一樣 //chrome window.WebSocket firfox window.MozWebSocket; window._WebSocket = window.WebSocket; // hook send window._WebSocket.prototype.send = function (data) { console.info("Hook WebSocket", data); return this.send(data) } Object.defineProperty(window, "WebSocket",{value: WebSocket})
hook 正則 —— 1
(function?()?{ ????var?_RegExp?=?RegExp; ????RegExp?=?function?(pattern,?modifiers)?{ ????????console.log("Some?codes?are?setting?regexp"); ????????debugger; ????????if?(modifiers)?{ ????????????return?_RegExp(pattern,?modifiers); ????????}?else?{ ????????????return?_RegExp(pattern); ????????} ????}; ????RegExp.toString?=?function?()?{ ????????return?"function?setInterval()?{?[native?code]?}" ????}; })();
hook 正則 2 加在sojson頭部過(guò)字符串格式化檢測(cè)
(function() { var _RegExp = RegExp; RegExp = function(pattern, modifiers) { if (pattern == decodeURIComponent("%5Cw%2B%20*%5C(%5C)%20*%7B%5Cw%2B%20*%5B'%7C%22%5D.%2B%5B'%7C%22%5D%3B%3F%20*%7D") || pattern == decodeURIComponent("function%20*%5C(%20*%5C)") || pattern == decodeURIComponent("%5C%2B%5C%2B%20*(%3F%3A_0x(%3F%3A%5Ba-f0-9%5D)%7B4%2C6%7D%7C(%3F%3A%5Cb%7C%5Cd)%5Ba-z0-9%5D%7B1%2C4%7D(%3F%3A%5Cb%7C%5Cd))") || pattern == decodeURIComponent("(%5C%5C%5Bx%7Cu%5D(%5Cw)%7B2%2C4%7D)%2B")) { pattern = '.*?'; console.log("發(fā)現(xiàn)sojson檢測(cè)特征,已幫您處理。") } if (modifiers) { console.log("疑似最后一個(gè)檢測(cè)...已幫您處理。") console.log("已通過(guò)全部檢測(cè),請(qǐng)手動(dòng)處理debugger后盡情調(diào)試吧!") return _RegExp(pattern, modifiers); } else { return _RegExp(pattern); } } ; RegExp.toString = function() { return _RegExp.toString(); } ; } )();
hook canvas (定位圖片生成的地方)
(function() { 'use strict'; let create_element = document.createElement.bind(doument); document.createElement = function (_element) { console.log("create_element:",_element); if (_element === "canvas") { debugger; } return create_element(_element); } })();
setInterval 定時(shí)器
(function() { setInterval_ = setInterval; console.log("原函數(shù)已被重命名為setInterval_") setInterval = function() {} ; setInterval.toString = function() { console.log("有函數(shù)正在檢測(cè)setInterval是否被hook"); return setInterval_.toString(); } ; } )();
setInterval 循環(huán)清除定時(shí)器
for(var i = 0; i < 9999999; i++) window.clearInterval(i)
console.log 檢測(cè)例子 (不讓你輸出調(diào)試)
var oldConsole = ["debug", "error", "info", "log", "warn", "dir", "dirxml", "table", "trace", "group", "groupCollapsed", "groupEnd", "clear", "count", "countReset", "assert", "profile", "profileEnd", "time", "timeLog", "timeEnd", "timeStamp", "context", "memory"].map(key=>{ var old = console[key]; console[key] = function() {} ; console[key].toString = old.toString.bind(old) return old; } )
檢測(cè)函數(shù)是否被hook例子
if (window.eval == 'native code') { console.log('發(fā)現(xiàn)eval函數(shù)被hook了 開(kāi)始死循環(huán)'); }
到此這篇關(guān)于JavaScript常用的Hook腳本的文章就介紹到這了,更多相關(guān)js hook腳本內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
js實(shí)現(xiàn)html滑動(dòng)圖片拼圖驗(yàn)證
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)html滑動(dòng)圖片拼圖驗(yàn)證,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-06-06JS實(shí)現(xiàn)為表格動(dòng)態(tài)添加標(biāo)題的方法
這篇文章主要介紹了JS實(shí)現(xiàn)為表格動(dòng)態(tài)添加標(biāo)題的方法,涉及javascript中createCaption方法添加標(biāo)題的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-03-03Typescript 中的 interface 和 type 到底有什么區(qū)別詳解
這篇文章主要介紹了Typescript 中的 interface 和 type 到底有什么區(qū)別詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06借助javascript代碼判斷網(wǎng)頁(yè)是靜態(tài)還是偽靜態(tài)
如何看同類(lèi)型的網(wǎng)站采用的是靜態(tài)還是偽靜態(tài),一般網(wǎng)頁(yè)后綴都是以.html結(jié)尾。我們可以借助一段簡(jiǎn)單的javascript代碼判斷一下2014-05-05原生js實(shí)現(xiàn)的金山打字小游戲(實(shí)例代碼詳解)
這篇文章主要介紹了原生js實(shí)現(xiàn)的金山打字小游戲,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03JavaScript中const關(guān)鍵字的用法及特性
該文章講解了JavaScript中const關(guān)鍵字的用法以及它的一些特性,該關(guān)鍵字用于創(chuàng)建常量,即一旦賦值之后就不能再修改,但是,使用?const創(chuàng)建的對(duì)象和數(shù)組卻可以被修改,本文通過(guò)講解“賦值”和“變異”之間的重要區(qū)別,詳細(xì)解釋了這一現(xiàn)象,需要的朋友可以參考下2023-05-05TypeScript對(duì)于Duck類(lèi)型和模塊命名空間應(yīng)用
這篇文章主要介紹了TypeScript對(duì)于Duck類(lèi)型和模塊命名空間應(yīng)用,Duck類(lèi)型是一種動(dòng)態(tài)類(lèi)型和多態(tài)形式,在duck類(lèi)型中,重點(diǎn)是對(duì)象的行為可以做什么,而不是對(duì)象所屬的類(lèi)型2022-08-08js實(shí)現(xiàn)超簡(jiǎn)單的展開(kāi)、折疊目錄代碼
這篇文章主要介紹了js實(shí)現(xiàn)超簡(jiǎn)單的展開(kāi)、折疊目錄代碼,通過(guò)javascript操作鼠標(biāo)點(diǎn)擊事件控制頁(yè)面元素樣式的動(dòng)態(tài)改變實(shí)現(xiàn)該功能,非常簡(jiǎn)單實(shí)用,需要的朋友可以參考下2015-08-08js實(shí)現(xiàn)同一個(gè)頁(yè)面,多個(gè)enter事件綁定的示例
今天小編就為大家分享一篇js實(shí)現(xiàn)同一個(gè)頁(yè)面,多個(gè)enter事件綁定的示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-10-10