#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 工作手机SDK - 深度数据调试脚本 目标:查明联系人/群组真实数量,验证SQL过滤条件 """ import frida, time, json, os from datetime import datetime PHONE_IP = "192.168.110.80" FRIDA_PORT = 27042 WECHAT_PID = 16816 BASE = "/Users/karuo/Documents/开发/2、私域银行/工作手机" RESULT_FILE = BASE + "/debug_data_20260518.json" # 内联调试脚本 - 直接执行原始SQL DEBUG_SCRIPT = """ 'use strict'; // 复用 _execSQL 逻辑 function findDbPath() { var paths = [ '/data/data/com.tencent.mm/MicroMsg/', ]; var dbPath = null; try { var File = Java.use('java.io.File'); var base = File.$new('/data/data/com.tencent.mm/MicroMsg/'); var dirs = base.listFiles(); if (dirs) { for (var i = 0; i < dirs.length; i++) { var d = dirs[i]; if (d.isDirectory() && d.getName().length === 32) { var candidate = d.getAbsolutePath() + '/EnMicroMsg.db'; if (File.$new(candidate).exists()) { dbPath = candidate; break; } } } } } catch(e) {} return dbPath; } function execSQL(sql, dbPath) { try { var SQLiteDatabase = Java.use('net.sqlcipher.database.SQLiteDatabase'); var db = SQLiteDatabase.openDatabase(dbPath, '00000000000000000000000000000000', null, 0); var cursor = db.rawQuery(sql, null); var rows = []; var colCount = cursor.getColumnCount(); var colNames = []; for (var i = 0; i < colCount; i++) colNames.push(cursor.getColumnName(i)); while (cursor.moveToNext()) { var row = {}; for (var j = 0; j < colCount; j++) { try { row[colNames[j]] = cursor.getString(j); } catch(_) { row[colNames[j]] = null; } } rows.push(row); } cursor.close(); db.close(); return rows; } catch(e) { return [{error: String(e)}]; } } rpc.exports = { debugContacts: function() { return Java.performNow(function() { var dbPath = findDbPath(); if (!dbPath) return {error: 'DB not found'}; var results = {}; // 1. 总联系人数(无过滤) var r1 = execSQL("SELECT COUNT(*) as cnt FROM rcontact", dbPath); results.total_rcontact = r1[0] ? r1[0].cnt : 'err'; // 2. type分布 var r2 = execSQL("SELECT type, COUNT(*) as cnt FROM rcontact GROUP BY type ORDER BY cnt DESC LIMIT 20", dbPath); results.type_distribution = r2; // 3. verifyFlag分布 var r3 = execSQL("SELECT verifyFlag, COUNT(*) as cnt FROM rcontact GROUP BY verifyFlag ORDER BY cnt DESC", dbPath); results.verifyflag_distribution = r3; // 4. 真实好友(type=3是好友) var r4 = execSQL("SELECT COUNT(*) as cnt FROM rcontact WHERE type=3", dbPath); results.type3_friends = r4[0] ? r4[0].cnt : 'err'; // 5. 放宽条件的好友 var r5 = execSQL("SELECT COUNT(*) as cnt FROM rcontact WHERE type NOT IN (0,33) AND username NOT LIKE '%@chatroom' AND username NOT LIKE 'gh_%'", dbPath); results.relaxed_friends = r5[0] ? r5[0].cnt : 'err'; // 6. 完全无过滤的好友(排除系统账号) var r6 = execSQL("SELECT COUNT(*) as cnt FROM rcontact WHERE username NOT LIKE '%@chatroom' AND username NOT LIKE 'gh_%' AND username NOT IN ('filehelper','fmessage','medianote','weibo','qqfriend','qmessage','tmessage','newsapp','brandsessionholder','notification_messages','officialaccounts','revokemsg','gh_792c1a7a1923','voipnotify','voipmessage','systemnotice','weapp','weixinofficialaccounts')", dbPath); results.no_filter_friends = r6[0] ? r6[0].cnt : 'err'; // 7. 群组数量 - rcontact表 var r7 = execSQL("SELECT COUNT(*) as cnt FROM rcontact WHERE username LIKE '%@chatroom'", dbPath); results.groups_in_rcontact = r7[0] ? r7[0].cnt : 'err'; // 8. 群组数量 - chatroom表 try { var r8 = execSQL("SELECT COUNT(*) as cnt FROM chatroom", dbPath); results.groups_in_chatroom = r8[0] ? r8[0].cnt : 'err'; } catch(e) { results.groups_in_chatroom = 'table_not_found: ' + String(e); } // 9. 前20个联系人(type=3) var r9 = execSQL("SELECT username, nickname, conRemark, type, verifyFlag FROM rcontact WHERE type=3 LIMIT 20", dbPath); results.sample_type3 = r9; // 10. 前5个群组 var r10 = execSQL("SELECT username, nickname FROM rcontact WHERE username LIKE '%@chatroom' LIMIT 10", dbPath); results.sample_groups = r10; // 11. 检查chatroom表结构 try { var r11 = execSQL("SELECT chatroomname, chatroomnick FROM chatroom LIMIT 10", dbPath); results.chatroom_sample = r11; } catch(e) { results.chatroom_sample = 'error: ' + String(e); } // 12. 所有type值的样本 var r12 = execSQL("SELECT username, nickname, type, verifyFlag FROM rcontact WHERE type NOT IN (0,33) LIMIT 5", dbPath); results.sample_non_system = r12; return {success: true, dbPath: dbPath, results: results}; }); } }; """ print(f"[{datetime.now().strftime('%H:%M:%S')}] 连接Frida: {PHONE_IP}:{FRIDA_PORT}") dm = frida.get_device_manager() device = dm.add_remote_device(f"{PHONE_IP}:{FRIDA_PORT}") session = device.attach(WECHAT_PID) print(f"[OK] 附加微信 PID={WECHAT_PID}") script = session.create_script(DEBUG_SCRIPT) script.on("message", lambda m, d: print(f"[MSG] {m}")) script.load() print("[OK] 调试脚本已加载,等待2秒...") time.sleep(2) rpc = script.exports_sync print("\n=== 深度数据调试 ===") result = rpc.debug_contacts() print(json.dumps(result, ensure_ascii=False, indent=2, default=str)) with open(RESULT_FILE, "w", encoding="utf-8") as f: json.dump(result, f, ensure_ascii=False, indent=2, default=str) print(f"\n已保存: {RESULT_FILE}") script.unload() session.detach()