Files
workphone-sdk/do_real_actions_v2.py

470 lines
21 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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()