本帖最后由 tzwsoho 于 2019-9-6 22:06 编辑
众所周知,最近由于某些特殊原因,pandownload关闭了默认搜索功能,一直使用畅快的我感到了前所未有的掣肘感。但很感谢pandownload的作者提供了这么好用的功能,希望事情过去后仍然可以把功能开放一下。本文仅供学习研究使用,禁止用作非法用途,如有不妥之处请告之,本人会在第一时间修改删除。
这篇文章主要是对pandownload(下面简称PD)两大功能的挖掘:
软件环境:
- Visual Studio 2012
- WireShark
- WinHex
- Navicat
- unluac_2015_06_13.jar(https://sourceforge.net/projects/unluac/)
- lua53(http://www.lua.org/ftp/lua-5.3.5.tar.gz)
- Pandownload v2.1.3
默认搜索功能
一直在用PD的朋友都应该知道,自从2019年8月30日开始,PD不再提供强大的默认搜索功能。而大家可以在PD的目录中看到,一些如盘多多之类的插件,都是通过lua脚本来实现的,这时我们可以很容易就联想,会不会默认搜索也是同样适用lua来实现呢?答案其实是肯定的,并且因为PD自身使用lua5.3的原因,我们可以通过修改lua53.dll的一些函数就可以把默认搜索的lua脚本提取出来,但因为搜索功能已经关闭,其实PD已不再加载相关的脚本,这个我们可以通过wireshark抓包知道:
首先我们打开WireShark,设置过滤器为http,再打开PD,我们可以看到,PD会先访问一个初始化的地址,然后会通过访问
http://pandownload.com/api/script/list?clienttype=0&referral=&t=1567735359&version=2.1.3
来获取脚本的配置信息,如下图:
这个脚本配置是个JSON文本,目前是这样的:
[JavaScript] 纯文本查看 复制代码 {
"scripts": [
{
"name": "search_pandown.lua",
"remove": true
},
{
"name": "search_ncckl.lua",
"remove": true
},
{
"name": "search_quzhuanpan.lua",
"remove": true
},
{
"name": "anime_01.lua",
"remove": true
},
{
"name": "anime_02.lua",
"id": 1000,
"url": "http://static.pandownload.com/scripts/anime_agefans_0.0.5.lua",
"md5": "2d5d32f3294e7617bb0e5f0d942b29c9"
},
{
"name": "anime_dilidili.lua",
"id": 1001,
"url": "http://pandownload.com/static/scripts/anime/anime_dilidili_0.0.4.lua",
"md5": "197927c0ad7098f59c2c8674fd7054a8"
},
{
"name": "s",
"id": 2,
"url": "http://pandownload.com/static/scripts/s005",
"md5": "93c6666f6b10c40ac6d55771ddb98367"
},
{
"name": "anime",
"id": 3,
"url": "http://static.pandownload.com/scripts/anime_0.0.2",
"md5": "5fd63dc5bf617225ebfb3b16413879cb"
},
{
"name": "default",
"id": 0,
"url": "http://pandownload.com/static/scripts/default_0.3.8",
"md5": "363d53675fdd959d2ec5ad30c160435d",
"key": "3ae81c85790faeccd3ed39d533816b32"
}
],
"code": 0,
"message": "success"
}
我们可以看到,search_pandown.lua就是默认搜索的脚本,而它的remove状态现在已经是true,所以PD不会从服务器里下载下来,那怎么才能知道默认搜索的功能实现呢?其实一般软件的开发都是迭代进行的,旧版本的PD或许还留有一些BUG之类的可以供我们去发掘,这时我们可以考虑下载旧版本的PD进行研究。我们从PD的官网更新日志得知,从2.0.3版本开始,PD便加入了搜索功能,可以通过https://pandownload.com/2.0.3这个链接下载v2.0.3版本,但解压后会发现这个版本并不包含默认搜索功能,可能是作者当时还没弄好本地数据库的原因吧。我们可以继续下载更新的版本,一直到v2.0.6,解压之后你可以看到里面就有一个search_pandown.lua。但打开后会发现这个文件其实是已经编译过的luac格式的文件,我们可以使用工具进行反编译(如果反编译出现错误,需要用WinHex把文件打开,把所有的0D0A字节替换成0A,后面操作雷同):
java -jar unluac_2015_06_13.jar search_pandown.lua > C:\search_pandown.lua
这时可以看到,这个版本的脚本访问的搜索URL并没有附加sign字段,可能是之前PD作者没考虑到会被盗链。
但本人很有幸,在PD作者关闭默认搜索脚本功能之前就已经把最新版本的代码dump了下来。dump脚本的方法很简单,我们可以在lua的官网上下载一份lua53的源码,使用VS编译出修改后的dll并替换掉原来的,那便可以为所欲为了!这里我自己修改了lua_loadbufferex函数:
[C++] 纯文本查看 复制代码 LUALIB_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t size,
const char *name, const char *mode) {
FILE* f = NULL;
char fn[50];
LoadS ls;
ls.s = buff;
ls.size = size;
sprintf(fn, "D:\\%d.luac", rand() * 100000);
f = fopen(fn, "w");
fwrite(buff, size, 1, f);
fclose(f);
return lua_load(L, getS, &ls, name, mode);
}
替换掉原来的DLL后,打开PD,随便搜索一些东西再关闭PD,我们可以看到D:盘下生成了许多“数字.luac”文件。我们再次使用unluac将它们逐一反编译,可以看到一份源码是这样的(由于边幅过长,我去掉了一些与本文无关紧要的代码):
[Lua] 纯文本查看 复制代码 local L1_1
L0_0 = require
L1_1 = "lcurl.safe"
L0_0 = L0_0(L1_1)
L1_1 = require
L1_1 = L1_1("cjson.safe")
script_info = {
title = "默认",
description = "",
version = "0.0.5"
}
function onSearch(A0_2, A1_3)
local L2_4, L3_5
L2_4 = os
L2_4 = L2_4.time
L2_4 = L2_4()
L3_5 = "http://search.pandown.cn/api/query?clienttype=0&highlight=1&key="
L3_5 = L3_5 .. pd.urlEncode(A0_2) .. "&page=" .. A1_3 .. "×tamp=" .. L2_4 .. "&sign=" .. e(A0_2, A1_3, L2_4)
return parse(get(L3_5))
end
function onItemClick(A0_6)
...
end
function get(A0_9)
...
end
function parse(A0_13)
...
end
function replace(A0_22, A1_23)
...
end
function getIcon(A0_25, A1_26)
...
end
function e(A0_33, A1_34, A2_35)
local L3_36
L3_36 = ""
if pd.makeSign then
L3_36 = pd.makeSign(A0_33 .. "_" .. A1_34 .. "_" .. A2_35)
end
return L3_36
end
这时我们可以清晰地看到,PD的默认搜索其实就是访问了一个URL,然后解析返回的内容再以列表的形式展示出来:
http://search.pandown.cn/api/query?clienttype=0&highlight=1&key=编码后的关键字&page=页码×tamp=当前时间&sign=pd.makeSign(原关键字 + "_" + 页码 + "_" + 当前时间)
这里的pd.makeSign其实是一个PD使用C/C++写的内置函数,并不是脚本实现,所以很可惜我并不能知道这个函数的实现细节。这个函数可以用两种方法来获取在内存中的地址,一种是修改lua,比如PanData\script\default\rename_01.lua,增加以下代码:
[Lua] 纯文本查看 复制代码 for k, v in pairs(pd) do
if "makeSign" == k then
pd.logInfo(k .. "|" .. tostring(v))
end
end
在PD启动时就会把makeSign函数的地址写入PanData\log\xxx.log日志文件里,这时直接用OD/VS/CheatEngine之类的调试器直接附加到PD,然后跳转到日志里的地址就可以进行反汇编。
另外还有一种方法就是跟踪lua_pushstring和lua_pushcclosure两个函数,PD在启动时会调用这两个函数生成pd表格对象,可以对lua_pushstring下个条件断点,然后也能找到makeSign函数的真实地址。虽然找到了makeSign的实现汇编代码,但由于能力所及我并不知道这个函数的实现原理。
看到这里,聪明的读者是不是想到,虽然我们并不知道pd.makeSign的实现方法,但是既然我们已经知道了默认搜索的实现脚本,而PD又支持插件功能,自己照样画葫芦再写一个相同功能的脚本不就同样可以实现默认搜索的功能?但是很遗憾的是,PD的作者在服务器端也将此功能关闭了,目前访问这个URL,得到的回复都只会是{"code":-1,"message":"服务器维护中"},所以一切只能等PD的作者恢复默认搜索功能才能愉快地玩耍了。
提取码搜索功能
我觉得PD之所以如此受大众喜爱,除了突破了某种限制,还有强大得无人能敌的默认搜索功能,最重要的我觉得就是网盘提取码的搜索功能。这个功能的发掘相对简单,使用WireShark即可。按之前的方法,我们先打开WireShark,设置http过滤器,打开PD,然后复制一个网盘分享链接(比如:https://pan.baidu.com/s/1GmaGU1FmZ5uwMtE8lUWKOA),这时PD会访问一个网址来搜索提取码:
我们可以看到,PD通过访问这个URL来获取提取码:
http://search.pandown.cn/api/query?clienttype=0&referral=&surl=1naiIOD7m8gZSrVk-Zr30dg&t=1567738781&version=2.1.3
其中,surl参数是网盘链接/s/后面的那段路径,t是当前时间,其他参数固定。返回的内容也是JSON格式的文本,如果找不到提取码,会返回以下内容:
[JavaScript] 纯文本查看 复制代码 {
"code": 0,
"message": "success",
"total": 0,
"data": []
}
如果找到了提取码,就会返回这样的格式:
[Asm] 纯文本查看 复制代码 {
"code": 0,
"message": "success",
"total": 1,
"data": [
{
"id": "3Nzk91",
"password": "mj8d",
"title": "彩虹岛",
"ctime": "1567679677",
"expired": "0",
"isdir": "1"
}
}
同时PD还内置了SQLite数据库,如果在找不到提取码的情况下,PD还允许用户自行输入提取码,当提取码正确的时候,PD会把提取码记录到PanData\share.db文件里面,下次用户再访问同一个分享链接便不需要再向服务器请求提取码。这文件可以使用Navicat之类的SQLite数据库管理器直接打开,除了这个数据库外还有下载任务列表数据库(PanData\task.db),看着像是用户数据库(PanData\user.db),但用户库文件由于进行了加密,并不能正常打开,有时间再研究打开这个数据库的密码吧。 |