篇幅有限
完整內(nèi)容及源碼關(guān)注公眾號:ReverseCode,發(fā)送 沖
當(dāng)我們拿到一個網(wǎng)站時沈自,首先就是抓包定位加密參數(shù)的實現(xiàn)鸠删,本文將通過常用的定位方案結(jié)合實際案例完成對加密參數(shù)的分析喉脖。
搜索關(guān)鍵參數(shù)
這是最常見也是最簡單的定位方案,F(xiàn)12打開網(wǎng)站控制臺后稳捆,Ctrl+Shift+F打開搜索面板执赡,比如搜索password參數(shù)或者submit函數(shù)
password:`,`password=`,`password =`請求url绽昼,搜索方法`var submit`或者`function submit`或者`submit:
to8to
搜索password
位置太多纺非,由于抓包請求是new_login.php
在Element面板中搜索new_login.php
,ctrl+shift+f 搜索loginCheck
該方法中jq('#rsa_userNum').val(rsaString(password));
舱馅,調(diào)用rsaString方法加密password
function rsaString(str) {
return encodeURIComponent(RSAUtilszb.encryptfun(str));
}
進入encryptfun
定義的js中缰泡,rsa加密最少2000行,該方法不過163行代嗤,拷貝該js通過編程貓專用工具中的JS調(diào)試工具棘钞,加載代碼,報錯引用錯誤: window 未定義
资溃,添加var window = this;
,報錯引用錯誤: JSEncrypt 未定義
,添加原js中var JSEncrypt = JSEncryptExports.JSEncrypt;
武翎,報錯引用錯誤: JSEncryptExports 未定義
,搜索var JSEncryptExports
,將var JSEncryptExports = {};
添加到JS調(diào)試工具溶锭,報錯類型錯誤: JSEncrypt is not a constructor
嘗試打上斷點宝恶,但是每次都不能進入斷點,說明肯定是動態(tài)加載的js趴捅,且每次刷新js后綴會有時間戳垫毙。勾選Disable cache,打開fiddler抓包,將js拷貝到本地實現(xiàn)http欺騙拱绑,選中該請求點擊AutoResponder-Add Rule下拉選擇Find a File,找到本地保存的js并開啟規(guī)則
由于每次js請求地址不一樣综芥,使用正則匹配regex:https://static\.to8to\.com/gb_js/to8torsaszb\.js\?_=\d+
并保存規(guī)則重新發(fā)起請求https://static.to8to.com/gb_js/to8torsaszb.js?_=1628128571412
,使用本地js欺騙網(wǎng)絡(luò)請求js
將整個js格式化找到之前報錯JSEncrypt is not a constructor
是從上面的壓縮的js中export出來的
將上面壓縮的代碼添加到編程貓的JS調(diào)試工具中加載代碼猎拨,報錯引用錯誤: navigator 未定義
膀藐,添加var navigator = {}
,報錯引用錯誤: window 未定義
红省,添加var window =this
,因為如果用window ={}
報錯ASN1 未定義
,而用this則可以拿到當(dāng)前js中所有的變量函數(shù)额各。
dom元素事件監(jiān)聽
通過控制臺的Elements中的Event Listeners
逐個排除按鈕的Remove
節(jié)點,直到最后一個Event Listeners
使按鈕無效吧恃,拿到該按鈕真正生效的js位置虾啦。
中煙新商盟
以下通過dom元素事件監(jiān)聽實現(xiàn)對該j_mcmm
加密參數(shù)邏輯定位分析。
以上通過盡可能多的地方打上斷點,監(jiān)聽元素事件定位到j(luò)smain-9826b285f8fad5a5.js
傲醉,左下角格式化js后添加斷點蝇闭,在js頁面ctrl查看所有變量值
鼠標(biāo)懸停,或者控制臺打印出來硬毕,點擊進入方法聲明時打上斷點呻引,為同一行中的函數(shù)打上斷點,F(xiàn)8單步調(diào)試,完成加密參數(shù)的定位
xhr斷點
通過定位發(fā)包函數(shù)跟棧昭殉,復(fù)制網(wǎng)址請求路徑到Sources下的XHR/fetch Breakpoints苞七,支持正則。
七麥數(shù)據(jù)
通過關(guān)鍵加密參數(shù)analysis
搜索無果挪丢,嘗試在Sources中加入XHR斷點,以請求路徑作為斷點內(nèi)容
XHR斷點后追溯調(diào)用棧卢厂,查看每個調(diào)用棧的出入?yún)⑹欠癜用芎蟮?code>analysis,直到進入Promise異步l.request
乾蓬,單步調(diào)試到n.then(t.shift(), t.shift())
,then作為Promise的異步函數(shù),promise.then(onCompleted, onRejected);
慎恒,而shift()
通過逐條調(diào)用t中的方法任内,參數(shù)是上一個方法的返回值,同時刪除該方法融柬,相當(dāng)于隊列先進先出死嗦。控制臺打印t粒氧,逐個方法進入打上斷點
在l.prototype.request
中暫時還沒生成analysis
加密參數(shù)越除,逐個進入t方法中
執(zhí)行完r().interceptors.request.use
該方法后生成的a就是analysis
,觀察該代碼中的邏輯完成加密分析外盯。a=(0,n.cv)((0,n.oZ)(r, l))
作為逗號表達式摘盆,由上圖分析n.cv和n.oZ是函數(shù),r和l是變量饱苟,可以還原為n.cv(n.oz(r,l))
孩擂。
通過控制臺獲取n中的函數(shù)
window = global;
window.document = {
cookie: '' // 這邊帶上自己的cookie
}
function i(e) {
var t, a = (t = "",
["66", "72", "6f", "6d", "43", "68", "61", "72", "43", "6f", "64", "65"].forEach((function (e) {
t += unescape("%u00" + e)
}
)),
t);
return String[a](e)
}
function s() {
return unescape("861831832863830866861836861862839831831839862863839830865834861863837837830830837839836861835833".replace(/8/g, "%u00"))
}
var n = {
oZ: function g(e, t) {
t || (t = s());
for (var a = (e = e.split("")).length, n = t.length, o = "charCodeAt", r = 0; r < a; r++)
e[r] = i(e[r][o](0) ^ t[(r + 10) % n][o](0));
return e.join("")
},
cv: function h(e) {
return function (e) {
try {
return btoa(e)
} catch (t) {
return Buffer.from(e).toString("base64")
}
}(encodeURIComponent(e).replace(/%([0-9A-F]{2})/g, (function (e, t) {
return i("0x" + t)
}
)))
},
ej: function u(e) {
var t, a = new RegExp("(^| )" + e + "=([^;]*)(;|$)");
return (t = document.cookie.match(a)) ? unescape(t[2]) : null
}
}
由于btoa本質(zhì)就是base64加密,通過引入CryptoJS.pad.js后
function base64(data) {
var wordArray = CryptoJS.enc.Utf8.parse(data);
var base64_data = CryptoJS.enc.Base64.stringify(wordArray);
return base64_data
}
var n = {
oZ: function g(e, t) {
t || (t = s());
for (var a = (e = e.split("")).length, n = t.length, o = "charCodeAt", r = 0; r < a; r++)
e[r] = i(e[r][o](0) ^ t[(r + 10) % n][o](0));
return e.join("")
},
cv: function h(e) {
return function (e) {
try {
return base64(e)
} catch (t) {
return Buffer.from(e).toString("base64")
}
}(encodeURIComponent(e).replace(/%([0-9A-F]{2})/g, (function (e, t) {
return i("0x" + t)
}
)))
},
ej: function u(e) {
var t, a = new RegExp("(^| )" + e + "=([^;]*)(;|$)");
return (t = document.cookie.match(a)) ? unescape(t[2]) : null
}
}
將try/catch中邏輯還原
var l = "00000008d78d46a"
var d = "@#"
var e = {
// url: "/rank/indexPlus/brand_id/1",
url: "/rank/indexPlus/brand_id/" + pg, // 1.免費榜 0.付費 2.暢銷榜
baseURL: "https://api.qimai.cn",
}
var c = {
default: function On(e) {
this._init(e)
}
}
var u = "synct"
var t = (0, n.ej)(u);
var m = "syncd"
var f = f = c.default.prototype.difftime = -(0, n.ej)(m) || +new Date - 1e3 * t
var o = +new Date - (f || 0) - 1515125653845
var r = []
r = r.sort().join(""), r = (0, n.cv)(r), r += d + e.url.replace(e.baseURL, ""), r += d + o, r += d + 1,
a_ = (0, n.cv)((0, n.oZ)(r, l))
return a_
Initiator棧追蹤
Network下的發(fā)包請求的Initiator箱熬,如jquery堆棧的頂層斷點(可能會請求多次类垦,找到發(fā)包請求時進入的斷點),重新請求找到堆棧中屬于目標(biāo)網(wǎng)站的js格式化斷點城须。
升學(xué)e網(wǎng)通
登錄抓包蚤认,打開Initiator,進入堆棧頂層定位的代碼行
打上斷點酿傍,查看右側(cè)調(diào)用棧烙懦,逐個方法往底層去調(diào)用,直到react庫js找到了preLogin,找到出現(xiàn)password的位置氯析,打上斷點
再次登錄時亏较,進入斷點,找到password
進入加密方法中掩缓,aes加密
打開WT-JS中的Crypto類復(fù)制key和iv雪情,輸出以HEX的十六進制格式,對比結(jié)果是標(biāo)準(zhǔn)的AES加密你辣。
基于base64或十六進制的AES加解密實現(xiàn)見aes.js
長房集團
搜索j_password
后打斷點巡通,重新登錄
進入desEncrypt
中,大致加密完成邏輯就在該函數(shù)中
加密邏輯中首先根據(jù)SECURITYKEY.get()
獲取到key舍哄,首先通過請求后端拿到str宴凉,判斷加密類型是否為aes后截取字符串通過toHexString
轉(zhuǎn)成十六進制拿到key和iv和security
整理完邏輯扣出js報錯CryptoJS is not defined
,點擊進入CryptoJS.AES.encrypt
扣出來aes.js源碼
function getdes(encodeType) {
// 請求"/resource/js/session.jsp?_=1628210376229"返回
var str = "E55A433905551AC39DB3165591D9CD74";
if (encodeType == null || encodeType == 'aes') {
if (str.length < 32) {
str += "abcdefghijklmnopqrstuvwxyz1234567890"
}
str = str.toUpperCase();
var key = {};
key.key = str.substring(0, 16);
key.iv = str.substring(16, 32);
key.security = "\u4435\u5320\u4d35"
} else {
if (str.length < 16) {
str += "abcdefghijklmnopqrstuvwxyz"
}
str = str.toUpperCase();
var key = {};
key.key = toHexString(str.substring(0, 8));
key.iv = toHexString(str.substring(8, 16));
key.security = "\u4445\u5320\u4d45"
}
return key
}
function getPwd(value, type) {
var keyObj = {};
if (type == null || "aes" == type.toLowerCase()) {
keyObj = getdes()
value = CryptoJS.AES.encrypt(value, CryptoJS.enc.Utf8.parse(keyObj.key), {
iv: CryptoJS.enc.Utf8.parse(keyObj.iv)
}).toString()
} else {
keyObj = getdes()('des');
value = CryptoJS.DES.encrypt(value, CryptoJS.enc.Hex.parse(keyObj.key), {
iv: CryptoJS.enc.Hex.parse(keyObj.iv)
})
}
return keyObj.security + value
}
安裝編程貓插件
- fiddler 版本必須 >= v4.6.3,復(fù)制
Fiddler 編程貓專用插件
到fiddler程序目錄下的Scripts目錄中示例:C:\Program Files (x86)\Fiddler2\Scripts
愛奇藝
- 覆蓋原函數(shù)
function xxx(){
console.log("1111")
}
var xxx_ = xxx;
xxx = function(){
console.log("2222")
}
window.alert = function(){console.log("?")}
console.clear = function(){console.log("?")}
setInterval = function(){}
- Object.defineProperty替換對象屬性(getter.setter)
(function () {
var a = "";
Object.defineProperty(document, 'cookie', {
set: function (val) {
console.log('Hook捕獲到cookie設(shè)置->', val);
a = val;
return val;
},
get: function(){
return a;
}
});
})();
document.cookie = "1" // 設(shè)置
document.cookie // 獲取
- hook的時機在控制臺注入的hook表悬,刷新網(wǎng)頁就失效了弥锄,過濾Network的js找到第一個加載的js,右鍵Open in Sources panel格式化蟆沫,第一行斷點籽暇,不過有些cookie可能異步可能在html中js生成,在控制臺中注入以上hook饭庞,清除cookie戒悠,手動注入hook,控制臺中找到VM虛擬機找到我們的hook的js打上斷點舟山,绸狐,每次hook都會經(jīng)過set,右側(cè)就可以查看調(diào)用棧捏顺,追溯cookie的來源與加密方式六孵。(有可能注入hook的時機會晚于部分異步請求或者html中的js)
- 利用fiddler代理所有請求替換響應(yīng),編程貓專用工具注入hook
(function () {
'use strict';
Object.defineProperty(document, 'cookie', {
set: function (val) {
if (val.indexOf("__dfp") != -1) {
debugger;
}
console.log('Hook捕獲到cookie設(shè)置->', val);
return val;
}
});
})();
接下來查看調(diào)用棧,最終保存到window.name中幅骄。
(function () {
'use strict';
var a = "";
Object.defineProperty(window, 'name', {
set: function (val) {
debugger;
a = val;
console.log('Hook捕獲到cookie設(shè)置->', val);
return val;
},
get: function(){
return a;
}
});
})();
重新進入iqiyi劫窒,斷點完成hook定位從而可以根據(jù)調(diào)用棧分析cookie的生成邏輯。
本文由博客群發(fā)一文多發(fā)等運營工具平臺 OpenWrite 發(fā)布