Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save lzghzr/858067598cf590af4c1b7d8faa211d21 to your computer and use it in GitHub Desktop.
Save lzghzr/858067598cf590af4c1b7d8faa211d21 to your computer and use it in GitHub Desktop.
openstd.samr.gov.cn(原gb688)PDF文件载入流程

0. 免责声明

没啥卵用, 但依然要说明一下, 本文未包含版权内容, 且未对所诉网站之程序进行破坏, 文章内容均为学习交流之用

1. 前言

2021年前, gb688 手机版使用的明文 pdf, 可直接下载, 不需要额外处理
2021年开始, 新站 openstd, 开始全面启用 pdf.js, 至此, 手机版也使用与 pc 同样加密技术
2022年4月, 网站弃用 pdf.js, 全面使用图片拼接模式, 本文内容已过时

2. 文件预览

openstd文件以两种方式开放给用户, 一种为直接下载, 另一种为在线预览
直接下载的文件有DRM保护, 需使用网站提供的工具打开
在线预览的文件使用 pdf.js, 浏览器解密后在线呈现给用户

因为浏览器管理较为困难, 且容易改造, 对于要求不高的用户, 可以使用打印功能将文件打印为纸质文件或PDF文件
亦可使用无头浏览器 (headless), 对网站文件进行批量获取

3. 文件载入

既然可以使用 pdf.js 进行预览, 说明必定有PDF文件进行载入
通过浏览器工具可知, 载入的文件并非明文, 而是加密后的Base64字符串, 并且使用了懒加载 (lazyload), 分段进行载入
下面通过 GB 39732-2020 (汽车事件数据记录系统) 为例, 来分析其载入过程

3.1

点击 "在线预览" 按钮后, 浏览器跳转至 预览页面
在此页面中包含变量 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

3.2

拿到密钥和初始向量后, 开始请求加密文件

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]

至此, 文件载入结束

@frpfan
Copy link

frpfan commented Feb 27, 2021

有没有完整的代码,可以发我一份吗?

@lzghzr
Copy link
Author

lzghzr commented Feb 28, 2021

有没有完整的代码,可以发我一份吗?

没有

@guohaiping
Copy link

不提供下载了好不方便

@soarcool
Copy link

小白看不懂,下载了pdf-work.wasm 不会用

@Lasx
Copy link

Lasx commented Apr 17, 2021

感谢分享,直接dump可以捡low-hanging fruit,retPtr-0x170
膜拜大佬,能否借一步说话。

@drcege
Copy link

drcege commented Mar 29, 2022

console PDFViewerApplication.save()

@PrintNow
Copy link

console PDFViewerApplication.save()

@drcege 感谢🙏 非常有用

@machinecatzm
Copy link

@drcege 感谢🙏 非常有用

@andrewmanvel
Copy link

@drcege 感谢🙏 非常有用

你好。请问你用console PDFViewerApplication.save()可以下载吗?我这出现
VM330:1 Uncaught ReferenceError: PDFViewerApplication is not defined at :1:1
没法下载啊

@machinecatzm
Copy link

machinecatzm commented Apr 23, 2022 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment