DuFile⽹盘逆向下载链接免等待破解思路
最近在逛某论坛时碰到了DuFile⽹盘的资源,对于这列靠下载限速+繁琐跳转促使⽤户付费的收费盘,当然要破解⼀下玩玩。经过⼏个⼩时的分析,笔者发现这家⽹盘的策略是
⽐较有趣的,故此记录⼀下。
注意:此类收费盘,破解会员⾼速通道在理论上基本是不可能的,我们能做的只是规避掉等待时间。
万磊
⽹页直接进⼊⽆法点击的调试状态,只要不关闭调试窗⼝就⼀直这样,⽽且事后证明如果在访问⽹址前就开启调试⾯板则⽹页根本就不会加载。这实际是⼀种不太常见的前端反
逆向措施(常见的是js代码混淆),详情可见,破解⽅法见。
幸运的是函数名没有加密,我们找到down_file函数(其余函数都是举报,开vip以及⽆关紧要的xxx),然后⽤查找功能追踪⾥⾯涉及到的变量,发现引⽤关系很简单,只涉及⼀
⼩段代码
var _0x100e = ['<div style="width:.太长略']
var _0x5289 = function(_0x24bdbe, _0x4f9026) {
_0x24bdbe = _0x24bdbe - 0x0;
var _0x471092 = _0x100e[_0x24bdbe];
return _0x471092;
};
function down_file(_0x5876ce, _0x3d630b) {
var _0x385fa2 = document[_0x5289('0x64')](_0x5289('0x65'));
_0x385fa2['id'] = 'filter';
_0x385fa2[_0x5289('0x18')] = _0x5289('0x66') + '<div id="frmmask" ></div>' + _0x5289('0x67') + _0x5289('0 document[_0x5289('0x19')][_0x5289('0x6a')](_0x385fa2);
showMask(!![], 0x15a, 0x164);
document[_0x5289('0x10')](_0x5289('0x6b'))['src'] = _0x5289('0x6c') + _0x5876ce + _0x5289('0x6d') + _0x3d630b;
}
View Code
将变量名作替换后就很明了
var elelist = ['<div style="width:.太长略']
var getelefunc = function(index, _) {
index = index - 0x0; //index=index-0,其实此⾏可以删除
var ele = elelist[index];
return ele;
};
function down_file(fileid, '0') { //fileid就是url⾥那⼀串字母数字,0是固定的
/*
这些不重要,能看出它们功能只是在⽹页⾥渲染⼀些元素框体
var _0x385fa2 = document[_0x5289('0x64')](_0x5289('0x65'));
_0x385fa2['id'] = 'filter';
_0x385fa2[_0x5289('0x18')] = _0x5289('0x66') + '<div id="frmmask" ></div>' + _0x5289('0x67') + _0x5289('0 document[_0x5289('0x19')][_0x5289('0x6a')](_0x385fa2);
showMask(!![], 0x15a, 0x164);
*/
document[getelefunc('0x10')](getelefunc('0x6b'))['src'] = getelefunc('0x6c') + fileid + getelefunc('0x6d') +'0';纳粹主义
//关键在于getelefunc('0x6c') + fileid + getelefunc('0x6d'),分别对应elelist[108]和elelist[109],⼀查便知。
}
View Code
事实上更简单的⽅法是直接⽤第三⽅⼯具抓包,⽐如Charles
可以很直观的看出发包次序和包内容,于是构造Python脚本如下:
import requests
from bs4 import BeautifulSoup as Bs
import re
class DuFile(object):
def__init__(lf):
lf.headers = {"Ur-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763"}
def getfile(lf, url, filepath):
ssion = requests.ssion() #⽤ssion来维持访问中的cookie
req1 = (url, headers=lf.headers)
if req1.status_code==200:
content = , 'lxml')
file_size = content.lect_one('#fbody1').lect_one('b').text
filename = content.lect_one('.title').text
filename = filename.split("下载")[1].strip()
print("filename: %s, filesize: %sKB" %(filename, file_size))
el:
return'error'
targetaddr = place('/file/','/down/')
lf.headers.update({'Host':'', "Referer":url})
req2 = (targetaddr, headers=lf.headers)
file_id = re.arch(r'/down/([a-z0-9]+)', targetaddr).group(1)
lf.headers.update({"Referer":targetaddr})
req4 = ("/dd.php?file_key={}&p=0".format(file_id), headers=lf.headers)
downurl = re.arch(r"id=\"downs\" href=\"(http.+?)\"", ).group(1)
host = re.arch(r'(.+?)/down', downurl).group(1)
req_file = (downurl, headers={'Host':host, 'Referer':"/dd.php?file_key={}&p=0".format(file_id)})
with open(filepath+filename, 'wb') as f:
f.write(t)
return filename
View Code
但使⽤中直接抛出了异常,req4返回了意外的结果,是⼀个地址,打开后
被认出来了......那么疏漏在哪⾥了呢?
英德宝晶宫
回顾之前的抓包,脚本⽐正常访问少的只有
两处。2发包时间在问题点的后⾯,应该不是,那就只有1,1是验证码的相关操作,分为⼀个get图⽚请求和⼀个post输⼊值提交,如果输⼊值正确即返回1。因为绝⼤多数⽹盘(飞猫、讯⽜等)只会⽤这个返回值来决定是否执⾏下⼀步的下载函数,所以根本不需要去真的填写验证码(飞猫云曾有⼀段时间把真正地址写在返回值⾥,这种是没办法跳过去的),DuFile是否在这⾥也做了验证?
经试验,DuFile的验证码图⽚分为两种,分别是4位纯数字和计算加减法,受URL⾥的down_code加不加下划线控制,因为我们不是搞CV的,所以没必要花时间研究验证码识别问题,直接调第三⽅服务就好,打码服务百度⼀下就能找到,⼀个码⼀般1分到⼏分钱,还是很便宜的,如果是那种⽐较⽩给的验证码,甚⾄可以试试百度免费的图⽚转⽂字服务,这⾥就不多做介绍了。直接上修改版代码
import requests
from bs4 import BeautifulSoup as Bs
import re
import random
import ba64
import time
import json
import hashlib
def md5(ss):
fd = hashlib.md5()
fd.de('utf-8'))
避孕套什么牌子好return fd.hexdigest()
def veryimg(img_data):
link = "/api/capreg"#这⾥就不放具体是哪家了
timestamp = str(int(time.time()))
pd_id = YOUR_ID
pd_key = YOUR_KEY
sign = md5(pd_id + timestamp + md5( timestamp + pd_key))
predict_type = '10400'#4位纯数字
data = {
'ur_id':pd_id,
'timestamp':timestamp,
分词作状语
'sign':sign,
'predict_type':predict_type,
'img_data':img_data
}
req = requests.post(link, data)
result = json.)['RspData']
code = json.loads(result)['result']
return code
class DuFile(object):
域名格式def__init__(lf):
lf.headers = {"Ur-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763"}
def getfile(lf, url, filepath):
ssion = requests.ssion() #⽤ssion来维持访问中的cookie
req1 = (url, headers=lf.headers)
if req1.status_code==200:
content = , 'lxml')
file_size = content.lect_one('#fbody1').lect_one('b').text
filename = content.lect_one('.title').text
filename = filename.split("下载")[1].strip()
print("filename: %s, filesize: %sKB" %(filename, file_size))
el:
return'error'
武术散打
targetaddr = place('/file/','/down/')
lf.headers.update({'Host':'', "Referer":url})
req2 = (targetaddr, headers=lf.headers)
file_id = re.arch(r'/down/([a-z0-9]+)', targetaddr).group(1)
lf.headers.update({"Referer":targetaddr})
'''
新增验证码提交
'''
req3 = ("/downcode.php?{}".format(str(random.random())), headers=lf.headers)
# 这⾥的随机值是防⽌浏览器去读缓存⽽设的,我们脚本⾥其实不加也⾏
if req3.status_code==200:
# 将图⽚⼆进制转为ba64字符串传⼊接⼝
code = veryimg(ba64.t).decode())
el:
return'error'
req_p = ssion.post("/downcode.php", data={'action':'yz','id':file_id, 'code':code}, headers=lf.headers)
#
req4 = ("/dd.php?file_key={}&p=0".format(file_id), headers=lf.headers)
downurl = re.arch(r"id=\"downs\" href=\"(http.+?)\"", ).group(1)
host = re.arch(r'(.+?)/down', downurl).group(1)
req_file = (downurl, headers={'Host':host, 'Referer':"/dd.php?file_key={}&p=0".format(file_id)})
# 直接⼀次性请求,如果⽂件⽐较⼤建议⽤分块下载(不要⽤多线程,免费⽤户不⽀持的),写法⽹上教程很多这⾥不赘述
什么是爱情观with open(filepath+filename, 'wb') as f:
f.write(t)
return filename
View Code
重新运⾏,搞定!
总结
笔者对Yunfile, 飞猫云,彩虹云,讯⽜,城通,Busdisk等多家收费盘均进⾏过逆向破解,DuFile不是难度最⼤的⼀个,但它的反破解套路⽐较有趣,⼀⽅⾯⽤到了禁调试脚本,⼀⽅⾯⼜细⼼地在验证码上下了功夫,这两种在笔者看来都有些剑⾛偏锋的意思;特别是验证码的部分,误导性很强,如果配合上彩虹云⽤的js修改cookies验证,应该能拦住⼀⼤波⼈。⽽且经笔者测试,DuFile的下载间隔限制是IP级的,所以即使每次的ssion都是新⽣成,也得⽼⽼实实等上10分钟,或者上IP代理池,这点许多⽹盘也没能做到。
真有下载刚需的话(嘿嘿嘿~你懂的),还是建议充个会员,中国的服务器、带宽真⼼挺贵的,⼈家也要恰饭嘛。