本次目标网址如下,使用base64解码后获得
aHR0cHM6Ly9wYW4uYmFpZHUuY29tL3MvMUZsaDBPeGpZamZJTFVZWUQzTm9fVnc=
链接提取码为:ly12
本次逆向分析分为上下两篇文章说明,一为讲解如何从原链接通过逆向拿到下载链接,二为逆向登录拿到cookie,因为在获取下载链接的过程中,是要登录百度网盘的账号的,本文在讲解提取的过程中,登录后的cookies先固定死,只讲解最后拿到的百度网盘链接,后面再讲解逆向登录拿到cookie
下载链接其实非常好找,打开network,点击下载查看接口协议就能看到,如下图
将下载链接跟接口中比对查找后就能发现,与dlink字段的值一模一样,那么下载链接就在share这个接口里面
我们将share接口复制成curl请求后,放到该网站解析
https://curlconverter.com/python/
通过转换成python代码后如下
那么本次需要分析的就是data参数和url链接参数
这些参数我们逐个研究,先从data参数入手,这里固定的参数就不再多说了,只说变化的参数,全局搜索extra字段, 通过试错查找,发现在这个位置生成
我们跟进s函数,发现就是取出cookie,那个extra值就是cookie中的BDCLND,由于之前说过,本文不涉及登录,cookie参数是固定的,所以这里就不再往下追究去找cookie的来源了
vcode_input是输入验证码的参数,vcode_str是请求验证码时附带的校验参数,需要和正确的验证码一起传回去,校验验证码是否正确,如下图,可以找到vcode_str的来源
接着看primaryid参数,还是跟栈查找,在这个位置
查找流程就不多说了,稍微根根就能找到,可以发现,primaryid就是shareid, uk就是share_uk,一下子解决两个参数,我们再往前跟栈找找,查看参数生成的位置
最终我们发现,这两个参数都是在请求网页时附带生成, 同样fid_list应该就是文件列表的id,也在加载网页时就附带了
至此,data参数已经分析完毕
接着,我们看请求链接中的参数,我们重放请求后,最后确定,可变的参数如下
f'https://pan.baidu.com/api/sharedownload?sign={sign}×tamp={timestamp}&channel=chunlei&web=1&app_id={appid}&bdstoken={bdstoken}&logid={logid}&clienttype=0&jsToken={jsToken}&dp-logid={dplogid}'
sign和timestamp在tplconfig接口里面
appid是固定应用id,bdstoken在yundata里面
logid是cookie里的BAIDUID
dplogid是全局函数window.BpDataInstance.getDpLogId()
至此,所有加密参数已经找到
加密接口组装流程如下,
初始化进入页面接口-获取sign接口-获取验证码接口-获取下载链接接口
按照流程,组装代码如下
response = session.get('https://pan.baidu.com/s/1Flh0OxjYjfILUYYD3No_Vw?pwd=ly12?', headers=headers)
# 使用正则表达式提取带有 window.jsToken 的 script 标签内容
pattern = r'<script\b[^>]*>([\s\S]*?)<\/script>'
matches = re.findall(pattern, response.text)
# 遍历匹配到的 script 标签内容
for match in matches:
if 'window.jsToken' in match:
# print(match)
jsToken = urllib.parse.unquote(match)
jsToken = jsToken.split('("')[1].split('")')[0]
# 遍历匹配到的 script 标签内容
for match in matches:
if 'window.yunData' in match:
# 使用正则表达式提取第二个自执行代码块
pattern = r'!function\(\)\s*{([\s\S]*?)}\(\);'
selfexecutes = re.findall(pattern, match)
# 输出第二个自执行代码块
for selfexecute in selfexecutes:
if "window.yunData" in selfexecute:
selfexecutefun = selfexecute
sign_url = 'https://pan.baidu.com/share/tplconfig?surl=' + download_param
sekey = urllib.parse.unquote(cookies.get("BDCLND"))
jsstr = execjs.compile(jsstr.replace("{selfexecutes}", selfexecutefun))
yunData = jsstr.call("get_yundata")
locals = jsstr.call("get_locals")
bdstoken = yunData.get("bdstoken")
fsid = locals.get('file_list')[0].get("fs_id")
# 获取sign接口
response = session.get(
sign_url + f'&fields=sign,timestamp&channel=chunlei&web=1&app_id={appid}&bdstoken={bdstoken}&logid={logid}&clienttype=0&dp-logid={dplogid}',
headers=headers,
)
sign = response.json().get("data").get("sign")
timestamp = response.json().get("data").get("timestamp")
# 请求验证码
response = session.get(
f'https://pan.baidu.com/api/getvcode?prod=pan&t=0.2430438848136891&channel=chunlei&web=1&app_id={appid}&bdstoken={bdstoken}&logid={logid}&clienttype=0&dp-logid={dplogid}',
headers=headers,
)
print(response.json())
vcode_str = response.json().get("vcode")
img = response.json().get("img")
# 下载验证码
response = session.get(img,
cookies=cookies,
headers=headers, )
with open('vcode.jpg', 'wb') as f:
f.write(response.content)
# vcode_str = '3332423865633234636166333465663732323763363637363764323966666433666231363236383236373834303030303030303030303030303031373035353639333539FD63FF431D35E2B5D98E13D16C79AEA0'
print(1)
# 获取下载链接
data = {
'encrypt': '0',
'extra': '{"sekey":"%s"}' % sekey,
'product': 'share',
'vcode_input': 'H4DG',
'vcode_str': vcode_str,
'uk': yunData.get("share_uk"),
'primaryid': yunData.get("shareid"),
'fid_list': f'[{fsid}]',
'path_list': '',
'vip': '2',
}
response = session.post(
f'https://pan.baidu.com/api/sharedownload?sign={sign}×tamp={timestamp}&channel=chunlei&web=1&app_id={appid}&bdstoken={bdstoken}&logid={logid}&clienttype=0&jsToken={jsToken}&dp-logid={dplogid}',
headers=headers,
data=data,
)
print(response.text)
dlink = response.json().get('list')[0].get('dlink')
server_filename = response.json().get('list')[0].get('server_filename')
response = session.get(
dlink,
cookies=cookies,
headers=headers,
)
print(response)
print(server_filename, len(response.content))
with open(server_filename, "wb") as f:
f.write(response.content)
用到的js补环境如下,navigator实际上并没有用到那么多,我使用一键获取,懒得删用不着的变量了:
window = global;
navigator = {
"vendorSub": "",
"productSub": "20030107",
"vendor": "Google Inc.",
"maxTouchPoints": 0,
"scheduling": {},
"userActivation": {},
"doNotTrack": null,
"geolocation": {},
"connection": {},
"plugins": {
"0": {
"0": {},
"1": {}
},
"1": {
"0": {},
"1": {}
},
"2": {
"0": {},
"1": {}
},
"3": {
"0": {},
"1": {}
},
"4": {
"0": {},
"1": {}
}
},
"mimeTypes": {
"0": {},
"1": {}
},
"pdfViewerEnabled": true,
"webkitTemporaryStorage": {},
"webkitPersistentStorage": {},
"hardwareConcurrency": 8,
"cookieEnabled": true,
"appCodeName": "Mozilla",
"appName": "Netscape",
"appVersion": "5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"product": "Gecko",
"language": "zh-CN",
"languages": [
"zh-CN",
"zh"
],
"onLine": true,
"webdriver": false,
"deprecatedRunAdAuctionEnforcesKAnonymity": false,
"bluetooth": {},
"clipboard": {},
"credentials": {},
"keyboard": {},
"managed": {},
"mediaDevices": {},
"storage": {},
"serviceWorker": {},
"virtualKeyboard": {},
"wakeLock": {},
"deviceMemory": 8,
"cookieDeprecationLabel": {},
"login": {},
"ink": {},
"hid": {},
"locks": {},
"gpu": {},
"mediaCapabilities": {},
"mediaSession": {},
"permissions": {},
"presentation": {},
"usb": {},
"xr": {},
"serial": {},
"windowControlsOverlay": {},
"userAgentData": {
"brands": [
{
"brand": "Not_A Brand",
"version": "8"
},
{
"brand": "Chromium",
"version": "120"
},
{
"brand": "Google Chrome",
"version": "120"
}
],
"mobile": false,
"platform": "Windows"
}
}
location = {
"ancestorOrigins": {},
"href": "https://pan.baidu.com/s/1TBy2gI-PUz2P_SWjCjq-ww?pwd=d1g1",
"origin": "https://pan.baidu.com",
"protocol": "https:",
"host": "pan.baidu.com",
"hostname": "pan.baidu.com",
"port": "",
"pathname": "/s/1TBy2gI-PUz2P_SWjCjq-ww",
"search": "?pwd=d1g1",
"hash": ""
}
document = {}
locals = {
set: function(k, v){
//console.log(k,v);
this[k] = v
},
mset: function(v){
this.data = v
}
}
require("./bpdatajs-sdk-min-1.3.3.js")
if (window.BpData) {
window.BpDataInstance = new BpData({
serverId: 13328,
from: 'main',
page: 'share_common_page',
parasitifer: 'web'
})
}
{selfexecutes}
function getDpLogId(){
/*
for(var i = 0;i < 40;i ++){
window.BpDataInstance.getDpLogId()
}
*/
return window.BpDataInstance.getDpLogId()
}
function get_yundata(){
return window.yunData;
}
function get_locals(){
return locals.data;
}
function get_servertime(){
return locals.servertime;
}
//console.log(locals);
最后,也能成功下载文件到本地