从二维码照片解码内核崩溃
Decode kernel panic from QR Code photo

原始链接: https://gist.github.com/skorotkiewicz/c59e591c26661cb52b06afc42d8ac546

这个 Python 脚本将 Linux 内核 panic 二维码解码为崩溃日志。它使用 ZXingReader 扫描图像中的二维码,解析 URL 中压缩的 `z` 参数,将十进制数字组转换为小端字节,并使用 zlib 解压缩结果。恢复的日志写入标准输出或输出文件。它会验证输入,并妥善处理格式错误的二维码/URL 数据、缺失的依赖、输出错误和管道中断。

Hacker News 最新 | 过去 | 评论 | 提问 | 展示 | 工作 | 提交 登录 从二维码照片解码内核崩溃 ( gist.github.com ) 5 分 由 modinfo 1 小时前 | 隐藏 | 过去 | 收藏 | 讨论 帮助 考虑申请 YC Winter 2027 批次!申请开放至 11 月 2 日。 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系 搜索:
相关文章

原文
#!/usr/bin/env python3 """ Scan a Linux panic QR code with ZXingReader and decompress its crash log. ./decode-kernel-panic.py screenshot.png -o panic.log """ import argparse import json from pathlib import Path import subprocess import sys from urllib.parse import parse_qs, urlsplit import zlib def decode_panic_url(url): """Decode the kernel's z parameter: 17 decimal digits per 7 little-endian bytes. Format reference: https://github.com/kdj0c/panic_report """ parts = urlsplit(url) parameters = parse_qs(parts.query, keep_blank_values=True) if "z" not in parameters: parameters = parse_qs(parts.fragment.lstrip("?"), keep_blank_values=True) if "z" not in parameters: raise ValueError("QR code URL has no compressed panic data (z parameter)") if len(parameters["z"]) != 1: raise ValueError("QR code URL has multiple z parameters") digits = parameters["z"][0] if not digits or not digits.isascii() or not digits.isdecimal(): raise ValueError("panic data must contain only decimal digits") # A final, partial group uses fewer digits and bytes. byte_counts = {3: 1, 5: 2, 8: 3, 10: 4, 13: 5, 15: 6, 17: 7} compressed = bytearray() for offset in range(0, len(digits), 17): chunk = digits[offset:offset + 17] if len(chunk) not in byte_counts: raise ValueError("invalid length of encoded panic data") try: compressed.extend(int(chunk).to_bytes(byte_counts[len(chunk)], "little")) except OverflowError as exc: raise ValueError("encoded panic data contains an out-of-range chunk") from exc return zlib.decompress(compressed) def scan_image(image): if not image.is_file(): raise ValueError(f"image does not exist or is not a file: {image}") try: result = subprocess.run( ["ZXingReader", "-formats", "QRCode", "-json", str(image.resolve())], capture_output=True, text=True, ) except FileNotFoundError as exc: raise ValueError("ZXingReader is required; install it and put it on PATH") from exc if result.returncode != 0: detail = result.stderr.strip() or "no readable QR code found" raise ValueError(f"ZXingReader failed: {detail}") if not result.stdout.strip(): raise ValueError("no readable QR code found") try: qr = json.loads(result.stdout) except json.JSONDecodeError as exc: raise ValueError("expected one QR code in ZXingReader's JSON output") from exc if not isinstance(qr, dict) or not isinstance(qr.get("Text"), str): raise ValueError("ZXingReader returned no QR code text") return qr["Text"] def main(): parser = argparse.ArgumentParser( description="Scan a Linux panic screenshot with ZXingReader and decompress its log.", epilog="Requires Python 3 and ZXingReader. Decoding runs locally without network access.", ) parser.add_argument("image", type=Path, help="screenshot or photo containing the panic QR code") parser.add_argument("-o", "--output", type=Path, help="write the log to a file instead of stdout") args = parser.parse_args() try: if args.output and args.output.resolve() == args.image.resolve(): raise ValueError("output must differ from the input image") log = decode_panic_url(scan_image(args.image)) if args.output: args.output.write_bytes(log) else: sys.stdout.buffer.write(log) except BrokenPipeError: # Allow commands such as `decode-kernel-panic screenshot.png | head`. import os os.dup2(os.open(os.devnull, os.O_WRONLY), sys.stdout.fileno()) return 0 except (OSError, ValueError, zlib.error) as exc: print(f"{parser.prog}: {exc}", file=sys.stderr) return 1 return 0 if __name__ == "__main__": sys.exit(main())
联系我们 contact @ memedata.com