Skip to content

WeChat 4.1+ key extraction: root cause + solution (PBKDF2 passphrase derivation) #96

@TANGandXUE

Description

@TANGandXUE

Problem

WeChat 4.1+ (Linux/macOS) no longer caches raw database encryption keys in the x'<64hex_key><32hex_salt>' format in process memory. This breaks the memory scanning approach used by this project and all similar tools.

Related issues: #49, jackwener/wx-cli#30, Thearas/wechat-db-decrypt-macos#9

Root Cause

We performed exhaustive analysis:

  • 387 million 16-byte-aligned HMAC brute-force candidates across all 20 WeChat processes → 0 hits
  • Raw database salt bytes found in ephemeral subprocesses (alive for seconds, then exit)
  • The x'<hex>' patterns in main process memory contain different salts — they are not the database keys

The actual mechanism: WeChat 4.1+ stores a passphrase (not raw key) in memory. The enc_key is derived via:

enc_key = PBKDF2-SHA512(passphrase, db_salt, iterations=256000, dklen=32)

This is consistent with SQLCipher's standard PRAGMA key behavior — the passphrase is passed to sqlite3_key(), and SQLCipher internally derives the raw key. Previous versions cached the post-derivation raw key in x'<hex>' format (which skips PBKDF2). Version 4.1+ stopped doing that.

Solution

ELF Static Analysis + GDB Breakpoint + PBKDF2 Derivation

1. Auto-locate breakpoint via ELF analysis

Search .rodata for com.Tencent.WCDB.Config.Cipher, trace LEA RSI xrefs in .text, find function head. This gives the breakpoint virtual address automatically for any WeChat version — no manual reverse engineering needed.

Verified offsets:

  • WeChat 4.1.1.4 Linux x86_64: 0x673A830
  • WeChat 4.1.0.10: 0x658FC90
  • WeChat 4.1.0.16: 0x6586C90

2. GDB breakpoint capture

Attach GDB to WeChat, set breakpoint, user re-logs in, read passphrase from *(void**)($rsi+8) (32 bytes). Detach immediately.

3. PBKDF2 derivation

For each database file, read its 16-byte salt from page 1, derive:

enc_key = hashlib.pbkdf2_hmac("sha512", passphrase, salt, 256000, dklen=32)

Result: 23/23 databases verified successfully on WeChat 4.1.1.4 Linux.

4. Caching

Save passphrase to disk (chmod 600). On subsequent runs, derive keys from saved passphrase — no GDB needed. If keys file already exists and validates, skip derivation entirely (instant startup).

Standalone Tool

We open-sourced this as: https://github.com/TANGandXUE/wcdb-key-tool

Single Python file, zero third-party dependencies (uses ctypes for libcrypto), auto-adapts to new versions.

Suggested Integration

The key change needed in find_all_keys_linux.py:

  1. After memory scan finds 0 matching keys, try loading saved passphrase + PBKDF2 derivation
  2. If no saved passphrase, fall back to GDB capture flow
  3. Add elf_analyzer module for auto breakpoint offset detection

Happy to submit a PR if there's interest in integrating this approach.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions