本次目标网址如下,使用base64解码后获得
aHR0cHM6Ly9wYW4uYmFpZHUuY29tL3MvMUZsaDBPeGpZamZJTFVZWUQzTm9fVnc=
链接提取码为:ly12
本次逆向分析分为上下两篇文章说明,一为讲解如何从原链接通过逆向拿到下载链接,二为逆向登录拿到cookie,因为在获取下载链接的过程中,是要登录百度网盘的账号的,本文在讲解提取的过程中,登录后的cookies先固定死,只讲解最后拿到的百度网盘链接,后面再讲解逆向登录拿到cookie
解密流程
- 1、找到下载链接
- 2、分析接口参数
- 3、分析data参数
- 4、分析链接参数
- 5、组装加密接口
1、找到下载链接
下载链接其实非常好找,打开network,点击下载查看接口协议就能看到,如下图
将下载链接跟接口中比对查找后就能发现,与dlink字段的值一模一样,那么下载链接就在share这个接口里面
2、分析接口参数
我们将share接口复制成curl请求后,放到该网站解析
https://curlconverter.com/python/
通过转换成python代码后如下
那么本次需要分析的就是data参数和url链接参数
3、分析data参数
这些参数我们逐个研究,先从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参数已经分析完毕
4、分析链接参数
接着,我们看请求链接中的参数,我们重放请求后,最后确定,可变的参数如下
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()
至此,所有加密参数已经找到
5、组装加密接口
加密接口组装流程如下,
初始化进入页面接口-获取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 = selfexecutesign_url = 'https://pan.baidu.com/share/tplconfig?surl=' + download_paramsekey = 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);
最后,也能成功下载文件到本地