/** * Frida debug script v4 — comprehensive WCDB hook * Hooks insert, insertWithOnConflict, replace, replaceOrThrow, execSQL, rawQuery * Usage: frida -U -p PID -l debug_wechat_send4.js */ function log(tag, msg) { console.log("[" + tag + "] " + msg); } function printStack(tag) { var Exception = Java.use("java.lang.Exception"); var Log = Java.use("android.util.Log"); var trace = Log.getStackTraceString(Exception.$new()); console.log("[" + tag + " STACK]\n" + trace + "\n[END STACK]"); } function hookAllWcdbMethods(clsName) { try { var cls = Java.use(clsName); log("HOOK", "Hooking " + clsName); // insert try { cls.insert.overload('java.lang.String', 'java.lang.String', 'android.content.ContentValues').implementation = function(table, nullCol, values) { if (table && table.toLowerCase().indexOf("message") !== -1) { var isSend = values ? values.getAsInteger("isSend") : null; var talker = values ? values.getAsString("talker") : null; var content = values ? values.getAsString("content") : null; log("INSERT", "table=" + table + " isSend=" + isSend + " talker=" + talker + " content=" + (content ? content.substring(0, 40) : "null")); if (isSend && isSend == 1) printStack("INSERT_SEND"); } return this.insert(table, nullCol, values); }; } catch(e) {} // insertWithOnConflict try { cls.insertWithOnConflict.overload('java.lang.String', 'java.lang.String', 'android.content.ContentValues', 'int').implementation = function(table, nullCol, values, conflict) { if (table && table.toLowerCase().indexOf("message") !== -1) { var isSend = values ? values.getAsInteger("isSend") : null; log("INSERT2", "table=" + table + " isSend=" + isSend); if (isSend && isSend == 1) printStack("INSERT2_SEND"); } return this.insertWithOnConflict(table, nullCol, values, conflict); }; } catch(e) {} // replace try { cls.replace.overload('java.lang.String', 'java.lang.String', 'android.content.ContentValues').implementation = function(table, nullCol, values) { if (table && table.toLowerCase().indexOf("message") !== -1) { log("REPLACE", "table=" + table); printStack("REPLACE"); } return this.replace(table, nullCol, values); }; } catch(e) {} // execSQL(String) try { cls.execSQL.overload('java.lang.String').implementation = function(sql) { var lowerSql = sql ? sql.toLowerCase() : ""; if (lowerSql.indexOf("message") !== -1 && (lowerSql.indexOf("insert") !== -1 || lowerSql.indexOf("replace") !== -1)) { log("EXECSQL", sql.substring(0, 200)); printStack("EXECSQL"); } return this.execSQL(sql); }; } catch(e) {} // execSQL(String, Object[]) try { cls.execSQL.overload('java.lang.String', '[Ljava.lang.Object;').implementation = function(sql, args) { var lowerSql = sql ? sql.toLowerCase() : ""; if (lowerSql.indexOf("message") !== -1 && (lowerSql.indexOf("insert") !== -1 || lowerSql.indexOf("replace") !== -1)) { log("EXECSQL2", sql.substring(0, 200)); printStack("EXECSQL2"); } return this.execSQL(sql, args); }; } catch(e) {} // rawQuery try { cls.rawQuery.overload('java.lang.String', '[Ljava.lang.String;').implementation = function(sql, args) { var lowerSql = sql ? sql.toLowerCase() : ""; if (lowerSql.indexOf("message") !== -1 && lowerSql.indexOf("insert") !== -1) { log("RAWQUERY", sql.substring(0, 200)); printStack("RAWQUERY"); } return this.rawQuery(sql, args); }; } catch(e) {} log("HOOK", clsName + " hooks installed"); } catch (e) { log("HOOK", "Failed to hook " + clsName + ": " + e); } } Java.perform(function () { log("MAIN", "Installing comprehensive WCDB hooks..."); // Hook WCDB hookAllWcdbMethods("com.tencent.wcdb.database.SQLiteDatabase"); // Also hook standard Android SQLite hookAllWcdbMethods("android.database.sqlite.SQLiteDatabase"); // Hook SQLiteStatement for prepared statement execution try { var Stmt = Java.use("com.tencent.wcdb.database.SQLiteStatement"); Stmt.execute.overload().implementation = function() { var sql = this.mSql ? this.mSql.value : "unknown"; if (sql.toLowerCase().indexOf("message") !== -1) { log("STMT", "execute: " + sql.substring(0, 100)); printStack("STMT"); } return this.execute(); }; log("HOOK", "SQLiteStatement hooked"); } catch(e) { log("HOOK", "SQLiteStatement hook failed: " + e); } log("MAIN", "All hooks installed. Send a message manually now."); });