百科问答小站 logo
百科问答小站 font logo



如何笔算解码二维码? 第1页

  

user avatar   dong_nan_xi_bei 网友的相关建议: 
      

先给题主一个小思路吧,假设这个二维码完好无损,我以四个汉字编为二维码为例(最小尺寸)。

由于在知乎二维码会自动转换成文字,因此原图见该链接

pic4.zhimg.com/v2-07f7d

不想点链接的,可以看技术处理过的图:

注意事项:

  1. 下文中的「二维码」一词,默认为 QR 码,即快速响应矩阵图码,同时本文主要讲解使用 UTF-8 的情况(文末附 Shift_JIS 的情况);
  2. 仅限于部分较小的二维码,尺寸过大的,编码的顺序会有交错(即使是同一尺寸的,可能也要看运气),则不适用于下面的方法

预备节:认识二维码构造

我想大家初次接触二维码时最深的印象肯定是三个角落的正方形,因为非常显眼,它们叫寻象图形。事实上,里面可能还暗藏小正方形(最小尺寸的二维码没有),叫校正图形。此外,连接两个相邻的寻象图形的内侧边缘处正好有黑白相间的线条,叫定位图形。最后,三个寻象图形的旁边会有一些格式信息(左上寻象图形的两侧、右上寻象图形的下侧、左下寻象图形的右侧各一排):

而我们真正要破译的部分,则是剩下的浅绿色的区域,当然不是全部,因为其中只有一部分能得到我们想要的数据,剩下的部分是纠错码字(有了它,可以在二维码里贴图徽而仍能扫出)。

值得一提的是,尺寸再大一点的二维码,即校正图形有 6 个及以上时,在右上寻象图形左侧三排、左下寻象图形上侧三排,还会有版本信息这东西,在破译时也要避开这些位置:

最后稍微了解下二维码的解码顺序,整体而言是从右边起,向上向下交错:

好,了解这些区域在破译时要避开后,我们现在可以开始实战演练了!

第一步:去掩码

可能有些人阅读下文后会有人问:去掩码的原理简单,但笔算(甚至心算)起来要非常细心。那么掩码存在的意义是什么?可以见这篇答案:二维码生成时为什么要再加一个掩码图案计算呢?

我们要看左上角的寻象图形正下方的这三块找到相应的掩码:

然后我们不难发现,是下表中的 ((i*j)%3+1+j)%2=0 的款式:

选好款式之后,我们先将掩码铺盖好:

二维码中要去掩码的部分为如下红色区域(即数据与纠错码字区域,由于是最小的二维码,因此没有校正图形):

以白为 0,以黑为 1,去掩码则是将原二维码与掩码同一坐标的数据做半加法(即 XOR,同色得白,异色得黑):

当然也可以交给 Photoshop 处理,建立二维码与掩码图案两个图层(掩码图层在上,二维码图层在下),然后掩码反相,最后两者用差值混合图层(因为差值做的是减法,要反相)。

去掉掩码后如此图(未被上上图红色部分覆盖的部分则原封不动,同时注意此时已扫不出来):

第二步:确定类别

我们现在可以开始解码了,不过先不急着破译。我们要先看的是右下用的 4 块:

编码的顺序为 Z 字型(从右下开始曲折往上),即右下、左下、右上、左上。白(浅)记 0,黑(深)记 1,得二进制数 0100

常见的有 0001 表示「纯数字」,0010 表示「字母数字」(但字母不区分大小写),0100 表示「8 位字节编码(UTF-8)」(通常使用这种,即使是纯英文文章或网址),1000 表示「日本汉字(要经过计算后转换为 Shift_JIS 编码)」。

第三步:确定长度

接着再往上看 8 块(蓝色框内):

同样我们按照 Z 字形的顺序,破译出 0000 1100,转成十进制数为 12:

在不同的编码类别(红框)下,对编码长度的理解不尽相同,这里用的是字节编码模式,编码长度表示的是字节数,即本文有 12 字节了解这点非常重要,可以告诉你到哪里破译结束。

值得一提的是,二维码大到一定尺寸时,表示编码长度的区域可能为 8 位以上(视编码类别而定,比如可能扩充为 16 位来表示编码长度),这里不展开讨论

第四步:解码破译

前面两关过了后,我们关心的破译数据就要开始了。我们知道,一个字节有 8 位,则以 8 位为单位一个个破译下来。首先继续往上看 8 块:

按图示的解码顺序,得第一字节为 1110 0100

按照顺序继续破译第二字节,不过要注意最上面一排有格式信息的部分,不要编进去,而要转弯向下

第二字节为 1011 1000。

我们依次破译下去(红色数字表示字节次序):

我们得到:

  1. 1110 0100
  2. 1011 1000
  3. 1001 1100
  4. 1110 0101
  5. 1000 1101
  6. 1001 0111
  7. 1110 1000
  8. 1010 0101
  9. 1011 1111
  10. 1110 0101
  11. 1000 1100
  12. 1001 0111

第五步:转换文字

这是 UTF-8 编码,有关 UTF-8 可以见UTF-8_百度百科,这里不展开讨论。

我们的目的是将 UTF-8 编码转换成 Unicode 编码然后查找对应字符。由于编码的内容为汉字,在 UTF-8 里每个汉字需用 3 个字节来表示,得前三个字节:

  • 第一字节:1110 0100
  • 第二字节:1011 1000
  • 第三字节:1001 1100

转换成 Unicode 时要去掉这三个字节前面 1110、10、10(上面加下划线的部分),剩下的组合在一起得到:

  • 0100 1110 0001 1100

最后转换为十六进制的 4E1C,在电脑中打开字符映射表,查到 U+4E1C 对应「」字:

(这里只能查表了,除非你能把 Unicode 码表背得滚瓜烂熟。)

同样,后面三个字节:

  • 第四字节:1110 0101
  • 第五字节:1000 1101
  • 第六字节:1001 0111

0101 0011 0101 0111U+5357→「

处理完这 12 个字节后得到「东南西北」四个字,此时破译结束。


总结图表如下:

(上图中的黑色部分为纠错码字部分,一般情况下没有破译的必要,但如果在当中插了图徽或者缺损的二维码,则有可能要利用剩余的纠错模块破译,此时算法较为复杂,本人暂时无法讲解。)


应大家的要求,我增添了相对实用的情况,即二维码的网址的破解方法。如果是纯字母的那还相对容易,如果是混有数字的就有一点难度了。

比如本文的链接为:zhihu.com/question/6525

需要注意的是斜杠「/」,它在 0010(字母数字模式)下也有,在 0100(字节模式 UTF-8)下也有,使用哪一种取决于节省编码长度的方式。

原二维码(原图:pic3.zhimg.com/80/v2-87):

去除掩码后:

破译细节举例:

附一:字节模式(0100)下的十进制编码表(UTF-8 或 ASCII 码表)

附二:字母数字模式(0010)下的十进制编码表(注意:不适用网址的小写字母,其中 43 代表斜杠)


附:Shift_JIS 处理方法

原二维码见此图pic1.zhimg.com/v2-61182

技术处理图:

去掉掩码后:

这个时候我们仍将视线从右下角看起:

此时 Enc 的编码为 1000,属于日本汉字编码之类;Len 为 0010 0111,十进制为 39,注意在日本汉字模式下表示字符数量而非字节数量,即本文有 39 个字符。

然后比较变态的操作开始了,是每 13 位为一组,比如第一组(图中的数字表示顺序,1 到 13 对应权 到 ):

得到 13 位二进制数:0101101000110,换成十六进制B46

还没完,还要进行一波操作:

  1. 将该十六进制数除以 C0 并取整数部分(示例: );
  2. 上述结果通常小于或等于 1E,则加上 81;少数情况会大于或等于 1F,此时加上 C1;该结果作为高字节(示例: ,高字节为 90);
  3. 回到原先的十六进制数,除以 C0 取余数部分(示例: );
  4. 上述结果加上 40,该结果作为低字节(示例: ,低字节为 46)。

我们将原先的 B46 转化为到四位十六进制数 9046,对应 Shift_JIS 中的「」字(注意要将字符集切换成日语,查的是 0x 起头的编码)

同样,我们继续破译紧接着的 13 位二进制数(蓝色部分,从 1 到 13 的顺序):

000010100110114D

  • 14D÷C0 取整得 1→1+81=82(高字节)
  • 14D÷C0 取余得 8D→8D+40=CD(低字节)

82CD→「

依此类推,我们一个个破译得出:

色は匂へど散りぬるを我が世誰ぞ常ならむ有為の奥山今日越えて浅き夢見じ酔ひもせず

(共 39 字)




  

相关话题

  如何证明一个无理数的整数倍数的小数部分在(0,1)上均匀分布? 
  有没有办法从数学上定义脸蛋的光滑性? 
  失传的缀数法最有可能是什么方法? 
  常微分方程的有没有什么学习经验? 
  有什么与数学名词有关的趣事? 
  普遍认为数学难学,你能说说数学到底难在哪里吗? 
  请问这种积分如何计算? 
  有哪些数学上的定理让你感觉「这不显然吗,这还用证明」? 
  怎么逐步学习 PDE? 
  函数方程 f(xy)=f(x)+f(y) 的严格解是什么?解是否唯一? 

前一个讨论
历史上汉族有入侵他国的记录吗?
下一个讨论
纯美学考虑最好看的国旗是哪个?





© 2024-11-21 - tinynew.org. All Rights Reserved.
© 2024-11-21 - tinynew.org. 保留所有权利