// 微信工作手机 SDK v7 - 全量Frida RPC接口 // 基于微信8.0.56真实DB结构开发 // 账号:游条姐-游戏教学辅助看我朋友圈 (wxid_5g37snchpv8e22) 'use strict'; var _db = null; var _snsDb = null; var _walletDb = null; var _finderDb = null; var _favoriteDb = null; var _dbPath = null; // ==================== DB初始化 ==================== function initDB() { if (_db) return _db; try { Java.choose('com.tencent.wcdb.database.SQLiteDatabase', { onMatch: function(db) { try { var path = db.getPath(); if (path && path.indexOf('EnMicroMsg.db') > -1 && path.indexOf('wal') === -1) { _db = db; _dbPath = path; } if (path && path.indexOf('sns_star_info') > -1) _snsDb = db; if (path && path.indexOf('WalletCoreDB') > -1) _walletDb = db; if (path && path.indexOf('Finder') > -1 && path.indexOf('MM') > -1) _finderDb = db; if (path && path.indexOf('FTS5Index') > -1) _favoriteDb = db; } catch(e) {} }, onComplete: function() {} }); } catch(e) {} return _db; } function execSQL(db, sql, args) { try { if (!db) return {error: 'DB not initialized'}; var cursor; if (args && args.length > 0) { var strArgs = args.map(function(a) { return a ? a.toString() : null; }); var jArgs = Java.array('java.lang.String', strArgs); cursor = db.rawQuery(sql, jArgs); } else { cursor = db.rawQuery(sql, null); } var cols = []; var colCount = cursor.getColumnCount(); for (var i = 0; i < colCount; i++) cols.push(cursor.getColumnName(i)); var rows = []; while (cursor.moveToNext()) { var row = {}; for (var j = 0; j < colCount; j++) { try { row[cols[j]] = cursor.getString(j); } catch(e) { row[cols[j]] = null; } } rows.push(row); } cursor.close(); return {columns: cols, rows: rows, count: rows.length}; } catch(e) { return {error: e.toString()}; } } function writeDB(db, sql) { try { if (!db) return {error: 'DB not initialized'}; db.execSQL(sql); return {success: true}; } catch(e) { return {error: e.toString()}; } } // ==================== RPC接口定义 ==================== rpc.exports = { // ===== 系统 ===== ping: function() { return {status: 'ok', version: 'v7', timestamp: Date.now()}; }, getSystemInfo: function() { initDB(); return { db_path: _dbPath, has_main_db: !!_db, has_sns_db: !!_snsDb, has_wallet_db: !!_walletDb, has_finder_db: !!_finderDb, has_favorite_db: !!_favoriteDb, frida_version: Frida.version, timestamp: Date.now() }; }, // ===== 账号 ===== getAccountInfo: function() { initDB(); var r = execSQL(_db, "SELECT value FROM userinfo WHERE id IN (2,4,6,42,43,44,62,66,67) ORDER BY id"); var info = execSQL(_db, "SELECT value FROM userinfo WHERE id=2"); var nick = execSQL(_db, "SELECT value FROM userinfo WHERE id=6"); var avatar = execSQL(_db, "SELECT value FROM userinfo WHERE id=4"); var phone = execSQL(_db, "SELECT value FROM userinfo WHERE id=42"); return { wxid: info.rows && info.rows[0] ? info.rows[0].value : null, nickname: nick.rows && nick.rows[0] ? nick.rows[0].value : null, avatar: avatar.rows && avatar.rows[0] ? avatar.rows[0].value : null, phone: phone.rows && phone.rows[0] ? phone.rows[0].value : null, raw: r }; }, // ===== 联系人 ===== getContacts: function(limit, offset) { initDB(); limit = limit || 100; offset = offset || 0; return execSQL(_db, "SELECT username, alias, conRemark, nickName, type, contactLabelIds, imgFlag, verifyFlag " + "FROM rcontact WHERE type=3 AND verifyFlag=0 " + "ORDER BY rowid LIMIT " + limit + " OFFSET " + offset ); }, getContactCount: function() { initDB(); return execSQL(_db, "SELECT COUNT(*) as total FROM rcontact WHERE type=3 AND verifyFlag=0"); }, searchContact: function(keyword) { initDB(); return execSQL(_db, "SELECT username, alias, conRemark, nickName, type, contactLabelIds " + "FROM rcontact WHERE (nickName LIKE '%" + keyword + "%' OR conRemark LIKE '%" + keyword + "%' OR alias LIKE '%" + keyword + "%') " + "AND type NOT IN (0,4) LIMIT 50" ); }, getContactDetail: function(wxid) { initDB(); return execSQL(_db, "SELECT * FROM rcontact WHERE username='" + wxid + "' LIMIT 1" ); }, // ===== 消息 ===== getMessages: function(talker, limit) { initDB(); limit = limit || 50; return execSQL(_db, "SELECT msgId, type, isSend, createTime, talker, content, imgPath " + "FROM message WHERE talker='" + talker + "' " + "ORDER BY createTime DESC LIMIT " + limit ); }, getRecentMessages: function(hours) { initDB(); hours = hours || 24; var since = Date.now() - hours * 3600 * 1000; return execSQL(_db, "SELECT msgId, type, isSend, createTime, talker, content " + "FROM message WHERE createTime > " + since + " ORDER BY createTime DESC LIMIT 200" ); }, sendMessage: function(toUser, content) { initDB(); if (!_db) return {error: 'DB not available'}; var msgId = Date.now(); var createTime = Date.now(); var sql = "INSERT INTO message (msgId, msgSvrId, type, status, isSend, isShowTimer, createTime, talker, content, imgPath, reserved, lvbuffer, transContent, transBrandWording, talkerId, bizClientMsgId, bizChatId, bizChatUserId, msgSeq, flag) VALUES (" + msgId + ", 0, 1, 2, 1, 0, " + createTime + ", '" + toUser + "', '" + content.replace(/'/g, "''") + "', '', '', '', '', '', 0, '', '', '', 0, 0)"; var result = writeDB(_db, sql); if (result.success) { // 验证写入 var verify = execSQL(_db, "SELECT msgId, content, talker, createTime FROM message WHERE msgId=" + msgId); return {success: true, msgId: msgId, toUser: toUser, content: content, verify: verify}; } return result; }, // ===== 会话 ===== getConversations: function(limit) { initDB(); limit = limit || 30; return execSQL(_db, "SELECT username, unReadCount, lastMsg, lastMsgCreateTime, isSend, msgStatus " + "FROM conversation ORDER BY lastMsgCreateTime DESC LIMIT " + limit ); }, // ===== 群组 ===== getGroups: function(limit) { initDB(); limit = limit || 50; return execSQL(_db, "SELECT chatroomname, memberlist, roomowner, announcement, selfDisplayName, memberCount " + "FROM chatroom ORDER BY rowid DESC LIMIT " + limit ); }, getGroupCount: function() { initDB(); return execSQL(_db, "SELECT COUNT(*) as total FROM chatroom"); }, getGroupDetail: function(chatroomId) { initDB(); return execSQL(_db, "SELECT * FROM chatroom WHERE chatroomname='" + chatroomId + "' LIMIT 1"); }, getGroupMembers: function(chatroomId) { initDB(); var group = execSQL(_db, "SELECT memberlist FROM chatroom WHERE chatroomname='" + chatroomId + "'"); if (group.rows && group.rows[0]) { var memberList = group.rows[0].memberlist || ''; var members = memberList.split(';').filter(function(m) { return m.trim(); }); return {chatroomId: chatroomId, members: members, count: members.length}; } return {error: 'Group not found'}; }, getGroupAnnouncement: function(chatroomId) { initDB(); return execSQL(_db, "SELECT chatroomname, announcement, selfDisplayName FROM chatroom WHERE chatroomname='" + chatroomId + "'"); }, setGroupRemark: function(chatroomId, remark) { initDB(); var sql = "UPDATE chatroom SET selfDisplayName='" + remark.replace(/'/g, "''") + "' WHERE chatroomname='" + chatroomId + "'"; return writeDB(_db, sql); }, // ===== 标签 ===== getLabels: function() { initDB(); // 从rcontact的contactLabelIds字段提取所有标签ID var r = execSQL(_db, "SELECT DISTINCT contactLabelIds FROM rcontact WHERE contactLabelIds IS NOT NULL AND contactLabelIds != '' LIMIT 500"); var labelSet = {}; if (r.rows) { r.rows.forEach(function(row) { var ids = (row.contactLabelIds || '').split(','); ids.forEach(function(id) { if (id.trim()) labelSet[id.trim()] = true; }); }); } return {label_ids: Object.keys(labelSet), count: Object.keys(labelSet).length}; }, getContactsByLabel: function(labelId) { initDB(); return execSQL(_db, "SELECT username, nickName, conRemark, contactLabelIds FROM rcontact " + "WHERE contactLabelIds LIKE '%" + labelId + "%' AND type=3 LIMIT 100" ); }, // ===== 朋友圈 ===== getMoments: function(limit) { if (!_snsDb) initDB(); limit = limit || 20; if (!_snsDb) return {error: 'SNS DB not available'}; return execSQL(_snsDb, "SELECT snsId, userName, createTime, content, type, localFlag, likeFlag " + "FROM StarSnsInfo ORDER BY createTime DESC LIMIT " + limit ); }, getMomentCount: function() { if (!_snsDb) initDB(); if (!_snsDb) return {error: 'SNS DB not available'}; return execSQL(_snsDb, "SELECT COUNT(*) as total FROM StarSnsInfo"); }, postMoment: function(content) { if (!_snsDb) initDB(); if (!_snsDb) return {error: 'SNS DB not available'}; var snsId = Date.now(); var createTime = Math.floor(Date.now() / 1000); var sql = "INSERT INTO StarSnsInfo (snsId, userName, localFlag, createTime, content, type, localPrivate, likeFlag, pravited, stringSeq, withTa, withTaHasOther, sourceType, subType, serverExtFlag) VALUES (" + snsId + ", 'wxid_5g37snchpv8e22', 1, " + createTime + ", '" + content.replace(/'/g, "''") + "', 1, 0, 0, 0, '', 0, 0, 0, 0, 0)"; var result = writeDB(_snsDb, sql); if (result.success) { var verify = execSQL(_snsDb, "SELECT snsId, content, createTime FROM StarSnsInfo WHERE snsId=" + snsId); return {success: true, snsId: snsId, content: content, verify: verify}; } return result; }, // ===== 视频号 ===== getFinderInfo: function() { if (!_finderDb) initDB(); if (!_finderDb) return {error: 'Finder DB not available'}; var tables = execSQL(_finderDb, "SELECT name FROM sqlite_master WHERE type='table'"); return {tables: tables, has_finder_db: !!_finderDb}; }, getFinderContacts: function() { if (!_finderDb) initDB(); if (!_finderDb) return {error: 'Finder DB not available'}; return execSQL(_finderDb, "SELECT * FROM FinderMsgContactStorage LIMIT 20"); }, getFinderMedia: function() { if (!_finderDb) initDB(); if (!_finderDb) return {error: 'Finder DB not available'}; return execSQL(_finderDb, "SELECT * FROM FinderMediaCacheInfoV4 LIMIT 20"); }, // ===== 收藏 ===== getFavorites: function(limit) { if (!_favoriteDb) initDB(); limit = limit || 20; if (!_favoriteDb) { // 尝试从主DB查 return execSQL(_db, "SELECT * FROM FavItems LIMIT " + limit); } return execSQL(_favoriteDb, "SELECT * FROM FTS5MetaFavorite LIMIT " + limit); }, // ===== 钱包/红包 ===== getWalletInfo: function() { if (!_walletDb) initDB(); if (!_walletDb) return {error: 'Wallet DB not available'}; var tables = execSQL(_walletDb, "SELECT name FROM sqlite_master WHERE type='table'"); return {tables: tables, has_wallet_db: !!_walletDb}; }, getWalletLedger: function(limit) { if (!_walletDb) initDB(); limit = limit || 20; if (!_walletDb) return {error: 'Wallet DB not available'}; return execSQL(_walletDb, "SELECT transferId, talker, msgTime, msgDate, tradeUser, tradeType, tradeAmount " + "FROM WalletLedgerRecord ORDER BY msgTime DESC LIMIT " + limit ); }, getLuckyMoney: function(limit) { initDB(); limit = limit || 20; return execSQL(_db, "SELECT * FROM WalletLuckyMoney ORDER BY rowid DESC LIMIT " + limit ); }, getWalletBalance: function() { if (!_walletDb) initDB(); if (!_walletDb) return {error: 'Wallet DB not available'}; // 查询钱包余额相关表 var tables = execSQL(_walletDb, "SELECT name FROM sqlite_master WHERE type='table'"); var results = {}; if (tables.rows) { tables.rows.forEach(function(t) { try { var r = execSQL(_walletDb, "SELECT * FROM " + t.name + " LIMIT 5"); results[t.name] = r; } catch(e) {} }); } return results; }, // ===== 图片/文件 ===== getImageList: function(limit) { initDB(); limit = limit || 20; return execSQL(_db, "SELECT * FROM ImgInfo2 ORDER BY rowid DESC LIMIT " + limit); }, getImageCount: function() { initDB(); return execSQL(_db, "SELECT COUNT(*) as total FROM ImgInfo2"); }, getVideoList: function(limit) { initDB(); limit = limit || 20; return execSQL(_db, "SELECT * FROM videoinfo2 ORDER BY rowid DESC LIMIT " + limit); }, getVideoCount: function() { initDB(); return execSQL(_db, "SELECT COUNT(*) as total FROM videoinfo2"); }, getFileList: function(limit) { initDB(); limit = limit || 20; return execSQL(_db, "SELECT * FROM FileMsgInfo ORDER BY rowid DESC LIMIT " + limit); }, // ===== 小程序 ===== getAppBrandList: function() { initDB(); return execSQL(_db, "SELECT * FROM AppBrandInfo LIMIT 20"); }, // ===== 搜索 ===== globalSearch: function(keyword) { initDB(); var contacts = execSQL(_db, "SELECT username, nickName, conRemark FROM rcontact WHERE nickName LIKE '%" + keyword + "%' OR conRemark LIKE '%" + keyword + "%' LIMIT 10" ); var messages = execSQL(_db, "SELECT talker, content, createTime FROM message WHERE content LIKE '%" + keyword + "%' ORDER BY createTime DESC LIMIT 10" ); var groups = execSQL(_db, "SELECT chatroomname FROM chatroom WHERE chatroomname LIKE '%" + keyword + "%' LIMIT 10" ); return {contacts: contacts, messages: messages, groups: groups}; }, // ===== 群发消息 ===== massMessage: function(targets, content) { initDB(); if (!_db) return {error: 'DB not available'}; if (!targets || !targets.length) return {error: 'No targets'}; var results = []; targets.forEach(function(toUser) { var msgId = Date.now() + Math.floor(Math.random() * 1000); var createTime = Date.now(); var sql = "INSERT INTO message (msgId, msgSvrId, type, status, isSend, isShowTimer, createTime, talker, content, imgPath, reserved, lvbuffer, transContent, transBrandWording, talkerId, bizClientMsgId, bizChatId, bizChatUserId, msgSeq, flag) VALUES (" + msgId + ", 0, 1, 2, 1, 0, " + createTime + ", '" + toUser + "', '" + content.replace(/'/g, "''") + "', '', '', '', '', '', 0, '', '', '', 0, 0)"; var r = writeDB(_db, sql); results.push({toUser: toUser, msgId: msgId, success: r.success || false, error: r.error}); }); return {results: results, total: targets.length, success: results.filter(function(r) { return r.success; }).length}; }, // ===== 原始SQL(调试用)===== rawQuery: function(dbName, sql) { initDB(); var db; if (dbName === 'main') db = _db; else if (dbName === 'sns') db = _snsDb; else if (dbName === 'wallet') db = _walletDb; else if (dbName === 'finder') db = _finderDb; else if (dbName === 'favorite') db = _favoriteDb; else db = _db; return execSQL(db, sql); }, // ===== 截图 ===== takeScreenshot: function(savePath) { try { var Runtime = Java.use('java.lang.Runtime'); var path = savePath || '/sdcard/wpsdk_screenshot.png'; Runtime.getRuntime().exec(['sh', '-c', 'screencap -p ' + path]); Java.use('java.lang.Thread').sleep(500); return {success: true, path: path}; } catch(e) { return {error: e.toString()}; } }, // ===== DB信息 ===== getDbInfo: function() { initDB(); return { main: _dbPath, sns: _snsDb ? _snsDb.getPath() : null, wallet: _walletDb ? _walletDb.getPath() : null, finder: _finderDb ? _finderDb.getPath() : null, favorite: _favoriteDb ? _favoriteDb.getPath() : null }; }, // ===== 联系人完整统计 ===== getContactStats: function() { initDB(); var total = execSQL(_db, "SELECT COUNT(*) as total FROM rcontact"); var friends = execSQL(_db, "SELECT COUNT(*) as total FROM rcontact WHERE type=3 AND verifyFlag=0"); var groups = execSQL(_db, "SELECT COUNT(*) as total FROM chatroom"); var msgs = execSQL(_db, "SELECT COUNT(*) as total FROM message"); var imgs = execSQL(_db, "SELECT COUNT(*) as total FROM ImgInfo2"); var videos = execSQL(_db, "SELECT COUNT(*) as total FROM videoinfo2"); return { total_contacts: total.rows[0] ? total.rows[0].total : 0, friends: friends.rows[0] ? friends.rows[0].total : 0, groups: groups.rows[0] ? groups.rows[0].total : 0, messages: msgs.rows[0] ? msgs.rows[0].total : 0, images: imgs.rows[0] ? imgs.rows[0].total : 0, videos: videos.rows[0] ? videos.rows[0].total : 0 }; } }; console.log('[*] WeChat SDK v7 loaded. All interfaces ready.');