GBK迷思——从乱码PDF引出的遐想

作者Nick Pang,在CC BY-SA 4.0许可下发布。

写于一个不想练口译的下午。
也不想写笔译作业。

0x0 拯救大兵PDF

我决定今天下午给自己放假。今天上午,昨天一整天,前天大半天,都在整翻译的事情。脑子要炸。

打开微信,发现这样一条有意思的朋友圈:

image
感谢Ms. JIAO的朋友圈

事实上,不止我一个人要炸,大家普遍精神状态美丽。比如下载下来的东西是一堆乱码,看不懂一点。

但是乱码并不意味着信息就丢失了,其实信息还在那里,只不过是以另一种方式呈现在那里了。也许是编码的问题。

这我可就不困了。ENTP贪玩的精神上头,我一定要弄明白这个编码的问题出在哪里。

最好还能搞清楚这个图片上的这堆乱码到底是什么。

0x1 捕风捉影

从严格意义上来讲,这算是一种逆向。众所周知,每一个逆向工程都需要一个Entry Point和Exit Point。虽然这个文档不是程序,没有PE头,但是我们也可以找到一个切入点,开始我们的分析。

首先从结构上来看,这应该是某种类型的自然语言文本——不是任何一种编程语言/标记语言。

原因很简单,因为在这一个截屏里,没有任何连续的ASCII字符。除非是易语言这种打着中文变成七号的语言,否则大部分编程语言(哪怕是写这篇文章用的Markdown标记语言)都要涉及到连续的ASCII字符。

知道了是自然语言,我们还能确定这个语言基本上不是西欧那些语言——否则不至于一个像样的拉丁字母都看不到。结合对于发帖人的了解,我猜这个大概是CJK中的某一种语言。

既然是自然语言,那么能看出来这应该是某一篇文章的开头。结合深绿色(其实后来发现是黄色,是因为摄屏时白平衡错了)背景,合理猜测是WPS的护眼模式(猜得很远,后面解释为什么这么猜测),那么限定了文件类型:不是PDF,就是DOC家族成员。

但至于具体是哪一个文件就不知道了,都有可能。

除了从技术角度去看以外,还可以从文本排版格式来看。之前已经说了,这是自然语言文本。前面又很像是文本的开头标题,因此“标题”下面的这一行小东西应该就是某种说明,看长度不是作者之类的信息,那就说明是时间或者地点或者两者都有,总之是一种标注信息。

image

看来一篇文章不需要标注作者,但是需要标注其他的信息。而且下面一行小字还不够,需要再用一个星号在页脚做注释。很有可能是书信或者选集或者演讲稿件。这样的话这个文件是PDF的概率很大,我们之后按照这个假设来走。

但是这些都不能构成entry point。

到这里,你可能会问:

Nick老师,我们为什么要做这些分析呢?直接把这些字符输入到编码/解码工具里挨个试编码,总有试出来的时候嘛!

也可以,我们可以拿标题来试一下这个方案。从这张图片来看,本文标题应该是:

ŌйúÉç»á¸÷½×¼¶µĀ·ŌÎō

如果按照UTF-16BE(PDF的默认编码方案,viz. PDF 1.7文件标准第85页表格),结果如下:

014C,00D0,00B9,00FA,00C9,00E7,00BB,00E1,
00B8,00F7,00BD,00D7,00BC,00B6,00B5,0100,
00B7,014C,00CE,014D

到这里基本上不用再试别的了,可以直接宣告凉凉了。

为什么?因为这个字的高8位诡异滴hin啊!我们可以考虑两种可能的情况:

  1. 万恶的程序员把宽字符切错了,把16位的编码分在两个wchar里。 但这样所有的高位应该都是0x00才对,但是很明显Ō(0x014C)它就不干了……
  2. 这是J/K/TC的编码系统。 更是一棍子打死。无论是日语的Shift-JISEUC-JP还是ISO-2022-JP,韩语的EUC-KR,以及我国宝岛常用的Big5,都需要高位>0x80!不可能,绝对不可能……
  3. 我们本身输入有误。 本来就是不清晰的屏摄,还涉及了拉丁扩展字母,输错一些东西很正常的。比如说Ō前面的这个·就很可能是错误的。而Ō本身到底对不对其实也有待商榷(后面证实这个字母确实输错了,但是现在即便告诉你错了你也找不到对的字母,哈哈)

那怎么办呢?

还有那个Entry Point到底在哪里呢?

0x2 自然语言

著名的北外校友何炅老师曾经说过一句话:

谁说这豆角老的,这豆角可太棒了!

我在不付任何版权费的情况下想要借用他的这句话:

谁说这自然语言没用的,这自然语言可太有用了!

再看一遍图片里的“正文”,你会发现每一段的结尾都很妙:

image

为什么妙呢?另外为什么要画出两个字符呢?请看VCR:

image

这个模式非常熟悉,甚至在开头短短这一部分就重复了六次。这种情况下可能在编程语言里很常见(保留字呗),但是在自然语言里绝对值得关注。

但你可能会说:

不就是全文的主题词嘛?

非也!主题词在文中尚可以解释,但是主题词难道会出现在句末嘛?

在句末的必然是一个标点符号。也就是说这个¡£肯定是标点符号,且我猜这应该是,因为这么频繁出现一定是句号或者逗号,而逗号不能出现在段尾。

Entry Point这不就来了!

现在,我们只需要分析怎么将转换为¡£就可以了。

先确定¡£的UTF-16BE编码是:

0x00A1, 0x00A3

然后我们惊喜地发现,的GBK编码刚好就是0xA1A3。

哇咔咔!

再用£¿试一下,£¿的UTF-16BE编码是:

0x00A3, 0x00BF

您猜怎么着!的GBK编码刚好就是0xA3BF!

那就明白了:

这个PDF文档是中文文档,原本是想要使用GBK编码,但是出于某种原因在生成PDF的时候没有考虑原本的编码,反而全都当UTF-16BE编码做成了一个一个的16位宽字符。

那有了这个基础,我们对于上一节的标题就能进行进一步处理了:

014C,00D0,00B9,00FA,00C9,00E7,00BB,00E1,
00B8,00F7,00BD,00D7,00BC,00B6,00B5,0100,
00B7,014C,00CE,014D

去掉一些明显不正确的字符并将其用0xA3BF(刚刚的)代替,就变成了

A3BF, B9FA, C9E7, BBE1, B8F7, BDD7, BCB6, A3BF, A3BF, A3BF

解码出来就是:

?国社会各阶级???

那么第一个问号是什么呢?有可能是“我国”,也有可能是“中国”,或者什么别的国家,先用“我”试一下:

GBK编码是0xCED2,按照这个PDF编码规则分解为0xCE和0xD2,不符合0x00D0。
GBK编码是0xD6D0,分解为0xD6和0xD0,正好符合!

再看0x00D6在UTF-16BE中是什么:是Ö……原来那个短横线是两点……虽然但是我学德语的时候也曾经用过这个shorthand,但是冷不丁一看,确实很难想起两点这一个可能……

好,以此类推,我们可以将这个标题纠正为:

ÖйúÉç»á¸÷½×¼¶µÄ·ÖÎö

经过上述的转换,这个文章标题是:

中国社会各阶级的分析

这是《毛选》的第一篇文章。得出这个PDF就是《毛选》。剩下的只要找到一本能看的PDF,内容就都出来了!

0x3 结束

至此,完成推理~和发帖人核对了一下信息,基本上都是对的。

但是唯独一点:这个PDF本身就有背景颜色,是米黄色。但是在屏摄的时候由于屏幕反光和摩尔纹干扰,给人一种底色是绿色的感觉……实际上这个浏览器是iOS中微信的PDF预览程序。

没事,总归是得出主要信息了。休息结束(^^ゞ滚去看口译材料了。

0x4 鸣谢

感谢Ms. JIAO Yufeng的朋友圈和原始下载文件。这篇文章使用了由她提供的照片和原始下载文件。

这篇文章同时使用了以下公开资源:

  1. Adobe公司的PDF 1.7文件定义

作者Nick Pang,在CC BY-SA 4.0许可下发布。

posted @ 2025-09-28 16:50  Nicholas-Flare  阅读(42)  评论(0)    收藏  举报
如未声明,则所有博客采用CC0授权。