Python 爬蟲進(jìn)階必備 | 某惠農(nóng)網(wǎng)行情大廳加密參數(shù)分析
第一時(shí)間關(guān)注Python技術(shù)干貨!

今日網(wǎng)站
aHR0cHM6Ly9tLmNuaG5iLmNvbS9oYW5ncWluZy8=
這個(gè)站來自讀者投稿

看了下網(wǎng)站比較有分析意義,所以今天就分析下這個(gè)文章
抓包分析與加密定位
這個(gè)網(wǎng)站需要分析得參數(shù)如下

并且提交得參數(shù)里并沒有特別需要注意得參數(shù)
可以通過上一篇提及得幾種方法定位到參數(shù)加密的地方
不清楚得可以點(diǎn)下方藍(lán)字跳轉(zhuǎn)
Python 爬蟲進(jìn)階必備 | 某器件商城加密參數(shù) sign 的分析
我們通過xhr斷點(diǎn)可以找到下面這個(gè)位置

進(jìn)去之后就可以看到一段混淆后的代碼了

并且在最后會(huì)生成我們需要得加密參數(shù),并返回


所以我們需要搞清楚這個(gè)t.default都做了什么操作,并且參數(shù)是怎么來的。
加密分析
可以看到t.default傳入了兩個(gè)參數(shù)一個(gè)是e一個(gè)是head,最后也是把這個(gè)head返回回去的

這里的e可以理解為一個(gè)上下文變量,這里的head才是需要分析的重點(diǎn)

可以看到在剛剛進(jìn)入這個(gè)方法的時(shí)候,head就已經(jīng)有一些值了,并且這個(gè)值就開始參與接下來的計(jì)算了
要搞清楚加密,就先要把head里的值搞清楚
如果翻堆棧,因?yàn)榻?jīng)過了異步比較難定位,要找到head初始參數(shù)
第一、可以像上面說的翻堆棧,定位的代碼如下

第二、可以搜索X-HN-JOB的值,就是那個(gè)一長串句子
If?you?see?these?message,?I?hope?you?dont?hack?us,?I?hope?you?can?join?us!?Please?visit?https://www.xxx.com/job.html

這一長串的句子是不變的,可以快速定位

這里逐個(gè)打上斷點(diǎn)就可以定位到參數(shù)的生成邏輯了
X-B3-TRACEID
toBase36(t.getTime(),?9)?+?toBase36(randomInt(0,?78364164095),?7)
X-CLIENT-TIME
t.getTime()
X-CLIENT-NONCE
newUUID?=?function(e)?{
?var?t?=?(new?Date).getTime();
?return?(e???"xxxxxxxxxxxxxyxxxxyxxxxxxxxxxxxx"?:?"xxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxx").replace(/[xy]/g,?(function(e)?{var?n?=?(t?+?16?*?Math.random())?%?16?|?0;return?t?=?Math.floor(t?/?16),("x"?==?e???n?:?3?&?n?|?8).toString(16)}))
?}
X-CLIENT-ID
X-CLIENT-ID?=?function(e)?{
????var?t?=?(new?Date).getTime();
????return?(e???"xxxxxxxxxxxxxyxxxxyxxxxxxxxxxxxx"?:?"xxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxx").replace(/[xy]/g,?(function(e)?{
????????????var?n?=?(t?+?16?*?Math.random())?%?16?|?0;
????????????return?t?=?Math.floor(t?/?16),
????????????????("x"?==?e???n?:?3?&?n?|?8).toString(16)
????????}
????))
}
獲取完這個(gè)幾個(gè)初始化參數(shù)之后,開始進(jìn)入t.default這個(gè)方法計(jì)算x-sign的值。
這個(gè)方法的最后計(jì)算出一個(gè)I,這個(gè)I經(jīng)過(0,c.default)()得到最終的結(jié)果
因?yàn)檫@個(gè)方法最后返回了一個(gè)很長的逗號(hào)表達(dá)式,所以我們直接從最后一步開始看

最后這里的I,未經(jīng)過計(jì)算的時(shí)候是一長串字符串,像是 4 個(gè) hash 的結(jié)果用!拼接起來了
這樣就可以大概知道I是經(jīng)過下面這個(gè)代碼得出的

經(jīng)過分析這個(gè)t又是遍歷自P中的元素
所以我們分析的重點(diǎn)轉(zhuǎn)而去分析P
繼續(xù)向上,可以看到P由下面的四個(gè)元素組成
P?=?[F,?A,?$,?T]
現(xiàn)在問題就可以拆成F, A, $, T是怎么得到的
所以繼續(xù)向上看
可以看到大部分的未知參數(shù)都是由類似下面的三元表達(dá)式計(jì)算出來的
F?=?1?===?(y?=?D)???(0,
????????????o.default)(v)["toS"?+?H("0x5",?"7sY@")?+?"ng"]()?:?2?===?y???(0,
????????????r.default)(v)[H("0x8",?"up@!")?+?H("0x68",?"%M3Q")?+?"ng"]()?:?3?===?y???(0,
????????????l.default)(v)[H("0x11",?"g0vo")?+?"tring"]()?:?void?0
要一個(gè)一個(gè)斷點(diǎn)調(diào)試分析他們是經(jīng)過了哪個(gè)表達(dá)式
這里感興趣的可以自己分析下哈
我調(diào)試之后知道這四個(gè)參數(shù)都是經(jīng)過了中間那個(gè)表達(dá)式計(jì)算出來的
這四個(gè)參數(shù)由可以變成下面的四行代碼
F?=??(0,r.default)(v)[H("0x8",?"up@!")?+?H("0x68",?"%M3Q")?+?"ng"]()
A?=?(0,o.default)(m)[H("0x14",?"3MMx")?+?"tring"]()
$?=??(0,r.default)(w?+?_)["toS"?+?H("0x38",?"voet")?+?"ng"]()
T?=?d[H("0x40",?"%M3Q")?+?"mSt"?+?H("0x60",?"oChJ")?+?"g"](W,?!0,?16)["toU"?+?H("0x1b",?"Cbz8")?+?H("0x22",?"zwd1")?+?"d"]()[H("0x52",?"wXa9")?+?"tring"](10)
以上代碼反混淆之后是下面這樣的
F?=??(0,r.default)(v)['toString']()
A?=?(0,o.default)(m)['toString']()
$?=??(0,r.default)(w?+?_)["toString"]()
T?=?d['fromString'](W,?!0,?16)["toUnsigned"]()['toString'](10)
這里就需要逐個(gè)拆出來分析了
參數(shù) F
F 中未知的是v,v是由V經(jīng)過(V = (h = Q).nonce得到的
而Q中的nonce就是上面?zhèn)魅氲?code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(71, 193, 168);">X-CLIENT-NONCE
X-CLIENT-NONCE經(jīng)過(0,r.default)()處理后得出F
分析可以知道(0,r.default)()是md5
分析思路見上次的文章
Python 爬蟲進(jìn)階必備 | 某器件商城加密參數(shù) sign 的分析


參數(shù) A
A 中未知的是m參數(shù),這個(gè)m參數(shù)由m = R = h.timestamp得到
這個(gè)h的參數(shù)是String(head[H("0x28", "g0vo") + "LIE" + H("0x49", "J7to") + H("0x53", "9GkD") + "E"])得到的
就是String(head['X-CLIENT-TIME'])得到的
這里的(0,o.default)()經(jīng)過分析是sha1
分析思路見上次的文章
Python 爬蟲進(jìn)階必備 | 某器件商城加密參數(shù) sign 的分析


參數(shù) $
$ 中未知的參數(shù)是w、_兩個(gè),由_ = E,w = V可以知道w就是X-CLIENT-NONCE,然后_ = E = h.deviceId
這里的h.deviceId就是head["X-CLIENT-ID"]
經(jīng)過(0,r.default)()就是md5的計(jì)算得出


參數(shù) T
這里的 T 傳入了參數(shù)W
W?=?W['substring'](W['length']?-?16,?W['length']?-?1)
這里只對W進(jìn)行了剪切,主要的生成部分如下
?W?=?(0,o.default)(S?+?M)['toString']()
未知的參數(shù)是S,M,這兩個(gè)參數(shù)可由S = j,M = R得出
R就是h.timestamp = String(head['X-CLIENT-TIME'])
j是一串字符串
j?=?h.secret?=?e[H("0x42",?"&J@X")?+?"v"][H("0x2b",?"jOT4")?+?"pp"]???L?:?B???N?:?G
上面一串字符串最終得到的是
H("0x4c",?"aq3T")?+?H("0x59",?"9GkD")?+?H("0x2e",?"h2!t")?+?H("0x34",?"3MMx")?+?H("0x13",?"voet")?+?H("0xd",?"xaTo")?+?H("0x35",?"%M3Q")?+?H("0x15",?"3MMx")?+?H("0x21",?"&J@X")?+?"gnAcr"
反正就是混淆,然后解混淆然再拼接
這里的(0,o.default)()就是sha1,結(jié)果再進(jìn)行了切片取倒數(shù)的16 位到倒 2 位為結(jié)果



這個(gè)結(jié)果再傳入T中
這里的T用到的算法解混淆為
T?=?d['fromString'](W,?!0,?16)["toUnsigned"]()['toString'](10)
這里的T直接把算法整出來,然后調(diào)用就完事了

到這里P的四個(gè)元素就全部解出來了
之后的I將P中的四個(gè)元素用!進(jìn)行了拼接
將拼接的結(jié)果傳入(0,c.default)()得出最終的結(jié)果
這里的(0,c.default)()分析結(jié)果為sha384,經(jīng)過sha384的計(jì)算最終得出最終的sign
以上就完成了所有參數(shù)的計(jì)算
接下來帶入Python中請求就可以了,我們來測試一下

好了,以上就是今天的全部內(nèi)容了。
我是沒有更新就在摸魚的咸魚
收到請回復(fù)~
我們下次再見。
對了,看完記得一鍵四連,這個(gè)對我真的很重要。
