android-wechat-sender-frida.js 1.79 KB
/**
 * android-wechat-sender-frida.js — 基于 Frida Daemon 的微信消息发送
 *
 * 原理:写入队列文件 /data/local/tmp/frida_daemon/queue.jsonl
 *       由常驻微信进程的 Frida daemon 读取并发送
 *
 * 前提:
 *   1. frida-server 运行中
 *   2. frida_daemon.js 已注入微信进程(通过 Mac 端 frida CLI)
 *   3. 队列目录 /data/local/tmp/frida_daemon/ 存在且可写
 *
 * 注意:发送为 fire-and-forget,daemon 会异步处理队列。
 *       如需确认送达,可通过 sqlcipher 查询 message 表。
 */

const fs = require('fs');

const QUEUE_DIR = '/data/local/tmp/frida_daemon';
const QUEUE_FILE = QUEUE_DIR + '/queue.jsonl';

function ensureDir() {
  try {
    if (!fs.existsSync(QUEUE_DIR)) {
      fs.mkdirSync(QUEUE_DIR, { recursive: true });
      fs.chmodSync(QUEUE_DIR, 0o777);
    }
  } catch (e) {
    // ignore
  }
}

/**
 * 使用 Frida daemon 发送文本消息(fire-and-forget)
 * @param {string} toUser — wxid / 群聊ID
 * @param {string} content — 消息内容
 * @returns {Promise<{ok: boolean, error?: string}>}
 */
async function sendTextMessageFrida(toUser, content) {
  if (!toUser || !content) {
    return { ok: false, error: 'toUser and content are required' };
  }

  ensureDir();

  const id = 'msg_' + Date.now() + '_' + Math.random().toString(36).slice(2, 8);
  const payload = JSON.stringify({ talker: toUser, content, id }) + '\n';

  try {
    fs.writeFileSync(QUEUE_FILE, payload);
    fs.chmodSync(QUEUE_FILE, 0o666);
  } catch (e) {
    return { ok: false, error: `Failed to write queue: ${e.message}` };
  }

  // Fire-and-forget: daemon will process asynchronously
  // 给 daemon 一点时间处理(通常 < 1s)
  await new Promise(r => setTimeout(r, 500));
  return { ok: true };
}

module.exports = { sendTextMessageFrida };