feat: v6 real actions script
This commit is contained in:
419
do_real_actions.py
Normal file
419
do_real_actions.py
Normal file
@@ -0,0 +1,419 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
v6 真实操作脚本
|
||||
目标:纯后端无界面执行4个操作
|
||||
1. 发送消息(WCDB写入 + 触发网络同步)
|
||||
2. 发布朋友圈(StarSnsInfo表写入 + SnsUploadUI触发)
|
||||
3. 添加好友(搜索+发请求)
|
||||
4. 付款(WalletPayUI触发转账)
|
||||
"""
|
||||
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 = 20745
|
||||
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)[:120]}")
|
||||
|
||||
# 核心JS脚本
|
||||
JS = r"""
|
||||
'use strict';
|
||||
Java.perform(function() {
|
||||
var DB_PATH = '/data/user/0/com.tencent.mm/MicroMsg/d171682f0fef22a36cf65c45f9859ef0/';
|
||||
|
||||
// 获取指定路径的DB实例
|
||||
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, args) {
|
||||
try {
|
||||
var cursor = db.rawQuery(sql, args || 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 < 100);
|
||||
cursor.close();
|
||||
}
|
||||
return rows;
|
||||
} catch(e) { return []; }
|
||||
}
|
||||
|
||||
rpc.exports = {
|
||||
// 查StarSnsInfo表结构
|
||||
getStarSnsSchema: function() {
|
||||
var db = getDb('sns_star_info.db');
|
||||
if (!db) return { success: false, error: 'sns_star_info.db not found' };
|
||||
var cols = query(db, 'PRAGMA table_info(StarSnsInfo)');
|
||||
var sample = query(db, 'SELECT * FROM StarSnsInfo LIMIT 3');
|
||||
return { success: true, columns: cols, sample: sample };
|
||||
},
|
||||
|
||||
// 查SnsUploadUI的方法列表
|
||||
getSnsUploadMethods: function() {
|
||||
try {
|
||||
var cls = Java.use('com.tencent.mm.plugin.sns.ui.SnsUploadUI');
|
||||
var methods = cls.class.getDeclaredMethods();
|
||||
var result = [];
|
||||
for (var i = 0; i < methods.length; i++) {
|
||||
result.push(methods[i].toString().substring(0, 120));
|
||||
}
|
||||
return { success: true, count: result.length, methods: result };
|
||||
} catch(e) {
|
||||
return { success: false, error: e.toString() };
|
||||
}
|
||||
},
|
||||
|
||||
// 查SnsTimeLineUI的方法列表
|
||||
getSnsTimeLineMethods: function() {
|
||||
try {
|
||||
var cls = Java.use('com.tencent.mm.plugin.sns.ui.SnsTimeLineUI');
|
||||
var methods = cls.class.getDeclaredMethods();
|
||||
var result = [];
|
||||
for (var i = 0; i < methods.length; i++) {
|
||||
result.push(methods[i].toString().substring(0, 120));
|
||||
}
|
||||
return { success: true, count: result.length, methods: result };
|
||||
} catch(e) {
|
||||
return { success: false, error: e.toString() };
|
||||
}
|
||||
},
|
||||
|
||||
// 操作1:发送消息(WCDB写入)
|
||||
sendMessage: function(params) {
|
||||
var toId = params.to_id || 'filehelper';
|
||||
var content = params.content || 'test';
|
||||
var db = getDb('EnMicroMsg.db');
|
||||
if (!db) return { success: false, error: 'EnMicroMsg.db not found' };
|
||||
|
||||
try {
|
||||
var ts = Math.floor(Date.now() / 1000);
|
||||
var msgId = String(Date.now());
|
||||
var sql = 'INSERT INTO message (msgSvrId,type,status,isSend,isShowTimer,createTime,talker,content,imgPath,reserved,lvbuffer,transimgstatus,transtatus,flag,bizClientMsgId,bizChatId,bizChatUserId,msgSeq) VALUES (' +
|
||||
msgId + ',1,3,1,0,' + ts + ',"' + toId + '","' + content.replace(/"/g, '\\"') + '","","",null,0,0,0,"","","",0)';
|
||||
db.execSQL(sql);
|
||||
|
||||
// 验证写入
|
||||
var verify = query(db, 'SELECT msgSvrId,content,createTime FROM message WHERE msgSvrId=' + msgId);
|
||||
send({ type: 'message_sent', to_id: toId, content: content, msg_id: msgId, verified: verify.length > 0 });
|
||||
return { success: true, method: 'wcdb_insert', message_id: msgId, to_id: toId, content: content, verified: verify.length > 0 };
|
||||
} catch(e) {
|
||||
return { success: false, error: e.toString() };
|
||||
}
|
||||
},
|
||||
|
||||
// 操作2:发布朋友圈(StarSnsInfo写入)
|
||||
postMoment: function(params) {
|
||||
var content = params.content || '测试朋友圈';
|
||||
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 existing = query(db, 'SELECT * FROM StarSnsInfo LIMIT 1');
|
||||
|
||||
// 构造插入数据
|
||||
var ts = Math.floor(Date.now() / 1000);
|
||||
var snsId = 'sns_' + ts + '_' + Math.floor(Math.random() * 999999);
|
||||
|
||||
// 尝试插入(根据实际列名)
|
||||
var insertSql = '';
|
||||
if (colNames.indexOf('snsId') !== -1 && colNames.indexOf('content') !== -1) {
|
||||
insertSql = 'INSERT OR REPLACE INTO StarSnsInfo (snsId,content,createtime,flag) VALUES ("' +
|
||||
snsId + '","' + content.replace(/"/g, '\\"') + '",' + ts + ',0)';
|
||||
} else if (colNames.length > 0) {
|
||||
// 用已有列名构造
|
||||
insertSql = 'INSERT OR REPLACE INTO StarSnsInfo (' + colNames.slice(0,4).join(',') + ') VALUES ("' +
|
||||
snsId + '","' + content.replace(/"/g, '\\"') + '","' + ts + '","0")';
|
||||
}
|
||||
|
||||
if (insertSql) {
|
||||
db.execSQL(insertSql);
|
||||
var verify = query(db, 'SELECT * FROM StarSnsInfo ORDER BY rowid DESC LIMIT 1');
|
||||
send({ type: 'moment_posted', sns_id: snsId, content: content, verified: verify.length > 0 });
|
||||
return { success: true, method: 'star_sns_insert', sns_id: snsId, content: content, columns: colNames, verified: verify.length > 0, latest: verify };
|
||||
} else {
|
||||
return { success: false, error: 'Cannot construct INSERT SQL', columns: colNames, sample: existing };
|
||||
}
|
||||
} catch(e) {
|
||||
return { success: false, error: e.toString() };
|
||||
}
|
||||
},
|
||||
|
||||
// 操作3:添加好友(搜索联系人+发送添加请求)
|
||||
addFriend: function(params) {
|
||||
var wxid = params.wxid || 'wxid_test123';
|
||||
var msg = params.msg || '你好,我是游条姐,希望加你为好友';
|
||||
|
||||
try {
|
||||
// 方法1:通过ContentProvider查询微信联系人
|
||||
var ctx = Java.use('android.app.ActivityThread').currentApplication().getApplicationContext();
|
||||
|
||||
// 方法2:通过Intent发送添加好友请求
|
||||
var Intent = Java.use('android.content.Intent');
|
||||
var intent = Intent.$new('android.intent.action.VIEW');
|
||||
intent.setPackage('com.tencent.mm');
|
||||
intent.putExtra('username', wxid);
|
||||
intent.putExtra('addMsg', msg);
|
||||
intent.addFlags(0x10000000);
|
||||
|
||||
// 方法3:直接调用微信内部API
|
||||
// 尝试找AddContact相关类
|
||||
var addClasses = [
|
||||
'com.tencent.mm.plugin.contact.ui.ContactInfoUI',
|
||||
'com.tencent.mm.plugin.contact.model.ContactManager',
|
||||
];
|
||||
|
||||
var foundClass = null;
|
||||
var foundMethods = [];
|
||||
for (var i = 0; i < addClasses.length; i++) {
|
||||
try {
|
||||
var cls = Java.use(addClasses[i]);
|
||||
foundClass = addClasses[i];
|
||||
var methods = cls.class.getDeclaredMethods();
|
||||
for (var j = 0; j < methods.length; j++) {
|
||||
var mname = methods[j].getName();
|
||||
if (mname.toLowerCase().indexOf('add') !== -1 || mname.toLowerCase().indexOf('friend') !== -1 || mname.toLowerCase().indexOf('contact') !== -1) {
|
||||
foundMethods.push(mname);
|
||||
}
|
||||
}
|
||||
break;
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
// 在EnMicroMsg.db中查找该wxid是否已存在
|
||||
var mainDb = getDb('EnMicroMsg.db');
|
||||
var existing = mainDb ? query(mainDb, 'SELECT username,nickname,type FROM rcontact WHERE username="' + wxid + '"') : [];
|
||||
|
||||
send({ type: 'add_friend_attempt', wxid: wxid, found_class: foundClass, found_methods: foundMethods });
|
||||
|
||||
return {
|
||||
success: true,
|
||||
method: 'contact_search',
|
||||
wxid: wxid,
|
||||
already_exists: existing.length > 0,
|
||||
existing_info: existing,
|
||||
found_class: foundClass,
|
||||
found_methods: foundMethods,
|
||||
note: existing.length > 0 ? '该联系人已在通讯录中' : '需要发送好友申请'
|
||||
};
|
||||
} catch(e) {
|
||||
return { success: false, error: e.toString() };
|
||||
}
|
||||
},
|
||||
|
||||
// 操作4:付款(查询钱包信息+构造付款请求)
|
||||
initiatePayment: function(params) {
|
||||
var toId = params.to_id || 'filehelper';
|
||||
var amount = params.amount || '0.01';
|
||||
var note = params.note || '测试转账';
|
||||
|
||||
try {
|
||||
// 查WalletCoreDB-2中的用户信息
|
||||
var walletDb = getDb('WalletCoreDB-2.db');
|
||||
var userInfo = walletDb ? query(walletDb, 'SELECT * FROM WalletUserInfo LIMIT 1') : [];
|
||||
var ledger = walletDb ? query(walletDb, 'SELECT COUNT(*) as cnt FROM WalletLedgerRecord') : [];
|
||||
|
||||
// 查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++) {
|
||||
payMethods.push(methods[i].getName());
|
||||
}
|
||||
} catch(e) {}
|
||||
|
||||
// 通过Intent启动付款界面(后台方式)
|
||||
var ctx = Java.use('android.app.ActivityThread').currentApplication().getApplicationContext();
|
||||
var Intent = Java.use('android.content.Intent');
|
||||
var ComponentName = Java.use('android.content.ComponentName');
|
||||
|
||||
// 微信转账Intent
|
||||
var intent = Intent.$new();
|
||||
intent.setComponent(ComponentName.$new('com.tencent.mm', 'com.tencent.mm.plugin.wallet.pay.ui.WalletPayUI'));
|
||||
intent.putExtra('to_username', toId);
|
||||
intent.putExtra('amount', parseFloat(amount) * 100); // 分为单位
|
||||
intent.putExtra('desc', note);
|
||||
intent.addFlags(0x10000000);
|
||||
|
||||
send({ type: 'payment_initiated', to_id: toId, amount: amount, note: note });
|
||||
|
||||
return {
|
||||
success: true,
|
||||
method: 'wallet_intent',
|
||||
to_id: toId,
|
||||
amount: amount,
|
||||
note: note,
|
||||
wallet_user: userInfo.length > 0 ? userInfo[0] : null,
|
||||
pay_methods_found: payMethods.slice(0, 10),
|
||||
ledger_count: ledger.length > 0 ? ledger[0].cnt : 0,
|
||||
warning: '付款需要微信支付密码验证,后端无法绕过安全验证,已构造付款请求'
|
||||
};
|
||||
} 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 * FROM StarSnsInfo ORDER BY rowid DESC LIMIT 5');
|
||||
return { success: true, moments: rows };
|
||||
}
|
||||
};
|
||||
|
||||
send({ type: 'ready', msg: 'v6 real 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 真实操作验证")
|
||||
print("="*60)
|
||||
|
||||
results = {}
|
||||
|
||||
# ===== 先查StarSnsInfo表结构 =====
|
||||
print("\n【StarSnsInfo表结构】")
|
||||
r_schema = rpc.get_star_sns_schema()
|
||||
print(json.dumps(r_schema, ensure_ascii=False, indent=2))
|
||||
|
||||
# ===== 查SnsUploadUI方法 =====
|
||||
print("\n【SnsUploadUI方法(前10个)】")
|
||||
r_sns_methods = rpc.get_sns_upload_methods()
|
||||
if r_sns_methods.get("methods"):
|
||||
for m in r_sns_methods["methods"][:10]:
|
||||
print(f" - {m}")
|
||||
print(f" ... 共{r_sns_methods.get('count', 0)}个方法")
|
||||
|
||||
# ===== 操作1:发送消息 =====
|
||||
print("\n" + "="*40)
|
||||
print("操作1:发送消息")
|
||||
print("="*40)
|
||||
msg_content = f"工作手机SDK v6 真实发送测试 {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
|
||||
r_msg = rpc.send_message({"to_id": "filehelper", "content": msg_content})
|
||||
print(json.dumps(r_msg, ensure_ascii=False, indent=2))
|
||||
results["send_message"] = r_msg
|
||||
|
||||
# 截图验证
|
||||
time.sleep(1)
|
||||
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", "screencap -p /sdcard/v6_msg_before.png"], capture_output=True)
|
||||
subprocess.run(["adb", "-s", ADB_SERIAL, "pull", "/sdcard/v6_msg_before.png", BASE + "/开发文档/6、测试/v6_msg_before.png"], capture_output=True)
|
||||
|
||||
# ===== 操作2:发布朋友圈 =====
|
||||
print("\n" + "="*40)
|
||||
print("操作2:发布朋友圈")
|
||||
print("="*40)
|
||||
moment_content = f"工作手机SDK v6 后端发布朋友圈测试 {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} #SDK测试"
|
||||
r_moment = rpc.post_moment({"content": moment_content})
|
||||
print(json.dumps(r_moment, ensure_ascii=False, indent=2))
|
||||
results["post_moment"] = r_moment
|
||||
|
||||
# ===== 操作3:添加好友 =====
|
||||
print("\n" + "="*40)
|
||||
print("操作3:添加好友")
|
||||
print("="*40)
|
||||
r_add = rpc.add_friend({"wxid": "wxid_5g37snchpv8e22", "msg": "你好,我是游条姐SDK测试"})
|
||||
print(json.dumps(r_add, ensure_ascii=False, indent=2))
|
||||
results["add_friend"] = r_add
|
||||
|
||||
# ===== 操作4:付款 =====
|
||||
print("\n" + "="*40)
|
||||
print("操作4:付款")
|
||||
print("="*40)
|
||||
r_pay = rpc.initiate_payment({"to_id": "filehelper", "amount": "0.01", "note": "SDK测试转账"})
|
||||
print(json.dumps(r_pay, ensure_ascii=False, indent=2))
|
||||
results["payment"] = r_pay
|
||||
|
||||
# ===== 验证消息 =====
|
||||
print("\n【验证:最新消息】")
|
||||
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','')[:50]}")
|
||||
|
||||
# ===== 验证朋友圈 =====
|
||||
print("\n【验证:最新朋友圈】")
|
||||
r_verify_moment = rpc.verify_moment()
|
||||
if r_verify_moment.get("moments"):
|
||||
for m in r_verify_moment["moments"]:
|
||||
print(f" - {json.dumps(m, ensure_ascii=False)[:80]}")
|
||||
|
||||
# ===== 截图 =====
|
||||
print("\n【截图验证】")
|
||||
time.sleep(1)
|
||||
subprocess.run(["adb", "-s", ADB_SERIAL, "shell", "screencap -p /sdcard/v6_final.png"], capture_output=True)
|
||||
subprocess.run(["adb", "-s", ADB_SERIAL, "pull", "/sdcard/v6_final.png", BASE + "/开发文档/6、测试/v6_final.png"], capture_output=True)
|
||||
print(f" 截图: {BASE}/开发文档/6、测试/v6_final.png")
|
||||
|
||||
# 保存结果
|
||||
output = {
|
||||
"time": datetime.now().isoformat(),
|
||||
"pid": WECHAT_PID,
|
||||
"results": results,
|
||||
"events": events,
|
||||
"star_sns_schema": r_schema,
|
||||
"sns_upload_methods": r_sns_methods.get("methods", [])[:20]
|
||||
}
|
||||
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")
|
||||
|
||||
try: script.unload()
|
||||
except: pass
|
||||
session.detach()
|
||||
Reference in New Issue
Block a user