没啥卵用, 但依然要说明一下, 本文未包含版权内容, 且未对所诉网站之程序进行破坏, 文章内容均为学习交流之用
2021年前, gb688 手机版使用的明文 pdf, 可直接下载, 不需要额外处理
2021年开始, 新站 openstd, 开始全面启用 pdf.js, 至此, 手机版也使用与 pc 同样加密技术
2022年4月, 网站弃用 pdf.js
, 全面使用图片拼接模式, 本文内容已过时
openstd文件以两种方式开放给用户, 一种为直接下载, 另一种为在线预览
直接下载的文件有DRM保护, 需使用网站提供的工具打开
在线预览的文件使用 pdf.js
, 浏览器解密后在线呈现给用户
因为浏览器管理较为困难, 且容易改造, 对于要求不高的用户, 可以使用打印功能将文件打印为纸质文件或PDF文件
亦可使用无头浏览器 (headless), 对网站文件进行批量获取
既然可以使用 pdf.js
进行预览, 说明必定有PDF文件进行载入
通过浏览器工具可知, 载入的文件并非明文, 而是加密后的Base64字符串, 并且使用了懒加载 (lazyload), 分段进行载入
下面通过 GB 39732-2020 (汽车事件数据记录系统) 为例, 来分析其载入过程
点击 "在线预览" 按钮后, 浏览器跳转至 预览页面
在此页面中包含变量 var HCNO="e+fr0OSr1Px3S3phy72jth0Hq3HBZZ+ZDXKIbZQEWVeWUhQ7hYT4ELgJTdrFvtx9lSgoZL0ew6+0DcVriDfUeMIK59fQUGvHqO8h3Ps31m4="
, 记录了加密PDF文件所使用的密钥 (key) 和初始向量 (iv)
其自身为密文, 通过网站编译的 pdf-work.wasm
中的固定参数进行解密, 之后在浏览器中初始化
Module.onRuntimeInitialized = function () {
var ptr = allocateUTF8(HCNO);
var retPtr = Module._init(ptr);
HCNO = UTF8ToString(retPtr);
DEFAULT_URL += HCNO;
console.log(DEFAULT_URL);
if (document.readyState === "interactive" || document.readyState === "complete") {
webViewerLoad();
} else {
document.addEventListener("DOMContentLoaded", webViewerLoad, true);
}
}
解密后得到 ****************:################:CC68F6BFD3E104560914271598AFE8C8
, 其中
****************
为密钥
################
为初始向量
CC68F6BFD3E104560914271598AFE8C8
为hcno
拿到密钥和初始向量后, 开始请求加密文件
GET http://c.gb688.cn/bzgk/gb/viewGb?type=online&hcno=CC68F6BFD3E104560914271598AFE8C8 HTTP/1.1
Host: c.gb688.cn
Connection: keep-alive
User-Agent: Mozilla/5.0 ********************************
Accept: */*
Referer: http://c.gb688.cn/bzgk/gb/showGb?type=online&hcno=CC68F6BFD3E104560914271598AFE8C8
Accept-Encoding: gzip, deflate
Accept-Language: ********************************
Cookie: JSESSIONID=********************************
服务器返回
HTTP/1.1 200 OK
Server: nginx/1.17.9
Date: ***, ** *** **** **:**:** GMT
Content-Type: Content-Type: application/octet-stream
Content-Length: 2967097
Connection: keep-alive
Accept-Ranges: bytes
Content-Range: bytes 0-2967096/2967097
此过程中没有发生文件传输, 而是从返回头中获得了文件大小, 即 Content-Range: bytes 0-2967096/2967097
紧接着正式开始请求文件
GET http://c.gb688.cn/bzgk/gb/viewGb?type=online&hcno=CC68F6BFD3E104560914271598AFE8C8 HTTP/1.1
Host: c.gb688.cn
Connection: keep-alive
User-Agent: Mozilla/5.0 ********************************
Accept: */*
Referer: http://c.gb688.cn/bzgk/gb/showGb?type=online&hcno=CC68F6BFD3E104560914271598AFE8C8
Accept-Encoding: identity
Accept-Language: ********************************
Cookie: JSESSIONID=********************************
Range: bytes=0-327679
其中 Range: bytes=0-327679
即为请求的文件块
服务器返回
HTTP/1.1 206 Partial Content
Server: nginx/1.17.9
Date: ***, ** *** **** **:**:** GMT
Content-Type: Content-Type: application/octet-stream
Content-Length: 436928
Connection: keep-alive
Accept-Ranges: bytes
Content-Range: bytes 0-327679/2967097
oYXL8/L6bpf0dcXYt862fxd+BOqPP2UYS1W/wxsGmxT7sSsU+cJkj33GTDmJxCq37p5tqIFmaYQVWNL88XredoArMcIpzsuaSTeL1Nj/t9CQCiQA8yFQmZOIQTp3vyXo
[more]
得到数据后进行解密, 载入到 pdf.js
中
用户下拉时再继续请求, 直到最后一块
GET http://c.gb688.cn/bzgk/gb/viewGb?type=online&hcno=CC68F6BFD3E104560914271598AFE8C8 HTTP/1.1
Host: c.gb688.cn
Connection: keep-alive
User-Agent: Mozilla/5.0 ********************************
Accept: */*
Referer: http://c.gb688.cn/bzgk/gb/showGb?type=online&hcno=CC68F6BFD3E104560914271598AFE8C8
Accept-Encoding: identity
Accept-Language: ********************************
Cookie: JSESSIONID=********************************
Range: bytes=2949120-2967096
HTTP/1.1 206 Partial Content
Server: nginx/1.17.9
Date: ***, ** *** **** **:**:** GMT
Content-Type: Content-Type: application/octet-stream
Content-Length: 23980
Connection: keep-alive
Accept-Ranges: bytes
Content-Range: bytes 2949120-2967096/2967097
7x/AI3CelgQLKM3uZOKMbuApo9I1NYbaEpZ9diKXfGuljC3S2p/t80GdRHLu6ybPSwED9bx4nkJXtEijAM9ben6g4CdO1UC85aTGxpWKpoh4umqfibsh3jTYkSnAoZtd
[more]
至此, 文件载入结束
有没有完整的代码,可以发我一份吗?