diff --git a/xhs_lsposed_a16_fix/backups/wechat_send_20260707.sh b/xhs_lsposed_a16_fix/backups/wechat_send_20260707.sh new file mode 100755 index 0000000..016e0a1 --- /dev/null +++ b/xhs_lsposed_a16_fix/backups/wechat_send_20260707.sh @@ -0,0 +1,86 @@ +#!/bin/bash +# wechat_send.sh — unified WeChat send CLI via the internal hook +# +# Usage: +# ./wechat_send.sh text +# ./wechat_send.sh image +# ./wechat_send.sh voice [duration_ms] +# +# All send operations go through the wechathook LSPosed module's internal API, +# which calls WeChat's own w11.r0/w11.s1 factory — no UI simulation. +# : talker id as stored in WeChat DB (e.g. 'filehelper', 'wxid_xxx'). +# IMPORTANT: test-only with 'filehelper' to avoid account risk. +# +# Voice notes: +# — local SILK V3 file (Tencent prefix \x02#!SILK_V3). +# [duration_ms] — playback duration in ms (default: 3000). +# The script pushes the SILK to WeChat's cache dir and fires the broadcast. +# +# Examples: +# ./wechat_send.sh text filehelper "hello world" +# ./wechat_send.sh image filehelper /tmp/screenshot.png +# ./wechat_send.sh voice filehelper /tmp/tts_out.silk 4617 + +set -e + +ADB="${ADB:-adb}" +WECHAT_CACHE="/data/data/com.tencent.mm/cache/hook_voice_src.amr" + +usage() { + echo "Usage: $0 text " + echo " $0 image " + echo " $0 voice [duration_ms]" + exit 1 +} + +[ $# -lt 3 ] && usage + +CMD="$1"; WXID="$2"; shift 2 + +case "$CMD" in +text) + PAYLOAD="$*" + B64_WXID=$(printf '%s' "$WXID" | base64 | tr -d '\n') + B64_TEXT=$(printf '%s' "$PAYLOAD" | base64 | tr -d '\n') + INNER=$(printf 'TO=$(printf "%%s" "%s" | base64 -d); TEXT=$(printf "%%s" "%s" | base64 -d); am broadcast -a com.hermes.wechat.SEND_MSG_INTERNAL --es to "$TO" --es text "$TEXT"' \ + "$B64_WXID" "$B64_TEXT") + B64_INNER=$(printf '%s' "$INNER" | base64 | tr -d '\n') + echo "Sending text to $WXID..." + $ADB shell "su -c 'echo $B64_INNER | base64 -d | sh'" + ;; + +image) + # Internal API: WeChat's own b80.u.oj (insert+prebuild) + v70.w.oj (CDN upload). + # No UI, no contact picker — fire-and-forget to . Verified full-res delivery. + IMAGE_PATH="$1" + [ -z "$IMAGE_PATH" ] && usage + EXT="${IMAGE_PATH##*.}" + # Stage into /sdcard so the WeChat process (runs the hook) can read it, regardless + # of whether the source path is root-only. If already under /sdcard this is a no-op copy. + SHARE="/sdcard/wechat_send_tmp.$EXT" + echo "Staging image to $SHARE..." + $ADB shell "su -c 'cp \"$IMAGE_PATH\" \"$SHARE\" && chmod 644 \"$SHARE\"'" + echo "Sending image to $WXID via internal API..." + $ADB shell "su -c 'am broadcast -a com.hermes.wechat.SEND_IMAGE_INTERNAL --es to \"$WXID\" --es path \"$SHARE\"'" + echo "Sent. (Verify via WeChat UI screenshot; full image uploads async via CDN.)" + ;; + +voice) + SILK_PATH="$1" + DURATION="${2:-3000}" + [ -z "$SILK_PATH" ] && usage + [ ! -f "$SILK_PATH" ] && { echo "File not found: $SILK_PATH"; exit 1; } + + echo "Pushing SILK to WeChat cache..." + $ADB push "$SILK_PATH" /sdcard/hook_voice_tmp.amr + $ADB shell "su -c 'cp /sdcard/hook_voice_tmp.amr $WECHAT_CACHE && chmod 644 $WECHAT_CACHE && chown u0_a330:u0_a330 $WECHAT_CACHE && rm /sdcard/hook_voice_tmp.amr'" + + echo "Sending voice to $WXID (duration=${DURATION}ms)..." + $ADB shell "su -c 'am broadcast -a com.hermes.wechat.SEND_VOICE_INTERNAL --es to $WXID --es src_path $WECHAT_CACHE --ei duration $DURATION'" + ;; + +*) + echo "Unknown command: $CMD" + usage + ;; +esac diff --git a/xhs_lsposed_a16_fix/skill_wechat_send/SKILL.md b/xhs_lsposed_a16_fix/skill_wechat_send/SKILL.md index d317003..3a72afd 100644 --- a/xhs_lsposed_a16_fix/skill_wechat_send/SKILL.md +++ b/xhs_lsposed_a16_fix/skill_wechat_send/SKILL.md @@ -38,11 +38,15 @@ adb shell su -c "am broadcast -a com.hermes.wechat.SEND_MSG_INTERNAL --es to yib ``` 或用封装脚本:`./wechat_send.sh text yibooo "你好火星人"` -### 🟢 图片(消息+缩略图已可发,全图 CDN 上传是最后一公里) +### ✅ 图片(全图 CDN 上传打通,已验证全分辨率送达) ```bash -adb shell su -c 'am broadcast -a com.hermes.wechat.SEND_IMAGE_INTERNAL --es to filehelper --es path /sdcard/Pictures/x.png' +adb shell su -c 'am broadcast -a com.hermes.wechat.SEND_IMAGE_INTERNAL --es to yibooo --es path /sdcard/Pictures/x.png' ``` -现状:图片消息建成、缩略图渲染、进真实发送管线;全图 CDN 上传仍在完善(详见技术文档 §3)。 +或用封装脚本:`./wechat_send.sh image yibooo /sdcard/Pictures/x.png` + +图片走微信自己的 CDN 上传,接收方点开是全分辨率原图(可保存)。`path` 必须是设备上 +`su` 能读到的路径(如 `/sdcard/...`)。发前若图片在 Mac 上,先 `adb push` 到设备。 +2026-07-07 真机验证:filehelper + 真人(火星人)均全图收到。详见技术文档 §3。 ### ✅ 语音(TTS→SILK,半自动 hot-swap) 纯合成卡「发送中」,用 hot-swap:让微信真录一段 + 偷换 SILK 字节。 diff --git a/xhs_lsposed_a16_fix/wechat_send.sh b/xhs_lsposed_a16_fix/wechat_send.sh index d73866a..016e0a1 100755 --- a/xhs_lsposed_a16_fix/wechat_send.sh +++ b/xhs_lsposed_a16_fix/wechat_send.sh @@ -50,18 +50,19 @@ text) ;; image) + # Internal API: WeChat's own b80.u.oj (insert+prebuild) + v70.w.oj (CDN upload). + # No UI, no contact picker — fire-and-forget to . Verified full-res delivery. IMAGE_PATH="$1" + [ -z "$IMAGE_PATH" ] && usage EXT="${IMAGE_PATH##*.}" - SHARE="/sdcard/wechat_share_tmp.$EXT" - MIME="image/jpeg" - [ "$EXT" = "png" ] && MIME="image/png" - echo "Copying image to $SHARE..." + # Stage into /sdcard so the WeChat process (runs the hook) can read it, regardless + # of whether the source path is root-only. If already under /sdcard this is a no-op copy. + SHARE="/sdcard/wechat_send_tmp.$EXT" + echo "Staging image to $SHARE..." $ADB shell "su -c 'cp \"$IMAGE_PATH\" \"$SHARE\" && chmod 644 \"$SHARE\"'" - echo "Sending image to $WXID via share intent..." - $ADB shell "am start -a android.intent.action.SEND -t $MIME \ - --eu android.intent.extra.STREAM 'file://$SHARE' \ - -p com.tencent.mm" - echo "WeChat share intent fired. Select '$WXID' in WeChat's contact picker and tap 发送." + echo "Sending image to $WXID via internal API..." + $ADB shell "su -c 'am broadcast -a com.hermes.wechat.SEND_IMAGE_INTERNAL --es to \"$WXID\" --es path \"$SHARE\"'" + echo "Sent. (Verify via WeChat UI screenshot; full image uploads async via CDN.)" ;; voice)