Files
workphone-sdk/verify_v10.py

405 lines
15 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
"""
工作手机 SDK - 完整验证脚本 v10
Frida 16.x 兼容exports_sync 方法名全小写
"""
import frida
import json
import time
import subprocess
import os
import sys
PHONE_IP = '192.168.110.80'
JS_FILE = '/Users/karuo/Documents/开发/2、私域银行/工作手机/sdk/agent/hook/wechat_api_v8_fix.js'
SCREENSHOT_DIR = '/Users/karuo/Documents/开发/2、私域银行/工作手机/开发文档/6、测试'
results = {}
errors = []
passed_count = 0
total_count = 0
def screenshot(name):
path = f'{SCREENSHOT_DIR}/v10_{name}.png'
try:
subprocess.run(['adb', '-s', f'{PHONE_IP}:5555', 'shell',
f'screencap -p /sdcard/v10_{name}.png'], timeout=5, capture_output=True)
subprocess.run(['adb', '-s', f'{PHONE_IP}:5555', 'pull',
f'/sdcard/v10_{name}.png', path], timeout=10, capture_output=True)
print(f" 📸 截图: v10_{name}.png")
except Exception as e:
print(f" ⚠️ 截图失败: {e}")
def wake_phone():
subprocess.run(['adb', '-s', f'{PHONE_IP}:5555', 'shell', 'input keyevent 26'], timeout=5, capture_output=True)
time.sleep(0.5)
subprocess.run(['adb', '-s', f'{PHONE_IP}:5555', 'shell', 'input swipe 540 1800 540 900'], timeout=5, capture_output=True)
time.sleep(0.5)
def get_wechat_pid():
result = subprocess.run(
['adb', '-s', f'{PHONE_IP}:5555', 'shell', 'ps -A'],
capture_output=True, text=True, timeout=5
)
for line in result.stdout.split('\n'):
if 'com.tencent.mm' in line and ':push' not in line and ':sandbox' not in line and ':tools' not in line and ':appbrand' not in line:
parts = line.split()
if len(parts) >= 2:
try:
return int(parts[1])
except:
pass
return None
def test(name, func):
global passed_count, total_count
total_count += 1
try:
r = func()
passed_count += 1
return r
except Exception as e:
errors.append(f"{name}: {str(e)[:80]}")
print(f"{name}: {str(e)[:80]}")
return None
def main():
global passed_count, total_count
print("=" * 70)
print("🔥 工作手机 SDK 完整验证 v10 (Frida 16.x 全小写调用)")
print(f"时间: {time.strftime('%Y-%m-%d %H:%M:%S')}")
print("=" * 70)
wake_phone()
# 确保ADB端口转发
subprocess.run(['adb', '-s', f'{PHONE_IP}:5555', 'forward', 'tcp:27042', 'tcp:27042'],
timeout=5, capture_output=True)
pid = get_wechat_pid()
if not pid:
print("❌ 微信未运行,启动微信...")
subprocess.run(['adb', '-s', f'{PHONE_IP}:5555', 'shell',
'monkey -p com.tencent.mm -c android.intent.category.LAUNCHER 1'],
timeout=10, capture_output=True)
time.sleep(8)
pid = get_wechat_pid()
if not pid:
print("❌ 无法启动微信")
return 0, 0
print(f"✅ 微信PID: {pid}")
print("\n📡 连接Frida (localhost:27042)...")
dm = frida.get_device_manager()
device = dm.add_remote_device('localhost:27042')
session = device.attach(pid)
with open(JS_FILE, 'r', encoding='utf-8') as f:
js_code = f.read()
script = session.create_script(js_code)
script.load()
time.sleep(3)
ex = script.exports_sync
print("✅ Frida连接成功使用exports_sync全小写方法名")
# 先列出所有可用方法
try:
methods = dir(ex)
print(f"✅ 可用方法数: {len([m for m in methods if not m.startswith('_')])}")
print(f" 前10个: {[m for m in methods if not m.startswith('_')][:10]}")
except Exception as e:
print(f"⚠️ 无法列出方法: {e}")
print("\n" + "=" * 70)
print("📊 开始全量接口验证26项")
print("=" * 70)
# ===== 1. ping =====
print("\n【1】系统ping")
r = test("ping", lambda: ex.ping())
if r: print(f"{r}")
results['ping'] = r
# ===== 2. 账号信息 =====
print("\n【2】账号信息")
r = test("account", lambda: ex.getaccountinfo())
if r:
print(f" ✅ 账号: {r.get('nickname','?')} | wxid: {r.get('wxid','?')}")
print(f" 手机: {r.get('phone','?')} | 地区: {r.get('region','?')}")
results['account'] = r
# ===== 3. 全量统计 =====
print("\n【3】全量数据统计")
r = test("stats", lambda: ex.getallstats())
if r:
print(f" ✅ 好友: {r.get('friends',0)} | 群组: {r.get('groups',0)} | 消息: {r.get('messages',0)}")
print(f" 图片: {r.get('images',0)} | 视频: {r.get('videos',0)} | 文件: {r.get('files',0)}")
results['stats'] = r
# ===== 4. 联系人列表 =====
print("\n【4】联系人列表前20个")
r = test("contacts", lambda: ex.getcontacts(20, 0))
if r:
rows = r.get('rows', [])
print(f" ✅ 联系人: {len(rows)}")
for c in rows[:3]:
print(f" - {c.get('nickName','?')} ({c.get('username','?')})")
results['contacts'] = {'count': len(rows), 'sample': rows[:3]}
# ===== 5. 联系人数量 =====
print("\n【5】联系人数量")
r = test("contact_count", lambda: ex.getcontactcount())
if r:
print(f" ✅ 好友: {r.get('friends',0)} | 总计: {r.get('total',0)}")
results['contact_count'] = r
# ===== 6. 群组列表 =====
print("\n【6】群组列表")
r = test("groups", lambda: ex.getgroups(50))
if r:
rows = r.get('rows', [])
print(f" ✅ 群组: {len(rows)}")
for g in rows[:3]:
print(f" - {g.get('nickName', g.get('NickName','?'))} ({g.get('username','?')})")
results['groups'] = {'count': len(rows), 'sample': rows[:3]}
# ===== 7. 标签 =====
print("\n【7】标签列表")
r = test("labels", lambda: ex.getlabels())
if r:
rows = r.get('rows', [])
print(f" ✅ 标签: {len(rows)}")
for l in rows[:5]:
print(f" - {l.get('labelName', l.get('name','?'))} (id:{l.get('labelId', l.get('id','?'))})")
results['labels'] = {'count': len(rows)}
# ===== 8. 最近消息 =====
print("\n【8】最近消息24小时")
r = test("recent_messages", lambda: ex.getrecentmessages(24))
if r:
rows = r.get('rows', [])
print(f" ✅ 消息: {len(rows)}")
results['recent_messages'] = {'count': len(rows)}
# ===== 9. 发送消息 =====
print("\n【9】发送消息到文件传输助手真实发送")
msg_content = f'[工作手机SDK v10] 自动测试 {time.strftime("%H:%M:%S")}'
r = test("send_message", lambda: ex.sendmessage('filehelper', msg_content, 1))
if r:
print(f" ✅ 发送结果: {json.dumps(r, ensure_ascii=False)[:200]}")
results['send_message'] = r
time.sleep(2)
screenshot('after_send_msg')
# ===== 10. 群发消息 =====
print("\n【10】群发消息前3个好友")
try:
contacts_r = ex.getcontacts(5, 0)
rows = contacts_r.get('rows', [])
targets = [c.get('username','') for c in rows if c.get('username','') and not c.get('username','').startswith('gh_')][:3]
if targets:
r = test("mass_message", lambda: ex.massmessage(targets, f'[群发测试] {time.strftime("%H:%M:%S")}'))
if r:
print(f" ✅ 群发: 目标{len(targets)}人, 结果: {json.dumps(r, ensure_ascii=False)[:150]}")
results['mass_message'] = r
else:
print(f" ⚠️ 没有有效目标")
except Exception as e:
print(f" ❌ 群发: {e}")
errors.append(f"mass_message: {str(e)[:80]}")
# ===== 11. 群成员 =====
print("\n【11】群成员第一个群")
try:
groups_r = ex.getgroups(1)
rows = groups_r.get('rows', [])
if rows:
chatroom_id = rows[0].get('username','')
r = test("group_members", lambda: ex.getgroupmembers(chatroom_id))
if r:
members = r.get('rows', [])
print(f" ✅ 群: {chatroom_id} | 成员: {len(members)}")
results['group_members'] = {'count': len(members), 'chatroom': chatroom_id}
except Exception as e:
print(f" ❌ 群成员: {e}")
errors.append(f"group_members: {str(e)[:80]}")
# ===== 12. 朋友圈DB信息 =====
print("\n【12】朋友圈DB信息")
r = test("moments_db", lambda: ex.getsnsdbinfo())
if r:
print(f" ✅ 朋友圈DB: {json.dumps(r, ensure_ascii=False)[:300]}")
results['moments_db'] = r
# ===== 13. 朋友圈列表 =====
print("\n【13】朋友圈列表")
r = test("moments", lambda: ex.getmoments(10))
if r:
rows = r.get('rows', [])
print(f" ✅ 朋友圈: {len(rows)}")
for m in rows[:2]:
print(f" - {str(m)[:100]}")
results['moments'] = {'count': len(rows)}
# ===== 14. 发布朋友圈 =====
print("\n【14】发布朋友圈")
moment_content = f'[工作手机SDK测试] {time.strftime("%Y-%m-%d %H:%M:%S")}'
r = test("post_moment", lambda: ex.postmoment(moment_content))
if r:
print(f" ✅ 发布结果: {json.dumps(r, ensure_ascii=False)[:200]}")
results['post_moment'] = r
time.sleep(2)
screenshot('after_post_moment')
# ===== 15. 视频号信息 =====
print("\n【15】视频号信息")
r = test("finder_info", lambda: ex.getfinderinfo())
if r:
print(f" ✅ 视频号: {json.dumps(r, ensure_ascii=False)[:300]}")
results['finder_info'] = r
# ===== 16. 视频号联系人 =====
print("\n【16】视频号联系人")
r = test("finder_contacts", lambda: ex.getfindercontacts(10))
if r:
rows = r.get('rows', [])
print(f" ✅ 视频号联系人: {len(rows)}")
results['finder_contacts'] = {'count': len(rows)}
# ===== 17. 视频号账号 =====
print("\n【17】视频号账号")
r = test("finder_accounts", lambda: ex.getfinderaccounts())
if r:
print(f" ✅ 视频号账号: {json.dumps(r, ensure_ascii=False)[:200]}")
results['finder_accounts'] = r
# ===== 18. 收藏 =====
print("\n【18】收藏列表")
r = test("favorites", lambda: ex.getfavorites(10))
if r:
rows = r.get('rows', [])
print(f" ✅ 收藏: {len(rows)}")
results['favorites'] = {'count': len(rows)}
# ===== 19. 钱包信息 =====
print("\n【19】钱包信息")
r = test("wallet_info", lambda: ex.getwalletinfo())
if r:
print(f" ✅ 钱包: {json.dumps(r, ensure_ascii=False)[:300]}")
results['wallet_info'] = r
# ===== 20. 钱包流水 =====
print("\n【20】钱包流水")
r = test("wallet_ledger", lambda: ex.getwalletledger(10))
if r:
rows = r.get('rows', [])
print(f" ✅ 钱包流水: {len(rows)}")
for l in rows[:2]:
print(f" - {str(l)[:100]}")
results['wallet_ledger'] = {'count': len(rows)}
# ===== 21. 红包记录 =====
print("\n【21】红包记录")
r = test("lucky_money", lambda: ex.getluckymoney(10))
if r:
rows = r.get('rows', [])
print(f" ✅ 红包: {len(rows)}")
for l in rows[:2]:
print(f" - {str(l)[:100]}")
results['lucky_money'] = {'count': len(rows)}
# ===== 22. 图片统计 =====
print("\n【22】图片统计")
r = test("image_count", lambda: ex.getimagecount())
if r:
print(f" ✅ 图片: {json.dumps(r, ensure_ascii=False)}")
results['image_count'] = r
# ===== 23. 视频列表 =====
print("\n【23】视频列表")
r = test("videos", lambda: ex.getvideolist(5))
if r:
rows = r.get('rows', [])
print(f" ✅ 视频: {len(rows)}")
results['videos'] = {'count': len(rows)}
# ===== 24. 文件列表 =====
print("\n【24】文件列表")
r = test("files", lambda: ex.getfilelist(5))
if r:
rows = r.get('rows', [])
print(f" ✅ 文件: {len(rows)}")
results['files'] = {'count': len(rows)}
# ===== 25. 小程序 =====
print("\n【25】小程序信息")
r = test("appbrand", lambda: ex.getappbrandlist())
if r:
print(f" ✅ 小程序: {json.dumps(r, ensure_ascii=False)[:200]}")
results['appbrand'] = r
# ===== 26. 原始SQL =====
print("\n【26】原始SQL查询")
r = test("raw_sql", lambda: ex.rawquery('main', 'SELECT type, COUNT(*) as cnt FROM rcontact GROUP BY type ORDER BY cnt DESC LIMIT 10'))
if r:
print(f" ✅ SQL结果: {json.dumps(r, ensure_ascii=False)[:300]}")
results['raw_sql'] = r
# ===== 最终截图 =====
print("\n📸 最终截图...")
screenshot('final')
# ===== 汇总 =====
print("\n" + "=" * 70)
print(f"📊 验证结果: {passed_count}/{total_count} 通过 ({passed_count/total_count*100:.0f}%)")
print("=" * 70)
if errors:
print("\n❌ 失败项:")
for e in errors:
print(f" - {e}")
print("\n✅ 真实数据汇总:")
acc = results.get('account', {})
stats = results.get('stats', {})
cc = results.get('contact_count', {})
print(f" 📱 账号: {acc.get('nickname','?')} | wxid: {acc.get('wxid','?')}")
print(f" 👥 好友: {cc.get('friends', stats.get('friends','?'))} | 总联系人: {cc.get('total','?')}")
print(f" 💬 群组: {results.get('groups',{}).get('count', stats.get('groups','?'))}")
print(f" 🏷️ 标签: {results.get('labels',{}).get('count','?')}")
print(f" 📨 24h消息: {results.get('recent_messages',{}).get('count','?')}")
print(f" 🖼️ 图片: {stats.get('images','?')}")
print(f" 🎬 视频: {stats.get('videos','?')}")
print(f" 📁 文件: {stats.get('files','?')}")
print(f" ⭐ 收藏: {results.get('favorites',{}).get('count','?')}")
print(f" 💰 钱包流水: {results.get('wallet_ledger',{}).get('count','?')}")
print(f" 🧧 红包: {results.get('lucky_money',{}).get('count','?')}")
print(f" 📹 视频号联系人: {results.get('finder_contacts',{}).get('count','?')}")
# 保存结果
result_file = f'{SCREENSHOT_DIR}/v10_verify_results.json'
with open(result_file, 'w', encoding='utf-8') as f:
json.dump({
'timestamp': int(time.time()),
'time': time.strftime('%Y-%m-%d %H:%M:%S'),
'passed': passed_count,
'total': total_count,
'pass_rate': f"{passed_count/total_count*100:.0f}%",
'results': results,
'errors': errors
}, f, ensure_ascii=False, indent=2)
print(f"\n💾 结果已保存: {result_file}")
return passed_count, total_count
if __name__ == '__main__':
passed, total = main()
print(f"\n🎯 最终: {passed}/{total} ({passed/total*100:.0f}%)")
sys.exit(0 if passed >= total * 0.8 else 1)