前言
最近练习js逆向,记录一下
目标声明:仅仅记录一下自己的学习方法,不作为学习参考、更不作为商业用途。如有侵犯请联系本人删除
目标url: aHR0cHM6Ly93d3cueGltYWxheWEuY29tLw==
1、分析
密文: 135a791df3418106bd30a4cec24918ea(64)1693202056545(17)1693202045790
结构:
- 135a791df3418106bd30a4cec24918ea:32位,像是md5加密
- (64),(17):暂时搞不懂是什么?
- 1693202056545,1693202045790:两个时间戳
2、定位加密位置
这个站比较简单直接拿Xm-Sign搜索就能搜索到
我们打个断点,看下是否在这里!!!
发现就是在d.getSign()这个方法生成的!!
这里使用XHR去定位,也可以,调用几个堆栈就能找到
2、加密算法实现
上面发现加密结果时 d.getSing()
方法返回的,我们进去看一下
这里我们分析一下这个function,
t.prototype[c("0x27")] = function() {
var t, e, r, n = 0;
return n = s() ? Date.now() : window.XM_SERVER_CLOCK || 0,
t = this[c("0x13")],
e = n,
r = Date[c("0x25")](), ("{" + t + e + "}(" + u(100) + ")" + e + "(" + u(100) + ")" + r)[c("0xa")](/{([\w-]+)}/, (function(t, e) {
return a(e)
}))
}
- n的值: 这明显是个三元运算符
- s()方法返回true,则n=Date.now(),时间戳。
- s()方法返回false,则n=window.XM_SERVER_CLOCK ,如果window.XM_SERVER_CLOCK没有定义,则 n=0;
这里就要看下s()
函数了
可以看出 s函数,只会返回false
所以n=window.XM_SERVER_CLOCK
这里看下window.XM_SERVER_CLOCK 是什么值:
可以看到也是个时间戳,那这个时间戳是什么时候生成的呢????这里留个问题
接下来看看 t的值:
结果多次调试,t的值是固定的,直接下一个
e=n,所以e也不用看了
r = Date[c("0x25")](),
//根据上面截图,可以看出,r=Date.now() 还是一个时间戳。
下面这一坨是什么,大致一眼看不懂我们在控制台输出一下
诶,看见我们的密文了,
这里分析下这个段代码
将{}大括号里面的值替换为后面函数生成的值a(e)
,
u(100) 看起来像是,生成100以内的随机数,
e:上面分析的 e=n ,n=window.XM_SERVER_CLOCK
r: r=Date.now()
这里重点就看下a(e)是什么鬼了 ,,,
e:t+e = ‘himalaya-’+window.XM_SERVER_CLOCK
a(e)函数:
上面抛出异常不用分析
直接看
var n = r[c("0x3c")](u(t, e));
因为明文直接传递给了u函数 ,我们直接看u函数干了什么东西
发现这里不就是md5了吗?再结合他的密文是32位的,
所以目前剩下的问题就是 window.XM_SERVER_CLOCK 是什么时候生成的??
根据开始断点和window.XM_SERVER_CLOCK 值可以分析出来在执行d.getSign()
方法之前就有了
那我们在 d生成的地方
下个断点
重点这里需要刷新页面,才能断到这里
进去一步一步跟
发现this[]
中括号里面没有XM_SERVER_CLOCK的值那么继续单步调试,到下一个方法
最后
this[c("0x36")]()方法异步的调用了
下面这个方法
return t[c("0x9")][c("0x36")] = function(t) {
var e = this;
void 0 === t && (t = !1),
s() || window.XM_SERVER_CLOCK && !t || this[c("0x44")]()[c("0x45")]((function(t) {
e[c("0x12")] = t,
window[c("0x20")] = t,
e[c("0x48")]()
}))
}
t就是这个时间戳
那么这个t哪里来的呢?,跟栈发现这个this.url也很可疑
去访问一下
到此所有问题分析完成
代码实现
js代码
const crypto = require('crypto');
function getKey(dataTime){
var r = Date.now();
var e= dataTime;
var t = "himalaya-";
return crypto.createHash('md5').update("himalaya-"+dataTime).digest('hex')+"(" + u(100) + ")" + e + "(" + u(100) + ")" + r;
}
function u(t) {
return ~~(Math["random"]() * t)
}
python代码
import requests
import execjs
headers = {
"Accept": "*/*",
"Accept-Language": "en,zh-CN;q=0.9,zh;q=0.8",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Pragma": "no-cache",
"Referer": "https://www.ximalaya.com/",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36",
"sec-ch-ua": "\"Not/A)Brand\";v=\"99\", \"Google Chrome\";v=\"115\", \"Chromium\";v=\"115\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"Windows\""
}
url = "https://www.ximalaya.com/revision/time"
response = requests.get(url, headers=headers)
print(response.text)
with open('./喜马拉雅.js', 'r',encoding='utf-8') as f:
js = f.read()
resCode=execjs.compile(js).call('getKey',response.text)
print(resCode)
headers = {
"Accept": "*/*",
"Accept-Language": "en,zh-CN;q=0.9,zh;q=0.8",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
"Pragma": "no-cache",
"Referer": "https://www.ximalaya.com/",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36",
"sec-ch-ua": "\"Not/A)Brand\";v=\"99\", \"Google Chrome\";v=\"115\", \"Chromium\";v=\"115\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"Windows\"",
"xm-sign": resCode
}
url = "https://www.ximalaya.com/revision/search/main"
params = {
"core": "all",
"kw": "音乐",
"spellchecker": "true",
"device": "iPhone",
"live": "true"
}
response = requests.get(url, headers=headers, params=params)
print(response.text)
结果
其实这段加密和发包,完全可以用python来实现了,这里小编就不在各位大佬面前班门弄斧了。。。