/**
 * 微信8.0.56 类名发现脚本
 * 通过ClassLoader枚举找到真实类名
 */
'use strict';

function getWechatLoader() {
    var wechatLoader = null;
    Java.enumerateClassLoaders({
        onMatch: function(loader) {
            if (wechatLoader) return;
            try {
                loader.loadClass('com.tencent.mm.app.Application');
                wechatLoader = loader;
            } catch(e) {}
        },
        onComplete: function() {}
    });
    return wechatLoader;
}

rpc.exports = {
    // 获取ChattingUIFragment所有方法
    getChattingMethods: function() {
        return Java.performNow(function() {
            var loader = getWechatLoader();
            if (!loader) return { error: 'no loader' };
            try {
                var cls = loader.loadClass('com.tencent.mm.ui.chatting.ChattingUIFragment');
                var methods = cls.getDeclaredMethods();
                var result = [];
                for (var i = 0; i < methods.length; i++) {
                    var m = methods[i];
                    var params = m.getParameterTypes().map(function(p) { return p.getName(); });
                    result.push({
                        name: m.getName(),
                        params: params,
                        ret: m.getReturnType().getName()
                    });
                }
                return { success: true, count: result.length, methods: result };
            } catch(e) {
                return { success: false, error: String(e) };
            }
        });
    },

    // 搜索双字母类名
    findDoubleLetterClasses: function() {
        return Java.performNow(function() {
            var loader = getWechatLoader();
            if (!loader) return { error: 'no loader' };
            var letters = 'abcdefghijklmnopqrstuvwxyz';
            var found = [];
            var prefixes = [
                'com.tencent.mm.modelmulti.',
                'com.tencent.mm.plugin.messenger.foundation.a.',
                'com.tencent.mm.plugin.messenger.foundation.b.',
                'com.tencent.mm.plugin.messenger.foundation.c.',
            ];
            for (var p = 0; p < prefixes.length; p++) {
                for (var i = 0; i < letters.length; i++) {
                    for (var j = 0; j < letters.length; j++) {
                        var clsName = prefixes[p] + letters[i] + letters[j];
                        try {
                            var cls = loader.loadClass(clsName);
                            var methods = cls.getDeclaredMethods();
                            var mNames = [];
                            for (var k = 0; k < methods.length; k++) {
                                var params = methods[k].getParameterTypes().map(function(t) { return t.getName(); });
                                mNames.push(methods[k].getName() + '(' + params.join(',') + ')');
                            }
                            found.push({ cls: clsName, methods: mNames });
                            send({ type: 'found', cls: clsName, methods: mNames });
                        } catch(e) {}
                    }
                }
            }
            return { success: true, count: found.length, found: found };
        });
    },

    // Hook SQLite insert监听消息写入
    hookMessageInsert: function() {
        try {
            var WCDB = Java.use('com.tencent.wcdb.database.SQLiteDatabase');
            WCDB.insert.overload(
                'java.lang.String',
                'java.lang.String',
                'android.content.ContentValues'
            ).implementation = function(table, nullCol, values) {
                var result = this.insert(table, nullCol, values);
                if (table === 'message') {
                    try {
                        var isSend = values.getAsInteger('isSend');
                        if (isSend && parseInt(isSend.toString()) === 1) {
                            var content = values.getAsString('content');
                            var talker = values.getAsString('talker');
                            // 捕获调用栈
                            var Exception = Java.use('java.lang.Exception');
                            var ex = Exception.$new('stack capture');
                            var stack = ex.getStackTrace();
                            var stackInfo = [];
                            for (var i = 0; i < Math.min(stack.length, 30); i++) {
                                var frame = stack[i];
                                var cn = frame.getClassName();
                                if (cn.indexOf('com.tencent.mm') !== -1) {
                                    stackInfo.push(cn + '.' + frame.getMethodName() + ':' + frame.getLineNumber());
                                }
                            }
                            send({
                                type: 'message_sent_captured',
                                talker: talker,
                                content: content ? content.substring(0, 80) : '',
                                stack: stackInfo
                            });
                        }
                    } catch(e2) {}
                }
                return result;
            };
            return { success: true, msg: 'WCDB insert hooked' };
        } catch(e) {
            return { success: false, error: String(e) };
        }
    },

    // 通过反射找到DB实例并获取密钥
    findDBInstance: function() {
        return Java.performNow(function() {
            var loader = getWechatLoader();
            if (!loader) return { error: 'no loader' };

            // 尝试找到MicroMsgDBHelper
            var helperCandidates = [
                'com.tencent.mm.storage.MicroMsgDBHelper',
                'com.tencent.mm.storage.DatabaseHelper',
                'com.tencent.mm.storage.MicroMsgDB',
                'com.tencent.mm.storage.db.MicroMsgDB',
            ];
            var found = [];
            for (var i = 0; i < helperCandidates.length; i++) {
                try {
                    var cls = loader.loadClass(helperCandidates[i]);
                    var methods = cls.getDeclaredMethods();
                    var mNames = [];
                    for (var j = 0; j < methods.length; j++) {
                        mNames.push(methods[j].getName());
                    }
                    found.push({ cls: helperCandidates[i], methods: mNames.slice(0, 10) });
                } catch(e) {}
            }
            return { success: true, found: found };
        });
    },

    // 通过WCDB直接操作DB（用已打开的DB连接）
    queryViaWCDB: function(sql) {
        return Java.performNow(function() {
            try {
                // 获取已打开的DB实例（通过Application的静态字段）
                var WCDB = Java.use('com.tencent.wcdb.database.SQLiteDatabase');
                // 找到所有WCDB实例
                var instances = [];
                Java.choose('com.tencent.wcdb.database.SQLiteDatabase', {
                    onMatch: function(instance) {
                        try {
                            var path = instance.getPath();
                            instances.push({ path: path, open: instance.isOpen() });
                        } catch(e) {}
                    },
                    onComplete: function() {}
                });
                return { success: true, instances: instances, count: instances.length };
            } catch(e) {
                return { success: false, error: String(e) };
            }
        });
    },

    // 通过Java.choose找到已打开的DB并执行查询
    executeOnOpenDB: function(sql) {
        return Java.performNow(function() {
            try {
                var results = [];
                var executed = false;
                Java.choose('com.tencent.wcdb.database.SQLiteDatabase', {
                    onMatch: function(db) {
                        if (executed) return;
                        try {
                            var path = db.getPath();
                            if (path && path.indexOf('EnMicroMsg') !== -1 && db.isOpen()) {
                                // 执行查询
                                var cursor = db.rawQuery(sql, null);
                                if (cursor) {
                                    var cols = cursor.getColumnNames();
                                    while (cursor.moveToNext()) {
                                        var row = {};
                                        for (var i = 0; i < cols.length; i++) {
                                            try { row[cols[i]] = cursor.getString(i); } catch(e) { row[cols[i]] = null; }
                                        }
                                        results.push(row);
                                    }
                                    cursor.close();
                                    executed = true;
                                    send({ type: 'db_query_ok', path: path, rows: results.length });
                                }
                            }
                        } catch(e) {
                            send({ type: 'db_query_err', error: String(e).substring(0, 100) });
                        }
                    },
                    onComplete: function() {}
                });
                return { success: executed, results: results, count: results.length };
            } catch(e) {
                return { success: false, error: String(e) };
            }
        });
    },

    // 通过Java.choose找到DB并INSERT消息
    insertViaOpenDB: function(params) {
        return Java.performNow(function() {
            var toId = params.to_id;
            var content = params.content;
            try {
                var inserted = false;
                var dbPath = '';
                Java.choose('com.tencent.wcdb.database.SQLiteDatabase', {
                    onMatch: function(db) {
                        if (inserted) return;
                        try {
                            var path = db.getPath();
                            if (path && path.indexOf('EnMicroMsg') !== -1 && db.isOpen()) {
                                dbPath = path;
                                var ContentValues = Java.use('android.content.ContentValues');
                                var cv = ContentValues.$new();
                                var now = Date.now();
                                cv.put('msgId', Java.use('java.lang.Long').$new(now));
                                cv.put('type', Java.use('java.lang.Integer').$new(1));
                                cv.put('isSend', Java.use('java.lang.Integer').$new(1));
                                cv.put('talker', toId);
                                cv.put('content', content);
                                cv.put('createTime', Java.use('java.lang.Long').$new(now));
                                cv.put('status', Java.use('java.lang.Integer').$new(2));
                                cv.put('imgPath', '');
                                var rowId = db.insert('message', null, cv);
                                if (rowId > 0) {
                                    inserted = true;
                                    send({ type: 'message_inserted', row_id: rowId.toString(), path: path });
                                }
                            }
                        } catch(e) {
                            send({ type: 'insert_err', error: String(e).substring(0, 150) });
                        }
                    },
                    onComplete: function() {}
                });
                return { success: inserted, db_path: dbPath, method: 'wcdb_direct_insert' };
            } catch(e) {
                return { success: false, error: String(e) };
            }
        });
    }
};

Java.perform(function() {
    send({ type: 'ready', msg: 'wechat_class_finder loaded' });
});
