javascript
JS逆向学习笔记
JS逆向?qū)W習(xí)筆記
尋找深圳爬蟲工作,微信:cjh-18888
?
文章目錄
- JS逆向?qū)W習(xí)筆記
-
- 一. JS Hook
-
- 1. JS HOOK 原理和作用
-
- 原理:替換原來(lái)的方法. (好像寫了句廢話)
- 作用: 可以去Hook一些內(nèi)置的函數(shù), 例如Debugger, setInterval,JSON.stringify等等
- 2.JSHook 檢測(cè)與過(guò)檢測(cè)
-
- 原理: 其實(shí)就是檢測(cè)代碼是否和原來(lái)的相等.
- 繞過(guò)手段: 修改Function的toString方法.
- 3.JS過(guò)反調(diào)試
- 4. JSHook 對(duì)象屬性
-
- 1. Object.defindPropety()
- 二. Chrome拓展(Chrome Extension)開發(fā)
-
- 1. 基本介紹
-
- 1. 什么是Chrome插件?
- 2. 學(xué)習(xí)Chrome插件開發(fā)的意義
- 3. 為什么是Chrome插件,而不是firefox插件?
- 2. 文件結(jié)構(gòu)
-
- 1. manifest.json
- 2. content-scripts
- 3.background
- 4. event-pages
- 5. popup
- 6. injected-script
- 7.更多
- 3.實(shí)戰(zhàn) - Js自動(dòng)注入Hook代碼
-
- 1. manifest.json
- 2. content_script.js
- 三. 調(diào)試技巧
-
- 1. 快速定位關(guān)鍵代碼
- 2. Conditional breakpoints
- 3. Reres拓展插件
- 4. monitor監(jiān)聽方法
- 5. monitorEvents監(jiān)聽方法
- 6. watch監(jiān)聽變量
- 7.控制臺(tái)實(shí)時(shí)表達(dá)式
- 四. 實(shí)戰(zhàn)
-
- 1. webpack整體改寫方案
-
-
- 整體改寫的思路如下:
-
- 1. 找到加密位置
- 2. 查到當(dāng)前方法實(shí)現(xiàn)代碼,整體拿下.
- 3. 找到"n"函數(shù)聲明位置.
- 4. window.n = a;
-
- 2. sojson反調(diào)試
-
- 1. 修改setInterval
- 2. Conditional breakpoints
- 3. 函數(shù)替換,函數(shù)置空
- 4. Activate breakpoints
- 5. 修改debugger
- 總結(jié):個(gè)人認(rèn)為,最好用的方法應(yīng)該是1,2,4了. 操作簡(jiǎn)單.
- 3. 某視頻反調(diào)試案例
- 4. 自寫算法案例 -1
- 5. 自寫算法案例 -2
- 6. JS混淆原理(eval和Function)
- 7. JS混淆原理(數(shù)字混淆和字符串混淆)
- 8. 五秒防火墻fuckjs原理分析改寫
- 9. 流程控制混淆原理(switch)
- 10. 流程控制混淆原理(逗號(hào)運(yùn)算符)
- 五.AST入門與實(shí)戰(zhàn)
-
- 1. AST抽象語(yǔ)法樹入門
- 2. Babel組件traverse
- 3. Babel組件types
- 4. 用Babel生成一個(gè)新函數(shù)
- 5. Babel中節(jié)點(diǎn)操作
- 6. 用Babel給函數(shù)加點(diǎn)料
- 7. 用Babel實(shí)現(xiàn)變量名混淆
- 7. 用Babel實(shí)現(xiàn)數(shù)組亂序
- 8. 用Babel實(shí)現(xiàn)字符串加密
- 9. 實(shí)現(xiàn)十六進(jìn)制文本加密
- 10. 實(shí)現(xiàn)unicode加密
- 11. JS混淆還原(字符串解密)
- 12. JS混淆還原(去除花指令)
- 13. JS混淆還原(AST節(jié)點(diǎn)調(diào)試技巧)
- 14. switch流程平坦化還原(復(fù)原指令順序)
- 15. JS混淆實(shí)戰(zhàn)案例
- 六. 滑塊破解
-
- 1. 云片
- 2. 2980
?
一. JS Hook
1. JS HOOK 原理和作用
原理:替換原來(lái)的方法. (好像寫了句廢話)
function test(aa,bb){cc = aa + bb;return cc; }Hook代碼:
var _test = test; // 拿到test test = function(x,y){console.log(x,y); //輸出拿到的參數(shù)var retval = _test(x,y); // retval 是原來(lái)的計(jì)算結(jié)果console.log( retval)return retval + 1 // 修改返回結(jié)果 }- ?
此時(shí)重新調(diào)用test, 結(jié)果比正常值多了1
作用: 可以去Hook一些內(nèi)置的函數(shù), 例如Debugger, setInterval,JSON.stringify等等
//Hook setInterval var _setInterval = setInterval; setInterval = function(a,b){console.log(a + '',b)return 'setInterval is Kill' }//Hook JSON.stringify stringify = JSON.stringify; JSON.stringify = function(a){ console.log('Hook JSON.stringify ->' + stringify(a)) return stringify(a) }2.JSHook 檢測(cè)與過(guò)檢測(cè)
原理: 其實(shí)就是檢測(cè)代碼是否和原來(lái)的相等.
案例代碼:
function test(aa,bb){var cc = aa + bb;return cc;}function checkTest(func){test + '' == 'function test(aa,bb){var cc = aa + bb;return cc;}'?console.log('func未被修改'):console.log('func被修改了') }此時(shí)我們可以把hook代碼置入到瀏覽器
//控制臺(tái)置入的代碼 var _test = test; test = function(x,y){console.log(x,y); var retval = _test(x,y); console.log( retval)return retval }繞過(guò)手段: 修改Function的toString方法.
Function.prototype.toString=function(){return "function test(x,y){z=x+y;return z;}"; }3.JS過(guò)反調(diào)試
反調(diào)試代碼:
var fuck=["\u0068\u0065\u006e\u0076\u0061\u0074","\u005f\u006b\u0070\u006f\u0076\u0074\u0071\u005f\u0076\u006b\u0074","\u0066\u006b\u005f\u0071\u0069\u0061\u0070\u0076","\u0068\u0071\u0070\u005f\u0076\u0065\u006b\u0070\u0022\u006f\u0076\u0074\u0056\u006b\u0051\u0065\u0070\u0076\u003a\u002a\u006f\u0076\u0074\u0025\u0077\u0068\u006b\u0074\u002a\u0078\u005d\u0074\u0022\u0065\u0039\u0032\u002e\u005d\u0074\u0074\u0039\u0057\u0059\u0037\u0065\u003e\u006f\u0076\u0074\u0030\u006e\u0061\u0070\u0063\u0076\u006a\u0037\u0065\u0027\u0027\u0025\u0077\u0078\u005d\u0074\u0022\u005d\u0039\u006f\u0076\u0074\u0030\u005f\u006a\u005d\u0074\u003f\u006b\u0066\u0061\u003d\u0076\u002a\u0065\u0025\u0037\u005d\u0074\u0074\u0030\u0072\u0071\u006f\u006a\u002a\u005d\u0021\u0034\u003b\u005d\u0029\u0036\u003c\u005d\u0027\u0034\u0025\u0037\u0079\u0074\u0061\u0076\u0071\u0074\u0070\u0022\u0070\u0061\u0073\u0022\u0051\u0065\u0070\u0076\u003a\u003d\u0074\u0074\u005d\u0075\u002a\u005d\u0074\u0074\u0025\u0037\u0079","\u0076\u006b\u004f\u0076\u0074\u0065\u0070\u0063","\u0074\u0061\u0076\u0071\u0074\u0070\u0022\u0076\u006a\u0065\u006f","\u0068\u0071\u005f\u0067\u0055\u006b\u0071","\u0070\u0067\u005b\u0059\u0078\u0061\u0067\u0072","\u006c\u0076\u005d\u006a","\u0066\u0061\u0059\u0072\u005b\u006c\u005d\u0072\u005f\u0065\u0059\u0067","\u0066\u0066\u0066","\u005b\u0067\u0072\u006b\u0067\u0070\u005d\u0032\u0070\u0067\u005f\u002c\u0026\u005d\u0076\u0076\u0026\u0021","\u006a\u0059\u0068\u0069\u005b\u005b\u0059\u0078\u002f","\u006c\u0069\u0074\u0057\u007a\u005d\u0063\u0074\u0026\u0067\u0059\u007a\u003d\u0074\u007a\u0059\u0078\u007c\u0055\u0072\u002e\u001d\u0026\u006f\u0026\u004f\u0074\u0055\u007a\u005d\u007c\u0059\u0026\u0057\u0063\u006a\u0059\u0051\u0026\u0071","\u006f\u0061\u0076\u0045\u0070\u0076\u0061\u0074\u0078\u005d\u006e\u002a\u0068\u0071\u005f\u0067\u002d\u0057\u0027\u0057\u0059\u0059\u0057\u006f\u0056\u006b\u004f\u002a\u0068\u0071\u005f\u0067\u0057\u0038\u0059\u0025\u0059\u002a\u0068\u0071\u005f\u0067\u002d\u0057\u0027\u0057\u0059\u0059\u0057\u006f\u0056\u006b\u004f\u002a\u0068\u0071\u005f\u0067\u0057\u0038\u0059\u0025\u0059\u002a\u0068\u0071\u005f\u0067\u002d\u0057\u0027\u0057\u0059\u0059\u0057\u006f\u0056\u006b\u004f\u002a\u0068\u0071\u005f\u0067\u0057\u0038\u0059\u0025\u0059\u002a\u0068\u0071\u005f\u0067\u0057\u002d\u0034\u0059\u0025\u0025\u0025\u002e\u002d\u0032\u0032\u0032\u0025","\u006a\u006d\u005b\u0063\u0029\u0053\u0023\u0053\u0055\u0055\u0053\u006b\u0058\u0067\u004b\u002c\u006b\u0058\u0067\u004b\u002c\u006a\u006d\u005b\u0063\u0053\u0031\u0055\u0021\u0021\u0055\u0035\u0035\u002b\u0037\u005b\u0067\u0072\u006b\u0067\u0070\u005d\u0032\u0070\u0067\u005f\u002c\u0026\u0067\u006e\u0066\u0063\u003e\u002f\u0038\u002f\u002f\u002f\u003a\u0026\u0023\u006a\u006d\u005b\u0063\u0029\u0053\u0023\u0053\u0055\u0055\u0053\u006b\u0058\u0067\u004b\u002c\u006b\u0058\u0067\u004b\u002c\u006a\u006d\u005b\u0063\u0053\u0031\u0055\u0021\u0021\u0055\u0023\u0026\u002f\u0038\u0026\u0021\u003e\u005b\u0067\u0072\u006b\u0067\u0070\u005d\u0032\u0070\u0067\u005f\u002c\u0026\u005d\u0076\u0076\u0026\u0021"],bianchengmao=-1,fff=-1;var fuck1=[1,2,3,4];console.log("過(guò)了檢測(cè)就會(huì)給你正確答案哦!");function Uint8ToStr_(arr){for(var i=0,str="";i<arr.length;i++){var a=arr[i];str+=String.fromCharCode(a)}return str}function strToUint8_(str){for(var i=0,arr=[];i<str.length;i++){var a=str.charCodeAt(i);arr.push(a)}return new Uint8Array(arr)}function strToUint8(str){for(var i=0,arr=[];i<str.length;i++){var a=str.charCodeAt(i);arr.push(a%2?a-4:a+2)}return new Uint8Array(arr)}function Uint8ToStr(arr){for(var i=0,str="";i<arr.length;i++){var a=arr[i];str+=String.fromCharCode(a%2?a+4:a-2)}return str}function sToS(x){return Uint8ToStr(strToUint8_(x))}fuck1[!+[]+!+[]]=[][sToS(fuck[0])][sToS(fuck[1])];fuck1[+[]]=fuck1[!+[]+!+[]](sToS(fuck[5]))(),fuck1[+[]][sToS(fuck[6])]=sToS;fuck1[!+[]+!+[]](fuck1[+[]][sToS(fuck[6])](fuck[14]))();fuck1[+[]][fuck1[+[]]["fuckYou"](fuck1[+[]]["fuckYou"](fuck[7]))][fuck1[+[]]["fuckYou"](fuck1[+[]]["fuckYou"](fuck[8]))]==fuck1[+[]]["fuckYou"](fuck1[+[]]["fuckYou"](fuck[9]))?fuck1[+[]][(![]+[])[+[]]+(![]+[])[+[]]+(![]+[])[+[]]]=1:fuck1[+[]][[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+[]]+(![]+[])[+[]]+(![]+[])[+[]])()]=0;fuck1[+[]][(![]+[])[+[]]+(![]+[])[+[]]+(![]+[])[+[]]]==+!+[]?fuck1[+[]][sToS(sToS(fuck[9]))]=1:fuck1[!+[]+!+[]](fuck1[+[]][sToS(fuck[6])](fuck[14]))();setInterval+""==fuck1[+[]][sToS(fuck[6])](fuck1[+[]][sToS(fuck[6])](fuck1[+[]][sToS(fuck[6])](fuck[13])))?fuck1[+[]][sToS(sToS(fuck[9]))]=fuck1[+[]][sToS(sToS(fuck[9]))]+2:fuck1[!+[]+!+[]](fuck1[+[]][sToS(fuck[6])](fuck[14]))();fuck1[!+[]+!+[]](fuck1[+[]][sToS(fuck[6])](fuck1[+[]][sToS(fuck[6])](fuck[15])))(+!+[])+(+!+[]);我們直接看到這塊
fuck1[!+[] + !+[]] = [][sToS(fuck[0])][sToS(fuck[1])]; // fuck[2] = Function; fuck1[+[]] = fuck1[!+[] + !+[]](sToS(fuck[5]))(), // fuck[0] = Function('return this')() fuck1[+[]][sToS(fuck[6])] = sToS; fuck1[!+[] + !+[]](fuck1[+[]][sToS(fuck[6])](fuck[14]))(); // fuck1[2]("setInterval(debugger;,1000)")()通過(guò)上面的代碼解析, 我們可以看到,debugger其實(shí)就是通過(guò)setInterval方法來(lái)調(diào)用的. 那么我們其實(shí)可以寫這個(gè)過(guò)調(diào)試代碼.
4. JSHook 對(duì)象屬性
Hook對(duì)象屬性需要使用到
Object.defineProperty() //方法會(huì)直接在一個(gè)對(duì)象上定義一個(gè)新屬性,或者修改一個(gè)對(duì)象的現(xiàn)有屬性,并返回此對(duì)象。 | 這個(gè)常用一些. Object.defineProperties() // 方法直接在一個(gè)對(duì)象上定義新的屬性或修改現(xiàn)有屬性,并返回該對(duì)象。1. Object.defindPropety()
下面這個(gè)是定義了一個(gè)案例. 我們使用Object.defindProperty()來(lái)修改屬性對(duì)象的set
var obj = {'name': function(){return 'xiaopang';} }然后我們編寫Hook代碼.
Object.defineProperty(obj,'name',{'set':function(x){console.log(x)return x;} })Hook注意點(diǎn):
- 對(duì)象需要?jiǎng)?chuàng)建以后方可Hook
- 一般都是Hook全局對(duì)象.
- 不只是可以Hook自定義,我們還可以Hook系統(tǒng)的對(duì)象屬性,?document.cookie
二. Chrome拓展(Chrome Extension)開發(fā)
1. 基本介紹
部分資料引用于 https://www.cnblogs.com/liuxianan/p/chrome-plugin-develop.html
1. 什么是Chrome插件?
? 嚴(yán)格來(lái)講,我們正在說(shuō)的東西應(yīng)該叫Chrome擴(kuò)展(Chrome Extension),真正意義上的Chrome插件是更底層的瀏覽器功能擴(kuò)展,可能需要對(duì)瀏覽器源碼有一定掌握才有能力去開發(fā)。鑒于Chrome插件的叫法已經(jīng)習(xí)慣,本文也全部采用這種叫法,但讀者需深知本文所描述的Chrome插件實(shí)際上指的是Chrome擴(kuò)展。
? Chrome插件是一個(gè)用Web技術(shù)開發(fā)、用來(lái)增強(qiáng)瀏覽器功能的軟件,它其實(shí)就是一個(gè)由HTML、CSS、JS、圖片等資源組成的一個(gè).crx后綴的壓縮包.
? 另外,其實(shí)不只是前端技術(shù),Chrome插件還可以配合C++編寫的dll動(dòng)態(tài)鏈接庫(kù)實(shí)現(xiàn)一些更底層的功能(NPAPI),比如全屏幕截圖。由于安全原因,Chrome瀏覽器42以上版本已經(jīng)陸續(xù)不再支持NPAPI插件,取而代之的是更安全的PPAPI。
2. 學(xué)習(xí)Chrome插件開發(fā)的意義
增強(qiáng)瀏覽器功能, 實(shí)現(xiàn)屬于自己的“定制版”瀏覽器。然后再本文中,我們則是需要通過(guò)學(xué)習(xí)Chrome瀏覽器插件的開發(fā),來(lái)實(shí)現(xiàn) JSHOOK 代碼的注入.
Chrome提供了非常多實(shí)用的API,包括但不限于:
- 書簽控制
- 下載控制
- 窗口控制
- 標(biāo)簽控制
- 網(wǎng)絡(luò)請(qǐng)求控制,各類事件堅(jiān)挺
- 自定義原生菜單
- 完善的通訊機(jī)制
- 等等
3. 為什么是Chrome插件,而不是firefox插件?
2. 文件結(jié)構(gòu)
Chrome插件沒有嚴(yán)格的項(xiàng)目結(jié)構(gòu)要求,只要保證本目錄有一個(gè)manifast.json即可.也不需要專門的IDE,普通的web開發(fā)工具即可。
從右上角菜單->更多工具->擴(kuò)展程序可以進(jìn)入 插件管理頁(yè)面,也可以直接在地址欄輸入chrome://extensions?訪問(wèn)。
勾選開發(fā)者模式即可以文件夾的形式直接加載插件,否則只能安裝.crx格式的文件。Chrome要求插件必須從它的Chrome應(yīng)用商店安裝,其它任何網(wǎng)站下載的都無(wú)法直接安裝,所以,其實(shí)我們可以把crx文件解壓,然后通過(guò)開發(fā)者模式直接加載。
開發(fā)中,代碼有任何改動(dòng)都必須重新加載插件,只需要在插件管理頁(yè)按下Ctrl+R即可,以防萬(wàn)一最好還把頁(yè)面刷新一下。
1. manifest.json
這是一個(gè)Chrome插件最重要也是必不可少的文件,用來(lái)配置所有和插件相關(guān)的配置,必須放在根目錄。其中,manifest_version、name、version3個(gè)是必不可少的,description和icons是推薦的。
{// 清單文件的版本,這個(gè)必須寫,而且必須是2"manifest_version": 2,// 插件的名稱"name": "demo",// 插件的版本"version": "1.0.0",// 插件描述"description": "簡(jiǎn)單的Chrome擴(kuò)展demo",// 圖標(biāo),一般偷懶全部用一個(gè)尺寸的也沒問(wèn)題"icons":{"16": "img/icon.png","48": "img/icon.png","128": "img/icon.png"},// 會(huì)一直常駐的后臺(tái)JS或后臺(tái)頁(yè)面"background":{// 2種指定方式,如果指定JS,那么會(huì)自動(dòng)生成一個(gè)背景頁(yè)"page": "background.html"//"scripts": ["js/background.js"]},// 瀏覽器右上角圖標(biāo)設(shè)置,browser_action、page_action、app必須三選一"browser_action": {"default_icon": "img/icon.png",// 圖標(biāo)懸停時(shí)的標(biāo)題,可選"default_title": "這是一個(gè)示例Chrome插件","default_popup": "popup.html"},// 當(dāng)某些特定頁(yè)面打開才顯示的圖標(biāo)/*"page_action":{"default_icon": "img/icon.png","default_title": "我是pageAction","default_popup": "popup.html"},*/// 需要直接注入頁(yè)面的JS"content_scripts": [{//"matches": ["http://*/*", "https://*/*"],// "<all_urls>" 表示匹配所有地址"matches": ["<all_urls>"],// 多個(gè)JS按順序注入"js": ["js/jquery-1.8.3.js", "js/content-script.js"],// JS的注入可以隨便一點(diǎn),但是CSS的注意就要千萬(wàn)小心了,因?yàn)橐徊恍⌒木涂赡苡绊懭謽邮?#34;css": ["css/custom.css"],// 代碼注入的時(shí)間,可選值: "document_start", "document_end", or "document_idle",最后一個(gè)表示頁(yè)面空閑時(shí),默認(rèn)document_idle"run_at": "document_start"},// 這里僅僅是為了演示content-script可以配置多個(gè)規(guī)則{"matches": ["*://*/*.png", "*://*/*.jpg", "*://*/*.gif", "*://*/*.bmp"],"js": ["js/show-image-content-size.js"]}],// 權(quán)限申請(qǐng)"permissions":["contextMenus", // 右鍵菜單"tabs", // 標(biāo)簽"notifications", // 通知"webRequest", // web請(qǐng)求"webRequestBlocking","storage", // 插件本地存儲(chǔ)"http://*/*", // 可以通過(guò)executeScript或者insertCSS訪問(wèn)的網(wǎng)站"https://*/*" // 可以通過(guò)executeScript或者insertCSS訪問(wèn)的網(wǎng)站],// 普通頁(yè)面能夠直接訪問(wèn)的插件資源列表,如果不設(shè)置是無(wú)法直接訪問(wèn)的"web_accessible_resources": ["js/inject.js"],// 插件主頁(yè),這個(gè)很重要,不要浪費(fèi)了這個(gè)免費(fèi)廣告位"homepage_url": "https://www.baidu.com",// 覆蓋瀏覽器默認(rèn)頁(yè)面"chrome_url_overrides":{// 覆蓋瀏覽器默認(rèn)的新標(biāo)簽頁(yè)"newtab": "newtab.html"},// Chrome40以前的插件配置頁(yè)寫法"options_page": "options.html",// Chrome40以后的插件配置頁(yè)寫法,如果2個(gè)都寫,新版Chrome只認(rèn)后面這一個(gè)"options_ui":{"page": "options.html",// 添加一些默認(rèn)的樣式,推薦使用"chrome_style": true},// 向地址欄注冊(cè)一個(gè)關(guān)鍵字以提供搜索建議,只能設(shè)置一個(gè)關(guān)鍵字"omnibox": { "keyword" : "go" },// 默認(rèn)語(yǔ)言"default_locale": "zh_CN",// devtools頁(yè)面入口,注意只能指向一個(gè)HTML文件,不能是JS文件"devtools_page": "devtools.html" }2. content-scripts
所謂content-scripts,其實(shí)就是Chrome插件中向頁(yè)面注入腳本的一種形式(雖然名為script,其實(shí)還可以包括css的),借助content-scripts我們可以實(shí)現(xiàn)通過(guò)配置的方式輕松向指定頁(yè)面注入JS和CSS(如果需要?jiǎng)討B(tài)注入,可以參考下文),最常見的比如:廣告屏蔽、頁(yè)面CSS定制,等等。
{// 需要直接注入頁(yè)面的JS"content_scripts": [{//"matches": ["http://*/*", "https://*/*"],// "<all_urls>" 表示匹配所有地址"matches": ["<all_urls>"],// 多個(gè)JS按順序注入"js": ["js/jquery-1.8.3.js", "js/content-script.js"],// JS的注入可以隨便一點(diǎn),但是CSS的注意就要千萬(wàn)小心了,因?yàn)橐徊恍⌒木涂赡苡绊懭謽邮?#34;css": ["css/custom.css"],// 代碼注入的時(shí)間,可選值: "document_start", "document_end", or "document_idle",最后一個(gè)表示頁(yè)面空閑時(shí),默認(rèn)document_idle"run_at": "document_start"}], }特別注意,如果沒有主動(dòng)指定run_at為document_start(默認(rèn)為document_idle),下面這種代碼是不會(huì)生效的:
document.addEventListener('DOMContentLoaded', function() {console.log('我被執(zhí)行了!'); });content-scripts和原始頁(yè)面共享DOM,但是不共享JS,如要訪問(wèn)頁(yè)面JS(例如某個(gè)JS變量),只能通過(guò)injected js來(lái)實(shí)現(xiàn)。content-scripts不能訪問(wèn)絕大部分chrome.xxx.api,除了下面這4種:
- chrome.extension(getURL , inIncognitoContext , lastError , onRequest , sendRequest)
- chrome.i18n
- chrome.runtime(connect , getManifest , getURL , id , onConnect , onMessage , sendMessage)
- chrome.storage
其實(shí)看到這里不要悲觀,這些API絕大部分時(shí)候都?jí)蛴昧?#xff0c;非要調(diào)用其它API的話,你還可以通過(guò)通信來(lái)實(shí)現(xiàn)讓background來(lái)幫你調(diào)用(關(guān)于通信,后文有詳細(xì)介紹)。
好了,Chrome插件給我們提供了這么強(qiáng)大的JS注入功能,剩下的就是發(fā)揮你的想象力去玩弄瀏覽器了。
3.background
后臺(tái)(姑且這么翻譯吧),是一個(gè)常駐的頁(yè)面,它的生命周期是插件中所有類型頁(yè)面中最長(zhǎng)的,它隨著瀏覽器的打開而打開,隨著瀏覽器的關(guān)閉而關(guān)閉,所以通常把需要一直運(yùn)行的、啟動(dòng)就運(yùn)行的、全局的代碼放在background里面。
background的權(quán)限非常高,幾乎可以調(diào)用所有的Chrome擴(kuò)展API(除了devtools),而且它可以無(wú)限制跨域,也就是可以跨域訪問(wèn)任何網(wǎng)站而無(wú)需要求對(duì)方設(shè)置CORS。
經(jīng)過(guò)測(cè)試,其實(shí)不止是background,所有的直接通過(guò)chrome-extension://id/xx.html這種方式打開的網(wǎng)頁(yè)都可以無(wú)限制跨域
配置中,background可以通過(guò)page指定一張網(wǎng)頁(yè),也可以通過(guò)scripts直接指定一個(gè)JS,Chrome會(huì)自動(dòng)為這個(gè)JS生成一個(gè)默認(rèn)的網(wǎng)頁(yè):
{// 會(huì)一直常駐的后臺(tái)JS或后臺(tái)頁(yè)面"background":{// 2種指定方式,如果指定JS,那么會(huì)自動(dòng)生成一個(gè)背景頁(yè)"page": "background.html"//"scripts": ["js/background.js"]}, }需要特別說(shuō)明的是,雖然你可以通過(guò)chrome-extension://xxx/background.html直接打開后臺(tái)頁(yè),但是你打開的后臺(tái)頁(yè)和真正一直在后臺(tái)運(yùn)行的那個(gè)頁(yè)面不是同一個(gè),換句話說(shuō),你可以打開無(wú)數(shù)個(gè)background.html,但是真正在后臺(tái)常駐的只有一個(gè),而且這個(gè)你永遠(yuǎn)看不到它的界面,只能調(diào)試它的代碼。
4. event-pages
這里順帶介紹一下event-pages,它是一個(gè)什么東西呢?鑒于background生命周期太長(zhǎng),長(zhǎng)時(shí)間掛載后臺(tái)可能會(huì)影響性能,所以Google又弄一個(gè)event-pages,在配置文件上,它與background的唯一區(qū)別就是多了一個(gè)persistent參數(shù):
{"background":{"scripts": ["event-page.js"],"persistent": false}, }它的生命周期是:在被需要時(shí)加載,在空閑時(shí)被關(guān)閉,什么叫被需要時(shí)呢?比如第一次安裝、插件更新、有content-script向它發(fā)送消息,等等。
除了配置文件的變化,代碼上也有一些細(xì)微變化,個(gè)人這個(gè)簡(jiǎn)單了解一下就行了,一般情況下background也不會(huì)很消耗性能的。
5. popup
popup是點(diǎn)擊browser_action或者page_action圖標(biāo)時(shí)打開的一個(gè)小窗口網(wǎng)頁(yè),焦點(diǎn)離開網(wǎng)頁(yè)就立即關(guān)閉,一般用來(lái)做一些臨時(shí)性的交互。
popup可以包含任意你想要的HTML內(nèi)容,并且會(huì)自適應(yīng)大小。可以通過(guò)default_popup字段來(lái)指定popup頁(yè)面,也可以調(diào)用setPopup()方法。
配置方式:
{"browser_action":{"default_icon": "img/icon.png",// 圖標(biāo)懸停時(shí)的標(biāo)題,可選"default_title": "這是一個(gè)示例Chrome插件","default_popup": "popup.html"} }需要特別注意的是,由于單擊圖標(biāo)打開popup,焦點(diǎn)離開又立即關(guān)閉,所以popup頁(yè)面的生命周期一般很短,需要長(zhǎng)時(shí)間運(yùn)行的代碼千萬(wàn)不要寫在popup里面。
在權(quán)限上,它和background非常類似,它們之間最大的不同是生命周期的不同,popup中可以直接通過(guò)chrome.extension.getBackgroundPage()獲取background的window對(duì)象。
6. injected-script
這里的injected-script是我給它取的,指的是通過(guò)DOM操作的方式向頁(yè)面注入的一種JS。為什么要把這種JS單獨(dú)拿出來(lái)討論呢?又或者說(shuō)為什么需要通過(guò)這種方式注入JS呢?
這是因?yàn)閏ontent-script有一個(gè)很大的“缺陷”,也就是無(wú)法訪問(wèn)頁(yè)面中的JS,雖然它可以操作DOM,但是DOM卻不能調(diào)用它,也就是無(wú)法在DOM中通過(guò)綁定事件的方式調(diào)用content-script中的代碼(包括直接寫onclick和addEventListener2種方式都不行),但是,“在頁(yè)面上添加一個(gè)按鈕并調(diào)用插件的擴(kuò)展API”是一個(gè)很常見的需求,那該怎么辦呢?其實(shí)這就是本小節(jié)要講的。
在content-script中通過(guò)DOM方式向頁(yè)面注入inject-script代碼示例:
// 向頁(yè)面注入JS function injectCustomJs(jsPath) {jsPath = jsPath || 'js/inject.js';var temp = document.createElement('script');temp.setAttribute('type', 'text/javascript');// 獲得的地址類似:chrome-extension://ihcokhadfjfchaeagdoclpnjdiokfakg/js/inject.jstemp.src = chrome.extension.getURL(jsPath);temp.onload = function(){// 放在頁(yè)面不好看,執(zhí)行完后移除掉this.parentNode.removeChild(this);};document.head.appendChild(temp); }你以為這樣就行了?執(zhí)行一下你會(huì)看到如下報(bào)錯(cuò):
Denying load of chrome-extension://efbllncjkjiijkppagepehoekjojdclc/js/inject.js. Resources must be listed in the web_accessible_resources manifest key in order to be loaded by pages outside the extension.- ?
意思就是你想要在web中直接訪問(wèn)插件中的資源的話必須顯示聲明才行,配置文件中增加如下:
{// 普通頁(yè)面能夠直接訪問(wèn)的插件資源列表,如果不設(shè)置是無(wú)法直接訪問(wèn)的"web_accessible_resources": ["js/inject.js"], }7.更多
更多關(guān)于Chrome Extension的開發(fā)請(qǐng)看博客https://www.cnblogs.com/liuxianan/p/chrome-plugin-develop.html
3.實(shí)戰(zhàn) - Js自動(dòng)注入Hook代碼
在2.2中,介紹了許許多多的Chrome的頁(yè)面各個(gè)作用. 接下來(lái)進(jìn)行實(shí)戰(zhàn).
1. manifest.json
由于我們是需要在網(wǎng)頁(yè)打開的時(shí)候, 立馬將我們的代碼注入進(jìn)去,這樣才能毫無(wú)遺漏的把一些操作給Hook出來(lái)。因此,我們的manifest.json文件應(yīng)該如下配置
{"manifest_version": 2,"name": "小胖JS自動(dòng)注入插件","version": "1.0","description": "小胖JS自動(dòng)注入插件,QQ2625112940","author": "xiaopang","icons":{"16":"ico.png","48": "icon.png","128": "icon.png"},"browser_action": {"default_icon": "icon.png","default_popup": "popup.html"},"content_scripts": [{"matches": ["<all_urls>"],"js": ["content-script.js"],"run_at": "document_start","all_frames": true}],"permissions":["<all_urls>","webRequest","webRequestBlocking","tabs","http://*/*","https://*/*","contextMenus","cookies","unlimitedStorage","notifications","storage","clipboardWrite"] }2. content_script.js
那么在瀏覽器中, 我們應(yīng)該要如何載入js文件呢?可以參照下面代碼
(function() {var spt = document.createElement('script');spt.innerHTML = `// ---- Cookie 監(jiān)聽var cookie_cache = document.cookie; // 獲取到原來(lái)的cookieObject.defineProperty(document,'cookie',{// 獲取Cookie時(shí),觸發(fā)的動(dòng)作get: function(){return cookie_cache; },//當(dāng)Cookie被設(shè)置的時(shí)候,觸發(fā)的動(dòng)作set: function(val){console.log('Cookies Setting',val);// debugger;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;})cookie_cache = cache.join("; ");if (!flag){cookie_cache += cookie + "; ";}this._value = val;return cookie_cache;}})// ----`document.documentElement.appendChild(spt); })();上面的例子是對(duì)Cookie進(jìn)行監(jiān)控的代碼,暫且忽略功能的實(shí)現(xiàn)問(wèn)題. 就單純看創(chuàng)建Script的過(guò)程, 其實(shí)就是下面這點(diǎn)而已.
(function() {var spt = document.createElement('script');spt.innerHTML = `// 業(yè)務(wù)邏輯代碼`document.documentElement.appendChild(spt); })();下面再祭出一些注入的業(yè)務(wù)邏輯代碼
//HOOK JSON stringifyvar rstringify = JSON.stringify;JSON.stringify = function(a){console.log("Detect Json.stringify", a);//debugger;return rstringify(a);}//HOOK json parse//var strparse = JSON.parse//JSON.parse = function(b){//console.log("Detect Json.Parse", b);//return strparse(b);//}//var plugins_cache = window.navigator//Object.defineProperty(navigator, 'plugins', {// get: function() {// console.log('Getting plugins');// //debugger;// return plugins_cache;// },// set: function(val) {// console.log('獲取信息');// console.log(val);// debugger;// },//});var _eval = eval;eval = function(e){_eval(e.replace("debugger",""));}eval.toString = _eval.toString;var _Function = Function;Function = function(e){_Function(e.replace("debugger",""));}Function.toString = _Function.toString;var _constructor = constructor;Function.prototype.constructor = function(s) {if (s == "debugger"){console.log(s);return null;}return _constructor(s);}三. 調(diào)試技巧
1. 快速定位關(guān)鍵代碼
- initiator函數(shù)堆棧
- callstack函數(shù)堆棧
- xhr斷點(diǎn)
- JS HOOK
2. Conditional breakpoints
在代碼左邊的行號(hào) - > 右鍵 -> Edit breakpoints -> 然后輸入表達(dá)式, 結(jié)果=true的時(shí)候會(huì)自動(dòng)斷下
3. Reres拓展插件
筆者使用該插件一般情況:
一般情況下是遇到大文件的時(shí)候,會(huì)使用Reres插件,或者需要修改代碼進(jìn)行調(diào)試的時(shí)候
Github地址:https://github.com/annnhan/ReRes
添加規(guī)則
點(diǎn)擊“添加規(guī)則”按鈕,輸入以下信息,然后保存:
- If URL match: 一個(gè)正則表達(dá)式,當(dāng)請(qǐng)求的URL與之匹配時(shí),規(guī)則生效。注意:不要填開頭的/和結(jié)束的/gi,如/.*/gi請(qǐng)寫成.*
- Response: 映射的響應(yīng)地址,這個(gè)地址會(huì)替換掉url中與上面正則匹配的部分。線上地址請(qǐng)以http://開頭,本地地址以file:///開頭,比如http://cssha.com或file:///D:/a.js
練習(xí)網(wǎng)站:
- https://www.cls.cn/ 登錄的password
- http://api.51pin.foxconn.com/iRecruitWeb/Recruit/Activity/ActivityParticipate.html?module=2
4. monitor監(jiān)聽方法
5. monitorEvents監(jiān)聽方法
6. watch監(jiān)聽變量
7.控制臺(tái)實(shí)時(shí)表達(dá)式
四. 實(shí)戰(zhàn)
1. webpack整體改寫方案
其實(shí)就是在webpack命名的函數(shù). webpack中,會(huì)有需要的
var aaa = n(12);
var bbb = n(45);
我們對(duì)于webpack的網(wǎng)站,我自認(rèn)為不適合用扣算法,不適合用缺少補(bǔ)啥的方法,誰(shuí)能知道n(*)里面還有沒有嵌套其他的n呢. 所以我認(rèn)為用整體改寫就是一個(gè)好的辦法.
整體改寫的思路如下:
1. 找到加密位置
2. 查到當(dāng)前方法實(shí)現(xiàn)代碼,整體拿下.
類似這種的就拿下.
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push( "aaa":function(e,t,r){}, "bbb":functino(e,t,r){} )()3. 找到"n"函數(shù)聲明位置.
一般類似于這樣, 具體如何說(shuō)我好像沒法表達(dá). 也是整個(gè)文件拿下一般.
!function(e) {function r(r) {for (var n, a, i = r[0], c = r[1], l = r[2], p = 0, s = []; p < i.length; p++)a = i[p],Object.prototype.hasOwnProperty.call(o, a) && o[a] && s.push(o[a][0]),o[a] = 0;for (n in c)Object.prototype.hasOwnProperty.call(c, n) && (e[n] = c[n]);for (f && f(r); s.length; )s.shift()();return u.push.apply(u, l || []),t()}function t() {for (var e, r = 0; r < u.length; r++) {for (var t = u[r], n = !0, i = 1; i < t.length; i++) {var c = t[i];0 !== o[c] && (n = !1)}n && (u.splice(r--, 1),e = a(a.s = t[0]))}return e}var n = {}, o = {1: 0}, u = [];function a(r) {if (n[r])return n[r].exports;var t = n[r] = {i: r,l: !1,exports: {}}, o = !0;try {e[r].call(t.exports, t, t.exports, a),o = !1} finally {o && delete n[r]}return t.l = !0,t.exports}a.e = function(e) {var r = [], t = o[e];if (0 !== t)if (t)r.push(t[2]);else {var n = new Promise((function(r, n) {t = o[e] = [r, n]}));r.push(t[2] = n);var u, i = document.createElement("script");i.charset = "utf-8",i.timeout = 120,a.nc && i.setAttribute("nonce", a.nc),i.src = function(e) {return a.p + "static/chunks/" + ({}[e] || e) + "." + {53: "6d99d4eacdc1f6ea047f",54: "cbec7184fead9e811bbf"}[e] + ".js"}(e);var c = new Error;u = function(r) {i.onerror = i.onload = null,clearTimeout(l);var t = o[e];if (0 !== t) {if (t) {var n = r && ("load" === r.type ? "missing" : r.type), u = r && r.target && r.target.src;c.message = "Loading chunk " + e + " failed.\n(" + n + ": " + u + ")",c.name = "ChunkLoadError",c.type = n,c.request = u,t[1](c)}o[e] = void 0}};var l = setTimeout((function() {u({type: "timeout",target: i})}), 12e4);i.onerror = i.onload = u,document.head.appendChild(i)}return Promise.all(r)},a.m = e,a.c = n,a.d = function(e, r, t) {a.o(e, r) || Object.defineProperty(e, r, {enumerable: !0,get: t})},a.r = function(e) {"undefined" !== typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, {value: "Module"}),Object.defineProperty(e, "__esModule", {value: !0})},a.t = function(e, r) {if (1 & r && (e = a(e)),8 & r)return e;if (4 & r && "object" === typeof e && e && e.__esModule)return e;var t = Object.create(null);if (a.r(t),Object.defineProperty(t, "default", {enumerable: !0,value: e}),2 & r && "string" != typeof e)for (var n in e)a.d(t, n, function(r) {return e[r]}.bind(null, n));return t},a.n = function(e) {var r = e && e.__esModule ? function() {return e.default}: function() {return e};return a.d(r, "a", r),r},a.o = function(e, r) {return Object.prototype.hasOwnProperty.call(e, r)},a.p = "",a.oe = function(e) {throw console.error(e),e};var i = window.webpackJsonp = window.webpackJsonp || [], c = i.push.bind(i);i.push = r,i = i.slice();for (var l = 0; l < i.length; l++)r(i[l]);var f = c;t() }([]);4. window.n = a;
!function(e) {function r(r) {for (var n, a, i = r[0], c = r[1], l = r[2], p = 0, s = []; p < i.length; p++)a = i[p],Object.prototype.hasOwnProperty.call(o, a) && o[a] && s.push(o[a][0]),o[a] = 0;for (n in c)Object.prototype.hasOwnProperty.call(c, n) && (e[n] = c[n]);for (f && f(r); s.length; )s.shift()();return u.push.apply(u, l || []),t()}function t() {for (var e, r = 0; r < u.length; r++) {for (var t = u[r], n = !0, i = 1; i < t.length; i++) {var c = t[i];0 !== o[c] && (n = !1)}n && (u.splice(r--, 1),e = a(a.s = t[0]))}return e}var n = {}, o = {1: 0}, u = [];function a(r) {if (n[r])return n[r].exports;var t = n[r] = {i: r,l: !1,exports: {}}, o = !0;try {e[r].call(t.exports, t, t.exports, a),o = !1} finally {o && delete n[r]}return t.l = !0,t.exports}a.e = function(e) {var r = [], t = o[e];if (0 !== t)if (t)r.push(t[2]);else {var n = new Promise((function(r, n) {t = o[e] = [r, n]}));r.push(t[2] = n);var u, i = document.createElement("script");i.charset = "utf-8",i.timeout = 120,a.nc && i.setAttribute("nonce", a.nc),i.src = function(e) {return a.p + "static/chunks/" + ({}[e] || e) + "." + {53: "6d99d4eacdc1f6ea047f",54: "cbec7184fead9e811bbf"}[e] + ".js"}(e);var c = new Error;u = function(r) {i.onerror = i.onload = null,clearTimeout(l);var t = o[e];if (0 !== t) {if (t) {var n = r && ("load" === r.type ? "missing" : r.type), u = r && r.target && r.target.src;c.message = "Loading chunk " + e + " failed.\n(" + n + ": " + u + ")",c.name = "ChunkLoadError",c.type = n,c.request = u,t[1](c)}o[e] = void 0}};var l = setTimeout((function() {u({type: "timeout",target: i})}), 12e4);i.onerror = i.onload = u,document.head.appendChild(i)}return Promise.all(r)},a.m = e,a.c = n,a.d = function(e, r, t) {a.o(e, r) || Object.defineProperty(e, r, {enumerable: !0,get: t})},a.r = function(e) {"undefined" !== typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, {value: "Module"}),Object.defineProperty(e, "__esModule", {value: !0})},a.t = function(e, r) {if (1 & r && (e = a(e)),8 & r)return e;if (4 & r && "object" === typeof e && e && e.__esModule)return e;var t = Object.create(null);if (a.r(t),Object.defineProperty(t, "default", {enumerable: !0,value: e}),2 & r && "string" != typeof e)for (var n in e)a.d(t, n, function(r) {return e[r]}.bind(null, n));return t},a.n = function(e) {var r = e && e.__esModule ? function() {return e.default}: function() {return e};return a.d(r, "a", r),r},a.o = function(e, r) {return Object.prototype.hasOwnProperty.call(e, r)},a.p = "",a.oe = function(e) {throw console.error(e),e};var i = window.webpackJsonp = window.webpackJsonp || [], c = i.push.bind(i);i.push = r,i = i.slice();for (var l = 0; l < i.length; l++)r(i[l]);var f = c;t()// 重要**** window.n = a;// 重要**** }([]);2. sojson反調(diào)試
案例地址:https://www.sojson.com/beian/
1. 修改setInterval
如何定位不說(shuō)了, 直接走到關(guān)鍵的地方
window[b('96', 'lInO')](function() { //b('96', 'lInO') == "setInterval"var cf = {'gSHOk': function(cg) {return cg(); //cg()其實(shí)就是一個(gè)檢測(cè)debug的函數(shù).}};cf['gSHOk'](en); }, 0x7d0);為了不影響到其他setInterval函數(shù)的執(zhí)行. 這里可以加一點(diǎn)條件.
var _setInterval = setInterval; setInterval = function(a,b){console.log(a + '',b)if(a.indexOf("gSHOk':function(cg){return cg();}")!= -1){return 'setInterval is Kill'}_setInterval(a,b) }2. Conditional breakpoints
這里打開調(diào)試工具會(huì)直接跳到下面這一塊,我們這節(jié)對(duì)debugger;行號(hào)欄目, 右鍵?add conditional breakpoints, 輸入false . 當(dāng)條件為false的時(shí)候,就不會(huì)執(zhí)行此條件.
function eC(eD) {var eE = {'oihUc': b('161', '!9L9'),'YSZMe': ep[b('162', 'bhfu')]};if (ep[b('163', 'QS!f')](b('164', '1$&&'), ep[b('165', 'C5IH')])) {en();} else {if (typeof eD === ep[b('166', '18LM')]) {var eG = function() {if (eE[b('167', 'tEyN')] !== eE[b('168', 'Gq^E')]) {debugger ;} else {so[b('169', 'eOuM')](res[b('16a', 'w2W4')]);}};return ep['bzKJh'](eG);} else {if (ep[b('16b', 'IIR5')](ep[b('16c', 'BDu]')]('', eD / eD)[ep[b('16d', '(igu')]], 0x1) || eD % 0x14 === 0x0) {debugger ;} else {debugger ;}}ep['RwYcr'](eC, ++eD);} }3. 函數(shù)替換,函數(shù)置空
4. Activate breakpoints
直接快捷鍵. Ctrl + F8
5. 修改debugger
(貌似失效了)
簡(jiǎn)單點(diǎn)的
Function.prototype.constructor = function(){}完善點(diǎn)
Function.prototype.__constructor_back = Function.prototype.constructor; Function.prototype.constructor = function() {if(arguments && typeof arguments[0]==='string'){//alert("new function: "+ arguments[0]);if("debugger" === arguments[0]){//arguments[0]="console.log(\"anti debugger\");";//arguments[0]=";";return}}return Function.prototype.__constructor_back.apply(this,arguments); }總結(jié):個(gè)人認(rèn)為,最好用的方法應(yīng)該是1,2,4了. 操作簡(jiǎn)單.
3. 某視頻反調(diào)試案例
http://peng3.com/vip?a=https%3A%2F%2F2.08bk.com%2F%3Furl%3D%0D%0A&url=http%3A%2F%2F1.zhananhome.applinzi.com%2Fwx
//定位到這邊. jdetects.create(function(e) {var a = 0;var n = setInterval(function() {if ("on" === e) {setTimeout(function() {if (a === 0) {a = 1;setTimeout(Base64.decode(code));}}, 200);}}, 100);- ?
注入JS代碼
var _setInterval = setInterval; setInterval = function(a,b){console.log(a + '',b)if(a+''.indexOf("setTimeout(Base64.decode(code));")!= -1){return 'Debugger is Kill'}_setInterval(a,b) }解決這個(gè)以后又發(fā)現(xiàn)個(gè)驚人的操作.在控制臺(tái)發(fā)現(xiàn)Console was cleared
function o() {window.Firebug && window.Firebug.chrome && window.Firebug.chrome.isInitialized ? t("on") : (a = "off",console.log(d),("undefined" !== typeof console.clear) && console.clear(),t(a)); }修改下o方法
o = function(){}或者在上面的setInterval代碼加多個(gè)條件. 原因是向上跟蹤發(fā)現(xiàn)以下代碼
var f = setInterval(o, i); var _setInterval = setInterval; setInterval = function(a,b){console.log(a + '',b)if( a + ''.indexOf("setTimeout(Base64.decode(code));")!= -1){return 'Debugger is Kill'}if (a + ''.indexOf('console.clear')!=-1){return 'console.clear is Kill'}_setInterval(a,b) }4. 自寫算法案例 -1
5. 自寫算法案例 -2
6. JS混淆原理(eval和Function)
7. JS混淆原理(數(shù)字混淆和字符串混淆)
8. 五秒防火墻fuckjs原理分析改寫
9. 流程控制混淆原理(switch)
10. 流程控制混淆原理(逗號(hào)運(yùn)算符)
五.AST入門與實(shí)戰(zhàn)
1. AST抽象語(yǔ)法樹入門
2. Babel組件traverse
3. Babel組件types
4. 用Babel生成一個(gè)新函數(shù)
5. Babel中節(jié)點(diǎn)操作
6. 用Babel給函數(shù)加點(diǎn)料
7. 用Babel實(shí)現(xiàn)變量名混淆
7. 用Babel實(shí)現(xiàn)數(shù)組亂序
8. 用Babel實(shí)現(xiàn)字符串加密
9. 實(shí)現(xiàn)十六進(jìn)制文本加密
10. 實(shí)現(xiàn)unicode加密
11. JS混淆還原(字符串解密)
12. JS混淆還原(去除花指令)
13. JS混淆還原(AST節(jié)點(diǎn)調(diào)試技巧)
14. switch流程平坦化還原(復(fù)原指令順序)
15. JS混淆實(shí)戰(zhàn)案例
六. 滑塊破解
1. 云片
2. 2980
總結(jié)
- 上一篇: Python弹窗提示警告框Message
- 下一篇: 算法设计TSP问题动态规划