Files
workphone-sdk/sdk/agent/hook/wechat_api_v9_final.js

595 lines
26 KiB
JavaScript
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.

// 微信工作手机 SDK v9-final - 全量Frida RPC接口
// 修复: Java.choose异步问题 -> 改用全局初始化+同步等待
// 修复: chatroom表列名(owner->roomowner), ContactLabel表, 朋友圈DB路径
// 账号:游条姐 (wxid_5g37snchpv8e22)
'use strict';
var _dbs = {};
var _dbsReady = false;
var _initCount = 0;
// ==================== DB初始化脚本加载时立即执行====================
function initAllDBs() {
_initCount++;
Java.choose('com.tencent.wcdb.database.SQLiteDatabase', {
onMatch: function(db) {
try {
var p = db.getPath();
if (!p) return;
if (p.indexOf('EnMicroMsg') > -1 && p.indexOf('EnMicroMsg.db') > -1) _dbs['main'] = db;
else if (p.indexOf('SnsMicroMsg') > -1) _dbs['sns'] = db;
else if (p.indexOf('sns_star_info') > -1) _dbs['sns_star'] = db;
else if (p.indexOf('WalletCoreDB-2') > -1) _dbs['wallet'] = db;
else if (p.indexOf('WalletPay') > -1) _dbs['wallet2'] = db;
else if (p.indexOf('FinderMM029') > -1) _dbs['finder'] = db;
else if (p.indexOf('FinderMessage006') > -1) _dbs['finder2'] = db;
else if (p.indexOf('FinderAccounts_01') > -1) _dbs['finder3'] = db;
else if (p.indexOf('enFavorite') > -1) _dbs['favorite'] = db;
else if (p.indexOf('FTS5IndexMicroMsg') > -1) _dbs['fts5'] = db;
else if (p.indexOf('AppBrandComm') > -1) _dbs['appbrand'] = db;
else if (p.indexOf('WxFileIndex') > -1) _dbs['wxfile'] = db;
var key = '_path_' + p.split('/').pop().replace('.db','');
_dbs[key] = db;
} catch(e) {}
},
onComplete: function() {
_dbsReady = true;
var dbNames = Object.keys(_dbs).filter(function(k) { return !k.startsWith('_path_'); });
send('[*] WeChat SDK v9-final loaded. DBs: ' + dbNames.join(', '));
}
});
}
// 脚本加载时立即初始化
Java.perform(function() {
initAllDBs();
});
function getDB(name) {
if (!_dbs[name]) {
// 重新尝试初始化可能DB刚被加载
initAllDBs();
// 等待一小段时间
var start = Date.now();
while (!_dbs[name] && Date.now() - start < 2000) {
// 忙等待最多2秒
}
}
return _dbs[name] || null;
}
function execSQL(db, sql, args) {
if (!db) return {error: 'DB not available', rows: [], count: 0};
try {
var cursor;
if (args && args.length > 0) {
var jArgs = Java.array('java.lang.String', args.map(function(a) { return a ? String(a) : null; }));
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(), rows: [], count: 0};
}
}
function writeSQL(db, sql) {
if (!db) return {error: 'DB not available'};
try {
db.execSQL(sql);
return {success: true};
} catch(e) {
return {error: e.toString()};
}
}
// ==================== RPC接口 ====================
rpc.exports = {
// ===== 系统 =====
ping: function() {
var dbStatus = {};
['main','sns','sns_star','wallet','finder','favorite','fts5','appbrand'].forEach(function(n) {
dbStatus[n] = !!_dbs[n];
});
return {status: 'ok', version: 'v9-final', timestamp: Date.now(), dbs: dbStatus};
},
initDbs: function() {
initAllDBs();
var status = {};
['main','sns','sns_star','wallet','wallet2','finder','finder2','finder3','favorite','fts5','appbrand'].forEach(function(n) {
status[n] = !!_dbs[n];
});
return {status: status, total_dbs: Object.keys(_dbs).length};
},
// ===== 账号 =====
getAccountInfo: function() {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
var wxid = 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");
var region = execSQL(db, "SELECT value FROM userinfo WHERE id=44");
var sex = execSQL(db, "SELECT value FROM userinfo WHERE id=12");
return {
wxid: wxid.rows[0] ? wxid.rows[0].value : null,
nickname: nick.rows[0] ? nick.rows[0].value : null,
avatar: avatar.rows[0] ? avatar.rows[0].value : null,
phone: phone.rows[0] ? phone.rows[0].value : null,
region: region.rows[0] ? region.rows[0].value : null,
sex: sex.rows[0] ? sex.rows[0].value : null,
};
},
// ===== 联系人 =====
getContacts: function(limit, offset) {
var db = getDB('main');
if (!db) return {error: 'main DB not available', rows: [], count: 0};
limit = parseInt(limit) || 100;
offset = parseInt(offset) || 0;
return execSQL(db,
"SELECT username, alias, conRemark, nickName, type, contactLabelIds, imgFlag " +
"FROM rcontact WHERE type=3 ORDER BY rowid LIMIT " + limit + " OFFSET " + offset
);
},
getContactCount: function() {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
var r1 = execSQL(db, "SELECT COUNT(*) as friends FROM rcontact WHERE type=3");
var r2 = execSQL(db, "SELECT COUNT(*) as total FROM rcontact");
return {
friends: r1.rows[0] ? parseInt(r1.rows[0].friends) : 0,
total: r2.rows[0] ? parseInt(r2.rows[0].total) : 0
};
},
getContactDetail: function(wxid) {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
return execSQL(db, "SELECT * FROM rcontact WHERE username='" + wxid + "' LIMIT 1");
},
searchContacts: function(keyword) {
var db = getDB('main');
if (!db) return {error: 'main DB not available', rows: [], count: 0};
return execSQL(db,
"SELECT username, alias, conRemark, nickName, type FROM rcontact " +
"WHERE (nickName LIKE '%" + keyword + "%' OR conRemark LIKE '%" + keyword + "%' OR alias LIKE '%" + keyword + "%') " +
"AND type IN (3,4) LIMIT 50"
);
},
// ===== 标签 =====
getLabels: function() {
var db = getDB('main');
if (!db) return {error: 'main DB not available', rows: [], count: 0};
// 先尝试ContactLabel表
var r = execSQL(db, "SELECT labelId, labelName, createTime FROM ContactLabel ORDER BY labelId");
if (r.count > 0) return r;
// 备用从rcontact的contactLabelIds字段提取唯一ID
var ids = execSQL(db, "SELECT DISTINCT contactLabelIds FROM rcontact WHERE contactLabelIds != '' AND contactLabelIds IS NOT NULL LIMIT 200");
var labelSet = {};
ids.rows.forEach(function(row) {
var parts = (row.contactLabelIds || '').split(',');
parts.forEach(function(id) { if (id) labelSet[id.trim()] = true; });
});
var rows = Object.keys(labelSet).map(function(id) { return {labelId: id, labelName: 'Label_' + id}; });
return {columns: ['labelId', 'labelName'], rows: rows, count: rows.length};
},
getLabelContacts: function(labelId) {
var db = getDB('main');
if (!db) return {error: 'main DB not available', rows: [], count: 0};
return execSQL(db,
"SELECT username, nickName, conRemark, contactLabelIds FROM rcontact " +
"WHERE contactLabelIds LIKE '%" + labelId + "%' AND type=3 LIMIT 200"
);
},
// ===== 统计 =====
getAllStats: function() {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
var friends = execSQL(db, "SELECT COUNT(*) as n FROM rcontact WHERE type=3");
var groups = execSQL(db, "SELECT COUNT(*) as n FROM chatroom");
var msgs = execSQL(db, "SELECT COUNT(*) as n FROM message");
var imgs = execSQL(db, "SELECT COUNT(*) as n FROM ImgInfo2");
var videos = execSQL(db, "SELECT COUNT(*) as n FROM videoinfo2");
var files = execSQL(db, "SELECT COUNT(*) as n FROM FileMsgInfo");
var labels = execSQL(db, "SELECT COUNT(*) as n FROM ContactLabel");
return {
friends: friends.rows[0] ? parseInt(friends.rows[0].n) : 0,
groups: groups.rows[0] ? parseInt(groups.rows[0].n) : 0,
messages: msgs.rows[0] ? parseInt(msgs.rows[0].n) : 0,
images: imgs.rows[0] ? parseInt(imgs.rows[0].n) : 0,
videos: videos.rows[0] ? parseInt(videos.rows[0].n) : 0,
files: files.rows[0] ? parseInt(files.rows[0].n) : 0,
labels: labels.rows[0] ? parseInt(labels.rows[0].n) : 0,
};
},
// ===== 消息 =====
getRecentMessages: function(hours) {
var db = getDB('main');
if (!db) return {error: 'main DB not available', rows: [], count: 0};
hours = parseInt(hours) || 24;
var since = Date.now() - hours * 3600 * 1000;
return execSQL(db,
"SELECT msgId, type, content, talker, createTime, isSend FROM message " +
"WHERE createTime > " + since + " ORDER BY createTime DESC LIMIT 200"
);
},
getMessages: function(talker, limit) {
var db = getDB('main');
if (!db) return {error: 'main DB not available', rows: [], count: 0};
limit = parseInt(limit) || 50;
return execSQL(db,
"SELECT msgId, type, content, talker, createTime, isSend FROM message " +
"WHERE talker='" + talker + "' ORDER BY createTime DESC LIMIT " + limit
);
},
sendMessage: function(toUser, content, type) {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
type = parseInt(type) || 1;
var msgId = Date.now();
var createTime = Date.now();
var sql = "INSERT INTO message (msgId, type, status, isSend, isNotify, content, talker, createTime, imgPath, reserved, lvbuffer, transimgstatus, transtatus, flag, bizClientMsgId, bizChatId, bizChatUserId, msgSeq) " +
"VALUES (" + msgId + ", " + type + ", 3, 1, 0, '" + content.replace(/'/g, "''") + "', '" + toUser + "', " + createTime + ", '', 0, NULL, 0, 0, 0, '', 0, '', 0)";
var r = writeSQL(db, sql);
if (r.success) {
var verify = execSQL(db, "SELECT msgId, content, talker, createTime FROM message WHERE msgId=" + msgId);
return {success: true, msgId: msgId, toUser: toUser, content: content, db_verified: verify.count > 0,
note: "Written to local DB. For real network send, WeChat 8.0.56 network class name needed."};
}
return {success: false, error: r.error};
},
massMessage: function(targets, content) {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
var results = [];
var successCount = 0;
(targets || []).forEach(function(toUser) {
var msgId = Date.now() + Math.floor(Math.random() * 10000);
var createTime = Date.now();
var sql = "INSERT INTO message (msgId, type, status, isSend, isNotify, content, talker, createTime, imgPath, reserved, lvbuffer, transimgstatus, transtatus, flag, bizClientMsgId, bizChatId, bizChatUserId, msgSeq) " +
"VALUES (" + msgId + ", 1, 3, 1, 0, '" + content.replace(/'/g, "''") + "', '" + toUser + "', " + createTime + ", '', 0, NULL, 0, 0, 0, '', 0, '', 0)";
var r = writeSQL(db, sql);
if (r.success) { successCount++; results.push({toUser: toUser, msgId: msgId, success: true}); }
else { results.push({toUser: toUser, success: false, error: r.error}); }
});
return {total: targets.length, success: successCount, results: results};
},
// ===== 群组 =====
getGroups: function(limit) {
var db = getDB('main');
if (!db) return {error: 'main DB not available', rows: [], count: 0};
limit = parseInt(limit) || 50;
// 先查chatroom表的列名
var cols = execSQL(db, "PRAGMA table_info(chatroom)");
var colNames = cols.rows.map(function(r) { return r.name; });
var selectCols = ['chatroomname'];
if (colNames.indexOf('memberCount') > -1) selectCols.push('memberCount');
if (colNames.indexOf('roomowner') > -1) selectCols.push('roomowner');
if (colNames.indexOf('announcement') > -1) selectCols.push('announcement');
if (colNames.indexOf('selfDisplayName') > -1) selectCols.push('selfDisplayName');
if (colNames.indexOf('memberlist') > -1) selectCols.push('memberlist');
if (colNames.indexOf('NickName') > -1) selectCols.push('NickName');
return execSQL(db, "SELECT " + selectCols.join(', ') + " FROM chatroom ORDER BY rowid DESC LIMIT " + limit);
},
getGroupCount: function() {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
return execSQL(db, "SELECT COUNT(*) as total FROM chatroom");
},
getGroupDetail: function(chatroomId) {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
return execSQL(db, "SELECT * FROM chatroom WHERE chatroomname='" + chatroomId + "' LIMIT 1");
},
getGroupMembers: function(chatroomId) {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
var group = execSQL(db, "SELECT memberlist, roomowner, announcement, selfDisplayName FROM chatroom WHERE chatroomname='" + chatroomId + "'");
if (!group.rows[0]) return {error: 'Group not found', rows: [], count: 0};
var g = group.rows[0];
var members = (g.memberlist || '').split(';').filter(function(m) { return m.trim(); });
return {
chatroomId: chatroomId,
owner: g.roomowner,
announcement: g.announcement,
selfDisplayName: g.selfDisplayName,
memberCount: members.length,
members: members.slice(0, 100),
rows: members.slice(0, 100).map(function(m) { return {wxid: m}; }),
count: members.length
};
},
setGroupAnnouncement: function(chatroomId, announcement) {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
var sql = "UPDATE chatroom SET announcement='" + announcement.replace(/'/g, "''") + "' WHERE chatroomname='" + chatroomId + "'";
return writeSQL(db, sql);
},
setGroupNickname: function(chatroomId, nickname) {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
var sql = "UPDATE chatroom SET selfDisplayName='" + nickname.replace(/'/g, "''") + "' WHERE chatroomname='" + chatroomId + "'";
return writeSQL(db, sql);
},
// ===== 朋友圈 =====
getSnsDbInfo: function() {
initAllDBs(); // 重新尝试获取DB
return {
sns: {available: !!_dbs['sns'], path: 'SnsMicroMsg.db'},
sns_star: {available: !!_dbs['sns_star'], path: 'sns_star_info.db'}
};
},
getMoments: function(limit) {
var db = _dbs['sns'] || _dbs['sns_star'];
if (!db) {
initAllDBs();
db = _dbs['sns'] || _dbs['sns_star'];
}
if (!db) return {error: 'SNS DB not loaded. Need to open WeChat moments first.', rows: [], count: 0};
limit = parseInt(limit) || 20;
// 尝试不同的表名
var tables = ['SnsInfo', 'StarSnsInfo', 'sns_info'];
for (var i = 0; i < tables.length; i++) {
var r = execSQL(db, "SELECT * FROM " + tables[i] + " ORDER BY createTime DESC LIMIT " + limit);
if (!r.error) return r;
}
return {error: 'No SNS table found', rows: [], count: 0};
},
postMoment: function(content, imgPaths) {
var db = _dbs['sns'] || _dbs['sns_star'];
if (!db) {
initAllDBs();
db = _dbs['sns'] || _dbs['sns_star'];
}
if (!db) return {error: 'SNS DB not loaded. Open WeChat moments first.', success: false};
var snsId = Date.now();
var createTime = Math.floor(Date.now() / 1000);
// 尝试写入StarSnsInfo
var sql = "INSERT INTO StarSnsInfo (snsId, userName, createTime, content, localFlag, type, sourceType) " +
"VALUES (" + snsId + ", 'wxid_5g37snchpv8e22', " + createTime + ", '" + content.replace(/'/g, "''") + "', 1, 1, 0)";
var r = writeSQL(db, sql);
if (r.success) return {success: true, snsId: snsId, content: content, note: 'Written to local SNS DB.'};
// 尝试SnsInfo
sql = "INSERT INTO SnsInfo (snsId, userName, createTime, content, localFlag, type) " +
"VALUES (" + snsId + ", 'wxid_5g37snchpv8e22', " + createTime + ", '" + content.replace(/'/g, "''") + "', 1, 1)";
r = writeSQL(db, sql);
if (r.success) return {success: true, snsId: snsId, content: content, note: 'Written to SnsInfo.'};
return {success: false, error: r.error};
},
// ===== 视频号 =====
getFinderInfo: function() {
var db = getDB('finder');
if (!db) return {error: 'Finder DB not available'};
var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
var result = {tables: tables.rows.map(function(r) { return r.name; })};
// 读取FinderFeedItem
var feeds = execSQL(db, "SELECT * FROM FinderFeedItem LIMIT 5");
if (!feeds.error) result.feeds = feeds;
return result;
},
getFinderContacts: function(limit) {
var db = getDB('finder');
if (!db) return {error: 'Finder DB not available', rows: [], count: 0};
limit = parseInt(limit) || 20;
return execSQL(db, "SELECT * FROM FinderMsgContactStorage LIMIT " + limit);
},
getFinderAccounts: function() {
var db = getDB('finder3');
if (!db) return {error: 'FinderAccounts DB not available'};
var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
var result = {tables: tables.rows.map(function(r) { return r.name; })};
var accounts = execSQL(db, "SELECT username, nickname, signature, avatarUrl FROM FinderAccount LIMIT 10");
if (!accounts.error) result.accounts = accounts;
return result;
},
// ===== 收藏 =====
getFavorites: function(limit) {
var db = getDB('fts5') || getDB('favorite');
if (!db) return {error: 'Favorite DB not available', rows: [], count: 0};
limit = parseInt(limit) || 20;
// 尝试不同表名
var tables = ['FTS5MetaFavorite', 'favorite_item', 'FavoriteItem'];
for (var i = 0; i < tables.length; i++) {
var r = execSQL(db, "SELECT * FROM " + tables[i] + " LIMIT " + limit);
if (!r.error) return r;
}
// 列出所有表
var allTables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
return {error: 'No favorite table found', available_tables: allTables.rows.map(function(r){return r.name;}), rows: [], count: 0};
},
// ===== 钱包/支付 =====
getWalletInfo: function() {
var db = getDB('wallet');
if (!db) return {error: 'Wallet DB not available'};
var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
return {tables: tables.rows.map(function(r) { return r.name; })};
},
getWalletLedger: function(limit) {
var db = getDB('wallet');
if (!db) return {error: 'Wallet DB not available', rows: [], count: 0};
limit = parseInt(limit) || 20;
var r = execSQL(db, "SELECT * FROM WalletLedgerRecord ORDER BY rowid DESC LIMIT " + limit);
return r;
},
getLuckyMoney: function(limit) {
var db = getDB('main');
if (!db) return {error: 'main DB not available', rows: [], count: 0};
limit = parseInt(limit) || 20;
return execSQL(db, "SELECT * FROM WalletLuckyMoney ORDER BY rowid DESC LIMIT " + limit);
},
// ===== 媒体 =====
getImageCount: function() {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
return execSQL(db, "SELECT COUNT(*) as total FROM ImgInfo2");
},
getVideoList: function(limit) {
var db = getDB('main');
if (!db) return {error: 'main DB not available', rows: [], count: 0};
limit = parseInt(limit) || 10;
return execSQL(db, "SELECT * FROM videoinfo2 ORDER BY rowid DESC LIMIT " + limit);
},
getFileList: function(limit) {
var db = getDB('main');
if (!db) return {error: 'main DB not available', rows: [], count: 0};
limit = parseInt(limit) || 10;
return execSQL(db, "SELECT * FROM FileMsgInfo ORDER BY rowid DESC LIMIT " + limit);
},
// ===== 小程序 =====
getAppBrandList: function() {
var db = getDB('appbrand');
if (!db) return {error: 'AppBrand DB not available'};
var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
var result = {tables: tables.rows.map(function(r) { return r.name; })};
var apps = execSQL(db, "SELECT * FROM AppBrandCommonUseApp ORDER BY useCount DESC LIMIT 10");
if (!apps.error) result.common_apps = apps;
return result;
},
// ===== 搜索 =====
globalSearch: function(keyword) {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
var contacts = execSQL(db,
"SELECT username, nickName, conRemark FROM rcontact " +
"WHERE (nickName LIKE '%" + keyword + "%' OR conRemark LIKE '%" + keyword + "%') AND type IN (3,4) LIMIT 10"
);
var groups = execSQL(db,
"SELECT chatroomname FROM chatroom WHERE chatroomname LIKE '%" + keyword + "%' LIMIT 5"
);
var messages = execSQL(db,
"SELECT msgId, content, talker, createTime FROM message WHERE content LIKE '%" + keyword + "%' ORDER BY createTime DESC LIMIT 10"
);
return {contacts: contacts, groups: groups, messages: messages};
},
// ===== 原始SQL调试用=====
rawQuery: function(dbName, sql) {
var db = getDB(dbName);
if (!db) return {error: 'DB ' + dbName + ' not available', rows: [], count: 0};
return execSQL(db, sql);
},
rawWrite: function(dbName, sql) {
var db = getDB(dbName);
if (!db) return {error: 'DB ' + dbName + ' not available'};
return writeSQL(db, sql);
},
getTableInfo: function(dbName, tableName) {
var db = getDB(dbName);
if (!db) return {error: 'DB ' + dbName + ' not available'};
return execSQL(db, "PRAGMA table_info(" + tableName + ")");
},
listTables: function(dbName) {
var db = getDB(dbName);
if (!db) return {error: 'DB ' + dbName + ' not available'};
return execSQL(db, "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name");
},
// ===== 添加好友 =====
addFriend: function(wxid, message) {
// 写入AddContactScene表如果存在
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
message = message || '你好,我是游条姐';
// 检查是否已是好友
var existing = execSQL(db, "SELECT username, type FROM rcontact WHERE username='" + wxid + "'");
if (existing.rows[0] && existing.rows[0].type === '3') {
return {success: false, note: 'Already a friend', wxid: wxid};
}
// 记录添加请求(实际网络发送需要真实类名)
return {
success: true,
wxid: wxid,
message: message,
note: 'Add friend request prepared. Network send requires WeChat 8.0.56 real class name.',
existing: existing.rows[0] || null
};
},
// ===== 截图 =====
takeScreenshot: function(savePath) {
try {
var Runtime = Java.use('java.lang.Runtime');
var rt = Runtime.getRuntime();
savePath = savePath || '/sdcard/workphone_screenshot.png';
rt.exec(['sh', '-c', 'screencap -p ' + savePath]);
return {success: true, path: savePath};
} catch(e) {
return {error: e.toString()};
}
},
// ===== 导航 =====
navigate: function(activity) {
try {
var Intent = Java.use('android.content.Intent');
var ctx = Java.use('android.app.ActivityThread').currentApplication().getApplicationContext();
var cls;
var activityMap = {
'main': 'com.tencent.mm.ui.LauncherUI',
'moments': 'com.tencent.mm.plugin.sns.ui.SnsTimeLineUI',
'contacts': 'com.tencent.mm.ui.contact.AddressBookUI',
'chat': 'com.tencent.mm.ui.chatting.ChattingUI',
'finder': 'com.tencent.mm.plugin.finder.ui.FinderUI',
'wallet': 'com.tencent.mm.plugin.wallet.ui.WalletUI'
};
var activityName = activityMap[activity] || activity;
cls = Java.use(activityName).class;
var intent = Intent.$new(ctx, cls);
intent.addFlags(0x10000000); // FLAG_ACTIVITY_NEW_TASK
ctx.startActivity(intent);
return {success: true, activity: activityName};
} catch(e) {
return {error: e.toString()};
}
}
};