一. 前言
這里主要是寫對於hook知識的一個理解和對於市面的混淆做出一個他的解法, 相當於一個總和
二. hook
什么是hook? Hook技術又叫做鈎子函數,在系統沒有調用該函數之前,鈎子程序就先捕獲該消息,鈎子函數先得到控制權,這時鈎子函數既可以加工處理(改變)該函數的執行行為,還可以強制結束消息的傳遞。簡單來說,就是把系統的程序拉出來變成我們自己執行代碼片段。在程序中我們可以把他理解為劫持。
在js中的hook,替換原函數的都可以理解為hook,那么我們就有個疑問了,我們為什么可以hook呢, 原因就是我們客戶端擁有最高解釋權,可以決定在任何時候注入hook,而服務器無法阻止,只能通過檢測hook或者混淆,讓其難度加大。這里我強烈推薦一篇文章, 可以讓你理解hook知識:https://mp.weixin.qq.com/s/IYFyjVrVkHtUdCzn9arkJQ。hook當然還有一個插件,那就是油猴,關於油猴就不在這里面過多描述了,可百度。
fillder中的JS替換
這里hook需要着重理解的就是object.defineProperty():
Object.defineProperty(obj, prop, descriptor)是基本語法,作用就是在一個對象上面定義一個新的屬性,或修改一個對象現有的屬性。
接收三個參數如下:
obj: 需要定義屬性的對象.
prop: 當前需要定義的屬性名, 也就是你要hook的屬性
descriptor:屬性的描述符, 可以取以下的值:
這里寫一個hook cookie的一個列子:
1 Object.defineProperty(document, 'cookie', { 2 set:function(val){ 3 debugger; 4 return val 5 } 6 })
這里第一個就是當前需要定義的對象, 第二個就是你要hook的屬性, 第三個就是描述符了。
在 Hook 中,使用最多的是存取描述符,即 get 和 set。
get:屬性的 getter 函數,如果沒有 getter,則為 undefined,當訪問該屬性時,會調用此函數,執行時不傳入任何參數,但是會傳入 this 對象(由於繼承關系,這里的 this 並不一定是定義該屬性的對象),該函數的返回值會被用作屬性的值。
set:屬性的 setter 函數,如果沒有 setter,則為 undefined,當屬性值被修改時,會調用此函數,該方法接受一個參數,也就是被賦予的新值,會傳入賦值時的 this 對象。
列子的話大家可以在我貼的上面代碼實現, 需要注意的是,網站加載時首先要運行我們的 Hook 代碼,再運行網站自己的代碼,才能夠成功斷下,或者用fillder替換。這個過程我們可以稱之為 Hook 代碼的注入,下面寫幾種注入hook獲取屬性方法。
Hook Cookie
Object.defineProperty(document, 'cookie', { set:function(val){ debugger; return val } })
Hook Header
Header Hook 用於定位 Header 中關鍵參數生成位置,以下代碼演示了當 Header 中包含 Authorization
關鍵字時,則插入斷點:
(function () { var org = window.XMLHttpRequest.prototype.setRequestHeader; window.XMLHttpRequest.prototype.setRequestHeader = function (key, value) { if (key == 'Authorization') { debugger; } return org.apply(this, arguments); }; })();
Hook URL
URL Hook 用於定位請求 URL 中關鍵參數生成位置,以下代碼演示了當請求的 URL 里包含 login
關鍵字時,則插入斷點:
(function () { var open = window.XMLHttpRequest.prototype.open; window.XMLHttpRequest.prototype.open = function (method, url, async) { if (url.indexOf("login") != -1) { debugger; } return open.apply(this, arguments); }; })();
Hook JSON.stringify
JSON.stringify()
方法用於將 JavaScript 值轉換為 JSON 字符串,在某些站點的加密過程中可能會遇到,以下代碼演示了遇到 JSON.stringify()
時,則插入斷點:
(function() { var stringify = JSON.stringify; JSON.stringify = function(params) { console.log("Hook JSON.stringify ——> ", params); debugger; return stringify(params); } })();
Hook JSON.parse
JSON.parse()
方法用於將一個 JSON 字符串轉換為對象,在某些站點的加密過程中可能會遇到,以下代碼演示了遇到 JSON.parse()
時,則插入斷點:
(function() { var parse = JSON.parse; JSON.parse = function(params) { console.log("Hook JSON.parse ——> ", params); debugger; return parse(params); } })();
ob混淆
ob混淆呢具有以下特征:
1. 具有大數組的情況
2. 數組移位(有內存泄露風險、建議不格式化),自執行函數,進行移位操作,有明顯的 push、shift 關鍵字
3.解密函數(有內存泄露風險、建議不格式化)------可能有定時器--------(看加密的開關開啟數量)
4.實際代碼+控制流平坦化(整體ob的強度幾乎完全取決於這段的代碼強度,這里面是加密前的邏輯)
5.控制流平坦化+無限debugger自執行函數+死代碼注入。一般情況下不會有業務邏輯所以不要問,ob、sojson如何破解。這些東西只是一層殼,破解強度完全取決於第四段代碼,也就是其他網站作者寫的代碼強度!
6.函數名和變量名通常以 _0x 或者 0x 開頭,后接 1~6 位數字或字母組合;
解決方法呢:上面也講了,還有就是AST解碼混淆 推薦和猿人學的解混淆http://tool.yuanrenxue.com/,或者你硬剛也是可以的。
列如猿人學的第二題
通過上面的列子我們可以知道運用hook的知識, 然后硬剛基本還是可以的, 不過遇到了復雜的混淆, hook是hook不到的 只能從頭開始跟。
JJEncode混淆
jjencode是日本的Yosuke HASEGAWA在2009年開發的,它可以將任意 JavaScript 編碼為僅使用 18 個符號的混淆形式 []()!+,\"$.:;_{}~=。
缺點:JJEncode 易於解碼,它不是實用的混淆,只是一個編碼器,JJEncode很容易被檢測,而且還瀏覽器依賴,它的缺點是壓棧很嚴重,如果 JS 很大,去做加密可能內存溢出,所以只適合核心功能加密,事實上 JJEncode 商用的還是很少,不過認識一下並沒有什么壞處。
舉例:
這一個正常的代碼。
然后這是混淆過后的代碼
解決辦法:
1:控制台執行報錯,且非unsafe錯誤:點擊報錯信息即可還原代碼
2:控制台執行不報錯,刪除一些語法(以括號為主),強制令其報錯
3:控制台報unsafe錯誤:自寫個html運行,然后刪除語法令其報錯即可還原
AAEncode混淆
跟JJencode , jsfuck一個作者,方法都是差不多 在控制台進行打印。上面那幾種方法都適用
解決方法:
1:去掉代碼最后一個符號 ('_') 后,放到瀏覽器里面去直接執行就可以看到源碼
2:在線調試,在 AAEncode 代碼第一行下斷點,然后一步一步執行,最終也會在虛擬機(VM)里看到源碼
jsFuck混淆
jsfuck都是差不多的,方法跟上面都適用, 不過會有一種jsfuck技術在控制台打印他也顯示不出來,他是在jsfuck套了一層,比如你想知道a 但是你控制台打印出來是b.
這種的解決辦法是:在混淆前面打上debugger,然后在控制台一步一步的調試。跟到生成a的代碼里面。這是唯一需要注意的一個點。其他基本差不多