二维码(QRCODE)纠错容错位读取修复操作

本文介绍了在CTF比赛中遇到的一道与二维码相关的解题过程。通过研究二维码的纠错机制,了解到纠错信息存储位置以及不同纠错等级的编码。在无法直接扫描出结果的情况下,需要对比和修复二维码的纠错位。最终,通过调整纠错容错等级成功解析出二维码的内容。解题过程中涉及到的知识点包括二维码的纠错码、容错率、以及如何利用编程修复错误信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一次CTF比赛的杂项解题遇到了一道和二维码相关的题目,但是利用扫描工具扫描不出来结果,随后查阅了二维码的相关资料,定位到了问题出在二维码的校验码上。需要读取二维码的纠错容错位,然后比对两个纠错容错码,最后修复二维码纠错位扫码找到结果。

二维码是一个仅支持校验和纠错的编码,对于纠错功能比较直观的感受就是遮挡了一部分非关键区块之后二维码还可以扫出结果。在计算机网络课程里面多多少少都会提到校验码、纠错码的概念,简单啰嗦一下。校验码是能发现信息代码中存在错误的编码算法,最常见的是CRC算法,在文件校验、网络校验中都有应用。纠错码除了能检查到错误还可以一定程度纠正错误情况保证不出意外的编码,海明码(Hamming Code)是常见的纠错码。

二维码纠错信息存储的位置

二维码纠错信息所在的位置(以25*25大小的二维码为例,不同版本有差异),第一个纠错串信息在左上角定位符附近:

(8, 0),(8, 1),(8, 2),(8, 3),(8, 4),(8, 5),(8, 7),(8, 8),(7, 8),(5, 8),(4, 8),(3, 8),(2, 8),(1, 8),(0, 8)

第二个纠错串信息在右下角定位符附近:

(24, 8),(23, 8),(22, 8),(21, 8),(20, 8),(19, 8),(18, 8),(8, 17),(8, 18),(8, 19),(8, 20),(8, 21),(8, 22),(8, 23),(8, 24)

注意,这里两个纠错字符串的信息必须一致才能进行纠错操作。测试很多工具扫码遇到两个纠错字符串不一致时会忽略,从而识别不出二维码内容。

二维码纠错容错等级

二维码的纠错等级,容错等级。纠错等级是指容错率的大小,按照容错率从小到大可分L(<7%),M(<15%),Q(<25%),H(<30%)。容错率也叫纠错率。纠错率指的就是二维码能被正常扫描时允许被遮挡的最大面积占总面积的比率,确保二维码在被遮挡部分面积后仍能被正常扫描。

纠容错等级纠错串
L0111011111000100
L1111001011110011
L2111110110101010
L3111100010011101
L4110011000101111
L5110001100011000
L6110110001000001
L7110100101110110
M0101010000010010
M1101000100100101
M2101111001111100
M3101101101001011
M4100010111111001
M5100000011001110
M6100111110010111
M7100101010100000
Q0011010101011111
Q1011000001101000
Q2011111100110001
Q3011101000000110
Q4010010010110100
Q5010000110000011
Q6010111011011010
Q7010101111101101
H0001011010001001
H1001001110111110
H2001110011100111
H3001100111010000
H4000011101100010
H5000001001010101
H6000110100001100
H7000100000111011

解题代码

图片本身有白色外边,先进行裁边,返回图片实际像素数量和一个信息编码位的比例。

def position(stdsize=25):
    from PIL import Image
    
    qr = Image.open('key.png')
    x, y = qr.size
    start = x
    end = 0
    for i in range(x):
        for j in range(y):
            if qr.getpixel((i, j)) != 1:
                start = min(i, j, start)
                end = max(i, j, end)
    img2 = qr.crop((start + 1, start + 1, end + 1, end + 1))
    proportion = (end - start) // stdsize
    return img2, proportion

还原信息到当前二维码25*25大小的数组上,并输出当前二维码的两个纠错容错等级。

dic = {
        "L0": "111011111000100",
        "L1": "111001011110011",
        "L2": "111110110101010",
        "L3": "111100010011101",
        "L4": "110011000101111",
        "L5": "110001100011000",
        "L6": "110110001000001",
        "L7": "110100101110110",
        "M0": "101010000010010",
        "M1": "101000100100101",
        "M2": "101111001111100",
        "M3": "101101101001011",
        "M4": "100010111111001",
        "M5": "100000011001110",
        "M6": "100111110010111",
        "M7": "100101010100000",
        "Q0": "011010101011111",
        "Q1": "011000001101000",
        "Q2": "011111100110001",
        "Q3": "011101000000110",
        "Q4": "010010010110100",
        "Q5": "010000110000011",
        "Q6": "010111011011010",
        "Q7": "010101111101101",
        "H0": "001011010001001",
        "H1": "001001110111110",
        "H2": "001110011100111",
        "H3": "001100111010000",
        "H4": "000011101100010",
        "H5": "000001001010101",
        "H6": "000110100001100",
        "H7": "000100000111011"}
l1 = [
    (8, 0),
    (8, 1),
    (8, 2),
    (8, 3),
    (8, 4),
    (8, 5),
    (8, 7),
    (8, 8),
    (7, 8),
    (5, 8),
    (4, 8),
    (3, 8),
    (2, 8),
    (1, 8),
    (0, 8)]
l2 = [
    (-1, 8),
    (-2, 8),
    (-3, 8),
    (-4, 8),
    (-5, 8),
    (-6, 8),
    (-7, 8),
    (8, -8),
    (8, -7),
    (8, -6),
    (8, -5),
    (8, -4),
    (8, -3),
    (8, -2),
    (8, -1)]


def reshape(img2, sub_step):
    sub_step = step
    result = []
    result2 = []
    x, y = img2.size
    for i in range(0, x, sub_step):
        tmpl = []
        tmpl2 = []
        for j in range(0, y, sub_step):
            tmpl.append(1 - img2.getpixel((j, i)))
            tmpl2.append(img2.getpixel((j, i)))
        result.append(tmpl)
        result2.append(tmpl2)
    f1 = ''.join([str(result[i[0]][i[1]]) for i in l1])
    f2 = ''.join([str(result[i[0]][i[1]]) for i in l2])
    for k, v in dic.items():
        if v == f1:
            print(f1, k)
        if v == f2:
            print(f2, k)
    return result2

最后有两种办法,可以暴力枚举纠错容错等级或者用较大的纠错容错等级替换纠错容错位修复图片(测试用L4可以扫出来),最后调用zxing扫描输出结果。

def fix(result2):
    import numpy as np
    import matplotlib.pyplot as plt
    import zxing

    for a, b in enumerate(dic['L4']):
        result2[l1[a][0]][l1[a][1]] = 1 - int(b)
        result2[l2[a][0]][l2[a][1]] = 1 - int(b)
    gray_array = np.array(result2)
    plt.imshow(gray_array, cmap='Greys_r')  # 转灰度图
    plt.axis('off')  # 不显示坐标轴
    plt.imsave('final.png', gray_array, cmap='Greys_r')
    
    new_qr = zxing.BarCodeReader()
    pw = new_qr.decode('final.png')
    pw = pw.parsed
    print(pw)


a1, a2 = position()
a3 = liupi(a1, a2)
fix(a3)
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值