#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ v6 真实操作脚本 v2 - 修复列名问题 先查真实列名,再正确写入 """ import frida, time, json, subprocess from datetime import datetime PHONE_IP = "192.168.110.80" FRIDA_PORT = 27042 ADB_SERIAL = "192.168.110.80:5555" WECHAT_PID = 1452 BASE = "/Users/karuo/Documents/开发/2、私域银行/工作手机" dm = frida.get_device_manager() device = dm.add_remote_device(f"{PHONE_IP}:{FRIDA_PORT}") session = device.attach(WECHAT_PID) events = [] def on_msg(m, d): if m.get("type") == "send": p = m["payload"] events.append(p) t = p.get("type", "") if t not in ("log",): print(f" [EVENT:{t}] {json.dumps(p, ensure_ascii=False)[:100]}") JS = r""" 'use strict'; Java.perform(function() { function getDb(dbName) { var found = null; Java.choose('com.tencent.wcdb.database.SQLiteDatabase', { onMatch: function(instance) { try { var p = instance.getPath(); if (p && p.indexOf(dbName) !== -1) found = instance; } catch(e) {} }, onComplete: function() {} }); return found; } function query(db, sql) { try { var cursor = db.rawQuery(sql, null); var rows = []; if (cursor && cursor.moveToFirst()) { var cols = cursor.getColumnCount(); do { var row = {}; for (var i = 0; i < cols; i++) { try { row[cursor.getColumnName(i)] = cursor.getString(i); } catch(e) {} } rows.push(row); } while (cursor.moveToNext() && rows.length < 20); cursor.close(); } return rows; } catch(e) { return []; } } rpc.exports = { // 查message表真实列名 getMsgTableSchema: function() { var db = getDb('EnMicroMsg.db'); if (!db) return { success: false, error: 'db not found' }; var cols = query(db, 'PRAGMA table_info(message)'); var sample = query(db, 'SELECT * FROM message ORDER BY rowid DESC LIMIT 1'); return { success: true, columns: cols.map(function(c){return c.name;}), sample: sample }; }, // 查StarSnsInfo表真实列名 getStarSnsSchema: function() { var db = getDb('sns_star_info.db'); if (!db) return { success: false, error: 'db not found' }; var cols = query(db, 'PRAGMA table_info(StarSnsInfo)'); var sample = query(db, 'SELECT * FROM StarSnsInfo ORDER BY rowid DESC LIMIT 2'); return { success: true, columns: cols, sample: sample }; }, // 操作1:发送消息(动态获取列名后写入) sendMessageFixed: function(params) { var toId = params.to_id || 'filehelper'; var content = params.content || 'test'; var db = getDb('EnMicroMsg.db'); if (!db) return { success: false, error: 'db not found' }; try { // 查真实列名 var cols = query(db, 'PRAGMA table_info(message)'); var colNames = cols.map(function(c) { return c.name; }); var ts = Math.floor(Date.now() / 1000); var msgId = String(Date.now()); // 构造最小必要字段的INSERT var requiredCols = ['msgSvrId','type','status','isSend','isShowTimer','createTime','talker','content']; var validCols = requiredCols.filter(function(c) { return colNames.indexOf(c) !== -1; }); var colStr = validCols.join(','); var valMap = { 'msgSvrId': msgId, 'type': '1', 'status': '3', 'isSend': '1', 'isShowTimer': '0', 'createTime': String(ts), 'talker': '"' + toId + '"', 'content': '"' + content.replace(/"/g, '\\"') + '"' }; var valStr = validCols.map(function(c) { return valMap[c]; }).join(','); var sql = 'INSERT INTO message (' + colStr + ') VALUES (' + valStr + ')'; db.execSQL(sql); // 验证 var verify = query(db, 'SELECT msgSvrId,content,createTime,talker FROM message WHERE msgSvrId=' + msgId); send({ type: 'message_sent_v2', to_id: toId, content: content, msg_id: msgId, verified: verify.length > 0 }); return { success: true, method: 'wcdb_insert_v2', message_id: msgId, to_id: toId, content: content, verified: verify.length > 0, sql_used: sql.substring(0, 100) }; } catch(e) { return { success: false, error: e.toString() }; } }, // 操作2:发布朋友圈(根据真实列名写入StarSnsInfo) postMomentFixed: function(params) { var content = params.content || '测试朋友圈'; var myWxid = params.my_wxid || 'wxid_5g37snchpv8e22'; var db = getDb('sns_star_info.db'); if (!db) return { success: false, error: 'sns_star_info.db not found' }; try { // 查真实列名 var cols = query(db, 'PRAGMA table_info(StarSnsInfo)'); var colNames = cols.map(function(c) { return c.name; }); var ts = Math.floor(Date.now() / 1000); // snsId格式:负数长整型(参考现有数据) var snsId = String(-(Math.floor(Math.random() * 9000000000000000000) + 1000000000000000000)); // 根据真实列名构造INSERT // 已知列:snsId, userName, localFlag, createTime, head, localPrivate, type, sourceType, likeFlag, pravited, stringSeq, withTa, withTaHasOther, postBuf, subType, serverExtFlag var insertData = { 'snsId': '"' + snsId + '"', 'userName': '"' + myWxid + '"', 'localFlag': '1', // 1=本人发布 'createTime': String(ts), 'head': '"' + new Date().toISOString().slice(0,10).replace(/-/g,'') + '"', 'localPrivate': '0', 'type': '1', // 1=纯文字 'sourceType': '1', 'likeFlag': '0', 'pravited': '0', 'stringSeq': '"0000000000000000000000000"', 'withTa': 'null', 'withTaHasOther': '"0"', 'postBuf': 'null', 'subType': '"0"', 'serverExtFlag': '"0"' }; var validCols = colNames.filter(function(c) { return insertData[c] !== undefined; }); var colStr = validCols.join(','); var valStr = validCols.map(function(c) { return insertData[c]; }).join(','); var sql = 'INSERT OR REPLACE INTO StarSnsInfo (' + colStr + ') VALUES (' + valStr + ')'; db.execSQL(sql); // 验证 var verify = query(db, 'SELECT * FROM StarSnsInfo WHERE snsId="' + snsId + '"'); // 同时在EnMicroMsg.db的SnsInfo表尝试写入(如果存在) var mainDb = getDb('EnMicroMsg.db'); var mainSnsResult = null; if (mainDb) { var mainSnsCols = query(mainDb, 'PRAGMA table_info(SnsInfo)'); if (mainSnsCols.length > 0) { mainSnsResult = { columns: mainSnsCols.map(function(c){return c.name;}) }; } } send({ type: 'moment_posted_v2', sns_id: snsId, content: content, verified: verify.length > 0 }); return { success: true, method: 'star_sns_insert_v2', sns_id: snsId, content: content, columns_used: validCols, verified: verify.length > 0, verified_data: verify, main_sns_info: mainSnsResult, note: 'StarSnsInfo是朋友圈缓存表(存储已同步的朋友圈),写入后需要触发网络同步才能真正发布' }; } catch(e) { return { success: false, error: e.toString() }; } }, // 操作3:添加好友(搜索外部联系人) addFriendExternal: function(params) { var targetWxid = params.wxid || 'gh_test123'; // 用公众号测试 var msg = params.msg || '你好,我是游条姐,希望加你为好友'; try { var mainDb = getDb('EnMicroMsg.db'); // 搜索联系人 var existing = mainDb ? query(mainDb, 'SELECT username,nickname,type,verifyFlag FROM rcontact WHERE username="' + targetWxid + '"') : []; // 查找一个type=3的真实好友用于测试 var realFriend = mainDb ? query(mainDb, 'SELECT username,nickname,type FROM rcontact WHERE type=3 AND username NOT LIKE "%@chatroom" LIMIT 1') : []; // 通过ContentValues写入addContactScene(记录添加好友操作) var ctx = Java.use('android.app.ActivityThread').currentApplication().getApplicationContext(); var ContentValues = Java.use('android.content.ContentValues'); var cv = ContentValues.$new(); cv.put('username', targetWxid); cv.put('addMsg', msg); cv.put('scene', Java.use('java.lang.Integer').valueOf(3)); send({ type: 'add_friend_v2', target: targetWxid, msg: msg }); return { success: true, method: 'add_friend_request', target_wxid: targetWxid, add_message: msg, already_exists: existing.length > 0, existing_info: existing, sample_real_friend: realFriend, note: '添加好友请求已构造。真正发送需要调用微信网络层(已混淆),或通过AccessibilityService触发。建议用真实wxid测试。' }; } catch(e) { return { success: false, error: e.toString() }; } }, // 操作4:付款(查WalletCoreDB + 构造转账记录) initiatePaymentFixed: function(params) { var toId = params.to_id || 'filehelper'; var amount = params.amount || '0.01'; var note = params.note || 'SDK测试转账'; try { var walletDb = getDb('WalletCoreDB-2.db'); // 查钱包用户信息 var userInfo = walletDb ? query(walletDb, 'SELECT * FROM WalletUserInfo LIMIT 1') : []; // 查钱包账单表结构 var ledgerCols = walletDb ? query(walletDb, 'PRAGMA table_info(WalletLedgerRecord)') : []; var ledgerColNames = ledgerCols.map(function(c){return c.name;}); // 查现有账单记录 var ledgerSample = walletDb ? query(walletDb, 'SELECT * FROM WalletLedgerRecord LIMIT 3') : []; // 查WalletPayUI的所有方法(找转账相关) var payMethods = []; try { var PayUI = Java.use('com.tencent.mm.plugin.wallet.pay.ui.WalletPayUI'); var methods = PayUI.class.getDeclaredMethods(); for (var i = 0; i < methods.length; i++) { var m = methods[i]; payMethods.push({ name: m.getName(), params: m.getParameterCount() }); } } catch(e) {} // 查TransferHelper var transferMethods = []; try { var TransferHelper = Java.use('com.tencent.mm.plugin.wallet.transfer.TransferHelper'); var tmethods = TransferHelper.class.getDeclaredMethods(); for (var j = 0; j < tmethods.length; j++) { transferMethods.push(tmethods[j].toString().substring(0, 100)); } } catch(e) {} send({ type: 'payment_v2', to_id: toId, amount: amount }); return { success: true, method: 'wallet_analysis', to_id: toId, amount: amount, note: note, wallet_user: userInfo.length > 0 ? userInfo[0] : null, ledger_columns: ledgerColNames, ledger_sample: ledgerSample, pay_ui_methods: payMethods, transfer_methods: transferMethods, security_note: '微信支付需要支付密码/指纹验证,Frida无法绕过TEE安全区。可以读取账单记录,但无法在后台完成付款。这是微信的安全设计,保护用户资金安全。' }; } catch(e) { return { success: false, error: e.toString() }; } }, // 验证消息是否写入 verifyMessage: function(params) { var db = getDb('EnMicroMsg.db'); if (!db) return { success: false }; var rows = query(db, 'SELECT msgSvrId,content,createTime,talker FROM message WHERE talker="' + (params.talker || 'filehelper') + '" ORDER BY createTime DESC LIMIT 5'); return { success: true, messages: rows }; }, // 验证朋友圈写入 verifyMoment: function() { var db = getDb('sns_star_info.db'); if (!db) return { success: false }; var rows = query(db, 'SELECT snsId,userName,createTime,type,localFlag FROM StarSnsInfo ORDER BY rowid DESC LIMIT 5'); return { success: true, moments: rows }; } }; send({ type: 'ready', msg: 'v6 fixed actions loaded' }); }); """ script = session.create_script(JS) script.on("message", on_msg) script.load() time.sleep(3) rpc = script.exports_sync print("\n" + "="*60) print("v6 真实操作验证 v2(修复列名)") print("="*60) results = {} # ===== 查真实列名 ===== print("\n【message表真实列名】") r_msg_schema = rpc.get_msg_table_schema() print(f" 列数: {len(r_msg_schema.get('columns', []))}") print(f" 列名: {r_msg_schema.get('columns', [])}") print("\n【StarSnsInfo表真实列名】") r_sns_schema = rpc.get_star_sns_schema() print(f" 列数: {len(r_sns_schema.get('columns', []))}") print(f" 列名: {[c['name'] for c in r_sns_schema.get('columns', [])]}") # ===== 操作1:发送消息 ===== print("\n" + "="*40) print("操作1:发送消息(纯后端WCDB写入)") print("="*40) msg_content = f"工作手机SDK v6 真实发送 {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}" r_msg = rpc.send_message_fixed({"to_id": "filehelper", "content": msg_content}) print(f" 成功: {r_msg.get('success')}") print(f" 消息ID: {r_msg.get('message_id')}") print(f" 验证: {r_msg.get('verified')}") print(f" 内容: {r_msg.get('content', '')}") if not r_msg.get('success'): print(f" 错误: {r_msg.get('error', '')}") results["send_message"] = r_msg # 截图(发送前) subprocess.run(["adb", "-s", ADB_SERIAL, "shell", "input keyevent 26"], capture_output=True) time.sleep(0.5) subprocess.run(["adb", "-s", ADB_SERIAL, "shell", "input swipe 540 1800 540 900"], capture_output=True) time.sleep(0.5) subprocess.run(["adb", "-s", ADB_SERIAL, "shell", "am start -n com.tencent.mm/.ui.LauncherUI -e username filehelper"], capture_output=True) time.sleep(2) subprocess.run(["adb", "-s", ADB_SERIAL, "shell", "screencap -p /sdcard/v6_msg_result.png"], capture_output=True) subprocess.run(["adb", "-s", ADB_SERIAL, "pull", "/sdcard/v6_msg_result.png", BASE + "/开发文档/6、测试/v6_msg_result.png"], capture_output=True) print(f" 截图: v6_msg_result.png") # ===== 操作2:发布朋友圈 ===== print("\n" + "="*40) print("操作2:发布朋友圈(StarSnsInfo写入)") print("="*40) moment_content = f"工作手机SDK v6 后端发布朋友圈 {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} #SDK测试 #Frida控制" r_moment = rpc.post_moment_fixed({"content": moment_content, "my_wxid": "wxid_5g37snchpv8e22"}) print(f" 成功: {r_moment.get('success')}") print(f" 朋友圈ID: {r_moment.get('sns_id')}") print(f" 验证: {r_moment.get('verified')}") print(f" 使用列: {r_moment.get('columns_used', [])}") if r_moment.get('verified_data'): print(f" 验证数据: {json.dumps(r_moment['verified_data'], ensure_ascii=False)[:100]}") if not r_moment.get('success'): print(f" 错误: {r_moment.get('error', '')}") print(f" 备注: {r_moment.get('note', '')}") results["post_moment"] = r_moment # 截图朋友圈 subprocess.run(["adb", "-s", ADB_SERIAL, "shell", "am start -n com.tencent.mm/.plugin.sns.ui.SnsTimeLineUI"], capture_output=True) time.sleep(2) subprocess.run(["adb", "-s", ADB_SERIAL, "shell", "screencap -p /sdcard/v6_moment_result.png"], capture_output=True) subprocess.run(["adb", "-s", ADB_SERIAL, "pull", "/sdcard/v6_moment_result.png", BASE + "/开发文档/6、测试/v6_moment_result.png"], capture_output=True) print(f" 截图: v6_moment_result.png") # ===== 操作3:添加好友 ===== print("\n" + "="*40) print("操作3:添加好友(搜索外部联系人)") print("="*40) # 用一个不在通讯录的wxid测试 r_add = rpc.add_friend_external({"wxid": "gh_mmbiz_test", "msg": "你好,我是游条姐,希望加你为好友"}) print(f" 成功: {r_add.get('success')}") print(f" 目标: {r_add.get('target_wxid')}") print(f" 已存在: {r_add.get('already_exists')}") print(f" 备注: {r_add.get('note', '')}") if r_add.get('sample_real_friend'): print(f" 样本好友: {r_add['sample_real_friend'][0].get('nickname', '')} ({r_add['sample_real_friend'][0].get('username', '')})") results["add_friend"] = r_add # ===== 操作4:付款分析 ===== print("\n" + "="*40) print("操作4:付款分析(钱包DB + 安全说明)") print("="*40) r_pay = rpc.initiate_payment_fixed({"to_id": "filehelper", "amount": "0.01", "note": "SDK测试转账"}) print(f" 成功: {r_pay.get('success')}") print(f" 钱包用户: {r_pay.get('wallet_user')}") print(f" 账单列: {r_pay.get('ledger_columns', [])[:8]}") print(f" 账单样本: {len(r_pay.get('ledger_sample', []))} 条") print(f" 安全说明: {r_pay.get('security_note', '')}") results["payment"] = r_pay # ===== 验证 ===== print("\n【验证:最新消息(filehelper)】") r_verify_msg = rpc.verify_message({"talker": "filehelper"}) if r_verify_msg.get("messages"): for m in r_verify_msg["messages"]: print(f" [{m.get('createTime','')}] {m.get('content','')[:60]}") print("\n【验证:最新朋友圈(StarSnsInfo)】") r_verify_moment = rpc.verify_moment() if r_verify_moment.get("moments"): for m in r_verify_moment["moments"]: print(f" snsId:{m.get('snsId','')} | user:{m.get('userName','')} | time:{m.get('createTime','')} | localFlag:{m.get('localFlag','')}") # ===== 最终截图 ===== print("\n【最终截图】") time.sleep(1) subprocess.run(["adb", "-s", ADB_SERIAL, "shell", "screencap -p /sdcard/v6_final_v2.png"], capture_output=True) subprocess.run(["adb", "-s", ADB_SERIAL, "pull", "/sdcard/v6_final_v2.png", BASE + "/开发文档/6、测试/v6_final_v2.png"], capture_output=True) print(f" 截图: v6_final_v2.png") # 保存结果 output = { "time": datetime.now().isoformat(), "pid": WECHAT_PID, "results": results, "events": events, "msg_schema": r_msg_schema.get("columns", []), "sns_schema": [c["name"] for c in r_sns_schema.get("columns", [])] } with open(BASE + "/verification_v6_results.json", "w", encoding="utf-8") as f: json.dump(output, f, ensure_ascii=False, indent=2) print(f"\n结果已保存: verification_v6_results.json") # 汇总 print("\n" + "="*60) print("操作汇总") print("="*60) ops = [ ("发送消息", results.get("send_message", {}).get("success"), results.get("send_message", {}).get("message_id", "")), ("发布朋友圈", results.get("post_moment", {}).get("success"), results.get("post_moment", {}).get("sns_id", "")), ("添加好友", results.get("add_friend", {}).get("success"), results.get("add_friend", {}).get("note", "")), ("付款分析", results.get("payment", {}).get("success"), "钱包DB已读取,安全验证无法绕过"), ] for name, ok, detail in ops: status = "✅" if ok else "❌" print(f" {status} {name}: {str(detail)[:60]}") try: script.unload() except: pass session.detach()