SuperAPI AI Directory

yichen-wecom-local-vault

Data & analytics

View repository

Updated 10-16 00:22

About this skill

yichen-wecom-local-vault: WeCom Local Data Vault

Only read the Mac WeCom 5.x local database, generate a new private plaintext snapshot, and then query contacts, conversations, and messages from the snapshot. Use it separately from Personal WeChat yichen-wechat-local-vault ; the containers, encryption algorithms, and table structures of the two are incompatible.

Hard boundaries

  • Never click, quit, restart, or re-sign the original /Applications/企业微信.app, and never send WeCom messages.
  • Only when the user explicitly requests “modify boundaries / capture the WeCom key with a re-signed copy / continue full decryption” is it allowed to copy WeCom into a private Vault, ad-hoc re-sign the copy, and launch this copy via Frida to capture the key.
  • The re-signed copy may only be used for data parsing authorized by the owner on this machine; by default do not reuse old copies, do not overwrite existing copies, and do not write to the project or cloud drive.
  • By default, do not attach to the WeCom process. Only when the user explicitly requests “capture the WeCom key / capture the key / continue decryption” may the capture command with --confirm-attach be run; if the system refuses attach, prefer switching to the signed-copy route.
  • Only read the source database and WAL; do not write back to the WeCom container.
  • Do not delete or overwrite any files. Each decryption creates a new timestamped snapshot; each export creates a new file.
  • Do not display raw keys, full account directories, internal contact IDs, or entire private chat transcripts in replies or logs.
  • Plaintext snapshots, keys, and export files are all sensitive data; do not put them in the project, desktop, cloud drive, or Git.

Entry point

SKILL_DIR="${CODEX_HOME:-$HOME/.codex}/skills/yichen-wecom-local-vault"
python3 "$SKILL_DIR/scripts/vault_cli.py" status

Dependencies: daily discovery and querying only require Python 3; decryption requires pycryptodome; passive key capture on Mac additionally requires frida. Do not automatically install dependencies; report missing items first.

Automatically select the workflow

  1. First use or the user asks “can it be parsed”: run status, only check the database, do not attach to the process.
  2. Private key file already available: run decrypt to create a new snapshot; by default merge committed WAL frames.
  3. Key missing: first explain that explicit authorization to capture is required; optionally read-only attach, and if macOS refuses task_for_pid, then use a re-signed copy to capture.
  4. Snapshot already available: directly use sessions、contacts、history、search、export, do not decrypt again.
  5. User specifies a conversation or time range: query only that range; when there are many messages, first write them to a Markdown/JSON file.

Database discovery and inspection

python3 "$SKILL_DIR/scripts/vault_cli.py" discover
python3 "$SKILL_DIR/scripts/vault_cli.py" status
python3 "$SKILL_DIR/scripts/vault_cli.py" status --show-paths
python3 "$SKILL_DIR/scripts/capture_key_macos.py" list
python3 "$SKILL_DIR/scripts/capture_key_macos.py" doctor
python3 "$SKILL_DIR/scripts/scan_dbkey_manager_macos.py" scan

Use --show-pathsonly when the user explicitly needs to see the real path. For multiple accounts, use --data-dir to specify the dataset containing message.db、session.db、user.db .

Capture the Mac WeCom key

This step only passively attaches to an already running process; it does not launch or operate the client. The user's explicit authorization for the current turn must be obtained:

python3 "$SKILL_DIR/scripts/capture_key_macos.py" capture \
  --confirm-attach \
  --duration 60

The capturer listens for CommonCrypto AES/MD5 calls, verifies candidate 16-byte keys one by one against the first page of the local encrypted database; only after successful verification does it write with 0600 to the private Vault, and the terminal does not display the key. If it times out, report “not captured”; do not ask the user to click in the client, and do not re-sign the app yourself.

doctor Read-only check of Python, Frida, Developer Tools, SIP, and database format. If macOS refuses task_for_pid, stop capturing and report the permission boundary; do not automatically disable SIP, relax system taskport or re-sign WeCom. See Frida macOS official documentationandofficial troubleshooting。

Re-signed copy capture route

When attaching to the original WeCom is denied by macOS, and the user explicitly permits modifying the boundary, you can copy and ad-hoc re-sign a copy of WeCom. The script will launch the copy via Frida and wait for the key; if the copy requires login, only prompt the user to log in manually, do not click the UI, do not send messages, do not close the original WeCom. If the original WeCom is still running and causes the copy to be launched by the single-instance mechanism and then exit, you must have the user quit the original client themselves before retrying.

python3 "$SKILL_DIR/scripts/capture_key_macos.py" capture \
  --mode spawn-signed-copy \
  --confirm-signed-copy \
  --duration 240

By default the copy is written to:

~/Library/Application Support/wecom-local-vault/apps/WeComSigned-<timestamp>.app

This route additionally hooks the DbKeyManager::UpdateKey、GetAllLocalEncryptKey callback and the internal wxSQLite3 page encryption/decryption functions. In the current 5.0.x macOS client, the internal page encryption/decryption function copies args[3][0..15], then concatenates the page number and sAlT to derive the per-page AES key; the capturer verifies this 16-byte raw key candidate one by one against the first page of the current local database, and only saves it if verification succeeds.

When Frida is denied by the system, you can instead use a read-only Mach VM scan of DbKeyManager; it does not inject code, does not restart or re-sign the client, and does not operate the UI, but requires the user to enter the administrator password in a local terminal:

python3 "$SKILL_DIR/scripts/scan_dbkey_manager_macos.py" scan --confirm-sudo

This scanner locates the DbKeyManager vtable based on the current process load address, and only reads the Apple libc++ this+0x68 candidate key of std::string ; the candidate is written to the private Vault only after passing verification against the first page of the database, and the terminal does not display the raw key.

Create plaintext snapshot

python3 "$SKILL_DIR/scripts/vault_cli.py" decrypt
python3 "$SKILL_DIR/scripts/vault_cli.py" decrypt --key-file "/private/path/keys-时间戳.json"

By default the snapshot is written to:

~/Library/Application Support/wecom-local-vault/snapshots/<timestamp>-<dataset_id>/

Each snapshot contains manifest.json, and marks contains_plaintext_wecom_data: true. The script decrypts and merges into the new snapshot the pages in the WAL whose header salt matches and which are before the last committed transaction, without modifying the source WAL.

Query and export

python3 "$SKILL_DIR/scripts/vault_cli.py" sessions --limit 50
python3 "$SKILL_DIR/scripts/vault_cli.py" contacts --query "关键词"
python3 "$SKILL_DIR/scripts/vault_cli.py" history "群名或conversation_id" \
  --start "2026-07-01" --end "2026-07-13" --limit 500
python3 "$SKILL_DIR/scripts/vault_cli.py" search "关键词" \
  --chat "群名" --start "2026-07-01" --limit 200
python3 "$SKILL_DIR/scripts/vault_cli.py" export "群名" \
  --start "2026-07-01" --format markdown

By default reads the latest snapshot; when you need to pin an evidence version, pass --snapshot. By default exports are written to exports/in the private Vault, with file permission 0600, and existing target files are always refused for overwrite.

Known limitations

  • Mac key capture depends on WeCom actually opening/reading/writing the encrypted database; if no wxSQLite3 page encryption/decryption call is triggered during capture, the key may not be captured.
  • Message binary content uses generic UTF-8/Protobuf text extraction; images, voice, and file bodies currently only output type placeholders and do not decrypt media.
  • Conversation direction requires a reliable internal ID for the user themselves; when unconfirmed, do not arbitrarily mark the sender as "me".
  • WeCom version upgrades may change key calls or table structures; run offline tests and status before processing real data.

For database format, table structure, and WAL description, see references/database-notes.md。

Verification

cd "$SKILL_DIR/scripts"
python3 test_wecom_local_vault.py
python3 -m py_compile *.py
python3 "$HOME/.codex/skills/.system/skill-creator/scripts/quick_validate.py" "$SKILL_DIR"

Snapshot reading and troubleshooting

  • Queries use a static plaintext snapshot, opened with mode=ro&immutable=1 ; do not use immutable for a running source database.
  • First use python3 -c "import Crypto" to check interpreter dependencies; if missing, report it, do not install automatically.
  • --data-dir accepts a database directory path, not the dataset_id from discovery results. When there are multiple datasets, choose explicitly and do not guess the account.
  • A snapshot only contains data that existed at creation time; check the snapshot time before querying the latest messages. Conversation summary times may lag; rely on the actual times in the message table.
  • File messages differ from media bodies; this query tool does not decrypt media.
  • Compatibility must distinguish client version/build number, operating system, decryption with existing keys, and re-capturing keys; full-version support cannot be inferred from "5.x".