web逆向-豆瓣读书搜索接口
一直都想写这篇,但之前都太懒,久而久之成了心里的一道坎
首先来看一下原始数据,可以看到 window.DATA 里面是一大串意义不明的乱码
直接全局搜索 window.__DATA__
然后下断点,刷新页面
进入到 Lt.dispatch
函数内部
这里很明显,r 就是 window.__DATA__
,即原始数据,e(t)(n) 意思是原始数据经过了若干个函数的处理
我们进入到函数内部,看看具体做了什么,以及怎么用python来实现相同的功能
第一个函数
首先是 (n) 函数
可以看到里面有好几处处理,我们一个一个来复现
a = e.from(r, “base64”)
原始数据r
经过e.from
函数的处理后,变成了Unit8Array的数据类型,其实就是对原始数据进行 base64 解码
python主要使用base64
标准库实现1
a = list(base64.b64decode(data))
从上图可以看到两个的效果都是一样的s 和 u
1
2s = Math.max(Math.floor((a.length - 2 * i) / 3), 0)
u = a.slice(s, s + i)这两个就不用多说了,s是地板除(后面的0可以忽视),u是切片操作,python实现:
1
2s = floor((len(a) - 2 * i) / 3)
u = a[s : s + i]a = e.concat([a.slice(0, s), a.slice(s + i)])
concat是连接的意思,e.concat
其实就是对两个数组进行合并操作1
a = a[0:s] + a[s + i :]
c = Object(o.hash)(e.concat([u, e.from(t)]))
这一步进行了较多操作,首先是e.concat([u, e.from(t)])
,几次打断点发现e.from(t)
都是空数组,所以这里结果只有 u数组
然后是Object(o.hash)
很明显这里是一个hash函数来处理 u,进入到内部看一下
继续进入 h.default 内部
这里就得凭经验来判断了,如果熟悉 xxhash算法(传送门),下方红框处的五个magic constants应该就会很眼熟,对照五个常数,确认是64位的xxhash算法
python的话,直接使用第三方的 xxhash库,seed 则是固定的 41405,两者的结果对比:
这里涉及到 bytes 和 list 的相互转换,直接使用对应的内置函数就行
xxh64_hexdigest
只能处理字节
第二个函数
第一个函数处理就到此结束,主要是为了得到 a 和 c 两个参数,下面进入第二个函数(需要经过三次 step in & out):
这里注意到 r = Pt.crypto.decrypt(t[n], n)
, t[n] 对应上一步的a,n则对应c,所以我们需要进入 decrypt内部看看做了什么
这里有几处很明显的特征,如果熟悉rc4
算法的朋友,应该能很快地认出来,下面是rc4的wiki
当然,如果认不出是rc4也没关系,就几十行代码,完全可以照着写实现整个过程,就是重复造轮子比较花时间
我们直接使用 Crypto
库 ARC4
模块
1 | def crypto_rc4(text: bytes, sec_key: str): |
拿一小段字节,分别进行加密测试,对比结果,成功复现原功能:
第三个函数
第二步一样,3次 step into & out
后,我们进入第三个函数内部,可以看到参数t就是经过rc4加密后的数组
再次进入函数内部
进入最后的 r函数内部
这里我们无法确定用的是哪种解析,直接拿出全部的关键词去google一下吧,出现最多的关键词是 bplist,看一下它的实现过程,是不是和豆瓣的很相似?
bplist的全称是 Binary Property List,
plist 属性列表
是一种ios系统中用来存储少量数据的文件格式,可以和 json、xml、binary等格式互相转换,这里有介绍
最终将 binary数组 转成 json数据
python的内置标准库已经有plistlib专门来处理plist文件,直接使用 loads
方法来加载 binary 就行
1 | import plistlib |
最终的解析结果是一个数组:
代码整理
1 | import requests |
运行结果如下,我做了一下筛选和格式化输出
最后,其实m端的豆瓣接口没有加密,可以直接用 xpath提取数据,不用去逆向这么麻烦 🤣🤣🤣