主頁 >  其他 > JS逆向學習筆記 - 持續更新中

JS逆向學習筆記 - 持續更新中

2020-11-12 20:36:50 其他

JS逆向學習筆記

尋找深圳爬蟲作業,微信:cjh-18888

文章目錄

  • JS逆向學習筆記
    • 一. JS Hook
      • 1. JS HOOK 原理和作用
        • 原理:替換原來的方法. (好像寫了句廢話)
        • 作用: 可以去Hook一些內置的函式, 例如Debugger, setInterval,JSON.stringify等等
      • 2.JSHook 檢測與過檢測
        • 原理: 其實就是檢測代碼是否和原來的相等.
        • 繞過手段: 修改Function的toString方法.
      • 3.JS過反除錯
      • 4. JSHook 物件屬性
        • 1. Object.defindPropety()
    • 二. Chrome拓展(Chrome Extension)開發
      • 1. 基本介紹
        • 1. 什么是Chrome插件?
        • 2. 學習Chrome插件開發的意義
        • 3. 為什么是Chrome插件,而不是firefox插件?
      • 2. 檔案結構
        • 1. manifest.json
        • 2. content-scripts
        • 3.background
        • 4. event-pages
        • 5. popup
        • 6. injected-script
        • 7.更多
      • 3.實戰 - Js自動注入Hook代碼
        • 1. manifest.json
        • 2. content_script.js
    • 三. 除錯技巧
      • 1. 快速定位關鍵代碼
      • 2. Conditional breakpoints
      • 3. Reres拓展插件
      • 4. monitor監聽方法
      • 5. monitorEvents監聽方法
      • 6. watch監聽變數
      • 7.控制臺實時運算式
    • 四. 實戰
      • 1. webpack整體改寫方案
          • 整體改寫的思路如下:
            • 1. 找到加密位置
            • 2. 查到當前方法實作代碼,整體拿下.
            • 3. 找到"n"函式宣告位置.
            • 4. window.n = a;
      • 2. sojson反除錯
        • 1. 修改setInterval
        • 2. Conditional breakpoints
        • 3. 函式替換,函式置空
        • 4. Activate breakpoints
        • 5. 修改debugger
        • 總結:個人認為,最好用的方法應該是1,2,4了. 操作簡單.
      • 3. 某視頻反除錯案例
      • 4. 自寫演算法案例 -1
      • 5. 自寫演算法案例 -2
      • 6. JS混淆原理(eval和Function)
      • 7. JS混淆原理(數字混淆和字串混淆)
      • 8. 五秒防火墻fuckjs原理分析改寫
      • 9. 流程控制混淆原理(switch)
      • 10. 流程控制混淆原理(逗號運算子)
    • 五.AST入門與實戰
      • 1. AST抽象語法樹入門
      • 2. Babel組件traverse
      • 3. Babel組件types
      • 4. 用Babel生成一個新函式
      • 5. Babel中節點操作
      • 6. 用Babel給函式加點料
      • 7. 用Babel實作變數名混淆
      • 7. 用Babel實作陣列亂序
      • 8. 用Babel實作字串加密
      • 9. 實作十六進制文本加密
      • 10. 實作unicode加密
      • 11. JS混淆還原(字串解密)
      • 12. JS混淆還原(去除花指令)
      • 13. JS混淆還原(AST節點除錯技巧)
      • 14. switch流程平坦化還原(復原指令順序)
      • 15. JS混淆實戰案例
    • 六. 滑塊破解
      • 1. 云片
      • 2. 2980

一. JS Hook

1. JS HOOK 原理和作用

原理:替換原來的方法. (好像寫了句廢話)

function test(aa,bb){
    cc = aa + bb;
    return cc;
}

Hook代碼:

var _test = test;  // 拿到test
test = function(x,y){
    console.log(x,y); //輸出拿到的引數
    var retval = _test(x,y); // retval 是原來的計算結果
    console.log( retval)
    return retval + 1 // 修改回傳結果
}

此時重新呼叫test, 結果比正常值多了1

作用: 可以去Hook一些內置的函式, 例如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 檢測與過檢測

原理: 其實就是檢測代碼是否和原來的相等.

案例代碼:

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被修改了')
}

此時我們可以把hook代碼置入到瀏覽器

//控制臺置入的代碼
var _test = test; 
test = function(x,y){
    console.log(x,y); 
    var retval = _test(x,y); 
    console.log( retval)
    return retval 
}

繞過手段: 修改Function的toString方法.

Function.prototype.toString=function(){
	return "function test(x,y){z=x+y;return z;}";
}

3.JS過反除錯

反除錯代碼:

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("過了檢測就會給你正確答案哦!");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)")()

通過上面的代碼決議, 我們可以看到,debugger其實就是通過setInterval方法來呼叫的. 那么我們其實可以寫這個過除錯代碼.

4. JSHook 物件屬性

Hook物件屬性需要使用到

Object.defineProperty() //方法會直接在一個物件上定義一個新屬性,或者修改一個物件的現有屬性,并回傳此物件, | 這個常用一些.
Object.defineProperties() // 方法直接在一個物件上定義新的屬性或修改現有屬性,并回傳該物件,

1. Object.defindPropety()

下面這個是定義了一個案例. 我們使用Object.defindProperty()來修改屬性物件的set

var obj = {
    'name': function(){
        return 'xiaopang';
    }
}

然后我們撰寫Hook代碼.

Object.defineProperty(obj,'name',{
    'set':function(x){
        console.log(x)
        return x;
    }
})

Hook注意點:

  • 物件需要創建以后方可Hook
  • 一般都是Hook全域物件.
  • 不只是可以Hook自定義,我們還可以Hook系統的物件屬性, document.cookie

二. Chrome拓展(Chrome Extension)開發

1. 基本介紹

部分資料參考于 https://www.cnblogs.com/liuxianan/p/chrome-plugin-develop.html

1. 什么是Chrome插件?

? 嚴格來講,我們正在說的東西應該叫Chrome擴展(Chrome Extension),真正意義上的Chrome插件是更底層的瀏覽器功能擴展,可能需要對瀏覽器原始碼有一定掌握才有能力去開發,鑒于Chrome插件的叫法已經習慣,本文也全部采用這種叫法,但讀者需深知本文所描述的Chrome插件實際上指的是Chrome擴展,

? Chrome插件是一個用Web技術開發、用來增強瀏覽器功能的軟體,它其實就是一個由HTML、CSS、JS、圖片等資源組成的一個.crx后綴的壓縮包.

? 另外,其實不只是前端技術,Chrome插件還可以配合C++撰寫的dll元件實作一些更底層的功能(NPAPI),比如全螢屏截圖,由于安全原因,Chrome瀏覽器42以上版本已經陸續不再支持NPAPI插件,取而代之的是更安全的PPAPI,

2. 學習Chrome插件開發的意義

增強瀏覽器功能, 實作屬于自己的“定制版”瀏覽器,然后再本文中,我們則是需要通過學習Chrome瀏覽器插件的開發,來實作 JSHOOK 代碼的注入.

Chrome提供了非常多實用的API,包括但不限于:

  • 書簽控制
  • 下載控制
  • 視窗控制
  • 標簽控制
  • 網路請求控制,各類事件堅挺
  • 自定義原生選單
  • 完善的通訊機制
  • 等等

3. 為什么是Chrome插件,而不是firefox插件?

  1. Chrome的市場占有率更高.
  2. 開發簡單
  3. 應用場景更廣泛,Firefox插件只能運行在Firefox上,而Chrome除了Chrome瀏覽器之外,還可以運行在所有webkit內核的國產瀏覽器,比如360極速瀏覽器、360安全瀏覽器、搜狗瀏覽器、QQ瀏覽器等等;
  4. 除此之外,Firefox瀏覽器也對Chrome插件的運行提供了一定的支持;

2. 檔案結構

Chrome插件沒有嚴格的專案結構要求,只要保證本目錄有一個manifast.json即可.也不需要專門的IDE,普通的web開發工具即可,

從右上角選單->更多工具->擴展程式可以進入 插件管理頁面,也可以直接在地址欄輸入 chrome://extensions 訪問,

勾選開發者模式即可以檔案夾的形式直接加載插件,否則只能安裝.crx格式的檔案,Chrome要求插件必須從它的Chrome應用商店安裝,其它任何網站下載的都無法直接安裝,所以,其實我們可以把crx檔案解壓,然后通過開發者模式直接加載,

開發中,代碼有任何改動都必須重新加載插件,只需要在插件管理頁按下Ctrl+R即可,以防萬一最好還把頁面重繪一下,

1. manifest.json

這是一個Chrome插件最重要也是必不可少的檔案,用來配置所有和插件相關的配置,必須放在根目錄,其中,manifest_versionnameversion3個是必不可少的,descriptionicons是推薦的,

{
	// 清單檔案的版本,這個必須寫,而且必須是2
	"manifest_version": 2,
	// 插件的名稱
	"name": "demo",
	// 插件的版本
	"version": "1.0.0",
	// 插件描述
	"description": "簡單的Chrome擴展demo",
	// 圖示,一般偷懶全部用一個尺寸的也沒問題
	"icons":
	{
		"16": "img/icon.png",
		"48": "img/icon.png",
		"128": "img/icon.png"
	},
	// 會一直常駐的后臺JS或后臺頁面
	"background":
	{
		// 2種指定方式,如果指定JS,那么會自動生成一個背景頁
		"page": "background.html"
		//"scripts": ["js/background.js"]
	},
	// 瀏覽器右上角圖示設定,browser_action、page_action、app必須三選一
	"browser_action": 
	{
		"default_icon": "img/icon.png",
		// 圖示懸停時的標題,可選
		"default_title": "這是一個示例Chrome插件",
		"default_popup": "popup.html"
	},
	// 當某些特定頁面打開才顯示的圖示
	/*"page_action":
	{
		"default_icon": "img/icon.png",
		"default_title": "我是pageAction",
		"default_popup": "popup.html"
	},*/
	// 需要直接注入頁面的JS
	"content_scripts": 
	[
		{
			//"matches": ["http://*/*", "https://*/*"],
			// "<all_urls>" 表示匹配所有地址
			"matches": ["<all_urls>"],
			// 多個JS按順序注入
			"js": ["js/jquery-1.8.3.js", "js/content-script.js"],
			// JS的注入可以隨便一點,但是CSS的注意就要千萬小心了,因為一不小心就可能影響全域樣式
			"css": ["css/custom.css"],
			// 代碼注入的時間,可選值: "document_start", "document_end", or "document_idle",最后一個表示頁面空閑時,默認document_idle
			"run_at": "document_start"
		},
		// 這里僅僅是為了演示content-script可以配置多個規則
		{
			"matches": ["*://*/*.png", "*://*/*.jpg", "*://*/*.gif", "*://*/*.bmp"],
			"js": ["js/show-image-content-size.js"]
		}
	],
	// 權限申請
	"permissions":
	[
		"contextMenus", // 右鍵選單
		"tabs", // 標簽
		"notifications", // 通知
		"webRequest", // web請求
		"webRequestBlocking",
		"storage", // 插件本地存盤
		"http://*/*", // 可以通過executeScript或者insertCSS訪問的網站
		"https://*/*" // 可以通過executeScript或者insertCSS訪問的網站
	],
	// 普通頁面能夠直接訪問的插件資源串列,如果不設定是無法直接訪問的
	"web_accessible_resources": ["js/inject.js"],
	// 插件主頁,這個很重要,不要浪費了這個免費廣告位
	"homepage_url": "https://www.baidu.com",
	// 覆寫瀏覽器默認頁面
	"chrome_url_overrides":
	{
		// 覆寫瀏覽器默認的新標簽頁
		"newtab": "newtab.html"
	},
	// Chrome40以前的插件配置頁寫法
	"options_page": "options.html",
	// Chrome40以后的插件配置頁寫法,如果2個都寫,新版Chrome只認后面這一個
	"options_ui":
	{
		"page": "options.html",
		// 添加一些默認的樣式,推薦使用
		"chrome_style": true
	},
	// 向地址欄注冊一個關鍵字以提供搜索建議,只能設定一個關鍵字
	"omnibox": { "keyword" : "go" },
	// 默認語言
	"default_locale": "zh_CN",
	// devtools頁面入口,注意只能指向一個HTML檔案,不能是JS檔案
	"devtools_page": "devtools.html"
}

2. content-scripts

所謂content-scripts,其實就是Chrome插件中向頁面注入腳本的一種形式(雖然名為script,其實還可以包括css的),借助content-scripts我們可以實作通過配置的方式輕松向指定頁面注入JS和CSS(如果需要動態注入,可以參考下文),最常見的比如:廣告屏蔽、頁面CSS定制,等等,

{
	// 需要直接注入頁面的JS
	"content_scripts": 
	[
		{
			//"matches": ["http://*/*", "https://*/*"],
			// "<all_urls>" 表示匹配所有地址
			"matches": ["<all_urls>"],
			// 多個JS按順序注入
			"js": ["js/jquery-1.8.3.js", "js/content-script.js"],
			// JS的注入可以隨便一點,但是CSS的注意就要千萬小心了,因為一不小心就可能影響全域樣式
			"css": ["css/custom.css"],
			// 代碼注入的時間,可選值: "document_start", "document_end", or "document_idle",最后一個表示頁面空閑時,默認document_idle
			"run_at": "document_start"
		}
	],
}

特別注意,如果沒有主動指定run_atdocument_start(默認為document_idle),下面這種代碼是不會生效的:

document.addEventListener('DOMContentLoaded', function()
{
	console.log('我被執行了!');
});

content-scripts和原始頁面共享DOM,但是不共享JS,如要訪問頁面JS(例如某個JS變數),只能通過injected js來實作,content-scripts不能訪問絕大部分chrome.xxx.api,除了下面這4種:

  • chrome.extension(getURL , inIncognitoContext , lastError , onRequest , sendRequest)
  • chrome.i18n
  • chrome.runtime(connect , getManifest , getURL , id , onConnect , onMessage , sendMessage)
  • chrome.storage

其實看到這里不要悲觀,這些API絕大部分時候都夠用了,非要呼叫其它API的話,你還可以通過通信來實作讓background來幫你呼叫(關于通信,后文有詳細介紹),

好了,Chrome插件給我們提供了這么強大的JS注入功能,剩下的就是發揮你的想象力去玩弄瀏覽器了,

3.background

后臺(姑且這么翻譯吧),是一個常駐的頁面,它的生命周期是插件中所有型別頁面中最長的,它隨著瀏覽器的打開而打開,隨著瀏覽器的關閉而關閉,所以通常把需要一直運行的、啟動就運行的、全域的代碼放在background里面,

background的權限非常高,幾乎可以呼叫所有的Chrome擴展API(除了devtools),而且它可以無限制跨域,也就是可以跨域訪問任何網站而無需要求對方設定CORS

經過測驗,其實不止是background,所有的直接通過chrome-extension://id/xx.html這種方式打開的網頁都可以無限制跨域

配置中,background可以通過page指定一張網頁,也可以通過scripts直接指定一個JS,Chrome會自動為這個JS生成一個默認的網頁:

{
	// 會一直常駐的后臺JS或后臺頁面
	"background":
	{
		// 2種指定方式,如果指定JS,那么會自動生成一個背景頁
		"page": "background.html"
		//"scripts": ["js/background.js"]
	},
}

需要特別說明的是,雖然你可以通過chrome-extension://xxx/background.html直接打開后臺頁,但是你打開的后臺頁和真正一直在后臺運行的那個頁面不是同一個,換句話說,你可以打開無數個background.html,但是真正在后臺常駐的只有一個,而且這個你永遠看不到它的界面,只能除錯它的代碼,

4. event-pages

這里順帶介紹一下event-pages,它是一個什么東西呢?鑒于background生命周期太長,長時間掛載后臺可能會影響性能,所以Google又弄一個event-pages,在組態檔上,它與background的唯一區別就是多了一個persistent引數:

{
	"background":
	{
		"scripts": ["event-page.js"],
		"persistent": false
	},
}

它的生命周期是:在被需要時加載,在空閑時被關閉,什么叫被需要時呢?比如第一次安裝、插件更新、有content-script向它發送訊息,等等,

除了組態檔的變化,代碼上也有一些細微變化,個人這個簡單了解一下就行了,一般情況下background也不會很消耗性能的,

5. popup

popup是點擊browser_action或者page_action圖示時打開的一個小視窗網頁,焦點離開網頁就立即關閉,一般用來做一些臨時性的互動,

博客園網摘插件popup效果

popup可以包含任意你想要的HTML內容,并且會自適應大小,可以通過default_popup欄位來指定popup頁面,也可以呼叫setPopup()方法,

配置方式:

{
	"browser_action":
	{
		"default_icon": "img/icon.png",
		// 圖示懸停時的標題,可選
		"default_title": "這是一個示例Chrome插件",
		"default_popup": "popup.html"
	}
}

img

需要特別注意的是,由于單擊圖示打開popup,焦點離開又立即關閉,所以popup頁面的生命周期一般很短,需要長時間運行的代碼千萬不要寫在popup里面,

在權限上,它和background非常類似,它們之間最大的不同是生命周期的不同,popup中可以直接通過chrome.extension.getBackgroundPage()獲取background的window物件,

6. injected-script

這里的injected-script是我給它取的,指的是通過DOM操作的方式向頁面注入的一種JS,為什么要把這種JS單獨拿出來討論呢?又或者說為什么需要通過這種方式注入JS呢?

這是因為content-script有一個很大的“缺陷”,也就是無法訪問頁面中的JS,雖然它可以操作DOM,但是DOM卻不能呼叫它,也就是無法在DOM中通過系結事件的方式呼叫content-script中的代碼(包括直接寫onclickaddEventListener2種方式都不行),但是,“在頁面上添加一個按鈕并呼叫插件的擴展API”是一個很常見的需求,那該怎么辦呢?其實這就是本小節要講的,

content-script中通過DOM方式向頁面注入inject-script代碼示例:

// 向頁面注入JS
function injectCustomJs(jsPath)
{
	jsPath = jsPath || 'js/inject.js';
	var temp = document.createElement('script');
	temp.setAttribute('type', 'text/javascript');
	// 獲得的地址類似:chrome-extension://ihcokhadfjfchaeagdoclpnjdiokfakg/js/inject.js
	temp.src = chrome.extension.getURL(jsPath);
	temp.onload = function()
	{
		// 放在頁面不好看,執行完后移除掉
		this.parentNode.removeChild(this);
	};
	document.head.appendChild(temp);
}

你以為這樣就行了?執行一下你會看到如下報錯:

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中直接訪問插件中的資源的話必須顯示宣告才行,組態檔中增加如下:

{
	// 普通頁面能夠直接訪問的插件資源串列,如果不設定是無法直接訪問的
	"web_accessible_resources": ["js/inject.js"],
}

7.更多

更多關于Chrome Extension的開發請看博客https://www.cnblogs.com/liuxianan/p/chrome-plugin-develop.html

3.實戰 - Js自動注入Hook代碼

在2.2中,介紹了許許多多的Chrome的頁面各個作用. 接下來進行實戰.

1. manifest.json

由于我們是需要在網頁打開的時候, 立馬將我們的代碼注入進去,這樣才能毫無遺漏的把一些操作給Hook出來,因此,我們的manifest.json檔案應該如下配置

{
	"manifest_version": 2,
	"name": "小胖JS自動注入插件",
	"version": "1.0",
	"description": "小胖JS自動注入插件,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

那么在瀏覽器中, 我們應該要如何載入js檔案呢?可以參照下面代碼

(function() {
	var spt = document.createElement('script');
	
	
	spt.innerHTML = `
		
		
		// ---- Cookie 監聽
		var cookie_cache = document.cookie; // 獲取到原來的cookie

		Object.defineProperty(document,'cookie',{

			// 獲取Cookie時,觸發的動作
			get: function(){
				return cookie_cache; 
			},

			//當Cookie被設定的時候,觸發的動作
			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);
})();

上面的例子是對Cookie進行監控的代碼,暫且忽略功能的實作問題. 就單純看創建Script的程序, 其實就是下面這點而已.

(function() {
	var spt = document.createElement('script');
	spt.innerHTML = `
		// 業務邏輯代碼
	`
	document.documentElement.appendChild(spt);
})();

下面再祭出一些注入的業務邏輯代碼

    //HOOK JSON stringify
    var 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);
	}
	

三. 除錯技巧

1. 快速定位關鍵代碼

  • initiator函式堆疊
  • callstack函式堆疊
  • xhr斷點
  • JS HOOK

2. Conditional breakpoints

在代碼左邊的行號 - > 右鍵 -> Edit breakpoints -> 然后輸入運算式, 結果=true的時候會自動斷下

3. Reres拓展插件

筆者使用該插件一般情況:

一般情況下是遇到大檔案的時候,會使用Reres插件,或者需要修改代碼進行除錯的時候

Github地址:https://github.com/annnhan/ReRes

添加規則

點擊“添加規則”按鈕,輸入以下資訊,然后保存:

  • If URL match: 一個正則運算式,當請求的URL與之匹配時,規則生效,注意:不要填開頭的/和結束的/gi,如/.*/gi請寫成.*
  • Response: 映射的回應地址,這個地址會替換掉url中與上面正則匹配的部分,線上地址請以http://開頭,本地地址以file:///開頭,比如http://cssha.comfile:///D:/a.js

練習網站:

  • https://www.cls.cn/ 登錄的password
  • http://api.51pin.foxconn.com/iRecruitWeb/Recruit/Activity/ActivityParticipate.html?module=2

4. monitor監聽方法

5. monitorEvents監聽方法

6. watch監聽變數

7.控制臺實時運算式

四. 實戰

1. webpack整體改寫方案

其實就是在webpack命名的函式. webpack中,會有需要的

var aaa = n(12);

var bbb = n(45);

我們對于webpack的網站,我自認為不適合用扣演算法,不適合用缺少補啥的方法,誰能知道n(*)里面還有沒有嵌套其他的n呢. 所以我認為用整體改寫就是一個好的辦法.

整體改寫的思路如下:
1. 找到加密位置
2. 查到當前方法實作代碼,整體拿下.

類似這種的就拿下.

(window["webpackJsonp"]=window["webpackJsonp"]||[]).push(
"aaa":function(e,t,r){},
"bbb":functino(e,t,r){}
)()
3. 找到"n"函式宣告位置.

一般類似于這樣, 具體如何說我好像沒法表達. 也是整個檔案拿下一般.

!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反除錯

案例地址:https://www.sojson.com/beian/

1. 修改setInterval

如何定位不說了, 直接走到關鍵的地方

window[b('96', 'lInO')](function() { //b('96', 'lInO') == "setInterval"
    var cf = {
        'gSHOk': function(cg) {
            return cg(); //cg()其實就是一個檢測debug的函式.
        }
    };
    cf['gSHOk'](en);
}, 0x7d0);

為了不影響到其他setInterval函式的執行. 這里可以加一點條件.

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

這里打開除錯工具會直接跳到下面這一塊,我們這節對debugger;行號欄目, 右鍵 add conditional breakpoints, 輸入false . 當條件為false的時候,就不會執行此條件.

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. 函式替換,函式置空

4. Activate breakpoints

直接快捷鍵. Ctrl + F8

5. 修改debugger

(貌似失效了)

簡單點的

Function.prototype.constructor = function(){}

完善點

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);
}

總結:個人認為,最好用的方法應該是1,2,4了. 操作簡單.

3. 某視頻反除錯案例

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)
}

解決這個以后又發現個驚人的操作.在控制臺發現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代碼加多個條件. 原因是向上跟蹤發現以下代碼

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混淆原理(數字混淆和字串混淆)

8. 五秒防火墻fuckjs原理分析改寫

9. 流程控制混淆原理(switch)

10. 流程控制混淆原理(逗號運算子)

五.AST入門與實戰

1. AST抽象語法樹入門

2. Babel組件traverse

3. Babel組件types

4. 用Babel生成一個新函式

5. Babel中節點操作

6. 用Babel給函式加點料

7. 用Babel實作變數名混淆

7. 用Babel實作陣列亂序

8. 用Babel實作字串加密

9. 實作十六進制文本加密

10. 實作unicode加密

11. JS混淆還原(字串解密)

12. JS混淆還原(去除花指令)

13. JS混淆還原(AST節點除錯技巧)

14. switch流程平坦化還原(復原指令順序)

15. JS混淆實戰案例

六. 滑塊破解

1. 云片

2. 2980

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/212482.html

標籤:其他

上一篇:淺拷貝與深拷貝多種實作

下一篇:還在踩坑?帶你使用webpack快速構建web專案

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more